https://gcc.gnu.org/g:58c5055162b698dab6a493b1f90c18af1a34ac65

commit r15-9230-g58c5055162b698dab6a493b1f90c18af1a34ac65
Author: Patrick Palka <ppa...@redhat.com>
Date:   Sat Apr 5 22:39:12 2025 -0400

    c++: maybe_dependent_member_ref and stripped alias [PR118626]
    
    Here during maybe_dependent_member_ref (as part of CTAD rewriting
    for the variant constructor) for __accepted_type<_Up> we strip this
    alias all the way to type _Nth_type<__accepted_index<_Up>>, for which
    we return NULL since _Nth_type is at namespace scope and so no
    longer needs rewriting.
    
    Note that however the template argument __accepted_index<_Up> of this
    stripped type _does_ need rewriting (since it specializes a variable
    template from the current instantiation).  We end up not rewriting this
    variable template reference at any point however because upon returning
    NULL, the caller (tsubst) proceeds to substitute the original form of
    the type __accepted_type<_Up>, which doesn't directly refer to
    __accepted_index.  This later leads to an ICE during subsequent alias
    CTAD rewriting of this guide that contains a non-rewritten reference
    to __accepted_index.
    
    So when maybe_dependent_member_ref decides to not rewrite a class-scope
    alias that's been stripped, the caller needs to commit to substituting
    the stripped type rather than the original type.  This patch essentially
    implements that by making maybe_dependent_member_ref call tsubst itself
    in that case.
    
            PR c++/118626
    
    gcc/cp/ChangeLog:
    
            * pt.cc (maybe_dependent_member_ref): Substitute and return the
            stripped type if we decided to not rewrite it directly.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/class-deduction-alias25.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/pt.cc                                       | 30 +++++++++++++++++++---
 .../g++.dg/cpp2a/class-deduction-alias25.C         | 19 ++++++++++++++
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f7c56a107945..23e41a0fdcb1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -17741,13 +17741,37 @@ maybe_dependent_member_ref (tree t, tree args, 
tsubst_flags_t complain,
 
   if (TYPE_P (t))
     {
+      bool stripped = false;
       if (typedef_variant_p (t))
-       t = strip_typedefs (t);
-      tree decl = TYPE_NAME (t);
+       {
+         /* Since this transformation may undesirably turn a deduced context
+            into a non-deduced one, we'd rather strip typedefs than perform
+            the transformation.  */
+         tree u = strip_typedefs (t);
+         if (u != t)
+           {
+             stripped = true;
+             t = u;
+           }
+       }
+      decl = TYPE_NAME (t);
       if (decl)
        decl = maybe_dependent_member_ref (decl, args, complain, in_decl);
       if (!decl)
-       return NULL_TREE;
+       {
+         if (stripped)
+           /* The original type was an alias from the current instantiation
+              which we stripped to something outside it.  At this point we
+              need to commit to using the stripped type rather than deferring
+              to the caller (which would use the original type), to ensure
+              eligible bits of the stripped type get transformed.  */
+           return tsubst (t, args, complain, in_decl);
+         else
+           /* The original type wasn't a typedef, and we decided it doesn't
+              need rewriting, so just let the caller (tsubst) substitute it
+              normally.  */
+           return NULL_TREE;
+       }
       return cp_build_qualified_type (TREE_TYPE (decl), cp_type_quals (t),
                                      complain);
     }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias25.C 
b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias25.C
new file mode 100644
index 000000000000..37ab932c2cc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias25.C
@@ -0,0 +1,19 @@
+// PR c++/118626
+// { dg-do compile { target c++20 } }
+
+template<long> struct _Nth_type;
+
+template<class _Up>
+struct variant {
+  template<class _Tp> static constexpr long __accepted_index = 0;
+  template<long _Np> using __to_type = _Nth_type<_Np>;
+  template<class _Tp> using __accepted_type = __to_type<__accepted_index<_Tp>>;
+  template<class = __accepted_type<_Up>> variant(_Up);
+};
+
+template<class _Tp>
+struct Node { Node(_Tp); };
+
+template<class R> using Tree = variant<Node<R>>;
+using type = decltype(Tree{Node{42}});
+using type = Tree<int>;

Reply via email to