https://gcc.gnu.org/g:53efe2f8d66bb6344d084ca731cdec56873c62a0

commit r17-1624-g53efe2f8d66bb6344d084ca731cdec56873c62a0
Author: Marek Polacek <[email protected]>
Date:   Fri Jun 5 13:42:06 2026 -0400

    c++: explicit instantiation and noexcept-specifier [PR125613]
    
    This patch implements this part of [except.spec]: In an explicit
    instantiation a noexcept-specifier may be specified, but is not required.
    If a noexcept-specifier is specified in an explicit instantiation, the
    exception specification shall be the same as the exception specification
    of all other declarations of that function.
    
    But we are not checking this, and are the only compiler that accepts:
    
      template<typename T>
      void fn (T) {}
      template void fn<int>(int) noexcept;
    
            PR c++/125613
    
    gcc/cp/ChangeLog:
    
            * pt.cc (check_explicit_specialization): Detect mismatches in
            exception specifications in explicit instantiations.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/explicit-inst2.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/pt.cc                                | 29 +++++++++++
 gcc/testsuite/g++.dg/cpp0x/explicit-inst2.C | 81 +++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 0c0b3a2cac57..b7f9ce4cb0a3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3276,10 +3276,39 @@ check_explicit_specialization (tree declarator,
                  targs = new_targs;
                }
 
+             tree e1;
              tree inst = instantiate_template (tmpl, targs, tf_error);
              if (variable_template_p (tmpl)
                  && !check_explicit_inst_of_var_template (inst, decl))
                return error_mark_node;
+             /* [except.spec] In an explicit instantiation
+                a noexcept-specifier may be specified, but is not required.
+                If a noexcept-specifier is specified in an explicit
+                instantiation, the exception specification shall be the same
+                as the exception specification of all other declarations of
+                that function.  */
+             else if (DECL_FUNCTION_TEMPLATE_P (tmpl)
+                      && (e1 = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)))
+                      /* This could be the implicit noexcept(true) given
+                         to destructors, but here we are interested only
+                         in user-written noexcept-specs which would have
+                         been evaluated by now.  */
+                      && !UNEVALUATED_NOEXCEPT_SPEC_P (e1)
+                      && maybe_instantiate_noexcept (inst))
+               {
+                 tree e2 = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (inst));
+                 if (!comp_except_specs (e1, e2, ce_normal))
+                   {
+                     auto_diagnostic_group d;
+                     error ("exception specification %qX in explicit "
+                            "instantiation does not match the instantiated "
+                            "one %qX", e1, e2 ? e2 : noexcept_false_spec);
+                     inform (DECL_SOURCE_LOCATION (tmpl),
+                             "template declared here");
+                     return error_mark_node;
+                   }
+               }
+
              return inst;
            }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit-inst2.C 
b/gcc/testsuite/g++.dg/cpp0x/explicit-inst2.C
new file mode 100644
index 000000000000..537a1af89ddb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit-inst2.C
@@ -0,0 +1,81 @@
+// PR c++/125613
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+void fn1 (T) {}
+template void fn1<int>(int); // OK
+
+template<typename T>
+void fn2 (T) noexcept {}
+template void fn2<int>(int) noexcept; // OK
+
+template<typename T>
+void fn3 (T) {}
+template void fn3<int>(int) noexcept; // { dg-error "exception specification 
.noexcept. in explicit instantiation does not match the instantiated one 
.noexcept \\(false\\)." }
+
+template<typename T>
+void fn4 (T) noexcept {}
+template void fn4<int>(int); // OK
+
+template<typename T, bool B>
+void fn5 (T) noexcept (B) {}
+template void fn5<int, true>(int) noexcept; // OK
+
+template<typename T, bool B>
+void fn6 (T) noexcept (B) {}
+template void fn6<int, false>(int) noexcept; // { dg-error "exception 
specification .noexcept. in explicit instantiation does not match the 
instantiated one .noexcept \\(false\\)." }
+
+template<typename T, bool B>
+void fn7 (T) noexcept (B) {}
+template void fn7<int, true>(int) noexcept(true); // OK
+
+template<typename T, bool B>
+void fn8 (T) noexcept (B) {}
+template void fn8<int, false>(int) noexcept(false); // OK
+
+template<typename T, bool B>
+void fn9 (T) noexcept (B) {}
+template void fn9<int, true>(int) noexcept(false); // { dg-error "exception 
specification .noexcept \\(false\\). in explicit instantiation does not match 
the instantiated one .noexcept." }
+
+template<typename T>
+void fn10 (T) noexcept {}
+template void fn10<int>(int) noexcept(false); // { dg-error "exception 
specification .noexcept \\(false\\). in explicit instantiation does not match 
the instantiated one .noexcept." }
+
+template<typename T>
+struct S {
+  void mfn1 () noexcept { }
+  void mfn2 () { }
+  template<bool B>
+  void mfn3 () noexcept (B) { }
+  template<bool B>
+  void mfn4 () noexcept (B) { }
+};
+
+template void S<int>::mfn1 () noexcept;
+template void S<int>::mfn2 () noexcept; // { dg-error "exception specification 
.noexcept. in explicit instantiation does not match the instantiated one 
.noexcept \\(false\\)." }
+template void S<int>::mfn3<true>() noexcept;
+template void S<int>::mfn4<false>() noexcept; // { dg-error "exception 
specification .noexcept. in explicit instantiation does not match the 
instantiated one .noexcept \\(false\\)." }
+
+template<typename>
+struct X {
+  X() {}
+  ~X() {}
+};
+template X<int>::X();
+template X<int>::~X();
+
+template<typename>
+struct Y {
+  Y() {}
+  ~Y() {}
+};
+template Y<int>::Y() noexcept; // { dg-error "exception specification 
.noexcept. in explicit instantiation does not match the instantiated one 
.noexcept \\(false\\)." }
+template Y<int>::~Y() noexcept;
+
+template<typename>
+struct Z {
+  Z() noexcept {}
+  ~Z() {}
+};
+template Z<int>::Z() noexcept;
+template Z<int>::~Z() noexcept(false); // { dg-error "exception specification 
.noexcept \\(false\\). in explicit instantiation does not match the 
instantiated one .noexcept." }

Reply via email to