diff --git a/clang/Driver/clang.cpp b/clang/Driver/clang.cpp index ba464147a1f8..397c27db54b6 100644 --- a/clang/Driver/clang.cpp +++ b/clang/Driver/clang.cpp @@ -400,6 +400,10 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK) { break; } + if (LangStd == lang_c89 || LangStd == lang_c94 || LangStd == lang_gnu89) + Options.ImplicitInt = 1; + else + Options.ImplicitInt = 0; Options.Trigraphs = 1; // -trigraphs or -ansi Options.DollarIdents = 1; // FIXME: Really a target property. Options.PascalStrings = PascalStrings; diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index f7278d2451df..243d56108be1 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -257,6 +257,11 @@ DIAG(ext_top_level_semi, EXTENSION, "ISO C does not allow an extra ';' outside of a function") DIAG(ext_extra_struct_semi, EXTENSION, "ISO C does not allow an extra ';' inside a struct or union") +DIAG(ext_missing_declspec, EXTENSION, + "declaration specifier missing, defaulting to 'int'") +DIAG(ext_missing_type_specifier, EXTENSION, + "type specifier missing, defaults to 'int'") + DIAG(ext_duplicate_declspec, EXTENSION, "duplicate '%0' declaration specifier") DIAG(ext_plain_complex, EXTENSION, @@ -539,8 +544,6 @@ DIAG(err_invalid_storage_class_in_func_decl, ERROR, "invalid storage class specifier in function declarator") DIAG(ext_anon_param_requires_type_specifier, EXTENSION, "type specifier required for unnamed parameter, defaults to int") -DIAG(ext_param_requires_type_specifier, EXTENSION, - "type specifier required for parameter '%0', defaults to int") DIAG(err_missing_param, ERROR, "expected parameter declarator") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 947492f04f4c..3975c51b9f2d 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -22,8 +22,9 @@ namespace clang { /// enabled, which controls the dialect of C that is accepted. struct LangOptions { unsigned Trigraphs : 1; // Trigraphs in source files. - unsigned BCPLComment : 1; // BCPL-style // comments. + unsigned BCPLComment : 1; // BCPL-style '//' comments. unsigned DollarIdents : 1; // '$' allowed in identifiers. + unsigned ImplicitInt : 1; // C89 implicit 'int'. unsigned Digraphs : 1; // C94, C99 and C++ unsigned HexFloats : 1; // C99 Hexadecimal float constants. unsigned C99 : 1; // C99 Support @@ -42,15 +43,14 @@ struct LangOptions { unsigned LaxVectorConversions : 1; LangOptions() { - Trigraphs = BCPLComment = DollarIdents = Digraphs = HexFloats = 0; + Trigraphs = BCPLComment = DollarIdents = ImplicitInt = Digraphs = 0; + HexFloats = 0; ObjC1 = ObjC2 = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = NoExtensions = 0; CXXOperatorNames = PascalStrings = Boolean = WritableStrings = 0; LaxVectorConversions = 0; } - bool isC90() const { return !C99 && !CPlusPlus; } - /// Emit - Emit this LangOptions object to bitcode. void Emit(llvm::Serializer& S) const; diff --git a/clang/include/clang/Parse/DeclSpec.h b/clang/include/clang/Parse/DeclSpec.h index 182b54c12834..b0572923044f 100644 --- a/clang/include/clang/Parse/DeclSpec.h +++ b/clang/include/clang/Parse/DeclSpec.h @@ -664,7 +664,7 @@ public: AttributeList *getAttributes() const { return AttrList; } void setInvalidType(bool flag) { InvalidType = flag; } - bool getInvalidType() { return InvalidType; } + bool getInvalidType() const { return InvalidType; } }; } // end namespace clang diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7d15e984ee62..9b8ecf8bd391 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1340,7 +1340,6 @@ void Parser::ParseParenDeclarator(Declarator &D) { ParmDecl.AddAttributes(ParseAttributes()); // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. - // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted. if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && DS.getStorageClassSpec() != DeclSpec::SCS_register) { Diag(DS.getStorageClassSpecLoc(), @@ -1353,11 +1352,6 @@ void Parser::ParseParenDeclarator(Declarator &D) { DS.ClearStorageClassSpecs(); } - // Inform the actions module about the parameter declarator, so it gets - // added to the current scope. - Action::TypeResult ParamTy = - Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); - // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDecl.getIdentifier(); @@ -1366,28 +1360,28 @@ void Parser::ParseParenDeclarator(Declarator &D) { Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition, ParmII->getName()); ParmII = 0; + ParmDecl.setInvalidType(true); } // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) { + // Completely missing, emit error. Diag(DSStart, diag::err_missing_param); - } else if (!DS.hasTypeSpecifier() && - (getLang().C99 || getLang().CPlusPlus)) { - // Otherwise, if something was specified but a type specifier wasn't, - // (e.g. "x" or "restrict x" or "restrict"), this is a use of implicit - // int. This is valid in C90, but not in C99 or C++. - if (ParmII) - Diag(ParmDecl.getIdentifierLoc(), - diag::ext_param_requires_type_specifier, ParmII->getName()); - else - Diag(DSStart, diag::ext_anon_param_requires_type_specifier); - } + } else { + // Otherwise, we have something. Add it and let semantic analysis try + // to grok it and add the result to the ParamInfo we are building. - ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), - ParmDecl.getDeclSpec().TakeAttributes())); + // Inform the actions module about the parameter declarator, so it gets + // added to the current scope. + Action::TypeResult ParamTy = + Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); + + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), + ParmDecl.getDeclSpec().TakeAttributes())); + } // If the next token is a comma, consume it and keep reading arguments. if (Tok.isNot(tok::comma)) break; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 76091245b557..cd99fc04ebe0 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -467,7 +467,7 @@ Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) { // 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) { + if (getLang().ImplicitInt && D.getDeclSpec().getParsedSpecifiers() == 0) { const char *PrevSpec; D.getDeclSpec().SetTypeSpecType(DeclSpec::TST_int, D.getIdentifierLoc(), PrevSpec); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index ca56c56dd9ad..d46e99756774 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -27,7 +27,7 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) { QualType Result; switch (DS.getTypeSpecType()) { - default: return QualType(); // FIXME: Handle unimp cases! + default: assert(0 && "Unknown TypeSpecType!"); case DeclSpec::TST_void: Result = Context.VoidTy; break; @@ -42,7 +42,29 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) { Result = Context.UnsignedCharTy; } break; - case DeclSpec::TST_unspecified: // Unspecific typespec defaults to int. + case DeclSpec::TST_unspecified: + // Unspecified typespec defaults to int in C90. However, the C90 grammar + // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, + // type-qualifier, or storage-class-specifier. If not, emit an extwarn. + // Note that the one exception to this is function definitions, which are + // allowed to be completely missing a declspec. This is handled in the + // parser already though by it pretending to have seen an 'int' in this + // case. + if (getLangOptions().ImplicitInt) { + if ((DS.getParsedSpecifiers() & (DeclSpec::PQ_StorageClassSpecifier | + DeclSpec::PQ_TypeSpecifier | + DeclSpec::PQ_TypeQualifier)) == 0) + Diag(DS.getSourceRange().getBegin(), diag::ext_missing_declspec); + } else { + // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: + // "At least one type specifier shall be given in the declaration + // specifiers in each declaration, and in the specifier-qualifier list in + // each struct declaration and type name." + if (!DS.hasTypeSpecifier()) + Diag(DS.getSourceRange().getBegin(), diag::ext_missing_type_specifier); + } + + // FALL THROUGH. case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { switch (DS.getTypeSpecWidth()) { diff --git a/clang/test/Parser/declarators.c b/clang/test/Parser/declarators.c index aaea35c2cbc1..15ae7c6b577c 100644 --- a/clang/test/Parser/declarators.c +++ b/clang/test/Parser/declarators.c @@ -6,7 +6,7 @@ void f0(); void f1(int [*]); void f2(int [const *]); void f3(int [volatile const*]); -int f4(*XX)(void); /* expected-error {{cannot return}} expected-warning {{type specifier required}} */ +int f4(*XX)(void); /* expected-error {{cannot return}} expected-warning {{type specifier missing, defaults to 'int'}} */ char ((((*X)))); diff --git a/clang/test/Sema/c89.c b/clang/test/Sema/c89.c index 301ec374db3a..6a12f1cc568e 100644 --- a/clang/test/Sema/c89.c +++ b/clang/test/Sema/c89.c @@ -36,6 +36,14 @@ int *__restrict; /* expected-error {{expected identifier}} */ /* Implicit int, always ok */ -foo() {} +test6() {} + +/* PR2012 */ +test7; /* expected-warning {{declaration specifier missing, defaulting to 'int'}} */ + +void test8(int, x); /* expected-warning {{declaration specifier missing, defaulting to 'int'}} */ + +typedef int sometype; +int a(sometype, y) {return 0;} /* expected-warning {{declaration specifier missing, defaulting to 'int'}} */ diff --git a/clang/test/Sema/function.c b/clang/test/Sema/function.c index 2a18dbb70509..152205dd2443 100644 --- a/clang/test/Sema/function.c +++ b/clang/test/Sema/function.c @@ -18,7 +18,7 @@ void h (const char *fmt, ...) {} //expected-error{{conflicting types for 'h'}} // PR1965 int t5(b); // expected-error {{parameter list without types}} -int t6(int x, g); // expected-warning {{type specifier required for parameter 'g'}} +int t6(int x, g); // expected-warning {{type specifier missing, defaults to 'int'}} int t7(, ); // expected-error {{expected parameter declarator}} expected-error {{expected parameter declarator}} int t8(, int a); // expected-error {{expected parameter declarator}}