tccgen: show useful line number with duplicate switch-case
- output correct line number with "error: duplicate case value" - libtcc.c:error1(): support specific line numbers with "%i:" tcc_error("%i:message ...", line_num, ...); Also: - simplify signed/unsigned switch compare - optimize implicit case ranges such as case 1: case 2: case 3: ... - simplify llong constant propagation in gen_opic() - rename Sym.ncl to Sym.cleanup_func
This commit is contained in:
parent
f0cd0fbe1b
commit
c717bac6e3
5 changed files with 125 additions and 103 deletions
8
libtcc.c
8
libtcc.c
|
@ -567,6 +567,7 @@ static void error1(int mode, const char *fmt, va_list ap)
|
||||||
BufferedFile **pf, *f;
|
BufferedFile **pf, *f;
|
||||||
TCCState *s1 = tcc_state;
|
TCCState *s1 = tcc_state;
|
||||||
CString cs;
|
CString cs;
|
||||||
|
int line = 0;
|
||||||
|
|
||||||
tcc_exit_state(s1);
|
tcc_exit_state(s1);
|
||||||
|
|
||||||
|
@ -589,6 +590,8 @@ static void error1(int mode, const char *fmt, va_list ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
cstr_new(&cs);
|
cstr_new(&cs);
|
||||||
|
if (fmt[0] == '%' && fmt[1] == 'i' && fmt[2] == ':')
|
||||||
|
line = va_arg(ap, int), fmt += 3;
|
||||||
f = NULL;
|
f = NULL;
|
||||||
if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */
|
if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */
|
||||||
/* use upper file if inline ":asm:" or token ":paste:" */
|
/* use upper file if inline ":asm:" or token ":paste:" */
|
||||||
|
@ -599,8 +602,9 @@ static void error1(int mode, const char *fmt, va_list ap)
|
||||||
for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
|
for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
|
||||||
cstr_printf(&cs, "In file included from %s:%d:\n",
|
cstr_printf(&cs, "In file included from %s:%d:\n",
|
||||||
(*pf)->filename, (*pf)->line_num - 1);
|
(*pf)->filename, (*pf)->line_num - 1);
|
||||||
cstr_printf(&cs, "%s:%d: ",
|
if (0 == line)
|
||||||
f->filename, f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr));
|
line = f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr);
|
||||||
|
cstr_printf(&cs, "%s:%d: ", f->filename, line);
|
||||||
} else if (s1->current_filename) {
|
} else if (s1->current_filename) {
|
||||||
cstr_printf(&cs, "%s: ", s1->current_filename);
|
cstr_printf(&cs, "%s: ", s1->current_filename);
|
||||||
} else {
|
} else {
|
||||||
|
|
4
tcc.h
4
tcc.h
|
@ -564,14 +564,16 @@ typedef struct Sym {
|
||||||
union {
|
union {
|
||||||
int sym_scope; /* scope level for locals */
|
int sym_scope; /* scope level for locals */
|
||||||
int jnext; /* next jump label */
|
int jnext; /* next jump label */
|
||||||
|
int jind; /* label position */
|
||||||
struct FuncAttr f; /* function attributes */
|
struct FuncAttr f; /* function attributes */
|
||||||
int auxtype; /* bitfield access type */
|
int auxtype; /* bitfield access type */
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
long long enum_val; /* enum constant if IS_ENUM_VAL */
|
long long enum_val; /* enum constant if IS_ENUM_VAL */
|
||||||
int *d; /* define token stream */
|
int *d; /* define token stream */
|
||||||
struct Sym *ncl; /* next cleanup */
|
struct Sym *cleanup_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
CType type; /* associated type */
|
CType type; /* associated type */
|
||||||
union {
|
union {
|
||||||
struct Sym *next; /* next related symbol (for fields and anoms) */
|
struct Sym *next; /* next related symbol (for fields and anoms) */
|
||||||
|
|
190
tccgen.c
190
tccgen.c
|
@ -90,7 +90,7 @@ static CString initstr;
|
||||||
static struct switch_t {
|
static struct switch_t {
|
||||||
struct case_t {
|
struct case_t {
|
||||||
int64_t v1, v2;
|
int64_t v1, v2;
|
||||||
int sym;
|
int ind, line;
|
||||||
} **p; int n; /* list of case ranges */
|
} **p; int n; /* list of case ranges */
|
||||||
int def_sym; /* default symbol */
|
int def_sym; /* default symbol */
|
||||||
int nocode_wanted;
|
int nocode_wanted;
|
||||||
|
@ -2236,7 +2236,11 @@ static void gen_opl(int op)
|
||||||
vtop[-1] = vtop[-2];
|
vtop[-1] = vtop[-2];
|
||||||
vtop[-2] = tmp;
|
vtop[-2] = tmp;
|
||||||
/* stack: L1 L2 H1 H2 */
|
/* stack: L1 L2 H1 H2 */
|
||||||
|
if (!cur_switch || cur_switch->bsym) {
|
||||||
|
/* avoid differnt registers being saved in branches.
|
||||||
|
This is not needed when comparing switch cases */
|
||||||
save_regs(4);
|
save_regs(4);
|
||||||
|
}
|
||||||
/* compare high */
|
/* compare high */
|
||||||
op1 = op;
|
op1 = op;
|
||||||
/* when values are equal, we need to compare low words. since
|
/* when values are equal, we need to compare low words. since
|
||||||
|
@ -2285,6 +2289,18 @@ static void gen_opl(int op)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* normalize values */
|
||||||
|
static uint64_t value64(uint64_t l1, int t)
|
||||||
|
{
|
||||||
|
if ((t & VT_BTYPE) == VT_LLONG
|
||||||
|
|| (PTR_SIZE == 8 && (t & VT_BTYPE) == VT_PTR))
|
||||||
|
return l1;
|
||||||
|
else if (t & VT_UNSIGNED)
|
||||||
|
return (uint32_t)l1;
|
||||||
|
else
|
||||||
|
return (uint32_t)l1 | -(l1 & 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b)
|
static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b)
|
||||||
{
|
{
|
||||||
uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b);
|
uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b);
|
||||||
|
@ -2306,18 +2322,11 @@ static void gen_opic(int op)
|
||||||
int t2 = v2->type.t & VT_BTYPE;
|
int t2 = v2->type.t & VT_BTYPE;
|
||||||
int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
||||||
int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
||||||
uint64_t l1 = c1 ? v1->c.i : 0;
|
uint64_t l1 = c1 ? value64(v1->c.i, v1->type.t) : 0;
|
||||||
uint64_t l2 = c2 ? v2->c.i : 0;
|
uint64_t l2 = c2 ? value64(v2->c.i, v2->type.t) : 0;
|
||||||
int shm = (t1 == VT_LLONG) ? 63 : 31;
|
int shm = (t1 == VT_LLONG) ? 63 : 31;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR))
|
|
||||||
l1 = ((uint32_t)l1 |
|
|
||||||
(v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000)));
|
|
||||||
if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR))
|
|
||||||
l2 = ((uint32_t)l2 |
|
|
||||||
(v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000)));
|
|
||||||
|
|
||||||
if (c1 && c2) {
|
if (c1 && c2) {
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case '+': l1 += l2; break;
|
case '+': l1 += l2; break;
|
||||||
|
@ -2367,10 +2376,7 @@ static void gen_opic(int op)
|
||||||
default:
|
default:
|
||||||
goto general_case;
|
goto general_case;
|
||||||
}
|
}
|
||||||
if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR))
|
v1->c.i = value64(l1, v1->type.t);
|
||||||
l1 = ((uint32_t)l1 |
|
|
||||||
(v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000)));
|
|
||||||
v1->c.i = l1;
|
|
||||||
v1->r |= v2->r & VT_NONCONST;
|
v1->r |= v2->r & VT_NONCONST;
|
||||||
vtop--;
|
vtop--;
|
||||||
} else {
|
} else {
|
||||||
|
@ -6701,79 +6707,74 @@ static void check_func_return(void)
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* switch/case */
|
/* switch/case */
|
||||||
|
|
||||||
static int case_cmpi(const void *pa, const void *pb)
|
static int case_cmp(uint64_t a, uint64_t b)
|
||||||
{
|
{
|
||||||
int64_t a = (*(struct case_t**) pa)->v1;
|
if (cur_switch->sv.type.t & VT_UNSIGNED)
|
||||||
int64_t b = (*(struct case_t**) pb)->v1;
|
|
||||||
return a < b ? -1 : a > b;
|
return a < b ? -1 : a > b;
|
||||||
|
else
|
||||||
|
return (int64_t)a < (int64_t)b ? -1 : (int64_t)a > (int64_t)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int case_cmpu(const void *pa, const void *pb)
|
static int case_cmp_qs(const void *pa, const void *pb)
|
||||||
{
|
{
|
||||||
uint64_t a = (uint64_t)(*(struct case_t**) pa)->v1;
|
return case_cmp((*(struct case_t**)pa)->v1, (*(struct case_t**)pb)->v1);
|
||||||
uint64_t b = (uint64_t)(*(struct case_t**) pb)->v1;
|
|
||||||
return a < b ? -1 : a > b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gtst_addr(int t, int a)
|
static void case_sort(struct switch_t *sw)
|
||||||
{
|
{
|
||||||
gsym_addr(gvtst(0, t), a);
|
struct case_t **p;
|
||||||
|
if (sw->n < 2)
|
||||||
|
return;
|
||||||
|
qsort(sw->p, sw->n, sizeof *sw->p, case_cmp_qs);
|
||||||
|
p = sw->p;
|
||||||
|
while (p < sw->p + sw->n - 1) {
|
||||||
|
if (case_cmp(p[0]->v2, p[1]->v1) >= 0) {
|
||||||
|
int l1 = p[0]->line, l2 = p[1]->line;
|
||||||
|
/* using special format "%i:..." to show specific line */
|
||||||
|
tcc_error("%i:duplicate case value", l1 > l2 ? l1 : l2);
|
||||||
|
} else if (p[0]->v2 + 1 == p[1]->v1 && p[0]->ind == p[1]->ind) {
|
||||||
|
/* treat "case 1: case 2: case 3:" like "case 1 ... 3: */
|
||||||
|
p[1]->v1 = p[0]->v1;
|
||||||
|
tcc_free(p[0]);
|
||||||
|
memmove(p, p + 1, (--sw->n - (p - sw->p)) * sizeof *p);
|
||||||
|
} else
|
||||||
|
++p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gcase(struct case_t **base, int len, int *bsym)
|
static int gcase(struct case_t **base, int len, int dsym)
|
||||||
{
|
{
|
||||||
struct case_t *p;
|
struct case_t *p;
|
||||||
int e;
|
int t, l2, e;
|
||||||
int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
|
|
||||||
while (len > 8) {
|
t = vtop->type.t & VT_BTYPE;
|
||||||
/* binary search */
|
if (t != VT_LLONG)
|
||||||
p = base[len/2];
|
t = VT_INT;
|
||||||
vdup();
|
while (len) {
|
||||||
if (ll)
|
/* binary search while len > 8, else linear */
|
||||||
vpushll(p->v2);
|
l2 = len > 8 ? len/2 : 0;
|
||||||
else
|
p = base[l2];
|
||||||
vpushi(p->v2);
|
vdup(), vpush64(t, p->v2);
|
||||||
gen_op(TOK_LE);
|
if (l2 == 0 && p->v1 == p->v2) {
|
||||||
e = gvtst(1, 0);
|
gen_op(TOK_EQ); /* jmp to case when equal */
|
||||||
vdup();
|
gsym_addr(gvtst(0, 0), p->ind);
|
||||||
if (ll)
|
|
||||||
vpushll(p->v1);
|
|
||||||
else
|
|
||||||
vpushi(p->v1);
|
|
||||||
gen_op(TOK_GE);
|
|
||||||
gtst_addr(0, p->sym); /* v1 <= x <= v2 */
|
|
||||||
/* x < v1 */
|
|
||||||
gcase(base, len/2, bsym);
|
|
||||||
/* x > v2 */
|
|
||||||
gsym(e);
|
|
||||||
e = len/2 + 1;
|
|
||||||
base += e; len -= e;
|
|
||||||
}
|
|
||||||
/* linear scan */
|
|
||||||
while (len--) {
|
|
||||||
p = *base++;
|
|
||||||
vdup();
|
|
||||||
if (ll)
|
|
||||||
vpushll(p->v2);
|
|
||||||
else
|
|
||||||
vpushi(p->v2);
|
|
||||||
if (p->v1 == p->v2) {
|
|
||||||
gen_op(TOK_EQ);
|
|
||||||
gtst_addr(0, p->sym);
|
|
||||||
} else {
|
} else {
|
||||||
gen_op(TOK_LE);
|
/* case v1 ... v2 */
|
||||||
e = gvtst(1, 0);
|
gen_op(TOK_GT); /* jmp over when > V2 */
|
||||||
vdup();
|
if (len == 1) /* last case test jumps to default when false */
|
||||||
if (ll)
|
dsym = gvtst(0, dsym), e = 0;
|
||||||
vpushll(p->v1);
|
|
||||||
else
|
else
|
||||||
vpushi(p->v1);
|
e = gvtst(0, 0);
|
||||||
gen_op(TOK_GE);
|
vdup(), vpush64(t, p->v1);
|
||||||
gtst_addr(0, p->sym);
|
gen_op(TOK_GE); /* jmp to case when >= V1 */
|
||||||
|
gsym_addr(gvtst(0, 0), p->ind);
|
||||||
|
dsym = gcase(base, l2, dsym);
|
||||||
gsym(e);
|
gsym(e);
|
||||||
}
|
}
|
||||||
|
++l2, base += l2, len -= l2;
|
||||||
}
|
}
|
||||||
*bsym = gjmp(*bsym);
|
/* jump automagically will suppress more jumps */
|
||||||
|
return gjmp(dsym);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_switch(void)
|
static void end_switch(void)
|
||||||
|
@ -6791,8 +6792,8 @@ static void try_call_scope_cleanup(Sym *stop)
|
||||||
{
|
{
|
||||||
Sym *cls = cur_scope->cl.s;
|
Sym *cls = cur_scope->cl.s;
|
||||||
|
|
||||||
for (; cls != stop; cls = cls->ncl) {
|
for (; cls != stop; cls = cls->next) {
|
||||||
Sym *fs = cls->next;
|
Sym *fs = cls->cleanup_func;
|
||||||
Sym *vs = cls->prev_tok;
|
Sym *vs = cls->prev_tok;
|
||||||
|
|
||||||
vpushsym(&fs->type, fs);
|
vpushsym(&fs->type, fs);
|
||||||
|
@ -6814,11 +6815,11 @@ static void try_call_cleanup_goto(Sym *cleanupstate)
|
||||||
|
|
||||||
/* search NCA of both cleanup chains given parents and initial depth */
|
/* search NCA of both cleanup chains given parents and initial depth */
|
||||||
ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
|
ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
|
||||||
for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
|
for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->next)
|
||||||
;
|
;
|
||||||
for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl)
|
for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->next)
|
||||||
;
|
;
|
||||||
for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
|
for (; cc != oc; cc = cc->next, oc = oc->next, --ccd)
|
||||||
;
|
;
|
||||||
|
|
||||||
try_call_scope_cleanup(cc);
|
try_call_scope_cleanup(cc);
|
||||||
|
@ -7153,6 +7154,8 @@ again:
|
||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
|
if (!is_integer_btype(vtop->type.t & VT_BTYPE))
|
||||||
|
tcc_error("switch value not an integer");
|
||||||
sw->sv = *vtop--; /* save switch value */
|
sw->sv = *vtop--; /* save switch value */
|
||||||
a = 0;
|
a = 0;
|
||||||
b = gjmp(0); /* jump to first case */
|
b = gjmp(0); /* jump to first case */
|
||||||
|
@ -7161,21 +7164,13 @@ again:
|
||||||
/* case lookup */
|
/* case lookup */
|
||||||
gsym(b);
|
gsym(b);
|
||||||
prev_scope_s(&o);
|
prev_scope_s(&o);
|
||||||
|
|
||||||
if (sw->nocode_wanted)
|
if (sw->nocode_wanted)
|
||||||
goto skip_switch;
|
goto skip_switch;
|
||||||
if (sw->sv.type.t & VT_UNSIGNED)
|
case_sort(sw);
|
||||||
qsort(sw->p, sw->n, sizeof(void*), case_cmpu);
|
sw->bsym = NULL; /* marker for 32bit:gen_opl() */
|
||||||
else
|
|
||||||
qsort(sw->p, sw->n, sizeof(void*), case_cmpi);
|
|
||||||
for (b = 1; b < sw->n; b++)
|
|
||||||
if (sw->sv.type.t & VT_UNSIGNED
|
|
||||||
? (uint64_t)sw->p[b - 1]->v2 >= (uint64_t)sw->p[b]->v1
|
|
||||||
: sw->p[b - 1]->v2 >= sw->p[b]->v1)
|
|
||||||
tcc_error("duplicate case value");
|
|
||||||
vpushv(&sw->sv);
|
vpushv(&sw->sv);
|
||||||
gv(RC_INT);
|
gv(RC_INT);
|
||||||
d = 0, gcase(sw->p, sw->n, &d);
|
d = gcase(sw->p, sw->n, 0);
|
||||||
vpop();
|
vpop();
|
||||||
if (sw->def_sym)
|
if (sw->def_sym)
|
||||||
gsym_addr(d, sw->def_sym);
|
gsym_addr(d, sw->def_sym);
|
||||||
|
@ -7192,17 +7187,18 @@ again:
|
||||||
expect("switch");
|
expect("switch");
|
||||||
cr = tcc_malloc(sizeof(struct case_t));
|
cr = tcc_malloc(sizeof(struct case_t));
|
||||||
dynarray_add(&cur_switch->p, &cur_switch->n, cr);
|
dynarray_add(&cur_switch->p, &cur_switch->n, cr);
|
||||||
cr->v1 = cr->v2 = expr_const64();
|
t = cur_switch->sv.type.t;
|
||||||
if (gnu_ext && tok == TOK_DOTS) {
|
cr->v1 = cr->v2 = value64(expr_const64(), t);
|
||||||
|
if (tok == TOK_DOTS && gnu_ext) {
|
||||||
next();
|
next();
|
||||||
cr->v2 = expr_const64();
|
cr->v2 = value64(expr_const64(), t);
|
||||||
if ((!(cur_switch->sv.type.t & VT_UNSIGNED) && cr->v2 < cr->v1)
|
if (case_cmp(cr->v2, cr->v1) < 0)
|
||||||
|| (cur_switch->sv.type.t & VT_UNSIGNED && (uint64_t)cr->v2 < (uint64_t)cr->v1))
|
|
||||||
tcc_warning("empty case range");
|
tcc_warning("empty case range");
|
||||||
}
|
}
|
||||||
/* case and default are unreachable from a switch under nocode_wanted */
|
/* case and default are unreachable from a switch under nocode_wanted */
|
||||||
if (!cur_switch->nocode_wanted)
|
if (!cur_switch->nocode_wanted)
|
||||||
cr->sym = gind();
|
cr->ind = gind();
|
||||||
|
cr->line = file->line_num;
|
||||||
skip(':');
|
skip(':');
|
||||||
goto block_after_label;
|
goto block_after_label;
|
||||||
|
|
||||||
|
@ -7211,7 +7207,7 @@ again:
|
||||||
expect("switch");
|
expect("switch");
|
||||||
if (cur_switch->def_sym)
|
if (cur_switch->def_sym)
|
||||||
tcc_error("too many 'default'");
|
tcc_error("too many 'default'");
|
||||||
cur_switch->def_sym = cur_switch->nocode_wanted ? 1 : gind();
|
cur_switch->def_sym = cur_switch->nocode_wanted ? -1 : gind();
|
||||||
skip(':');
|
skip(':');
|
||||||
goto block_after_label;
|
goto block_after_label;
|
||||||
|
|
||||||
|
@ -7244,7 +7240,7 @@ again:
|
||||||
s->jnext = gjmp(s->jnext);
|
s->jnext = gjmp(s->jnext);
|
||||||
} else {
|
} else {
|
||||||
try_call_cleanup_goto(s->cleanupstate);
|
try_call_cleanup_goto(s->cleanupstate);
|
||||||
gjmp_addr(s->jnext);
|
gjmp_addr(s->jind);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
|
|
||||||
|
@ -7275,7 +7271,7 @@ again:
|
||||||
} else {
|
} else {
|
||||||
s = label_push(&global_label_stack, t, LABEL_DEFINED);
|
s = label_push(&global_label_stack, t, LABEL_DEFINED);
|
||||||
}
|
}
|
||||||
s->jnext = gind();
|
s->jind = gind();
|
||||||
s->cleanupstate = cur_scope->cl.s;
|
s->cleanupstate = cur_scope->cl.s;
|
||||||
|
|
||||||
block_after_label:
|
block_after_label:
|
||||||
|
@ -8132,8 +8128,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||||
Sym *cls = sym_push2(&all_cleanups,
|
Sym *cls = sym_push2(&all_cleanups,
|
||||||
SYM_FIELD | ++cur_scope->cl.n, 0, 0);
|
SYM_FIELD | ++cur_scope->cl.n, 0, 0);
|
||||||
cls->prev_tok = sym;
|
cls->prev_tok = sym;
|
||||||
cls->next = ad->cleanup_func;
|
cls->cleanup_func = ad->cleanup_func;
|
||||||
cls->ncl = cur_scope->cl.s;
|
cls->next = cur_scope->cl.s;
|
||||||
cur_scope->cl.s = cls;
|
cur_scope->cl.s = cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -490,4 +490,20 @@ int *invalid_operation(int *p, double d)
|
||||||
return p + d;
|
return p + d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined test_duplicate_case
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
unsigned int x;
|
||||||
|
switch (x) {
|
||||||
|
case -1 ... 0: /* empty case range with unsigned */
|
||||||
|
case 3:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3: /* show this line number in error */
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -240,3 +240,7 @@ arg[1] = "Y"
|
||||||
|
|
||||||
[test_pointer_plus_double]
|
[test_pointer_plus_double]
|
||||||
60_errors_and_warnings.c:490: error: invalid operand types for binary operation
|
60_errors_and_warnings.c:490: error: invalid operand types for binary operation
|
||||||
|
|
||||||
|
[test_duplicate_case]
|
||||||
|
60_errors_and_warnings.c:499: warning: empty case range
|
||||||
|
60_errors_and_warnings.c:507: error: duplicate case value
|
||||||
|
|
Loading…
Add table
Reference in a new issue