https://github.com/ahatanak updated https://github.com/llvm/llvm-project/pull/219953
>From 056d41605942f677106df91d2f88f38210759c8d Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Mon, 31 Aug 2026 17:29:08 +0530 Subject: [PATCH 1/2] [clang][Parse] Fix stale CurParsedObjCImpl after an @implementation ends early ObjCImplParsingDataRAII only reset CurParsedObjCImpl in its destructor, but an @implementation can be finished well before that: CheckNestedObjCContexts ends it as soon as a nested @interface/@protocol/@implementation shows up, and that container is then parsed inside the same frame. Anything defined in there still looked like it was inside the already finished @implementation, so ParseFunctionDefinition queued the body into a LateParsedObjCMethods that nobody was going to drain again, and the destructor's assert(LateParsedObjCMethods.empty()) fired. finish() now restores the previous CurParsedObjCImpl the moment the @implementation ends, instead of the destructor nulling it later. Restoring rather than clearing also covers the mirror image: an @implementation nested through a namespace inside another one used to wipe out the outer, still open one when it ended, and the next method definition in the outer one tripped the "Method out of @implementation" assert. Fixes #209503 --- clang/docs/ReleaseNotes.md | 3 +++ clang/include/clang/Parse/Parser.h | 4 +++- clang/lib/Parse/ParseObjc.cpp | 5 ++++- clang/test/Parser/GH209503.mm | 27 +++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 clang/test/Parser/GH209503.mm diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3cca316a91d4d..1799c5c9ac23a 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -709,6 +709,9 @@ features cannot lower the translation-unit ABI level; - Fixed an assertion when the `dim` argument to an OpenACC `gang` clause evaluated to a value not representable by a signed integer, such as an unsigned wrap around. (#GH221418) +- Fixed an assertion failure when a method or function definition follows an + Objective-C `@implementation` that was ended by a nested `@interface`, + `@protocol` or `@implementation` before its `@end`. (#GH209503) ### OpenACC Specific Changes diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 6913c42884a36..9b2de3a10e988 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5710,7 +5710,8 @@ class Parser : public CodeCompletionHandler { LateParsedObjCMethodContainer LateParsedObjCMethods; ObjCImplParsingDataRAII(Parser &parser, Decl *D) - : P(parser), Dcl(D), HasCFunction(false) { + : P(parser), Dcl(D), HasCFunction(false), + PrevParsedObjCImpl(parser.CurParsedObjCImpl) { P.CurParsedObjCImpl = this; Finished = false; } @@ -5720,6 +5721,7 @@ class Parser : public CodeCompletionHandler { bool isFinished() const { return Finished; } private: + ObjCImplParsingDataRAII *PrevParsedObjCImpl; bool Finished; }; ObjCImplParsingDataRAII *CurParsedObjCImpl; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index a70f6356ae013..7ca08cb2112e6 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -2035,7 +2035,6 @@ Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { << SemaObjC::OCK_Implementation; } } - P.CurParsedObjCImpl = nullptr; assert(LateParsedObjCMethods.empty()); } @@ -2061,6 +2060,10 @@ void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { delete *I; LateParsedObjCMethods.clear(); + // Parsing may go on in the enclosing frame before this object is destroyed + // (e.g. a nested @interface ended the @implementation early), so stop being + // the current @implementation now rather than in the destructor. + P.CurParsedObjCImpl = PrevParsedObjCImpl; Finished = true; } diff --git a/clang/test/Parser/GH209503.mm b/clang/test/Parser/GH209503.mm new file mode 100644 index 0000000000000..43d14b242dbcc --- /dev/null +++ b/clang/test/Parser/GH209503.mm @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s + +// Method and function bodies are parsed when their @implementation ends; make +// sure they are queued into the right @implementation (if any) after a nested +// container has ended one. + +@interface Z +@end +@interface A +@end + +@implementation Z +namespace N { +@implementation A // expected-error {{Objective-C declarations may only appear in global scope}} +@end +} +- (void)m { + undeclared(); // expected-error {{use of undeclared identifier 'undeclared'}} +} +@end + +@implementation NSArray // expected-warning {{cannot find interface declaration for 'NSArray'}} \ + // expected-note {{implementation started here}} +@interface NSIndexSet // expected-error {{missing '@end'}} \ + // expected-note {{class started here}} +// expected-warning@+1 {{function definition inside an Objective-C container is deprecated}} +void f(void) {} // expected-error {{missing '@end'}} >From 6f1deae95075d7b7420c30b972cda0addf90b813 Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Fri, 11 Sep 2026 08:05:23 +0530 Subject: [PATCH 2/2] Document `PrevParsedObjCImpl` Explain that it is only ever non-null for invalid code, where an @implementation starts while a previous one is still open. --- clang/include/clang/Parse/Parser.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 9b2de3a10e988..960b3c2485db0 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5721,6 +5721,11 @@ class Parser : public CodeCompletionHandler { bool isFinished() const { return Finished; } private: + /// The \@implementation that was still open when this one started; made + /// current again once this one finishes. Only invalid code has one: an + /// \@implementation that starts while a previous \@implementation is + /// still open (e.g. through an intervening namespace). For valid code + /// this is always null. ObjCImplParsingDataRAII *PrevParsedObjCImpl; bool Finished; }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
