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).

Reply via email to