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

            Bug ID: 85153
           Summary: _Pragma to disable -Wswitch-unreachable diagnostic not
                    properly working when used within preprocessor macro
           Product: gcc
           Version: 7.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: driver
          Assignee: unassigned at gcc dot gnu.org
          Reporter: falemagn at gmail dot com
  Target Milestone: ---

Created attachment 43809
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=43809&action=edit
The preprocessed source, which works as expected

The preprocessed output (attached) behaves as expected, so I assume this
problem has to do with the driver and/or a strange interaction between driver,
preprocessor and compiler. For lack of better knowledge, I've filed this bug
under the "driver" component.

The whole code is on godbolt: https://godbolt.org/g/rTc3AU

Given the following code, g++ properly emits a warning.

    int x;

    int test1(int val) {
        switch (val) {
                    if (!x) {
            case 1:     return 10;
                    }
        }

        return 0;
    }

pragmatest.cpp: In function ‘int test1(int)’:
pragmatest.cpp:5:25: warning: statement will never be executed
[-Wswitch-unreachable]
                     if (!x) {
                         ^~
If I then try to silence this warning with the proper _Pragma directive, in
clear, like in the following code, it works as expected as in the compiler
doesn't complain any longer:

    int test2(int val) {
        switch (val) {
                    _Pragma("GCC diagnostic push")
                    _Pragma("GCC diagnostic ignored \"-Wswitch-unreachable\"")
                    if (!x) {
                    _Pragma("GCC diagnostic pop")
            case 1:     return 10;
                    }
        }

        return 0;
    }

If I then try to to hide the pragmas within 2 macros, like in the following
code, it still works:

    #define B _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored
\"-Wswitch-unreachable\"")
    #define E _Pragma("GCC diagnostic pop")

    int test3(int val) {
        switch (val) {
                    B if (!x) E {
            case 1:     return 10;
                    }
        }

        return 0;
    }

However, if now I want to turn the whole "B if (!x) E" statement into a define
of its own, like in the following code, it doesn't work any longer.

    #define X() B if (!x) E

    int test4(int val) {
        switch (val) {
                    X() {
            case 1:     return 10;
                    }
        }

        return 0;
    }

pragmatest.cpp: In function ‘int test4(int)’:
pragmatest.cpp:39:23: warning: statement will never be executed
[-Wswitch-unreachable]
     #define X() B if (!x) E
                       ^~
pragmatest.cpp:43:21: note: in expansion of macro ‘X’
                     X() {
                     ^

This looked quite odd, and at first thought I couldn't figure out what was
going on, but then I thought of using a layer of indirection around the pragma
macros, thinking it might have something to do with secondary expansion, so I
tried the following code, but still no luck.

    #define Y(x) x
    #define X2() Y(B) if (!x) Y(E)
    int test5(int val) {
        switch (val) {
                    X2() {
            case 1:     return 10;
                    }
        }

        return 0;
    }

pragmatest.cpp: In function ‘int test5(int)’:
pragmatest.cpp:52:27: warning: statement will never be executed
[-Wswitch-unreachable]
     #define X2() Y(B) if (!x) Y(E)
                           ^~
pragmatest.cpp:55:21: note: in expansion of macro ‘X2’
                     X2() {
                     ^~

So I tried something which in my mind wouldn't make sense at all - notice that
I wrapped the x **variable** in the Y() macro - but what did I have to lose
anyway? But the following code still (unsurprinsigly?) didn't work:

    #define X3() Y(B) if (!Y(x)) Y(E)
    int test6(int val) {
        switch (val) {
                    X3() {
            case 1:     return 10;
                    }
        }

        return 0;
    }

pragmatest.cpp: In function ‘int test6(int)’:
pragmatest.cpp:63:27: warning: statement will never be executed
[-Wswitch-unreachable]
     #define X3() Y(B) if (!Y(x)) Y(E)
                           ^
pragmatest.cpp:66:21: note: in expansion of macro ‘X3’
                     X3() {
                     ^~

However this time around the warning message gave me a hint! Why would the
compiler complain only about the exclamation mark not being reachable? So I
tried the following... and it worked!

    #define X4() Y(B) if (Y(!)x) Y(E)
    int test7(int val) {
        switch (val) {
                    X4() {
            case 1:     return 10;
                    }
        }

        return 0;
    }

That code above makes the compiler stay silent, against all odds.

So I thought: let's see if removing the Y() wrapping around the pragma macros
still works. Nope, it didn't.

    #define X5() B if (Y(!)x) E
    int test8(int val) {
        switch (val) {
                    X5() {
            case 1:     return 10;
                    }
        }

        return 0;
    }

pragmatest.cpp: In function ‘int test8(int)’:
pragmatest.cpp:85:26: warning: statement will never be executed
[-Wswitch-unreachable]
     #define X5() B if (Y(!)x) E
                          ^
pragmatest.cpp:51:18: note: in definition of macro ‘Y’
     #define Y(x) x
                  ^
pragmatest.cpp:88:21: note: in expansion of macro ‘X5’
                     X5() {
                     ^~

Again, the compiler indicated that the error has to do with the exclamation
mark.

Reply via email to