On Mon, Apr 07, 2025 at 01:58:08PM -0400, Marek Polacek wrote:
> On Wed, Feb 12, 2025 at 08:27:37PM -0500, Lewis Hyatt wrote:
> > Hello-
> >
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118838
> >
> > This patch addresses the issue mentioned in the PR (another instance of
> > _Pragma string location issues). bootstrap + regtest all languages on
> > aarch64 looks good. Is it OK please for now or for stage 1? Note, it is not
> > a regression, since this never worked in C or C++ frontends; but on the
> > other hand, r15-4505 for GCC 15 fixed some related issues, so it could be
> > nice if this one gets in along with it. Thanks!
> >
> > -Lewis
> >
> > -- >8 --
> >
> > 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.
> > ---
> > libcpp/errors.cc | 10 +++++++++
> > libcpp/include/cpplib.h | 5 +++++
> > gcc/c-family/c-lex.cc | 7 +++++-
> > .../cpp/pragma-diagnostic-loc-2.c | 15 +++++++++++++
> > gcc/testsuite/g++.dg/gomp/macro-4.C | 8 +++----
> > gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c | 22 +++++++++++--------
> > gcc/testsuite/gcc.dg/gomp/macro-4.c | 8 +++----
> > 7 files changed, 57 insertions(+), 18 deletions(-)
> > create mode 100644 gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
> >
> > 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. */
>
> I don't love duplicating the comment like this, it's going to get out of sync.
>
> > +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
> > 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)
>
> I think checking == UNKNOWN_LOCATION is clearer.
>
> > + fe_loc = loc;
> >
> > space = name = (const unsigned char *) "";
> >
> > diff --git a/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
> > b/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
> > new file mode 100644
> > index 00000000000..e7e8cf23759
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
> > @@ -0,0 +1,15 @@
> > +/* { dg-do compile } */
> > +/* { dg-additional-options "-Wunknown-pragmas" } */
> > +
> > +/* PR 118838 */
>
> Usually this would be the first line and also mention "c/".
>
> But those comments are details. I think the patch is OK for GCC 16.
>
> Thanks,
> Marek
>
Thanks very much for the review. I have pushed the below version with your
suggested changes as r16-179.
-Lewis
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.
diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc
index e450c9a57f0..fef6ae6f457 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 == UNKNOWN_LOCATION)
+ fe_loc = loc;
space = name = (const unsigned char *) "";
diff --git a/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
b/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
new file mode 100644
index 00000000000..734da215470
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c
@@ -0,0 +1,15 @@
+/* PR c/118838 */
+/* { dg-do compile } */
+/* { dg-additional-options "-Wunknown-pragmas" } */
+
+/* Make sure the warnings are suppressed as expected. */
+
+/* The tokens need to be all on the same line here. */
+_Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic ignored
\"-Wunknown-pragmas\"") _Pragma ("__unknown__") _Pragma ("GCC diagnostic pop")
+
+#define MACRO \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wunknown-pragmas\"") \
+ _Pragma ("__unknown__") \
+ _Pragma ("GCC diagnostic pop")
+MACRO
diff --git a/gcc/testsuite/g++.dg/gomp/macro-4.C
b/gcc/testsuite/g++.dg/gomp/macro-4.C
index dcc8bcbc8e5..5aa6d97c660 100644
--- a/gcc/testsuite/g++.dg/gomp/macro-4.C
+++ b/gcc/testsuite/g++.dg/gomp/macro-4.C
@@ -3,7 +3,7 @@
// { dg-options "-fopenmp -Wunknown-pragmas" }
#define p _Pragma ("omp parallel")
-#define omp_p _Pragma ("omp p")
+#define omp_p _Pragma ("omp p") // { dg-warning "ignoring '#pragma
omp _Pragma'" }
void bar (void);
@@ -12,18 +12,18 @@ foo (void)
{
#pragma omp p // { dg-warning "-:ignoring '#pragma omp _Pragma'" }
bar ();
- omp_p // { dg-warning "-:ignoring '#pragma omp
_Pragma'" }
+ omp_p // { dg-note "in expansion of macro 'omp_p'" }
bar ();
}
#define parallel serial
-#define omp_parallel _Pragma ("omp parallel")
+#define omp_parallel _Pragma ("omp parallel") // { dg-warning "ignoring
'#pragma omp serial'" }
void
baz (void)
{
#pragma omp parallel // { dg-warning "-:ignoring '#pragma omp serial'" }
bar ();
- omp_parallel // { dg-warning "-:ignoring '#pragma omp serial'" }
+ omp_parallel // { dg-note "in expansion of macro 'omp_parallel'" }
bar ();
}
diff --git a/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c
b/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c
index 06a244e097d..f3c790195e1 100644
--- a/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c
+++ b/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c
@@ -8,21 +8,25 @@
#pragma unknown1 /* { dg-warning "-:unknown1" "unknown1" } */
#define COMMA ,
-#define FOO(x) x
-#define BAR(x) _Pragma("unknown_before") x
-#define BAZ(x) x _Pragma("unknown_after")
+#define FOO(x) x /* { dg-note "in definition of macro 'FOO'" } */
-int _Pragma("unknown2") bar1; /* { dg-warning "-:unknown2" "unknown2" } */
+#define BAR1(x) _Pragma("unknown_before1") x /* { dg-warning
"unknown_before1" } */
+#define BAR2(x) _Pragma("unknown_before2") x /* { dg-warning
"unknown_before2" } */
-FOO(int _Pragma("unknown3") bar2); /* { dg-warning "-:unknown3" "unknown3" } */
+#define BAZ1(x) x _Pragma("unknown_after1") /* { dg-warning "unknown_after1"
} */
+#define BAZ2(x) x _Pragma("unknown_after2") /* { dg-warning "unknown_after2"
} */
-int BAR(bar3); /* { dg-warning "-:unknown_before" "unknown_before 1" } */
+int _Pragma("unknown2") bar1; /* { dg-warning "unknown2" "unknown2" } */
-BAR(int bar4); /* { dg-warning "-:unknown_before" "unknown_before 2" } */
+FOO(int _Pragma("unknown3") bar2); /* { dg-warning "unknown3" "unknown3" } */
-int BAZ(bar5); /* { dg-warning "-:unknown_after" "unknown_after 1" } */
+int BAR1(bar3); /* { dg-note "in expansion of macro 'BAR1'" } */
-int BAZ(bar6;) /* { dg-warning "-:unknown_after" "unknown_after 2" } */
+BAR2(int bar4); /* { dg-note "in expansion of macro 'BAR2'" } */
+
+int BAZ1(bar5); /* { dg-note "in expansion of macro 'BAZ1'" } */
+
+int BAZ2(bar6;) /* { dg-note "in expansion of macro 'BAZ2'" } */
FOO(int bar7; _Pragma("unknown4")) /* { dg-warning "-:unknown4" "unknown4" } */
diff --git a/gcc/testsuite/gcc.dg/gomp/macro-4.c
b/gcc/testsuite/gcc.dg/gomp/macro-4.c
index a4ed9a3980a..961c599f2fe 100644
--- a/gcc/testsuite/gcc.dg/gomp/macro-4.c
+++ b/gcc/testsuite/gcc.dg/gomp/macro-4.c
@@ -3,7 +3,7 @@
/* { dg-options "-fopenmp -Wunknown-pragmas" } */
#define p _Pragma ("omp parallel")
-#define omp_p _Pragma ("omp p")
+#define omp_p _Pragma ("omp p") /* { dg-warning "ignoring '#pragma
omp _Pragma'" } */
void bar (void);
@@ -12,18 +12,18 @@ foo (void)
{
#pragma omp p /* { dg-warning "-:ignoring '#pragma omp _Pragma'" } */
bar ();
- omp_p /* { dg-warning "-:ignoring '#pragma omp
_Pragma'" } */
+ omp_p /* { dg-note "in expansion of macro 'omp_p'" }
*/
bar ();
}
#define parallel serial
-#define omp_parallel _Pragma ("omp parallel")
+#define omp_parallel _Pragma ("omp parallel") /* { dg-warning "ignoring
'#pragma omp serial'" } */
void
baz (void)
{
#pragma omp parallel /* { dg-warning "-:ignoring '#pragma omp serial'" } */
bar ();
- omp_parallel /* { dg-warning "-:ignoring '#pragma omp serial'" } */
+ omp_parallel /* { dg-note "in expansion of macro 'omp_parallel'" }
*/
bar ();
}
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 3bf33ab4884..7c147ae5847 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -1169,6 +1169,8 @@ 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;
+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