@@ -9633,6 +9633,18 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner;
}
+ /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */
+ if (deduction_guide_p (cand1->fn))
+ {
+ gcc_assert (deduction_guide_p (cand2->fn));
+ /* We distinguish between candidates from an explicit deduction guide and
+ candidates built from a constructor based on DECL_ARTIFICIAL. */
+ int art1 = DECL_ARTIFICIAL (cand1->fn);
+ int art2 = DECL_ARTIFICIAL (cand2->fn);
+ if (art1 != art2)
+ return art2 - art1;
+ }
+
/* or, if not that,
F1 is a non-template function and F2 is a template function
specialization. */
@@ -24776,8 +24776,9 @@ dguide_name_p (tree name)
bool
deduction_guide_p (tree fn)
{
- if (tree name = DECL_NAME (fn))
- return dguide_name_p (name);
+ if (DECL_P (fn))
+ if (tree name = DECL_NAME (fn))
+ return dguide_name_p (name);
return false;
}
@@ -24981,7 +24982,9 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
FUNCTION_DECL,
dguide_name (type), fntype);
DECL_ARGUMENTS (ded_fn) = fargs;
+ DECL_ARTIFICIAL (ded_fn) = true;
tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
+ DECL_ARTIFICIAL (ded_tmpl) = true;
DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn);
DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs);
new file mode 100644
@@ -0,0 +1,24 @@
+// Testcase from P0512R0 for C++17 NB comment US 19
+// { dg-options -std=c++1z }
+
+template<typename> struct remove_ref;
+template<typename _Tp> struct remove_ref { typedef _Tp type; };
+template<typename _Tp> struct remove_ref<_Tp&> { typedef _Tp type; };
+template<typename _Tp> struct remove_ref<_Tp&&> { typedef _Tp type; };
+template<typename _Tp> using remove_ref_t = typename remove_ref<_Tp>::type;
+
+template<class T> struct A {
+ A(T, int*); // #1
+ A(A<T>&, int*); // #2
+ enum { value };
+};
+template<class T, int N = remove_ref_t<T>::value> A(T&&, int*) -> A<T>; //#3
+
+A a{1,0}; // uses #1 to deduce A<int> and initializes with #1
+A b{a,0}; // uses #3 (not #2) to deduce A<A<int>&> and initializes with #1
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+same<decltype(a),A<int>> s1;
+same<decltype(b),A<A<int>&>> s2;
commit 0709587b7c94c96b56d3d303e86fc65cee762ce3
Author: Jason Merrill <jason@redhat.com>
Date: Thu Jan 19 15:17:38 2017 -0500
US 20 - forwarding references and class template argument deduction
* cp-tree.h (TEMPLATE_TYPE_PARM_FOR_CLASS): New.
* pt.c (push_template_decl_real): Set it.
(maybe_adjust_types_for_deduction): Check it.
(rewrite_template_parm): Copy it.
@@ -146,6 +146,7 @@ operator == (const cp_expr &lhs, tree rhs)
BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
FOLD_EXPR_MODOP_P (*_FOLD_EXPR)
IF_STMT_CONSTEXPR_P (IF_STMT)
+ TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -5207,6 +5208,11 @@ enum auto_deduction_context
adc_decomp_type /* Decomposition declaration initializer deduction */
};
+/* True if this type-parameter belongs to a class template, used by C++17
+ class template argument deduction. */
+#define TEMPLATE_TYPE_PARM_FOR_CLASS(NODE) \
+ (TREE_LANG_FLAG_0 (TEMPLATE_TYPE_PARM_CHECK (NODE)))
+
/* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */
#define AUTO_IS_DECLTYPE(NODE) \
(TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE)))
@@ -5263,7 +5263,18 @@ push_template_decl_real (tree decl, bool is_friend)
}
else if (DECL_IMPLICIT_TYPEDEF_P (decl)
&& CLASS_TYPE_P (TREE_TYPE (decl)))
- /* OK */;
+ {
+ /* Class template, set TEMPLATE_TYPE_PARM_FOR_CLASS. */
+ tree parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+ for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i)
+ {
+ tree t = TREE_VALUE (TREE_VEC_ELT (parms, i));
+ if (TREE_CODE (t) == TYPE_DECL)
+ t = TREE_TYPE (t);
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ TEMPLATE_TYPE_PARM_FOR_CLASS (t) = true;
+ }
+ }
else if (TREE_CODE (decl) == TYPE_DECL
&& TYPE_DECL_ALIAS_P (decl))
/* alias-declaration */
@@ -18649,12 +18660,16 @@ maybe_adjust_types_for_deduction (unification_kind_t strict,
*arg = TYPE_MAIN_VARIANT (*arg);
}
- /* From C++0x [14.8.2.1/3 temp.deduct.call] (after DR606), "If P is
- of the form T&&, where T is a template parameter, and the argument
- is an lvalue, T is deduced as A& */
+ /* [14.8.2.1/3 temp.deduct.call], "A forwarding reference is an rvalue
+ reference to a cv-unqualified template parameter that does not represent a
+ template parameter of a class template (during class template argument
+ deduction (13.3.1.8)). If P is a forwarding reference and the argument is
+ an lvalue, the type "lvalue reference to A" is used in place of A for type
+ deduction. */
if (TREE_CODE (*parm) == REFERENCE_TYPE
&& TYPE_REF_IS_RVALUE (*parm)
&& TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM
+ && !TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (*parm))
&& cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED
&& (arg_expr ? lvalue_p (arg_expr)
/* try_one_overload doesn't provide an arg_expr, but
@@ -24798,8 +24813,12 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
if (TREE_CODE (olddecl) == TYPE_DECL
|| TREE_CODE (olddecl) == TEMPLATE_DECL)
{
- newtype = cxx_make_type (TREE_CODE (TREE_TYPE (olddecl)));
+ tree oldtype = TREE_TYPE (olddecl);
+ newtype = cxx_make_type (TREE_CODE (oldtype));
TYPE_MAIN_VARIANT (newtype) = newtype;
+ if (TREE_CODE (oldtype) == TEMPLATE_TYPE_PARM)
+ TEMPLATE_TYPE_PARM_FOR_CLASS (newtype)
+ = TEMPLATE_TYPE_PARM_FOR_CLASS (oldtype);
}
else
newtype = tsubst (TREE_TYPE (olddecl), tsubst_args,
new file mode 100644
@@ -0,0 +1,23 @@
+// Testcase from P0512R0 for C++17 NB comment US 20
+// { dg-options -std=c++1z }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+template<class T> struct A {
+ template<class U>
+ A(T&&, U&&, int*); // #1: T&& is not a forwarding reference
+ // U&& is a forwarding reference
+ A(T&&, int*); // #2
+};
+template<class T>
+A(T&&, int*) -> A<T>; // #3: T&& is a forwarding reference
+
+int i;
+int *ip;
+A a0{0, 0, ip}; // uses #1 to deduce A<int> and #1 to initialize
+same<decltype(a0),A<int>> s1;
+A a2{i, ip}; // uses #3 to deduce A<int&> and #2 to initialize
+same<decltype(a2),A<int&>> s2;
+
+A a{i, 0, ip}; // { dg-error "" } cannot deduce from #1