From 79214530e01e751773da6627142e40f0d5a6d5c6 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 27 Nov 2023 20:39:15 +0800 Subject: [PATCH 1/4] Maximum total count of errors before the compiler unconditionally bails out is now 200. If more than 20 errors occur on the same source line, the compiler will immediately bail out. --- src/cc65/error.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cc65/error.c b/src/cc65/error.c index 39b0678250..2ad7133ed5 100644 --- a/src/cc65/error.c +++ b/src/cc65/error.c @@ -61,6 +61,8 @@ /* Count of errors/warnings */ unsigned ErrorCount = 0; unsigned WarningCount = 0; +unsigned RecentLineNo = 0; +unsigned RecentErrorCount = 0; /* Warning and error options */ IntStack WarnEnable = INTSTACK(1); /* Enable warnings */ @@ -205,8 +207,16 @@ static void IntError (const char* Filename, unsigned LineNo, const char* Msg, va if (Line) { Print (stderr, 1, "Input: %.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } + ++ErrorCount; - if (ErrorCount > 20) { + if (RecentLineNo != LineNo) { + RecentLineNo = LineNo; + RecentErrorCount = 0; + } else { + ++RecentErrorCount; + } + + if (RecentErrorCount > 20 || ErrorCount > 200) { Fatal ("Too many errors"); } } From ac04394254be9bc7d0ec58c572d5d07c6e808792 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 27 Nov 2023 20:39:15 +0800 Subject: [PATCH 2/4] Fixed and improved diagnostics about declaration errors. --- src/cc65/declare.c | 108 +++++++++++++++++++++++++++------------------ src/cc65/declare.h | 23 ++++++++-- 2 files changed, 84 insertions(+), 47 deletions(-) diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 4bfd52c5ed..1d60053e9e 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1766,7 +1766,7 @@ static void ParseAnsiParamList (FuncDesc* F) /* Allow parameters without a name, but remember if we had some to ** eventually print an error message later. */ - ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); + ParseDecl (&Spec, &Decl, DM_ACCEPT_PARAM_IDENT); if (Decl.Ident[0] == '\0') { /* Unnamed symbol. Generate a name that is not user accessible, @@ -1886,7 +1886,7 @@ static FuncDesc* ParseFuncDecl (void) -static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) +static declmode_t DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) /* Recursively process direct declarators. Build a type array in reverse order. */ { /* Read optional function or pointer qualifiers that modify the identifier @@ -1903,61 +1903,49 @@ static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) /* Skip the star */ NextToken (); + /* A pointer type cannot be used as an empty declaration */ + if (Mode == DM_ACCEPT_IDENT) { + Mode = DM_NEED_IDENT; + } + /* Allow const, restrict, and volatile qualifiers */ Qualifiers |= OptionalQualifiers (Qualifiers, T_QUAL_CVR); /* Parse the type that the pointer points to */ - DirectDecl (Spec, D, Mode); + Mode = DirectDecl (Spec, D, Mode); /* Add the type */ AddTypeCodeToDeclarator (D, T_PTR | Qualifiers); - return; + return Mode; } if (CurTok.Tok == TOK_LPAREN) { NextToken (); - DirectDecl (Spec, D, Mode); + /* An empty declaration cannot contain parentheses where an identifier + ** would show up if it were a non-empty declaration. + */ + if (Mode == DM_ACCEPT_IDENT) { + Mode = DM_NEED_IDENT; + } + Mode = DirectDecl (Spec, D, Mode); ConsumeRParen (); + } else if (CurTok.Tok == TOK_IDENT) { + strcpy (D->Ident, CurTok.Ident); + NextToken (); } else { - /* Things depend on Mode now: - ** - Mode == DM_NEED_IDENT means: - ** we *must* have a type and a variable identifer. - ** - Mode == DM_NO_IDENT means: - ** we must have a type but no variable identifer - ** (if there is one, it's not read). - ** - Mode == DM_ACCEPT_IDENT means: - ** we *may* have an identifier. If there is an identifier, - ** it is read, but it is no error, if there is none. - */ - if (Mode == DM_NO_IDENT) { - D->Ident[0] = '\0'; - } else if (CurTok.Tok == TOK_IDENT) { - strcpy (D->Ident, CurTok.Ident); - NextToken (); - } else { - if (Mode == DM_NEED_IDENT) { - /* Some fix point tokens that are used for error recovery */ - static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY }; - - Error ("Identifier expected"); - - /* Try some smart error recovery */ - SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0])); - - /* Skip curly braces */ - if (CurTok.Tok == TOK_LCURLY) { - static const token_t CurlyToken[] = { TOK_RCURLY }; - SkipTokens (CurlyToken, sizeof(CurlyToken) / sizeof(CurlyToken[0])); - NextToken (); - } else if (CurTok.Tok == TOK_RCURLY) { - NextToken (); - } - } - D->Ident[0] = '\0'; + D->Ident[0] = '\0'; + if (Mode == DM_NEED_IDENT) { + Error ("Identifier expected"); } } while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) { + /* An array or function type cannot be used as an empty declaration */ + if (Mode == DM_ACCEPT_IDENT && D->Ident[0] == '\0') { + Mode = DM_NEED_IDENT; + Error ("Identifier expected"); + } + if (CurTok.Tok == TOK_LPAREN) { /* Function declarator */ @@ -2043,6 +2031,8 @@ static void DirectDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) if (Qualifiers & T_QUAL_CDECL) { Error ("Invalid '__cdecl__' qualifier"); } + + return Mode; } @@ -2154,12 +2144,44 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) } if (PrevErrorCount != ErrorCount) { - /* Make the declaration fictitious if is is not parsed correctly */ - D->StorageClass |= SC_FICTITIOUS; + /* Some fix point tokens that are used for error recovery */ + static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY }; + + /* Try some smart error recovery */ + SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0])); + + /* Skip curly braces */ + if (CurTok.Tok == TOK_LCURLY) { + static const token_t CurlyToken[] = { TOK_RCURLY }; + SkipTokens (CurlyToken, sizeof (CurlyToken) / sizeof (CurlyToken[0])); + NextToken (); + } else if (CurTok.Tok == TOK_RCURLY) { + NextToken (); + } if (Mode == DM_NEED_IDENT && D->Ident[0] == '\0') { + /* Make the declaration fictitious if is is not parsed correctly */ + D->StorageClass |= SC_FICTITIOUS; + /* Use a fictitious name for the identifier if it is missing */ - AnonName (D->Ident, "global"); + const char* Level = ""; + + switch (GetLexicalLevel ()) { + case LEX_LEVEL_GLOBAL: + Level = "global"; + break; + case LEX_LEVEL_FUNCTION: + case LEX_LEVEL_BLOCK: + Level = "local"; + break; + case LEX_LEVEL_STRUCT: + Level = "field"; + break; + default: + Level = "unknown"; + break; + } + AnonName (D->Ident, Level); } } } diff --git a/src/cc65/declare.h b/src/cc65/declare.h index 89d7be7eaf..ca1b88165f 100644 --- a/src/cc65/declare.h +++ b/src/cc65/declare.h @@ -98,11 +98,26 @@ struct Declarator { unsigned Index; /* Used to build Type */ }; -/* Modes for ParseDecl */ +/* Modes for ParseDecl: +** - DM_NEED_IDENT means: +** we *must* have a type and a variable identifer. +** - DM_NO_IDENT means: +** we must have a type but no variable identifer +** (if there is one, it's not read). +** - DM_ACCEPT_IDENT means: +** we *may* have an identifier, or none. If it is the latter case, +** the type must be used as an empty declaration, or it is an error. +** Note: this is used for struct/union members. +** - DM_IGNORE_IDENT means: +** we *may* have an identifier. If there is an identifier, +** it is read, but it is no error, if there is none. +** Note: this is used for function parameter type lists. +*/ typedef enum { - DM_NEED_IDENT, /* We must have an identifier */ - DM_NO_IDENT, /* We won't read an identifier */ - DM_ACCEPT_IDENT, /* We will accept an id if there is one */ + DM_NEED_IDENT, + DM_NO_IDENT, + DM_ACCEPT_IDENT, + DM_ACCEPT_PARAM_IDENT, } declmode_t; From 7574e36e95324afa8f50559838227d9660c2afae Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 27 Nov 2023 20:39:15 +0800 Subject: [PATCH 3/4] Improved error recovery with function declarations. Fixed some rare cases when a single file-scope error could get reapeated endlessly until the maximum total count of errors allowed is reached. --- src/cc65/compile.c | 32 ++++- src/cc65/declare.c | 160 +++++++++++++++++++---- src/cc65/declare.h | 12 +- test/ref/bug1889-missing-identifier.cref | 2 - 4 files changed, 170 insertions(+), 36 deletions(-) diff --git a/src/cc65/compile.c b/src/cc65/compile.c index a591a60b8c..02d37c53e3 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -94,6 +94,8 @@ static void Parse (void) while (CurTok.Tok != TOK_CEOF) { DeclSpec Spec; + int NeedClean = 0; + unsigned PrevErrorCount = ErrorCount; /* Check for empty statements */ if (CurTok.Tok == TOK_SEMI) { @@ -144,7 +146,11 @@ static void Parse (void) Declarator Decl; /* Read the next declaration */ - ParseDecl (&Spec, &Decl, DM_NEED_IDENT); + NeedClean = ParseDecl (&Spec, &Decl, DM_NEED_IDENT); + if (Decl.Ident[0] == '\0') { + Sym = 0; + goto NextDecl; + } /* Check if we must reserve storage for the variable. We do this, ** @@ -310,6 +316,7 @@ static void Parse (void) } +NextDecl: /* Check for end of declaration list */ if (CurTok.Tok == TOK_COMMA) { NextToken (); @@ -325,6 +332,7 @@ static void Parse (void) /* Function */ if (CurTok.Tok == TOK_SEMI) { /* Prototype only */ + NeedClean = 0; NextToken (); } else if (CurTok.Tok == TOK_LCURLY) { /* ISO C: The type category in a function definition cannot be @@ -337,6 +345,7 @@ static void Parse (void) } /* Parse the function body anyways */ + NeedClean = 0; NewFunc (Sym, FuncDef); /* Make sure we aren't omitting any work */ @@ -345,10 +354,27 @@ static void Parse (void) } else { - /* Must be followed by a semicolon */ - ConsumeSemi (); + if (Sym) { + /* Must be followed by a semicolon */ + if (CurTok.Tok != TOK_SEMI) { + NeedClean = -1; + } + ConsumeSemi (); + } } + + /* Try some smart error recovery */ + if (PrevErrorCount != ErrorCount && NeedClean < 0) { + /* Some fix point tokens that are used for error recovery */ + static const token_t TokenList[] = { TOK_SEMI, TOK_RCURLY }; + + SmartErrorSkip (); + SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0])); + if (CurTok.Tok == TOK_SEMI || CurTok.Tok == TOK_RCURLY) { + NextToken (); + } + } } /* Done with deferred operations */ diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 1d60053e9e..31a0df2c35 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -83,6 +83,104 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp +static void OpenBrace (Collection* C, token_t Tok) +/* Consume an opening parenthesis/bracket/curly brace and remember that */ +{ + switch (Tok) { + case TOK_LPAREN: Tok = TOK_RPAREN; break; + case TOK_LBRACK: Tok = TOK_RBRACK; break; + case TOK_LCURLY: Tok = TOK_RCURLY; break; + default: Internal ("Unexpected opening token: %02X", (unsigned)Tok); + } + CollAppend (C, (void*)Tok); + NextToken (); +} + + + +static int CloseBrace (Collection* C, token_t Tok) +/* Consume a closing parenthesis/bracket/curly brace if it is matched with an +** opening one and return 0, or bail out and return -1 if it is not matched. +*/ +{ + if (CollCount (C) > 0) { + token_t LastTok = (token_t)CollLast (C); + if (LastTok == Tok) { + CollPop (C); + NextToken (); + return 0; + } + } + + return -1; +} + + + +int SmartErrorSkip (void) +/* Try some smart error recovery. Skip tokens until either a comma or semicolon +** that is not enclosed in an open parenthesis/bracket/curly brace, or until an +** unpaired right parenthesis/bracket/curly brace is reached. Return 0 if it is +** the former case, or -1 if it is the latter case. */ +{ + Collection C = AUTO_COLLECTION_INITIALIZER; + int Res = 0; + + /* Some fix point tokens that are used for error recovery */ + static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, + TOK_LPAREN, TOK_RPAREN, TOK_LBRACK, TOK_RBRACK, TOK_LCURLY, TOK_RCURLY }; + + while (CurTok.Tok != TOK_CEOF) { + SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0])); + + switch (CurTok.Tok) { + case TOK_LPAREN: + case TOK_LBRACK: + case TOK_LCURLY: + OpenBrace (&C, CurTok.Tok); + break; + + case TOK_RPAREN: + case TOK_RBRACK: + if (CloseBrace (&C, CurTok.Tok)) { + Res = -1; + goto ExitPoint; + } + break; + + case TOK_RCURLY: + if (CloseBrace (&C, CurTok.Tok)) { + Res = -1; + goto ExitPoint; + } else if (CollCount (&C) == 0) { + goto ExitPoint; + } + break; + + case TOK_COMMA: + if (CollCount (&C) == 0) { + goto ExitPoint; + } + NextToken (); + break; + + case TOK_SEMI: + case TOK_CEOF: + Res = -1; + goto ExitPoint; + + default: + Internal ("Unexpected token: %02X", (unsigned)CurTok.Tok); + } + } + +ExitPoint: + DoneCollection (&C); + return Res; +} + + + static unsigned ParseOneStorageClass (void) /* Parse and return a storage class specifier */ { @@ -1537,6 +1635,12 @@ static void ParseTypeSpec (DeclSpec* Spec, typespec_t TSFlags, int* SignednessSp *SignednessSpecified = 1; } break; + } else if ((TSFlags & TS_MASK_DEFAULT_TYPE) == TS_DEFAULT_TYPE_NONE) { + /* Treat this identifier as an unknown type */ + Error ("Unknown type name '%s'", CurTok.Ident); + TypeCopy (Spec->Type, type_int); + NextToken (); + break; } } else { /* This is a label. Use the default type flag to end the loop @@ -1618,14 +1722,13 @@ static void ParseOldStyleParamList (FuncDesc* F) NextToken (); } else { - /* Some fix point tokens that are used for error recovery */ - static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI }; - /* Not a parameter name */ Error ("Identifier expected for parameter name"); /* Try some smart error recovery */ - SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0])); + if (SmartErrorSkip () < 0) { + break; + } } /* Check for more parameters */ @@ -1711,12 +1814,9 @@ static void ParseOldStyleParamList (FuncDesc* F) ConsumeSemi (); } - if (PrevErrorCount != ErrorCount) { - /* Some fix point tokens that are used for error recovery */ - static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI }; - + if (PrevErrorCount != ErrorCount && CurTok.Tok != TOK_LCURLY) { /* Try some smart error recovery */ - SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0])); + SmartErrorSkip (); } } @@ -1731,6 +1831,7 @@ static void ParseAnsiParamList (FuncDesc* F) DeclSpec Spec; Declarator Decl; SymEntry* Param; + unsigned PrevErrorCount = ErrorCount; /* Allow an ellipsis as last parameter */ if (CurTok.Tok == TOK_ELLIPSIS) { @@ -1798,6 +1899,13 @@ static void ParseAnsiParamList (FuncDesc* F) /* Count arguments */ ++F->ParamCount; + if (PrevErrorCount != ErrorCount) { + /* Try some smart error recovery */ + if (SmartErrorSkip () < 0) { + break; + } + } + /* Check for more parameters */ if (CurTok.Tok == TOK_COMMA) { NextToken (); @@ -2065,8 +2173,10 @@ Type* ParseType (Type* T) -void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) -/* Parse a variable, type or function declarator */ +int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) +/* Parse a variable, type or function declarator. Return -1 if this stops at +** an unpaired right parenthesis/bracket/curly brace. +*/ { /* Used to check if we have any errors during parsing this */ unsigned PrevErrorCount = ErrorCount; @@ -2117,7 +2227,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) } /* Check a few pre-C99 things */ - if ((Spec->Flags & DS_DEF_TYPE) != 0) { + if (D->Ident[0] != '\0' && (Spec->Flags & DS_DEF_TYPE) != 0) { /* 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 @@ -2129,7 +2239,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET; } - /* For anthing that is not a function or typedef, check for an implicit + /* For anything that is not a function or typedef, check for an implicit ** int declaration. */ if ((D->StorageClass & SC_FUNC) != SC_FUNC && @@ -2144,22 +2254,7 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) } if (PrevErrorCount != ErrorCount) { - /* Some fix point tokens that are used for error recovery */ - static const token_t TokenList[] = { TOK_COMMA, TOK_SEMI, TOK_LCURLY, TOK_RCURLY }; - - /* Try some smart error recovery */ - SkipTokens (TokenList, sizeof (TokenList) / sizeof (TokenList[0])); - - /* Skip curly braces */ - if (CurTok.Tok == TOK_LCURLY) { - static const token_t CurlyToken[] = { TOK_RCURLY }; - SkipTokens (CurlyToken, sizeof (CurlyToken) / sizeof (CurlyToken[0])); - NextToken (); - } else if (CurTok.Tok == TOK_RCURLY) { - NextToken (); - } - - if (Mode == DM_NEED_IDENT && D->Ident[0] == '\0') { + if ((Spec->Flags & DS_DEF_TYPE) == 0 && Mode == DM_NEED_IDENT && D->Ident[0] == '\0') { /* Make the declaration fictitious if is is not parsed correctly */ D->StorageClass |= SC_FICTITIOUS; @@ -2183,7 +2278,14 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode) } AnonName (D->Ident, Level); } + + /* Try some smart error recovery */ + if (CurTok.Tok != TOK_LCURLY || !IsTypeFunc (D->Type)) { + return SmartErrorSkip (); + } } + + return 0; } diff --git a/src/cc65/declare.h b/src/cc65/declare.h index ca1b88165f..add86594dc 100644 --- a/src/cc65/declare.h +++ b/src/cc65/declare.h @@ -128,11 +128,19 @@ typedef enum { +int SmartErrorSkip (void); +/* Try some smart error recovery. Skip tokens until either a comma or semicolon +** that is not enclosed in an open parenthesis/bracket/curly brace, or until an +** unpaired right parenthesis/bracket/curly brace is reached. Return 0 if it is +** the former case, or -1 if it is the latter case. */ + Type* ParseType (Type* Type); /* Parse a complete type specification */ -void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode); -/* Parse a variable, type or function declarator */ +int ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode); +/* Parse a variable, type or function declarator. Return -1 if this stops at +** an unpaired right parenthesis/bracket/curly brace. +*/ void ParseDeclSpec (DeclSpec* Spec, typespec_t TSFlags, unsigned DefStorage); /* Parse a declaration specification */ diff --git a/test/ref/bug1889-missing-identifier.cref b/test/ref/bug1889-missing-identifier.cref index acaf53f945..534c6aaba8 100644 --- a/test/ref/bug1889-missing-identifier.cref +++ b/test/ref/bug1889-missing-identifier.cref @@ -1,5 +1,3 @@ bug1889-missing-identifier.c:3: Error: Identifier expected bug1889-missing-identifier.c:3: Error: ';' expected -bug1889-missing-identifier.c:3: Warning: Implicit 'int' is an obsolete feature bug1889-missing-identifier.c:4: Error: Identifier expected -bug1889-missing-identifier.c:4: Warning: Implicit 'int' is an obsolete feature From b99ebc1256ff5400e70c7df8d97a708b45b23620 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 27 Nov 2023 20:39:15 +0800 Subject: [PATCH 4/4] Fixed diagnostic messages about undeclared identifiers. --- src/cc65/asmstmt.c | 2 +- src/cc65/expr.c | 2 +- src/cc65/symtab.c | 2 +- test/ref/custom-reference-error.cref | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc65/asmstmt.c b/src/cc65/asmstmt.c index 6cb6f2ef74..166d054343 100644 --- a/src/cc65/asmstmt.c +++ b/src/cc65/asmstmt.c @@ -102,7 +102,7 @@ static SymEntry* AsmGetSym (unsigned Arg, unsigned Type) /* Did we find a symbol with this name? */ if (Sym == 0) { - Error ("Undefined symbol '%s' for argument %u", CurTok.Ident, Arg); + Error ("Undeclared symbol '%s' for argument %u", CurTok.Ident, Arg); AsmErrorSkip (); return 0; } diff --git a/src/cc65/expr.c b/src/cc65/expr.c index f7ad5affcd..6d4b048920 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1322,10 +1322,10 @@ static void Primary (ExprDesc* E) E->Name = (uintptr_t) Sym->Name; } else { /* Undeclared Variable */ + Error ("Undeclared identifier '%s'", Ident); Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0); E->Flags = E_LOC_STACK | E_RTYPE_LVAL; E->Type = type_int; - Error ("Undefined symbol: '%s'", Ident); } } diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index a7436b6b6d..ee8e0bbf83 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -1484,7 +1484,7 @@ void MakeZPSym (const char* Name) if (Entry) { Entry->Flags |= SC_ZEROPAGE; } else { - Error ("Undefined symbol: '%s'", Name); + Error ("Undeclared symbol: '%s'", Name); } } diff --git a/test/ref/custom-reference-error.cref b/test/ref/custom-reference-error.cref index fa584f307b..728cc0e15b 100644 --- a/test/ref/custom-reference-error.cref +++ b/test/ref/custom-reference-error.cref @@ -1,5 +1,5 @@ custom-reference-error.c:18: Error: Call to undeclared function 'printf' -custom-reference-error.c:19: Error: Undefined symbol: 'n' +custom-reference-error.c:19: Error: Undeclared identifier 'n' custom-reference-error.c:21: Warning: Control reaches end of non-void function [-Wreturn-type] custom-reference-error.c:21: Warning: Parameter 'argc' is never used custom-reference-error.c:21: Warning: Parameter 'argv' is never used