Hi! In C++20, types with user-declared constructors are not aggregate types, while in C++17 only types with user-provided or explicit constructors. In check_bases_and_members we handle it properly: CLASSTYPE_NON_AGGREGATE (t) |= ((cxx_dialect < cxx2a ? type_has_user_provided_or_explicit_constructor (t) : TYPE_HAS_USER_CONSTRUCTOR (t)) || TYPE_POLYMORPHIC_P (t)); but for templates the code right now behaves the C++20 way regardless of the selected standard.
The following patch tweaks finish_struct to match check_bases_and_members. I had to add !CLASSTYPE_NON_AGGREGATE check because type_has_user_provided_or_explicit_constructor -> user_provided_p ICEd on inherited ctors represented as USING_DECLs. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2019-12-10 Jakub Jelinek <ja...@redhat.com> PR c++/92869 * class.c (finish_struct): For C++17 and earlier, check type_has_user_provided_or_explicit_constructor rather than TYPE_HAS_USER_CONSTRUCTOR whether to set CLASSTYPE_NON_AGGREGATE. * g++.dg/cpp0x/aggr3.C: New test. --- gcc/cp/class.c.jj 2019-12-06 00:40:44.525629037 +0100 +++ gcc/cp/class.c 2019-12-10 14:18:41.171380767 +0100 @@ -7456,7 +7456,13 @@ finish_struct (tree t, tree attributes) /* Remember current #pragma pack value. */ TYPE_PRECISION (t) = maximum_field_alignment; - if (TYPE_HAS_USER_CONSTRUCTOR (t)) + if (cxx_dialect < cxx2a) + { + if (!CLASSTYPE_NON_AGGREGATE (t) + && type_has_user_provided_or_explicit_constructor (t)) + CLASSTYPE_NON_AGGREGATE (t) = 1; + } + else if (TYPE_HAS_USER_CONSTRUCTOR (t)) CLASSTYPE_NON_AGGREGATE (t) = 1; /* Fix up any variants we've already built. */ --- gcc/testsuite/g++.dg/cpp0x/aggr3.C.jj 2019-12-10 14:25:22.344231923 +0100 +++ gcc/testsuite/g++.dg/cpp0x/aggr3.C 2019-12-10 14:23:31.700927787 +0100 @@ -0,0 +1,20 @@ +// PR c++/92869 +// { dg-do compile { target c++11 } } + +struct A { + A () = default; + A (const A &) = default; + A (A &&) = default; + int arr[3]; +}; + +template <typename T, int N> +struct B { + B () = default; + B (const B &) = default; + B (B &&) = default; + T arr[N]; +}; + +A a = { { 1, 2, 3 } }; // { dg-error "could not convert" "" { target c++2a } } +B<int, 3> b = { { 1, 2, 3 } }; // { dg-error "could not convert" "" { target c++2a } } Jakub