Barry pointed out to me that our braced-init-list as a template-argument extension doesn't work as expected when we aggregate-initialize. Thus fixed by calling digest_init in convert_nontype_argument so that we can actually convert the CONSTRUCTOR.
I don't think we can call digest_init any earlier, and it needs to happen before the call to build_converted_constant_expr. Barry also noticed that we allow designated initializers for non-aggregate types in the template-argument argument context, i.e. this struct S { unsigned a; unsigned b; constexpr S(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { } }; template<S s> struct X { }; void f() { X<{.a = 1, .b = 2}> x; } probably should not compile. But I'm not too sure about it, and don't know how I would fix it anyway, so I'm not dealing with it in this patch. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? gcc/cp/ChangeLog: PR c++/95369 * pt.c (convert_nontype_argument): In C++20, reshape and digest a braced-init-list if the type is an aggregate. gcc/testsuite/ChangeLog: PR c++/95369 * g++.dg/cpp2a/nontype-class38.C: New test. --- gcc/cp/pt.c | 13 +++++++++ gcc/testsuite/g++.dg/cpp2a/nontype-class38.C | 30 ++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class38.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 90dafff3aa7..adb7593f77d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7133,6 +7133,19 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) return error_mark_node; } + /* For a { } template argument, like in X<{ 1, 2 }>, we need to digest + here so that build_converted_constant_expr below is able to convert + it to TYPE. */ + if (cxx_dialect >= cxx20 + && BRACE_ENCLOSED_INITIALIZER_P (expr) + && CP_AGGREGATE_TYPE_P (type)) + { + expr = reshape_init (type, expr, complain); + expr = digest_init (type, expr, complain); + if (expr == error_mark_node) + return error_mark_node; + } + /* If we are in a template, EXPR may be non-dependent, but still have a syntactic, rather than semantic, form. For example, EXPR might be a SCOPE_REF, rather than the VAR_DECL to which the diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class38.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class38.C new file mode 100644 index 00000000000..5b440fd1c9e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class38.C @@ -0,0 +1,30 @@ +// PR c++/95369 +// { dg-do compile { target c++20 } } + +struct S { + int a; + int b; +}; + +struct W { + int i; + S s; +}; + +template <S p> +void fnc() +{ +} + +template<S s> struct X { }; +template<W w> struct Y { }; + +void f() +{ + fnc<{ .a = 10, .b = 20 }>(); + fnc<{ 10, 20 }>(); + X<{ .a = 1, .b = 2 }> x; + X<{ 1, 2 }> x2; + // Brace elision is likely to be allowed. + Y<{ 1, 2, 3 }> x3; +} base-commit: 3d8d5ddb539a5254c7ef83414377f4c74c7701d4 -- Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA