Hi!

The following patch attempts to implement the paper just by dropping the
diagnostics.
Because we don't differentiate between "C" types vs. "C++" types, this is
less important.
Or shall we go even further and not mark the templates or their
specializations internally with C++ linkage?  I think with reflection
this is actually observable, one can call has_c_language_linkage on
a reflection of function or variable template specialization.  Guess
then at least mangle.cc would need to be changed so that e.g.
unmangled_name_p ignores DECL_EXTERN_C_FUNCTION_P for function template
instantiations or DECL_EXTERN_C_P for variable template instantiations.

2026-09-09  Jakub Jelinek  <[email protected]>

        P2243R0
        PR c++/125823
        * parser.cc: Implement C++29 P2243R0: Language linkage for templates.
        (cp_parser_explicit_specialization): Don't diagnose
        template specialization with C linkage.
        (cp_parser_explicit_template_declaration): Don't diagnose
        template with C linkage.

        * g++.dg/diagnostic/unclosed-extern-c.C: Don't expect error
        and inform about template with C linkage.
        * g++.dg/parse/bitfield10.C: Likewise.
        * g++.dg/template/extern-c.C: Likewise.
        * g++.dg/cpp29/tmpl-extern-c1.C: New test.
        * g++.dg/cpp29/tmpl-extern-c2.C: New test.

--- a/gcc/cp/parser.cc  2026-09-08 22:18:28.484021504 +0200
+++ b/gcc/cp/parser.cc  2026-09-09 12:47:00.081357116 +0200
@@ -22353,21 +22353,11 @@ cp_parser_explicit_specialization (cp_pa
   /* We have processed another parameter list.  */
   ++parser->num_template_parameter_lists;
 
-  /* [temp]
-
-     A template ... explicit specialization ... shall not have C
-     linkage.  */
   bool need_lang_pop = current_lang_name == lang_name_c;
   if (need_lang_pop)
-    {
-      auto_diagnostic_group d;
-      error_at (token->location, "template specialization with C linkage");
-      maybe_show_extern_c_location ();
-
-      /* Give it C++ linkage to avoid confusing other parts of the
-        front end.  */
-      push_lang_context (lang_name_cplusplus);
-    }
+    /* Give it C++ linkage to avoid confusing other parts of the
+       front end.  */
+    push_lang_context (lang_name_cplusplus);
 
   /* Let the front end know that we are beginning a specialization.  */
   if (begin_specialization ())
@@ -36559,14 +36549,8 @@ cp_parser_explicit_template_declaration
       cp_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
-  /* [temp]
-
-     A template ... shall not have C linkage.  */
   if (current_lang_name == lang_name_c)
     {
-      auto_diagnostic_group d;
-      error_at (location, "template with C linkage");
-      maybe_show_extern_c_location ();
       /* Give it C++ linkage to avoid confusing other parts of the
          front end.  */
       push_lang_context (lang_name_cplusplus);
--- a/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C       2026-03-27 
10:17:15.754304304 +0100
+++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C       2026-09-09 
12:59:24.653915865 +0200
@@ -4,9 +4,9 @@ extern "C" { // { dg-line open_extern_c
 
 /* Missing close-brace for the extern "C" here.  */
 
-template <typename T> // { dg-error "template with C linkage" }
+template <typename T> // { dg-bogus "template with C linkage" }
 void bar (void);
-// { dg-message "1: 'extern .C.' linkage started here" "" { target *-*-* } 
open_extern_c }
+// { dg-bogus "1: 'extern .C.' linkage started here" "" { target *-*-* } 
open_extern_c }
 
 void test (void);
 // { dg-message "12: to match this '.'" "" { target *-*-* } open_extern_c }
--- a/gcc/testsuite/g++.dg/parse/bitfield10.C   2026-03-27 10:17:16.066299212 
+0100
+++ b/gcc/testsuite/g++.dg/parse/bitfield10.C   2026-09-09 12:55:14.741084080 
+0200
@@ -2,7 +2,7 @@
 /* { dg-do "compile" } */
 
 extern "C" {
-  template <int> class b; /* { dg-error "with C linkage" } */
+  template <int> class b; /* { dg-bogus "with C linkage" } */
   struct {
     typedef b: /* { dg-error "at end of input" } */
 
--- a/gcc/testsuite/g++.dg/template/extern-c.C  2026-03-27 10:17:16.181297336 
+0100
+++ b/gcc/testsuite/g++.dg/template/extern-c.C  2026-09-09 12:53:53.393115354 
+0200
@@ -2,9 +2,9 @@ template <typename T> void specializable
 
 /* Invalid template: within "extern C".  */
 
-extern "C" { // { dg-message "1: 'extern .C.' linkage started here" }
+extern "C" { // { dg-bogus "1: 'extern .C.' linkage started here" }
 
-template <typename T> // { dg-error "template with C linkage" }
+template <typename T> // { dg-bogus "template with C linkage" }
 void within_extern_c_braces (void);
 
 }
@@ -17,9 +17,9 @@ void not_within_extern_c (void);
 
 /* Invalid specialization: within "extern C".  */
 
-extern "C" { // { dg-message "1: 'extern .C.' linkage started here" }
+extern "C" { // { dg-bogus "1: 'extern .C.' linkage started here" }
 
-template <>  // { dg-error "template specialization with C linkage" }
+template <>  // { dg-bogus "template specialization with C linkage" }
 void specializable (int);
 
 }
@@ -34,8 +34,8 @@ void specializable (char);
 
 extern "C" template <typename T> // { dg-line open_extern_c_no_braces }
 void within_extern_c_no_braces (void);
-// { dg-error "12: template with C linkage" "" { target *-*-* } 
open_extern_c_no_braces }
-// { dg-message "1: 'extern .C.' linkage started here" "" { target *-*-* } 
open_extern_c_no_braces }
+// { dg-bogus "12: template with C linkage" "" { target *-*-* } 
open_extern_c_no_braces }
+// { dg-bogus "1: 'extern .C.' linkage started here" "" { target *-*-* } 
open_extern_c_no_braces }
 
 
 /* Nested extern "C" specifications.
@@ -46,9 +46,9 @@ extern "C" {
     extern "C" {
     }
 
-    template <typename T>  // { dg-error "template with C linkage" }
+    template <typename T>  // { dg-bogus "template with C linkage" }
     void within_nested_extern_c (void);
-    // { dg-message "3: 'extern .C.' linkage started here" "" { target *-*-* } 
middle_open_extern_c }
+    // { dg-bogus "3: 'extern .C.' linkage started here" "" { target *-*-* } 
middle_open_extern_c }
 
     extern "C++" {
       /* Valid template: within extern "C++".  */
@@ -57,9 +57,9 @@ extern "C" {
 
       extern "C" {  // { dg-line last_open_extern_c }
        /* Invalid template: within "extern C".  */
-       template <typename T> // { dg-error "template with C linkage" }
+       template <typename T> // { dg-bogus "template with C linkage" }
        void within_extern_c_within_extern_cpp (void);
-       // { dg-message "7: 'extern .C.' linkage started here" "" { target 
*-*-* } last_open_extern_c } 
+       // { dg-bogus "7: 'extern .C.' linkage started here" "" { target *-*-* 
} last_open_extern_c }   
       }
     }
   }
--- a/gcc/testsuite/g++.dg/cpp29/tmpl-extern-c1.C       2026-09-09 
12:56:00.477504267 +0200
+++ b/gcc/testsuite/g++.dg/cpp29/tmpl-extern-c1.C       2026-09-09 
13:04:14.858236867 +0200
@@ -0,0 +1,35 @@
+// C++29 P2243R0: Language linkage for templates
+// { dg-do compile }
+
+extern "C" {
+template <int> struct A {};                    // { dg-bogus "template with C 
linkage" }
+template <int> void foo ();                    // { dg-bogus "template with C 
linkage" }
+#if __cpp_variable_templates >= 201304
+template <int> int v;                          // { dg-bogus "template with C 
linkage" }
+#endif
+#if __cpp_alias_templates >= 200704
+template <int N> using B = A <N>;              // { dg-bogus "template with C 
linkage" }
+#endif
+#if __cpp_concepts >= 201907 
+template <int> concept C = requires { true; }; // { dg-bogus "template with C 
linkage" }
+#endif
+template <int, int> struct D {};               // { dg-bogus "template with C 
linkage" }
+template <> struct D <42, 42> {};              // { dg-bogus "template 
specialization with C linkage" }
+template <int N> struct D <N, N + 1> {};       // { dg-bogus "template with C 
linkage" }
+}
+extern "C++" {
+template <int> struct E {};
+template <int> void bar ();
+#if __cpp_variable_templates >= 201304
+template <int> int w;
+#endif
+#if __cpp_alias_templates >= 200704
+template <int N> using F = E <N>;
+#endif
+#if __cpp_concepts >= 201907 
+template <int> concept G = requires { true; };
+#endif
+template <int, int> struct H {};
+template <> struct H <42, 42> {};
+template <int N> struct H <N, N + 1> {};
+}
--- a/gcc/testsuite/g++.dg/cpp29/tmpl-extern-c2.C       2026-09-09 
12:56:03.679463676 +0200
+++ b/gcc/testsuite/g++.dg/cpp29/tmpl-extern-c2.C       2026-09-09 
13:09:33.902183045 +0200
@@ -0,0 +1,39 @@
+// C++29 P2243R0: Language linkage for templates
+// { dg-do compile }
+
+template <int> extern "C" struct A {};                         // { dg-error 
"expected unqualified-id before string constant" }
+                                                               // { dg-error 
"extra ';' outside of a function only allowed in C\\\+\\\+11" "" { target 
c++98_only } .-1 }
+template <int> extern "C" void foo ();                         // { dg-error 
"expected unqualified-id before string constant" }
+#if __cpp_variable_templates >= 201304
+template <int> extern "C" int v;                               // { dg-error 
"expected unqualified-id before string constant" "" { target c++14 } }
+#endif
+#if __cpp_alias_templates >= 200704
+template <int N> extern "C" using B = A <N>;                   // { dg-error 
"expected unqualified-id before string constant" "" { target c++11 } }
+#endif
+#if __cpp_concepts >= 201907 
+template <int> extern "C" concept C = requires { true; };      // { dg-error 
"expected unqualified-id before string constant" "" { target c++20 } }
+#endif
+template <int, int> struct D {};
+template <> extern "C" struct D <42, 42> {};                   // { dg-error 
"expected unqualified-id before string constant" }
+                                                               // { dg-error 
"explicit template specialization cannot have a storage class" "" { target 
*-*-* } .-1 }
+                                                               // { dg-error 
"extra ';' outside of a function only allowed in C\\\+\\\+11" "" { target 
c++98_only } .-2 }
+template <int N> extern "C" struct D <N, N + 1> {};            // { dg-error 
"expected unqualified-id before string constant" }
+                                                               // { dg-error 
"extra ';' outside of a function only allowed in C\\\+\\\+11" "" { target 
c++98_only } .-1 }
+template <int> extern "C++" struct E {};                       // { dg-error 
"expected unqualified-id before string constant" }
+                                                               // { dg-error 
"extra ';' outside of a function only allowed in C\\\+\\\+11" "" { target 
c++98_only } .-1 }
+template <int> extern "C++" void bar ();                       // { dg-error 
"expected unqualified-id before string constant" }
+#if __cpp_variable_templates >= 201304
+template <int> extern "C++" int w;                             // { dg-error 
"expected unqualified-id before string constant" "" { target c++14 } }
+#endif
+#if __cpp_alias_templates >= 200704
+template <int N> extern "C++" using F = E <N>;                 // { dg-error 
"expected unqualified-id before string constant" "" { target c++11 } }
+#endif
+#if __cpp_concepts >= 201907 
+template <int> extern "C++" concept G = requires { true; };    // { dg-error 
"expected unqualified-id before string constant" "" { target c++20 } }
+#endif
+template <int, int> struct H {};
+template <> extern "C++" struct H <42, 42> {};                 // { dg-error 
"expected unqualified-id before string constant" }
+                                                               // { dg-error 
"explicit template specialization cannot have a storage class" "" { target 
*-*-* } .-1 }
+                                                               // { dg-error 
"extra ';' outside of a function only allowed in C\\\+\\\+11" "" { target 
c++98_only } .-2 }
+template <int N> extern "C++" struct H <N, N + 1> {};          // { dg-error 
"expected unqualified-id before string constant" }
+                                                               // { dg-error 
"extra ';' outside of a function only allowed in C\\\+\\\+11" "" { target 
c++98_only } .-1 }

        Jakub

Reply via email to