From: Eli Friedman Date: Tue, 20 Dec 2011 01:50:37 +0000 (+0000) Subject: Fix tentative parsing so it knows how to handle an ambiguous for-range-declaration... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9490ab433deef70105d817616928d700f87642d9;p=clang Fix tentative parsing so it knows how to handle an ambiguous for-range-declaration. PR11601. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146953 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 07d21bfeed..e4318375af 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1683,13 +1683,13 @@ private: return isDeclarationSpecifier(true); } - /// isSimpleDeclaration - Disambiguates between a declaration or an - /// expression, mainly used for the C 'clause-1' or the C++ + /// isForInitDeclaration - Disambiguates between a declaration or an + /// expression in the context of the C 'clause-1' or the C++ // 'for-init-statement' part of a 'for' statement. /// Returns true for declaration, false for expression. - bool isSimpleDeclaration() { + bool isForInitDeclaration() { if (getLang().CPlusPlus) - return isCXXSimpleDeclaration(); + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); return isDeclarationSpecifier(true); } @@ -1734,7 +1734,7 @@ private: /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. /// Returns false if the statement is disambiguated as expression. - bool isCXXSimpleDeclaration(); + bool isCXXSimpleDeclaration(bool AllowForRangeDecl); /// isCXXFunctionDeclarator - Disambiguates between a function declarator or /// a constructor-style initializer, when parsing declaration statements. @@ -1808,7 +1808,7 @@ private: // They all consume tokens, so backtracking should be used after calling them. TPResult TryParseDeclarationSpecifier(); - TPResult TryParseSimpleDeclaration(); + TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl); TPResult TryParseTypeofSpecifier(); TPResult TryParseProtocolQualifiers(); TPResult TryParseInitDeclaratorList(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index da0e865862..435bde3375 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1306,7 +1306,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { if (Tok.is(tok::semi)) { // for (; // no first part, eat the ';'. ConsumeToken(); - } else if (isSimpleDeclaration()) { // for (int X = 4; + } else if (isForInitDeclaration()) { // for (int X = 4; // Parse declaration, which eats the ';'. if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 7c280ff50b..2c9018316a 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -62,7 +62,7 @@ bool Parser::isCXXDeclarationStatement() { return true; // simple-declaration default: - return isCXXSimpleDeclaration(); + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); } } @@ -75,7 +75,11 @@ bool Parser::isCXXDeclarationStatement() { /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// -bool Parser::isCXXSimpleDeclaration() { +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // C++ 6.8p1: // There is an ambiguity in the grammar involving expression-statements and // declarations: An expression-statement with a function-style explicit type @@ -112,7 +116,7 @@ bool Parser::isCXXSimpleDeclaration() { // We need tentative parsing... TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); PA.Revert(); // In case of an error, let the declaration parsing code handle it. @@ -130,7 +134,12 @@ bool Parser::isCXXSimpleDeclaration() { /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// -Parser::TPResult Parser::TryParseSimpleDeclaration() { +/// (if AllowForRangeDecl specified) +/// for ( for-range-declaration : for-range-initializer ) statement +/// for-range-declaration: +/// attribute-specifier-seqopt type-specifier-seq declarator +/// +Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { // We know that we have a simple-type-specifier/typename-specifier followed // by a '('. assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous()); @@ -150,7 +159,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { if (TPR != TPResult::Ambiguous()) return TPR; - if (Tok.isNot(tok::semi)) + if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) return TPResult::False(); return TPResult::Ambiguous(); diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp index b4b34ee54e..fa42ca45a5 100644 --- a/test/SemaCXX/for-range-no-std.cpp +++ b/test/SemaCXX/for-range-no-std.cpp @@ -36,3 +36,8 @@ void f() { for (int b : NS::ADL()) {} // ok for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}} } + +void PR11601() { + void (*vv[])() = {PR11601, PR11601, PR11601}; + for (void (*i)() : vv) i(); +}