public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/autopar_devel] c++: Improve CTAD for aggregates [PR93976]
@ 2020-08-22 22:58 Giuliano Belinassi
  0 siblings, 0 replies; only message in thread
From: Giuliano Belinassi @ 2020-08-22 22:58 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fe0ea182f878ee8b31305380ea651002d57b4f8e

commit fe0ea182f878ee8b31305380ea651002d57b4f8e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 22 15:44:45 2020 -0400

    c++: Improve CTAD for aggregates [PR93976]
    
    P2082R1 adjusted the rules for class template argument deduction for an
    aggregate to better handle arrays and pack expansions.
    
    gcc/cp/ChangeLog:
    
            PR c++/93976
            Implement C++20 P2082R1, Fixing CTAD for aggregates.
            * cp-tree.h (TPARMS_PRIMARY_TEMPLATE): Split out from...
            (DECL_PRIMARY_TEMPLATE): ...here.
            (builtin_guide_p): Declare.
            * decl.c (reshape_init_class): Handle bases of a template.
            (reshape_init_r): An array with dependent bound takes a single
            initializer.
            * pt.c (tsubst_default_argument): Shortcut {}.
            (unify_pack_expansion): Allow omitted arguments to trailing pack.
            (builtin_guide_p): New.
            (collect_ctor_idx_types): Give a trailing pack a {} default
            argument.  Handle arrays better.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/class-deduction-aggr3.C: New test.
            * g++.dg/cpp2a/class-deduction-aggr4.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                                   |  5 +-
 gcc/cp/decl.c                                      | 55 +++++++++++++++-
 gcc/cp/pt.c                                        | 73 ++++++++++++++++++----
 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr3.C | 24 +++++++
 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr4.C | 29 +++++++++
 5 files changed, 171 insertions(+), 15 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1396686968..78e8ca4150a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4815,8 +4815,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    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))
@@ -7024,6 +7026,7 @@ extern bool dguide_name_p			(tree);
 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);
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1d960be1ee6..3afad5ca805 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6153,7 +6153,22 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
 
   /* 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)
     {
@@ -6171,6 +6186,9 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
       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)
     {
@@ -6218,6 +6236,13 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
       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);
@@ -6243,7 +6268,27 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
       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;
@@ -6319,7 +6364,11 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
 
   /* 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.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index efaadf73772..53a64c3a15e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13406,6 +13406,11 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
   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);
@@ -22769,7 +22774,15 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	{
 	  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.  */
@@ -27982,6 +27995,23 @@ template_guide_p (const_tree fn)
   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
@@ -28293,22 +28323,43 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
 /* 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;
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr3.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr3.C
new file mode 100644
index 00000000000..13d7ec9b57d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr3.C
@@ -0,0 +1,24 @@
+// 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
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr4.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr4.C
new file mode 100644
index 00000000000..0debbb2443f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr4.C
@@ -0,0 +1,29 @@
+// 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; }
+};


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-08-22 22:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-22 22:58 [gcc/devel/autopar_devel] c++: Improve CTAD for aggregates [PR93976] Giuliano Belinassi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).