As discussed in bug 88766 comment #4, GCC treats some statement expressions as lvalues even though their last statement is an rvalue. As noted in the rest of the discussion a statement expression should evaluate to an rvalue even if it's last statement is an lvalue. Besides adjusting GCC to reflect that the manual should be updated to explain this. $ cat u.c && gcc -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout u.c void f (void) { int i = 0; ++__extension__ ({ (int)i; }); // accepted (bug) if (i != 1) // folded to false __builtin_abort (); } int* g (void) { int i = 0; int *p = &++__extension__ ({ (int)i; }); // rejected (good) return p; } u.c: In function ‘g’: u.c:12:12: error: lvalue required as unary ‘&’ operand 12 | int *p = &++__extension__ ({ (int)i; }); // rejected (good) | ^