Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -217,6 +217,8 @@ assert(Tok.isObjCAtKeyword(tok::objc_interface) && "ParseObjCAtInterfaceDeclaration(): Expected @interface"); CheckNestedObjCContexts(AtLoc); + if (isEofOrEom()) + return nullptr; ConsumeToken(); // the "interface" identifier // Code completion after '@interface'. @@ -2101,6 +2103,8 @@ assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); CheckNestedObjCContexts(AtLoc); + if (isEofOrEom()) + return nullptr; ConsumeToken(); // the "implementation" identifier // Code completion after '@implementation'. @@ -3627,6 +3631,14 @@ SourceLocation OrigLoc = Tok.getLocation(); assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!"); + // Store an artificial EOF token to ensure that we don't run off the end of + // the method's body when we come to parse it. + Token Eof; + Eof.startToken(); + Eof.setKind(tok::eof); + Eof.setEofData(MCDecl); + Eof.setLocation(Tok.getLocation()); + LM.Toks.push_back(Eof); // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); @@ -3658,7 +3670,10 @@ Actions.ActOnDefaultCtorInitializers(MCDecl); ParseFunctionStatementBody(MCDecl, BodyScope); } - + + // Clean up the remaining EOF token. + if (Tok.is(tok::eof) && Tok.getEofData() == MCDecl) + ConsumeAnyToken(); if (Tok.getLocation() != OrigLoc) { // Due to parsing error, we either went over the cached tokens or // there are still cached tokens left. If it's the latter case skip the Index: test/Parser/objc-at-implementation-eof-crash.m =================================================================== --- /dev/null +++ test/Parser/objc-at-implementation-eof-crash.m @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify -Wno-objc-root-class %s + +@interface ClassA + +- (void)fileExistsAtPath:(int)x; + +@end + +@interface ClassB + +@end + +@implementation ClassB // expected-note {{implementation started here}} + +- (void) method:(ClassA *)mgr { // expected-note {{to match this '{'}} + mgr fileExistsAtPath:0 +} // expected-error {{expected ']'}} + +@implementation ClassC // expected-error {{missing '@end'}} // expected-error {{expected '}'}} // expected-warning {{cannot find interface declaration for 'ClassC'}} + +@end Index: test/Parser/objc-at-interface-eof-crash.m =================================================================== --- /dev/null +++ test/Parser/objc-at-interface-eof-crash.m @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify -Wno-objc-root-class %s + +@interface ClassA + +- (void)fileExistsAtPath:(int)x; + +@end + +@interface ClassB + +@end + +@implementation ClassB // expected-note {{implementation started here}} + +- (void) method:(ClassA *)mgr { // expected-note {{to match this '{'}} + mgr fileExistsAtPath:0 +} // expected-error {{expected ']'}} + +@interface ClassC // expected-error {{missing '@end'}} // expected-error {{expected '}'}} + +@end