Consider the following source file: test.c: --------------------------------------- #define STDC_FENV_ACCESS_ON \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wunknown-pragmas\"") \ _Pragma ("STDC FENV_ACCESS ON") \ _Pragma ("GCC diagnostic pop") STDC_FENV_ACCESS_ON --------------------------------------- GCC doesn't support pragma STDC FENV_ACCESS (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34678), but the macro should suppress the warning. This macro is useful for compat with both GCC and CLang. However the diagnostic pragmas don't seem to have any effect: $ gcc -c test-gcc.c -Wall test-gcc.c:7: warning: ignoring '#pragma STDC FENV_ACCESS' [-Wunknown-pragmas] 7 | STDC_FENV_ACCESS_ON If we avoid the macro, everything works correctly: test.c: --------------------------------------- _Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic ignored \"-Wunknown-pragmas\"") _Pragma ("STDC FENV_ACCESS ON") _Pragma ("GCC diagnostic pop") --------------------------------------- There are a few similar bug reports that are closed as RESOLVED: - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69558 Thanks in advance, Luca
Thanks, so this one is not actually about macros or the C frontend, you will see the same with C++ and also without the macro (if you put all tokens on the same line). The reason is that -Wunknown-pragmas is issued from the def_pragma() callback: directives.cc: pfile->cb.def_pragma (pfile, pfile->directive_line); and libcpp is passing pfile->directive_line to this callback, which is a location for the line as a whole and not for the specific location of the unknown pragma token. Prior to r15-4505, it wouldn't have worked anyway due to PR114423, but now it would work if pfile->directive_line were replaced by a better location. However, I don't think we can just change it here, affecting other uses of the def_pragma callback. (For example, preprocess-only mode in c-ppoutput.cc uses this location, and changing from pfile->directive_line to something like the location of the _Pragma token would change its output, in case say the _Pragma started and ended on different lines.) It seems safer to modify the warning to be issued at a better location; libcpp provides diagnostic_override_loc already to say what location should be used (the _Pragma token), but it needs a new accessor function added in order for the caller to find out what it is. Like this: ==== diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index e450c9a57f0..df84020de62 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -248,7 +248,12 @@ cb_def_pragma (cpp_reader *pfile, location_t loc) { const unsigned char *space, *name; const cpp_token *s; - location_t fe_loc = loc; + + /* If we are processing a _Pragma, LOC is not a valid location, but libcpp + will provide a good location via this function instead. */ + location_t fe_loc = cpp_get_diagnostic_override_loc (pfile); + if (!fe_loc) + fe_loc = loc; space = name = (const unsigned char *) ""; diff --git a/libcpp/errors.cc b/libcpp/errors.cc index 9621c4b66ea..d9efb6acd30 100644 --- a/libcpp/errors.cc +++ b/libcpp/errors.cc @@ -52,6 +52,16 @@ cpp_diagnostic_get_current_location (cpp_reader *pfile) } } +/* Sometimes a diagnostic needs to be generated before libcpp has been able + to generate a valid location for the current token; in that case, the + non-zero location returned by this function is the preferred one to use. */ + +location_t +cpp_get_diagnostic_override_loc (const cpp_reader *pfile) +{ + return pfile->diagnostic_override_loc; +} + /* Print a diagnostic at the given location. */ ATTRIBUTE_CPP_PPDIAG (5, 0) diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 90aa3160ebf..04d4621da3c 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -1168,6 +1168,11 @@ extern const char *cpp_probe_header_unit (cpp_reader *, const char *file, extern const char *cpp_get_narrow_charset_name (cpp_reader *) ATTRIBUTE_PURE; extern const char *cpp_get_wide_charset_name (cpp_reader *) ATTRIBUTE_PURE; +/* Sometimes a diagnostic needs to be generated before libcpp has been able + to generate a valid location for the current token; in that case, the + non-zero location returned by this function is the preferred one to use. */ +extern location_t cpp_get_diagnostic_override_loc (const cpp_reader *); + /* This function reads the file, but does not start preprocessing. It returns the name of the original file; this is the same as the input file, except for preprocessed input. This will generate at ==== I can test this sometime, some existing -Wunknown-pragmas tests will need to be tweaked for the improved locations. Given this has never worked in any version of GCC, it will probably need to wait for GCC 16 at this point.
> Given this has never worked in any version of GCC, it will probably need to wait for GCC 16 at this point No problem at all, thanks for the fix!
Patch was submitted: https://gcc.gnu.org/pipermail/gcc-patches/2025-February/675645.html
The master branch has been updated by Lewis Hyatt <lhyatt@gcc.gnu.org>: https://gcc.gnu.org/g:78673484b4055b93207eee0efd60a434b0bf96ab commit r16-179-g78673484b4055b93207eee0efd60a434b0bf96ab Author: Lewis Hyatt <lhyatt@gmail.com> Date: Tue Feb 11 13:45:41 2025 -0500 c-family: Improve location for -Wunknown-pragmas in a _Pragma [PR118838] The warning for -Wunknown-pragmas is issued at the location provided by libcpp to the def_pragma() callback. This location is cpp_reader::directive_line, which is a location for the start of the line only; it is also not a valid location in case the unknown pragma was lexed from a _Pragma string. These factors make it impossible to suppress -Wunknown-pragmas via _Pragma("GCC diagnostic...") directives on the same source line, as in the PR and the test case. Address that by issuing the warning at a better location returned by cpp_get_diagnostic_override_loc(). libcpp already maintains this location to handle _Pragma-related diagnostics internally; it was needed also to make a publicly accessible version of it. gcc/c-family/ChangeLog: PR c/118838 * c-lex.cc (cb_def_pragma): Call cpp_get_diagnostic_override_loc() to get a valid location at which to issue -Wunknown-pragmas, in case it was triggered from a _Pragma. libcpp/ChangeLog: PR c/118838 * errors.cc (cpp_get_diagnostic_override_loc): New function. * include/cpplib.h (cpp_get_diagnostic_override_loc): Declare. gcc/testsuite/ChangeLog: PR c/118838 * c-c++-common/cpp/pragma-diagnostic-loc-2.c: New test. * g++.dg/gomp/macro-4.C: Adjust expected output. * gcc.dg/gomp/macro-4.c: Likewise. * gcc.dg/cpp/Wunknown-pragmas-1.c: Likewise.
Fixed for GCC 16.