From: Marek Polacek Date: Fri, 5 Jun 2026 17:42:06 +0000 (-0400) Subject: c++: explicit instantiation and noexcept-specifier [PR125613] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53efe2f8d66bb6344d084ca731cdec56873c62a0;p=thirdparty%2Fgcc.git 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 void fn (T) {} template void fn(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 --- diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 0c0b3a2cac5..b7f9ce4cb0a 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 00000000000..537a1af89dd --- /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 +void fn1 (T) {} +template void fn1(int); // OK + +template +void fn2 (T) noexcept {} +template void fn2(int) noexcept; // OK + +template +void fn3 (T) {} +template void fn3(int) noexcept; // { dg-error "exception specification .noexcept. in explicit instantiation does not match the instantiated one .noexcept \\(false\\)." } + +template +void fn4 (T) noexcept {} +template void fn4(int); // OK + +template +void fn5 (T) noexcept (B) {} +template void fn5(int) noexcept; // OK + +template +void fn6 (T) noexcept (B) {} +template void fn6(int) noexcept; // { dg-error "exception specification .noexcept. in explicit instantiation does not match the instantiated one .noexcept \\(false\\)." } + +template +void fn7 (T) noexcept (B) {} +template void fn7(int) noexcept(true); // OK + +template +void fn8 (T) noexcept (B) {} +template void fn8(int) noexcept(false); // OK + +template +void fn9 (T) noexcept (B) {} +template void fn9(int) noexcept(false); // { dg-error "exception specification .noexcept \\(false\\). in explicit instantiation does not match the instantiated one .noexcept." } + +template +void fn10 (T) noexcept {} +template void fn10(int) noexcept(false); // { dg-error "exception specification .noexcept \\(false\\). in explicit instantiation does not match the instantiated one .noexcept." } + +template +struct S { + void mfn1 () noexcept { } + void mfn2 () { } + template + void mfn3 () noexcept (B) { } + template + void mfn4 () noexcept (B) { } +}; + +template void S::mfn1 () noexcept; +template void S::mfn2 () noexcept; // { dg-error "exception specification .noexcept. in explicit instantiation does not match the instantiated one .noexcept \\(false\\)." } +template void S::mfn3() noexcept; +template void S::mfn4() noexcept; // { dg-error "exception specification .noexcept. in explicit instantiation does not match the instantiated one .noexcept \\(false\\)." } + +template +struct X { + X() {} + ~X() {} +}; +template X::X(); +template X::~X(); + +template +struct Y { + Y() {} + ~Y() {} +}; +template Y::Y() noexcept; // { dg-error "exception specification .noexcept. in explicit instantiation does not match the instantiated one .noexcept \\(false\\)." } +template Y::~Y() noexcept; + +template +struct Z { + Z() noexcept {} + ~Z() {} +}; +template Z::Z() noexcept; +template Z::~Z() noexcept(false); // { dg-error "exception specification .noexcept \\(false\\). in explicit instantiation does not match the instantiated one .noexcept." }