diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index bee0b51ab2..947492f04f 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -49,6 +49,8 @@ struct LangOptions { LaxVectorConversions = 0; } + bool isC90() const { return !C99 && !CPlusPlus; } + /// Emit - Emit this LangOptions object to bitcode. void Emit(llvm::Serializer& S) const; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 703144b3c4..76091245b5 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -356,8 +356,10 @@ Parser::DeclTy *Parser::ParseExternalDeclaration() { /// compound-statement in function-definition. /// /// function-definition: [C99 6.9.1] -/// declaration-specifiers[opt] declarator declaration-list[opt] -/// compound-statement +/// decl-specs declarator declaration-list[opt] compound-statement +/// [C90] function-definition: [C99 6.7.1] - implicit int result +/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement +/// /// declaration: [C99 6.7] /// declaration-specifiers init-declarator-list[opt] ';' /// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] @@ -451,8 +453,10 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. /// -/// declaration-specifiers[opt] declarator declaration-list[opt] -/// compound-statement [TODO] +/// function-definition: [C99 6.9.1] +/// decl-specs declarator declaration-list[opt] compound-statement +/// [C90] function-definition: [C99 6.7.1] - implicit int result +/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement /// Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) { const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); @@ -460,6 +464,15 @@ Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) { "This isn't a function declarator!"); const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun; + // If this is C90 and the declspecs were completely missing, fudge in an + // implicit int. We do this here because this is the only place where + // declaration-specifiers are completely optional in the grammar. + if (getLang().isC90() && !D.getDeclSpec().getParsedSpecifiers() == 0) { + const char *PrevSpec; + D.getDeclSpec().SetTypeSpecType(DeclSpec::TST_int, D.getIdentifierLoc(), + PrevSpec); + } + // 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; {} diff --git a/test/Sema/c89.c b/test/Sema/c89.c index 831c1ce7c5..301ec374db 100644 --- a/test/Sema/c89.c +++ b/test/Sema/c89.c @@ -33,3 +33,9 @@ void test5(register); /* PR2041 */ int *restrict; int *__restrict; /* expected-error {{expected identifier}} */ + + +/* Implicit int, always ok */ +foo() {} + +