US 20 - forwarding references and class template argument deduction
authorJason Merrill <jason@redhat.com>
Fri, 20 Jan 2017 04:43:19 +0000 (23:43 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 20 Jan 2017 04:43:19 +0000 (23:43 -0500)
* 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.

From-SVN: r244682

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/class-deduction26.C [new file with mode: 0644]

index e16853971fb30f906c5282e6d3dfca60f297c9f0..bfd898d874bc574a328cdc7a79c99317d00ff625 100644 (file)
@@ -1,5 +1,11 @@
 2017-01-19  Jason Merrill  <jason@redhat.com>
 
+       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.
+
        US 19 - deduction guides and constructors
        * call.c (joust): Prefer deduction guides to constructors.
        * pt.c (build_deduction_guide): Set DECL_ARTIFICIAL.
index 9c4436710dda8711bf075ed17eb456623fcfa347..f7c7a359a48d1690a2dc16b9221518ea0bc60e1e 100644 (file)
@@ -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)))
index f683727e9775ecc0db4d6ad2f344d069333a7294..8c920c3644236517a8ee1dfb3b10f9f9c1da4838 100644 (file)
@@ -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,
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction26.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction26.C
new file mode 100644 (file)
index 0000000..ea58af7
--- /dev/null
@@ -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