1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-28 06:30:16 +00:00

Fixed missing diagnosis on function parameter lists with trailing commas.

This commit is contained in:
acqn 2023-12-13 22:57:32 +08:00
parent bc97bce8c1
commit f8fe1d1560
3 changed files with 78 additions and 38 deletions

View File

@ -1740,10 +1740,12 @@ static const Type* ParamTypeCvt (Type* T)
static void ParseOldStyleParamList (FuncDesc* F) static void ParseOldStyleParamList (FuncDesc* F)
/* Parse an old-style (K&R) parameter list */ /* Parse an old-style (K&R) parameter list */
{ {
unsigned PrevErrorCount = ErrorCount; if (CurTok.Tok == TOK_RPAREN) {
return;
}
/* Parse params */ /* Parse params */
while (CurTok.Tok != TOK_RPAREN) { while (1) {
/* List of identifiers expected */ /* List of identifiers expected */
if (CurTok.Tok == TOK_IDENT) { if (CurTok.Tok == TOK_IDENT) {
@ -1768,29 +1770,33 @@ static void ParseOldStyleParamList (FuncDesc* F)
} }
/* Check for more parameters */ /* Check for more parameters */
if (CurTok.Tok == TOK_COMMA) { if (CurTok.Tok != TOK_COMMA) {
NextToken ();
} else {
break; break;
} }
NextToken ();
}
} }
/* Skip right paren. We must explicitly check for one here, since some of
** the breaks above bail out without checking.
*/ static void ParseOldStyleParamDeclList (FuncDesc* F attribute ((unused)))
ConsumeRParen (); /* 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 */ /* An optional list of type specifications follows */
while (CurTok.Tok != TOK_LCURLY) { while (CurTok.Tok != TOK_LCURLY) {
DeclSpec Spec; DeclSpec Spec;
int NeedClean;
/* Read the declaration specifier */ /* Read the declaration specifier */
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO); 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 accept only auto and register as storage class specifiers, but
** we ignore all this, since we use auto anyway. ** we ignore all this, since we use auto anyway.
*/ */
@ -1799,10 +1805,14 @@ static void ParseOldStyleParamList (FuncDesc* F)
Error ("Illegal storage class"); 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) { if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
Error ("Expected declaration specifiers"); /* Avoid extra errors if it was a failed type specifier */
break; if ((Spec.Flags & DS_EXTRA_TYPE) == 0) {
Error ("Declaration specifier expected");
}
NeedClean = -1;
goto EndOfDecl;
} }
/* Parse a comma separated variable list */ /* Parse a comma separated variable list */
@ -1811,7 +1821,12 @@ static void ParseOldStyleParamList (FuncDesc* F)
Declarator Decl; Declarator Decl;
/* Read the parameter */ /* 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 */ /* Warn about new local type declaration */
if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) { if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) {
@ -1820,9 +1835,9 @@ static void ParseOldStyleParamList (FuncDesc* F)
} }
if (Decl.Ident[0] != '\0') { if (Decl.Ident[0] != '\0') {
/* We have a name given. Search for the symbol */ /* We have a name given. Search for the symbol */
SymEntry* Param = FindLocalSym (Decl.Ident); SymEntry* Param = FindLocalSym (Decl.Ident);
if (Param) { if (Param) {
/* Check if we already changed the type for this /* Check if we already changed the type for this
** parameter. ** parameter.
@ -1837,35 +1852,54 @@ static void ParseOldStyleParamList (FuncDesc* F)
Error ("Redefinition for parameter '%s'", Param->Name); Error ("Redefinition for parameter '%s'", Param->Name);
} }
} else { } else {
Error ("Unknown identifier: '%s'", Decl.Ident); Error ("Unknown parameter '%s'", Decl.Ident);
}
} }
if (CurTok.Tok == TOK_COMMA) { /* Initialization is not allowed */
NextToken (); if (CurTok.Tok == TOK_ASSIGN) {
} else { Error ("Parameter '%s' cannot be initialized", Decl.Ident);
break;
}
}
/* Variable list must be semicolon terminated */
ConsumeSemi ();
}
if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) {
/* Try some smart error recovery */ /* Try some smart error recovery */
SmartErrorSkip (0); SmartErrorSkip (0);
} }
} }
/* Check for more declarators */
if (CurTok.Tok != TOK_COMMA) {
break;
}
NextToken ();
}
EndOfDecl:
if (NeedClean > 0) {
/* Must be followed by a semicolon */
if (ConsumeSemi ()) {
NeedClean = 0;
} else {
NeedClean = -1;
}
}
/* Try some smart error recovery */
if (NeedClean < 0) {
SmartErrorSkip (1);
}
}
}
static void ParseAnsiParamList (FuncDesc* F) static void ParseAnsiParamList (FuncDesc* F)
/* Parse a new-style (ANSI) parameter list */ /* Parse a new-style (ANSI) parameter list */
{ {
if (CurTok.Tok == TOK_RPAREN) {
return;
}
/* Parse params */ /* Parse params */
while (CurTok.Tok != TOK_RPAREN) { while (1) {
DeclSpec Spec; DeclSpec Spec;
Declarator Decl; Declarator Decl;
@ -1894,7 +1928,7 @@ static void ParseAnsiParamList (FuncDesc* F)
/* Type must be specified */ /* Type must be specified */
if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) { if ((Spec.Flags & DS_TYPE_MASK) == DS_NONE) {
Error ("Type specifier missing"); Error ("Declaration specifier or '...' expected");
} }
/* Warn about new local type declaration */ /* Warn about new local type declaration */
@ -1945,18 +1979,12 @@ static void ParseAnsiParamList (FuncDesc* F)
} }
} }
/* Check for more parameters */ /* Check for end of parameter type list */
if (CurTok.Tok == TOK_COMMA) { if (CurTok.Tok != TOK_COMMA) {
NextToken ();
} else {
break; 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) { if ((F->Flags & FD_OLDSTYLE) == 0) {
/* New-style function */ /* New-style function */
ParseAnsiParamList (F); ParseAnsiParamList (F);
ConsumeRParen ();
} else { } else {
/* Old-style function */ /* Old-style function */
ParseOldStyleParamList (F); ParseOldStyleParamList (F);
ConsumeRParen ();
ParseOldStyleParamDeclList (F);
} }
PopLexicalLevel (); PopLexicalLevel ();

View File

@ -0,0 +1,3 @@
/* Bug #2301 - Function parameter list with an extra trailing comma should not compile */
int foo(int a,); /* Should fail */

View File

@ -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;
}