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.
commit 51f060584f93ef1f3d9ad56b5f11c5b2cfe6fd7a
Author: Jason Merrill <ja...@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;

Reply via email to