templates are primary, too. */
/* Returns the primary template corresponding to these parameters. */
+#define TPARMS_PRIMARY_TEMPLATE(NODE) (TREE_TYPE (NODE))
+
#define DECL_PRIMARY_TEMPLATE(NODE) \
- (TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)))
+ (TPARMS_PRIMARY_TEMPLATE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)))
/* Returns nonzero if NODE is a primary template. */
#define PRIMARY_TEMPLATE_P(NODE) (DECL_PRIMARY_TEMPLATE (NODE) == (NODE))
extern bool deduction_guide_p (const_tree);
extern bool copy_guide_p (const_tree);
extern bool template_guide_p (const_tree);
+extern bool builtin_guide_p (const_tree);
extern void store_explicit_specifier (tree, tree);
extern tree add_outermost_template_args (tree, tree);
/* The initializer for a class is always a CONSTRUCTOR. */
new_init = build_constructor (init_list_type_node, NULL);
- field = next_initializable_field (TYPE_FIELDS (type));
+
+ int binfo_idx = -1;
+ tree binfo = TYPE_BINFO (type);
+ tree base_binfo = NULL_TREE;
+ if (cxx_dialect >= cxx17 && uses_template_parms (type))
+ {
+ /* We get here from maybe_aggr_guide for C++20 class template argument
+ deduction. In this case we need to look through the binfo because a
+ template doesn't have base fields. */
+ binfo_idx = 0;
+ BINFO_BASE_ITERATE (binfo, binfo_idx, base_binfo);
+ }
+ if (base_binfo)
+ field = base_binfo;
+ else
+ field = next_initializable_field (TYPE_FIELDS (type));
if (!field)
{
return new_init;
}
+ /* For C++20 CTAD, handle pack expansions in the base list. */
+ tree last_was_pack_expansion = NULL_TREE;
+
/* Loop through the initializable fields, gathering initializers. */
while (d->cur != d->end)
{
if (!field)
break;
+ last_was_pack_expansion = (PACK_EXPANSION_P (TREE_TYPE (field))
+ ? field : NULL_TREE);
+ if (last_was_pack_expansion)
+ /* Each non-trailing aggregate element that is a pack expansion is
+ assumed to correspond to no elements of the initializer list. */
+ goto continue_;
+
field_init = reshape_init_r (TREE_TYPE (field), d,
/*first_initializer_p=*/NULL_TREE,
complain);
if (TREE_CODE (type) == UNION_TYPE)
break;
- field = next_initializable_field (DECL_CHAIN (field));
+ continue_:
+ if (base_binfo)
+ {
+ BINFO_BASE_ITERATE (binfo, ++binfo_idx, base_binfo);
+ if (base_binfo)
+ field = base_binfo;
+ else
+ field = next_initializable_field (TYPE_FIELDS (type));
+ }
+ else
+ field = next_initializable_field (DECL_CHAIN (field));
+ }
+
+ /* A trailing aggregate element that is a pack expansion is assumed to
+ correspond to all remaining elements of the initializer list (if any). */
+ if (last_was_pack_expansion)
+ {
+ CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init),
+ last_was_pack_expansion, d->cur->value);
+ while (d->cur != d->end)
+ d->cur++;
}
return new_init;
/* A non-aggregate type is always initialized with a single
initializer. */
- if (!CP_AGGREGATE_TYPE_P (type))
+ if (!CP_AGGREGATE_TYPE_P (type)
+ /* As is an array with dependent bound. */
+ || (cxx_dialect >= cxx20
+ && TREE_CODE (type) == ARRAY_TYPE
+ && uses_template_parms (TYPE_DOMAIN (type))))
{
/* It is invalid to initialize a non-aggregate type with a
brace-enclosed initializer before C++0x.
if (TREE_CODE (arg) == DEFERRED_PARSE)
return arg;
+ /* Shortcut {}. */
+ if (BRACE_ENCLOSED_INITIALIZER_P (arg)
+ && CONSTRUCTOR_NELTS (arg) == 0)
+ return arg;
+
tree parm = FUNCTION_FIRST_USER_PARM (fn);
parm = chain_index (parmnum, parm);
tree parmtype = TREE_TYPE (parm);
{
tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE;
tree old_args = ARGUMENT_PACK_ARGS (old_pack);
-
+ temp_override<int> ovl (TREE_VEC_LENGTH (old_args));
+ /* During template argument deduction for the aggregate deduction
+ candidate, the number of elements in a trailing parameter pack
+ is only deduced from the number of remaining function
+ arguments if it is not otherwise deduced. */
+ if (cxx_dialect >= cxx20
+ && TREE_VEC_LENGTH (new_args) < TREE_VEC_LENGTH (old_args)
+ && builtin_guide_p (TPARMS_PRIMARY_TEMPLATE (tparms)))
+ TREE_VEC_LENGTH (old_args) = TREE_VEC_LENGTH (new_args);
if (!comp_template_args (old_args, new_args,
&bad_old_arg, &bad_new_arg))
/* Inconsistent unification of this parameter pack. */
return false;
}
+/* True if FN is an aggregate initialization guide or the copy deduction
+ guide. */
+
+bool
+builtin_guide_p (const_tree fn)
+{
+ if (!deduction_guide_p (fn))
+ return false;
+ if (!DECL_ARTIFICIAL (fn))
+ /* Explicitly declared. */
+ return false;
+ if (DECL_ABSTRACT_ORIGIN (fn))
+ /* Derived from a constructor. */
+ return false;
+ return true;
+}
+
/* OLDDECL is a _DECL for a template parameter. Return a similar parameter at
LEVEL:INDEX, using tsubst_args and complain for substitution into non-type
template parameter types. Note that the handling of template template
/* Add to LIST the member types for the reshaped initializer CTOR. */
static tree
-collect_ctor_idx_types (tree ctor, tree list)
+collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE)
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (ctor);
tree idx, val; unsigned i;
FOR_EACH_CONSTRUCTOR_ELT (v, i, idx, val)
{
+ tree ftype = elt ? elt : finish_decltype_type (idx, true, tf_none);
if (BRACE_ENCLOSED_INITIALIZER_P (val)
- && CONSTRUCTOR_NELTS (val))
- if (tree subidx = CONSTRUCTOR_ELT (val, 0)->index)
- if (TREE_CODE (subidx) == FIELD_DECL)
- {
- list = collect_ctor_idx_types (val, list);
- continue;
- }
- tree ftype = finish_decltype_type (idx, true, tf_none);
- list = tree_cons (NULL_TREE, ftype, list);
+ && CONSTRUCTOR_NELTS (val)
+ /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound
+ type gets a single initializer. */
+ && CP_AGGREGATE_TYPE_P (ftype)
+ && !(TREE_CODE (ftype) == ARRAY_TYPE
+ && uses_template_parms (TYPE_DOMAIN (ftype))))
+ {
+ tree subelt = NULL_TREE;
+ if (TREE_CODE (ftype) == ARRAY_TYPE)
+ subelt = TREE_TYPE (ftype);
+ list = collect_ctor_idx_types (val, list, subelt);
+ continue;
+ }
+ tree arg = NULL_TREE;
+ if (i == v->length() - 1
+ && PACK_EXPANSION_P (ftype))
+ /* Give the trailing pack expansion parameter a default argument to
+ match aggregate initialization behavior, even if we deduce the
+ length of the pack separately to more than we have initializers. */
+ arg = build_constructor (init_list_type_node, NULL);
+ /* if ei is of array type and xi is a braced-init-list or string literal,
+ Ti is an rvalue reference to the declared type of ei */
+ STRIP_ANY_LOCATION_WRAPPER (val);
+ if (TREE_CODE (ftype) == ARRAY_TYPE
+ && (BRACE_ENCLOSED_INITIALIZER_P (val)
+ || TREE_CODE (val) == STRING_CST))
+ ftype = (cp_build_reference_type
+ (ftype, BRACE_ENCLOSED_INITIALIZER_P (val)));
+ list = tree_cons (arg, ftype, list);
}
return list;
--- /dev/null
+// Pack expansion testcases from P2082R1
+// { dg-do compile { target c++20 } }
+
+template<typename U, typename... T>
+struct C2 : T... {
+ U a;
+ static constexpr int len = sizeof...(T);
+};
+C2 c2 = {
+ []{ return 1; },
+};
+static_assert (c2.len == 0);
+
+template <typename... T>
+struct Types {};
+template <typename... T>
+struct F : Types<T...>, T... {};
+struct X {};
+struct Y {};
+struct Z {};
+struct W { operator Y(); };
+F f1 = {Types<X, Y, Z>{}, {}, {}}; // OK, F<X, Y, Z> deduced
+F f2 = {Types<X, Y, Z>{}, X{}, Y{}}; // OK, F<X, Y, Z> deduced
+F f3 = {Types<X, Y, Z>{}, X{}, W{}}; // { dg-error "" } conflicting types deduced; operator Y not considered
--- /dev/null
+// Other testcases from P2082R1
+// { dg-do compile { target c++20 } }
+
+template <typename T>
+struct X {};
+int main() {
+ X<int> x1;
+ X x2 {x1};
+}
+
+template <typename T, int N>
+struct A {
+ T array[N];
+};
+A a1 = {{1, 2, 3}}; // should deduce A<int, 3>
+A a2 = {"meow"}; // should deduce A<const char, 5>
+
+template <typename T>
+struct B {
+ T array[2];
+};
+B b = {0, 1};
+
+template<typename... T>
+struct C : T... {};
+C c = {
+ []{ return 1; },
+ []{ return 2; }
+};