Xarn
Xarn

Reputation: 3561

G++ ignores _Pragma diagnostic ignored

I am trying to disable g++ warnings in code expanded from macros. By my understanding, _Pragma should follow macro usage and this should not trigger Wparentheses when being compiled with g++:

#include <stdio.h>

#define TEST(expr) \
    int a = 1; \
    _Pragma( "GCC diagnostic push" ) \
    _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) \
    if (a <= expr) { \
        printf("filler\n"); \
    } \
    _Pragma( "GCC diagnostic pop" )

int main(){
    int b = 2, c = 3;
    TEST(b == c);
}

When I compile this with g++, I get Wparentheses warning, which I am trying to disable.

xarn@DESKTOP-B2A3CNC:/mnt/c/ubuntu$ g++ -Wall -Wextra test3.c
test3.c: In function ‘int main()’:
test3.c:8:11: warning: suggest parentheses around comparison in operand of ‘==’ [-Wparentheses]
     if (a <= expr) { \
           ^
test3.c:15:5: note: in expansion of macro ‘TEST’
     TEST(b == c);
     ^

However it works as expected when using gcc:

xarn@DESKTOP-B2A3CNC:/mnt/c/ubuntu$ gcc -Wall -Wextra test3.c
test3.c: In function ‘main’:
test3.c:16:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

I am using g++ version 4.8.5.

Upvotes: -1

Views: 1014

Answers (3)

FeRD
FeRD

Reputation: 2094

Xarn's answer was very helpful in working out why we were hitting the same issues with our macros when compiling with g++ < 9.0, but fortunately I'm stubborn and don't take "the only solution" for an answer. Some more digging revealed that there is a workaround for affected versions of GCC.

One of the original 2012 reports for this issue at GNU's bugzilla included an offhand mention from the reporter, that _Pragma() would be processed as expected if they added either -save-temps or -no-integrated-cpp to the compile command.

Turns out, either of those options cause g++ NOT to run in its default streamlined mode, which folds the preprocessing and compiling stages together into a single pass. From the man page for g++ 9.1.1:

    -no-integrated-cpp

       Perform preprocessing as a separate pass before compilation.  By
       default, GCC performs preprocessing as an integrated part of input
       tokenization and parsing.  If this option is provided, the
       appropriate language front end (cc1, cc1plus, or cc1obj for C, C++,
       and Objective-C, respectively) is instead invoked twice, once for
       preprocessing only and once for actual compilation of the
       preprocessed input.  This option may be useful in conjunction with
       the -B or -wrapper options to specify an alternate preprocessor or
       perform additional processing of the program source between normal
       preprocessing and compilation.

Which means that adding -no-integrated-cpp does indeed work around the _Pragma() bug in every affected version of GCC we've tested — so far that's 5.4, 7.3, and I believe 8.1 — but otherwise has no effect on the final results of the build. (One can deduce from this that the _Pragma() bug was introduced with and by that single-pass streamlining.)

The only real tradeoff is that compilation is indeed a bit slower, if you build with that option enabled. While that's certainly worth it when your GCC is one of the affected versions, we're using a conditional in our CMake build setup to ensure -no-integrated-cpp is only set when necessary:

#### Work around a GCC < 9 bug with handling of _Pragma() in macros
#### See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND
    (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS "9.0.0"))
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-integrated-cpp")
endif()

(Substitute appropriately modern calls to target_compile_options() for the ugly brute-forcing of CMAKE_CXX_FLAGS, if your CMake setup is better than ours.)

Upvotes: 1

Xarn
Xarn

Reputation: 3561

There are long-standing bugs in g++ handling of _Pragmas, that are not present when using the gcc front-end. The only solution is to either go forward to a sufficiently modern version of g++ (IIRC 6+), or to disable the warning for the entire TU.

Upvotes: 1

dodo951
dodo951

Reputation: 454

Typically you use warning suppression only to deal with unavoidable warning coming from third-party code so they won't clutter compilation logs. In your case it would be better to

1) use regular function because macros are evil

2) deal with warning by adding round brackets around potentially broken expression

if (a <= (expr)) { 

Upvotes: 0

Related Questions