diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index eb820570b969..ca2d706f23a2 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -809,7 +809,8 @@ private: // C99 6.7: Declarations. DeclGroupPtrTy ParseDeclaration(unsigned Context); - DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context); + DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, + bool RequireSemi = true); DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D); DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl); void ParseDeclarationSpecifiers(DeclSpec &DS, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 5de4dd4a7c60..f80afe3f4b13 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -257,7 +257,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context) { /// declaration-specifiers init-declarator-list[opt] ';' ///[C90/C++]init-declarator-list ';' [TODO] /// [OMP] threadprivate-directive [TODO] -Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context) { +/// +/// If RequireSemi is false, this does not check for a ';' at the end of the +/// declaration. +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, + bool RequireSemi) { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS); @@ -275,22 +279,16 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context) { DeclGroupPtrTy DG = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); + + // If the client wants to check what comes after the declaration, just return + // immediately without checking anything! + if (!RequireSemi) return DG; if (Tok.is(tok::semi)) { ConsumeToken(); - // for(is key; in keys) is error. - if (Context == Declarator::ForContext && isTokIdentifier_in()) - Diag(Tok, diag::err_parse_error); - return DG; } - // If this is an ObjC2 for-each loop, this is a successful declarator - // parse. The syntax for these looks like: - // 'for' '(' declaration 'in' expr ')' statement - if (Context == Declarator::ForContext && isTokIdentifier_in()) - return DG; - Diag(Tok, diag::err_expected_semi_declation); // Skip to end of block or statement SkipUntil(tok::r_brace, true, true); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index b1a32decffcf..3ca2f02b52bf 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -912,12 +912,18 @@ Parser::OwningStmtResult Parser::ParseForStatement() { Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); SourceLocation DeclStart = Tok.getLocation(); - DeclGroupPtrTy VarDecls = ParseSimpleDeclaration(Declarator::ForContext); - // FIXME: Pass in the right location for the end of the declstmt. - FirstPart = Actions.ActOnDeclStmt(VarDecls, DeclStart, DeclStart); - if ((ForEach = isTokIdentifier_in())) { + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, false); + FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); + + if (Tok.is(tok::semi)) { // for (int x = 4; + ConsumeToken(); + } else if ((ForEach = isTokIdentifier_in())) { + // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' SecondPart = ParseExpression(); + } else { + Diag(Tok, diag::err_expected_semi_for); + SkipUntil(tok::semi); } } else { Value = ParseExpression(); diff --git a/clang/test/Parser/objc-foreach-error-1.m b/clang/test/Parser/objc-foreach-error-1.m deleted file mode 100644 index 16a7ea8e3dc3..000000000000 --- a/clang/test/Parser/objc-foreach-error-1.m +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: clang-cc -fsyntax-only -verify %s - -ce MyList // expected-error {{invalid token after top level declarator}} -@end - - -@implementation MyList -- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount -{ - return 0; -} -@end - - -int LOOP(); - -@implementation MyList (BasicTest) // expected-error {{cannot find interface declaration for 'MyList'}} -- (void)compilerTestAgainst { -MyList * el; // expected-error {{use of undeclared identifier 'MyList'}} - for (el in @"foo") // expected-error {{use of undeclared identifier 'el'}} - { LOOP(); } -} -@end - diff --git a/clang/test/Parser/objc-foreach-syntax.m b/clang/test/Parser/objc-foreach-syntax.m index 950fc2f114a3..e6e3ccf12d1a 100644 --- a/clang/test/Parser/objc-foreach-syntax.m +++ b/clang/test/Parser/objc-foreach-syntax.m @@ -1,7 +1,28 @@ // RUN: clang-cc -fsyntax-only -verify %s -static int test_NSURLGetResourceValueForKey( id keys ) +ce MyList // expected-error {{invalid token after top level declarator}} +@end + + +@implementation MyList +- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount { - for ( id key; in keys) { // expected-error {{parse error}} - } + return 0; +} +@end + + +int LOOP(); + +@implementation MyList (BasicTest) // expected-error {{cannot find interface declaration for 'MyList'}} +- (void)compilerTestAgainst { +MyList * el; // expected-error {{use of undeclared identifier 'MyList'}} + for (el in @"foo") // expected-error {{use of undeclared identifier 'el'}} + { LOOP(); } +} +@end + + +static int test7(id keys) { + for (id key; in keys) ; // expected-error {{use of undeclared identifier 'in'}} }