]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: explicit instantiation and noexcept-specifier [PR125613]
authorMarek Polacek <polacek@redhat.com>
Fri, 5 Jun 2026 17:42:06 +0000 (13:42 -0400)
committerMarek Polacek <polacek@redhat.com>
Wed, 17 Jun 2026 15:05:00 +0000 (11:05 -0400)
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 <jason@redhat.com>
gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp0x/explicit-inst2.C [new file with mode: 0644]

index 0c0b3a2cac571be33d48ca674e75336a48ccd458..b7f9ce4cb0a3c933ece8e8366b5d5604a0581b45 100644 (file)
@@ -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 (file)
index 0000000..537a1af
--- /dev/null
@@ -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." }