https://github.com/anirudhmathur12 updated 
https://github.com/llvm/llvm-project/pull/221440

>From d507501ab7b106f7bf9e42a4094cbf8374f6b0f0 Mon Sep 17 00:00:00 2001
From: AnirudhMathur12 <[email protected]>
Date: Sat, 5 Sep 2026 16:22:58 +0530
Subject: [PATCH 1/4] [Clang][Sema] Don't treat error-recovery dependence as
 genuine template dependence in ActOnTag

When a template argument fails to resolve (e.g. a namespace name used
where a value is expected), Sema substitutes a RecoveryExpr with a
dependent type so downstream code can recover gracefully. This
error-induced dependence was being conflated with genuine template
parameter dependence in ActOnTag's handling of TagUseKind::Reference/
Friend, causing computeDeclContext to report failure the same way it
would for an actually-dependent nested-name-specifier. This tripped an
assert in ActOnExplicitInstantiation that assumes dependent names
can't reach explicit instantiation, when in fact the diagnostic had
already been emitted at the point the RecoveryExpr was created.

Fixes #220525
---
 clang/lib/Sema/SemaDecl.cpp     | 10 +++++++++-
 clang/test/SemaCXX/GH220525.cpp |  7 +++++++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/GH220525.cpp

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d6114ccbae7fe..7f22701376770 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -18356,7 +18356,15 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind 
TUK, SourceLocation KWLoc,
     if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) {
       DC = computeDeclContext(SS, false);
       if (!DC) {
-        IsDependent = true;
+        if (SS.getScopeRep().getAsType() &&
+            !SS.getScopeRep().getAsType()->containsErrors()) {
+          // This is a genuinely dependent nested-name-specifier (e.g. it
+          // depends on an uninstantiated template parameter), not one that
+          // merely appears dependent because of an embedded error-recovery
+          // placeholder. Only in that genuine case should we defer/treat this
+          // as a dependent name for the caller to handle.
+          IsDependent = true;
+        }
         return true;
       }
     } else {
diff --git a/clang/test/SemaCXX/GH220525.cpp b/clang/test/SemaCXX/GH220525.cpp
new file mode 100644
index 0000000000000..5f34e67d70886
--- /dev/null
+++ b/clang/test/SemaCXX/GH220525.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+
+namespace foo {
+  template<typename T> struct S {}; // expected-note {{template parameter is 
declared here}}
+}
+template struct foo::S<foo>::bar; // expected-error {{template argument for 
template type parameter must be a type}} \
+                                  // expected-error {{unexpected namespace 
name 'foo': expected expression}}

>From 5e74ba80882b499d0defe13bb76580c60dfb8d44 Mon Sep 17 00:00:00 2001
From: AnirudhMathur12 <[email protected]>
Date: Mon, 7 Sep 2026 16:04:51 +0530
Subject: [PATCH 2/4] Updates ReleaseNotes.md

---
 clang/docs/ReleaseNotes.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index db9220d43936a..97548a5ca308e 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -614,6 +614,11 @@ features cannot lower the translation-unit ABI level;
   in a token that was lexed and cached before the first occurrence was parsed.
   (#GH214128)
 
+- Fixed an assertion failure when explicitly instantiating a nested member
+  through a nested-name-specifier whose template argument was ill-formed. The
+  resulting error-recovery placeholder was being treated as a genuinely
+  dependent name instead of an already-diagnosed error. (#GH220525)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made

>From 3ca71415b4082313967d4ce038acbbdfcc9c5c5f Mon Sep 17 00:00:00 2001
From: AnirudhMathur12 <[email protected]>
Date: Tue, 8 Sep 2026 22:15:22 +0530
Subject: [PATCH 3/4] use isDependentScopeSpecifier

---
 clang/lib/Sema/SemaDecl.cpp | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7f22701376770..d52df8192afce 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -18356,15 +18356,14 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind 
TUK, SourceLocation KWLoc,
     if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) {
       DC = computeDeclContext(SS, false);
       if (!DC) {
-        if (SS.getScopeRep().getAsType() &&
-            !SS.getScopeRep().getAsType()->containsErrors()) {
-          // This is a genuinely dependent nested-name-specifier (e.g. it
-          // depends on an uninstantiated template parameter), not one that
-          // merely appears dependent because of an embedded error-recovery
-          // placeholder. Only in that genuine case should we defer/treat this
-          // as a dependent name for the caller to handle.
-          IsDependent = true;
-        }
+        // This is a genuinely dependent nested-name-specifier (e.g. it
+        // depends on an uninstantiated template parameter), not one that
+        // merely appears dependent because of an embedded error-recovery
+        // placeholder. Only in that genuine case should we defer/treat this
+        // as a dependent name for the caller to handle.
+        const Type *T = SS.getScopeRep().getAsType();
+        IsDependent =
+            isDependentScopeSpecifier(SS) && (!T || !T->containsErrors());
         return true;
       }
     } else {

>From 17e75d93e7c928bb5c26352774428e88f0100cf4 Mon Sep 17 00:00:00 2001
From: AnirudhMathur12 <[email protected]>
Date: Sat, 19 Sep 2026 15:09:24 +0530
Subject: [PATCH 4/4] Reverted changes in SemaDecl.cpp and moved TagD nullptr
 check above assert

---
 clang/lib/Sema/SemaDecl.cpp     | 9 +--------
 clang/lib/Sema/SemaTemplate.cpp | 4 +++-
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d52df8192afce..d6114ccbae7fe 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -18356,14 +18356,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind 
TUK, SourceLocation KWLoc,
     if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) {
       DC = computeDeclContext(SS, false);
       if (!DC) {
-        // This is a genuinely dependent nested-name-specifier (e.g. it
-        // depends on an uninstantiated template parameter), not one that
-        // merely appears dependent because of an embedded error-recovery
-        // placeholder. Only in that genuine case should we defer/treat this
-        // as a dependent name for the caller to handle.
-        const Type *T = SS.getScopeRep().getAsType();
-        IsDependent =
-            isDependentScopeSpecifier(SS) && (!T || !T->containsErrors());
+        IsDependent = true;
         return true;
       }
     } else {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dd17f9365a5a1..4a405fb3021a2 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -10600,11 +10600,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, 
SourceLocation ExternLoc,
                false, TypeResult(), /*IsTypeSpecifier*/ false,
                /*IsTemplateParamOrArg*/ false, /*OOK=*/OffsetOfKind::Outside)
           .get();
-  assert(!IsDependent && "explicit instantiation of dependent name not yet 
handled");
 
   if (!TagD)
     return true;
 
+  assert(!IsDependent &&
+         "explicit instantiation of dependent name not yet handled");
+
   TagDecl *Tag = cast<TagDecl>(TagD);
   assert(!Tag->isEnum() && "shouldn't see enumerations here");
 

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

Reply via email to