PR c++/92206 - ICE with typedef to dependent alias.
authorJason Merrill <jason@redhat.com>
Wed, 27 Nov 2019 22:05:41 +0000 (17:05 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 27 Nov 2019 22:05:41 +0000 (17:05 -0500)
rsandifo's patch for 92206 demonstrated a problem with the existing checking
for alias template specializations: they were returning false for a typedef
to an alias template specialization.  Which is sometimes what the caller
wants, and sometimes not: Sometimes we're interested in whether the type was
written as an alias template-id, and sometimes whether it represents one.

The testcase illustrates a case that remained wrong with the earlier patch:
if the typedef is itself an alias template specialization, we can't strip an
underlying dependent alias.

* pt.c (dependent_alias_template_spec_p)
(alias_template_specialization_p): Add transparent_typedefs
parameter.
(iterative_hash_template_arg, any_template_parm_r)
(primary_template_specialization_p, tsubst, dependent_type_p_r):
Adjust.
* decl.c (check_elaborated_type_specifier): Adjust.
* error.c (dump_template_bindings, dump_aggr_type): Adjust.

From-SVN: r278784

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-4.C [new file with mode: 0644]

index c3e66d4e40fb58bf26a4115defe932b8e398e392..0f26009b2be9fbd66a1a465ed86bf56708a2dfc6 100644 (file)
@@ -1,3 +1,15 @@
+2019-11-12  Jason Merrill  <jason@redhat.com>
+
+       PR c++/92206 - ICE with typedef to dependent alias.
+       * pt.c (dependent_alias_template_spec_p)
+       (alias_template_specialization_p): Add transparent_typedefs
+       parameter.
+       (iterative_hash_template_arg, any_template_parm_r)
+       (primary_template_specialization_p, tsubst, dependent_type_p_r):
+       Adjust.
+       * decl.c (check_elaborated_type_specifier): Adjust.
+       * error.c (dump_template_bindings, dump_aggr_type): Adjust.
+
 2019-11-27  Andrew Sutton  <asutton@lock3software.com>
 
        PR c++/92236
index 4b4bc245d8104b235e3e8d9ba1fcff28254067c0..d8e12e99ba3c5283915304ebbd0f2dd7417fc6cd 100644 (file)
@@ -6938,8 +6938,9 @@ extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
 extern tree instantiate_non_dependent_or_null   (tree);
 extern bool variable_template_specialization_p  (tree);
 extern bool alias_type_or_template_p            (tree);
-extern bool alias_template_specialization_p     (const_tree);
-extern bool dependent_alias_template_spec_p     (const_tree);
+enum { nt_opaque = false, nt_transparent = true };
+extern tree alias_template_specialization_p     (const_tree, bool);
+extern tree dependent_alias_template_spec_p     (const_tree, bool);
 extern bool template_parm_object_p             (const_tree);
 extern bool explicit_class_specialization_p     (tree);
 extern bool push_tinst_level                    (tree);
index 26120720f07494fb014ce0bc9326657a10156610..7d5bc914d2d407e4409714906bf57da12ff35efc 100644 (file)
@@ -14548,7 +14548,7 @@ check_elaborated_type_specifier (enum tag_types tag_code,
           && !DECL_SELF_REFERENCE_P (decl)
           && tag_code != typename_type)
     {
-      if (alias_template_specialization_p (type))
+      if (alias_template_specialization_p (type, nt_opaque))
        error ("using alias template specialization %qT after %qs",
               type, tag_name (tag_code));
       else
index 4261d3c4cc934736964bb1123375211564bfb048..a15230a1f012af34689b836acc99e5ff9885d033 100644 (file)
@@ -421,7 +421,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
 static void
 dump_alias_template_specialization (cxx_pretty_printer *pp, tree t, int flags)
 {
-  gcc_assert (alias_template_specialization_p (t));
+  gcc_assert (alias_template_specialization_p (t, nt_opaque));
 
   tree decl = TYPE_NAME (t);
   if (!(flags & TFF_UNQUALIFIED_NAME))
@@ -454,7 +454,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
                                    ? STF_USER_VISIBLE : 0);
          t = strip_typedefs (t, NULL, stf_flags);
        }
-      else if (alias_template_specialization_p (t))
+      else if (alias_template_specialization_p (t, nt_opaque))
        {
          dump_alias_template_specialization (pp, t, flags);
          return;
@@ -711,7 +711,7 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags)
       typdef = (!DECL_ARTIFICIAL (name)
                /* An alias specialization is not considered to be a
                   typedef.  */
-               && !alias_template_specialization_p (t));
+               && !alias_template_specialization_p (t, nt_opaque));
 
       if ((typdef
           && ((flags & TFF_CHASE_TYPEDEF)
index 3eed27bb4265c9a4d3b5fec0e20c98dec45b0a14..244eb7d4ff355dd2dc6bc5d6abe32cf3092e1dae 100644 (file)
@@ -1882,7 +1882,7 @@ iterative_hash_template_arg (tree arg, hashval_t val)
   switch (tclass)
     {
     case tcc_type:
-      if (alias_template_specialization_p (arg))
+      if (tree ats = alias_template_specialization_p (arg, nt_transparent))
        {
          // We want an alias specialization that survived strip_typedefs
          // to hash differently from its TYPE_CANONICAL, to avoid hash
@@ -1891,7 +1891,7 @@ iterative_hash_template_arg (tree arg, hashval_t val)
          // left alone, or untouched specializations because
          // coerce_template_parms returns the unconverted template
          // arguments if it sees incomplete argument packs.
-         tree ti = TYPE_ALIAS_TEMPLATE_INFO (arg);
+         tree ti = TYPE_ALIAS_TEMPLATE_INFO (ats);
          return hash_tmpl_and_args (TI_TEMPLATE (ti), TI_ARGS (ti));
        }
       if (TYPE_CANONICAL (arg))
@@ -3575,7 +3575,7 @@ primary_template_specialization_p (const_tree t)
     return (CLASSTYPE_TEMPLATE_INFO (t)
            && CLASSTYPE_USE_TEMPLATE (t)
            && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)));
-  else if (alias_template_specialization_p (t))
+  else if (alias_template_specialization_p (t, nt_transparent))
     return true;
   return false;
 }
@@ -6298,18 +6298,30 @@ alias_type_or_template_p (tree t)
          || DECL_ALIAS_TEMPLATE_P (t));
 }
 
-/* Return TRUE iff T is a specialization of an alias template.  */
+/* If T is a specialization of an alias template, return it; otherwise return
+   NULL_TREE.  If TRANSPARENT_TYPEDEFS is true, look through other aliases.  */
 
-bool
-alias_template_specialization_p (const_tree t)
+tree
+alias_template_specialization_p (const_tree t,
+                                bool transparent_typedefs)
 {
+  if (!TYPE_P (t))
+    return NULL_TREE;
+
   /* 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))
-    if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t))
-      return PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo));
+  if (typedef_variant_p (t))
+    {
+      if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t))
+       if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)))
+         return CONST_CAST_TREE (t);
+      if (transparent_typedefs)
+       return alias_template_specialization_p (DECL_ORIGINAL_TYPE
+                                               (TYPE_NAME (t)),
+                                               transparent_typedefs);
+    }
 
-  return false;
+  return NULL_TREE;
 }
 
 /* An alias template is complex from a SFINAE perspective if a template-id
@@ -6354,24 +6366,30 @@ complex_alias_template_p (const_tree tmpl)
   return false;
 }
 
-/* Return TRUE iff T is a specialization of a complex alias template with
-   dependent template-arguments.  */
+/* If T is a specialization of a complex alias template with dependent
+   template-arguments, return it; otherwise return NULL_TREE.  If T is a
+   typedef to such a specialization, return the specialization.  */
 
-bool
-dependent_alias_template_spec_p (const_tree t)
+tree
+dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs)
 {
-  if (!alias_template_specialization_p (t))
-    return false;
+  if (!TYPE_P (t) || !typedef_variant_p (t))
+    return NULL_TREE;
 
   tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t);
-  if (!TEMPLATE_DECL_COMPLEX_ALIAS_P (TI_TEMPLATE (tinfo)))
-    return false;
+  if (tinfo
+      && TEMPLATE_DECL_COMPLEX_ALIAS_P (TI_TEMPLATE (tinfo))
+      && (any_dependent_template_arguments_p
+         (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)))))
+    return CONST_CAST_TREE (t);
 
-  tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo));
-  if (!any_dependent_template_arguments_p (args))
-    return false;
+  if (transparent_typedefs)
+    {
+      tree utype = DECL_ORIGINAL_TYPE (TYPE_NAME (t));
+      return dependent_alias_template_spec_p (utype, transparent_typedefs);
+    }
 
-  return true;
+  return NULL_TREE;
 }
 
 /* Return the number of innermost template parameters in TMPL.  */
@@ -10384,9 +10402,9 @@ any_template_parm_r (tree t, void *data)
     case UNION_TYPE:
     case ENUMERAL_TYPE:
       /* Search for template parameters in type aliases.  */
-      if (alias_template_specialization_p (t))
+      if (tree ats = alias_template_specialization_p (t, nt_opaque))
        {
-         tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t);
+         tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (ats);
          WALK_SUBTREE (TI_ARGS (tinfo));
         }
       break;
@@ -14896,7 +14914,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     {
       tree decl = TYPE_NAME (t);
 
-      if (alias_template_specialization_p (t))
+      if (alias_template_specialization_p (t, nt_opaque))
        {
          /* DECL represents an alias template and we want to
             instantiate it.  */
@@ -25815,7 +25833,7 @@ dependent_type_p_r (tree type)
 
   /* An alias template specialization can be dependent even if the
      resulting type is not.  */
-  if (dependent_alias_template_spec_p (type))
+  if (dependent_alias_template_spec_p (type, nt_transparent))
     return true;
 
   /* -- a cv-qualified type where the cv-unqualified type is
index d125d60b270676b7b4267c22a8f125737bbefd42..f500ee614427c6ee52429e8c8636f0638558c6b7 100644 (file)
@@ -1489,7 +1489,7 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags)
     return t;
 
   if (!(flags & STF_STRIP_DEPENDENT)
-      && dependent_alias_template_spec_p (t))
+      && dependent_alias_template_spec_p (t, nt_opaque))
     /* DR 1558: However, if the template-id is dependent, subsequent
        template argument substitution still applies to the template-id.  */
     return t;
@@ -1673,14 +1673,19 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags)
          if ((flags & STF_USER_VISIBLE)
              && !user_facing_original_type_p (t))
            return t;
+         /* If T is a non-template alias or typedef, we can assume that
+            instantiating its definition will hit any substitution failure,
+            so we don't need to retain it here as well.  */
+         if (!alias_template_specialization_p (t, nt_opaque))
+           flags |= STF_STRIP_DEPENDENT;
          result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)),
-                                  remove_attributes,
-                                  flags | STF_STRIP_DEPENDENT);
+                                  remove_attributes, flags);
        }
       else
        result = TYPE_MAIN_VARIANT (t);
     }
   gcc_assert (!typedef_variant_p (result)
+             || dependent_alias_template_spec_p (result, nt_opaque)
              || ((flags & STF_USER_VISIBLE)
                  && !user_facing_original_type_p (result)));
 
index 98c428db52e93d8fe29deaafbfb5c95434147f96..a9b87ea8caf6175f863ebc46983cb907a6ef1b4b 100644 (file)
@@ -1463,10 +1463,13 @@ structural_comptypes (tree t1, tree t2, int strict)
      substitute into the specialization arguments at instantiation
      time.  And aliases can't be equivalent without being ==, so
      we don't need to look any deeper.  */
-  if (comparing_specializations
-      && (dependent_alias_template_spec_p (t1)
-         || dependent_alias_template_spec_p (t2)))
-    return false;
+  if (comparing_specializations)
+    {
+      tree dep1 = dependent_alias_template_spec_p (t1, nt_transparent);
+      tree dep2 = dependent_alias_template_spec_p (t2, nt_transparent);
+      if ((dep1 || dep2) && dep1 != dep2)
+       return false;
+    }
 
   /* If we get here, we know that from a target independent POV the
      types are the same.  Make sure the target attributes are also
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-4.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-4.C
new file mode 100644 (file)
index 0000000..4c86d45
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T> struct A { };
+template <typename T, int = sizeof(typename T::type)> using AA = A<T>; // { dg-error  "char" }
+template <typename T> using AAA = AA<T>;
+
+template <class T> struct C { };
+template <class T> struct B {
+  C<AAA<T>> a;
+};
+B<char> b;                     // { dg-message "" }