diff --git a/src/cc65/declare.c b/src/cc65/declare.c index eee6dff9f..2746d1326 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1740,10 +1740,12 @@ static const Type* ParamTypeCvt (Type* T) static void ParseOldStyleParamList (FuncDesc* F) /* Parse an old-style (K&R) parameter list */ { - unsigned PrevErrorCount = ErrorCount; + if (CurTok.Tok == TOK_RPAREN) { + return; + } /* Parse params */ - while (CurTok.Tok != TOK_RPAREN) { + while (1) { /* List of identifiers expected */ if (CurTok.Tok == TOK_IDENT) { @@ -1768,29 +1770,33 @@ static void ParseOldStyleParamList (FuncDesc* F) } /* Check for more parameters */ - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { + if (CurTok.Tok != TOK_COMMA) { break; } - } + NextToken (); - /* Skip right paren. We must explicitly check for one here, since some of - ** the breaks above bail out without checking. - */ - ConsumeRParen (); + } +} + + + +static void ParseOldStyleParamDeclList (FuncDesc* F attribute ((unused))) +/* Parse an old-style (K&R) function declarator declaration list */ +{ + if (CurTok.Tok == TOK_SEMI) { + /* No parameter declaration list */ + return; + } /* An optional list of type specifications follows */ while (CurTok.Tok != TOK_LCURLY) { DeclSpec Spec; + int NeedClean; /* Read the declaration specifier */ ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO); - /* Paremeters must have identifiers as names */ - Spec.Flags |= DS_NO_EMPTY_DECL; - /* We accept only auto and register as storage class specifiers, but ** we ignore all this, since we use auto anyway. */ @@ -1799,10 +1805,14 @@ static void ParseOldStyleParamList (FuncDesc* F) Error ("Illegal storage class"); } - /* Type must be specified */ + /* If we haven't got a type specifier yet, something must be wrong */ if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) { - Error ("Expected declaration specifiers"); - break; + /* Avoid extra errors if it was a failed type specifier */ + if ((Spec.Flags & DS_EXTRA_TYPE) == 0) { + Error ("Declaration specifier expected"); + } + NeedClean = -1; + goto EndOfDecl; } /* Parse a comma separated variable list */ @@ -1811,7 +1821,12 @@ static void ParseOldStyleParamList (FuncDesc* F) Declarator Decl; /* Read the parameter */ - ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY); + NeedClean = ParseDecl (&Spec, &Decl, DM_IDENT_OR_EMPTY); + + /* Bail out if there are errors */ + if (NeedClean <= 0) { + break; + } /* Warn about new local type declaration */ if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) { @@ -1820,9 +1835,9 @@ static void ParseOldStyleParamList (FuncDesc* F) } if (Decl.Ident[0] != '\0') { - /* We have a name given. Search for the symbol */ SymEntry* Param = FindLocalSym (Decl.Ident); + if (Param) { /* Check if we already changed the type for this ** parameter. @@ -1837,25 +1852,40 @@ static void ParseOldStyleParamList (FuncDesc* F) Error ("Redefinition for parameter '%s'", Param->Name); } } else { - Error ("Unknown identifier: '%s'", Decl.Ident); + Error ("Unknown parameter '%s'", Decl.Ident); + } + + /* Initialization is not allowed */ + if (CurTok.Tok == TOK_ASSIGN) { + Error ("Parameter '%s' cannot be initialized", Decl.Ident); + + /* Try some smart error recovery */ + SmartErrorSkip (0); } } - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { + /* Check for more declarators */ + if (CurTok.Tok != TOK_COMMA) { break; } + NextToken (); } - /* Variable list must be semicolon terminated */ - ConsumeSemi (); - } +EndOfDecl: + if (NeedClean > 0) { + /* Must be followed by a semicolon */ + if (ConsumeSemi ()) { + NeedClean = 0; + } else { + NeedClean = -1; + } + } - if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) { /* Try some smart error recovery */ - SmartErrorSkip (0); + if (NeedClean < 0) { + SmartErrorSkip (1); + } } } @@ -1864,8 +1894,12 @@ static void ParseOldStyleParamList (FuncDesc* F) static void ParseAnsiParamList (FuncDesc* F) /* Parse a new-style (ANSI) parameter list */ { + if (CurTok.Tok == TOK_RPAREN) { + return; + } + /* Parse params */ - while (CurTok.Tok != TOK_RPAREN) { + while (1) { DeclSpec Spec; Declarator Decl; @@ -1894,7 +1928,7 @@ static void ParseAnsiParamList (FuncDesc* F) /* Type must be specified */ if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) { - Error ("Type specifier missing"); + Error ("Declaration specifier or '...' expected"); } /* Warn about new local type declaration */ @@ -1945,18 +1979,12 @@ static void ParseAnsiParamList (FuncDesc* F) } } - /* Check for more parameters */ - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - } else { + /* Check for end of parameter type list */ + if (CurTok.Tok != TOK_COMMA) { break; } + NextToken (); } - - /* Skip right paren. We must explicitly check for one here, since some of - ** the breaks above bail out without checking. - */ - ConsumeRParen (); } @@ -1998,9 +2026,12 @@ static FuncDesc* ParseFuncDecl (void) if ((F->Flags & FD_OLDSTYLE) == 0) { /* New-style function */ ParseAnsiParamList (F); + ConsumeRParen (); } else { /* Old-style function */ ParseOldStyleParamList (F); + ConsumeRParen (); + ParseOldStyleParamDeclList (F); } PopLexicalLevel (); diff --git a/test/err/bug2301-trailing-coma-1.c b/test/err/bug2301-trailing-coma-1.c new file mode 100644 index 000000000..66cd4fae3 --- /dev/null +++ b/test/err/bug2301-trailing-coma-1.c @@ -0,0 +1,3 @@ +/* Bug #2301 - Function parameter list with an extra trailing comma should not compile */ + +int foo(int a,); /* Should fail */ diff --git a/test/err/bug2301-trailing-coma-2.c b/test/err/bug2301-trailing-coma-2.c new file mode 100644 index 000000000..40ca3d0ca --- /dev/null +++ b/test/err/bug2301-trailing-coma-2.c @@ -0,0 +1,6 @@ +/* Bug #2301 - Function parameter list with an extra trailing comma should not compile */ + +int bar(a,) int a; /* Should fail */ +{ + return a; +}