llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Qizhi Hu (jcsxky)

<details>
<summary>Changes</summary>

Consider the following testcase:
```cpp
namespace PR12884_original {
  template &lt;typename T&gt; struct A {
    struct B { ##<!-- -->1
      template &lt;typename U&gt; struct X {};
      typedef int arg;
    };
    struct C {
      typedef B::X&lt;typename B::arg&gt; x; 
    };
  };

  template &lt;&gt; struct A&lt;int&gt;::B { ##<!-- -->2
    template &lt;int N&gt; struct X {};
    static const int arg = 0;
  };

  A&lt;int&gt;::C::x a;
}
```
It will crash when compiling with `clang(assertions trunk)`. The reason is that 
we lookup `X`(`B::X`) in `##<!-- -->1` when instantiating `typedef 
B::X&lt;typename B::arg&gt; x; ` during instantiating `A&lt;int&gt;::C::x`. 
This is incorrect because we should lookup `X` in `##<!-- -->2` when we see the 
declaration `A&lt;int&gt;::C::x a;`. Since clang parse `A&lt;T&gt;::B&lt;T&gt;` 
to an `ElaboratedType`(`typename` is not required while compiling with 
`-std=c++20`)  while `typename A&lt;T&gt;::B&lt;T&gt;` turns to be a 
`DependentTemplateSpecializationType`, we should rebuild the `TemplateName` 
with transformed `Qualifier`(whose type is `NestedNameSpecifier`) to make sure 
the lookup context is correct.
This patch also attempts to fix #<!-- -->91677 which crashes with the same 
reason.

---
Full diff: https://github.com/llvm/llvm-project/pull/93411.diff


3 Files Affected:

- (modified) clang/lib/Sema/TreeTransform.h (+24-3) 
- (added) clang/test/SemaCXX/PR91677.cpp (+31) 
- (modified) clang/test/SemaTemplate/typename-specifier-3.cpp (+4-3) 


``````````diff
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index dee335b526991..6ef2eec09ec02 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7216,9 +7216,30 @@ 
TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
       return QualType();
   }
 
-  QualType NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc());
-  if (NamedT.isNull())
-    return QualType();
+  QualType NamedT;
+  if (SemaRef.getLangOpts().CPlusPlus20 && QualifierLoc &&
+      isa<TemplateSpecializationType>(TL.getNamedTypeLoc().getType())) {
+    TemplateSpecializationTypeLoc SpecTL =
+        TL.getNamedTypeLoc().castAs<TemplateSpecializationTypeLoc>();
+    const TemplateSpecializationType *TST =
+        SpecTL.getType()->castAs<TemplateSpecializationType>();
+    CXXScopeSpec SS;
+    SS.Adopt(QualifierLoc);
+    if (TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) {
+      TemplateName InstName = getDerived().RebuildTemplateName(
+          SS, TL.getTemplateKeywordLoc(), *TD->getIdentifier(),
+          TL.getNamedTypeLoc().getBeginLoc(), /*ObjectType=*/QualType(),
+          /*FirstQualifierInScope=*/nullptr, /*AllowInjectedClassName=*/false);
+      if (InstName.isNull())
+        return QualType();
+      NamedT = TransformTemplateSpecializationType(TLB, SpecTL, InstName);
+    }
+  }
+  if (NamedT.isNull()) {
+    NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc());
+    if (NamedT.isNull())
+      return QualType();
+  }
 
   // C++0x [dcl.type.elab]p2:
   //   If the identifier resolves to a typedef-name or the simple-template-id
diff --git a/clang/test/SemaCXX/PR91677.cpp b/clang/test/SemaCXX/PR91677.cpp
new file mode 100644
index 0000000000000..ef2999f959506
--- /dev/null
+++ b/clang/test/SemaCXX/PR91677.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+// expected-no-diagnostics
+
+template <typename> struct t1 {
+  template <typename>
+  struct t2 {};
+};
+
+template <typename T>
+t1<T>::template t2<T> f1();
+
+void f2() {
+  f1<bool>();
+}
+
+namespace N {
+  template <typename T> struct A {
+    struct B {
+      template <typename U> struct X {};
+      typedef int arg;
+    };
+    struct C {
+      typedef B::template X<B::arg> x;
+    };
+  };
+
+  template <> struct A<int>::B {
+    template <int N> struct X {};
+    static const int arg = 0;
+  };
+}
diff --git a/clang/test/SemaTemplate/typename-specifier-3.cpp 
b/clang/test/SemaTemplate/typename-specifier-3.cpp
index 714830f0032d2..a62a1fc5ab39c 100644
--- a/clang/test/SemaTemplate/typename-specifier-3.cpp
+++ b/clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -28,16 +28,17 @@ namespace PR12884_original {
       typedef int arg;
     };
     struct C {
-      typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' 
prior to dependent type name B::X; implicit 'typename' is a C++20 extension}}
+      typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' 
prior to dependent type name B::X; implicit 'typename' is a C++20 extension}} \
+                                       cxx17-error{{typename specifier refers 
to non-type member 'arg' in 'PR12884_original::A<int>::B'}}
     };
   };
 
   template <> struct A<int>::B {
     template <int N> struct X {};
-    static const int arg = 0;
+    static const int arg = 0; // cxx17-note{{referenced member 'arg' is 
declared here}}
   };
 
-  A<int>::C::x a;
+  A<int>::C::x a; // cxx17-note{{in instantiation of member class 
'PR12884_original::A<int>::C' requested here}}
 }
 namespace PR12884_half_fixed {
   template <typename T> struct A {

``````````

</details>


https://github.com/llvm/llvm-project/pull/93411
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to