https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122050
--- Comment #7 from Alejandro Colomar <[email protected]> --- (In reply to Waffl3x from comment #6) > (In reply to Alejandro Colomar from comment #5) > > When the _Pragma() is removed, the trailing semicolon remains there. If the > > C behavior were wrong, this code would suddenly fail. > > > > This code has been historically portable, and IMO should remain valid. > Per this PR, this code is not portable with C++, it fails in C++ mode > in both GCC and Clang. IMO the code is clearly wrong as _Pragma does > not require a semicolon. Agreed. > (In reply to Richard Biener from comment #2) > > I think the current behavior of the C frontend doesn't make sense and is > > inconsistent. Of course fixing it might break existing code ... I'd suggest > > to emit a pedantic error if the 2nd last stmt isn't 'void' as well. > However I agree we should preserve the behavior, at least for now. I > reckon the question is where to draw the line. > > I can think of 4 cases: > > 1. Empty statements after any non-void statements. > ``` > ({ > int a = 0; > a; > ; // error/warning > }); > > ({ > int a = 0; > ++a; > ; // error/warning > }); > ``` Agreed. > > 2. Statements of type void (non-empty) after any non-void statements. > ``` > int g (); > > ({ > int a = 0; > a; > (void)g (); // error/warning > }); > > > ({ > int a = 0; > ++a; > (void)g (); // error/warning > }); > ``` These are (and should be) treated the same as 3. They are already diagnosed. ``` alx@devuan:~/tmp$ cat se2.c++ #include <stdlib.h> int my_abort(void) { abort(); } #define assert(e) ((e) ? (void)0 : ({42; (void)my_abort();})) int main(void) { assert(1); } alx@devuan:~/tmp$ g++ -Wall -Wextra se2.c++ se2.c++: In function ‘int main()’: se2.c++:8:39: warning: statement has no effect [-Wunused-value] 8 | #define assert(e) ((e) ? (void)0 : ({42; (void)my_abort();})) | ^~ se2.c++:13:9: note: in expansion of macro ‘assert’ 13 | assert(1); | ^~~~~~ ``` > > 3. Statements of type void after a non-void statement... > a. ...without side effects. > ``` > void f (); > > ({ > int a = 0; > a; > f (); // error/warning > }); > ``` These are already diagnosed as part of -Wunused-value: ``` alx@devuan:~/tmp$ cat se3a.c++ #include <stdlib.h> #define assert(e) ((e) ? (void)0 : ({42; abort();})) int main(void) { assert(1); } alx@devuan:~/tmp$ g++ -Wall -Wextra se3a.c++ se3a.c++: In function ‘int main()’: se3a.c++:3:39: warning: statement has no effect [-Wunused-value] 3 | #define assert(e) ((e) ? (void)0 : ({42; abort();})) | ^~ se3a.c++:8:9: note: in expansion of macro ‘assert’ 8 | assert(1); | ^~~~~~ ``` > 3b. ...with side effects. > ``` > void f (); > > ({ > int a = 0; > ++a; > f (); // error/warning > }); > ``` These are already diagnosed as part of -Wunused-but-set-variable: ``` alx@devuan:~/tmp$ cat se3b.c++ #include <stdlib.h> #define assert(e) ((e) ? (void)0 : ({int i = 42; i++; abort();})) int main(void) { assert(1); } alx@devuan:~/tmp$ g++ -Wall -Wextra se3b.c++ se3b.c++: In function ‘int main()’: se3b.c++:3:43: warning: variable ‘i’ set but not used [-Wunused-but-set-variable=] 3 | #define assert(e) ((e) ? (void)0 : ({int i = 42; i++; abort();})) | ^ se2.c++:8:9: note: in expansion of macro ‘assert’ 8 | assert(1); | ^~~~~~ ``` > > I think cases 1 and 3a should be diagnosed, while 2b could possibly > have false positives. I could also see case 2 being diagnosed. I can > draft a patch for whichever we select. Obviously the safest is to only > warn/error for the first case (empty statements).
