Reputation: 3561
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
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
Reputation: 3561
There are long-standing bugs in g++ handling of _Pragma
s, 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
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