mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 04:30:10 +00:00
Added missing checks for forward declarations of the main() function.
More accurate diagnosis on implicit 'int' type specifiers.
This commit is contained in:
parent
bea2e86210
commit
ba75a2ac26
@ -2417,49 +2417,55 @@ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||
/* Parse attributes for this declarator */
|
||||
ParseAttribute (D);
|
||||
|
||||
/* 'inline' is only allowed on functions */
|
||||
if (Mode != DM_ACCEPT_PARAM_IDENT &&
|
||||
(D->StorageClass & SC_TYPEMASK) != SC_FUNC &&
|
||||
(D->StorageClass & SC_INLINE) == SC_INLINE) {
|
||||
Error ("'inline' on non-function declaration");
|
||||
/* Check a few things for the instance (rather than the type) */
|
||||
if (D->Ident[0] != '\0') {
|
||||
/* Check a few pre-C99 things */
|
||||
if ((Spec->Flags & DS_TYPE_MASK) == DS_DEF_TYPE && IsRankInt (Spec->Type)) {
|
||||
/* If the standard was not set explicitly to C89, print a warning
|
||||
** for typedefs with implicit int type specifier.
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_C99) {
|
||||
if ((D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
||||
Warning ("Implicit 'int' type specifier is an obsolete feature");
|
||||
} else {
|
||||
Warning ("Type specifier defaults to 'int' in typedef of '%s'",
|
||||
D->Ident);
|
||||
Note ("Implicit 'int' type specifier is an obsolete feature");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check other things depending on the "kind" of the instance */
|
||||
if ((D->StorageClass & SC_TYPEMASK) == SC_FUNC) {
|
||||
/* Special handling for main() */
|
||||
if (strcmp (D->Ident, "main") == 0) {
|
||||
/* main() cannot be a fastcall function */
|
||||
if (IsQualFastcall (D->Type)) {
|
||||
Error ("'main' cannot be declared __fastcall__");
|
||||
}
|
||||
|
||||
/* main() cannot be an inline function */
|
||||
if ((D->StorageClass & SC_INLINE) == SC_INLINE) {
|
||||
Error ("'main' cannot be declared inline");
|
||||
D->StorageClass &= ~SC_INLINE;
|
||||
}
|
||||
|
||||
/* Check a few pre-C99 things */
|
||||
if (D->Ident[0] != '\0' && (Spec->Flags & DS_TYPE_MASK) == DS_DEF_TYPE) {
|
||||
/* Check and warn about an implicit int return in the function */
|
||||
if (IsTypeFunc (D->Type) && IsRankInt (GetFuncReturnType (D->Type))) {
|
||||
/* Function has an implicit int return. Output a warning if we don't
|
||||
** have the C89 standard enabled explicitly.
|
||||
/* Check return type */
|
||||
if (GetUnqualRawTypeCode (GetFuncReturnType (D->Type)) != T_INT) {
|
||||
/* If cc65 extensions aren't enabled, don't allow a main function
|
||||
** that doesn't return an int.
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_C99) {
|
||||
Warning ("Implicit 'int' return type is an obsolete feature");
|
||||
}
|
||||
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
|
||||
}
|
||||
|
||||
/* For anything that is not a function, check for an implicit int
|
||||
** declaration.
|
||||
*/
|
||||
if (!IsTypeFunc (D->Type) && IsRankInt (D->Type)) {
|
||||
if ((D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
||||
/* If the standard was not set explicitly to C89, print a warning
|
||||
** for variables with implicit int type.
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_C99) {
|
||||
Warning ("Implicit 'int' is an obsolete feature");
|
||||
}
|
||||
} else {
|
||||
/* If the standard was not set explicitly to C89, print a warning
|
||||
** for typedefs with implicit int type.
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_C99) {
|
||||
Warning ("Type defaults to 'int' in typedef of '%s'",
|
||||
D->Ident);
|
||||
Note ("Implicit 'int' is an obsolete feature");
|
||||
if (IS_Get (&Standard) != STD_CC65) {
|
||||
Error ("'main' must always return an int");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (Mode != DM_ACCEPT_PARAM_IDENT &&
|
||||
(D->StorageClass & SC_INLINE) == SC_INLINE) {
|
||||
/* 'inline' is only allowed on functions */
|
||||
Error ("'inline' on non-function declaration");
|
||||
D->StorageClass &= ~SC_INLINE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the size of the declared type */
|
||||
|
@ -450,7 +450,6 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Parse argument declarations and function body. */
|
||||
{
|
||||
int ParamComplete; /* If all paramemters have complete types */
|
||||
int C99MainFunc = 0;/* Flag for C99 main function returning int */
|
||||
SymEntry* Param;
|
||||
const Type* RType; /* Real type used for struct parameters */
|
||||
const Type* ReturnType; /* Return type */
|
||||
@ -513,34 +512,6 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Mark this as the main function */
|
||||
CurrentFunc->Flags |= FF_IS_MAIN;
|
||||
|
||||
/* Main cannot be a fastcall function */
|
||||
if (IsQualFastcall (Func->Type)) {
|
||||
Error ("'main' cannot be declared as __fastcall__");
|
||||
}
|
||||
|
||||
/* main() cannot be an inline function */
|
||||
if ((Func->Flags & SC_INLINE) == SC_INLINE) {
|
||||
Error ("'main' cannot be declared inline");
|
||||
Func->Flags &= ~SC_INLINE;
|
||||
}
|
||||
|
||||
/* Check return type */
|
||||
if (GetUnqualRawTypeCode (ReturnType) == T_INT) {
|
||||
/* Determine if this is a main function in a C99 environment that
|
||||
** returns an int.
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_C99) {
|
||||
C99MainFunc = 1;
|
||||
}
|
||||
} else {
|
||||
/* If cc65 extensions aren't enabled, don't allow a main function
|
||||
** that doesn't return an int.
|
||||
*/
|
||||
if (IS_Get (&Standard) != STD_CC65) {
|
||||
Error ("'main' must always return an int");
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a forced import of a symbol that is contained in the startup
|
||||
** code. This will force the startup code to be linked in.
|
||||
*/
|
||||
@ -665,7 +636,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* If this is the main function in a C99 environment returning an int,
|
||||
** let it always return zero. Otherwise output a warning.
|
||||
*/
|
||||
if (C99MainFunc) {
|
||||
if (IS_Get (&Standard) >= STD_C99 && GetUnqualRawTypeCode (ReturnType) == T_INT) {
|
||||
g_getimmed (CF_INT | CF_CONST, 0, 0);
|
||||
} else if (IS_Get (&WarnReturnType)) {
|
||||
Warning ("Control reaches end of non-void function [-Wreturn-type]");
|
||||
|
@ -1,4 +1,4 @@
|
||||
bug1889-missing-identifier.c:3: Error: Identifier or ';' expected after declaration specifiers
|
||||
bug1889-missing-identifier.c:3: Warning: Implicit 'int' is an obsolete feature
|
||||
bug1889-missing-identifier.c:3: Warning: Implicit 'int' type specifier is an obsolete feature
|
||||
bug1889-missing-identifier.c:4: Error: 'inline' on empty declaration
|
||||
bug1889-missing-identifier.c:6: Error: Expression expected
|
||||
|
@ -33,4 +33,6 @@ inline int main(void) /* Error */
|
||||
f2b(); /* Still imported */
|
||||
}
|
||||
|
||||
inline int main(void); /* Error */
|
||||
|
||||
/* Warning: non-external inline functions declared but undefined in TU */
|
||||
|
@ -13,8 +13,9 @@ inline-error.c:22: Error: 'inline' on non-function declaration
|
||||
inline-error.c:23: Error: 'inline' on non-function declaration
|
||||
inline-error.c:24: Error: 'inline' on non-function declaration
|
||||
inline-error.c:34: Warning: Variable 'fp2' is defined but never used
|
||||
inline-error.c:37: Warning: Inline function 'f1a' used but never defined
|
||||
inline-error.c:37: Warning: Inline function 'f1b' used but never defined
|
||||
inline-error.c:37: Warning: Static function 'f1c' used but never defined
|
||||
inline-error.c:37: Warning: Inline function 'f2a' used but never defined
|
||||
inline-error.c:37: Warning: Inline function 'f2b' used but never defined
|
||||
inline-error.c:36: Error: 'main' cannot be declared inline
|
||||
inline-error.c:39: Warning: Inline function 'f1a' used but never defined
|
||||
inline-error.c:39: Warning: Inline function 'f1b' used but never defined
|
||||
inline-error.c:39: Warning: Static function 'f1c' used but never defined
|
||||
inline-error.c:39: Warning: Inline function 'f2a' used but never defined
|
||||
inline-error.c:39: Warning: Inline function 'f2b' used but never defined
|
||||
|
Loading…
Reference in New Issue
Block a user