public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: C++ PATCH for C++17 class template argument deduction issues
       [not found] <CADzB+2ky3hxWhm-JMf8+RAj0hPn0uchY=gv1NwyKQDQ7auirrQ@mail.gmail.com>
@ 2017-03-02  1:58 ` Jason Merrill
  2017-03-03  1:27   ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Jason Merrill @ 2017-03-02  1:58 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 202 bytes --]

On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill <jason@redhat.com> wrote:
> This patch implements some proposed resolutions to open issues with
> C++17 class template argument deduction.

And some more:

[-- Attachment #2: ded-new.diff --]
[-- Type: text/plain, Size: 6963 bytes --]

commit 41e5f38da5699736eb02a5b9c65549799c288714
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 1 13:15:11 2017 -1000

            Class template argument deduction in new-expression
            * init.c (build_new): Handle deduction from no initializer.
            * parser.c (cp_parser_new_expression): Don't require a single
            expression for class template deduction.
            * typeck2.c (cxx_incomplete_type_diagnostic): Fix diagnostic for
            class template placeholder.
            * pt.c (tsubst_copy) [TEMPLATE_DECL]: Handle dependent context.
            (tsubst_copy_and_build) [TEMPLATE_ID_EXPR]: Handle SCOPE_REF.
            (redeclare_class_template): Set TEMPLATE_TYPE_PARM_FOR_CLASS.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 7ded37e..191fe13 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3478,15 +3478,19 @@ build_new (vec<tree, va_gc> **placement, tree type, tree nelts,
   if (type == error_mark_node)
     return error_mark_node;
 
-  if (nelts == NULL_TREE && vec_safe_length (*init) == 1
+  if (nelts == NULL_TREE
       /* Don't do auto deduction where it might affect mangling.  */
       && (!processing_template_decl || at_function_scope_p ()))
     {
       tree auto_node = type_uses_auto (type);
       if (auto_node)
 	{
-	  tree d_init = (**init)[0];
-	  d_init = resolve_nondeduced_context (d_init, complain);
+	  tree d_init = NULL_TREE;
+	  if (vec_safe_length (*init) == 1)
+	    {
+	      d_init = (**init)[0];
+	      d_init = resolve_nondeduced_context (d_init, complain);
+	    }
 	  type = do_auto_deduction (type, d_init, auto_node);
 	}
     }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 50528e2..e684870 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8228,7 +8228,8 @@ cp_parser_new_expression (cp_parser* parser)
      contain a new-initializer of the form ( assignment-expression )".
      Additionally, consistently with the spirit of DR 1467, we want to accept
      'new auto { 2 }' too.  */
-  else if (type_uses_auto (type)
+  else if ((ret = type_uses_auto (type))
+	   && !CLASS_PLACEHOLDER_TEMPLATE (ret)
 	   && (vec_safe_length (initializer) != 1
 	       || (BRACE_ENCLOSED_INITIALIZER_P ((*initializer)[0])
 		   && CONSTRUCTOR_NELTS ((*initializer)[0]) != 1)))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ec9d53a..8144ca6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5732,6 +5732,9 @@ 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;
     }
 
   // Cannot redeclare a class template with a different set of constraints.
@@ -14638,6 +14641,15 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     have to substitute this with one having context `D<int>'.  */
 
 	  tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl);
+	  if (dependent_scope_p (context))
+	    {
+	      /* When rewriting a constructor into a deduction guide, a
+		 non-dependent name can become dependent, so memtmpl<args>
+		 becomes context::template memtmpl<args>.  */
+	      tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	      return build_qualified_name (type, context, DECL_NAME (t),
+					   /*template*/true);
+	    }
 	  return lookup_field (context, DECL_NAME(t), 0, false);
 	}
       else
@@ -16621,6 +16633,14 @@ tsubst_copy_and_build (tree t,
 	if (targs == error_mark_node)
 	  return error_mark_node;
 
+	if (TREE_CODE (templ) == SCOPE_REF)
+	  {
+	    tree name = TREE_OPERAND (templ, 1);
+	    tree tid = lookup_template_function (name, targs);
+	    TREE_OPERAND (templ, 1) = tid;
+	    return templ;
+	  }
+
 	if (variable_template_p (templ))
 	  RETURN (lookup_and_finish_template_variable (templ, targs, complain));
 
@@ -25144,7 +25164,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
       type = TREE_TYPE (most_general_template (tmpl));
     }
 
-  bool saw_default = false;
+  bool saw_ctor = false;
   bool saw_copy = false;
   if (CLASSTYPE_METHOD_VEC (type))
     // FIXME cache artificial deduction guides
@@ -25154,9 +25174,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
 	tree guide = build_deduction_guide (fn, outer_args, complain);
 	cands = ovl_cons (guide, cands);
 
+	saw_ctor = true;
+
 	tree parms = FUNCTION_FIRST_USER_PARMTYPE (fn);
-	if (sufficient_parms_p (parms))
-	  saw_default = true;
 	if (parms && sufficient_parms_p (TREE_CHAIN (parms)))
 	  {
 	    tree pt = TREE_VALUE (parms);
@@ -25167,7 +25187,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
 	  }
       }
 
-  if (!saw_default && args->length() == 0)
+  if (!saw_ctor && args->length() == 0)
     {
       tree guide = build_deduction_guide (type, outer_args, complain);
       cands = ovl_cons (guide, cands);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 1e0354d..58a01c9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -523,8 +523,14 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
 
     case TEMPLATE_TYPE_PARM:
       if (is_auto (type))
-	emit_diagnostic (diag_kind, loc, 0,
-			 "invalid use of %<auto%>");
+	{
+	  if (CLASS_PLACEHOLDER_TEMPLATE (type))
+	    emit_diagnostic (diag_kind, loc, 0,
+			     "invalid use of placeholder %qT", type);
+	  else
+	    emit_diagnostic (diag_kind, loc, 0,
+			     "invalid use of %qT", type);
+	}
       else
 	emit_diagnostic (diag_kind, loc, 0,
 			 "invalid use of template type parameter %qT", type);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction33.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction33.C
new file mode 100644
index 0000000..d135031
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction33.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++1z }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+template <class T = void> struct A { };
+template <class T> struct B { B(T,T); };
+
+int main()
+{
+  same<decltype(new A),A<void>*>();
+  same<decltype(new B{1,2}),B<int>*>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction34.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction34.C
new file mode 100644
index 0000000..b035879
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction34.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++1z }
+
+template <class T>
+struct A
+{
+  template <class U>
+  static constexpr bool B = U();
+
+  template <class U, bool V = B<U>>
+  A(T, U);
+};
+
+A a (1,2);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction35.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction35.C
new file mode 100644
index 0000000..b0e53d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction35.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A;
+
+template <class T> struct A {
+  A(T&&);
+};
+
+int i;
+A a = i;			// { dg-error "" }

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: C++ PATCH for C++17 class template argument deduction issues
  2017-03-02  1:58 ` C++ PATCH for C++17 class template argument deduction issues Jason Merrill
@ 2017-03-03  1:27   ` Jason Merrill
  2017-03-03  7:31     ` Jason Merrill
  2017-03-06 14:44     ` Jason Merrill
  0 siblings, 2 replies; 4+ messages in thread
From: Jason Merrill @ 2017-03-03  1:27 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 423 bytes --]

On Wed, Mar 1, 2017 at 3:58 PM, Jason Merrill <jason@redhat.com> wrote:
> On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill <jason@redhat.com> wrote:
>> This patch implements some proposed resolutions to open issues with
>> C++17 class template argument deduction.
>
> And some more:

This patch handles the issues of references to members of the class
template differently, by also allowing explicit guides to refer to
them:

[-- Attachment #2: ded-type.diff --]
[-- Type: text/plain, Size: 10813 bytes --]

commit d32c5f542b7bfe825149fc134b8c5348061f0bfb
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Mar 2 13:20:27 2017 -1000

            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.
            * parser.c (cp_parser_decl_specifier_seq): Set constructor_p.
            (cp_parser_init_declarator): Check it.  Set ctor_dtor_or_conv_p.
            Clear deduction_guide_type.  Don't handle deduction guide names.
            (cp_parser_declarator): Don't clear ctor_dtor_or_conv_p.
            (cp_parser_direct_declarator): Likewise.  Handle deduction guides.
            (cp_parser_member_declaration, cp_parser_cache_defarg)
            (cp_parser_objc_class_ivars): Set ctor_dtor_or_conv_p.
            * pt.c (tsubst_copy, tsubst_copy_and_build): Revert last change.
            (build_deduction_guide): Set deduction_guide_type.
            (dependent_scope_p): Check deduction_guide_type.
            * search.c (lookup_member): Likewise.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f53f744..31edc5f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1272,6 +1272,7 @@ struct GTY(()) saved_scope {
   vec<tree, va_gc> *lang_base;
   tree lang_name;
   tree template_parms;
+  tree deduction_guide_type;
   cp_binding_level *x_previous_class_level;
   tree x_saved_tree;
 
@@ -5422,6 +5423,9 @@ struct cp_decl_specifier_seq {
   BOOL_BITFIELD gnu_thread_keyword_p : 1;
   /* True iff the type is a decltype.  */
   BOOL_BITFIELD decltype_p : 1;
+  /* True iff the declaration declares a constructor or C++17 deduction
+     guide.  */
+  BOOL_BITFIELD constructor_p : 1;
 };
 
 /* The various kinds of declarators.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e684870..fbe864f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13313,6 +13313,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	   && constructor_possible_p
 	   && (cp_parser_constructor_declarator_p
 	       (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend))));
+      if (constructor_p)
+	decl_specs->constructor_p = true;
 
       /* If we don't have a DECL_SPEC yet, then we must be looking at
 	 a type-specifier.  */
@@ -19010,7 +19012,7 @@ cp_parser_init_declarator (cp_parser* parser,
   enum cpp_ttype initialization_kind;
   bool is_direct_init = false;
   bool is_non_constant_init;
-  int ctor_dtor_or_conv_p;
+  int ctor_dtor_or_conv_p = decl_specifiers->constructor_p ? -1 : 0;
   bool friend_p = cp_parser_friend_p (decl_specifiers);
   tree pushed_scope = NULL_TREE;
   bool range_for_decl_p = false;
@@ -19048,6 +19050,9 @@ cp_parser_init_declarator (cp_parser* parser,
 
   parser->default_arg_ok_p = saved_default_arg_ok_p;
 
+  if (cxx_dialect >= cxx1z)
+    scope_chain->deduction_guide_type = NULL_TREE;
+
   /* If the DECLARATOR was erroneous, there's no need to go
      further.  */
   if (declarator == cp_error_declarator)
@@ -19095,25 +19100,6 @@ cp_parser_init_declarator (cp_parser* parser,
 
   if (function_declarator_p (declarator))
     {
-      /* Handle C++17 deduction guides.  */
-      if (!decl_specifiers->type
-	  && ctor_dtor_or_conv_p <= 0
-	  && cxx_dialect >= cxx1z)
-	{
-	  cp_declarator *id = get_id_declarator (declarator);
-	  tree name = id->u.id.unqualified_name;
-	  parser->scope = id->u.id.qualifying_scope;
-	  tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc);
-	  if (tmpl
-	      && (DECL_CLASS_TEMPLATE_P (tmpl)
-		  || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
-	    {
-	      id->u.id.unqualified_name = dguide_name (tmpl);
-	      id->u.id.sfk = sfk_deduction_guide;
-	      ctor_dtor_or_conv_p = 1;
-	    }
-	}
-
       /* Check to see if the token indicates the start of a
 	 function-definition.  */
       if (cp_parser_token_starts_function_definition_p (token))
@@ -19432,8 +19418,10 @@ cp_parser_init_declarator (cp_parser* parser,
 
    If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
    detect constructors, destructors, deduction guides, or conversion operators.
-   It is set to -1 if the declarator is a name, and +1 if it is a
-   function. Otherwise it is set to zero. Usually you just want to
+   The caller should set it before the call, to -1 if parsing the
+   decl-specifier-seq determined that we're declaring a constructor or
+   deduction guide, or 0 otherwise.  This function sets it to -1 if the
+   declarator is a name, and +1 if it is a function. Usually you just want to
    test for >0, but internally the negative value is used.
 
    (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have
@@ -19464,11 +19452,6 @@ cp_parser_declarator (cp_parser* parser,
   tree class_type;
   tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE;
 
-  /* Assume this is not a constructor, destructor, or type-conversion
-     operator.  */
-  if (ctor_dtor_or_conv_p)
-    *ctor_dtor_or_conv_p = 0;
-
   if (cp_parser_allow_gnu_extensions_p (parser))
     gnu_attributes = cp_parser_gnu_attributes_opt (parser);
 
@@ -19766,9 +19749,6 @@ cp_parser_direct_declarator (cp_parser* parser,
 	  /* Parse an array-declarator.  */
 	  tree bounds, attrs;
 
-	  if (ctor_dtor_or_conv_p)
-	    *ctor_dtor_or_conv_p = 0;
-
 	  first = false;
 	  parser->default_arg_ok_p = false;
 	  parser->in_declarator_p = true;
@@ -20023,6 +20003,34 @@ cp_parser_direct_declarator (cp_parser* parser,
 		      *ctor_dtor_or_conv_p = -1;
 		  }
 	      }
+
+	    if (cxx_dialect >= cxx1z
+		&& sfk == sfk_none
+		&& ctor_dtor_or_conv_p
+		&& *ctor_dtor_or_conv_p == -1)
+	      {
+		/* If *ctor_dtor_or_conv_p is set and we aren't declaring a
+		   constructor, we must be declaring a deduction guide.  */
+		tree tmpl;
+		if (qualifying_scope)
+		  tmpl = (lookup_qualified_name
+			  (qualifying_scope, unqualified_name,
+			   /*prefer_type*/false, /*complain*/true));
+		else
+		  tmpl = lookup_name (unqualified_name);
+		if (tmpl
+		    && (DECL_CLASS_TEMPLATE_P (tmpl)
+			|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
+		  {
+		    unqualified_name = dguide_name (tmpl);
+		    scope_chain->deduction_guide_type
+		      = TREE_TYPE (unqualified_name);
+		    sfk = sfk_deduction_guide;
+		  }
+		else
+		  gcc_checking_assert (false);
+	      }
+
 	    declarator = make_id_declarator (qualifying_scope,
 					     unqualified_name,
 					     sfk);
@@ -23251,7 +23259,7 @@ cp_parser_member_declaration (cp_parser* parser)
 	      cp_declarator *declarator;
 	      tree initializer;
 	      tree asm_specification;
-	      int ctor_dtor_or_conv_p;
+	      int ctor_dtor_or_conv_p = decl_specifiers.constructor_p ? -1 : 0;
 
 	      /* Parse the declarator.  */
 	      declarator
@@ -28334,7 +28342,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
 		     declarator.  */
 		  do
 		    {
-		      int ctor_dtor_or_conv_p;
+		      int ctor_dtor_or_conv_p = 0;
 		      cp_lexer_consume_token (parser->lexer);
 		      cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					    &ctor_dtor_or_conv_p,
@@ -29655,7 +29663,7 @@ cp_parser_objc_class_ivars (cp_parser* parser)
 	{
 	  tree width = NULL_TREE, attributes, first_attribute, decl;
 	  cp_declarator *declarator = NULL;
-	  int ctor_dtor_or_conv_p;
+	  int ctor_dtor_or_conv_p = 0;
 
 	  /* Check for a (possibly unnamed) bitfield declaration.  */
 	  token = cp_lexer_peek_token (parser->lexer);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8144ca6..3b320fc 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14641,15 +14641,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     have to substitute this with one having context `D<int>'.  */
 
 	  tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl);
-	  if (dependent_scope_p (context))
-	    {
-	      /* When rewriting a constructor into a deduction guide, a
-		 non-dependent name can become dependent, so memtmpl<args>
-		 becomes context::template memtmpl<args>.  */
-	      tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	      return build_qualified_name (type, context, DECL_NAME (t),
-					   /*template*/true);
-	    }
 	  return lookup_field (context, DECL_NAME(t), 0, false);
 	}
       else
@@ -16633,14 +16624,6 @@ tsubst_copy_and_build (tree t,
 	if (targs == error_mark_node)
 	  return error_mark_node;
 
-	if (TREE_CODE (templ) == SCOPE_REF)
-	  {
-	    tree name = TREE_OPERAND (templ, 1);
-	    tree tid = lookup_template_function (name, targs);
-	    TREE_OPERAND (templ, 1) = tid;
-	    return templ;
-	  }
-
 	if (variable_template_p (templ))
 	  RETURN (lookup_and_finish_template_variable (templ, targs, complain));
 
@@ -23476,6 +23459,9 @@ bool
 dependent_scope_p (tree scope)
 {
   return (scope && TYPE_P (scope) && dependent_type_p (scope)
+	  && !(cxx_dialect >= cxx1z
+	       && scope_chain->deduction_guide_type
+	       && same_type_p (scope, scope_chain->deduction_guide_type))
 	  && !currently_open_class (scope));
 }
 
@@ -24997,6 +24983,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
       if (outer_args)
 	ctor = tsubst (ctor, outer_args, complain, ctor);
       type = DECL_CONTEXT (ctor);
+      scope_chain->deduction_guide_type = type;
       tree fn_tmpl;
       if (TREE_CODE (ctor) == TEMPLATE_DECL)
 	{
@@ -25089,6 +25076,7 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
 	  current_template_parms = save_parms;
 	  --processing_template_decl;
 	}
+      scope_chain->deduction_guide_type = NULL_TREE;
     }
 
   if (!memtmpl)
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 09c1b4e..6eb4124 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1279,6 +1279,13 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
     if (tree t = currently_open_class (type))
       type = t;
 
+  /* Declaration of a deduction guide can look inside the primary class
+     template; replace a compatible type with the real one.  */
+  if (cxx_dialect >= cxx1z
+      && scope_chain->deduction_guide_type
+      && same_type_p (type, scope_chain->deduction_guide_type))
+    type = scope_chain->deduction_guide_type;
+
   if (!basetype_path)
     basetype_path = TYPE_BINFO (type);
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C
new file mode 100644
index 0000000..ee21d14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C
@@ -0,0 +1,16 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A
+{
+  using value_t = T;
+  A(value_t);
+};
+
+template <class T>
+A(typename A<T>::value_t) -> A<double>;
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+A a(42);
+same<decltype(a),A<double>> s1;

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: C++ PATCH for C++17 class template argument deduction issues
  2017-03-03  1:27   ` Jason Merrill
@ 2017-03-03  7:31     ` Jason Merrill
  2017-03-06 14:44     ` Jason Merrill
  1 sibling, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2017-03-03  7:31 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 555 bytes --]

On Thu, Mar 2, 2017 at 3:26 PM, Jason Merrill <jason@redhat.com> wrote:
> On Wed, Mar 1, 2017 at 3:58 PM, Jason Merrill <jason@redhat.com> wrote:
>> On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill <jason@redhat.com> wrote:
>>> This patch implements some proposed resolutions to open issues with
>>> C++17 class template argument deduction.
>>
>> And some more:
>
> This patch handles the issues of references to members of the class
> template differently, by also allowing explicit guides to refer to
> them:

This patch adjusts some overload resolution.

[-- Attachment #2: ded-ovl.diff --]
[-- Type: text/plain, Size: 6056 bytes --]

commit a777aadaf635dc1ef460c5e12d2ead4292eaa6a9
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 1 16:11:26 2017 -1000

            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.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index babab00..dc629b96 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 31edc5f..7583672 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 3b320fc..13293eb 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 0000000..129e29e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C
@@ -0,0 +1,15 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A {
+  A(T&);
+  A(const A&);
+};
+
+int i;
+A a = i;
+A a2 = a;
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+same<decltype(a),A<int>> s1;
+same<decltype(a2),A<int>> 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 0000000..fe6c200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C
@@ -0,0 +1,27 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A {
+  using value_type = T;
+  A(value_type); // #1
+  A(const A&); // #2
+  A(T, T, int); // #3
+  template<class U> 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 <class T> A(T) -> A<T>;  // #6, less specialized than #5
+
+A a (42); // uses #6 to deduce A<int> and #1 to initialize
+A b = a;  // uses #5 to deduce A<int> and #2 to initialize
+
+template <class T> A(A<T>) -> A<A<T>>;  // #7, as specialized as #5
+
+A b2 = a;  // uses #7 to deduce A<A<int>> and #1 to initialize
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+same<decltype(a),A<int>> s1;
+same<decltype(b),A<int>> s2;
+same<decltype(b2),A<A<int>>> s3;

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: C++ PATCH for C++17 class template argument deduction issues
  2017-03-03  1:27   ` Jason Merrill
  2017-03-03  7:31     ` Jason Merrill
@ 2017-03-06 14:44     ` Jason Merrill
  1 sibling, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2017-03-06 14:44 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 552 bytes --]

On Thu, Mar 2, 2017 at 3:26 PM, Jason Merrill <jason@redhat.com> wrote:
> On Wed, Mar 1, 2017 at 3:58 PM, Jason Merrill <jason@redhat.com> wrote:
>> On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill <jason@redhat.com> wrote:
>>> This patch implements some proposed resolutions to open issues with
>>> C++17 class template argument deduction.
>
> This patch handles the issues of references to members of the class
> template differently, by also allowing explicit guides to refer to
> them:

The committee didn't like this direction, so I'm reverting it.

[-- Attachment #2: no-ded-typename.diff --]
[-- Type: text/plain, Size: 9989 bytes --]

commit 522ce181ad77238b7e314377bf21f45579e7b6e8
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Mar 4 13:18:47 2017 -1000

            Revert "Allow deduction guides to look into primary template."
    
            * cp-tree.h, parser.c, pt.c, search.c: Revert.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7583672..68f2722 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1272,7 +1272,6 @@ struct GTY(()) saved_scope {
   vec<tree, va_gc> *lang_base;
   tree lang_name;
   tree template_parms;
-  tree deduction_guide_type;
   cp_binding_level *x_previous_class_level;
   tree x_saved_tree;
 
@@ -5423,9 +5422,6 @@ struct cp_decl_specifier_seq {
   BOOL_BITFIELD gnu_thread_keyword_p : 1;
   /* True iff the type is a decltype.  */
   BOOL_BITFIELD decltype_p : 1;
-  /* True iff the declaration declares a constructor or C++17 deduction
-     guide.  */
-  BOOL_BITFIELD constructor_p : 1;
 };
 
 /* The various kinds of declarators.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index fbe864f..e684870 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13313,8 +13313,6 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	   && constructor_possible_p
 	   && (cp_parser_constructor_declarator_p
 	       (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend))));
-      if (constructor_p)
-	decl_specs->constructor_p = true;
 
       /* If we don't have a DECL_SPEC yet, then we must be looking at
 	 a type-specifier.  */
@@ -19012,7 +19010,7 @@ cp_parser_init_declarator (cp_parser* parser,
   enum cpp_ttype initialization_kind;
   bool is_direct_init = false;
   bool is_non_constant_init;
-  int ctor_dtor_or_conv_p = decl_specifiers->constructor_p ? -1 : 0;
+  int ctor_dtor_or_conv_p;
   bool friend_p = cp_parser_friend_p (decl_specifiers);
   tree pushed_scope = NULL_TREE;
   bool range_for_decl_p = false;
@@ -19050,9 +19048,6 @@ cp_parser_init_declarator (cp_parser* parser,
 
   parser->default_arg_ok_p = saved_default_arg_ok_p;
 
-  if (cxx_dialect >= cxx1z)
-    scope_chain->deduction_guide_type = NULL_TREE;
-
   /* If the DECLARATOR was erroneous, there's no need to go
      further.  */
   if (declarator == cp_error_declarator)
@@ -19100,6 +19095,25 @@ cp_parser_init_declarator (cp_parser* parser,
 
   if (function_declarator_p (declarator))
     {
+      /* Handle C++17 deduction guides.  */
+      if (!decl_specifiers->type
+	  && ctor_dtor_or_conv_p <= 0
+	  && cxx_dialect >= cxx1z)
+	{
+	  cp_declarator *id = get_id_declarator (declarator);
+	  tree name = id->u.id.unqualified_name;
+	  parser->scope = id->u.id.qualifying_scope;
+	  tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc);
+	  if (tmpl
+	      && (DECL_CLASS_TEMPLATE_P (tmpl)
+		  || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
+	    {
+	      id->u.id.unqualified_name = dguide_name (tmpl);
+	      id->u.id.sfk = sfk_deduction_guide;
+	      ctor_dtor_or_conv_p = 1;
+	    }
+	}
+
       /* Check to see if the token indicates the start of a
 	 function-definition.  */
       if (cp_parser_token_starts_function_definition_p (token))
@@ -19418,10 +19432,8 @@ cp_parser_init_declarator (cp_parser* parser,
 
    If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
    detect constructors, destructors, deduction guides, or conversion operators.
-   The caller should set it before the call, to -1 if parsing the
-   decl-specifier-seq determined that we're declaring a constructor or
-   deduction guide, or 0 otherwise.  This function sets it to -1 if the
-   declarator is a name, and +1 if it is a function. Usually you just want to
+   It is set to -1 if the declarator is a name, and +1 if it is a
+   function. Otherwise it is set to zero. Usually you just want to
    test for >0, but internally the negative value is used.
 
    (The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have
@@ -19452,6 +19464,11 @@ cp_parser_declarator (cp_parser* parser,
   tree class_type;
   tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE;
 
+  /* Assume this is not a constructor, destructor, or type-conversion
+     operator.  */
+  if (ctor_dtor_or_conv_p)
+    *ctor_dtor_or_conv_p = 0;
+
   if (cp_parser_allow_gnu_extensions_p (parser))
     gnu_attributes = cp_parser_gnu_attributes_opt (parser);
 
@@ -19749,6 +19766,9 @@ cp_parser_direct_declarator (cp_parser* parser,
 	  /* Parse an array-declarator.  */
 	  tree bounds, attrs;
 
+	  if (ctor_dtor_or_conv_p)
+	    *ctor_dtor_or_conv_p = 0;
+
 	  first = false;
 	  parser->default_arg_ok_p = false;
 	  parser->in_declarator_p = true;
@@ -20003,34 +20023,6 @@ cp_parser_direct_declarator (cp_parser* parser,
 		      *ctor_dtor_or_conv_p = -1;
 		  }
 	      }
-
-	    if (cxx_dialect >= cxx1z
-		&& sfk == sfk_none
-		&& ctor_dtor_or_conv_p
-		&& *ctor_dtor_or_conv_p == -1)
-	      {
-		/* If *ctor_dtor_or_conv_p is set and we aren't declaring a
-		   constructor, we must be declaring a deduction guide.  */
-		tree tmpl;
-		if (qualifying_scope)
-		  tmpl = (lookup_qualified_name
-			  (qualifying_scope, unqualified_name,
-			   /*prefer_type*/false, /*complain*/true));
-		else
-		  tmpl = lookup_name (unqualified_name);
-		if (tmpl
-		    && (DECL_CLASS_TEMPLATE_P (tmpl)
-			|| DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
-		  {
-		    unqualified_name = dguide_name (tmpl);
-		    scope_chain->deduction_guide_type
-		      = TREE_TYPE (unqualified_name);
-		    sfk = sfk_deduction_guide;
-		  }
-		else
-		  gcc_checking_assert (false);
-	      }
-
 	    declarator = make_id_declarator (qualifying_scope,
 					     unqualified_name,
 					     sfk);
@@ -23259,7 +23251,7 @@ cp_parser_member_declaration (cp_parser* parser)
 	      cp_declarator *declarator;
 	      tree initializer;
 	      tree asm_specification;
-	      int ctor_dtor_or_conv_p = decl_specifiers.constructor_p ? -1 : 0;
+	      int ctor_dtor_or_conv_p;
 
 	      /* Parse the declarator.  */
 	      declarator
@@ -28342,7 +28334,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
 		     declarator.  */
 		  do
 		    {
-		      int ctor_dtor_or_conv_p = 0;
+		      int ctor_dtor_or_conv_p;
 		      cp_lexer_consume_token (parser->lexer);
 		      cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					    &ctor_dtor_or_conv_p,
@@ -29663,7 +29655,7 @@ cp_parser_objc_class_ivars (cp_parser* parser)
 	{
 	  tree width = NULL_TREE, attributes, first_attribute, decl;
 	  cp_declarator *declarator = NULL;
-	  int ctor_dtor_or_conv_p = 0;
+	  int ctor_dtor_or_conv_p;
 
 	  /* Check for a (possibly unnamed) bitfield declaration.  */
 	  token = cp_lexer_peek_token (parser->lexer);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 13293eb..416f132 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14641,6 +14641,15 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     have to substitute this with one having context `D<int>'.  */
 
 	  tree context = tsubst (DECL_CONTEXT (t), args, complain, in_decl);
+	  if (dependent_scope_p (context))
+	    {
+	      /* When rewriting a constructor into a deduction guide, a
+		 non-dependent name can become dependent, so memtmpl<args>
+		 becomes context::template memtmpl<args>.  */
+	      tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	      return build_qualified_name (type, context, DECL_NAME (t),
+					   /*template*/true);
+	    }
 	  return lookup_field (context, DECL_NAME(t), 0, false);
 	}
       else
@@ -16624,6 +16633,14 @@ tsubst_copy_and_build (tree t,
 	if (targs == error_mark_node)
 	  return error_mark_node;
 
+	if (TREE_CODE (templ) == SCOPE_REF)
+	  {
+	    tree name = TREE_OPERAND (templ, 1);
+	    tree tid = lookup_template_function (name, targs);
+	    TREE_OPERAND (templ, 1) = tid;
+	    return templ;
+	  }
+
 	if (variable_template_p (templ))
 	  RETURN (lookup_and_finish_template_variable (templ, targs, complain));
 
@@ -23459,9 +23476,6 @@ bool
 dependent_scope_p (tree scope)
 {
   return (scope && TYPE_P (scope) && dependent_type_p (scope)
-	  && !(cxx_dialect >= cxx1z
-	       && scope_chain->deduction_guide_type
-	       && same_type_p (scope, scope_chain->deduction_guide_type))
 	  && !currently_open_class (scope));
 }
 
@@ -25012,7 +25026,6 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
       if (outer_args)
 	ctor = tsubst (ctor, outer_args, complain, ctor);
       type = DECL_CONTEXT (ctor);
-      scope_chain->deduction_guide_type = type;
       tree fn_tmpl;
       if (TREE_CODE (ctor) == TEMPLATE_DECL)
 	{
@@ -25105,7 +25118,6 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
 	  current_template_parms = save_parms;
 	  --processing_template_decl;
 	}
-      scope_chain->deduction_guide_type = NULL_TREE;
     }
 
   if (!memtmpl)
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 6eb4124..09c1b4e 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1279,13 +1279,6 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
     if (tree t = currently_open_class (type))
       type = t;
 
-  /* Declaration of a deduction guide can look inside the primary class
-     template; replace a compatible type with the real one.  */
-  if (cxx_dialect >= cxx1z
-      && scope_chain->deduction_guide_type
-      && same_type_p (type, scope_chain->deduction_guide_type))
-    type = scope_chain->deduction_guide_type;
-
   if (!basetype_path)
     basetype_path = TYPE_BINFO (type);
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C
deleted file mode 100644
index ee21d14..0000000
--- a/gcc/testsuite/g++.dg/cpp1z/class-deduction37.C
+++ /dev/null
@@ -1,16 +0,0 @@
-// { dg-options -std=c++1z }
-
-template <class T> struct A
-{
-  using value_t = T;
-  A(value_t);
-};
-
-template <class T>
-A(typename A<T>::value_t) -> A<double>;
-
-template <class,class> struct same;
-template <class T> struct same<T,T> {};
-
-A a(42);
-same<decltype(a),A<double>> s1;

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-03-06 14:44 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CADzB+2ky3hxWhm-JMf8+RAj0hPn0uchY=gv1NwyKQDQ7auirrQ@mail.gmail.com>
2017-03-02  1:58 ` C++ PATCH for C++17 class template argument deduction issues Jason Merrill
2017-03-03  1:27   ` Jason Merrill
2017-03-03  7:31     ` Jason Merrill
2017-03-06 14:44     ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).