diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 0dc75273d..b996c78df 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -206,6 +206,14 @@ static void Parse (void) } else { /* Just a declaration */ Decl.StorageClass |= SC_DECL; + + FuncDef = GetFuncDesc (Decl.Type); + if ((FuncDef->Flags & (FD_EMPTY | FD_OLDSTYLE)) == FD_OLDSTYLE) { + /* A parameter list without types is only allowed in a + ** function definition. + */ + Error ("Parameter names without types in function declaration"); + } } } diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 2746d1326..8b7512730 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1989,7 +1989,7 @@ static void ParseAnsiParamList (FuncDesc* F) -static FuncDesc* ParseFuncDecl (void) +static void ParseFuncDecl (Declarator* D, declmode_t Mode, TypeCode Qualifiers) /* Parse the argument list of a function with the enclosing parentheses */ { /* Create a new function descriptor */ @@ -2009,14 +2009,17 @@ static FuncDesc* ParseFuncDecl (void) /* Parameter list declared as void */ NextToken (); F->Flags |= FD_VOID_PARAM; - } else if (CurTok.Tok == TOK_IDENT && + } else if (Mode != DM_NO_IDENT && + CurTok.Tok == TOK_IDENT && (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) { /* If the identifier is a typedef, we have a new-style parameter list; ** if it's some other identifier, it's an old-style parameter list. + ** Note: Non-empty Old-style (K&R) parameter list is not allowed in + ** type names. */ SymEntry* Sym = FindSym (CurTok.Ident); if (Sym == 0 || !SymIsTypeDef (Sym)) { - /* Old-style (K&R) function. */ + /* Old-style (K&R) function */ F->Flags |= FD_OLDSTYLE; } } @@ -2026,13 +2029,20 @@ static FuncDesc* ParseFuncDecl (void) if ((F->Flags & FD_OLDSTYLE) == 0) { /* New-style function */ ParseAnsiParamList (F); - ConsumeRParen (); } else { /* Old-style function */ ParseOldStyleParamList (F); - ConsumeRParen (); + } + + if (!ConsumeRParen ()) { + /* Try some smart error recovery */ + SimpleErrorSkip (); + NextToken (); + } else if (Mode == DM_IDENT_OR_EMPTY && (F->Flags & FD_OLDSTYLE) != 0) { + /* Parameter declaration list is only allowed in function definitions */ ParseOldStyleParamDeclList (F); } + PopLexicalLevel (); /* Remember the last function parameter. We need it later for several @@ -2040,18 +2050,27 @@ static FuncDesc* ParseFuncDecl (void) ** more symbols are added to the table, it is easier if we remember it ** now, since it is currently the last entry in the symbol table. */ - F->LastParam = GetSymTab()->SymTail; + F->LastParam = GetSymTab ()->SymTail; + + /* Leave the lexical level remembering the symbol tables */ + RememberFunctionLevel (F); /* It is allowed to use incomplete types in function prototypes, so we ** won't always get to know the parameter sizes here and may do that later. */ F->Flags |= FD_INCOMPLETE_PARAM; - /* Leave the lexical level remembering the symbol tables */ - RememberFunctionLevel (F); + /* We cannot specify fastcall for variadic functions */ + if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) { + Error ("Variadic functions cannot be __fastcall__"); + Qualifiers &= ~T_QUAL_FASTCALL; + } - /* Return the function descriptor */ - return F; + /* Add the function type. Be sure to bounds check the type buffer */ + NeedTypeSpace (D, 1); + D->Type[D->Index].C = T_FUNC | Qualifiers; + D->Type[D->Index].A.F = F; + ++D->Index; } @@ -2090,15 +2109,37 @@ static void DirectDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode) } if (CurTok.Tok == TOK_LPAREN) { - NextToken (); + SymEntry* Entry; + /* An empty declaration cannot contain parentheses where an identifier ** would show up if it were a non-empty declaration. */ if (Mode == DM_IDENT_OR_EMPTY) { Spec->Flags |= DS_NO_EMPTY_DECL; } - DirectDecl (Spec, D, Mode); - ConsumeRParen (); + + /* We have to disambiguate the meanings of 'type (identifier' when + ** the identifier can be a typedef'ed parameter type specifier or + ** a declarator enclosed in parentheses in some cases. + */ + if (Mode == DM_IDENT_OR_EMPTY || /* If we are in a declaration... */ + NextTok.Tok == TOK_LPAREN || /* or the next token is one more paren... */ + NextTok.Tok == TOK_STAR || /* or a '*' ... */ + (NextTok.Tok == TOK_IDENT && /* or an identifier that... */ + ((Entry = FindSym (NextTok.Ident)) == 0 || /* is not a typedef. */ + !SymIsTypeDef (Entry)))) { + /* Parse the direct declarator in parentheses */ + NextToken (); + DirectDecl (Spec, D, Mode); + ConsumeRParen (); + } else { + /* This is a parameter type list in parentheses */ + ParseFuncDecl (D, Mode, Qualifiers); + + /* Qualifiers now used */ + Qualifiers = T_QUAL_NONE; + } + } else if (CurTok.Tok == TOK_IDENT) { if (Mode == DM_NO_IDENT) { Error ("Unexpected identifier in type name"); @@ -2119,28 +2160,11 @@ static void DirectDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode) while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) { if (CurTok.Tok == TOK_LPAREN) { - /* Function declarator */ - FuncDesc* F; - - /* Parse the function declarator */ - F = ParseFuncDecl (); - - /* We cannot specify fastcall for variadic functions */ - if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) { - Error ("Variadic functions cannot be __fastcall__"); - Qualifiers &= ~T_QUAL_FASTCALL; - } - - /* Add the function type. Be sure to bounds check the type buffer */ - NeedTypeSpace (D, 1); - D->Type[D->Index].C = T_FUNC | Qualifiers; - D->Type[D->Index].A.F = F; - ++D->Index; + ParseFuncDecl (D, Mode, Qualifiers); /* Qualifiers now used */ Qualifiers = T_QUAL_NONE; - } else { /* Array declarator */ long Size = UNSPECIFIED; @@ -2385,9 +2409,11 @@ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode) } /* Try some smart error recovery */ - if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) { + if (Mode == DM_NO_IDENT) { + return SimpleErrorSkip (); + } else if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) { /* Skip to the end of the whole declaration if it is not part of a - ** parameter list or a type cast. + ** parameter list. */ return SmartErrorSkip (Mode == DM_IDENT_OR_EMPTY); } diff --git a/test/err/bug2303.c b/test/err/bug2303.c new file mode 100644 index 000000000..609725ad8 --- /dev/null +++ b/test/err/bug2303.c @@ -0,0 +1 @@ +int f(a); /* Should be an error */ diff --git a/test/val/bug2302.c b/test/val/bug2302.c new file mode 100644 index 000000000..3ca8a5572 --- /dev/null +++ b/test/val/bug2302.c @@ -0,0 +1,32 @@ +/* Bug #2302 - Parameters of function types not parsed correctly */ + +#include + +typedef int A; +int zoo(A ()); /* OK: int zoo(int (*)()) */ +int zoo(A (())); /* OK: int zoo(int ((*)())) aka. int zoo(int (*)()) */ +int zoo(A (A)); /* OK: int zoo(int (*)(int)) */ +int zoo(A ((A))); /* OK: int zoo(int ((*)(int))) aka. int zoo(int (*)(int)) */ +int zoo(A A(A)); /* OK: int zoo(int (*A)(int)) */ +int zoo(A (*)(A)); /* OK: int zoo(int (*)(int)) */ +int zoo(A (*A)(A)); /* OK: int zoo(int (*A)(int)) */ +int zoo(A ((*A))(A)); /* OK: int zoo(int (*A)(int)) */ +int zoo(A ((((*((fp))))(A A)))) /* OK: int zoo(int (*fp)(int A)) */ +{ + return fp(42); +} + +int bar(int a) +{ + return a ^ 42; +} + +int main(void) +{ + int a = zoo((int (*)())bar); + if (a != 0) + { + printf("failed: a = %d\n", a); + } + return a; +}