Fix PR7617 by not entering ParseFunctionDefinition when
a function prototype is followed by a declarator if we aren't parsing a K&R style identifier list. Also, avoid skipping randomly after a declaration if a semicolon is missing. Before we'd get: t.c:3:1: error: expected function body after function declarator void bar(); ^ Now we get: t.c:1:11: error: invalid token after top level declarator void foo() ^ ; llvm-svn: 108105
This commit is contained in:
parent
dbb1e93a9f
commit
1390134c18
|
@ -888,6 +888,13 @@ struct DeclaratorChunk {
|
|||
delete[] Exceptions;
|
||||
}
|
||||
|
||||
/// isKNRPrototype - Return true if this is a K&R style identifier list,
|
||||
/// like "void foo(a,b,c)". In a function definition, this will be followed
|
||||
/// by the argument type definitions.
|
||||
bool isKNRPrototype() const {
|
||||
return !hasPrototype && NumArgs != 0;
|
||||
}
|
||||
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
return SourceLocation::getFromRawEncoding(EllipsisLoc);
|
||||
}
|
||||
|
|
|
@ -834,7 +834,7 @@ private:
|
|||
// C99 6.9: External Definitions.
|
||||
DeclGroupPtrTy ParseExternalDeclaration(CXX0XAttributeList Attr);
|
||||
bool isDeclarationAfterDeclarator() const;
|
||||
bool isStartOfFunctionDefinition();
|
||||
bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator);
|
||||
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
|
||||
AccessSpecifier AS = AS_none);
|
||||
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
|
||||
|
|
|
@ -402,7 +402,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
// start of a function definition in GCC-extended K&R C.
|
||||
!isDeclarationAfterDeclarator()) {
|
||||
|
||||
if (isStartOfFunctionDefinition()) {
|
||||
if (isStartOfFunctionDefinition(D)) {
|
||||
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
Diag(Tok, diag::err_function_declared_typedef);
|
||||
|
||||
|
@ -412,6 +412,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
|
||||
DeclPtrTy TheDecl = ParseFunctionDefinition(D);
|
||||
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
||||
}
|
||||
|
||||
if (isDeclarationSpecifier()) {
|
||||
// If there is an invalid declaration specifier right after the function
|
||||
// prototype, then we must be in a missing semicolon case where this isn't
|
||||
// actually a body. Just fall through into the code that handles it as a
|
||||
// prototype, and let the top-level code handle the erroneous declspec
|
||||
// where it would otherwise expect a comma or semicolon.
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_fn_body);
|
||||
SkipUntil(tok::semi);
|
||||
|
@ -463,9 +471,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
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();
|
||||
// Okay, there was no semicolon and one was expected. If we see a
|
||||
// declaration specifier, just assume it was missing and continue parsing.
|
||||
// Otherwise things are very confused and we skip to recover.
|
||||
if (!isDeclarationSpecifier()) {
|
||||
SkipUntil(tok::r_brace, true, true);
|
||||
if (Tok.is(tok::semi))
|
||||
ConsumeToken();
|
||||
}
|
||||
}
|
||||
|
||||
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
|
||||
|
|
|
@ -238,7 +238,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
|||
}
|
||||
|
||||
if (DeclaratorInfo.isFunctionDeclarator() &&
|
||||
isStartOfFunctionDefinition()) {
|
||||
isStartOfFunctionDefinition(DeclaratorInfo)) {
|
||||
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
Diag(Tok, diag::err_function_declared_typedef);
|
||||
|
||||
|
|
|
@ -521,12 +521,17 @@ bool Parser::isDeclarationAfterDeclarator() const {
|
|||
|
||||
/// \brief Determine whether the current token, if it occurs after a
|
||||
/// declarator, indicates the start of a function definition.
|
||||
bool Parser::isStartOfFunctionDefinition() {
|
||||
bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
|
||||
assert(Declarator.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
||||
"Isn't a function declarator");
|
||||
if (Tok.is(tok::l_brace)) // int X() {}
|
||||
return true;
|
||||
|
||||
if (!getLang().CPlusPlus)
|
||||
return isDeclarationSpecifier(); // int X(f) int f; {}
|
||||
// Handle K&R C argument lists: int X(f) int f; {}
|
||||
if (!getLang().CPlusPlus &&
|
||||
Declarator.getTypeObject(0).Fun.isKNRPrototype())
|
||||
return isDeclarationSpecifier();
|
||||
|
||||
return Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
|
||||
Tok.is(tok::kw_try); // X() try { ... }
|
||||
}
|
||||
|
@ -649,7 +654,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D,
|
|||
// If this declaration was formed with a K&R-style identifier list for the
|
||||
// arguments, parse declarations for all of the args next.
|
||||
// int foo(a,b) int a; float b; {}
|
||||
if (!FTI.hasPrototype && FTI.NumArgs != 0)
|
||||
if (FTI.isKNRPrototype())
|
||||
ParseKNRParamDeclarations(D);
|
||||
|
||||
// We should have either an opening brace or, in a C++ constructor,
|
||||
|
|
|
@ -86,3 +86,11 @@ struct test13 { int a; } (test13x);
|
|||
|
||||
// <rdar://problem/8044088>
|
||||
struct X<foo::int> { }; // expected-error{{expected identifier or '('}}
|
||||
|
||||
|
||||
// PR7617 - error recovery on missing ;.
|
||||
|
||||
void test14() // expected-error {{invalid token after top level declarator}}
|
||||
|
||||
void test14a();
|
||||
void *test14b = (void*)test14a; // Make sure test14a didn't get skipped.
|
||||
|
|
Loading…
Reference in New Issue