Author: Matheus Izvekov Date: 2026-07-03T14:43:30-03:00 New Revision: 210834279ac6c3c47fdbe8dfe112c625f429e869
URL: https://github.com/llvm/llvm-project/commit/210834279ac6c3c47fdbe8dfe112c625f429e869 DIFF: https://github.com/llvm/llvm-project/commit/210834279ac6c3c47fdbe8dfe112c625f429e869.diff LOG: [clang] fix redeclarations of the injected class name (#207301) The declaration used to represent an injected class name should never be part of any redeclaration chain. Fixes #202320 Added: Modified: clang/docs/ReleaseNotes.md clang/lib/Sema/SemaDecl.cpp clang/test/SemaCXX/injected-class-name-crash.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3e6c10666ca16..bc9bda95d1990 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -811,6 +811,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 9948a633d7e98..6eb6c00f842c8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -18448,16 +18448,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; } } @@ -18489,6 +18479,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, @@ -18689,7 +18691,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
