mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-28 04:00:06 +08:00
605538f46d
Sym.sym_scope and Sym.f (FuncAttr) share space, so blindly setting one clobbers the other. Right now this only leads to missing errors on incompatible typedefs (see testcase), which this commit fixes. But it points to a larger problem: Generally we can only manipulate Sym.f for anonymous and field symbols, not for anything that has a top-level name (basically any proper decl), because the latter use sym_scope. Luckily the functions type always contains an anonymous symbol (in sym->type.ref), so we can use that. But some of the functions attributes actually _do_ apply to the decl, not the type (e.g. always_inline), so we still have a problem possibly, when we update an pre-existing type that may already be shared with another decl. Would need untangling and perhaps using accessor functions that check that Sym.f and Sym.sym_scope aren't used for the same symbol.
467 lines
9.3 KiB
C
467 lines
9.3 KiB
C
#if defined test_56_btype_excess_1
|
|
struct A {} int i;
|
|
|
|
#elif defined test_57_btype_excess_2
|
|
char int i;
|
|
|
|
#elif defined test_58_function_redefinition
|
|
int f(void) { return 0; }
|
|
int f(void) { return 1; }
|
|
|
|
#elif defined test_global_redefinition
|
|
int xxx = 1;
|
|
int xxx;
|
|
int xxx = 2;
|
|
|
|
#elif defined test_59_function_array
|
|
int (*fct)[42](int x);
|
|
|
|
#elif defined test_60_enum_redefinition
|
|
enum color { RED, GREEN, BLUE };
|
|
enum color { R, G, B };
|
|
enum color c;
|
|
|
|
#elif defined test_62_enumerator_redefinition
|
|
enum color { RED, GREEN, BLUE };
|
|
enum rgb { RED, G, B};
|
|
enum color c = RED;
|
|
|
|
#elif defined test_63_local_enumerator_redefinition
|
|
enum {
|
|
FOO,
|
|
BAR
|
|
};
|
|
|
|
int main(void)
|
|
{
|
|
enum {
|
|
FOO = 2,
|
|
BAR
|
|
};
|
|
|
|
return BAR - FOO;
|
|
}
|
|
|
|
#elif defined test_61_undefined_enum
|
|
enum rgb3 c = 42;
|
|
|
|
#elif defined test_74_non_const_init
|
|
int i = i++;
|
|
|
|
#elif defined test_pointer_assignment
|
|
|
|
void (*f1)(void);
|
|
void f2(void) {}
|
|
|
|
struct s1 *ps1;
|
|
struct s2 *ps2;
|
|
|
|
void *v1, **v2, ***v3;
|
|
|
|
enum e1 { a = 4 } e10, *e11, *e12;
|
|
enum e2 { b = -4 } e20, *e21;
|
|
enum e3 { c = 5000000000LL } e30;
|
|
|
|
int *ip;
|
|
unsigned int *up;
|
|
long *lp;
|
|
long long *llp;
|
|
|
|
char **c1;
|
|
char const **c2;
|
|
unsigned char **u1;
|
|
|
|
int no_main ()
|
|
{
|
|
// function
|
|
f1 = f2;
|
|
// struct
|
|
ps1 = ps2;
|
|
// void*
|
|
v1 = v3;
|
|
v2 = v3;
|
|
|
|
// enum
|
|
e11 = e12;
|
|
e11 = e21;
|
|
e11 = &e10;
|
|
ip = &e10;
|
|
ip = &e20;
|
|
up = &e10;
|
|
up = &e20;
|
|
up = &e30;
|
|
|
|
lp = ip;
|
|
lp = llp;
|
|
|
|
// constness
|
|
c1 = c2;
|
|
*c1 = *c2;
|
|
**c1 = **c2;
|
|
|
|
// unsigned = signed
|
|
u1 = c2;
|
|
*u1 = *c2;
|
|
**u1 = **c2;
|
|
|
|
c2 = c1;
|
|
*c2 = *c1;
|
|
**c2 = **c1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#elif defined test_enum_compat
|
|
enum e4;
|
|
enum e5;
|
|
void f3(enum e4 e);
|
|
void f3(enum e5 e);
|
|
|
|
#elif defined test_enum_compat_2
|
|
enum e6 { E1 = -1, E0 };
|
|
void f3(enum e6);
|
|
void f3(int); // should work as int and e6 are compatible
|
|
void f4(enum e6 e);
|
|
void f4(unsigned e); // should error as unsigned and e6 are incompatible
|
|
|
|
#elif defined test_ptr_to_str
|
|
void f() { _Generic((int const *[]){0}, int:0); }
|
|
#elif defined test_fnptr_to_str
|
|
void f() { _Generic((int (*(*)(float,char))(double,int)){0}, int:0); }
|
|
#elif defined test_array_to_str
|
|
void f() { _Generic((int(*)[3]){0}, int:0); }
|
|
#elif defined test_duplicate_def_1
|
|
static enum myenum { L = -1 } L;
|
|
#elif defined test_duplicate_def_2
|
|
void foo(void) {
|
|
static enum myenum { L = -1 } L;
|
|
}
|
|
#elif defined test_abstract_decls
|
|
int bar(const char *()); // abstract declarator here is okay
|
|
int bar (const char *(*g)()) // should match this 'g' argument
|
|
{
|
|
g();
|
|
return 42;
|
|
}
|
|
int foo(int ()) // abstract decl is wrong in definitions
|
|
{
|
|
return 0;
|
|
#elif defined test_invalid_1
|
|
void f(char*);
|
|
void g(void) {
|
|
f((char[]){1, ,});
|
|
}
|
|
#elif defined test_invalid_2
|
|
int ga = 0.42 { 2 };
|
|
#elif defined test_invalid_3
|
|
struct S { int a, b; };
|
|
struct T { struct S x; };
|
|
struct T gt = { 42 a: 1, 43 };
|
|
#elif defined test_invalid_4
|
|
enum E {
|
|
x = 1 / 0
|
|
};
|
|
#elif defined test_conflicting_types
|
|
int i;
|
|
void foo(void) {
|
|
int i;
|
|
{
|
|
extern double i;
|
|
i = 42.2;
|
|
}
|
|
}
|
|
#elif defined test_nested_types
|
|
union u {
|
|
union u {
|
|
int i;
|
|
} m;
|
|
};
|
|
#elif defined test_vla_1
|
|
int X=1;
|
|
|
|
int main(void) {
|
|
int t[][][X];
|
|
}
|
|
#elif defined test_invalid_alignas
|
|
/* _Alignas is no type qualifier */
|
|
void * _Alignas(16) p1;
|
|
|
|
#elif defined test_static_assert
|
|
|
|
#define ONE 0
|
|
_Static_assert(ONE == 0, "don't show me this");
|
|
struct x{ _Static_assert(ONE == 1, "ONE is not 1"); };
|
|
|
|
#elif defined test_static_assert_2
|
|
_Static_assert(1, "1"" is 1");
|
|
struct y { _Static_assert(0, "0"" is 0"); };
|
|
|
|
#elif defined test_static_assert_c2x
|
|
_Static_assert(1);
|
|
struct z { _Static_assert(0); }
|
|
|
|
#elif defined test_static_assert_empty_string
|
|
_Static_assert(0,"");
|
|
|
|
#elif defined test_void_array
|
|
void t[3];
|
|
|
|
#elif defined test_incomplete_enum_array
|
|
enum e t[3];
|
|
|
|
#elif defined test_incomplete_struct_array
|
|
struct s t[3];
|
|
|
|
#elif defined test_const_fun_array
|
|
typedef void f(void);
|
|
const f t[3];
|
|
|
|
#elif defined test_incomplete_array_array
|
|
int t[][3]; // gr: not an error, see below
|
|
|
|
/******************************************************************/
|
|
#elif defined test_extern_array
|
|
int iii[] = { 1,2,3 };
|
|
extern int iii[];
|
|
int x[];
|
|
int x[2];
|
|
int x[];
|
|
int x[2];
|
|
int x[];
|
|
extern int x[2];
|
|
extern int x[];
|
|
int x[3];
|
|
|
|
/******************************************************************/
|
|
#elif defined test_func_1 \
|
|
|| defined test_func_2 \
|
|
|| defined test_func_3 \
|
|
|| defined test_func_4 \
|
|
|| defined test_func_5 \
|
|
|| defined test_func_6
|
|
#if defined test_func_1
|
|
int hello(int);
|
|
#elif defined test_func_4
|
|
static int hello(int);
|
|
#endif
|
|
int main () {
|
|
#if defined test_func_6
|
|
static
|
|
#endif
|
|
int hello(int);
|
|
hello(123);
|
|
return 0;
|
|
}
|
|
int printf(const char*, ...);
|
|
#if defined test_func_3
|
|
static int hello(int a)
|
|
#elif defined test_func_5
|
|
int hello(int a, int b)
|
|
#else
|
|
int hello(int a)
|
|
#endif
|
|
{ printf("%s: a = %d\n", __FUNCTION__, a); return 0; }
|
|
|
|
/******************************************************************/
|
|
#elif defined test_var_1 \
|
|
|| defined test_var_2 \
|
|
|| defined test_var_3
|
|
#define P(n,v) printf("%-5s: %d ; %d\n", __FUNCTION__, n, v)
|
|
#if defined test_var_1
|
|
int xxx[];
|
|
#endif
|
|
int bar();
|
|
int printf(const char*, ...);
|
|
int main ()
|
|
{
|
|
#if !defined test_var_3
|
|
int xxx = 2;
|
|
#endif
|
|
{
|
|
extern int xxx[
|
|
#if defined test_var_3
|
|
2
|
|
#endif
|
|
];
|
|
P(1, xxx[0]);
|
|
xxx[0] += 2;
|
|
}
|
|
#if !defined test_var_3
|
|
P(2, xxx);
|
|
#endif
|
|
bar(123);
|
|
return 0;
|
|
}
|
|
int xxx[1] = {1};
|
|
int bar() { P(3, xxx[0]); return 0; }
|
|
|
|
#elif defined test_var_4
|
|
struct yyy { int y; };
|
|
struct zzz;
|
|
void f1() {
|
|
extern char *x;
|
|
extern char **xx;
|
|
extern struct yyy y;
|
|
extern struct yyy *yy;
|
|
extern struct zzz z;
|
|
extern struct zzz *zz;
|
|
}
|
|
void f2() {
|
|
extern char *x;
|
|
extern char **xx;
|
|
extern struct yyy y;
|
|
extern struct yyy *yy;
|
|
extern struct zzz z;
|
|
extern struct zzz *zz;
|
|
}
|
|
struct yyy y, *yy;
|
|
struct zzz { int z; } z, *zz;
|
|
|
|
/******************************************************************/
|
|
#elif defined test_long_double_type_for_win32
|
|
|
|
int main()
|
|
{
|
|
double *a = 0;
|
|
long double *b = a;
|
|
int n = _Generic(*a, double:0, long double:1);
|
|
}
|
|
|
|
#elif defined test_stray_backslash
|
|
#define x \a
|
|
x
|
|
|
|
#elif defined test_stray_backslash2
|
|
int printf(const char*, ...);
|
|
int main()
|
|
{
|
|
#define _S(x) #x
|
|
#define S(x) _S(x)
|
|
printf("%sn\n", S(\\));
|
|
}
|
|
|
|
/******************************************************************/
|
|
#elif defined test_var_array
|
|
|
|
static struct var_len { int i; const char str[]; } var_array[] =
|
|
{ { 1, "abcdefghijklmnopqrstuvwxyz" },
|
|
{ 2, "longlonglonglonglong" },
|
|
{ 3, "tst3" } };
|
|
|
|
#elif defined test_var_array2
|
|
|
|
struct c1 { int a; int b[]; };
|
|
struct c1 c1 = { 1, { 2, 3, 4 } };
|
|
|
|
struct c2 { int c; struct c1 c1; };
|
|
struct c2 c2 = { 1, { 2, { 3, 4, 5 }}};
|
|
|
|
#elif defined test_var_array3
|
|
/* similar to test_var_array2 but with string initializers */
|
|
struct A { int a; char b[]; };
|
|
struct A a = { 1, "1" };
|
|
struct B { struct A a; };
|
|
struct B b = { { 1, "1" } };
|
|
/******************************************************************/
|
|
#elif defined test_default_int_type
|
|
n; // warn
|
|
f(); // don't warn
|
|
|
|
#elif defined test_invalid_global_stmtexpr
|
|
n[sizeof({3;})]; // crashed in block() due to missing local scope
|
|
|
|
#elif defined test_invalid_tokckill
|
|
f(){"12"3;} // second const token killed the value of the first
|
|
|
|
/******************************************************************/
|
|
#elif defined test_duplicate_member
|
|
struct S {
|
|
int a, a;
|
|
};
|
|
#elif defined test_duplicate_member_anon
|
|
struct S1 {
|
|
int b;
|
|
struct {
|
|
int b;
|
|
} c;
|
|
};
|
|
struct S2 {
|
|
int d;
|
|
struct {
|
|
int d;
|
|
};
|
|
};
|
|
|
|
/******************************************************************/
|
|
#elif defined test_conflicting_array_definition
|
|
extern int array[2];
|
|
int array[] = { 1, 2, 3 };
|
|
|
|
#elif defined test_incompatible_local_redef
|
|
void foo (void)
|
|
{
|
|
typedef int localfunctype (int);
|
|
extern localfunctype func2;
|
|
typedef void localfunctype (int, int);
|
|
}
|
|
|
|
#elif defined test_cast_from_void
|
|
void v() {}
|
|
int f() { return v(); }
|
|
|
|
#elif defined test_switch_W1 || defined test_switch_W2 \
|
|
|| defined test_switch_W3 || defined test_switch_W4
|
|
#if defined test_switch_W1
|
|
#pragma comment(option, "-Wall")
|
|
#elif defined test_switch_W2
|
|
#pragma comment(option, "-Wunsupported -Wno-implicit-function-declaration -Wstuff")
|
|
#elif defined test_switch_W3
|
|
#pragma comment(option, "-Wwrite-strings -Werror=discarded-qualifiers")
|
|
#elif defined test_switch_W4
|
|
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
|
|
#endif
|
|
void func()
|
|
{
|
|
char *ccp = "123";
|
|
fink();
|
|
}
|
|
__attribute__((stuff)) int fink() {return 0;}
|
|
|
|
#elif defined test_invalid_funcparam_1
|
|
void func(int a, int b, int a);
|
|
|
|
#elif defined test_invalid_funcparam_2
|
|
void func(int a, int if);
|
|
|
|
#elif defined test_array_funcparam
|
|
int amain(int argc, char *argv[static argc + 1])
|
|
{
|
|
int i;
|
|
int printf(const char*, ...);
|
|
for (i = 0; i < argc; ++i)
|
|
printf("arg[%d] = \"%s\"\n", i, argv[i]);
|
|
return 0;
|
|
}
|
|
int main()
|
|
{
|
|
return amain(2, (char *[]){ "X", "Y", 0 });
|
|
}
|
|
|
|
#elif defined test_return_from_statement_expr
|
|
int f() { ({ return 78; }); }
|
|
int main() { return f(); }
|
|
|
|
/******************************************************************/
|
|
|
|
#elif defined test_illegal_unicode
|
|
int main() {
|
|
char *str = "\Uffffffff";
|
|
}
|
|
|
|
#elif defined test_error_string
|
|
#error \123\\
|
|
456
|
|
|
|
#endif
|