https://github.com/zyn0217 created 
https://github.com/llvm/llvm-project/pull/230766

Fixes https://github.com/llvm/llvm-project/issues/75248

>From 883868380df0aa1169f52fbcf7d9f33f46fd2e78 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Sat, 10 Oct 2026 17:14:19 +0800
Subject: [PATCH] [Clang] Suggest missing typename to dependent packs

---
 clang/docs/ReleaseNotes.md                     |  4 +++-
 clang/lib/Sema/SemaTemplate.cpp                | 16 +++++++++++++---
 clang/test/SemaTemplate/typename-specifier.cpp | 18 ++++++++++++++++++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 2ea67cbd78bcc..d6079299657bc 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -587,6 +587,8 @@ features cannot lower the translation-unit ABI level;
   `operator delete`, since such a delete expression never invokes the
   destructor. (#GH65524)
 
+- Suggest missing `typename` prefixes to dependent packs within template 
arguments. (#GH75248)
+
 - Fixed a false-positive `-Wshadow` warning when a variable in an
   inline-defined friend function shares the name of a non-static class
   member variable. (#GH221190)
@@ -605,7 +607,7 @@ features cannot lower the translation-unit ABI level;
   keyword, such as when deferring the last statement of a block; when
   used as the body of a conditional; or when it immediately precedes
   a `break`/`continue` statement or a `return` with no argument.
- 
+
 - Clang now diagnoses arrays whose size is deduced from an initializer list 
when they exceed the maximum object size
 
 ### Improvements to Clang's time-trace
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 8e7433bc71281..d2c5ec821c038 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5245,13 +5245,17 @@ bool Sema::CheckTemplateTypeArgument(
     // expression; see if maybe it is missing the "typename" keyword.
     CXXScopeSpec SS;
     DeclarationNameInfo NameInfo;
+    TemplateArgument Pattern = Arg;
+    if (Pattern.isPackExpansion())
+      Pattern = Pattern.getPackExpansionPattern();
+    Expr *E = Pattern.getAsExpr();
 
-   if (DependentScopeDeclRefExpr *ArgExpr =
-               dyn_cast<DependentScopeDeclRefExpr>(Arg.getAsExpr())) {
+    if (DependentScopeDeclRefExpr *ArgExpr =
+            dyn_cast<DependentScopeDeclRefExpr>(E)) {
       SS.Adopt(ArgExpr->getQualifierLoc());
       NameInfo = ArgExpr->getNameInfo();
     } else if (CXXDependentScopeMemberExpr *ArgExpr =
-               dyn_cast<CXXDependentScopeMemberExpr>(Arg.getAsExpr())) {
+                   dyn_cast<CXXDependentScopeMemberExpr>(E)) {
       if (ArgExpr->isImplicitAccess()) {
         SS.Adopt(ArgExpr->getQualifierLoc());
         NameInfo = ArgExpr->getMemberNameInfo();
@@ -5282,6 +5286,12 @@ bool Sema::CheckTemplateTypeArgument(
         TL.setElaboratedKeywordLoc(SourceLocation(/*synthesized*/));
         TL.setQualifierLoc(SS.getWithLocInContext(Context));
         TL.setNameLoc(NameInfo.getLoc());
+        if (Arg.isPackExpansion()) {
+          ArgType = Context.getPackExpansionType(ArgType, std::nullopt);
+          PackExpansionTypeLoc TL = TLB.push<PackExpansionTypeLoc>(ArgType);
+          TL.setEllipsisLoc(
+              cast<PackExpansionExpr>(Arg.getAsExpr())->getEllipsisLoc());
+        }
         TSI = TLB.getTypeSourceInfo(Context, ArgType);
 
         // Overwrite our input TemplateArgumentLoc so that we can recover
diff --git a/clang/test/SemaTemplate/typename-specifier.cpp 
b/clang/test/SemaTemplate/typename-specifier.cpp
index 27175c5b0b568..3c88d0806ffd8 100644
--- a/clang/test/SemaTemplate/typename-specifier.cpp
+++ b/clang/test/SemaTemplate/typename-specifier.cpp
@@ -192,6 +192,24 @@ class ExampleClass1 {
   pair<ExampleItemMap::iterator, int> entry;
   pair<bar, int> foobar; // expected-error {{template argument for template 
type parameter must be a type}}
 };
+
+#if __cplusplus >= 201103L
+namespace GH75248 {
+
+template <typename... Ts> struct S;
+
+template <typename... Ts>
+using U2 = S<Ts::Type...>;
+#ifdef MSVC
+// expected-warning@-2 {{must be a type; omitted 'typename' is a Microsoft 
extension}}
+#else
+// expected-error@-4 {{must be a type; did you forget 'typename'?}}
+#endif
+// expected-note@-9 {{declared here}}
+
+}
+#endif
+
 } // namespace missing_typename
 
 namespace missing_typename_and_base {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to