Fixed visibility of undeclared functions and objects.

This commit is contained in:
acqn 2024-01-13 00:46:14 +08:00
parent a173428fab
commit 3d0dc58153
6 changed files with 78 additions and 21 deletions

View File

@ -163,19 +163,19 @@ static void Parse (void)
break;
}
/* Check if we must reserve storage for the variable. We do this,
**
** - if it is not a typedef or function,
** - if we don't had a storage class given ("int i")
** - if the storage class is explicitly specified as static,
** - or if there is an initialization.
**
** This means that "extern int i;" will not get storage allocated
** in this translation unit.
*/
/* The symbol is now visible in the file scope */
if ((Decl.StorageClass & SC_TYPEMASK) != SC_FUNC &&
(Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
/* The variable is visible in the file scope */
/* Check if we must reserve storage for the variable. We do this,
**
** - if it is not a typedef or function,
** - if we don't had a storage class given ("int i")
** - if the storage class is explicitly specified as static,
** - or if there is an initialization.
**
** This means that "extern int i;" will not get storage allocated
** in this translation unit.
*/
if ((Decl.StorageClass & SC_STORAGEMASK) == SC_NONE ||
(Decl.StorageClass & SC_STORAGEMASK) == SC_STATIC ||
((Decl.StorageClass & SC_STORAGEMASK) == SC_EXTERN &&
@ -189,7 +189,6 @@ static void Parse (void)
** or semicolon, it must be followed by a function body.
*/
if ((Decl.StorageClass & SC_TYPEMASK) == SC_FUNC) {
/* The function is now visible in the file scope */
if (CurTok.Tok == TOK_LCURLY) {
/* A definition */
Decl.StorageClass |= SC_DEF;

View File

@ -557,8 +557,10 @@ static SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned H
static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
/* Find the symbol with the given name in the table tree that starts with T */
static SymEntry* FindVisibleSymInTree (const SymTable* Tab, const char* Name)
/* Find the visible symbol with the given name in the table tree that starts
** with Tab.
*/
{
/* Get the hash over the name */
unsigned Hash = HashStr (Name);
@ -574,7 +576,7 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
}
/* Bail out if we found it */
if (E != 0) {
if (E != 0 && (Tab != SymTab0 || (E->Flags & SC_LOCALSCOPE) == 0)) {
return E;
}
@ -589,9 +591,9 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
SymEntry* FindSym (const char* Name)
/* Find the symbol with the given name */
/* Find with the given name the symbol visible in the current scope */
{
return FindSymInTree (SymTab, Name);
return FindVisibleSymInTree (SymTab, Name);
}
@ -613,9 +615,9 @@ SymEntry* FindLocalSym (const char* Name)
SymEntry* FindTagSym (const char* Name)
/* Find the symbol with the given name in the tag table */
/* Find with the given name the tag symbol visible in the current scope */
{
return FindSymInTree (TagTab, Name);
return FindVisibleSymInTree (TagTab, Name);
}
@ -1356,6 +1358,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
Name);
Entry = 0;
} else if ((Flags & SC_TYPEMASK) != SC_TYPEDEF) {
/* If we are adding the symbol in the file scope, it is now
** visible there.
*/
if (SymTab == SymTab0) {
Entry->Flags &= ~SC_LOCALSCOPE;
}
/* The C standard specifies that the result is undefined if the
** same thing has both internal and external linkage. Most
** compilers choose to either give an error at compile time, or
@ -1415,6 +1424,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
}
if (Entry == 0) {
/* Hide the symbol in the file scope if we are declaring it in a
** local scope.
*/
if (Tab == SymTab0 && SymTab != SymTab0) {
Flags |= SC_LOCALSCOPE;
}
/* Create a new entry */
Entry = NewSymEntry (Name, Flags);

View File

@ -142,7 +142,7 @@ void LeaveStructLevel (void);
SymEntry* FindSym (const char* Name);
/* Find the symbol with the given name */
/* Find with the given name the symbol visible in the current scope */
SymEntry* FindGlobalSym (const char* Name);
/* Find the symbol with the given name in the global symbol table only */
@ -151,7 +151,7 @@ SymEntry* FindLocalSym (const char* Name);
/* Find the symbol with the given name in the current symbol table only */
SymEntry* FindTagSym (const char* Name);
/* Find the symbol with the given name in the tag table */
/* Find with the given name the tag symbol visible in the current scope */
SymEntry FindStructField (const Type* TypeArray, const char* Name);
/* Find a struct/union field in the fields list.

View File

@ -0,0 +1,15 @@
/* Bug 2304 - Visibility of objects/functions undeclared in file scope but 'extern'-declared in unrelated block scopes */
void f1(void)
{
extern int a;
}
/* 'a' is still invisible in the file scope */
int main(void)
{
return a * 0; /* Usage of 'a' should be an error */
}
int a = 42;

View File

@ -133,6 +133,12 @@ $(WORKDIR)/goto.$1.$2.prg: goto.c $(ISEQUAL) | $(WORKDIR)
$(CC65) -t sim$2 -$1 -o $$@ $$< 2>$(WORKDIR)/goto.$1.$2.out
$(ISEQUAL) $(WORKDIR)/goto.$1.$2.out goto.ref
# this one requires failure with --std=c89, it fails with --std=cc65 due to
# stricter checks
$(WORKDIR)/bug2304-implicit-func.$1.$2.prg: bug2304-implicit-func.c | $(WORKDIR)
$(if $(QUIET),echo misc/bug2304-implicit-func.$1.$2.prg)
$(NOT) $(CC65) --standard c89 -t sim$2 -$1 -o $$@ $$< $(NULLERR)
# should not compile until 3-byte struct by value tests are re-enabled
$(WORKDIR)/struct-by-value.$1.$2.prg: struct-by-value.c | $(WORKDIR)
$(if $(QUIET),echo misc/struct-by-value.$1.$2.prg)

View File

@ -0,0 +1,21 @@
/* Bug 2304 - Visibility of objects/functions undeclared in file scope but 'extern'-declared in unrelated block scopes */
/* This one should fail even in C89 */
void f1(void)
{
extern unsigned int f();
}
/* 'f' is still invisible in the file scope */
int main(void)
{
f(); /* Should be a conflict since the implicit function type is incompatible */
return 0;
}
unsigned int f()
{
return 42;
}