aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-11-15 09:51:05 -0500
committerJason Merrill <jason@gcc.gnu.org>2019-11-15 09:51:05 -0500
commit9b41ebbcdf9e33285a0eebeb7c841afe20e4a7c1 (patch)
tree63d5b9a564430d47fdbe55993a501c3fa8fa098e
parentf6e20012ef792d659fec65fafecc29736c57f79c (diff)
downloadgcc-9b41ebbcdf9e33285a0eebeb7c841afe20e4a7c1.zip
gcc-9b41ebbcdf9e33285a0eebeb7c841afe20e4a7c1.tar.gz
gcc-9b41ebbcdf9e33285a0eebeb7c841afe20e4a7c1.tar.bz2
Implement P1816R0, class template argument deduction for aggregates.
Rather than reimplement brace elision here, we call reshape_init and then discard the result. We needed to set CLASSTYPE_NON_AGGREGATE a bit more in this patch, since outside a template it's set in check_bases_and_members. * pt.c (maybe_aggr_guide, collect_ctor_idx_types): New. (is_spec_or_derived): Split out from do_class_deduction. (build_deduction_guide): Handle aggregate guide. * class.c (finish_struct): Set CLASSTYPE_NON_AGGREGATE in a template. * cp-tree.h (CP_AGGREGATE_TYPE_P): An incomplete class is not an aggregate. From-SVN: r278298
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/class.c14
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/pt.c172
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction43.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr1.C36
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr2.C52
7 files changed, 254 insertions, 35 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f45b59b..0129731 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2019-11-14 Jason Merrill <jason@redhat.com>
+
+ Implement P1816R0, class template argument deduction for aggregates.
+ * pt.c (maybe_aggr_guide, collect_ctor_idx_types): New.
+ (is_spec_or_derived): Split out from do_class_deduction.
+ (build_deduction_guide): Handle aggregate guide.
+ * class.c (finish_struct): Set CLASSTYPE_NON_AGGREGATE in a
+ template.
+ * cp-tree.h (CP_AGGREGATE_TYPE_P): An incomplete class is not an
+ aggregate.
+
2019-11-14 Richard Sandiford <richard.sandiford@arm.com>
* call.c (build_conditional_expr_1): Use truth_type_for instead
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a9aa5e7..ef1d513 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7349,7 +7349,16 @@ finish_struct (tree t, tree attributes)
add_method (t, *iter, true);
}
else if (DECL_DECLARES_FUNCTION_P (x))
- DECL_IN_AGGR_P (x) = false;
+ {
+ DECL_IN_AGGR_P (x) = false;
+ if (DECL_VIRTUAL_P (x))
+ CLASSTYPE_NON_AGGREGATE (t) = true;
+ }
+ else if (TREE_CODE (x) == FIELD_DECL)
+ {
+ if (TREE_PROTECTED (x) || TREE_PRIVATE (x))
+ CLASSTYPE_NON_AGGREGATE (t) = true;
+ }
/* Also add a USING_DECL for operator=. We know there'll be (at
least) one, but we don't know the signature(s). We want name
@@ -7387,6 +7396,9 @@ finish_struct (tree t, tree attributes)
/* Remember current #pragma pack value. */
TYPE_PRECISION (t) = maximum_field_alignment;
+ if (TYPE_HAS_USER_CONSTRUCTOR (t))
+ CLASSTYPE_NON_AGGREGATE (t) = 1;
+
/* Fix up any variants we've already built. */
for (x = TYPE_NEXT_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 42afe1b..56b75ca 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4251,7 +4251,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define CP_AGGREGATE_TYPE_P(TYPE) \
(TREE_CODE (TYPE) == VECTOR_TYPE \
|| TREE_CODE (TYPE) == ARRAY_TYPE \
- || (CLASS_TYPE_P (TYPE) && !CLASSTYPE_NON_AGGREGATE (TYPE)))
+ || (CLASS_TYPE_P (TYPE) && COMPLETE_TYPE_P (TYPE) && !CLASSTYPE_NON_AGGREGATE (TYPE)))
/* Nonzero for a class type means that the class type has a
user-declared constructor. */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 84db3f9..8f7734a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27724,28 +27724,39 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
/* Returns a C++17 class deduction guide template based on the constructor
CTOR. As a special case, CTOR can be a RECORD_TYPE for an implicit default
- guide, or REFERENCE_TYPE for an implicit copy/move guide. */
+ guide, REFERENCE_TYPE for an implicit copy/move guide, or TREE_LIST for an
+ aggregate initialization guide. */
static tree
-build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
+build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t complain)
{
- tree type, tparms, targs, fparms, fargs, ci;
+ tree tparms, targs, fparms, fargs, ci;
bool memtmpl = false;
bool explicit_p;
location_t loc;
tree fn_tmpl = NULL_TREE;
- if (TYPE_P (ctor))
+ if (outer_args)
{
- type = ctor;
- bool copy_p = TYPE_REF_P (type);
- if (copy_p)
+ ++processing_template_decl;
+ type = tsubst (type, outer_args, complain, CLASSTYPE_TI_TEMPLATE (type));
+ --processing_template_decl;
+ }
+
+ if (!DECL_DECLARES_FUNCTION_P (ctor))
+ {
+ if (TYPE_P (ctor))
{
- type = TREE_TYPE (type);
- fparms = tree_cons (NULL_TREE, type, void_list_node);
+ bool copy_p = TYPE_REF_P (ctor);
+ if (copy_p)
+ fparms = tree_cons (NULL_TREE, type, void_list_node);
+ else
+ fparms = void_list_node;
}
+ else if (TREE_CODE (ctor) == TREE_LIST)
+ fparms = ctor;
else
- fparms = void_list_node;
+ gcc_unreachable ();
tree ctmpl = CLASSTYPE_TI_TEMPLATE (type);
tparms = DECL_TEMPLATE_PARMS (ctmpl);
@@ -27767,8 +27778,6 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
fn_tmpl = tsubst (fn_tmpl, outer_args, complain, ctor);
ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
- type = DECL_CONTEXT (ctor);
-
tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
/* If type is a member class template, DECL_TI_ARGS (ctor) will have
fully specialized args for the enclosing class. Strip those off, as
@@ -27889,6 +27898,103 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
return ded_tmpl;
}
+/* Add to LIST the member types for the reshaped initializer CTOR. */
+
+static tree
+collect_ctor_idx_types (tree ctor, tree list)
+{
+ vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (ctor);
+ tree idx, val; unsigned i;
+ FOR_EACH_CONSTRUCTOR_ELT (v, i, idx, val)
+ {
+ 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);
+ }
+
+ return list;
+}
+
+/* Return a C++20 aggregate deduction candidate for TYPE initialized from
+ INIT. */
+
+static tree
+maybe_aggr_guide (tree type, tree init)
+{
+ if (cxx_dialect < cxx2a)
+ return NULL_TREE;
+
+ if (init == NULL_TREE)
+ return NULL_TREE;
+ if (!CP_AGGREGATE_TYPE_P (type))
+ return NULL_TREE;
+
+ /* If we encounter a problem, we just won't add the candidate. */
+ tsubst_flags_t complain = tf_none;
+
+ tree parms = NULL_TREE;
+ if (TREE_CODE (init) == CONSTRUCTOR)
+ {
+ init = reshape_init (type, init, complain);
+ if (init == error_mark_node)
+ return NULL_TREE;
+ parms = collect_ctor_idx_types (init, parms);
+ }
+ else if (TREE_CODE (init) == TREE_LIST)
+ {
+ int len = list_length (init);
+ for (tree field = TYPE_FIELDS (type);
+ len;
+ --len, field = DECL_CHAIN (field))
+ {
+ field = next_initializable_field (field);
+ if (!field)
+ return NULL_TREE;
+ tree ftype = finish_decltype_type (field, true, complain);
+ parms = tree_cons (NULL_TREE, ftype, parms);
+ }
+ }
+ else
+ /* Aggregate initialization doesn't apply to an initializer expression. */
+ return NULL_TREE;
+
+ if (parms)
+ {
+ tree last = parms;
+ parms = nreverse (parms);
+ TREE_CHAIN (last) = void_list_node;
+ tree guide = build_deduction_guide (type, parms, NULL_TREE, complain);
+ return guide;
+ }
+
+ return NULL_TREE;
+}
+
+/* Return whether ETYPE is, or is derived from, a specialization of TMPL. */
+
+static bool
+is_spec_or_derived (tree etype, tree tmpl)
+{
+ if (!etype || !CLASS_TYPE_P (etype))
+ return false;
+
+ tree type = TREE_TYPE (tmpl);
+ tree tparms = (INNERMOST_TEMPLATE_PARMS
+ (DECL_TEMPLATE_PARMS (tmpl)));
+ tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
+ int err = unify (tparms, targs, type, etype,
+ UNIFY_ALLOW_DERIVED, /*explain*/false);
+ ggc_free (targs);
+ return !err;
+}
+
/* Deduce template arguments for the class template placeholder PTYPE for
template TMPL based on the initializer INIT, and return the resulting
type. */
@@ -27913,16 +28019,15 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
tree type = TREE_TYPE (tmpl);
bool try_list_ctor = false;
+ bool copy_init = false;
releasing_vec rv_args = NULL;
vec<tree,va_gc> *&args = *&rv_args;
- if (init == NULL_TREE
- || TREE_CODE (init) == TREE_LIST)
- args = make_tree_vector_from_list (init);
+ if (init == NULL_TREE)
+ args = make_tree_vector ();
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
{
- try_list_ctor = TYPE_HAS_LIST_CTOR (type);
- if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1)
+ if (CONSTRUCTOR_NELTS (init) == 1)
{
/* As an exception, the first phase in 16.3.1.7 (considering the
initializer list as a single argument) is omitted if the
@@ -27930,26 +28035,24 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
where U is a specialization of C or a class derived from a
specialization of C. */
tree elt = CONSTRUCTOR_ELT (init, 0)->value;
- if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
- {
- tree etype = TREE_TYPE (elt);
- tree tparms = (INNERMOST_TEMPLATE_PARMS
- (DECL_TEMPLATE_PARMS (tmpl)));
- tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
- int err = unify (tparms, targs, type, etype,
- UNIFY_ALLOW_DERIVED, /*explain*/false);
- if (err == 0)
- try_list_ctor = false;
- ggc_free (targs);
- }
+ copy_init = is_spec_or_derived (TREE_TYPE (elt), tmpl);
}
+ try_list_ctor = !copy_init && TYPE_HAS_LIST_CTOR (type);
if (try_list_ctor || is_std_init_list (type))
args = make_tree_vector_single (init);
else
args = make_tree_vector_from_ctor (init);
}
else
- args = make_tree_vector_single (init);
+ {
+ if (TREE_CODE (init) == TREE_LIST)
+ args = make_tree_vector_from_list (init);
+ else
+ args = make_tree_vector_single (init);
+
+ if (args->length() == 1)
+ copy_init = is_spec_or_derived (TREE_TYPE ((*args)[0]), tmpl);
+ }
tree dname = dguide_name (tmpl);
tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname,
@@ -27994,7 +28097,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
if (iter.using_p ())
continue;
- tree guide = build_deduction_guide (*iter, outer_args, complain);
+ tree guide = build_deduction_guide (type, *iter, outer_args, complain);
if (guide == error_mark_node)
return error_mark_node;
if ((flags & LOOKUP_ONLYCONVERTING)
@@ -28006,6 +28109,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
saw_ctor = true;
}
+ if (!copy_init)
+ if (tree guide = maybe_aggr_guide (type, init))
+ cands = lookup_add (guide, cands);
+
tree call = error_mark_node;
/* If this is list-initialization and the class has a list constructor, first
@@ -28047,7 +28154,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
if (gtype)
{
- tree guide = build_deduction_guide (gtype, outer_args, complain);
+ tree guide = build_deduction_guide (type, gtype, outer_args,
+ complain);
if (guide == error_mark_node)
return error_mark_node;
cands = lookup_add (guide, cands);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction43.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction43.C
index 55a79b3..2585eb6 100644
--- a/gcc/testsuite/g++.dg/cpp1z/class-deduction43.C
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction43.C
@@ -7,4 +7,4 @@ struct array
int a [N];
};
-array a = { 1, 2, 3 }; // { dg-error "cannot deduce" }
+array a = { 1, 2, 3 }; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr1.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr1.C
new file mode 100644
index 0000000..61ba65a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr1.C
@@ -0,0 +1,36 @@
+// Testcase from P1816R0
+// { dg-do compile { target c++2a } }
+
+template <typename T>
+struct S {
+ T x;
+ T y;
+};
+
+S s = { 1, 2 };
+
+template <typename T>
+struct C {
+ S<T> s;
+ T t;
+};
+template <typename T>
+struct D {
+ S<int> s;
+ T t;
+};
+C c1 = {1, 2}; // { dg-error "" "deduction failed" }
+C c2 = {1, 2, 3}; // { dg-error "" "deduction failed" }
+C c3 = {{1u, 2u}, 3}; // { dg-bogus "" "OK, C<int> deduced" }
+D d1 = {1, 2}; // { dg-error "" "deduction failed" }
+D d2 = {1, 2, 3}; // { dg-bogus "" "OK, braces elided, D<int> deduced" }
+template <typename T>
+struct I {
+ using type = T;
+};
+template <typename T>
+struct E {
+ typename I<T>::type i;
+ T t;
+};
+E e1 = {1, 2}; // { dg-bogus "" "OK, E<int> deduced" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr2.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr2.C
new file mode 100644
index 0000000..896554f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr2.C
@@ -0,0 +1,52 @@
+// Test that non-aggregates don't get the aggregate deduction.
+// { dg-do compile { target c++2a } }
+// { dg-prune-output "no matching function" }
+
+struct A { A(); };
+
+template <typename T>
+struct S1 {
+ T x;
+};
+
+S1 s1 = {1}; // OK
+
+template <typename T>
+struct S2 {
+ S2 ();
+ T x;
+};
+
+S2 s2 = {1}; // { dg-error "deduction failed" }
+
+template <typename T>
+struct S3 {
+private:
+ T x;
+};
+
+S3 s3 = {1}; // { dg-error "deduction failed" }
+
+template <typename T>
+struct S4 {
+ virtual void f();
+ T x;
+};
+
+S4 s4 = {1}; // { dg-error "deduction failed" }
+
+template <typename T>
+struct S5: public A {
+ using A::A;
+ T x;
+};
+
+S5 s5 = {1}; // { dg-error "deduction failed" }
+
+template <typename T>
+struct S6: virtual A {
+ T x;
+};
+
+S6 s6 = {1}; // { dg-error "deduction failed" }
+