Bootstrapped and regtested on x86_64-pc-linux-gnu, does thi look
OK for trunk/14?
-- >8 --

As a followup of r15-2047-g7954bb4fcb6fa8, we also need to consider
dependent attributes when recursing into a non-template alias that names
a dependent alias template specialization (and so STF_STRIP_DEPENDENT
is set), otherwise in the first testcase below we undesirably strip B
all the way to T instead of to A<T>.

We also need to move the typedef recursion case of strip_typedefs up to
get checked before the compound type recursion cases.  Otherwise for C
below (which ultimately aliases T*) we end up stripping it to T* instead
of to A<T*> because the POINTER_TYPE recursion dominates the typedef
recursion.  It also means we issue an unexpected extra error in the
third testcase below.

Ideally we would also want to consider dependent attributes on
non-template aliases, so that we accept the second testcase below, but
making that work correctly would require broader changes to e.g.
spec_hasher which currently assumes all non-template aliases are
stripped and hence it'd conflate the dependent specializations A<T>
and A<B> even if we didn't strip B.

        PR c++/115897

gcc/cp/ChangeLog:

        * tree.cc (strip_typedefs): Move up the typedef recursion case.
        Never strip a dependent alias template-id that has dependent
        attributes.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/alias-decl-78.C: New test.
        * g++.dg/cpp0x/alias-decl-79.C: New test.
        * g++.dg/cpp0x/alias-decl-pr92206-1a.C: New test.
---
 gcc/cp/tree.cc                                | 51 +++++++++++--------
 gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C    | 34 +++++++++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C    | 37 ++++++++++++++
 .../g++.dg/cpp0x/alias-decl-pr92206-1a.C      | 10 ++++
 4 files changed, 110 insertions(+), 22 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-1a.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b..0e6be8de59a 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1607,11 +1607,32 @@ strip_typedefs (tree t, bool *remove_attributes /* = 
NULL */,
   if (t == TYPE_CANONICAL (t))
     return t;
 
-  if (!(flags & STF_STRIP_DEPENDENT)
-      && 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;
+  if (typedef_variant_p (t))
+    {
+      if ((flags & STF_USER_VISIBLE)
+         && !user_facing_original_type_p (t))
+       return t;
+
+      if (alias_template_specialization_p (t, nt_opaque))
+       {
+         if (dependent_alias_template_spec_p (t, nt_opaque)
+             && (!(flags & STF_STRIP_DEPENDENT)
+                 || any_dependent_type_attributes_p (DECL_ATTRIBUTES
+                                                     (TYPE_NAME (t)))))
+           /* DR 1558: However, if the template-id is dependent, subsequent
+              template argument substitution still applies to the template-id. 
 */
+           return t;
+       }
+      else
+       /* 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.  */
+       flags |= STF_STRIP_DEPENDENT;
+
+      result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)),
+                              remove_attributes, flags);
+      goto stripped;
+    }
 
   switch (TREE_CODE (t))
     {
@@ -1805,23 +1826,9 @@ strip_typedefs (tree t, bool *remove_attributes /* = 
NULL */,
     }
 
   if (!result)
-    {
-      if (typedef_variant_p (t))
-       {
-         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);
-       }
-      else
-       result = TYPE_MAIN_VARIANT (t);
-    }
+    result = TYPE_MAIN_VARIANT (t);
+
+stripped:
   /*gcc_assert (!typedef_variant_p (result)
              || dependent_alias_template_spec_p (result, nt_opaque)
              || ((flags & STF_USER_VISIBLE)
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C
new file mode 100644
index 00000000000..a52c0622e46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-78.C
@@ -0,0 +1,34 @@
+// PR c++/115897
+// { dg-do compile { target c++11 } }
+
+template<class T, class U>
+struct is_same { static constexpr bool value = __is_same(T, U); };
+
+#if __cpp_variable_templates
+template<class T, class U>
+constexpr bool is_same_v = __is_same(T, U);
+#endif
+
+template<class T>
+using A [[gnu::vector_size(16)]] = T;
+
+template<class T>
+void f() {
+  using B = A<T>;
+  static_assert(!is_same<T, B>::value, "");
+#if __cpp_variable_templates
+  static_assert(!is_same_v<T, B>, "");
+#endif
+};
+
+template<class T>
+void g() {
+  using C = A<T*>;
+  static_assert(!is_same<T*, C>::value, "");
+#if __cpp_variable_templates
+  static_assert(!is_same_v<T*, C>, "");
+#endif
+};
+
+template void f<float>();
+template void g<float>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
new file mode 100644
index 00000000000..e0f07475cc1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-79.C
@@ -0,0 +1,37 @@
+// PR c++/115897
+// { dg-do compile { target c++11 } }
+
+template<class T, class U>
+struct is_same { static constexpr bool value = __is_same(T, U); };
+
+#if __cpp_variable_templates
+template<class T, class U>
+constexpr bool is_same_v = __is_same(T, U);
+#endif
+
+template<class T> struct A;
+
+template<class T>
+void f() {
+  using B [[gnu::vector_size(16)]] = T;
+  static_assert(!is_same<T, B>::value, "");        // { dg-bogus "" "" { xfail 
*-*-* } }
+  static_assert(!is_same<A<T>, A<B>>::value, "");  // { dg-bogus "" "" { xfail 
*-*-* } }
+#if __cpp_variable_templates
+  static_assert(!is_same_v<T, B>, "");             // { dg-bogus "" "" { xfail 
c++14 } }
+  static_assert(!is_same_v<A<T>, A<B>>, "");       // { dg-bogus "" "" { xfail 
c++14 } }
+#endif
+};
+
+template<class T>
+void g() {
+  using C [[gnu::vector_size(16)]] = T*;
+  static_assert(!is_same<T*, C>::value, "");       // { dg-bogus "" "" { xfail 
*-*-* } }
+  static_assert(!is_same<A<T*>, A<C>>::value, ""); // { dg-bogus "" "" { xfail 
*-*-* } }
+#if __cpp_variable_templates
+  static_assert(!is_same_v<T*, C>, "");            // { dg-bogus "" "" { xfail 
c++14 } }
+  static_assert(!is_same_v<A<T*>, A<C>>, "");      // { dg-bogus "" "" { xfail 
c++14 } }
+#endif
+};
+
+template void f<float>();
+template void g<float>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-1a.C 
b/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-1a.C
new file mode 100644
index 00000000000..09781f68bb6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-pr92206-1a.C
@@ -0,0 +1,10 @@
+// A version of alias-decl-pr92206-1.C where alias2 is a compound type.
+// { dg-require-effective-target c++11 }
+
+template<typename> struct A {};
+template<typename T1, typename T2 = typename T1::value> using alias1 = A<T1>;
+template<typename T> class B {
+  using alias2 = alias1<A<T>>*; // { dg-error {no type named 'value'} }
+  A<alias2> a; // { dg-bogus {no type named 'value'} }
+};
+B<int> b;
-- 
2.46.0.rc0.106.g1c4a234a1c

Reply via email to