diff mbox series

[RFC,v2] libcpp: adjust pedwarn handling

Message ID 20240905204621.3023803-1-jason@redhat.com
State New
Headers show
Series [RFC,v2] libcpp: adjust pedwarn handling | expand

Commit Message

Jason Merrill Sept. 5, 2024, 8:42 p.m. UTC
On 8/28/24 12:44 PM, Joseph Myers wrote:
> On Wed, 28 Aug 2024, Jason Merrill wrote:
> 
>> Tested x86_64-pc-linux-gnu.  Any objections?  Should I change all the other
>> instances of
>>
>> if (CPP_PEDANTIC...
>>    cpp_error (...CPP_DL_PEDWARN
>>
>> the same way?
> Yes, I think that's a good change.

Done.

> A followup question might be whether cases such as the unchanged code in
> 
>> -      if (!CPP_OPTION (pfile, binary_constants)
>> -	  && CPP_PEDANTIC (pfile))
>> -	cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
>> -			     CPP_OPTION (pfile, cplusplus)
>> -			     ? N_("binary constants are a C++14 feature "
>> -				  "or GCC extension")
>> -			     : N_("binary constants are a C23 feature "
>> -				  "or GCC extension"));
>> +      if (!CPP_OPTION (pfile, binary_constants))
>> +	cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, virtual_location, 0,
>> +				  CPP_OPTION (pfile, cplusplus)
>> +				  ? N_("binary constants are a C++14 feature "
>> +				       "or GCC extension")
>> +				  : N_("binary constants are a C23 feature "
>> +				       "or GCC extension"));
>>         else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)
>>   	cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT,
>>   			       virtual_location, 0,
> could be refactored to reduce duplication (the C front end has pedwarn_c11
> for such cases of features added in C23, that can be a pedwarn-if-pedantic
> up to C11, or a warning with -Wc11-c23-compat).  Though libcpp handling
> both C and C++, and the use of conditionals such as CPP_OPTION (pfile,
> binary_constants) for individual features, might make that hard.

As mentioned below, I'd like to leave such refactoring to someone else.

Tested x86_64-pc-linux-gnu.  Any objections?

-- 8< --

Using cpp_pedwarning (CPP_W_PEDANTIC instead of if (CPP_PEDANTIC cpp_error
lets users suppress these diagnostics with
 #pragma GCC diagnostic ignored "-Wpedantic".

This patch changes all instances of the cpp_error (CPP_DL_PEDWARN to
cpp_pedwarning.  In cases where the extension appears in a later C++
revision, we now condition the warning on the relevant -Wc++??-extensions
flag instead of -Wpedantic; in such cases often the if (CPP_PEDANTIC) check
is retained to preserve the default non-warning behavior.

I didn't attempt to adjust the warning flags for the C compiler, since it
seems to follow a different system than C++.

The CPP_PEDANTIC check is also kept in _cpp_lex_direct to avoid an ICE in
the self-tests from cb.diagnostics not being initialized.

While working on testcases for these changes I noticed that the c-c++-common
tests are not run with -pedantic-errors by default like the gcc.dg and
g++.dg directories are.  And if I specify -pedantic-errors with dg-options,
the default -std= changes from c++?? to gnu++??, which interferes with some
other pedwarns.  So two of the tests are C++-only.

libcpp/ChangeLog:

	* include/cpplib.h (enum cpp_warning_reason): Add
	CPP_W_CXX{14,17,20,23}_EXTENSIONS.
	* charset.cc (_cpp_valid_ucn, convert_hex, convert_oct)
	(convert_escape, narrow_str_to_charconst): Use cpp_pedwarning
	instead of cpp_error for pedwarns.
	* directives.cc (directive_diagnostics, _cpp_handle_directive)
	(do_line, do_elif): Likewise.
	* expr.cc (cpp_classify_number, eval_token): Likewise.
	* lex.cc (skip_whitespace, maybe_va_opt_error)
	(_cpp_lex_direct): Likewise.
	* macro.cc (_cpp_arguments_ok): Likewise.
	(replace_args): Use -Wvariadic-macros for pedwarn about
	empty macro arguments.

gcc/c-family/ChangeLog:

	* c.opt: Add CppReason for Wc++{14,17,20,23}-extensions.
	* c-pragma.cc (handle_pragma_diagnostic_impl): Don't check
	OPT_Wc__23_extensions.

gcc/testsuite/ChangeLog:

	* c-c++-common/pragma-diag-17.c: New test.
	* g++.dg/cpp0x/va-opt1.C: New test.
	* g++.dg/cpp23/named-universal-char-escape3.C: New test.
---
 gcc/c-family/c.opt                            |  8 +-
 libcpp/include/cpplib.h                       |  4 +
 gcc/c-family/c-pragma.cc                      |  2 -
 gcc/testsuite/c-c++-common/pragma-diag-17.c   | 25 ++++++
 gcc/testsuite/g++.dg/cpp0x/va-opt1.C          | 18 +++++
 .../cpp23/named-universal-char-escape3.C      | 19 +++++
 libcpp/charset.cc                             | 65 +++++++++-------
 libcpp/directives.cc                          | 78 +++++++++++--------
 libcpp/expr.cc                                | 77 ++++++++++--------
 libcpp/lex.cc                                 | 24 +++---
 libcpp/macro.cc                               | 14 ++--
 11 files changed, 213 insertions(+), 121 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pragma-diag-17.c
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/va-opt1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/named-universal-char-escape3.C


base-commit: d9d34f9a91371dea4bab0b54b2d7f762a6cc23e0
diff mbox series

Patch

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 491aa02e1a3..f3b0d0e2d11 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -487,19 +487,19 @@  C++ ObjC++ Var(warn_cxx11_extensions) Warning Init(1)
 Warn about C++11 constructs in code compiled with an older standard.
 
 Wc++14-extensions
-C++ ObjC++ Var(warn_cxx14_extensions) Warning Init(1)
+C++ ObjC++ Var(warn_cxx14_extensions) Warning Init(1) CppReason(CPP_W_CXX14_EXTENSIONS)
 Warn about C++14 constructs in code compiled with an older standard.
 
 Wc++17-extensions
-C++ ObjC++ Var(warn_cxx17_extensions) Warning Init(1)
+C++ ObjC++ Var(warn_cxx17_extensions) Warning Init(1) CppReason(CPP_W_CXX17_EXTENSIONS)
 Warn about C++17 constructs in code compiled with an older standard.
 
 Wc++20-extensions
-C++ ObjC++ Var(warn_cxx20_extensions) Warning Init(1)
+C++ ObjC++ Var(warn_cxx20_extensions) Warning Init(1) CppReason(CPP_W_CXX20_EXTENSIONS)
 Warn about C++20 constructs in code compiled with an older standard.
 
 Wc++23-extensions
-C++ ObjC++ Var(warn_cxx23_extensions) Warning Init(1)
+C++ ObjC++ Var(warn_cxx23_extensions) Warning Init(1) CppReason(CPP_W_CXX23_EXTENSIONS)
 Warn about C++23 constructs in code compiled with an older standard.
 
 Wc++26-extensions
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index d76817c94fc..e045152d6ab 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -699,6 +699,10 @@  enum cpp_warning_reason {
   CPP_W_C11_C23_COMPAT,
   CPP_W_CXX11_COMPAT,
   CPP_W_CXX20_COMPAT,
+  CPP_W_CXX14_EXTENSIONS,
+  CPP_W_CXX17_EXTENSIONS,
+  CPP_W_CXX20_EXTENSIONS,
+  CPP_W_CXX23_EXTENSIONS,
   CPP_W_EXPANSION_TO_DEFINED,
   CPP_W_BIDIRECTIONAL,
   CPP_W_INVALID_UTF8,
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index bb867eb995a..ed2a7a00e9e 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -964,8 +964,6 @@  handle_pragma_diagnostic_impl ()
   unsigned int option_index = find_opt (data.option_str + 1, lang_mask);
 
   if (early && !(c_option_is_from_cpp_diagnostics (option_index)
-		 /* For interpret_float.  */
-		 || option_index == OPT_Wc__23_extensions
 		 || option_index == OPT_Wunknown_pragmas))
     return;
 
diff --git a/gcc/testsuite/c-c++-common/pragma-diag-17.c b/gcc/testsuite/c-c++-common/pragma-diag-17.c
new file mode 100644
index 00000000000..29aebe75bc4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pragma-diag-17.c
@@ -0,0 +1,25 @@ 
+/* Test silencing the numeric constant extension pedwarns.  */
+/* { dg-options "-pedantic-errors" } */
+/* { dg-additional-options -fext-numeric-literals { target c++14 } } */
+
+#pragma GCC diagnostic push
+
+void f()
+{
+  2.0j;				/* { dg-error "imaginary" } */
+  1.0dd;			/* { dg-error "decimal float" } */
+  1.0d;				/* { dg-error "double constant" } */
+  0b0100;	   /* { dg-error "binary constant" "" { target { ! c++14 } } */
+#pragma GCC diagnostic ignored "-Wpedantic"
+  2.0j;
+  1.0dd;
+  1.0d;
+
+#ifdef __cplusplus
+#pragma GCC diagnostic ignored "-Wc++14-extensions"
+#endif
+  0b0100;
+
+  1.0K; /* { dg-bogus {fixed-point types not supported in C\+\+} "" { xfail c++ } } */
+	/* { dg-error {fixed-point types not supported for this target} "" { target { c && { ! fixed_point } } } .-1 } */
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/va-opt1.C b/gcc/testsuite/g++.dg/cpp0x/va-opt1.C
new file mode 100644
index 00000000000..e22ad984bdb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/va-opt1.C
@@ -0,0 +1,18 @@ 
+/* Test silencing C++20 va_opt pedwarns.  */
+
+#pragma GCC diagnostic push
+
+void f()
+{
+#define MAC1(FMT, ...) __builtin_printf ((FMT) __VA_OPT__(,) __VA_ARGS__)
+  /* { dg-error "variadic macro" "" { target { c++98_only } } .-1 } */
+  /* { dg-error "VA_OPT" "" { target { c++17_down } } .-2 } */
+  MAC1("foo"); /* { dg-error "empty macro arguments" "" { target c++98_only } } */
+  /* { dg-error "at least one argument" "" { target c++17_down } .-1 } */
+
+#pragma GCC diagnostic ignored "-Wvariadic-macros"
+#pragma GCC diagnostic ignored "-Wc++20-extensions"
+
+#define MAC2(FMT, ...) __builtin_printf ((FMT) __VA_OPT__(,) __VA_ARGS__)
+  MAC2("foo");
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/named-universal-char-escape3.C b/gcc/testsuite/g++.dg/cpp23/named-universal-char-escape3.C
new file mode 100644
index 00000000000..03c58b31ad3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/named-universal-char-escape3.C
@@ -0,0 +1,19 @@ 
+/* Test silencing C++23 #warning and P2071 escape pedwarns.  */
+#pragma GCC diagnostic push
+
+void f() {
+
+#warning foo			/* { dg-warning foo } */
+/* { dg-error "extension" "" { target { ! c++23 } } .-1 } */
+
+'\x{0f}';		/* { dg-error "delimited escape" "" { target { ! c++23 } } }*/
+"\N{OHM SIGN}";	/* { dg-error "named universal character" "" { target { ! c++23 } } }*/
+
+#pragma GCC diagnostic ignored "-Wc++23-extensions"
+
+#warning foo			/* { dg-warning foo } */
+
+'\x{0f}';
+"\N{OHM SIGN}";
+
+}
diff --git a/libcpp/charset.cc b/libcpp/charset.cc
index fd57f613980..32b6fd5b5a4 100644
--- a/libcpp/charset.cc
+++ b/libcpp/charset.cc
@@ -1633,9 +1633,11 @@  _cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr,
 	      else if ((!identifier_pos || strict)
 		       && !CPP_OPTION (pfile, delimited_escape_seqs)
 		       && CPP_OPTION (pfile, cpp_pedantic))
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "named universal character escapes are only valid "
-			   "in C++23");
+		cpp_pedwarning (pfile,
+				CPP_OPTION (pfile, cplusplus)
+				? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC,
+				"named universal character escapes are only "
+				"valid in C++23");
 	      if (name == str)
 		result = 0x40;
 	      else
@@ -1757,8 +1759,9 @@  _cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr,
 		   "empty delimited escape sequence");
       else if (!CPP_OPTION (pfile, delimited_escape_seqs)
 	       && CPP_OPTION (pfile, cpp_pedantic))
-	cpp_error (pfile, CPP_DL_PEDWARN,
-		   "delimited escape sequences are only valid in C++23");
+	cpp_pedwarning (pfile, (CPP_OPTION (pfile, cplusplus)
+				? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC),
+			"delimited escape sequences are only valid in C++23");
       str++;
       length = 0;
       delimited = false;
@@ -2129,10 +2132,11 @@  convert_hex (cpp_reader *pfile, const uchar *from, const uchar *limit,
 		     "empty delimited escape sequence");
 	  return from;
 	}
-     else if (!CPP_OPTION (pfile, delimited_escape_seqs)
-	      && CPP_OPTION (pfile, cpp_pedantic))
-	cpp_error (pfile, CPP_DL_PEDWARN,
-		   "delimited escape sequences are only valid in C++23");
+      else if (!CPP_OPTION (pfile, delimited_escape_seqs)
+	       && CPP_OPTION (pfile, cpp_pedantic))
+	cpp_pedwarning (pfile, (CPP_OPTION (pfile, cplusplus)
+				? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC),
+			"delimited escape sequences are only valid in C++23");
       delimited = false;
       extend_char_range (&char_range, loc_reader);
     }
@@ -2234,8 +2238,10 @@  convert_oct (cpp_reader *pfile, const uchar *from, const uchar *limit,
 	    }
 	  else if (!CPP_OPTION (pfile, delimited_escape_seqs)
 		   && CPP_OPTION (pfile, cpp_pedantic))
-	    cpp_error (pfile, CPP_DL_PEDWARN,
-		       "delimited escape sequences are only valid in C++23");
+	    cpp_pedwarning (pfile, (CPP_OPTION (pfile, cplusplus)
+				    ? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC),
+			    "delimited escape sequences are only valid "
+			    "in C++23");
 	  extend_char_range (&char_range, loc_reader);
 	}
       else
@@ -2300,20 +2306,20 @@  convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit,
 			  char_range, loc_reader, ranges);
 
     case 'x':
-      if (uneval && CPP_PEDANTIC (pfile))
-	cpp_error (pfile, CPP_DL_PEDWARN,
-		   "numeric escape sequence in unevaluated string: "
-		   "'\\%c'", (int) c);
+      if (uneval)
+	cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+			"numeric escape sequence in unevaluated string: "
+			"'\\%c'", (int) c);
       return convert_hex (pfile, from, limit, tbuf, cvt,
 			  char_range, loc_reader, ranges);
 
     case '0':  case '1':  case '2':  case '3':
     case '4':  case '5':  case '6':  case '7':
     case 'o':
-      if (uneval && CPP_PEDANTIC (pfile))
-	cpp_error (pfile, CPP_DL_PEDWARN,
-		   "numeric escape sequence in unevaluated string: "
-		   "'\\%c'", (int) c);
+      if (uneval)
+	cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+			"numeric escape sequence in unevaluated string: "
+			"'\\%c'", (int) c);
       return convert_oct (pfile, from, limit, tbuf, cvt,
 			  char_range, loc_reader, ranges);
 
@@ -2345,9 +2351,8 @@  convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit,
       break;
 
     case 'e': case 'E':
-      if (CPP_PEDANTIC (pfile))
-	cpp_error (pfile, CPP_DL_PEDWARN,
-		   "non-ISO-standard escape sequence, '\\%c'", (int) c);
+      cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+		      "non-ISO-standard escape sequence, '\\%c'", (int) c);
       c = charconsts[2];
       break;
 
@@ -2757,7 +2762,7 @@  narrow_str_to_charconst (cpp_reader *pfile, cpp_string str,
 
   if (type == CPP_UTF8CHAR)
     max_chars = 1;
-  else if (i > 1 && CPP_OPTION (pfile, cplusplus) && CPP_PEDANTIC (pfile))
+  else if (i > 1 && CPP_OPTION (pfile, cplusplus))
     {
       /* C++ as a DR since
 	 P1854R4 - Making non-encodable string literals ill-formed
@@ -2773,15 +2778,15 @@  narrow_str_to_charconst (cpp_reader *pfile, cpp_string str,
 	    {
 	      if (src_chars <= 2)
 		diagnosed
-		  = cpp_error (pfile, CPP_DL_PEDWARN,
-			       "character not encodable in a single execution "
-			       "character code unit");
+		  = cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+				    "character not encodable in a single "
+				    "execution character code unit");
 	      else
 		diagnosed
-		  = cpp_error (pfile, CPP_DL_PEDWARN,
-			       "at least one character in a multi-character "
-			       "literal not encodable in a single execution "
-			       "character code unit");
+		  = cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+				    "at least one character in a multi-"
+				    "character literal not encodable in a "
+				    "single execution character code unit");
 	      if (diagnosed && i > max_chars)
 		i = max_chars;
 	    }
diff --git a/libcpp/directives.cc b/libcpp/directives.cc
index 479f8c716e8..72b749564ab 100644
--- a/libcpp/directives.cc
+++ b/libcpp/directives.cc
@@ -381,28 +381,37 @@  directive_diagnostics (cpp_reader *pfile, const directive *dir, int indented)
      -pedantic take precedence if both are applicable.  */
   if (! pfile->state.skipping)
     {
+      bool warned = false;
       if (dir->origin == EXTENSION
-	  && !(dir == &dtable[T_IMPORT] && CPP_OPTION (pfile, objc))
-	  && CPP_PEDANTIC (pfile))
-	cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name);
-      else if (dir == &dtable[T_WARNING])
+	  && !(dir == &dtable[T_IMPORT] && CPP_OPTION (pfile, objc)))
+	warned
+	  = cpp_pedwarning (pfile, CPP_W_PEDANTIC, "#%s is a GCC extension",
+			    dir->name);
+      if (!warned && dir == &dtable[T_WARNING])
 	{
 	  if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, warning_directive))
 	    {
 	      if (CPP_OPTION (pfile, cplusplus))
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "#%s before C++23 is a GCC extension", dir->name);
+		warned
+		  = cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS,
+				    "#%s before C++23 is a GCC extension",
+				    dir->name);
 	      else
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "#%s before C23 is a GCC extension", dir->name);
+		warned
+		  = cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+				    "#%s before C23 is a GCC extension",
+				    dir->name);
 	    }
-	  else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)
-	    cpp_warning (pfile, CPP_W_C11_C23_COMPAT,
-			 "#%s before C23 is a GCC extension", dir->name);
+
+	  if (!warned && CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)
+	    warned = cpp_warning (pfile, CPP_W_C11_C23_COMPAT,
+				  "#%s before C23 is a GCC extension",
+				  dir->name);
 	}
-      else if (((dir->flags & DEPRECATED) != 0
-		|| (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc)))
-	       && CPP_OPTION (pfile, cpp_warn_deprecated))
+
+      if (((dir->flags & DEPRECATED) != 0
+	   || (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc)))
+	  && !warned)
 	cpp_warning (pfile, CPP_W_DEPRECATED,
                      "#%s is a deprecated GCC extension", dir->name);
     }
@@ -448,9 +457,9 @@  _cpp_handle_directive (cpp_reader *pfile, bool indented)
 
   if (was_parsing_args)
     {
-      if (CPP_OPTION (pfile, cpp_pedantic))
-	cpp_error (pfile, CPP_DL_PEDWARN,
-	     "embedding a directive within macro arguments is not portable");
+      cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+		      "embedding a directive within macro arguments is not "
+		      "portable");
       pfile->state.parsing_args = 0;
       pfile->state.prevent_expansion = 0;
     }
@@ -475,10 +484,10 @@  _cpp_handle_directive (cpp_reader *pfile, bool indented)
   else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM)
     {
       dir = &linemarker_dir;
-      if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed)
+      if (! CPP_OPTION (pfile, preprocessed)
 	  && ! pfile->state.skipping)
-	cpp_error (pfile, CPP_DL_PEDWARN,
-		   "style of line directive is a GCC extension");
+	cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+			"style of line directive is a GCC extension");
     }
 
   if (dir)
@@ -1016,8 +1025,9 @@  do_line (cpp_reader *pfile)
       return;
     }
 
-  if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap || wrapped))
-    cpp_error (pfile, CPP_DL_PEDWARN, "line number out of range");
+  if ((new_lineno == 0 || new_lineno > cap || wrapped)
+      && cpp_pedwarning (pfile, CPP_W_PEDANTIC, "line number out of range"))
+    ;
   else if (wrapped)
     cpp_error (pfile, CPP_DL_WARNING, "line number out of range");
 
@@ -2159,13 +2169,13 @@  do_elif (cpp_reader *pfile)
 	      && !pfile->state.skipping)
 	    {
 	      if (CPP_OPTION (pfile, cplusplus))
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "#%s before C++23 is a GCC extension",
-			   pfile->directive->name);
+		cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS,
+				"#%s before C++23 is a GCC extension",
+				pfile->directive->name);
 	      else
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "#%s before C23 is a GCC extension",
-			   pfile->directive->name);
+		cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+				"#%s before C23 is a GCC extension",
+				pfile->directive->name);
 	    }
 	  pfile->state.skipping = 1;
 	}
@@ -2198,13 +2208,13 @@  do_elif (cpp_reader *pfile)
 		      && pfile->state.skipping != skip)
 		    {
 		      if (CPP_OPTION (pfile, cplusplus))
-			cpp_error (pfile, CPP_DL_PEDWARN,
-				   "#%s before C++23 is a GCC extension",
-				   pfile->directive->name);
+			cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS,
+					"#%s before C++23 is a GCC extension",
+					pfile->directive->name);
 		      else
-			cpp_error (pfile, CPP_DL_PEDWARN,
-				   "#%s before C23 is a GCC extension",
-				   pfile->directive->name);
+			cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+					"#%s before C23 is a GCC extension",
+					pfile->directive->name);
 		    }
 		  pfile->state.skipping = skip;
 		}
diff --git a/libcpp/expr.cc b/libcpp/expr.cc
index 815eb137a99..e886bfcc02d 100644
--- a/libcpp/expr.cc
+++ b/libcpp/expr.cc
@@ -662,9 +662,9 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
 	  if (radix == 8)
 	    radix = 10;
 
-	  if (CPP_PEDANTIC (pfile))
-	    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-				 "fixed-point constants are a GCC extension");
+	  cpp_pedwarning_with_line
+	    (pfile, CPP_W_PEDANTIC, virtual_location, 0,
+	     "fixed-point constants are a GCC extension");
 	  goto syntax_ok;
 	}
       else
@@ -701,11 +701,13 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
 	  && !CPP_OPTION (pfile, extended_numbers))
 	{
 	  if (CPP_OPTION (pfile, cplusplus))
-	    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-				 "use of C++17 hexadecimal floating constant");
+	    cpp_pedwarning_with_line (pfile, CPP_W_CXX17_EXTENSIONS,
+				      virtual_location, 0, "use of C++17 "
+				      "hexadecimal floating constant");
 	  else
-	    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-				 "use of C99 hexadecimal floating constant");
+	    cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC,
+				      virtual_location, 0, "use of C99 "
+				      "hexadecimal floating constant");
 	}
 
       if (float_flag == AFTER_EXPON)
@@ -766,9 +768,10 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
       /* A suffix for double is a GCC extension via decimal float support.
 	 If the suffix also specifies an imaginary value we'll catch that
 	 later.  */
-      if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile))
-	cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-			     "suffix for double constant is a GCC extension");
+      if (result == CPP_N_MEDIUM)
+	cpp_pedwarning_with_line
+	  (pfile, CPP_W_PEDANTIC, virtual_location, 0,
+	   "suffix for double constant is a GCC extension");
 
       /* Radix must be 10 for decimal floats.  */
       if ((result & CPP_N_DFLOAT) && radix != 10)
@@ -779,15 +782,16 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
           return CPP_N_INVALID;
         }
 
-      if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile))
-	cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-			     "fixed-point constants are a GCC extension");
+      if (result & (CPP_N_FRACT | CPP_N_ACCUM))
+	cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, virtual_location, 0,
+				  "fixed-point constants are a GCC extension");
 
       if (result & CPP_N_DFLOAT)
 	{
-	  if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, dfp_constants))
-	    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-				 "decimal float constants are a C23 feature");
+	  if (!CPP_OPTION (pfile, dfp_constants))
+	    cpp_pedwarning_with_line
+	      (pfile, CPP_W_PEDANTIC, virtual_location, 0,
+	       "decimal float constants are a C23 feature");
 	  else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)
 	    cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT,
 				   virtual_location, 0,
@@ -870,12 +874,12 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
 		cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT,
 				       virtual_location, 0, message);
 	    }
-	  else if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, true_false))
+	  else if (!CPP_OPTION (pfile, true_false))
 	    {
 	      const char *message = N_("ISO C does not support literal "
 				       "%<wb%> suffixes before C23");
-	      cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-				   message);
+	      cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC,
+					virtual_location, 0, message);
 	    }
 	}
 
@@ -883,20 +887,27 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
     }
 
  syntax_ok:
-  if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
-    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-			 "imaginary constants are a GCC extension");
+  if (result & CPP_N_IMAGINARY)
+    cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, virtual_location, 0,
+			      "imaginary constants are a GCC extension");
   if (radix == 2)
     {
+      bool warned = false;
       if (!CPP_OPTION (pfile, binary_constants)
 	  && CPP_PEDANTIC (pfile))
-	cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
-			     CPP_OPTION (pfile, cplusplus)
-			     ? N_("binary constants are a C++14 feature "
-				  "or GCC extension")
-			     : N_("binary constants are a C23 feature "
-				  "or GCC extension"));
-      else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)
+	{
+	  if (CPP_OPTION (pfile, cplusplus))
+	    warned
+	      = (cpp_pedwarning_with_line
+		 (pfile, CPP_W_CXX14_EXTENSIONS, virtual_location, 0,
+		  "binary constants are a C++14 feature or GCC extension"));
+	  else
+	    warned
+	      = (cpp_pedwarning_with_line
+		 (pfile, CPP_W_PEDANTIC, virtual_location, 0,
+		  "binary constants are a C23 feature or GCC extension"));
+	}
+      if (!warned && CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0)
 	cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT,
 			       virtual_location, 0,
 			       "binary constants are a C23 feature");
@@ -1264,10 +1275,10 @@  eval_token (cpp_reader *pfile, const cpp_token *token,
 	{
 	  /* A pedantic warning takes precedence over a deprecated
 	     warning here.  */
-	  if (CPP_PEDANTIC (pfile))
-	    cpp_error_with_line (pfile, CPP_DL_PEDWARN,
-				 virtual_location, 0,
-				 "assertions are a GCC extension");
+	  if (cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC,
+					virtual_location, 0,
+					"assertions are a GCC extension"))
+	    ;
 	  else if (CPP_OPTION (pfile, cpp_warn_deprecated))
 	    cpp_warning_with_line (pfile, CPP_W_DEPRECATED, virtual_location, 0,
 				   "assertions are a deprecated extension");
diff --git a/libcpp/lex.cc b/libcpp/lex.cc
index 7f0f8d07735..86da218b5d7 100644
--- a/libcpp/lex.cc
+++ b/libcpp/lex.cc
@@ -1856,11 +1856,12 @@  skip_whitespace (cpp_reader *pfile, cppchar_t c)
       /* Just \f \v or \0 left.  */
       else if (c == '\0')
 	saw_NUL = true;
-      else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
-	cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line,
-			     CPP_BUF_COL (buffer),
-			     "%s in preprocessing directive",
-			     c == '\f' ? "form feed" : "vertical tab");
+      else if (pfile->state.in_directive)
+	cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC,
+				  pfile->line_table->highest_line,
+				  CPP_BUF_COL (buffer),
+				  "%s in preprocessing directive",
+				  c == '\f' ? "form feed" : "vertical tab");
 
       c = *buffer->cur++;
     }
@@ -2026,11 +2027,11 @@  maybe_va_opt_error (cpp_reader *pfile)
       if (!_cpp_in_system_header (pfile))
 	{
 	  if (CPP_OPTION (pfile, cplusplus))
-	    cpp_error (pfile, CPP_DL_PEDWARN,
-		       "__VA_OPT__ is not available until C++20");
+	    cpp_pedwarning (pfile, CPP_W_CXX20_EXTENSIONS,
+			    "__VA_OPT__ is not available until C++20");
 	  else
-	    cpp_error (pfile, CPP_DL_PEDWARN,
-		       "__VA_OPT__ is not available until C23");
+	    cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+			    "__VA_OPT__ is not available until C23");
 	}
     }
   else if (!pfile->state.va_args_ok)
@@ -3903,8 +3904,9 @@  _cpp_lex_direct (cpp_reader *pfile)
 		   && CPP_PEDANTIC (pfile)
 		   && ! buffer->warned_cplusplus_comments)
 	    {
-	      if (cpp_error (pfile, CPP_DL_PEDWARN,
-			     "C++ style comments are not allowed in ISO C90"))
+	      if (cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+				  "C++ style comments are not allowed "
+				  "in ISO C90"))
 		cpp_error (pfile, CPP_DL_NOTE,
 			   "(this will be reported only once per input file)");
 	      buffer->warned_cplusplus_comments = 1;
diff --git a/libcpp/macro.cc b/libcpp/macro.cc
index 352eb2e4fd9..43771d9321e 100644
--- a/libcpp/macro.cc
+++ b/libcpp/macro.cc
@@ -1117,13 +1117,13 @@  _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node
 	      && ! CPP_OPTION (pfile, va_opt))
 	    {
 	      if (CPP_OPTION (pfile, cplusplus))
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "ISO C++11 requires at least one argument "
-			   "for the \"...\" in a variadic macro");
+		cpp_pedwarning (pfile, CPP_W_CXX20_EXTENSIONS,
+				"ISO C++11 requires at least one argument "
+				"for the \"...\" in a variadic macro");
 	      else
-		cpp_error (pfile, CPP_DL_PEDWARN,
-			   "ISO C99 requires at least one argument "
-			   "for the \"...\" in a variadic macro");
+		cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+				"ISO C99 requires at least one argument "
+				"for the \"...\" in a variadic macro");
 	    }
 	  return true;
 	}
@@ -2312,7 +2312,7 @@  replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro,
 	       && ! macro->syshdr && ! _cpp_in_system_header (pfile))
 	{
 	  if (CPP_OPTION (pfile, cplusplus))
-	    cpp_pedwarning (pfile, CPP_W_PEDANTIC,
+	    cpp_pedwarning (pfile, CPP_W_VARIADIC_MACROS,
 			    "invoking macro %s argument %d: "
 			    "empty macro arguments are undefined"
 			    " in ISO C++98",