From fb5ce60890c11a637aa1809389a9e8f6f7b87360 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 3 Mar 2017 02:31:54 -0500 Subject: [PATCH] Update overload resolution with deduction guides. * pt.c (do_class_deduction): Always build the copy guide. (copy_guide_p, template_guide_p): New. (build_deduction_guide): Remember the original constructor. * call.c (joust): Prefer the copy guide and non-template guides. From-SVN: r245859 --- gcc/cp/ChangeLog | 6 +++ gcc/cp/call.c | 16 +++++++ gcc/cp/cp-tree.h | 2 + gcc/cp/pt.c | 44 ++++++++++++++----- .../g++.dg/cpp1z/class-deduction36.C | 15 +++++++ .../g++.dg/cpp1z/class-deduction38.C | 27 ++++++++++++ 6 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction36.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction38.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7b68b139599..be98880c963 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2017-03-02 Jason Merrill + Update overload resolution with deduction guides. + * pt.c (do_class_deduction): Always build the copy guide. + (copy_guide_p, template_guide_p): New. + (build_deduction_guide): Remember the original constructor. + * call.c (joust): Prefer the copy guide and non-template guides. + Allow deduction guides to look into primary template. * cp-tree.h (struct saved_scope): Add deduction_guide_type. (struct cp_decl_specifier_seq): Add constructor_p. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index babab00158d..dc629b96bb7 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9717,6 +9717,22 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, int art2 = DECL_ARTIFICIAL (cand2->fn); if (art1 != art2) return art2 - art1; + + if (art1) + { + /* Prefer the special copy guide over a declared copy/move + constructor. */ + if (copy_guide_p (cand1->fn)) + return 1; + if (copy_guide_p (cand2->fn)) + return -1; + + /* Prefer a candidate generated from a non-template constructor. */ + int tg1 = template_guide_p (cand1->fn); + int tg2 = template_guide_p (cand2->fn); + if (tg1 != tg2) + return tg2 - tg1; + } } /* or, if not that, F2 is from a using-declaration, F1 is not, and the diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 31edc5f175b..75836727d80 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6288,6 +6288,8 @@ extern tree template_parm_to_arg (tree); extern tree dguide_name (tree); 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); /* in repo.c */ extern void init_repo (void); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3b320fc2b48..13293ebd557 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -24852,6 +24852,35 @@ deduction_guide_p (const_tree fn) return false; } +/* True if FN is the copy deduction guide, i.e. A(A)->A. */ + +bool +copy_guide_p (const_tree fn) +{ + gcc_assert (deduction_guide_p (fn)); + if (!DECL_ARTIFICIAL (fn)) + return false; + tree parms = FUNCTION_FIRST_USER_PARMTYPE (DECL_TI_TEMPLATE (fn)); + return (TREE_CHAIN (parms) == void_list_node + && same_type_p (TREE_VALUE (parms), TREE_TYPE (DECL_NAME (fn)))); +} + +/* True if FN is a guide generated from a constructor template. */ + +bool +template_guide_p (const_tree fn) +{ + gcc_assert (deduction_guide_p (fn)); + if (!DECL_ARTIFICIAL (fn)) + return false; + if (tree ctor = DECL_ABSTRACT_ORIGIN (fn)) + { + tree tmpl = DECL_TI_TEMPLATE (ctor); + return PRIMARY_TEMPLATE_P (tmpl); + } + return false; +} + /* 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 @@ -25100,6 +25129,8 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn); DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs); DECL_PRIMARY_TEMPLATE (ded_tmpl) = ded_tmpl; + if (DECL_P (ctor)) + DECL_ABSTRACT_ORIGIN (ded_fn) = ctor; if (ci) set_constraints (ded_tmpl, ci); @@ -25153,7 +25184,6 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags, } bool saw_ctor = false; - bool saw_copy = false; if (CLASSTYPE_METHOD_VEC (type)) // FIXME cache artificial deduction guides for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns)) @@ -25163,16 +25193,6 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags, cands = ovl_cons (guide, cands); saw_ctor = true; - - tree parms = FUNCTION_FIRST_USER_PARMTYPE (fn); - if (parms && sufficient_parms_p (TREE_CHAIN (parms))) - { - tree pt = TREE_VALUE (parms); - if (TREE_CODE (pt) == REFERENCE_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (pt), type))) - saw_copy = true; - } } if (!saw_ctor && args->length() == 0) @@ -25180,7 +25200,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags, tree guide = build_deduction_guide (type, outer_args, complain); cands = ovl_cons (guide, cands); } - if (!saw_copy && args->length() == 1) + if (args->length() == 1) { tree guide = build_deduction_guide (build_reference_type (type), outer_args, complain); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C new file mode 100644 index 00000000000..129e29ec131 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C @@ -0,0 +1,15 @@ +// { dg-options -std=c++1z } + +template struct A { + A(T&); + A(const A&); +}; + +int i; +A a = i; +A a2 = a; + +template struct same; +template struct same {}; +same> s1; +same> s2; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C new file mode 100644 index 00000000000..fe6c20012aa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C @@ -0,0 +1,27 @@ +// { dg-options -std=c++1z } + +template struct A { + using value_type = T; + A(value_type); // #1 + A(const A&); // #2 + A(T, T, int); // #3 + template A(int, T, U); // #4 +}; // A(A); #5, the copy deduction candidate + +A x (1, 2, 3); // uses #3, generated from a non-template constructor + +template A(T) -> A; // #6, less specialized than #5 + +A a (42); // uses #6 to deduce A and #1 to initialize +A b = a; // uses #5 to deduce A and #2 to initialize + +template A(A) -> A>; // #7, as specialized as #5 + +A b2 = a; // uses #7 to deduce A> and #1 to initialize + +template struct same; +template struct same {}; + +same> s1; +same> s2; +same>> s3; -- 2.30.2