https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88475
Ryan Egesdahl <ryan.egesdahl at mongodb dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |ryan.egesdahl at mongodb dot com --- Comment #6 from Ryan Egesdahl <ryan.egesdahl at mongodb dot com> --- The actual bug here appears to be the fact that "gcc -E" (which I believe invokes "cpp"?) has different behavior than the integrated preprocessor. If you compile the code in the initial report with just "gcc", it works irrespective of passing "-fdirectives-only" to the compiler. A different way of demonstrating the problem looks like this: test.cpp: #define expand(x) x #define test(...) \ expand(_test_2(__VA_ARGS__)) #define _test_2(Expression) \ doSomething((Expression)) template <typename T> inline bool doSomething( const T& testOK) { if (!testOK) { return false; } return true; } int main() { bool condition = true; return test(!condition || condition == condition); } The above compiles correctly with this: $ g++ -Wall test.cpp -o test However, this fails: $ g++ -Wall -E test.cpp -o test.ii $ g++ -fpreprocessed -fdirectives-only -Wall -c test.ii -o test test.cpp: In function ‘int main()’: test.cpp:21:49: warning: self-comparison always evaluates to true [-Wtautological-compare] return test(!condition || condition == condition); As does this: $ g++ -fdirectives-only -Wall -c test.ii -o test $ g++ -fpreprocessed -Wall -c test.ii -o test test.cpp: In function ‘int main()’: test.cpp:21:41: warning: self-comparison always evaluates to true [-Wtautological-compare] return test(!condition || condition == condition); ~~~~~~~~~~^~~~~~~~~~~~ test.cpp:21:12: error: ‘test’ was not declared in this scope return test(!condition || condition == condition); ^~~~ I understand (from testing) that not passing -fdirectives-only is the actual cause of the behavior in my test case; however, it is not immediately obvious why passing -fdirectives-only should be necessary with both the compiler and preprocessor, nor does the documentation state so. The point is that the integrated compiler and "gcc -E" (or cpp) behave differently. Most build wrappers like ccache and icecc (when ICECC_REMOTE_CPP is enabled) work by taking a gcc command and splitting it into separate preprocessing and compilation steps, which involves adding -E to the flags for preprocessing and -c for compiling, then passing the preprocessing results to the compiler. Because "gcc -E" and the integrated compiler behave differently, some builds fail with separate preprocessing and compilation steps that otherwise would have succeeded with a single step. The lack of documentation around -fdirectives-only and that it must be passed to the compiler (and that it implies -fpreprocessed to the compiler, for that matter) is making the confusion worse. To resolve this report, GCC should not behave differently depending on how you preprocess source. My personal thought is that "gcc -E" should invoke the internal preprocessor and just stop before compiling. Also, the documentation for -fdirectives-only needs to be improved (and maybe added it to the compiler documentation?) to make clear that the option needs to be passed to the compiler as well, and that passing it to the compiler with no preprocessed source is effectively a no-op.