https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89718

            Bug ID: 89718
           Summary: _Pragma GCC diagnostic ignored inside macro
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: federico.kircheis at gmail dot com
  Target Milestone: ---

Given following piece of code

----
#define DIAGNOSTIC_HELPER0(x) #x
#define DIAGNOSTIC_HELPER1(kind, y) DIAGNOSTIC_HELPER0(GCC diagnostic kind #y)

#define DIAGNOSTIC(kind, warning, statements)\
    _Pragma("GCC diagnostic push")\
    _Pragma(DIAGNOSTIC_HELPER1(kind, warning))\
    statements \
    _Pragma("GCC diagnostic pop")

DIAGNOSTIC(error, -Wuninitialized,
int foo(int a, int b){return a;}
int main(){
    int i;
    return foo(i, i);
}
----

I would expect it not to compile when executing `g++ main.cpp`, but it compiles
without any issues.

With clang++ (expected behavior):

--
clang++ main.cpp
main.cpp:15:16: error: variable 'i' is uninitialized when used here
[-Werror,-Wuninitialized]
    return foo(i, i);
               ^
main.cpp:7:5: note: expanded from macro 'DIAGNOSTIC'
    statements \
    ^~~~~~~~~~
main.cpp:14:5: note: variable 'i' is declared here
    int i;
    ^
1 error generated.
--

When manually "expanding" the macros to

----
_Pragma("GCC diagnostic push")\
_Pragma(DIAGNOSTIC_HELPER1(error, -Wuninitialized))
int foo(int a, int b){return a;}
int main(){
    int i;
    return foo(i, i);
}
_Pragma("GCC diagnostic pop")
----

The behavior is the expected:

--
g++ main.cpp
main.cpp: In function ‘int main()’:
main.cpp:26:15: error: ‘i’ is used uninitialized in this function
[-Werror=uninitialized]
     return foo(i, i);
            ~~~^~~~~~
cc1plus: some warnings being treated as errors
--

and no file is generated.


Notice that the same behavior (__pragma not taken into account) is reproducible
when using "ignored" or "warning" instead of "error".

Some other considerations/information:
msvc works like clang (with other pragmas obviously).
With the provided code, also (tested on https://godbolt.org/) elcc (any
version), djggp4.9.4, and zapcc, all behaves like clang (pragma is taken into
account).

While testing different compilers, I discovered that this seems to be a
"partial" regression, since gcc 4.9.4.
Here the compiler triggers a warning (and not error) when using "GCC diagnostic
error", but does not ignore the warning when using "GCC diagnostic ignored".

It is a regression compared to gcc 4.4.7, since it triggers an error (when
using "GCC diagnostic error", I'm unsure why the warnings are generated):

--
<source>:16: warning: expected [error|warning|ignored] after '#pragma GCC
diagnostic'
<source>:16: warning: expected [error|warning|ignored] after '#pragma GCC
diagnostic'
<source>: In function 'int main()':
<source>:10: error: 'i' is used uninitialized in this function
Compiler returned: 1
--

My local gcc version:
--
g++ (Debian 8.3.0-2) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--

but the behavior is consistent since gcc5 on different operating systems.

Notice that this is not a duplicate of
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69543, since 

----
# define ERR_BEGIN \
    _Pragma ("GCC diagnostic push") \
    _Pragma ("GCC diagnostic error \"-Wuninitialized\"")\
    _Pragma ("GCC diagnostic error \"-Wmaybe-uninitialized\"")
# define ERR_END \
    _Pragma ("GCC diagnostic pop")

int main (int yylval, char**)
{
  char *yyvsp;
  ERR_BEGIN
  *++yyvsp = yylval;
  ERR_END
}
----

triggers a compile error:

--
g++ /tmp/main.cpp
/tmp/main.cpp: In function ‘int main(int, char**)’:
/tmp/main.cpp:12:12: error: ‘yyvsp’ is used uninitialized in this function
[-Werror=uninitialized]
   *++yyvsp = yylval;
   ~~~~~~~~~^~~~~~~~
cc1plus: some warnings being treated as errors
--

Reply via email to