diff mbox

[C++] c++/78776 fix alias template ICE

Message ID eebc1c03-1535-a8e4-bf38-7bd50193a0fb@acm.org
State New
Headers show

Commit Message

Nathan Sidwell Dec. 13, 2016, 5:49 p.m. UTC
On 12/12/2016 10:28 PM, Jason Merrill wrote:

> I suspect that most uses don't need to change.


Indeed. This addresses the ones I could find.  Both by grepping pt.c and 
fixing subsequent test fall out.

took the opportunity to make the control flow in get_underlying_template 
somewhat clearer.  I don't think there's anything unsurprising in this 
patch.

ok?

nathan

-- 
Nathan Sidwell

Comments

Jason Merrill Dec. 13, 2016, 7:03 p.m. UTC | #1
On 12/13/2016 12:49 PM, Nathan Sidwell wrote:
> +/* Template information for an alias template type.  */

> +#define TYPE_ALIAS_TEMPLATE_INFO(NODE)					\

> +  (DECL_LANG_SPECIFIC (TYPE_NAME (NODE))				\

> +   ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE))				\

> +   : NULL_TREE)

> +

> +/* If NODE is a specialization of an alias template, this accessor

> +   returns the template info for the alias template.  Otherwise behave

> +   as TYPE_TEMPLATE_INFO.  */

> +#define TYPE_TEMPLATE_INFO_MAYBE_ALIAS(NODE)				\

> +  (TYPE_ALIAS_P (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE))		\

> +   ? TYPE_ALIAS_TEMPLATE_INFO (NODE)					\

> +   : TYPE_TEMPLATE_INFO (NODE))


Looks like this is checking DECL_LANG_SPECIFIC twice again; we should be 
able to drop the check from TYPE_TEMPLATE_INFO_MAYBE_ALIAS.

>  	    /* An alias template name is never deduced.  */

>  	    if (TYPE_ALIAS_P (arg))

>  	      arg = strip_typedefs (arg);

> -	    tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));

> +

> +	    tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (arg);


You don't need _MAYBE_ALIAS here.  And without it, we should be able to 
drop the strip_typedefs.

OK with those changes.

Jason
Jason Merrill Dec. 13, 2016, 8:58 p.m. UTC | #2
On 12/13/2016 03:43 PM, Nathan Sidwell wrote:
> On 12/13/2016 02:03 PM, Jason Merrill wrote:

>

>> OK with those changes.

>

> Done.


> +/* Template information for an alias template type.  */

> +#define TYPE_ALIAS_TEMPLATE_INFO(NODE)					\

> +  (DECL_LANG_SPECIFIC (TYPE_NAME (NODE))				\

> +   ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE))				\

> +   : NULL_TREE)

> +

> +/* If NODE is a specialization of an alias template, this accessor

> +   returns the template info for the alias template.  Otherwise behave

> +   as TYPE_TEMPLATE_INFO.  */

> +#define TYPE_TEMPLATE_INFO_MAYBE_ALIAS(NODE)				\

> +  (TYPE_ALIAS_P (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE))		\

> +   ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE))				\

> +   : TYPE_TEMPLATE_INFO (NODE))


I'm still seeing the redundant DECL_LANG_SPECIFIC check.

Jason
diff mbox

Patch

2016-12-12  Nathan Sidwell  <nathan@acm.org>

	PR c++/69481
	* cp-tree.h (TYPE_TEMPLATE_INFO): Remove alias type checking.
	(TYPE_ALIAS_TEMPLATE_INFO): New.
	(TYPE_TEMPLATE_INFO_MAYBE_ALIAS): New.  Use those macros.
	* error.c (dump_alias_template_specialization): Adjust.
	* pt.c (maybe_process_partial_specialization,
	iterative_has_template_arg, find_parameter_packs_r,
	alias_template_specialization_p, dependent_alias_template_spec_p,
	get_underlying_template, lookup_template_class_1, unify): Adjust
	template using decl access.

	PR c++/69481
	* g++.dg/cpp0x/pr69481.C: New.

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 243604)
+++ cp/cp-tree.h	(working copy)
@@ -3038,23 +3038,30 @@  extern void decl_shadowed_for_var_insert
    ->template_info)
 
 /* Template information for an ENUMERAL_, RECORD_, UNION_TYPE, or
-   BOUND_TEMPLATE_TEMPLATE_PARM type.  Note that if NODE is a
-   specialization of an alias template, this accessor returns the
-   template info for the alias template, not the one (if any) for the
-   template of the underlying type.  */
+   BOUND_TEMPLATE_TEMPLATE_PARM type.  This ignores any alias
+   templateness of NODE.  */
 #define TYPE_TEMPLATE_INFO(NODE)					\
-  ((TYPE_ALIAS_P (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE)))	\
-   ? (DECL_LANG_SPECIFIC (TYPE_NAME (NODE))				\
-      ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE))				\
-      : NULL_TREE)							\
-   : ((TREE_CODE (NODE) == ENUMERAL_TYPE)				\
-      ? ENUM_TEMPLATE_INFO (NODE)					\
-      : ((TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM)		\
-	 ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE)			\
-	 : (CLASS_TYPE_P (NODE)						\
-	    ? CLASSTYPE_TEMPLATE_INFO (NODE)				\
-	    : NULL_TREE))))
+  (TREE_CODE (NODE) == ENUMERAL_TYPE					\
+   ? ENUM_TEMPLATE_INFO (NODE)						\
+   : (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM			\
+      ? TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (NODE)			\
+      : (CLASS_TYPE_P (NODE)						\
+	 ? CLASSTYPE_TEMPLATE_INFO (NODE)				\
+	 : NULL_TREE)))
 
+/* Template information for an alias template type.  */
+#define TYPE_ALIAS_TEMPLATE_INFO(NODE)					\
+  (DECL_LANG_SPECIFIC (TYPE_NAME (NODE))				\
+   ? DECL_TEMPLATE_INFO (TYPE_NAME (NODE))				\
+   : NULL_TREE)
+
+/* If NODE is a specialization of an alias template, this accessor
+   returns the template info for the alias template.  Otherwise behave
+   as TYPE_TEMPLATE_INFO.  */
+#define TYPE_TEMPLATE_INFO_MAYBE_ALIAS(NODE)				\
+  (TYPE_ALIAS_P (NODE) && DECL_LANG_SPECIFIC (TYPE_NAME (NODE))		\
+   ? TYPE_ALIAS_TEMPLATE_INFO (NODE)					\
+   : TYPE_TEMPLATE_INFO (NODE))
 
 /* Set the template information for an ENUMERAL_, RECORD_, or
    UNION_TYPE to VAL.  */
Index: cp/error.c
===================================================================
--- cp/error.c	(revision 243604)
+++ cp/error.c	(working copy)
@@ -365,15 +365,13 @@  dump_template_bindings (cxx_pretty_print
 static void
 dump_alias_template_specialization (cxx_pretty_printer *pp, tree t, int flags)
 {
-  tree name;
-
   gcc_assert (alias_template_specialization_p (t));
 
+  tree decl = TYPE_NAME (t);
   if (!(flags & TFF_UNQUALIFIED_NAME))
-    dump_scope (pp, CP_DECL_CONTEXT (TYPE_NAME (t)), flags);
-  name = TYPE_IDENTIFIER (t);
-  pp_cxx_tree_identifier (pp, name);
-  dump_template_parms (pp, TYPE_TEMPLATE_INFO (t),
+    dump_scope (pp, CP_DECL_CONTEXT (decl), flags);
+  pp_cxx_tree_identifier (pp, DECL_NAME (decl));
+  dump_template_parms (pp, DECL_TEMPLATE_INFO (decl),
 		       /*primary=*/false,
 		       flags & ~TFF_TEMPLATE_HEADER);
 }
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 243604)
+++ cp/pt.c	(working copy)
@@ -940,10 +940,11 @@  maybe_process_partial_specialization (tr
 
   if (TYPE_ALIAS_P (type))
     {
-      if (TYPE_TEMPLATE_INFO (type)
-	  && DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (type)))
+      tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (type);
+
+      if (tinfo && DECL_ALIAS_TEMPLATE_P (TI_TEMPLATE (tinfo)))
 	error ("specialization of alias template %qD",
-	       TYPE_TI_TEMPLATE (type));
+	       TI_TEMPLATE (tinfo));
       else
 	error ("explicit specialization of non-template %qT", type);
       return error_mark_node;
@@ -1829,7 +1830,7 @@  iterative_hash_template_arg (tree arg, h
 	  // left alone, or untouched specializations because
 	  // coerce_template_parms returns the unconverted template
 	  // arguments if it sees incomplete argument packs.
-	  tree ti = TYPE_TEMPLATE_INFO (arg);
+	  tree ti = TYPE_ALIAS_TEMPLATE_INFO (arg);
 	  return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti));
 	}
       if (TYPE_CANONICAL (arg))
@@ -3459,8 +3460,8 @@  find_parameter_packs_r (tree *tp, int *w
   /* Handle type aliases/typedefs.  */
   if (TYPE_ALIAS_P (t))
     {
-      if (TYPE_TEMPLATE_INFO (t))
-	cp_walk_tree (&TYPE_TI_ARGS (t),
+      if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t))
+	cp_walk_tree (&TI_ARGS (tinfo),
 		      &find_parameter_packs_r,
 		      ppd, ppd->visited);
       *walk_subtrees = 0;
@@ -5794,15 +5795,9 @@  alias_template_specialization_p (const_t
   /* It's an alias template specialization if it's an alias and its
      TYPE_NAME is a specialization of a primary template.  */
   if (TYPE_ALIAS_P (t))
-    {
-      tree name = TYPE_NAME (t);
-      if (DECL_LANG_SPECIFIC (name))
-	if (tree ti = DECL_TEMPLATE_INFO (name))
-	  {
-	    tree tmpl = TI_TEMPLATE (ti);
-	    return PRIMARY_TEMPLATE_P (tmpl);
-	  }
-    }
+    if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t))
+      return PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo));
+
   return false;
 }
 
@@ -5854,10 +5849,18 @@  complex_alias_template_p (const_tree tmp
 bool
 dependent_alias_template_spec_p (const_tree t)
 {
-  return (alias_template_specialization_p (t)
-	  && TEMPLATE_DECL_COMPLEX_ALIAS_P (DECL_TI_TEMPLATE (TYPE_NAME (t)))
-	  && (any_dependent_template_arguments_p
-	      (INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (t)))));
+  if (!alias_template_specialization_p (t))
+    return false;
+
+  tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t);
+  if (!TEMPLATE_DECL_COMPLEX_ALIAS_P (TI_TEMPLATE (tinfo)))
+    return false;
+
+  tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo));
+  if (!any_dependent_template_arguments_p (args))
+    return false;
+
+  return true;
 }
 
 /* Return the number of innermost template parameters in TMPL.  */
@@ -5879,26 +5882,27 @@  get_underlying_template (tree tmpl)
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   while (DECL_ALIAS_TEMPLATE_P (tmpl))
     {
-      tree result = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
-      if (TYPE_TEMPLATE_INFO (result))
-	{
-	  tree sub = TYPE_TI_TEMPLATE (result);
-	  if (PRIMARY_TEMPLATE_P (sub)
-	      && (num_innermost_template_parms (tmpl)
-		  == num_innermost_template_parms (sub)))
-	    {
-	      tree alias_args = INNERMOST_TEMPLATE_ARGS
-		(template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl)));
-	      if (!comp_template_args (TYPE_TI_ARGS (result), alias_args))
-		break;
-	      /* The alias type is equivalent to the pattern of the
-		 underlying template, so strip the alias.  */
-	      tmpl = sub;
-	      continue;
-	    }
-	}
-      break;
+      /* Determine if the alias is equivalent to an underlying template.  */
+      tree orig_type = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+      tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (orig_type);
+      if (!tinfo)
+	break;
+
+      tree underlying = TI_TEMPLATE (tinfo);
+      if (!PRIMARY_TEMPLATE_P (underlying)
+	  || (num_innermost_template_parms (tmpl)
+	      != num_innermost_template_parms (underlying)))
+	break;
+
+      tree alias_args = INNERMOST_TEMPLATE_ARGS
+	(template_parms_to_args (DECL_TEMPLATE_PARMS (tmpl)));
+      if (!comp_template_args (TI_ARGS (tinfo), alias_args))
+	break;
+
+      /* Alias is equivalent.  Strip it and repeat.  */
+      tmpl = underlying;
     }
+
   return tmpl;
 }
 
@@ -8375,9 +8379,8 @@  lookup_template_class_1 (tree d1, tree a
 	     TEMPLATE will be `template <class T> template
 	     <class U> struct S1<T>::S2'.  We must fill in the missing
 	     arguments.  */
-	  arglist
-	    = add_outermost_template_args (TYPE_TI_ARGS (TREE_TYPE (templ)),
-					   arglist);
+	  tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (TREE_TYPE (templ));
+	  arglist = add_outermost_template_args (TI_ARGS (ti), arglist);
 	  arg_depth = TMPL_ARGS_DEPTH (arglist);
 	}
 
@@ -8407,13 +8410,15 @@  lookup_template_class_1 (tree d1, tree a
 
 	 the `C<T>' is just the same as `C'.  Outside of the
 	 class, however, such a reference is an instantiation.  */
-      if ((entering_scope
-	   || !PRIMARY_TEMPLATE_P (gen_tmpl)
-	   || currently_open_class (template_type))
-	  /* comp_template_args is expensive, check it last.  */
-	  && comp_template_args (TYPE_TI_ARGS (template_type),
-				 arglist))
-	return template_type;
+      if (entering_scope
+	  || !PRIMARY_TEMPLATE_P (gen_tmpl)
+	  || currently_open_class (template_type))
+	{
+	  tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (template_type);
+
+	  if (comp_template_args (TI_ARGS (tinfo), arglist))
+	    return template_type;
+	}
 
       /* If we already have this specialization, return it.  */
       elt.tmpl = gen_tmpl;
@@ -8641,12 +8646,11 @@  lookup_template_class_1 (tree d1, tree a
 	  && CLASS_TYPE_P (context)
 	  && !same_type_p (context, DECL_CONTEXT (gen_tmpl)))
 	{
-	  tree partial_inst_args;
 	  TREE_VEC_LENGTH (arglist)--;
 	  ++processing_template_decl;
-	  partial_inst_args =
-	    tsubst (INNERMOST_TEMPLATE_ARGS
-			(TYPE_TI_ARGS (TREE_TYPE (gen_tmpl))),
+	  tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (TREE_TYPE (gen_tmpl));
+	  tree partial_inst_args =
+	    tsubst (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)),
 		    arglist, complain, NULL_TREE);
 	  --processing_template_decl;
 	  TREE_VEC_LENGTH (arglist)++;
@@ -8678,11 +8682,11 @@  lookup_template_class_1 (tree d1, tree a
 	     for parameters in the TYPE_DECL of the alias template
 	     done earlier.  So be careful while getting the template
 	     of FOUND.  */
-	  found = TREE_CODE (found) == TEMPLATE_DECL
-	    ? found
-	    : TREE_CODE (found) == TYPE_DECL
-	    ? TYPE_TI_TEMPLATE (TREE_TYPE (found))
-	    : CLASSTYPE_TI_TEMPLATE (found);
+	  found = (TREE_CODE (found) == TEMPLATE_DECL
+		   ? found
+		   : (TREE_CODE (found) == TYPE_DECL
+		      ? DECL_TI_TEMPLATE (found)
+		      : CLASSTYPE_TI_TEMPLATE (found)));
 	}
 
       // Build template info for the new specialization.
@@ -20035,10 +20039,13 @@  unify (tree tparms, tree targs, tree par
 	    return unify_template_deduction_failure (explain_p, parm, arg);
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
+
 	    /* An alias template name is never deduced.  */
 	    if (TYPE_ALIAS_P (arg))
 	      arg = strip_typedefs (arg);
-	    tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
+
+	    tree tinfo = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (arg);
+	    tree argvec = INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo));
 	    tree full_argvec = add_to_template_args (targs, argvec);
 	    tree parm_parms 
               = DECL_INNERMOST_TEMPLATE_PARMS
Index: testsuite/g++.dg/cpp0x/pr69481.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr69481.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr69481.C	(working copy)
@@ -0,0 +1,26 @@ 
+// PR c++/69481
+// { dg-do compile { target c++11 } }
+
+// ICE with canonical type verification
+
+template <typename> struct Traits;
+
+template <typename T>
+struct Bob {
+  using Loc = Traits<T>;
+  using typename Loc::Thing;
+
+  Thing Foo (); 
+};
+
+template <class V> struct tt
+{
+  using ut = tt<V>;
+  ut Bob ();
+};
+
+template <class V>
+tt<V> tt<V>::Bob ()
+{
+  return tt();
+}