diff mbox

C++ PATCH for c++/66289 (ICE with alias-template)

Message ID 557854F9.2080702@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 10, 2015, 3:17 p.m. UTC
On 06/10/2015 09:09 AM, Jason Merrill wrote:
> My patch for DR 1558 broke this testcase: suppressing the stripping of
> alias template-ids with dependent arguments prevented us from
> recognizing that APtr<T> is more specialized than shared_ptr<T>.  At the
> Lenexa meeting we in Core talked about establishing a category of alias
> templates that are actually equivalent to their expansions, based
> largely on whether all the template parameters are used.  This patch
> implements that idea, and fixes the testcase.
>
> Tested x86_64-pc-linux-gnu, applying to trunk and 5.

Actually, applying this patch, which uses a flag to remember whether an 
alias template is complex.
diff mbox

Patch

commit 51f060584f93ef1f3d9ad56b5f11c5b2cfe6fd7a
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jun 5 18:48:24 2015 -0400

    	PR c++/66289
    	* cp-tree.h (TEMPLATE_DECL_COMPLEX_ALIAS_P): New.
    	* pt.c (push_template_decl_real): Set it.
    	(dependent_alias_template_spec_p): Use it.
    	(dependent_type_p_r): Use dependent_alias_template_spec_p.
    	(uses_all_template_parms_data, uses_all_template_parms_r)
    	(complex_alias_template_p): New.
    	(get_template_parm_index): Handle BOUND_TEMPLATE_TEMPLATE_PARM.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 603a871..1eac636 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -155,6 +155,7 @@  c-common.h, not after.
       LABEL_DECL_CONTINUE (in LABEL_DECL)
    2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
       DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
+      TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL)
    3: DECL_IN_AGGR_P.
    4: DECL_C_BIT_FIELD (in a FIELD_DECL)
       DECL_ANON_UNION_VAR_P (in a VAR_DECL)
@@ -2732,6 +2733,10 @@  extern void decl_shadowed_for_var_insert (tree, tree);
 #define TYPE_DECL_ALIAS_P(NODE) \
   DECL_LANG_FLAG_6 (TYPE_DECL_CHECK (NODE))
 
+/* Nonzero for TEMPLATE_DECL means that it is a 'complex' alias template.  */
+#define TEMPLATE_DECL_COMPLEX_ALIAS_P(NODE) \
+  DECL_LANG_FLAG_2 (TEMPLATE_DECL_CHECK (NODE))
+
 /* Nonzero for a type which is an alias for another type; i.e, a type
    which declaration was written 'using name-of-type =
    another-type'.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2ebeb65..7f04fe6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -211,6 +211,7 @@  static tree template_parm_to_arg (tree t);
 static tree current_template_args (void);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
 static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
+static bool complex_alias_template_p (const_tree tmpl);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -4420,6 +4421,7 @@  get_template_parm_index (tree parm)
 	   || TREE_CODE (parm) == TEMPLATE_DECL)
     parm = TREE_TYPE (parm);
   if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM
       || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
     parm = TEMPLATE_TYPE_PARM_INDEX (parm);
   gcc_assert (TREE_CODE (parm) == TEMPLATE_PARM_INDEX);
@@ -5096,6 +5098,11 @@  template arguments to %qD do not match original template %qD",
 	  if (TREE_CODE (parm) == TEMPLATE_DECL)
 	    DECL_CONTEXT (parm) = tmpl;
 	}
+
+      if (TREE_CODE (decl) == TYPE_DECL
+	  && TYPE_DECL_ALIAS_P (decl)
+	  && complex_alias_template_p (tmpl))
+	TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true;
     }
 
   /* The DECL_TI_ARGS of DECL contains full set of arguments referring
@@ -5353,13 +5360,56 @@  alias_template_specialization_p (const_tree t)
   return false;
 }
 
-/* Return TRUE iff T is a specialization of an alias template with
+/* An alias template is complex from a SFINAE perspective if a template-id
+   using that alias can be ill-formed when the expansion is not, as with
+   the void_t template.  We determine this by checking whether the
+   expansion for the alias template uses all its template parameters.  */
+
+struct uses_all_template_parms_data
+{
+  int level;
+  bool *seen;
+};
+
+static int
+uses_all_template_parms_r (tree t, void *data_)
+{
+  struct uses_all_template_parms_data &data
+    = *(struct uses_all_template_parms_data*)data_;
+  tree idx = get_template_parm_index (t);
+
+  if (TEMPLATE_PARM_LEVEL (idx) == data.level)
+    data.seen[TEMPLATE_PARM_IDX (idx)] = true;
+  return 0;
+}
+
+static bool
+complex_alias_template_p (const_tree tmpl)
+{
+  struct uses_all_template_parms_data data;
+  tree pat = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+  tree parms = DECL_TEMPLATE_PARMS (tmpl);
+  data.level = TMPL_PARMS_DEPTH (parms);
+  int len = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS (parms));
+  data.seen = XALLOCAVEC (bool, len);
+  for (int i = 0; i < len; ++i)
+    data.seen[i] = false;
+
+  for_each_template_parm (pat, uses_all_template_parms_r, &data, NULL, true);
+  for (int i = 0; i < len; ++i)
+    if (!data.seen[i])
+      return true;
+  return false;
+}
+
+/* Return TRUE iff T is a specialization of a complex alias template with
    dependent template-arguments.  */
 
 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)))));
 }
@@ -20951,9 +21001,7 @@  dependent_type_p_r (tree type)
     return true;
   /* For an alias template specialization, check the arguments both to the
      class template and the alias template.  */
-  else if (alias_template_specialization_p (type)
-	   && (any_dependent_template_arguments_p
-	       (INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (type)))))
+  else if (dependent_alias_template_spec_p (type))
     return true;
 
   /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_TYPEs are
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-48.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-48.C
new file mode 100644
index 0000000..8d5eb23
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-48.C
@@ -0,0 +1,13 @@ 
+// PR c++/66289
+// { dg-do compile { target c++11 } }
+
+template<typename T> struct A {};
+
+template<typename T> struct shared_ptr { };
+template<typename T> using APtr = shared_ptr<A<T>>;
+
+template<typename T> struct foo;
+template<typename T> struct foo<shared_ptr<T>> { };
+template<typename T> struct foo<APtr<T>> { };
+
+foo<shared_ptr<A<int>>> aa;