This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for Concepts TS multiple auto


The Concepts TS extends 'auto' deduction so that auto, or a constrained-type-specifier, can appear anywhere in the type of a declaration, rather than only as a type-specifier. This was already implemented for function parameters; this patch implements it for variables as well. Use of a constrained-type-specifier as a placeholder for a non-type or template template argument is not supported yet, however.

The second patch is a prerequisite, changing for_each_template_parameter to return a tree value rather than 1 or 0.

The third and fourth patches are small bits I noticed while working on this: the third improves the error messages for auto deduction failure and the fourth uses the hash function on the template's UID rather than using it directly as the seed.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit cf9a0db7c1add4fe26a1b4c5b5ec82a74fd3f1d1
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 28 13:29:32 2015 -0400

    	Implement multiple 'auto' feature from Concepts TS.
    
    	* parser.c (cp_parser_type_id_1): Allow 'auto' if -fconcepts.
    	(cp_parser_template_type_arg): Likewise.
    	(get_concept_from_constraint): Split out most logic to...
    	* constraint.cc (placeholder_extract_concept_and_args): ...here.
    	(equivalent_placeholder_constraints, hash_placeholder_constraint): New.
    	* cxx-pretty-print.c (pp_cxx_constrained_type_spec): New.
    	* cxx-pretty-print.h: Declare it.
    	* error.c (dump_type) [TEMPLATE_TYPE_PARM]: Call it.
    	* pt.c (is_auto_r, extract_autos_r, extract_autos, auto_hash): New.
    	(type_uses_auto): Use is_auto_r.
    	(do_auto_deduction): Handle multiple 'auto's if -fconcepts.
    	* typeck.c (structural_comptypes) [TEMPLATE_TYPE_PARM]: Compare
    	constraints.

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index cb82535..a1fbf17 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1379,6 +1379,89 @@ make_constrained_auto (tree con, tree args)
   return decl;
 }
 
+/* Given the predicate constraint T from a placeholder type, extract its
+   TMPL and ARGS.  */
+
+void
+placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
+{
+  gcc_assert (TREE_CODE (t) == PRED_CONSTR);
+  t = PRED_CONSTR_EXPR (t);
+  gcc_assert (TREE_CODE (t) == CALL_EXPR
+              || TREE_CODE (t) == TEMPLATE_ID_EXPR
+              || VAR_P (t));
+
+  if (TREE_CODE (t) == CALL_EXPR)
+    t = CALL_EXPR_FN (t);
+  if (TREE_CODE (t) == TEMPLATE_ID_EXPR)
+    {
+      tmpl = TREE_OPERAND (t, 0);
+      if (TREE_CODE (tmpl) == OVERLOAD)
+	{
+	  gcc_assert (OVL_CHAIN (tmpl) == NULL_TREE);
+	  tmpl = OVL_FUNCTION (tmpl);
+	}
+      args = TREE_OPERAND (t, 1);
+    }
+  else if (DECL_P (t))
+    {
+      tmpl = DECL_TI_TEMPLATE (t);
+      args = DECL_TI_ARGS (t);
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Returns true iff the placeholders C1 and C2 are equivalent.  C1
+   and C2 can be either PRED_CONSTR_EXPR or TEMPLATE_TYPE_PARM.  */
+
+bool
+equivalent_placeholder_constraints (tree c1, tree c2)
+{
+  if (TREE_CODE (c1) == TEMPLATE_TYPE_PARM)
+    c1 = PLACEHOLDER_TYPE_CONSTRAINTS (c1);
+  if (TREE_CODE (c2) == TEMPLATE_TYPE_PARM)
+    c2 = PLACEHOLDER_TYPE_CONSTRAINTS (c2);
+
+  if (c1 == c2)
+    return true;
+  if (!c1 || !c2)
+    return false;
+
+  tree t1, t2, a1, a2;
+  placeholder_extract_concept_and_args (c1, t1, a1);
+  placeholder_extract_concept_and_args (c2, t2, a2);
+
+  if (t1 != t2)
+    return false;
+  int len = TREE_VEC_LENGTH (a1);
+  if (len != TREE_VEC_LENGTH (a2))
+    return false;
+  /* Skip the first argument to avoid infinite recursion on the
+     placeholder auto itself.  */
+  for (int i = len-1; i > 0; --i)
+    if (!cp_tree_equal (TREE_VEC_ELT (a1, i),
+			TREE_VEC_ELT (a2, i)))
+      return false;
+  return true;
+}
+
+/* Return a hash value for the placeholder PRED_CONSTR C.  */
+
+hashval_t
+hash_placeholder_constraint (tree c)
+{
+  tree t, a;
+  placeholder_extract_concept_and_args (c, t, a);
+
+  /* Like hash_tmpl_and_args, but skip the first argument.  */
+  hashval_t val = iterative_hash_object (DECL_UID (t), 0);
+
+  for (int i = TREE_VEC_LENGTH (a)-1; i > 0; --i)
+    val = iterative_hash_template_arg (TREE_VEC_ELT (a, i), val);
+
+  return val;
+}
 
 /*---------------------------------------------------------------------------
                         Constraint substitution
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6202cab..adb4bae 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6729,6 +6729,9 @@ extern tree get_shorthand_constraints           (tree);
 extern tree build_concept_check                 (tree, tree, tree = NULL_TREE);
 extern tree build_constrained_parameter         (tree, tree, tree = NULL_TREE);
 extern tree make_constrained_auto               (tree, tree);
+extern void placeholder_extract_concept_and_args (tree, tree&, tree&);
+extern bool equivalent_placeholder_constraints  (tree, tree);
+extern hashval_t hash_placeholder_constraint	(tree);
 extern bool deduce_constrained_parameter        (tree, tree&, tree&);
 extern tree resolve_constraint_check            (tree);
 extern tree check_function_concept              (tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index ea6b4c5..72bbfc5 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -2195,6 +2195,26 @@ pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm)
   pp_cxx_end_template_argument_list (pp);
 }
 
+/* Print a constrained-type-specifier.  */
+
+void
+pp_cxx_constrained_type_spec (cxx_pretty_printer *pp, tree c)
+{
+  tree t, a;
+  placeholder_extract_concept_and_args (c, t, a);
+  pp->id_expression (t);
+  if (TREE_VEC_LENGTH (a) > 1)
+    {
+      pp_cxx_begin_template_argument_list (pp);
+      tree args = make_tree_vec (TREE_VEC_LENGTH (a) - 1);
+      for (int i = TREE_VEC_LENGTH (a) - 1; i > 0; --i)
+	TREE_VEC_ELT (args, i-1) = TREE_VEC_ELT (a, i);
+      pp_cxx_template_argument_list (pp, args);
+      ggc_free (args);
+      pp_cxx_end_template_argument_list (pp);
+    }
+}
+
 /*
   template-declaration:
      export(opt) template < template-parameter-list > declaration
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index e5161df..9bb9ccf 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -107,5 +107,6 @@ void pp_cxx_parameterized_constraint (cxx_pretty_printer *, tree);
 void pp_cxx_conjunction (cxx_pretty_printer *, tree);
 void pp_cxx_disjunction (cxx_pretty_printer *, tree);
 void pp_cxx_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_constrained_type_spec (cxx_pretty_printer *, tree);
 
 #endif /* GCC_CXX_PRETTY_PRINT_H */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index b0280d2..75f6abb 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -494,7 +494,9 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
 
     case TEMPLATE_TYPE_PARM:
       pp_cxx_cv_qualifier_seq (pp, t);
-      if (TYPE_IDENTIFIER (t))
+      if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+	pp_cxx_constrained_type_spec (pp, c);
+      else if (TYPE_IDENTIFIER (t))
 	pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t));
       else
 	pp_cxx_canonical_template_parameter
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 3c6b2b1..19e306d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19442,6 +19442,8 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
     abstract_declarator = NULL;
 
   if (type_specifier_seq.type
+      /* The concepts TS allows 'auto' as a type-id.  */
+      && !flag_concepts
       /* None of the valid uses of 'auto' in C++14 involve the type-id
 	 nonterminal, but it is valid in a trailing-return-type.  */
       && !(cxx_dialect >= cxx14 && is_trailing_return)
@@ -19484,7 +19486,7 @@ cp_parser_template_type_arg (cp_parser *parser)
     = G_("types may not be defined in template arguments");
   r = cp_parser_type_id_1 (parser, true, false);
   parser->type_definition_forbidden_message = saved_message;
-  if (cxx_dialect >= cxx14 && type_uses_auto (r))
+  if (cxx_dialect >= cxx14 && !flag_concepts && type_uses_auto (r))
     {
       error ("invalid use of %<auto%> in template argument");
       r = error_mark_node;
@@ -36557,23 +36559,9 @@ tree_type_is_auto_or_concept (const_tree t)
 static tree
 get_concept_from_constraint (tree t)
 {
-  gcc_assert (TREE_CODE (t) == PRED_CONSTR);
-  t = PRED_CONSTR_EXPR (t);
-  gcc_assert (TREE_CODE (t) == CALL_EXPR
-              || TREE_CODE (t) == TEMPLATE_ID_EXPR
-              || VAR_P (t));
-
-  if (TREE_CODE (t) == TEMPLATE_ID_EXPR)
-    return DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
-  if (VAR_P (t))
-    return DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (t));
-  else
-    {
-      tree fn = CALL_EXPR_FN (t);
-      tree ovl = TREE_OPERAND (fn, 0);
-      tree tmpl = OVL_FUNCTION (ovl);
-      return DECL_TEMPLATE_RESULT (tmpl);
-    }
+  tree tmpl, args;
+  placeholder_extract_concept_and_args (t, tmpl, args);
+  return DECL_TEMPLATE_RESULT (tmpl);
 }
 
 /* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3d3e4a6..e836ec7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -23394,6 +23394,100 @@ listify_autos (tree type, tree auto_node)
   return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
 }
 
+/* Hash traits for hashing possibly constrained 'auto'
+   TEMPLATE_TYPE_PARMs for use by do_auto_deduction.  */
+
+struct auto_hash : default_hash_traits<tree>
+{
+  static inline hashval_t hash (tree);
+  static inline bool equal (tree, tree);
+};
+
+/* Hash the 'auto' T.  */
+
+inline hashval_t
+auto_hash::hash (tree t)
+{
+  if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+    /* Matching constrained-type-specifiers denote the same template
+       parameter, so hash the constraint.  */
+    return hash_placeholder_constraint (c);
+  else
+    /* But unconstrained autos are all separate, so just hash the pointer.  */
+    return iterative_hash_object (t, 0);
+}
+
+/* Compare two 'auto's.  */
+
+inline bool
+auto_hash::equal (tree t1, tree t2)
+{
+  if (t1 == t2)
+    return true;
+
+  tree c1 = PLACEHOLDER_TYPE_CONSTRAINTS (t1);
+  tree c2 = PLACEHOLDER_TYPE_CONSTRAINTS (t2);
+
+  /* Two unconstrained autos are distinct.  */
+  if (!c1 || !c2)
+    return false;
+
+  return equivalent_placeholder_constraints (c1, c2);
+}
+
+/* for_each_template_parm callback for extract_autos: if t is a (possibly
+   constrained) auto, add it to the vector.  */
+
+static int
+extract_autos_r (tree t, void *data)
+{
+  hash_table<auto_hash> &hash = *(hash_table<auto_hash>*)data;
+  if (is_auto_or_concept (t))
+    {
+      /* All the autos were built with index 0; fix that up now.  */
+      tree *p = hash.find_slot (t, INSERT);
+      unsigned idx;
+      if (*p)
+	/* If this is a repeated constrained-type-specifier, use the index we
+	   chose before.  */
+	idx = TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (*p));
+      else
+	{
+	  /* Otherwise this is new, so use the current count.  */
+	  *p = t;
+	  idx = hash.elements () - 1;
+	}
+      TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (t)) = idx;
+    }
+
+  /* Always keep walking.  */
+  return 0;
+}
+
+/* Return a TREE_VEC of the 'auto's used in type under the Concepts TS, which
+   says they can appear anywhere in the type.  */
+
+static tree
+extract_autos (tree type)
+{
+  hash_set<tree> visited;
+  hash_table<auto_hash> hash (2);
+
+  for_each_template_parm (type, extract_autos_r, &hash, &visited, true);
+
+  tree tree_vec = make_tree_vec (hash.elements());
+  for (hash_table<auto_hash>::iterator iter = hash.begin();
+       iter != hash.end(); ++iter)
+    {
+      tree elt = *iter;
+      unsigned i = TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (elt));
+      TREE_VEC_ELT (tree_vec, i)
+	= build_tree_list (NULL_TREE, TYPE_NAME (elt));
+    }
+
+  return tree_vec;
+}
+
 /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
    from INIT.  AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE.  */
 
@@ -23450,11 +23544,11 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 
   init = resolve_nondeduced_context (init);
 
-  targs = make_tree_vec (1);
   if (AUTO_IS_DECLTYPE (auto_node))
     {
       bool id = (DECL_P (init) || (TREE_CODE (init) == COMPONENT_REF
 				   && !REF_PARENTHESIZED_P (init)));
+      targs = make_tree_vec (1);
       TREE_VEC_ELT (targs, 0)
 	= finish_decltype_type (init, id, tf_warning_or_error);
       if (type != auto_node)
@@ -23467,14 +23561,21 @@ do_auto_deduction (tree type, tree init, tree auto_node,
   else
     {
       tree parms = build_tree_list (NULL_TREE, type);
-      tree tparms = make_tree_vec (1);
-      int val;
+      tree tparms;
 
-      TREE_VEC_ELT (tparms, 0)
-	= build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
-      val = type_unification_real (tparms, targs, parms, &init, 1, 0,
-				   DEDUCE_CALL, LOOKUP_NORMAL,
-				   NULL, /*explain_p=*/false);
+      if (flag_concepts)
+	tparms = extract_autos (type);
+      else
+	{
+	  tparms = make_tree_vec (1);
+	  TREE_VEC_ELT (tparms, 0)
+	    = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
+	}
+
+      targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
+      int val = type_unification_real (tparms, targs, parms, &init, 1, 0,
+				       DEDUCE_CALL, LOOKUP_NORMAL,
+				       NULL, /*explain_p=*/false);
       if (val > 0)
 	{
 	  if (processing_template_decl)
@@ -23503,7 +23604,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
      of each declared variable is determined as described above. If the
      type deduced for the template parameter U is not the same in each
      deduction, the program is ill-formed.  */
-  if (TREE_TYPE (auto_node)
+  if (!flag_concepts && TREE_TYPE (auto_node)
       && !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)))
     {
       if (cfun && auto_node == current_function_auto_return_pattern
@@ -23516,7 +23617,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 	       auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0));
       return error_mark_node;
     }
-  if (context != adc_requirement)
+  if (!flag_concepts)
     TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0);
 
   /* Check any placeholder constraints against the deduced type. */
@@ -23592,13 +23693,33 @@ is_auto (const_tree type)
     return false;
 }
 
+/* for_each_template_parm callback for type_uses_auto.  */
+
+int
+is_auto_r (tree tp, void */*data*/)
+{
+  return is_auto_or_concept (tp);
+}
+
 /* Returns the TEMPLATE_TYPE_PARM in TYPE representing `auto' iff TYPE contains
    a use of `auto'.  Returns NULL_TREE otherwise.  */
 
 tree
 type_uses_auto (tree type)
 {
-  return find_type_usage (type, is_auto);
+  if (flag_concepts)
+    {
+      /* The Concepts TS allows multiple autos in one type-specifier; just
+	 return the first one we find, do_auto_deduction will collect all of
+	 them.  */
+      if (uses_template_parms (type))
+	return for_each_template_parm (type, is_auto_r, /*data*/NULL,
+				       /*visited*/NULL, /*nondeduced*/true);
+      else
+	return NULL_TREE;
+    }
+  else
+    return find_type_usage (type, is_auto);
 }
 
 /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto',
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9d043e0..e68e9df 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1333,6 +1333,10 @@ structural_comptypes (tree t1, tree t2, int strict)
 	 template parameters set, they can't be equal.  */
       if (!comp_template_parms_position (t1, t2))
 	return false;
+      /* Constrained 'auto's are distinct from parms that don't have the same
+	 constraints.  */
+      if (!equivalent_placeholder_constraints (t1, t2))
+	return false;
       break;
 
     case TYPENAME_TYPE:
diff --git a/gcc/testsuite/g++.dg/concepts/auto1.C b/gcc/testsuite/g++.dg/concepts/auto1.C
new file mode 100644
index 0000000..6068e4c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/auto1.C
@@ -0,0 +1,27 @@
+// { dg-options "-std=c++1z" }
+
+template <class T1, class T2> class A { };
+
+A<int, int> a;
+A<double, float> a2;
+A<double, double> a22;
+
+A<auto, auto> b = a;
+A<auto, auto> b1 = a2;
+
+template <class T> concept bool C = __is_same_as (T, int);
+
+A<C,C> b2 = a;
+A<C,C> b3 = a2;			// { dg-error "" }
+A<C,C> b32 = a22;		// { dg-error "" }
+
+template <class T> concept bool C2() { return __is_enum (T); }
+
+enum E1 { };
+enum E2 { };
+
+A<E1,E1> a3;
+A<C2,C2> b4 = a3;
+
+A<E1,E2> a4;
+A<C2,C2> b5 = a4;		// { dg-error "" }

commit 331307a70c2b098e224d7351b2a1620edf094555
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Oct 29 00:31:41 2015 -0400

    	Streamline for_each_template_parm.
    
    	* pt.c (for_each_template_parm_r): Use WALK_SUBTREE.
    	Return a meaningful value rather than error_mark_node.
    	(for_each_template_parm): Return a tree.
    	(uses_template_parms_level): Return bool.
    	* cp-tree.h: Adjust.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index acdd71c..6202cab 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5984,7 +5984,7 @@ extern tree lookup_template_class		(tree, tree, tree, tree,
 extern tree lookup_template_function		(tree, tree);
 extern tree lookup_template_variable		(tree, tree);
 extern int uses_template_parms			(tree);
-extern int uses_template_parms_level		(tree, int);
+extern bool uses_template_parms_level		(tree, int);
 extern bool in_template_function		(void);
 extern tree instantiate_class_template		(tree);
 extern tree instantiate_template		(tree, tree, tsubst_flags_t);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c6ef2f5..3d3e4a6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -166,8 +166,8 @@ static tree convert_nontype_argument_function (tree, tree, tsubst_flags_t);
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
 static tree convert_template_argument (tree, tree, tree,
 				       tsubst_flags_t, int, tree);
-static int for_each_template_parm (tree, tree_fn_t, void*,
-				   hash_set<tree> *, bool);
+static tree for_each_template_parm (tree, tree_fn_t, void*,
+				    hash_set<tree> *, bool);
 static tree expand_template_argument_pack (tree);
 static tree build_template_parm_index (int, int, int, tree, tree);
 static bool inline_needs_template_parms (tree, bool);
@@ -8692,12 +8692,20 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
   struct pair_fn_data *pfd = (struct pair_fn_data *) d;
   tree_fn_t fn = pfd->fn;
   void *data = pfd->data;
+  tree result = NULL_TREE;
+
+#define WALK_SUBTREE(NODE)						\
+  do									\
+    {									\
+      result = for_each_template_parm (NODE, fn, data, pfd->visited,	\
+				       pfd->include_nondeduced_p);	\
+      if (result) goto out;						\
+    }									\
+  while (0)
 
   if (TYPE_P (t)
-      && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE)
-      && for_each_template_parm (TYPE_CONTEXT (t), fn, data, pfd->visited,
-				 pfd->include_nondeduced_p))
-    return error_mark_node;
+      && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE))
+    WALK_SUBTREE (TYPE_CONTEXT (t));
 
   switch (TREE_CODE (t))
     {
@@ -8710,35 +8718,24 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
     case ENUMERAL_TYPE:
       if (!TYPE_TEMPLATE_INFO (t))
 	*walk_subtrees = 0;
-      else if (for_each_template_parm (TYPE_TI_ARGS (t),
-				       fn, data, pfd->visited, 
-				       pfd->include_nondeduced_p))
-	return error_mark_node;
+      else
+	WALK_SUBTREE (TYPE_TI_ARGS (t));
       break;
 
     case INTEGER_TYPE:
-      if (for_each_template_parm (TYPE_MIN_VALUE (t),
-				  fn, data, pfd->visited, 
-				  pfd->include_nondeduced_p)
-	  || for_each_template_parm (TYPE_MAX_VALUE (t),
-				     fn, data, pfd->visited,
-				     pfd->include_nondeduced_p))
-	return error_mark_node;
+      WALK_SUBTREE (TYPE_MIN_VALUE (t));
+      WALK_SUBTREE (TYPE_MAX_VALUE (t));
       break;
 
     case METHOD_TYPE:
       /* Since we're not going to walk subtrees, we have to do this
 	 explicitly here.  */
-      if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data,
-				  pfd->visited, pfd->include_nondeduced_p))
-	return error_mark_node;
+      WALK_SUBTREE (TYPE_METHOD_BASETYPE (t));
       /* Fall through.  */
 
     case FUNCTION_TYPE:
       /* Check the return type.  */
-      if (for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
-				  pfd->include_nondeduced_p))
-	return error_mark_node;
+      WALK_SUBTREE (TREE_TYPE (t));
 
       /* Check the parameter types.  Since default arguments are not
 	 instantiated until they are needed, the TYPE_ARG_TYPES may
@@ -8750,9 +8747,7 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 	tree parm;
 
 	for (parm = TYPE_ARG_TYPES (t); parm; parm = TREE_CHAIN (parm))
-	  if (for_each_template_parm (TREE_VALUE (parm), fn, data,
-				      pfd->visited, pfd->include_nondeduced_p))
-	    return error_mark_node;
+	  WALK_SUBTREE (TREE_VALUE (parm));
 
 	/* Since we've already handled the TYPE_ARG_TYPES, we don't
 	   want walk_tree walking into them itself.  */
@@ -8771,67 +8766,51 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 
     case FUNCTION_DECL:
     case VAR_DECL:
-      if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
-	  && for_each_template_parm (DECL_TI_ARGS (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
-	return error_mark_node;
+      if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+	WALK_SUBTREE (DECL_TI_ARGS (t));
       /* Fall through.  */
 
     case PARM_DECL:
     case CONST_DECL:
-      if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t)
-	  && for_each_template_parm (DECL_INITIAL (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
-	return error_mark_node;
+      if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t))
+	WALK_SUBTREE (DECL_INITIAL (t));
       if (DECL_CONTEXT (t)
-	  && pfd->include_nondeduced_p
-	  && for_each_template_parm (DECL_CONTEXT (t), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
-	return error_mark_node;
+	  && pfd->include_nondeduced_p)
+	WALK_SUBTREE (DECL_CONTEXT (t));
       break;
 
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       /* Record template parameters such as `T' inside `TT<T>'.  */
-      if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited,
-				  pfd->include_nondeduced_p))
-	return error_mark_node;
+      WALK_SUBTREE (TYPE_TI_ARGS (t));
       /* Fall through.  */
 
     case TEMPLATE_TEMPLATE_PARM:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_PARM_INDEX:
       if (fn && (*fn)(t, data))
-	return error_mark_node;
+	return t;
       else if (!fn)
-	return error_mark_node;
+	return t;
       break;
 
     case TEMPLATE_DECL:
       /* A template template parameter is encountered.  */
-      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
-	  && for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited,
-				     pfd->include_nondeduced_p))
-	return error_mark_node;
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+	WALK_SUBTREE (TREE_TYPE (t));
 
       /* Already substituted template template parameter */
       *walk_subtrees = 0;
       break;
 
     case TYPENAME_TYPE:
-      if (!fn
-	  || for_each_template_parm (TYPENAME_TYPE_FULLNAME (t), fn,
-				     data, pfd->visited, 
-				     pfd->include_nondeduced_p))
-	return error_mark_node;
+      if (!fn)
+	WALK_SUBTREE (TYPENAME_TYPE_FULLNAME (t));
       break;
 
     case CONSTRUCTOR:
       if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))
-	  && pfd->include_nondeduced_p
-	  && for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
-				     (TREE_TYPE (t)), fn, data,
-				     pfd->visited, pfd->include_nondeduced_p))
-	return error_mark_node;
+	  && pfd->include_nondeduced_p)
+	WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
       break;
 
     case INDIRECT_REF:
@@ -8861,8 +8840,11 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
       break;
     }
 
+  #undef WALK_SUBTREE
+
   /* We didn't find any template parameters we liked.  */
-  return NULL_TREE;
+ out:
+  return result;
 }
 
 /* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM,
@@ -8878,13 +8860,13 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
    parameters that occur in non-deduced contexts.  When false, only
    visits those template parameters that can be deduced.  */
 
-static int
+static tree
 for_each_template_parm (tree t, tree_fn_t fn, void* data,
 			hash_set<tree> *visited,
 			bool include_nondeduced_p)
 {
   struct pair_fn_data pfd;
-  int result;
+  tree result;
 
   /* Set up.  */
   pfd.fn = fn;
@@ -8903,7 +8885,7 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data,
   result = cp_walk_tree (&t,
 		         for_each_template_parm_r,
 		         &pfd,
-		         pfd.visited) != NULL_TREE;
+		         pfd.visited);
 
   /* Clean up.  */
   if (!visited)
@@ -8979,7 +8961,7 @@ in_template_function (void)
 
 /* Returns true if T depends on any template parameter with level LEVEL.  */
 
-int
+bool
 uses_template_parms_level (tree t, int level)
 {
   return for_each_template_parm (t, template_parm_this_level_p, &level, NULL,

commit f631e5b5b0e1497225875b6ee37c97945cea11b6
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Oct 30 13:36:35 2015 -0400

    	Improve deduction failure diagnostics.
    
    	* pt.c (unify): Don't diagnose no common base if we already have
    	the same template.
    	(do_auto_deduction): Explain deduction failure.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 243464d..c6ef2f5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19633,7 +19633,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 					 explain_p, &t);
 
 		  if (!t)
-		    return unify_no_common_base (explain_p, r, parm, arg);
+		    {
+		      /* Don't give the derived diagnostic if we're
+			 already dealing with the same template.  */
+		      bool same_template
+			= (CLASSTYPE_TEMPLATE_INFO (arg)
+			   && (CLASSTYPE_TI_TEMPLATE (parm)
+			       == CLASSTYPE_TI_TEMPLATE (arg)));
+		      return unify_no_common_base (explain_p && !same_template,
+						   r, parm, arg);
+		    }
 		}
 	    }
 	  else if (CLASSTYPE_TEMPLATE_INFO (arg)
@@ -23500,6 +23509,9 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 		error ("unable to deduce lambda return type from %qE", init);
 	      else
 		error ("unable to deduce %qT from %qE", type, init);
+	      type_unification_real (tparms, targs, parms, &init, 1, 0,
+				     DEDUCE_CALL, LOOKUP_NORMAL,
+				     NULL, /*explain_p=*/true);
 	    }
 	  return error_mark_node;
 	}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
index b97c1cd..d79ee7f 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
@@ -15,5 +15,5 @@ void g() {
   
   f<0>(s0, s2);
   f(s0, s2); // { dg-error "" } no matching function
-  // { dg-message "(candidate|deduced conflicting types|ambiguous base class)" "candidate note" { target *-*-* } 17 }
+  // { dg-message "(candidate|deduced conflicting|ambiguous base class)" "candidate note" { target *-*-* } 17 }
 }

commit 82a9072ecc7393b141b6923abe22820c7d813498
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Oct 30 14:55:57 2015 -0400

    	* pt.c (hash_tmpl_and_args): Use iterative_hash_object on template
    	uid.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 438ec2d..243464d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1682,7 +1682,7 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2)
 static hashval_t
 hash_tmpl_and_args (tree tmpl, tree args)
 {
-  hashval_t val = DECL_UID (tmpl);
+  hashval_t val = iterative_hash_object (DECL_UID (tmpl), 0);
   return iterative_hash_template_arg (args, val);
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]