0

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.

Xarn
  • 3,460
  • 1
  • 21
  • 43
  • gcc 4.8.5 will not compile the posted source code with `gcc -Wall -Wextra test3.c`. It fails with `fatal error: iostream: No such file or directory`, as it should, since `iostream` is not a C header file. Please post the real code. – Mike Kinghan Mar 28 '17 at 10:36
  • @MikeKinghan Sorry, copy pasted from the .cpp file that spurred the question. Now it uses `printf` – Xarn Mar 28 '17 at 11:19

3 Answers3

1

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.

Xarn
  • 3,460
  • 1
  • 21
  • 43
  • I actually did manage to find a solution for affected GCC versions, see [my answer](https://stackoverflow.com/a/56703042/200794). (This was a HUGE help in pointing me in the right direction, though!) – FeRD Jul 04 '19 at 21:19
1

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

FeRD
  • 1,699
  • 15
  • 24
0

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)) { 
dodo951
  • 438
  • 4
  • 8
  • The code in question is a minimal example. In the real code, `a` is instance of a special type that uses overloaded `<=` operator to perform magic. – Xarn Mar 28 '17 at 08:54
  • 1
    As [operator overloading guideline](http://stackoverflow.com/questions/4421706/operator-overloading/4421708#4421708) suggest making overloaded operators perform magic (i guess in your case <= will return something other than bool, right?) is typically not a good idea and often indicates a logic flaw. Mixing them into macros is even worse. – dodo951 Mar 28 '17 at 09:14
  • I am fairly sure that [Catch](https://github.com/philsquared/Catch) and friends disagree. – Xarn Mar 30 '17 at 17:05