From d8ac05753dc4506224d445ff98399c01da3136e5 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 3 Nov 2009 19:26:08 +0000 Subject: [PATCH] Reorganize the parsing of decl groups / function definitions so that declarators are parsed primarily within a single function (at least for these cases). Remove some excess diagnostics arising during parse failures. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85924 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 7 +- lib/Parse/ParseDecl.cpp | 170 +++++++++++++++++++---------------- lib/Parse/ParseStmt.cpp | 3 +- lib/Parse/Parser.cpp | 50 +---------- test/Lexer/block_cmt_end.c | 4 +- test/Sema/decl-invalid.c | 3 +- test/Sema/init.c | 2 +- 7 files changed, 103 insertions(+), 136 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index a0c06f375e..14dc8f8e36 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -950,11 +950,12 @@ private: DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd, - bool RequireSemi = true); + SourceLocation &DeclEnd); + DeclGroupPtrTy ParseDeclGroup(DeclSpec &DS, unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd = 0); DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); - DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D); DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl); DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6cee0b4bb6..6e3a348430 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -336,8 +336,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd, - bool RequireSemi) { + SourceLocation &DeclEnd) { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS); @@ -350,29 +349,102 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, return Actions.ConvertDeclToDeclGroup(TheDecl); } - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); - ParseDeclarator(DeclaratorInfo); + DeclGroupPtrTy DG = ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, + &DeclEnd); + return DG; +} - DeclGroupPtrTy DG = - ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); +/// ParseDeclGroup - Having concluded that this is either a function +/// definition or a group of object declarations, actually parse the +/// result. +Parser::DeclGroupPtrTy Parser::ParseDeclGroup(DeclSpec &DS, unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd) { + // Parse the first declarator. + Declarator D(DS, static_cast(Context)); + ParseDeclarator(D); - DeclEnd = Tok.getLocation(); - - // 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(); - return DG; + // Bail out if the first declarator didn't seem well-formed. + if (!D.hasName() && !D.mayOmitIdentifier()) { + // Skip until ; or }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return DeclGroupPtrTy(); } - Diag(Tok, diag::err_expected_semi_declaration); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) + if (AllowFunctionDefinitions && D.isFunctionDeclarator()) { + if (isDeclarationAfterDeclarator()) { + // Fall though. We have to check this first, though, because + // __attribute__ might be the start of a function definition in + // (extended) K&R C. + } else if (isStartOfFunctionDefinition()) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); + + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } + + DeclPtrTy TheDecl = ParseFunctionDefinition(D); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + } + + llvm::SmallVector DeclsInGroup; + DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D); + if (FirstDecl.get()) + DeclsInGroup.push_back(FirstDecl); + + // If we don't have a comma, it is either the end of the list (a ';') or an + // error, bail out. + while (Tok.is(tok::comma)) { + // Consume the comma. ConsumeToken(); - return DG; + + // Parse the next declarator. + D.clear(); + + // Accept attributes in an init-declarator. In the first declarator in a + // declaration, these would be part of the declspec. In subsequent + // declarators, they become part of the declarator itself, so that they + // don't apply to declarators after *this* one. Examples: + // short __attribute__((common)) var; -> declspec + // short var __attribute__((common)); -> declarator + // short x, __attribute__((common)) var; -> declarator + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseAttributes(&Loc); + D.AddAttributes(AttrList, Loc); + } + + ParseDeclarator(D); + + DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); + if (ThisDecl.get()) + DeclsInGroup.push_back(ThisDecl); + } + + if (DeclEnd) + *DeclEnd = Tok.getLocation(); + + if (Context != Declarator::ForContext && + ExpectAndConsume(tok::semi, + Context == Declarator::FileContext + ? diag::err_invalid_token_after_toplevel_declarator + : diag::err_expected_semi_declaration)) { + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + + return Actions.FinalizeDeclaratorGroup(CurScope, DS, + DeclsInGroup.data(), + DeclsInGroup.size()); } /// \brief Parse 'declaration' after parsing 'declaration-specifiers @@ -498,63 +570,6 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, return ThisDecl; } -/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after -/// parsing 'declaration-specifiers declarator'. This method is split out this -/// way to handle the ambiguity between top-level function-definitions and -/// declarations. -/// -/// init-declarator-list: [C99 6.7] -/// init-declarator -/// init-declarator-list ',' init-declarator -/// -/// According to the standard grammar, =default and =delete are function -/// definitions, but that definitely doesn't fit with the parser here. -/// -Parser::DeclGroupPtrTy Parser:: -ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { - // Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls - // that we parse together here. - llvm::SmallVector DeclsInGroup; - - // At this point, we know that it is not a function definition. Parse the - // rest of the init-declarator-list. - while (1) { - DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); - if (ThisDecl.get()) - DeclsInGroup.push_back(ThisDecl); - - // If we don't have a comma, it is either the end of the list (a ';') or an - // error, bail out. - if (Tok.isNot(tok::comma)) - break; - - // Consume the comma. - ConsumeToken(); - - // Parse the next declarator. - D.clear(); - - // Accept attributes in an init-declarator. In the first declarator in a - // declaration, these would be part of the declspec. In subsequent - // declarators, they become part of the declarator itself, so that they - // don't apply to declarators after *this* one. Examples: - // short __attribute__((common)) var; -> declspec - // short var __attribute__((common)); -> declarator - // short x, __attribute__((common)) var; -> declarator - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); - D.AddAttributes(AttrList, Loc); - } - - ParseDeclarator(D); - } - - return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(), - DeclsInGroup.data(), - DeclsInGroup.size()); -} - /// ParseSpecifierQualifierList /// specifier-qualifier-list: /// type-specifier specifier-qualifier-list[opt] @@ -2118,7 +2133,6 @@ void Parser::ParseDeclarator(Declarator &D) { /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { - if (Diags.hasAllExtensionsSilenced()) D.setExtension(); // C++ member pointers start with a '::' or a nested-name. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 272be2f660..7637382ac0 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -938,8 +938,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() { Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, - false); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (Tok.is(tok::semi)) { // for (int x = 4; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index bc737e9f0c..e69cb72a0a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -548,6 +548,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { SkipUntil(tok::semi); // FIXME: better skip? return DeclGroupPtrTy(); } + const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) @@ -571,54 +572,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { return Actions.ConvertDeclToDeclGroup(TheDecl); } - // Parse the first declarator. - Declarator DeclaratorInfo(DS, Declarator::FileContext); - ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? - if (!DeclaratorInfo.hasName()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return DeclGroupPtrTy(); - } - - // If we have a declaration or declarator list, handle it. - if (isDeclarationAfterDeclarator()) { - // Parse the init-declarator-list for a normal declaration. - DeclGroupPtrTy DG = - ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); - // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); - return DG; - } - - if (DeclaratorInfo.isFunctionDeclarator() && - isStartOfFunctionDefinition()) { - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - if (Tok.is(tok::l_brace)) { - // This recovery skips the entire function body. It would be nice - // to simply call ParseFunctionDefinition() below, however Sema - // assumes the declarator represents a function, not a typedef. - ConsumeBrace(); - SkipUntil(tok::r_brace, true); - } else { - SkipUntil(tok::semi); - } - return DeclGroupPtrTy(); - } - DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo); - return Actions.ConvertDeclToDeclGroup(TheDecl); - } - - if (DeclaratorInfo.isFunctionDeclarator()) - Diag(Tok, diag::err_expected_fn_body); - else - Diag(Tok, diag::err_invalid_token_after_toplevel_declarator); - SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return ParseDeclGroup(DS, Declarator::FileContext, true); } /// ParseFunctionDefinition - We parsed and verified that the specified diff --git a/test/Lexer/block_cmt_end.c b/test/Lexer/block_cmt_end.c index d85cf81f21..83d6cf1892 100644 --- a/test/Lexer/block_cmt_end.c +++ b/test/Lexer/block_cmt_end.c @@ -17,7 +17,7 @@ next comment ends with normal escaped newline: /* expected-warning {{escaped newline}} expected-warning {{backslash and newline}} *\ / -int bar +int bar /* expected-error {{invalid token after top level declarator}} */ /* xyz @@ -26,7 +26,7 @@ next comment ends with a trigraph escaped newline: */ /* expected-warning {{escaped newline between}} expected-warning {{backslash and newline separated by space}} expected-warning {{trigraph ends block comment}} *??/ / -foo /* expected-error {{invalid token after top level declarator}} */ +foo // rdar://6060752 - We should not get warnings about trigraphs in comments: diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c index 051f0f7ffb..823551f02e 100644 --- a/test/Sema/decl-invalid.c +++ b/test/Sema/decl-invalid.c @@ -10,8 +10,7 @@ int a() { int r[x()]; // expected-error {{size of array has non-integer type 'void'}} static y ?; // expected-error{{unknown type name 'y'}} \ - expected-error{{expected identifier or '('}} \ - expected-error{{expected ';' at end of declaration}} + expected-error{{expected identifier or '('}} } int; // expected-error {{declaration does not declare anything}} diff --git a/test/Sema/init.c b/test/Sema/init.c index 1cbcbb7e36..840b24fd30 100644 --- a/test/Sema/init.c +++ b/test/Sema/init.c @@ -21,7 +21,7 @@ int *h = &x; int test() { int a[10]; int b[10] = a; // expected-error {{initialization with '{...}' expected}} -int +; // expected-error {{expected identifier or '('}} expected-error {{expected ';' at end of declaration}} +int +; // expected-error {{expected identifier or '('}} }