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.
Unified · Split
| @@ -995,7 +995,9 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) · 994 unmodified lines | ||
| 995 | 995 | { |
| 996 | 996 | Sym *s; |
| 997 | 997 | s = sym_find(v); |
| 998 | − if (!s) { | |
| 998 | + if (!s || (!(s->type.t & VT_EXTERN) && (s->type.t & VT_BTYPE) != VT_FUNC)) { | |
| 999 | + if (s && !is_compatible_types(&s->type, type)) | |
| 1000 | + tcc_error("conflicting types for '%s'", get_tok_str(s->v, NULL)); | |
| 999 | 1001 | /* push forward reference */ |
| 1000 | 1002 | s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
| 1001 | 1003 | s->type.t |= VT_EXTERN; |
| @@ -77,6 +77,7 @@ void expr_test(); · 76 unmodified lines | ||
| 77 | 77 | void macro_test(); |
| 78 | 78 | void recursive_macro_test(); |
| 79 | 79 | void scope_test(); |
| 80 | +void scope_test2(); | |
| 80 | 81 | void forward_test(); |
| 81 | 82 | void funcptr_test(); |
| 82 | 83 | void loop_test(); |
| @@ -718,6 +719,7 @@ int main(int argc, char **argv) · 635 unmodified lines | ||
| 718 | 719 | macro_test(); |
| 719 | 720 | recursive_macro_test(); |
| 720 | 721 | scope_test(); |
| 722 | + scope_test2(); | |
| 721 | 723 | forward_test(); |
| 722 | 724 | funcptr_test(); |
| 723 | 725 | loop_test(); |
| @@ -800,6 +802,20 @@ void scope_test() · 76 unmodified lines | ||
| 800 | 802 | printf("g5=%d\n", g); |
| 801 | 803 | } |
| 802 | 804 | |
| 805 | +int st2_i; | |
| 806 | +int *st2_p = &st2_i; | |
| 807 | +void scope_test2() | |
| 808 | +{ | |
| 809 | + char a[50]; | |
| 810 | + st2_i = 42; | |
| 811 | + for (int st2_i = 1; st2_i < 10; st2_i++) { | |
| 812 | + extern int st2_i; | |
| 813 | + st2_i++; | |
| 814 | + printf("exloc: %d\n", st2_i); | |
| 815 | + } | |
| 816 | + printf("exloc: %d\n", *st2_p); | |
| 817 | +} | |
| 818 | + | |
| 803 | 819 | void array_test() |
| 804 | 820 | { |
| 805 | 821 | int i, j, a[4]; |
| @@ -151,4 +151,13 @@ int ga = 0.42 { 2 }; · 150 unmodified lines | ||
| 151 | 151 | struct S { int a, b; }; |
| 152 | 152 | struct T { struct S x; }; |
| 153 | 153 | struct T gt = { 42 a: 1, 43 }; |
| 154 | +#elif defined test_conflicting_types | |
| 155 | +int i; | |
| 156 | +void foo(void) { | |
| 157 | + int i; | |
| 158 | + { | |
| 159 | + extern double i; | |
| 160 | + i = 42.2; | |
| 161 | + } | |
| 162 | +} | |
| 154 | 163 | #endif |
| @@ -71,3 +71,6 @@ · 70 unmodified lines | ||
| 71 | 71 | |
| 72 | 72 | [test_invalid_3] |
| 73 | 73 | 60_errors_and_warnings.c:153: error: ',' expected (got "a") |
| 74 | + | |
| 75 | +[test_conflicting_types] | |
| 76 | +60_errors_and_warnings.c:159: error: conflicting types for 'i' | |