diff --git a/src/expr.c b/src/expr.c index 8986d35f0c..f0abc94b52 100644 --- a/src/expr.c +++ b/src/expr.c @@ -54859,8 +54859,10 @@ is TRUE if the expression is the immediate operand of an "&" operator. } /* if */ } else if (is_nontype_template_param_symbol(fund_sym)) { /* A dependent construct. Represent it generically with a - tpck_template_ref constant. */ - expl_templ_arg_list = + tpck_template_ref constant. Leave expl_templ_arg_list + unsubstituted, since scan_identifier will also substitute + it. */ + a_template_arg_ptr subst_templ_arg_list = copy_template_arg_list_with_substitution_rebuilding_arg_operands( fund_sym, expl_templ_arg_list, (a_template_param_ptr)NULL, @@ -54875,7 +54877,7 @@ is TRUE if the expression is the immediate operand of an "&" operator. con->variant.template_param.variant.template_ref.con = sym->variant.constant; con->variant.template_param.variant.template_ref.arg_list = - expl_templ_arg_list; + subst_templ_arg_list; con->type = type_of_unknown_templ_param_nontype; sym = alloc_symbol(sk_constant, sym->header, &sym->decl_position); diff --git a/src/pending_changes/gh-532-alias-ctad-noexcept-template-call.txt b/src/pending_changes/gh-532-alias-ctad-noexcept-template-call.txt new file mode 100644 index 0000000000..e8d4245c43 --- /dev/null +++ b/src/pending_changes/gh-532-alias-ctad-noexcept-template-call.txt @@ -0,0 +1,18 @@ +[GH #532] +Alias template CTAD with a template-id in a constructor noexcept specification + +Class template argument deduction through an alias template could crash +when the noexcept specification of a constructor template of the underlying +class template called a member function template with the constructor's +template parameter pack as explicit template arguments, e.g. aliases of +std::tuple with libstdc++. The explicit template arguments were substituted +twice. For example, with --c++20: + + template struct S { + template static constexpr bool n() { return true; } + S(const E&...) {} + template S(U&&...) noexcept(n()) {} + }; + template struct F {}; + template using A = S...>; + A a{F{}}; diff --git a/tests/tests/regressions/.gh-532.rto/default.1.1.txt b/tests/tests/regressions/.gh-532.rto/default.1.1.txt new file mode 100644 index 0000000000..32fc82e916 --- /dev/null +++ b/tests/tests/regressions/.gh-532.rto/default.1.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=1 --c++20 Test_name.c diff --git a/tests/tests/regressions/.gh-532.rto/default.2.1.txt b/tests/tests/regressions/.gh-532.rto/default.2.1.txt new file mode 100644 index 0000000000..15f97a3e0c --- /dev/null +++ b/tests/tests/regressions/.gh-532.rto/default.2.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=2 --c++20 --g++ --gnu_version=150200 Test_name.c diff --git a/tests/tests/regressions/.gh-532.rto/default.3.1.txt b/tests/tests/regressions/.gh-532.rto/default.3.1.txt new file mode 100644 index 0000000000..8f47794cbf --- /dev/null +++ b/tests/tests/regressions/.gh-532.rto/default.3.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=3 --c++20 --clang --clang_version=220100 Test_name.c diff --git a/tests/tests/regressions/.gh-532.rto/default.4.1.txt b/tests/tests/regressions/.gh-532.rto/default.4.1.txt new file mode 100644 index 0000000000..1bbe45a65c --- /dev/null +++ b/tests/tests/regressions/.gh-532.rto/default.4.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=4 --ms_c++20 --microsoft_version 1950 Test_name.c diff --git a/tests/tests/regressions/gh-532.sft.cpp b/tests/tests/regressions/gh-532.sft.cpp new file mode 100644 index 0000000000..be10456b0f --- /dev/null +++ b/tests/tests/regressions/gh-532.sft.cpp @@ -0,0 +1,18 @@ +//type:fp +//options:--c++20:--c++20 --g++ --gnu_version=150200:--c++20 --clang --clang_version=220100:--ms_c++20 --microsoft_version 1950 + +// Class template argument deduction through an alias template crashed when +// the noexcept specification of a constructor template called a member +// function template with the constructor's parameter pack as explicit +// template arguments, e.g. aliases of std::tuple with libstdc++. The +// explicit template arguments of the call were substituted twice. + +template struct S +{ + template static constexpr bool n() { return true; } + S(const E&...) {} + template S(U&&...) noexcept(n()) {} +}; +template struct F {}; +template using A = S...>; +A a{F{}};