https://github.com/mizvekov updated 
https://github.com/llvm/llvm-project/pull/207301

>From 764e84b6a1035b8df52a2ac2d1c40b3641226808 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <[email protected]>
Date: Thu, 2 Jul 2026 17:16:52 -0300
Subject: [PATCH] [clang] fix redeclarations of the injected class name

The declaration used to represent an injected class name should never
be part of any redeclaration chain.

Fixes #202320
---
 clang/docs/ReleaseNotes.md                    |  1 +
 clang/lib/Sema/SemaDecl.cpp                   | 25 +++++++++++--------
 .../SemaCXX/injected-class-name-crash.cpp     |  7 ++++++
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index ba9572e2e7c59..a60504f1b9ae6 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -798,6 +798,7 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
   when used inside decltype in the return type. (#GH180460)
 - Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type 
vectors in `constexpr`. (#GH180044)
 - Fixed a crash when `explicit(bool)` is used with an incomplete enumeration. 
(#GH183887)
+- Fix crash-on-invalid caused by qualified forward declarations. (#GH202320)
 - Fixed a crash on `typeid` of incomplete local types during template 
instantiation. (#GH63242), (#GH176397)
 - Fixed spurious diagnostics produced when checking if constraints are 
equivalent for redeclarations,
   which could make the program mistakenly ill-formed.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f6d1d7a7877c7..813aebf263f97 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -18447,16 +18447,6 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind 
TUK, SourceLocation KWLoc,
             Previous.resolveKind();
           }
         }
-      } else if (auto *RD = dyn_cast<CXXRecordDecl>(PrevDecl);
-                 TUK == TagUseKind::Reference && RD &&
-                 RD->isInjectedClassName()) {
-        // If lookup found the injected class name, the previous declaration is
-        // the class being injected into.
-        PrevDecl = cast<TagDecl>(RD->getDeclContext());
-        Previous.clear();
-        Previous.addDecl(PrevDecl);
-        Previous.resolveKind();
-        IsInjectedClassName = true;
       }
     }
 
@@ -18488,6 +18478,18 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind 
TUK, SourceLocation KWLoc,
       if (TUK == TagUseKind::Reference || TUK == TagUseKind::Friend ||
           isDeclInScope(DirectPrevDecl, SearchDC, S,
                         SS.isNotEmpty() || isMemberSpecialization)) {
+
+        if (auto *RD = dyn_cast<CXXRecordDecl>(PrevDecl);
+            RD && RD->isInjectedClassName()) {
+          // If lookup found the injected class name, the previous declaration
+          // is the class being injected into.
+          Previous.clear();
+          PrevDecl = PrevTagDecl = cast<CXXRecordDecl>(RD->getDeclContext());
+          Previous.addDecl(PrevDecl);
+          Previous.resolveKind();
+          IsInjectedClassName = true;
+        }
+
         // Make sure that this wasn't declared as an enum and now used as a
         // struct or something similar.
         if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
@@ -18688,7 +18690,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind 
TUK, SourceLocation KWLoc,
           // Okay, we're going to make a redeclaration.  If this is some kind
           // of reference, make sure we build the redeclaration in the same DC
           // as the original, and ignore the current access specifier.
-          if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference) {
+          if (TUK == TagUseKind::Friend || TUK == TagUseKind::Reference ||
+              IsInjectedClassName) {
             SearchDC = PrevTagDecl->getDeclContext();
             AS = AS_none;
           }
diff --git a/clang/test/SemaCXX/injected-class-name-crash.cpp 
b/clang/test/SemaCXX/injected-class-name-crash.cpp
index a044ba064b58e..141762fe41d93 100644
--- a/clang/test/SemaCXX/injected-class-name-crash.cpp
+++ b/clang/test/SemaCXX/injected-class-name-crash.cpp
@@ -9,3 +9,10 @@ struct X : public Foo<Bar { // expected-error {{unknown 
template name 'Foo'}} ex
 template <class T>
 X<T>::X() {
 }
+
+namespace GH202320 {
+  struct S { S f(); };
+  struct S::S;
+  // expected-error@-1 {{forward declaration of struct cannot have a nested 
name specifier}}
+  S S::f() { return S(); }
+} // namespace GH202320

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

Reply via email to