Fix local extern vardecl

see testcases.  A local 'extern int i' declaration needs to
refer to the global declaration, not to a local one it might
be shadowing.  Doesn't seem to happen in the wild very often as
this was broken forever.
This commit is contained in:
Michael Matz 2019-03-18 05:53:03 +01:00
parent e6980f6cc7
commit 1fd3709379
4 changed files with 31 additions and 1 deletions

View File

@ -995,7 +995,9 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
{
Sym *s;
s = sym_find(v);
if (!s) {
if (!s || (!(s->type.t & VT_EXTERN) && (s->type.t & VT_BTYPE) != VT_FUNC)) {
if (s && !is_compatible_types(&s->type, type))
tcc_error("conflicting types for '%s'", get_tok_str(s->v, NULL));
/* push forward reference */
s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
s->type.t |= VT_EXTERN;

View File

@ -77,6 +77,7 @@ void expr_test();
void macro_test();
void recursive_macro_test();
void scope_test();
void scope_test2();
void forward_test();
void funcptr_test();
void loop_test();
@ -718,6 +719,7 @@ int main(int argc, char **argv)
macro_test();
recursive_macro_test();
scope_test();
scope_test2();
forward_test();
funcptr_test();
loop_test();
@ -800,6 +802,20 @@ void scope_test()
printf("g5=%d\n", g);
}
int st2_i;
int *st2_p = &st2_i;
void scope_test2()
{
char a[50];
st2_i = 42;
for (int st2_i = 1; st2_i < 10; st2_i++) {
extern int st2_i;
st2_i++;
printf("exloc: %d\n", st2_i);
}
printf("exloc: %d\n", *st2_p);
}
void array_test()
{
int i, j, a[4];

View File

@ -151,4 +151,13 @@ int ga = 0.42 { 2 };
struct S { int a, b; };
struct T { struct S x; };
struct T gt = { 42 a: 1, 43 };
#elif defined test_conflicting_types
int i;
void foo(void) {
int i;
{
extern double i;
i = 42.2;
}
}
#endif

View File

@ -71,3 +71,6 @@
[test_invalid_3]
60_errors_and_warnings.c:153: error: ',' expected (got "a")
[test_conflicting_types]
60_errors_and_warnings.c:159: error: conflicting types for 'i'