https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/207301
The declaration used to represent an injected class name should never be part of any redeclaration chain. This is a regression since Clang 22, and this will be backported, so no release notes. Fixes #202320 >From 247a27257805528c5f7db43c277b8a7f97c725a1 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. This is a regression since Clang 22, and this will be backported, so no release notes. Fixes #202320 --- clang/lib/Sema/SemaDecl.cpp | 25 +++++++++++-------- .../SemaCXX/injected-class-name-crash.cpp | 7 ++++++ 2 files changed, 21 insertions(+), 11 deletions(-) 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
