58
#include <iostream>

int main() {
    bool b = true;
    std::cout << std::is_same<decltype(!(!b)), bool>::value << "\n";

    auto bb = (!(!b));
    std::cout << std::is_same<decltype(bb), bool>::value << "\n";
}

The above code has different results using different compilers. Is this a compiler bug or am I missing something?

Jason
  • 36,170
  • 5
  • 26
  • 60
Nir
  • 1,608
  • 1
  • 17
  • 29
  • 2
    Looks like a gcc bug to me, especially since it only comes up with double negation...in the meantime, you could use std::is_convertible – joergbrech Sep 28 '22 at 07:09
  • 25
    GCC thinks `!!b` is an lvalue, so `decltype` reports `bool &`. It even allows `!!b = false;` Looks like an obvious bug, please report this. The same happens with any even number of `!`s. – HolyBlackCat Sep 28 '22 at 07:09

1 Answers1

50

This is a gcc bug. The problem is that gcc incorrectly treats the expression !(!b) as an lvalue instead of rvalue. You can confirm this here. As you'll see in the above linked demo, the output gcc gives is lvalue instead of prvalue.

The bug has been reported as:

GCC treats rvalue as an lvalue

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 8
    Perhaps it happens as an optimization in a very early pass that eliminates !! as "redundant". – Pablo H Sep 28 '22 at 15:58
  • 10
    Not only does `value_category` mis-categorize it, `!(!b) = false;` actually compiles (in a debug build https://godbolt.org/z/Wxx3ds84f to a `mov` store that sets `b=0`, otherwise optimized away). So that's fun. It's not just a bug in the categorizing output. Other compilers of course correctly reject this. @PabloH: any even number of `!` compiles, any odd number is rejected as not being an lvalue, so yeah, your guess about early elimination is compatible with that experiment. – Peter Cordes Sep 28 '22 at 20:17