зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
9c21289a86
Коммит
d8ac05753d
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<Declarator::TheContext>(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<DeclPtrTy, 8> 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<DeclPtrTy, 8> 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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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 '('}}
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче