When the preprocessor does not understand the pragma inside _Pragma it calls cb_def_pragma to print it (converting it to '#pragma'). Unfortunately that function uses puts() to print the pragma directly to file. If we are within a macro being expanded inside another macro then this will results in all pragma within that macro being expanded at the top instead of at their original location within the macro. For example I would expect the following test to pass: /* { dg-do assemble } * { dg-additional-options "-save-temps -Wall" } */ extern int b; #define OUTPUT(stmt) \ stmt #define WITH_PRAGMA() \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\""); \ a--; \ _Pragma("GCC diagnostic pop") int main() { int a; if (b) { b++; } OUTPUT( else { b--; WITH_PRAGMA(); } ) } Instead with trunk gcc I get: test.c: In function 'main': test.c:28:3: error: 'else' without a previous 'if' Because the pragma statements are printed right at the beginning of output instead of where WITH_PRAGMA is.
I think there's another bug like this; forget its number right now though...
I found 69543 which looks similar but is different (and fixed): the cause of the bug is different and it applies to the first level of a macro, while this bug requires 2 levels of macro to show up.
Created attachment 46384 [details] _Pragma tests These all yield different results, the first two won't compile but fail on different lines, which is a bit strange, as the preprocessor output doesn't appear to change (e.g. if only doing -E). The last one compiles, but obviously just because it omits the pragmas. GCC10 and GCC7 behave both the same with this test setup, so I suspect this is a long standing feature and/or issue. gcc -Wall -Wextra -c pragma.c gcc -Wall -Wextra -save-temps -c pragma.c gcc -Wall -Wextra -save-temps -DNOPRAGMA -c pragma.c
If I look at the 'gcc -E' output, the order is reverted: #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wall" #pragma GCC diagnostic pop else { b--; ; ; a--; ; } this should be instead: else { b--; #pragma GCC diagnostic push ; #pragma GCC diagnostic ignored "-Wall" ; a--; #pragma GCC diagnostic pop ; } I did observe the same in PR102409 – see analysis there. But contrary to the issue in the other PR, the patch there does not solve the issue in this PR. Additionally, for 'GCC diagnostic' there might be a column issue as discussed in PR91669 comment 3.
The problem is that the pragma is not known/registered. In that case, when calling libcpp/directives.c's do_pragma, the result is p == NULL and thus: if (p) ... else if (pfile->cb.def_pragma) ... pfile->cb.def_pragma (pfile, pfile->directive_line); the latter immediately prints the '#pragma ...' I think what needs to be done is if (p == NULL && pfile->state.in_directive) to create a new pragma on the fly and store it in pfile->directive_result to use it later. * * * Side note: For 'gcc -E c-c++-common/gomp/pragma-1.c' the same issue occurs, but if one adds -fopenmp, p != NULL and everything is fine.
Created attachment 51700 [details] Draft patch for the 'gcc -E' / 'gcc -save-temps' issue This solves the -E / -save-temps preprocessing issue. For the non -E issue, it could be the issue described at PR 91669.
(In reply to Tobias Burnus from comment #6) > Created attachment 51700 [details] > Draft patch for the 'gcc -E' / 'gcc -save-temps' issue > > This solves the -E / -save-temps preprocessing issue. > > For the non -E issue, it could be the issue described at PR 91669. Regarding "-E": Actually, looking at PR103165 comment 2, I note that for the example there 'clang -E' outputs: "hello; \"\" _Pragma(\"GCC diagnostic pop\") world;" that is: While the macros are replaced, the (unknown) _Pragma remains as _Pragma - such that it is then later only processed when running the compiler. No idea whether that makes sense or not not - just as observation.
(In reply to Tobias Burnus from comment #7) > Regarding "-E": Actually, looking at PR103165 comment 2, I note that for the > example there 'clang -E' outputs: > > "hello; \"\" _Pragma(\"GCC diagnostic pop\") world;" > > that is: While the macros are replaced, the (unknown) _Pragma remains as > _Pragma - such that it is then later only processed when running the > compiler. > > No idea whether that makes sense or not not - just as observation. This issue was indeed fixed by r12-5454, the fix for PR103165. I will get a testcase added and then close this one. The testcase will be a tweaked version of the original one from this PR. It needs to use a different _Pragma, because nowadays, '#pragma GCC diagnostic' is recognized by the preprocessor. The existing c-c++-common/gomp/pragma-2.c provides coverage for that case. '#pragma GCC unroll' is a useful new testcase, being another pragma that is explicitly ignored during preprocess-only modes.
The master branch has been updated by Lewis Hyatt <lhyatt@gcc.gnu.org>: https://gcc.gnu.org/g:d8e08ba9396b1f7da50011468f260250b7afaab7 commit r14-4186-gd8e08ba9396b1f7da50011468f260250b7afaab7 Author: Lewis Hyatt <lhyatt@gmail.com> Date: Fri Aug 25 15:57:19 2023 -0400 testsuite: Add test for already-fixed issue with _Pragma expansion [PR90400] The PR was fixed by r12-5454. Since the fix was somewhat incidental, although related, add a testcase from PR90400 too before closing it out. gcc/testsuite/ChangeLog: PR preprocessor/90400 * c-c++-common/cpp/pr90400.c: New test.
Marking it fixed now that the testcase is added.
*** Bug 91517 has been marked as a duplicate of this bug. ***