-- >8 --
PR c++/88252
gcc/cp/ChangeLog:
* cp-tree.h (TEMPLATE_TYPE_PARM_FOR_CLASS): Remove.
* pt.c (push_template_decl): Remove TEMPLATE_TYPE_PARM_FOR_CLASS
handling.
(redeclare_class_template): Likewise.
(forwarding_reference_p): Define.
(maybe_adjust_types_for_deduction): Use it. Add tparms parameter.
(unify_one_argument): Pass tparms to
maybe_adjust_types_for_deduction.
(try_one_overload): Likewise.
(unify): Likewise.
(rewrite_template_parm): Remove TEMPLATE_TYPE_PARM_FOR_CLASS
handling.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1z/class-deduction96.C: New test.
---
gcc/cp/cp-tree.h | 6 --
gcc/cp/pt.c | 89 ++++++++++---------
.../g++.dg/cpp1z/class-deduction96.C | 34 +++++++
3 files changed, 83 insertions(+), 46 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction96.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b1cf44ecdb8..f4bcab5b18d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -443,7 +443,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
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)
DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL)
SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT)
REINTERPRET_CAST_P (in NOP_EXPR)
@@ -5863,11 +5862,6 @@ 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)))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index cf0ce770d52..6d6b7f90985 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -154,8 +154,8 @@ static void tsubst_enum (tree, tree, tree);
static bool check_instantiated_args (tree, tree, tsubst_flags_t);
static int check_non_deducible_conversion (tree, tree, int, int,
struct conversion **, bool);
-static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
- tree);
+static int maybe_adjust_types_for_deduction (tree, unification_kind_t,
+ tree*, tree*, tree);
static int type_unification_real (tree, tree, tree, const tree *,
unsigned int, int, unification_kind_t,
vec<deferred_access_check, va_gc> **,
@@ -5801,18 +5801,7 @@ push_template_decl (tree decl, bool is_friend)
}
else if (DECL_IMPLICIT_TYPEDEF_P (decl)
&& CLASS_TYPE_P (TREE_TYPE (decl)))
- {
- /* 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;
- }
- }
+ /* Class template. */;
else if (TREE_CODE (decl) == TYPE_DECL
&& TYPE_DECL_ALIAS_P (decl))
/* alias-declaration */
@@ -6292,9 +6281,6 @@ redeclare_class_template (tree type, tree parms, tree
cons)
gcc_assert (DECL_CONTEXT (parm) == NULL_TREE);
DECL_CONTEXT (parm) = tmpl;
}
-
- if (TREE_CODE (parm) == TYPE_DECL)
- TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (parm)) = true;
}
tree ci = get_constraints (tmpl);
@@ -21709,6 +21695,40 @@ fn_type_unification (tree fn,
return r;
}
+/* Returns true iff PARM is a forwarding reference in the context of
+ template argument deduction for TMPL. */
+
+static bool
+forwarding_reference_p (tree parm, tree tmpl)
+{
+ /* [temp.deduct.call], "A forwarding reference is an rvalue reference to a
+ cv-unqualified template parameter ..." */
+ if (TYPE_REF_P (parm)
+ && TYPE_REF_IS_RVALUE (parm)
+ && TREE_CODE (TREE_TYPE (parm)) == TEMPLATE_TYPE_PARM
+ && cp_type_quals (TREE_TYPE (parm)) == TYPE_UNQUALIFIED)
+ {
+ /* [temp.deduct.call], "... that does not represent a template parameter
+ of a class template (during class template argument deduction)." */
+ if (tmpl
+ && deduction_guide_p (tmpl)
+ && DECL_ARTIFICIAL (tmpl))
+ {
+ /* Since the template parameters of an artificial guide consist of
+ the template parameters of the class template followed by those of
+ the constructor (if any), we can tell if PARM represents a template
+ parameter of the class template by comparing its index with the
+ arity of the class template. */
+ tree ctmpl = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (TREE_TYPE (tmpl)));
+ if (TEMPLATE_TYPE_IDX (TREE_TYPE (parm))
+ < TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (ctmpl)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
/* Adjust types before performing type deduction, as described in
[temp.deduct.call] and [temp.deduct.conv]. The rules in these two
sections are symmetric. PARM is the type of a function parameter
@@ -21718,7 +21738,8 @@ fn_type_unification (tree fn,
ARG_EXPR is the original argument expression, which may be null. */
static int
-maybe_adjust_types_for_deduction (unification_kind_t strict,
+maybe_adjust_types_for_deduction (tree tparms,
+ unification_kind_t strict,
tree* parm,
tree* arg,
tree arg_expr)
@@ -21741,10 +21762,7 @@ maybe_adjust_types_for_deduction (unification_kind_t
strict,
/* Core issue #873: Do the DR606 thing (see below) for these cases,
too, but here handle it by stripping the reference from PARM
rather than by adding it to ARG. */
- if (TYPE_REF_P (*parm)
- && TYPE_REF_IS_RVALUE (*parm)
- && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM
- && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED
+ if (forwarding_reference_p (*parm, TPARMS_PRIMARY_TEMPLATE (tparms))
&& TYPE_REF_P (*arg)
&& !TYPE_REF_IS_RVALUE (*arg))
*parm = TREE_TYPE (*parm);
@@ -21781,17 +21799,10 @@ maybe_adjust_types_for_deduction (unification_kind_t
strict,
*arg = TYPE_MAIN_VARIANT (*arg);
}
- /* [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 (TYPE_REF_P (*parm)
- && 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
+ /* [temp.deduct.call], "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 (forwarding_reference_p (*parm, TPARMS_PRIMARY_TEMPLATE (tparms))
&& (arg_expr ? lvalue_p (arg_expr)
/* try_one_overload doesn't provide an arg_expr, but
functions are always lvalues. */
@@ -22080,8 +22091,8 @@ unify_one_argument (tree tparms, tree targs, tree parm,
tree arg,
return unify_invalid (explain_p);
}
- arg_strict |=
- maybe_adjust_types_for_deduction (strict, &parm, &arg, arg_expr);
+ arg_strict |= maybe_adjust_types_for_deduction (tparms, strict,
+ &parm, &arg, arg_expr);
}
else
if ((TYPE_P (parm) || TREE_CODE (parm) == TEMPLATE_DECL)
@@ -22750,7 +22761,8 @@ try_one_overload (tree tparms,
else if (addr_p)
arg = build_pointer_type (arg);
- sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg, NULL);
+ sub_strict |= maybe_adjust_types_for_deduction (tparms, strict,
+ &parm, &arg, NULL_TREE);
/* We don't copy orig_targs for this because if we have already deduced
some template args from previous args, unify would complain when we
@@ -23449,7 +23461,7 @@ unify (tree tparms, tree targs, tree parm, tree arg,
int strict,
/* It should only be possible to get here for a call. */
gcc_assert (elt_strict & UNIFY_ALLOW_OUTER_LEVEL);
elt_strict |= maybe_adjust_types_for_deduction
- (DEDUCE_CALL, &elttype, &type, elt);
+ (tparms, DEDUCE_CALL, &elttype, &type, elt);
elt = type;
}
@@ -28495,9 +28507,6 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
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
{
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction96.C
b/gcc/testsuite/g++.dg/cpp1z/class-deduction96.C
new file mode 100644
index 00000000000..7fa8400830e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction96.C
@@ -0,0 +1,34 @@
+// PR c++/88252
+// { dg-do compile { target c++17 } }
+
+template<class T>
+struct A {
+ A(T&&);
+ template<class U> A(T&&, U&&);
+ template<class U> struct B;
+};
+
+template<class T>
+A<T>::A(T&&) { }
+
+template<class T>
+template<class U>
+A<T>::A(T&&, U&&) { }
+
+template<class T>
+template<class U>
+struct A<T>::B {
+ B(U&&);
+ template<class V> B(U&&, V&&);
+};
+
+int i;
+
+int main() {
+ A{i}; // { dg-error "deduction|no match|rvalue reference" }
+ A{i, 0}; // { dg-error "deduction|no match|rvalue reference" }
+ A{0, i};
+ A<int>::B{i}; // { dg-error "deduction|no match|rvalue reference" }
+ A<int>::B{i, 0}; // { dg-error "deduction|no match|rvalue reference" }
+ A<int>::B{0, i};
+}