Bug 118838 - _Pragma diagnostic ignored inside macro
Summary: _Pragma diagnostic ignored inside macro
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: unknown
: P3 normal
Target Milestone: 16.0
Assignee: Not yet assigned to anyone
URL: https://gcc.gnu.org/pipermail/gcc-pat...
Keywords: diagnostic, patch
Depends on:
Blocks:
 
Reported: 2025-02-11 17:04 UTC by Luca Bacci
Modified: 2025-04-28 02:57 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2025-02-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Luca Bacci 2025-02-11 17:04:22 UTC
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
Comment 1 Lewis Hyatt 2025-02-11 23:46:17 UTC
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.
Comment 2 Luca Bacci 2025-02-12 17:18:31 UTC
> 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!
Comment 3 Lewis Hyatt 2025-02-13 01:28:45 UTC
Patch was submitted:
https://gcc.gnu.org/pipermail/gcc-patches/2025-February/675645.html
Comment 4 GCC Commits 2025-04-28 02:49:49 UTC
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.
Comment 5 Lewis Hyatt 2025-04-28 02:57:50 UTC
Fixed for GCC 16.