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;
"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,
"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")
/// 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
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;
AttributeList *getAttributes() const { return AttrList; }
void setInvalidType(bool flag) { InvalidType = flag; }
- bool getInvalidType() { return InvalidType; }
+ bool getInvalidType() const { return InvalidType; }
};
} // end namespace clang
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(),
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();
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;
// 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);
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;
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()) {
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))));
/* 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'}} */
// 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}}