diff mbox series

[committed] c: Add -std=c2y, -std=gnu2y, -Wc23-c2y-compat, C2Y _Generic with type operand

Message ID 69a2bd1f-6877-6f5e-1940-3154f7471ba3@redhat.com
State New
Headers show
Series [committed] c: Add -std=c2y, -std=gnu2y, -Wc23-c2y-compat, C2Y _Generic with type operand | expand

Commit Message

Joseph Myers June 11, 2024, 11:01 p.m. UTC
The first new C2Y feature, _Generic where the controlling operand is a
type name rather than an expression (as defined in N3260), was voted
into C2Y today.  (In particular, this form of _Generic allows
distinguishing qualified and unqualified versions of a type.)  This
feature also includes allowing the generic associations to specify
incomplete and function types.

Add this feature to GCC, along with the -std=c2y, -std=gnu2y and
-Wc23-c2y-compat options to control when and how it is diagnosed.  As
usual, the feature is allowed by default in older standards modes,
subject to diagnosis with -pedantic, -pedantic-errors or
-Wc23-c2y-compat.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.

gcc/
	* doc/cpp.texi (__STDC_VERSION__): Document C2Y handling.
	* doc/invoke.texi (-Wc23-c2y-compat, -std=c2y, -std=gnu2y):
	Document options.
	(-std=gnu23): Update documentation.
	* doc/standards.texi (C Language): Document C2Y.  Update C23
	description.
	* config/rl78/rl78.cc (rl78_option_override): Handle "GNU C2Y"
	language name.
	* dwarf2out.cc (highest_c_language, gen_compile_unit_die):
	Likewise.

gcc/c-family/
	* c-common.cc (flag_isoc2y): New.
	(flag_isoc99, flag_isoc11, flag_isoc23): Update comments.
	* c-common.h (flag_isoc2y): New.
	(clk_c, flag_isoc23): Update comments.
	* c-opts.cc (set_std_c2y): New.
	(c_common_handle_option): Handle OPT_std_c2y and OPT_std_gnu2y.
	(set_std_c89, set_std_c99, set_std_c11, set_std_c17, set_std_c23):
	Set flag_isoc2y.
	(set_std_c23): Update comment.
	* c.opt (Wc23-c2y-compat, std=c2y, std=gnu2y): New.
	* c.opt.urls: Regenerate.

gcc/c/
	* c-errors.cc (pedwarn_c23): New.
	* c-parser.cc (disable_extension_diagnostics)
	(restore_extension_diagnostics): Save and restore
	warn_c23_c2y_compat.
	(c_parser_generic_selection): Handle type name as controlling
	operand.  Allow incomplete and function types subject to
	pedwarn_c23 calls.
	* c-tree.h (pedwarn_c23): New.

gcc/testsuite/
	* gcc.dg/c23-generic-1.c, gcc.dg/c23-generic-2.c,
	gcc.dg/c23-generic-3.c, gcc.dg/c23-generic-4.c,
	gcc.dg/c2y-generic-1.c, gcc.dg/c2y-generic-2.c,
	gcc.dg/c2y-generic-3.c, gcc.dg/gnu2y-generic-1.c: New tests.
	* gcc.dg/c23-tag-6.c: Use -pedantic-errors.

libcpp/
	* include/cpplib.h (CLK_GNUC2Y, CLK_STDC2Y): New.
	* init.cc (lang_defaults): Add GNUC2Y and STDC2Y entries.
	(cpp_init_builtins): Define __STDC_VERSION__ to 202500L for GNUC2Y
	and STDC2Y.
diff mbox series

Patch

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 0341c44a2cd..24335deeb58 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -216,18 +216,22 @@  int flag_cond_mismatch;
 
 int flag_isoc94;
 
-/* Nonzero means use the ISO C99 (or C11) dialect of C.  */
+/* Nonzero means use the ISO C99 (or later) dialect of C.  */
 
 int flag_isoc99;
 
-/* Nonzero means use the ISO C11 dialect of C.  */
+/* Nonzero means use the ISO C11 (or later) dialect of C.  */
 
 int flag_isoc11;
 
-/* Nonzero means use the ISO C23 dialect of C.  */
+/* Nonzero means use the ISO C23 (or later) dialect of C.  */
 
 int flag_isoc23;
 
+/* Nonzero means use the ISO C2Y (or later) dialect of C.  */
+
+int flag_isoc2y;
+
 /* Nonzero means that we have builtin functions, and main is an int.  */
 
 int flag_hosted = 1;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ae79912c89f..48c89b603bc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -531,7 +531,7 @@  extern GTY(()) tree c_global_trees[CTI_MAX];
 
 enum c_language_kind
 {
-  clk_c		= 0,		/* C90, C94, C99, C11 or C23 */
+  clk_c		= 0,		/* C without ObjC features.  */
   clk_objc	= 1,		/* clk_c with ObjC features.  */
   clk_cxx	= 2,		/* ANSI/ISO C++ */
   clk_objcxx	= 3		/* clk_cxx with ObjC features.  */
@@ -676,10 +676,14 @@  extern int flag_isoc99;
 
 extern int flag_isoc11;
 
-/* Nonzero means use the ISO C23 dialect of C.  */
+/* Nonzero means use the ISO C23 (or later) dialect of C.  */
 
 extern int flag_isoc23;
 
+/* Nonzero means use the ISO C2Y (or later) dialect of C.  */
+
+extern int flag_isoc2y;
+
 /* Nonzero means that we have builtin functions, and main is an int.  */
 
 extern int flag_hosted;
diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index be3058dca63..faaf9ee6350 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -121,6 +121,7 @@  static void set_std_c99 (int);
 static void set_std_c11 (int);
 static void set_std_c17 (int);
 static void set_std_c23 (int);
+static void set_std_c2y (int);
 static void check_deps_environment_vars (void);
 static void handle_deferred_opts (void);
 static void sanitize_cpp_opts (void);
@@ -743,6 +744,16 @@  c_common_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 	set_std_c23 (false /* ISO */);
       break;
 
+    case OPT_std_c2y:
+      if (!preprocessing_asm_p)
+	set_std_c2y (true /* ISO */);
+      break;
+
+    case OPT_std_gnu2y:
+      if (!preprocessing_asm_p)
+	set_std_c2y (false /* ISO */);
+      break;
+
     case OPT_trigraphs:
       cpp_opts->trigraphs = 1;
       break;
@@ -1782,6 +1793,7 @@  set_std_c89 (int c94, int iso)
   flag_isoc99 = 0;
   flag_isoc11 = 0;
   flag_isoc23 = 0;
+  flag_isoc2y = 0;
   lang_hooks.name = "GNU C89";
 }
 
@@ -1793,6 +1805,7 @@  set_std_c99 (int iso)
   flag_no_asm = iso;
   flag_no_nonansi_builtin = iso;
   flag_iso = iso;
+  flag_isoc2y = 0;
   flag_isoc23 = 0;
   flag_isoc11 = 0;
   flag_isoc99 = 1;
@@ -1808,6 +1821,7 @@  set_std_c11 (int iso)
   flag_no_asm = iso;
   flag_no_nonansi_builtin = iso;
   flag_iso = iso;
+  flag_isoc2y = 0;
   flag_isoc23 = 0;
   flag_isoc11 = 1;
   flag_isoc99 = 1;
@@ -1823,6 +1837,7 @@  set_std_c17 (int iso)
   flag_no_asm = iso;
   flag_no_nonansi_builtin = iso;
   flag_iso = iso;
+  flag_isoc2y = 0;
   flag_isoc23 = 0;
   flag_isoc11 = 1;
   flag_isoc99 = 1;
@@ -1830,7 +1845,7 @@  set_std_c17 (int iso)
   lang_hooks.name = "GNU C17";
 }
 
-/* Set the C 2X standard (without GNU extensions if ISO).  */
+/* Set the C 23 standard (without GNU extensions if ISO).  */
 static void
 set_std_c23 (int iso)
 {
@@ -1838,6 +1853,7 @@  set_std_c23 (int iso)
   flag_no_asm = iso;
   flag_no_nonansi_builtin = iso;
   flag_iso = iso;
+  flag_isoc2y = 0;
   flag_isoc23 = 1;
   flag_isoc11 = 1;
   flag_isoc99 = 1;
@@ -1845,6 +1861,22 @@  set_std_c23 (int iso)
   lang_hooks.name = "GNU C23";
 }
 
+/* Set the C 2Y standard (without GNU extensions if ISO).  */
+static void
+set_std_c2y (int iso)
+{
+  cpp_set_lang (parse_in, iso ? CLK_STDC23: CLK_GNUC23);
+  flag_no_asm = iso;
+  flag_no_nonansi_builtin = iso;
+  flag_iso = iso;
+  flag_isoc2y = 1;
+  flag_isoc23 = 1;
+  flag_isoc11 = 1;
+  flag_isoc99 = 1;
+  flag_isoc94 = 1;
+  lang_hooks.name = "GNU C2Y";
+}
+
 
 /* Set the C++ 98 standard (without GNU extensions if ISO).  */
 static void
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index fb34c3b7031..b067369fa7e 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -441,6 +441,10 @@  Wc11-c2x-compat
 C ObjC Alias(Wc11-c23-compat)
 Deprecated in favor of -Wc11-c23-compat.
 
+Wc23-c2y-compat
+C ObjC Var(warn_c23_c2y_compat) Init(-1) Warning
+Warn about features not present in ISO C23, but present in ISO C2Y.
+
 Wc90-c99-compat
 C ObjC CPP(cpp_warn_c90_c99_compat) CppReason(CPP_W_C90_C99_COMPAT) Var(warn_c90_c99_compat) Init(-1) Warning
 Warn about features not present in ISO C90, but present in ISO C99.
@@ -2515,6 +2519,10 @@  std=c2x
 C ObjC Alias(std=c23)
 Deprecated in favor of -std=c23.
 
+std=c2y
+C ObjC
+Conform to the ISO 202Y C standard draft (experimental and incomplete support).
+
 std=c89
 C ObjC Alias(std=c90)
 Conform to the ISO 1990 C standard.
@@ -2613,6 +2621,10 @@  std=gnu2x
 C ObjC Alias(std=gnu23)
 Deprecated in favor of -std=gnu23.
 
+std=gnu2y
+C ObjC
+Conform to the ISO 202Y C standard draft with GNU extensions (experimental and incomplete support).
+
 std=gnu89
 C ObjC Alias(std=gnu90)
 Conform to the ISO 1990 C standard with GNU extensions.
diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls
index dd455d7c0dc..31d9ffef578 100644
--- a/gcc/c-family/c.opt.urls
+++ b/gcc/c-family/c.opt.urls
@@ -160,6 +160,9 @@  UrlSuffix(gcc/Warning-Options.html#index-Wbuiltin-macro-redefined)
 Wc11-c23-compat
 UrlSuffix(gcc/Warning-Options.html#index-Wc11-c23-compat)
 
+Wc23-c2y-compat
+UrlSuffix(gcc/Warning-Options.html#index-Wc23-c2y-compat)
+
 Wc90-c99-compat
 UrlSuffix(gcc/Warning-Options.html#index-Wc90-c99-compat)
 
diff --git a/gcc/c/c-errors.cc b/gcc/c/c-errors.cc
index 7aa5e0db34e..f36e7f9780a 100644
--- a/gcc/c/c-errors.cc
+++ b/gcc/c/c-errors.cc
@@ -25,6 +25,45 @@  along with GCC; see the file COPYING3.  If not see
 #include "c-tree.h"
 #include "opts.h"
 
+/* Issue an ISO C23 pedantic warning MSGID if -pedantic outside C2Y mode,
+   otherwise issue warning MSGID if -Wc23-c2y-compat is specified.
+   This function is supposed to be used for matters that are allowed in
+   ISO C2Y but not supported in ISO C23, thus we explicitly don't pedwarn
+   when C2Y is specified.  */
+
+bool
+pedwarn_c23 (location_t location, int opt, const char *gmsgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+  bool warned = false;
+  rich_location richloc (line_table, location);
+
+  va_start (ap, gmsgid);
+  /* If desired, issue the C23/C2Y compat warning, which is more specific
+     than -pedantic.  */
+  if (warn_c23_c2y_compat > 0)
+    {
+      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+			   (pedantic && !flag_isoc2y)
+			   ? DK_PEDWARN : DK_WARNING);
+      diagnostic.option_index = OPT_Wc23_c2y_compat;
+      warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
+    }
+  /* -Wno-c23-c2y-compat suppresses even the pedwarns.  */
+  else if (warn_c23_c2y_compat == 0)
+    ;
+  /* For -pedantic outside C2Y, issue a pedwarn.  */
+  else if (pedantic && !flag_isoc2y)
+    {
+      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
+      diagnostic.option_index = opt;
+      warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
+    }
+  va_end (ap);
+  return warned;
+}
+
 /* Issue an ISO C11 pedantic warning MSGID if -pedantic outside C23 mode,
    otherwise issue warning MSGID if -Wc11-c23-compat is specified.
    This function is supposed to be used for matters that are allowed in
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 0c5018134cc..e83e9c683f7 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1534,6 +1534,9 @@  disable_extension_diagnostics (void)
 	     /* Similarly for warn_c11_c23_compat.  */
 	     | ((warn_c11_c23_compat == 1) << 11)
 	     | ((warn_c11_c23_compat == -1) << 12)
+	     /* Similarly for warn_c23_c2y_compat.  */
+	     | ((warn_c23_c2y_compat == 1) << 13)
+	     | ((warn_c23_c2y_compat == -1) << 14)
 	     );
   cpp_opts->cpp_pedantic = pedantic = 0;
   warn_pointer_arith = 0;
@@ -1545,6 +1548,7 @@  disable_extension_diagnostics (void)
   warn_c90_c99_compat = 0;
   warn_c99_c11_compat = 0;
   warn_c11_c23_compat = 0;
+  warn_c23_c2y_compat = 0;
   return ret;
 }
 
@@ -1565,6 +1569,7 @@  restore_extension_diagnostics (int flags)
   warn_c90_c99_compat = (flags >> 7) & 1 ? 1 : ((flags >> 8) & 1 ? -1 : 0);
   warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0);
   warn_c11_c23_compat = (flags >> 11) & 1 ? 1 : ((flags >> 12) & 1 ? -1 : 0);
+  warn_c23_c2y_compat = (flags >> 13) & 1 ? 1 : ((flags >> 14) & 1 ? -1 : 0);
 }
 
 /* Helper data structure for parsing #pragma acc routine.  */
@@ -10273,8 +10278,14 @@  struct c_generic_association
 /* Parse a generic-selection.  (C11 6.5.1.1).
    
    generic-selection:
-     _Generic ( assignment-expression , generic-assoc-list )
-     
+     _Generic ( generic-controlling-operand , generic-assoc-list )
+
+  generic-controlling-operand:
+    assignment-expression
+    type-name
+
+  (The use of a type-name is new in C2Y.)
+
    generic-assoc-list:
      generic-association
      generic-assoc-list , generic-association
@@ -10314,30 +10325,43 @@  c_parser_generic_selection (c_parser *parser)
   if (!parens.require_open (parser))
     return error_expr;
 
-  c_inhibit_evaluation_warnings++;
   selector_loc = c_parser_peek_token (parser)->location;
-  selector = c_parser_expr_no_commas (parser, NULL);
-  selector = default_function_array_conversion (selector_loc, selector);
-  c_inhibit_evaluation_warnings--;
-
-  if (selector.value == error_mark_node)
+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
     {
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-      return selector;
-    }
-  mark_exp_read (selector.value);
-  selector_type = TREE_TYPE (selector.value);
-  /* In ISO C terms, rvalues (including the controlling expression of
-     _Generic) do not have qualified types.  */
-  if (TREE_CODE (selector_type) != ARRAY_TYPE)
-    selector_type = TYPE_MAIN_VARIANT (selector_type);
-  /* In ISO C terms, _Noreturn is not part of the type of expressions
-     such as &abort, but in GCC it is represented internally as a type
-     qualifier.  */
-  if (FUNCTION_POINTER_TYPE_P (selector_type)
-      && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
-    selector_type
-      = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+      c_inhibit_evaluation_warnings++;
+      pedwarn_c23 (selector_loc, OPT_Wpedantic,
+		   "ISO C does not support use of type name as %<_Generic%> "
+		   "controlling operand before C2Y");
+      struct c_type_name *type = c_parser_type_name (parser);
+      selector_type = groktypename (type, NULL, NULL);
+      c_inhibit_evaluation_warnings--;
+    }
+  else
+    {
+      c_inhibit_evaluation_warnings++;
+      selector = c_parser_expr_no_commas (parser, NULL);
+      selector = default_function_array_conversion (selector_loc, selector);
+      c_inhibit_evaluation_warnings--;
+
+      if (selector.value == error_mark_node)
+	{
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	  return selector;
+	}
+      mark_exp_read (selector.value);
+      selector_type = TREE_TYPE (selector.value);
+      /* In ISO C terms, rvalues (including the controlling expression
+	 of _Generic) do not have qualified types.  */
+      if (TREE_CODE (selector_type) != ARRAY_TYPE)
+	selector_type = TYPE_MAIN_VARIANT (selector_type);
+      /* In ISO C terms, _Noreturn is not part of the type of expressions
+	 such as &abort, but in GCC it is represented internally as a type
+	 qualifier.  */
+      if (FUNCTION_POINTER_TYPE_P (selector_type)
+	  && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
+	selector_type
+	  = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+    }
 
   if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
     {
@@ -10376,11 +10400,13 @@  c_parser_generic_selection (c_parser *parser)
 	    }
 
 	  if (TREE_CODE (assoc.type) == FUNCTION_TYPE)
-	    error_at (assoc.type_location,
-		      "%<_Generic%> association has function type");
+	    pedwarn_c23 (assoc.type_location, OPT_Wpedantic,
+			 "ISO C does not support %<_Generic%> association with "
+			 "function type before C2Y");
 	  else if (!COMPLETE_TYPE_P (assoc.type))
-	    error_at (assoc.type_location,
-		      "%<_Generic%> association has incomplete type");
+	    pedwarn_c23 (assoc.type_location, OPT_Wpedantic,
+			 "ISO C does not support %<_Generic%> association with "
+			 "incomplete type before C2Y");
 
 	  if (c_type_variably_modified_p (assoc.type))
 	    error_at (assoc.type_location,
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 56a33b8156c..15da875a029 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -905,6 +905,8 @@  extern bool pedwarn_c99 (location_t, int opt, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
 extern bool pedwarn_c11 (location_t, int opt, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
+extern bool pedwarn_c23 (location_t, int opt, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
 
 extern void
 set_c_expr_source_range (c_expr *expr,
diff --git a/gcc/config/rl78/rl78.cc b/gcc/config/rl78/rl78.cc
index e5345bfa9dd..b4bb145b5a6 100644
--- a/gcc/config/rl78/rl78.cc
+++ b/gcc/config/rl78/rl78.cc
@@ -367,6 +367,7 @@  rl78_option_override (void)
       && strcmp (lang_hooks.name, "GNU C11")
       && strcmp (lang_hooks.name, "GNU C17")
       && strcmp (lang_hooks.name, "GNU C23")
+      && strcmp (lang_hooks.name, "GNU C2Y")
       && strcmp (lang_hooks.name, "GNU C89")
       && strcmp (lang_hooks.name, "GNU C99")
       /* Compiling with -flto results in a language of GNU GIMPLE being used... */
diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index 3f38ca37fea..a99c8dfdbe3 100644
--- a/gcc/doc/cpp.texi
+++ b/gcc/doc/cpp.texi
@@ -1887,7 +1887,9 @@  signifies the 2011 revision of the C standard; the value
 @code{201710L} signifies the 2017 revision of the C standard (which is
 otherwise identical to the 2011 version apart from correction of
 defects).  The value @code{202311L} is used for the experimental
-@option{-std=c23} and @option{-std=gnu23} modes.
+@option{-std=c23} and @option{-std=gnu23} modes.  An unspecified value
+larger than @code{202311L} is used for the experimental
+@option{-std=c2y} and @option{-std=gnu2y} modes.
 
 This macro is not defined if the @option{-traditional-cpp} option is
 used, nor when compiling C++ or Objective-C@.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index a0b37564646..26e6a349d51 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -340,7 +340,7 @@  Objective-C and Objective-C++ Dialects}.
 -Wbool-compare  -Wbool-operation
 -Wno-builtin-declaration-mismatch
 -Wno-builtin-macro-redefined  -Wc90-c99-compat  -Wc99-c11-compat
--Wc11-c23-compat
+-Wc11-c23-compat  -Wc23-c2y-compat
 -Wc++-compat  -Wc++11-compat  -Wc++14-compat  -Wc++17-compat
 -Wc++20-compat
 -Wno-c++11-extensions  -Wno-c++14-extensions -Wno-c++17-extensions
@@ -2472,6 +2472,10 @@  ISO C23, the 2023 revision of the ISO C standard (expected to be
 published in 2024).  The support for this version is experimental and
 incomplete.  The name @samp{c2x} is deprecated.
 
+@item c2y
+The next version of the ISO C standard, still under development.  The
+support for this version is experimental and incomplete.
+
 @item gnu90
 @itemx gnu89
 GNU dialect of ISO C90 (including some C99 features).
@@ -2491,6 +2495,10 @@  GNU dialect of ISO C17.  This is the default for C code.
 
 @item gnu23
 @itemx gnu2x
+GNU dialect of ISO C23.  The support for this version is experimental
+and incomplete.  The name @samp{gnu2x} is deprecated.
+
+@item gnu2y
 The next version of the ISO C standard, still under development, plus
 GNU extensions.  The support for this version is experimental and
 incomplete.  The name @samp{gnu2x} is deprecated.
@@ -9326,6 +9334,19 @@  deprecated.
 When not compiling in C23 mode, these warnings are upgraded to errors
 by @option{-pedantic-errors}.
 
+@opindex Wc23-c2y-compat
+@opindex Wno-c23-c2y-compat
+@item -Wc23-c2y-compat @r{(C and Objective-C only)}
+@itemx -Wc23-c2y-compat @r{(C and Objective-C only)}
+Warn about features not present in ISO C23, but present in ISO C2Y.
+For instance, warn about @code{_Generic} selecting with a type name
+instead of an expression.  This option is independent of the standards
+mode.  Warnings are disabled in the expression that follows
+@code{__extension__}.
+
+When not compiling in C2Y mode, these warnings are upgraded to errors
+by @option{-pedantic-errors}.
+
 @opindex Wc++-compat
 @opindex Wno-c++-compat
 @item -Wc++-compat @r{(C and Objective-C only)}
diff --git a/gcc/doc/standards.texi b/gcc/doc/standards.texi
index 586835b28f3..484fbb10352 100644
--- a/gcc/doc/standards.texi
+++ b/gcc/doc/standards.texi
@@ -42,6 +42,8 @@  with some exceptions, and possibly with some extensions.
 @cindex C23
 @cindex ISO C2X
 @cindex C2X
+@cindex ISO C2Y
+@cindex C2Y
 @cindex Technical Corrigenda
 @cindex TC1
 @cindex Technical Corrigendum 1
@@ -113,12 +115,16 @@  known as @dfn{C17} and is supported with @option{-std=c17} or
 @option{-std=c11}, and the only difference between the options is the
 value of @code{__STDC_VERSION__}.
 
-A further version of the C standard, known as @dfn{C23}, is under
+A fifth version of the C standard, known as @dfn{C23}, is under
 development and expected to be published in 2024 as ISO/IEC 9899:2024.
 (While in development, drafts of this standard version were referred
 to as @dfn{C2X}.)  Experimental and incomplete support for this is
 enabled with @option{-std=c23} or @option{-std=iso9899:2024}.
 
+A further version of the C standard, known as @dfn{C2Y}, is under
+development; experimental and incomplete support for this is enabled
+with @option{-std=c2y}.
+
 By default, GCC provides some extensions to the C language that, on
 rare occasions conflict with the C standard.  @xref{C
 Extensions,,Extensions to the C Language Family}.  
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index f90f7b1cfef..18256843a4c 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -25281,6 +25281,8 @@  highest_c_language (const char *lang1, const char *lang2)
   if (strcmp ("GNU C++98", lang1) == 0 || strcmp ("GNU C++98", lang2) == 0)
     return "GNU C++98";
 
+  if (strcmp ("GNU C2Y", lang1) == 0 || strcmp ("GNU C2Y", lang2) == 0)
+    return "GNU C2Y";
   if (strcmp ("GNU C23", lang1) == 0 || strcmp ("GNU C23", lang2) == 0)
     return "GNU C23";
   if (strcmp ("GNU C17", lang1) == 0 || strcmp ("GNU C17", lang2) == 0)
@@ -25363,7 +25365,8 @@  gen_compile_unit_die (const char *filename)
 	  if (dwarf_version >= 5 /* || !dwarf_strict */)
 	    if (strcmp (language_string, "GNU C11") == 0
 		|| strcmp (language_string, "GNU C17") == 0
-		|| strcmp (language_string, "GNU C23") == 0)
+		|| strcmp (language_string, "GNU C23") == 0
+		|| strcmp (language_string, "GNU C2Y") == 0)
 	      language = DW_LANG_C11;
 	}
     }
diff --git a/gcc/testsuite/gcc.dg/c23-generic-1.c b/gcc/testsuite/gcc.dg/c23-generic-1.c
new file mode 100644
index 00000000000..26c97fb4a9e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-generic-1.c
@@ -0,0 +1,17 @@ 
+/* Test C2Y _Generic features: error with -std=c23 -pedantic-errors.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2); /* { dg-error "use of type name" } */
+
+_Static_assert (_Generic (void, int : 1, void : 2) == 2); /* { dg-error "use of type name" } */
+/* { dg-error "incomplete type" "incomplete type" { target *-*-* } .-1 } */
+
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2); /* { dg-error "use of type name" } */
+/* { dg-error "function type" "function type" { target *-*-* } .-1 } */
+
+const int ci;
+
+_Static_assert (_Generic (typeof (ci), const int : 1, int : 2) == 1); /* { dg-error "use of type name" } */
+
+_Static_assert (_Generic (ci, const int : 1, int : 2) == 2);
diff --git a/gcc/testsuite/gcc.dg/c23-generic-2.c b/gcc/testsuite/gcc.dg/c23-generic-2.c
new file mode 100644
index 00000000000..eb31d37b092
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-generic-2.c
@@ -0,0 +1,17 @@ 
+/* Test C2Y _Generic features: warning with -std=c23 -pedantic.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic" } */
+
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2); /* { dg-warning "use of type name" } */
+
+_Static_assert (_Generic (void, int : 1, void : 2) == 2); /* { dg-warning "use of type name" } */
+/* { dg-warning "incomplete type" "incomplete type" { target *-*-* } .-1 } */
+
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2); /* { dg-warning "use of type name" } */
+/* { dg-warning "function type" "function type" { target *-*-* } .-1 } */
+
+const int ci;
+
+_Static_assert (_Generic (typeof (ci), const int : 1, int : 2) == 1); /* { dg-warning "use of type name" } */
+
+_Static_assert (_Generic (ci, const int : 1, int : 2) == 2);
diff --git a/gcc/testsuite/gcc.dg/c23-generic-3.c b/gcc/testsuite/gcc.dg/c23-generic-3.c
new file mode 100644
index 00000000000..adf4b3549ff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-generic-3.c
@@ -0,0 +1,16 @@ 
+/* Test C2Y _Generic features: no warning or error with -std=c23
+   -pedantic-errors -Wno-c23-c2y-compat.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
+
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2);
+
+_Static_assert (_Generic (void, int : 1, void : 2) == 2);
+
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2);
+
+const int ci;
+
+_Static_assert (_Generic (typeof (ci), const int : 1, int : 2) == 1);
+
+_Static_assert (_Generic (ci, const int : 1, int : 2) == 2);
diff --git a/gcc/testsuite/gcc.dg/c23-generic-4.c b/gcc/testsuite/gcc.dg/c23-generic-4.c
new file mode 100644
index 00000000000..f9f65615dd9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-generic-4.c
@@ -0,0 +1,16 @@ 
+/* Test C2Y _Generic features: no warning or error with -std=c23 by
+   default.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2);
+
+_Static_assert (_Generic (void, int : 1, void : 2) == 2);
+
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2);
+
+const int ci;
+
+_Static_assert (_Generic (typeof (ci), const int : 1, int : 2) == 1);
+
+_Static_assert (_Generic (ci, const int : 1, int : 2) == 2);
diff --git a/gcc/testsuite/gcc.dg/c23-tag-6.c b/gcc/testsuite/gcc.dg/c23-tag-6.c
index 1b65ed3e35d..7a81487c6e4 100644
--- a/gcc/testsuite/gcc.dg/c23-tag-6.c
+++ b/gcc/testsuite/gcc.dg/c23-tag-6.c
@@ -1,6 +1,6 @@ 
 /*
  * { dg-do compile }
- * { dg-options "-std=c23" }
+ * { dg-options "-std=c23 -pedantic-errors" }
  */
 
 // (in-)completeness
diff --git a/gcc/testsuite/gcc.dg/c2y-generic-1.c b/gcc/testsuite/gcc.dg/c2y-generic-1.c
new file mode 100644
index 00000000000..afb46df99fe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2y-generic-1.c
@@ -0,0 +1,15 @@ 
+/* Test C2Y _Generic features.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2);
+
+_Static_assert (_Generic (void, int : 1, void : 2) == 2);
+
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2);
+
+const int ci;
+
+_Static_assert (_Generic (typeof (ci), const int : 1, int : 2) == 1);
+
+_Static_assert (_Generic (ci, const int : 1, int : 2) == 2);
diff --git a/gcc/testsuite/gcc.dg/c2y-generic-2.c b/gcc/testsuite/gcc.dg/c2y-generic-2.c
new file mode 100644
index 00000000000..c37fcc1283b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2y-generic-2.c
@@ -0,0 +1,17 @@ 
+/* Test C2Y _Generic features: warning with -Wc23-c2y-compat.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
+
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2); /* { dg-warning "use of type name" } */
+
+_Static_assert (_Generic (void, int : 1, void : 2) == 2); /* { dg-warning "use of type name" } */
+/* { dg-warning "incomplete type" "incomplete type" { target *-*-* } .-1 } */
+
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2); /* { dg-warning "use of type name" } */
+/* { dg-warning "function type" "function type" { target *-*-* } .-1 } */
+
+const int ci;
+
+_Static_assert (_Generic (typeof (ci), const int : 1, int : 2) == 1); /* { dg-warning "use of type name" } */
+
+_Static_assert (_Generic (ci, const int : 1, int : 2) == 2);
diff --git a/gcc/testsuite/gcc.dg/c2y-generic-3.c b/gcc/testsuite/gcc.dg/c2y-generic-3.c
new file mode 100644
index 00000000000..09174fdb095
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2y-generic-3.c
@@ -0,0 +1,9 @@ 
+/* Test C2Y _Generic features: VM types still not allowed.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+void
+f (int i)
+{
+  (void) _Generic (i, int : 1, int (*)[i] : 2); /* { dg-error "variable length" } */
+}
diff --git a/gcc/testsuite/gcc.dg/gnu2y-generic-1.c b/gcc/testsuite/gcc.dg/gnu2y-generic-1.c
new file mode 100644
index 00000000000..98868ad51d1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu2y-generic-1.c
@@ -0,0 +1,15 @@ 
+/* Test C2Y _Generic features: __extension__ suppresses -Wc23-c2y-compat
+   warnings (and the state is restored after __extension__).  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2y -pedantic-errors -Wc23-c2y-compat" } */
+
+_Static_assert (__extension__ _Generic (const int, int : 1, const int : 2) == 2);
+_Static_assert (_Generic (const int, int : 1, const int : 2) == 2); /* { dg-warning "use of type name" } */
+
+_Static_assert (__extension__ _Generic (void, int : 1, void : 2) == 2);
+_Static_assert (_Generic (void, int : 1, void : 2) == 2); /* { dg-warning "use of type name" } */
+/* { dg-warning "incomplete type" "incomplete type" { target *-*-* } .-1 } */
+
+_Static_assert (__extension__ _Generic (int (), int (*) () : 1, int () : 2) == 2);
+_Static_assert (_Generic (int (), int (*) () : 1, int () : 2) == 2); /* { dg-warning "use of type name" } */
+/* { dg-warning "function type" "function type" { target *-*-* } .-1 } */
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index c62374d3192..d76817c94fc 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -172,8 +172,9 @@  enum cpp_ttype
 
 /* C language kind, used when calling cpp_create_reader.  */
 enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_GNUC11, CLK_GNUC17, CLK_GNUC23,
+	     CLK_GNUC2Y,
 	     CLK_STDC89, CLK_STDC94, CLK_STDC99, CLK_STDC11, CLK_STDC17,
-	     CLK_STDC23,
+	     CLK_STDC23, CLK_STDC2Y,
 	     CLK_GNUCXX, CLK_CXX98, CLK_GNUCXX11, CLK_CXX11,
 	     CLK_GNUCXX14, CLK_CXX14, CLK_GNUCXX17, CLK_CXX17,
 	     CLK_GNUCXX20, CLK_CXX20, CLK_GNUCXX23, CLK_CXX23,
diff --git a/libcpp/init.cc b/libcpp/init.cc
index c457fa659e7..9ae06a9595d 100644
--- a/libcpp/init.cc
+++ b/libcpp/init.cc
@@ -109,12 +109,14 @@  static const struct lang_flags lang_defaults[] =
   /* GNUC11   */  { 1,  0,  1,  1,  1,  0,    0,  1,   1,   1,   0,    0,     0,     0,   0,      1,   1,     0,   0,   0,      0,      0,    0 },
   /* GNUC17   */  { 1,  0,  1,  1,  1,  0,    0,  1,   1,   1,   0,    0,     0,     0,   0,      1,   1,     0,   0,   0,      0,      0,    0 },
   /* GNUC23   */  { 1,  0,  1,  1,  1,  1,    0,  1,   1,   1,   0,    1,     1,     0,   1,      1,   1,     1,   0,   1,      1,      0,    1 },
+  /* GNUC2Y   */  { 1,  0,  1,  1,  1,  1,    0,  1,   1,   1,   0,    1,     1,     0,   1,      1,   1,     1,   0,   1,      1,      0,    1 },
   /* STDC89   */  { 0,  0,  0,  0,  0,  0,    1,  0,   0,   0,   0,    0,     0,     1,   0,      0,   0,     0,   0,   0,      0,      0,    0 },
   /* STDC94   */  { 0,  0,  0,  0,  0,  0,    1,  1,   0,   0,   0,    0,     0,     1,   0,      0,   0,     0,   0,   0,      0,      0,    0 },
   /* STDC99   */  { 1,  0,  1,  1,  0,  0,    1,  1,   0,   0,   0,    0,     0,     1,   0,      0,   0,     0,   0,   0,      0,      0,    0 },
   /* STDC11   */  { 1,  0,  1,  1,  1,  0,    1,  1,   1,   0,   0,    0,     0,     1,   0,      0,   0,     0,   0,   0,      0,      0,    0 },
   /* STDC17   */  { 1,  0,  1,  1,  1,  0,    1,  1,   1,   0,   0,    0,     0,     1,   0,      0,   0,     0,   0,   0,      0,      0,    0 },
   /* STDC23   */  { 1,  0,  1,  1,  1,  1,    1,  1,   1,   0,   0,    1,     1,     0,   1,      1,   1,     1,   0,   1,      1,      0,    1 },
+  /* STDC2Y   */  { 1,  0,  1,  1,  1,  1,    1,  1,   1,   0,   0,    1,     1,     0,   1,      1,   1,     1,   0,   1,      1,      0,    1 },
   /* GNUCXX   */  { 0,  1,  1,  1,  0,  1,    0,  1,   0,   0,   0,    0,     0,     0,   0,      1,   1,     0,   0,   0,      0,      0,    1 },
   /* CXX98    */  { 0,  1,  0,  1,  0,  1,    1,  1,   0,   0,   0,    0,     0,     1,   0,      0,   1,     0,   0,   0,      0,      0,    1 },
   /* GNUCXX11 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    0,     0,     0,   0,      1,   1,     0,   0,   0,      0,      0,    1 },
@@ -595,6 +597,9 @@  cpp_init_builtins (cpp_reader *pfile, int hosted)
   else if (CPP_OPTION (pfile, lang) == CLK_STDC23
 	   || CPP_OPTION (pfile, lang) == CLK_GNUC23)
     _cpp_define_builtin (pfile, "__STDC_VERSION__ 202311L");
+  else if (CPP_OPTION (pfile, lang) == CLK_STDC2Y
+	   || CPP_OPTION (pfile, lang) == CLK_GNUC2Y)
+    _cpp_define_builtin (pfile, "__STDC_VERSION__ 202500L");
   else if (CPP_OPTION (pfile, lang) == CLK_STDC17
 	   || CPP_OPTION (pfile, lang) == CLK_GNUC17)
     _cpp_define_builtin (pfile, "__STDC_VERSION__ 201710L");