work on local extern declarations
Example: int a = 1; void f(void) { int a = 2; { extern int a; // = 1 !! .... To get this (more) correctly there is a new function to copy syms between local to global stacks. Also, this patch changes the meaning of VT_EXTERN back to the simpler and IMO more useful notion of DECLARED but not (yet) DEFINED. and that for both variables and functions. That is, VT_EXTERN in tcc doesn't have to do with the keyword 'extern' necessarily. Also this patch does allow int x[]; as alias for extern int x[]; (as do gcc and msvc)
This commit is contained in:
parent
cbbba01b46
commit
8569048031
4 changed files with 214 additions and 86 deletions
2
tccasm.c
2
tccasm.c
|
@ -38,7 +38,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, in
|
||||||
static Sym *asm_label_find(int v)
|
static Sym *asm_label_find(int v)
|
||||||
{
|
{
|
||||||
Sym *sym = sym_find(v);
|
Sym *sym = sym_find(v);
|
||||||
while (sym && sym->sym_scope)
|
while (sym && sym->sym_scope && !(sym->type.t & VT_STATIC))
|
||||||
sym = sym->prev_tok;
|
sym = sym->prev_tok;
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
181
tccgen.c
181
tccgen.c
|
@ -263,6 +263,7 @@ ST_FUNC int tccgen_compile(TCCState *s1)
|
||||||
section_sym = 0;
|
section_sym = 0;
|
||||||
const_wanted = 0;
|
const_wanted = 0;
|
||||||
nocode_wanted = 0x80000000;
|
nocode_wanted = 0x80000000;
|
||||||
|
local_scope = 0;
|
||||||
|
|
||||||
/* define some often used types */
|
/* define some often used types */
|
||||||
int_type.t = VT_INT;
|
int_type.t = VT_INT;
|
||||||
|
@ -325,8 +326,7 @@ ST_FUNC void update_storage(Sym *sym)
|
||||||
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
|
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
|
||||||
| sym->a.visibility;
|
| sym->a.visibility;
|
||||||
|
|
||||||
if ((sym->type.t & VT_STATIC)
|
if (sym->type.t & (VT_STATIC | VT_INLINE))
|
||||||
|| (sym->type.t & (VT_EXTERN | VT_INLINE)) == VT_INLINE)
|
|
||||||
sym_bind = STB_LOCAL;
|
sym_bind = STB_LOCAL;
|
||||||
else if (sym->a.weak)
|
else if (sym->a.weak)
|
||||||
sym_bind = STB_WEAK;
|
sym_bind = STB_WEAK;
|
||||||
|
@ -408,7 +408,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
|
||||||
} else {
|
} else {
|
||||||
sym_type = STT_OBJECT;
|
sym_type = STT_OBJECT;
|
||||||
}
|
}
|
||||||
if ((t & VT_STATIC) || (t & (VT_EXTERN | VT_INLINE)) == VT_INLINE)
|
if (t & (VT_STATIC | VT_INLINE))
|
||||||
sym_bind = STB_LOCAL;
|
sym_bind = STB_LOCAL;
|
||||||
else
|
else
|
||||||
sym_bind = STB_GLOBAL;
|
sym_bind = STB_GLOBAL;
|
||||||
|
@ -927,8 +927,7 @@ static void merge_attr(AttributeDef *ad, AttributeDef *ad1)
|
||||||
/* Merge some type attributes. */
|
/* Merge some type attributes. */
|
||||||
static void patch_type(Sym *sym, CType *type)
|
static void patch_type(Sym *sym, CType *type)
|
||||||
{
|
{
|
||||||
if ((!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t))
|
if (!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t)) {
|
||||||
&& (type->t & VT_BTYPE) != VT_FUNC) {
|
|
||||||
if (!(sym->type.t & VT_EXTERN))
|
if (!(sym->type.t & VT_EXTERN))
|
||||||
tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
|
tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
|
||||||
sym->type.t &= ~VT_EXTERN;
|
sym->type.t &= ~VT_EXTERN;
|
||||||
|
@ -955,29 +954,30 @@ static void patch_type(Sym *sym, CType *type)
|
||||||
tcc_warning("static storage ignored for redefinition of '%s'",
|
tcc_warning("static storage ignored for redefinition of '%s'",
|
||||||
get_tok_str(sym->v, NULL));
|
get_tok_str(sym->v, NULL));
|
||||||
|
|
||||||
/* Force external definition if unequal inline specifier
|
/* set 'inline' if both agree or if one has static */
|
||||||
or an explicit extern one. */
|
if ((type->t | sym->type.t) & VT_INLINE) {
|
||||||
if ((sym->type.t | type->t) & VT_STATIC) {
|
if (!((type->t ^ sym->type.t) & VT_INLINE)
|
||||||
type->t |= sym->type.t & VT_INLINE;
|
|| ((type->t | sym->type.t) & VT_STATIC))
|
||||||
sym->type.t |= type->t & VT_INLINE;
|
static_proto |= VT_INLINE;
|
||||||
} else if (((type->t & VT_INLINE) != (sym->type.t & VT_INLINE)
|
|
||||||
|| (type->t | sym->type.t) & VT_EXTERN)
|
|
||||||
&& !static_proto) {
|
|
||||||
type->t &= ~VT_INLINE;
|
|
||||||
sym->type.t &= ~VT_INLINE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == (type->t & VT_EXTERN)) {
|
if (0 == (type->t & VT_EXTERN)) {
|
||||||
/* put complete type, use static from prototype, but don't
|
/* put complete type, use static from prototype */
|
||||||
overwrite type.ref, it might contain parameter names */
|
sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto;
|
||||||
sym->type.t = (type->t & ~VT_STATIC) | static_proto;
|
sym->type.ref = type->ref;
|
||||||
|
} else {
|
||||||
|
sym->type.t &= ~VT_INLINE | static_proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sym->type.ref->f.func_type == FUNC_OLD
|
||||||
|
&& type->ref->f.func_type != FUNC_OLD) {
|
||||||
|
sym->type.ref = type->ref;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) {
|
if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) {
|
||||||
/* set array size if it was omitted in extern declaration */
|
/* set array size if it was omitted in extern declaration */
|
||||||
if (sym->type.ref->c < 0)
|
|
||||||
sym->type.ref->c = type->ref->c;
|
sym->type.ref->c = type->ref->c;
|
||||||
else if (sym->type.ref->c != type->ref->c)
|
|
||||||
tcc_error("conflicting type for '%s'", get_tok_str(sym->v, NULL));
|
|
||||||
}
|
}
|
||||||
if ((type->t ^ sym->type.t) & VT_STATIC)
|
if ((type->t ^ sym->type.t) & VT_STATIC)
|
||||||
tcc_warning("storage mismatch for redefinition of '%s'",
|
tcc_warning("storage mismatch for redefinition of '%s'",
|
||||||
|
@ -985,7 +985,6 @@ static void patch_type(Sym *sym, CType *type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Merge some storage attributes. */
|
/* Merge some storage attributes. */
|
||||||
static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
|
static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
|
||||||
{
|
{
|
||||||
|
@ -1003,29 +1002,55 @@ static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
|
||||||
update_storage(sym);
|
update_storage(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* copy sym to other stack */
|
||||||
|
static Sym *sym_copy(Sym *s0, Sym **ps)
|
||||||
|
{
|
||||||
|
Sym *s;
|
||||||
|
s = sym_malloc(), *s = *s0;
|
||||||
|
s->prev = *ps, *ps = s;
|
||||||
|
if (s->v < SYM_FIRST_ANOM) {
|
||||||
|
ps = &table_ident[s->v - TOK_IDENT]->sym_identifier;
|
||||||
|
s->prev_tok = *ps, *ps = s;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy a list of syms */
|
||||||
|
static void sym_copy_ref(Sym *s0, Sym **ps)
|
||||||
|
{
|
||||||
|
Sym *s, **sp = &s0->type.ref;
|
||||||
|
for (s = *sp, *sp = NULL; s; s = s->next)
|
||||||
|
sp = &(*sp = sym_copy(s, ps))->next;
|
||||||
|
}
|
||||||
|
|
||||||
/* define a new external reference to a symbol 'v' */
|
/* define a new external reference to a symbol 'v' */
|
||||||
static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
|
static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
|
||||||
{
|
{
|
||||||
Sym *s;
|
Sym *s; int bt;
|
||||||
|
|
||||||
|
/* look for global symbol */
|
||||||
s = sym_find(v);
|
s = sym_find(v);
|
||||||
if (!s || (!IS_ASM_SYM(s) && !(s->type.t & VT_EXTERN)
|
while (s && s->sym_scope)
|
||||||
&& (!(type->t & VT_EXTERN) || s->sym_scope)
|
s = s->prev_tok;
|
||||||
&& (s->type.t & VT_BTYPE) != VT_FUNC)) {
|
|
||||||
if (s && !is_compatible_types(&s->type, type))
|
if (!s) {
|
||||||
tcc_error("conflicting types for '%s'", get_tok_str(s->v, NULL));
|
|
||||||
/* push forward reference */
|
/* push forward reference */
|
||||||
s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
|
s = global_identifier_push(v, type->t, 0);
|
||||||
|
s->r |= r;
|
||||||
s->a = ad->a;
|
s->a = ad->a;
|
||||||
s->asm_label = ad->asm_label;
|
s->asm_label = ad->asm_label;
|
||||||
s->sym_scope = 0;
|
|
||||||
} else {
|
|
||||||
if (s->type.ref == func_old_type.ref) {
|
|
||||||
s->type.ref = type->ref;
|
s->type.ref = type->ref;
|
||||||
s->r = r | VT_CONST | VT_SYM;
|
bt = s->type.t & (VT_BTYPE|VT_ARRAY);
|
||||||
s->type.t |= VT_EXTERN;
|
/* copy type to the global stack also */
|
||||||
}
|
if (local_scope && (bt == VT_FUNC || (bt & VT_ARRAY)))
|
||||||
|
sym_copy_ref(s, &global_stack);
|
||||||
|
} else {
|
||||||
patch_storage(s, ad, type);
|
patch_storage(s, ad, type);
|
||||||
|
bt = s->type.t & VT_BTYPE;
|
||||||
}
|
}
|
||||||
|
/* push variables to local scope if any */
|
||||||
|
if (local_stack && bt != VT_FUNC)
|
||||||
|
s = sym_copy(s, &local_stack);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2880,27 +2905,29 @@ static int is_compatible_func(CType *type1, CType *type2)
|
||||||
|
|
||||||
s1 = type1->ref;
|
s1 = type1->ref;
|
||||||
s2 = type2->ref;
|
s2 = type2->ref;
|
||||||
if (!is_compatible_types(&s1->type, &s2->type))
|
|
||||||
return 0;
|
|
||||||
/* check func_call */
|
|
||||||
if (s1->f.func_call != s2->f.func_call)
|
if (s1->f.func_call != s2->f.func_call)
|
||||||
return 0;
|
return 0;
|
||||||
/* XXX: not complete */
|
if (s1->f.func_type != s2->f.func_type
|
||||||
if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD)
|
&& s1->f.func_type != FUNC_OLD
|
||||||
|
&& s2->f.func_type != FUNC_OLD)
|
||||||
|
return 0;
|
||||||
|
/* we should check the function return type for FUNC_OLD too
|
||||||
|
but that causes problems with the internally used support
|
||||||
|
functions such as TOK_memmove */
|
||||||
|
if (s1->f.func_type == FUNC_OLD && !s1->next)
|
||||||
return 1;
|
return 1;
|
||||||
if (s1->f.func_type != s2->f.func_type)
|
if (s2->f.func_type == FUNC_OLD && !s2->next)
|
||||||
return 0;
|
return 1;
|
||||||
while (s1 != NULL) {
|
for (;;) {
|
||||||
if (s2 == NULL)
|
|
||||||
return 0;
|
|
||||||
if (!is_compatible_unqualified_types(&s1->type, &s2->type))
|
if (!is_compatible_unqualified_types(&s1->type, &s2->type))
|
||||||
return 0;
|
return 0;
|
||||||
s1 = s1->next;
|
s1 = s1->next;
|
||||||
s2 = s2->next;
|
s2 = s2->next;
|
||||||
}
|
if (!s1)
|
||||||
if (s2)
|
return !s2;
|
||||||
|
if (!s2)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return true if type1 and type2 are the same. If unqualified is
|
/* return true if type1 and type2 are the same. If unqualified is
|
||||||
|
@ -2926,15 +2953,19 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
|
||||||
/* XXX: bitfields ? */
|
/* XXX: bitfields ? */
|
||||||
if (t1 != t2)
|
if (t1 != t2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if ((t1 & VT_ARRAY)
|
||||||
|
&& !(type1->ref->c < 0
|
||||||
|
|| type2->ref->c < 0
|
||||||
|
|| type1->ref->c == type2->ref->c))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* test more complicated cases */
|
/* test more complicated cases */
|
||||||
bt1 = t1 & (VT_BTYPE | VT_ARRAY);
|
bt1 = t1 & VT_BTYPE;
|
||||||
if (bt1 == VT_PTR) {
|
if (bt1 == VT_PTR) {
|
||||||
type1 = pointed_type(type1);
|
type1 = pointed_type(type1);
|
||||||
type2 = pointed_type(type2);
|
type2 = pointed_type(type2);
|
||||||
return is_compatible_types(type1, type2);
|
return is_compatible_types(type1, type2);
|
||||||
} else if (bt1 & VT_ARRAY) {
|
|
||||||
return type1->ref->c < 0 || type2->ref->c < 0
|
|
||||||
|| type1->ref->c == type2->ref->c;
|
|
||||||
} else if (bt1 == VT_STRUCT) {
|
} else if (bt1 == VT_STRUCT) {
|
||||||
return (type1->ref == type2->ref);
|
return (type1->ref == type2->ref);
|
||||||
} else if (bt1 == VT_FUNC) {
|
} else if (bt1 == VT_FUNC) {
|
||||||
|
@ -7285,9 +7316,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||||
sym = sym_push(v, type, r | VT_SYM, 0);
|
sym = sym_push(v, type, r | VT_SYM, 0);
|
||||||
patch_storage(sym, ad, NULL);
|
patch_storage(sym, ad, NULL);
|
||||||
}
|
}
|
||||||
/* Local statics have a scope until now (for
|
|
||||||
warnings), remove it here. */
|
|
||||||
sym->sym_scope = 0;
|
|
||||||
/* update symbol definition */
|
/* update symbol definition */
|
||||||
put_extern_sym(sym, sec, addr, size);
|
put_extern_sym(sym, sec, addr, size);
|
||||||
} else {
|
} else {
|
||||||
|
@ -7431,7 +7459,7 @@ static void gen_inline_functions(TCCState *s)
|
||||||
for (i = 0; i < s->nb_inline_fns; ++i) {
|
for (i = 0; i < s->nb_inline_fns; ++i) {
|
||||||
fn = s->inline_fns[i];
|
fn = s->inline_fns[i];
|
||||||
sym = fn->sym;
|
sym = fn->sym;
|
||||||
if (sym && (sym->c || !(sym->type.t & (VT_INLINE | VT_STATIC)) )) {
|
if (sym && (sym->c || !(sym->type.t & VT_INLINE))) {
|
||||||
/* the function was used or forced (and then not internal):
|
/* the function was used or forced (and then not internal):
|
||||||
generate its code and convert it to a normal function */
|
generate its code and convert it to a normal function */
|
||||||
fn->sym = NULL;
|
fn->sym = NULL;
|
||||||
|
@ -7544,22 +7572,26 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((type.t & VT_BTYPE) == VT_FUNC) {
|
if ((type.t & VT_BTYPE) == VT_FUNC) {
|
||||||
if ((type.t & VT_STATIC) && (l == VT_LOCAL)) {
|
|
||||||
tcc_error("function without file scope cannot be static");
|
|
||||||
}
|
|
||||||
/* if old style function prototype, we accept a
|
/* if old style function prototype, we accept a
|
||||||
declaration list */
|
declaration list */
|
||||||
sym = type.ref;
|
sym = type.ref;
|
||||||
if (sym->f.func_type == FUNC_OLD && l == VT_CONST)
|
if (sym->f.func_type == FUNC_OLD && l == VT_CONST)
|
||||||
decl0(VT_CMP, 0, sym);
|
decl0(VT_CMP, 0, sym);
|
||||||
|
/* always compile 'extern inline' */
|
||||||
|
if (type.t & VT_EXTERN)
|
||||||
|
type.t &= ~VT_INLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
|
if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
|
||||||
ad.asm_label = asm_label_instr();
|
ad.asm_label = asm_label_instr();
|
||||||
/* parse one last attribute list, after asm label */
|
/* parse one last attribute list, after asm label */
|
||||||
parse_attribute(&ad);
|
parse_attribute(&ad);
|
||||||
|
#if 0
|
||||||
|
/* gcc does not allow __asm__("label") with function definition,
|
||||||
|
but why not ... */
|
||||||
if (tok == '{')
|
if (tok == '{')
|
||||||
expect(";");
|
expect(";");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
|
@ -7591,18 +7623,12 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put function symbol */
|
/* put function symbol */
|
||||||
|
type.t &= ~VT_EXTERN;
|
||||||
sym = external_sym(v, &type, 0, &ad);
|
sym = external_sym(v, &type, 0, &ad);
|
||||||
/* This is the def, so overwrite any other parameter names
|
|
||||||
we got from prototypes. */
|
|
||||||
sym->type.ref = type.ref;
|
|
||||||
if (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF
|
|
||||||
&& !(elfsym(sym)->st_other & ST_ASM_SET))
|
|
||||||
tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
|
|
||||||
|
|
||||||
/* static inline functions are just recorded as a kind
|
/* static inline functions are just recorded as a kind
|
||||||
of macro. Their code will be emitted at the end of
|
of macro. Their code will be emitted at the end of
|
||||||
the compilation unit only if they are used */
|
the compilation unit only if they are used */
|
||||||
if ((sym->type.t & (VT_INLINE | VT_EXTERN)) == VT_INLINE) {
|
if (sym->type.t & VT_INLINE) {
|
||||||
struct InlineFunc *fn;
|
struct InlineFunc *fn;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
|
||||||
|
@ -7669,15 +7695,14 @@ found:
|
||||||
has_init = (tok == '=');
|
has_init = (tok == '=');
|
||||||
if (has_init && (type.t & VT_VLA))
|
if (has_init && (type.t & VT_VLA))
|
||||||
tcc_error("variable length array cannot be initialized");
|
tcc_error("variable length array cannot be initialized");
|
||||||
if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) ||
|
if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST))
|
||||||
((type.t & VT_BTYPE) == VT_FUNC) ||
|
|| (type.t & VT_BTYPE) == VT_FUNC
|
||||||
((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
|
/* as with GCC, uninitialized global arrays with no size
|
||||||
!has_init && l == VT_CONST && type.ref->c < 0)) {
|
are considered extern: */
|
||||||
|
|| ((type.t & VT_ARRAY) && !has_init
|
||||||
|
&& l == VT_CONST && type.ref->c < 0)
|
||||||
|
) {
|
||||||
/* external variable or function */
|
/* external variable or function */
|
||||||
/* NOTE: as GCC, uninitialized global static
|
|
||||||
arrays of null size are considered as
|
|
||||||
extern */
|
|
||||||
if ((type.t & VT_BTYPE) != VT_FUNC)
|
|
||||||
type.t |= VT_EXTERN;
|
type.t |= VT_EXTERN;
|
||||||
sym = external_sym(v, &type, r, &ad);
|
sym = external_sym(v, &type, r, &ad);
|
||||||
if (ad.alias_target) {
|
if (ad.alias_target) {
|
||||||
|
@ -7687,9 +7712,6 @@ found:
|
||||||
esym = elfsym(alias_target);
|
esym = elfsym(alias_target);
|
||||||
if (!esym)
|
if (!esym)
|
||||||
tcc_error("unsupported forward __alias__ attribute");
|
tcc_error("unsupported forward __alias__ attribute");
|
||||||
/* Local statics have a scope until now (for
|
|
||||||
warnings), remove it here. */
|
|
||||||
sym->sym_scope = 0;
|
|
||||||
put_extern_sym2(sym, esym->st_shndx, esym->st_value, esym->st_size, 0);
|
put_extern_sym2(sym, esym->st_shndx, esym->st_value, esym->st_size, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -7699,8 +7721,7 @@ found:
|
||||||
r |= l;
|
r |= l;
|
||||||
if (has_init)
|
if (has_init)
|
||||||
next();
|
next();
|
||||||
else if (l == VT_CONST
|
else if (l == VT_CONST)
|
||||||
&& (type.t & VT_BTYPE) != VT_FUNC)
|
|
||||||
/* uninitialized global variables may be overridden */
|
/* uninitialized global variables may be overridden */
|
||||||
type.t |= VT_EXTERN;
|
type.t |= VT_EXTERN;
|
||||||
decl_initializer_alloc(&type, &ad, r, has_init, v, l);
|
decl_initializer_alloc(&type, &ad, r, has_init, v, l);
|
||||||
|
|
|
@ -196,6 +196,82 @@ void * _Alignas(16) p1;
|
||||||
const f t[3];
|
const f t[3];
|
||||||
|
|
||||||
#elif defined test_incomplete_array_array
|
#elif defined test_incomplete_array_array
|
||||||
int t[][3];
|
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
|
||||||
|
#if defined test_func_1
|
||||||
|
int hello(int);
|
||||||
|
#elif defined test_func_4
|
||||||
|
static int hello(int);
|
||||||
|
#endif
|
||||||
|
int main () {
|
||||||
|
#if defined test_func_5
|
||||||
|
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; }
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
60_errors_and_warnings.c:153: error: ',' expected (got "a")
|
60_errors_and_warnings.c:153: error: ',' expected (got "a")
|
||||||
|
|
||||||
[test_conflicting_types]
|
[test_conflicting_types]
|
||||||
60_errors_and_warnings.c:159: error: conflicting types for 'i'
|
60_errors_and_warnings.c:159: error: incompatible types for redefinition of 'i'
|
||||||
|
|
||||||
[test_nested_types]
|
[test_nested_types]
|
||||||
60_errors_and_warnings.c:166: error: struct/union/enum already defined
|
60_errors_and_warnings.c:166: error: struct/union/enum already defined
|
||||||
|
@ -100,4 +100,35 @@
|
||||||
60_errors_and_warnings.c:196: error: declaration of an array of functions
|
60_errors_and_warnings.c:196: error: declaration of an array of functions
|
||||||
|
|
||||||
[test_incomplete_array_array]
|
[test_incomplete_array_array]
|
||||||
60_errors_and_warnings.c:199: error: unknown type size
|
|
||||||
|
[test_extern_array]
|
||||||
|
60_errors_and_warnings.c:212: error: incompatible types for redefinition of 'x'
|
||||||
|
|
||||||
|
[test_func_1]
|
||||||
|
hello: a = 123
|
||||||
|
|
||||||
|
[test_func_2]
|
||||||
|
hello: a = 123
|
||||||
|
|
||||||
|
[test_func_3]
|
||||||
|
60_errors_and_warnings.c:241: warning: static storage ignored for redefinition of 'hello'
|
||||||
|
hello: a = 123
|
||||||
|
|
||||||
|
[test_func_4]
|
||||||
|
hello: a = 123
|
||||||
|
|
||||||
|
[test_func_5]
|
||||||
|
60_errors_and_warnings.c:241: error: incompatible types for redefinition of 'hello'
|
||||||
|
|
||||||
|
[test_var_1]
|
||||||
|
main : 1 ; 1
|
||||||
|
main : 2 ; 2
|
||||||
|
bar : 3 ; 3
|
||||||
|
|
||||||
|
[test_var_2]
|
||||||
|
main : 1 ; 1
|
||||||
|
main : 2 ; 2
|
||||||
|
bar : 3 ; 3
|
||||||
|
|
||||||
|
[test_var_3]
|
||||||
|
60_errors_and_warnings.c:273: error: incompatible types for redefinition of 'xxx'
|
||||||
|
|
Loading…
Reference in a new issue