History

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

grischka committed 1 year ago

Commit c717bac1 parent f0cd0fb5 files · +125 −103Browse files

Unified · Split

5 files
  1. libtcc.c +6 −2
  2. tcc.h +3 −1
  3. tccgen.c +96 −100
  4. tests/tests2/60_errors_and_warnings.c +16 −0
  5. tests/tests2/60_errors_and_warnings.expect +4 −0
libtcc.c+6−2
@@ -567,6 +567,7 @@ static void error1(int mode, const char *fmt, va_list ap) · 566 unmodified lines
567567 BufferedFile **pf, *f;
568568 TCCState *s1 = tcc_state;
569569 CString cs;
570+ int line = 0;
570571
571572 tcc_exit_state(s1);
572573
@@ -589,6 +590,8 @@ static void error1(int mode, const char *fmt, va_list ap) · 16 unmodified lines
589590 }
590591
591592 cstr_new(&cs);
593+ if (fmt[0] == '%' && fmt[1] == 'i' && fmt[2] == ':')
594+ line = va_arg(ap, int), fmt += 3;
592595 f = NULL;
593596 if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */
594597 /* use upper file if inline ":asm:" or token ":paste:" */
@@ -599,8 +602,9 @@ static void error1(int mode, const char *fmt, va_list ap) · 4 unmodified lines
599602 for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
600603 cstr_printf(&cs, "In file included from %s:%d:\n",
601604 (*pf)->filename, (*pf)->line_num - 1);
602− cstr_printf(&cs, "%s:%d: ",
603− f->filename, f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr));
605+ if (0 == line)
606+ line = f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr);
607+ cstr_printf(&cs, "%s:%d: ", f->filename, line);
604608 } else if (s1->current_filename) {
605609 cstr_printf(&cs, "%s: ", s1->current_filename);
606610 } else {
tcc.h+3−1
@@ -564,14 +564,16 @@ typedef struct Sym { · 563 unmodified lines
564564 union {
565565 int sym_scope; /* scope level for locals */
566566 int jnext; /* next jump label */
567+ int jind; /* label position */
567568 struct FuncAttr f; /* function attributes */
568569 int auxtype; /* bitfield access type */
569570 };
570571 };
571572 long long enum_val; /* enum constant if IS_ENUM_VAL */
572573 int *d; /* define token stream */
573− struct Sym *ncl; /* next cleanup */
574+ struct Sym *cleanup_func;
574575 };
576+
575577 CType type; /* associated type */
576578 union {
577579 struct Sym *next; /* next related symbol (for fields and anoms) */
tccgen.c+96−100
@@ -90,7 +90,7 @@ static CString initstr; · 89 unmodified lines
9090 static struct switch_t {
9191 struct case_t {
9292 int64_t v1, v2;
93− int sym;
93+ int ind, line;
9494 } **p; int n; /* list of case ranges */
9595 int def_sym; /* default symbol */
9696 int nocode_wanted;
@@ -2236,7 +2236,11 @@ static void gen_opl(int op) · 2139 unmodified lines
22362236 vtop[-1] = vtop[-2];
22372237 vtop[-2] = tmp;
22382238 /* stack: L1 L2 H1 H2 */
2239− save_regs(4);
2239+ if (!cur_switch || cur_switch->bsym) {
2240+ /* avoid differnt registers being saved in branches.
2241+ This is not needed when comparing switch cases */
2242+ save_regs(4);
2243+ }
22402244 /* compare high */
22412245 op1 = op;
22422246 /* when values are equal, we need to compare low words. since
@@ -2285,6 +2289,18 @@ static void gen_opl(int op) · 42 unmodified lines
22852289 }
22862290 #endif
22872291
2292+/* normalize values */
2293+static uint64_t value64(uint64_t l1, int t)
2294+{
2295+ if ((t & VT_BTYPE) == VT_LLONG
2296+ || (PTR_SIZE == 8 && (t & VT_BTYPE) == VT_PTR))
2297+ return l1;
2298+ else if (t & VT_UNSIGNED)
2299+ return (uint32_t)l1;
2300+ else
2301+ return (uint32_t)l1 | -(l1 & 0x80000000);
2302+}
2303+
22882304 static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b)
22892305 {
22902306 uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b);
@@ -2306,18 +2322,11 @@ static void gen_opic(int op) · 15 unmodified lines
23062322 int t2 = v2->type.t & VT_BTYPE;
23072323 int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
23082324 int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
2309− uint64_t l1 = c1 ? v1->c.i : 0;
2310− uint64_t l2 = c2 ? v2->c.i : 0;
2325+ uint64_t l1 = c1 ? value64(v1->c.i, v1->type.t) : 0;
2326+ uint64_t l2 = c2 ? value64(v2->c.i, v2->type.t) : 0;
23112327 int shm = (t1 == VT_LLONG) ? 63 : 31;
23122328 int r;
23132329
2314− if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR))
2315− l1 = ((uint32_t)l1 |
2316− (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000)));
2317− if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR))
2318− l2 = ((uint32_t)l2 |
2319− (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000)));
2320−
23212330 if (c1 && c2) {
23222331 switch(op) {
23232332 case '+': l1 += l2; break;
@@ -2367,10 +2376,7 @@ static void gen_opic(int op) · 43 unmodified lines
23672376 default:
23682377 goto general_case;
23692378 }
2370− if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR))
2371− l1 = ((uint32_t)l1 |
2372− (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000)));
2373− v1->c.i = l1;
2379+ v1->c.i = value64(l1, v1->type.t);
23742380 v1->r |= v2->r & VT_NONCONST;
23752381 vtop--;
23762382 } else {
@@ -6701,79 +6707,74 @@ static void check_func_return(void) · 4324 unmodified lines
67016707 /* ------------------------------------------------------------------------- */
67026708 /* switch/case */
67036709
6704−static int case_cmpi(const void *pa, const void *pb)
6710+static int case_cmp(uint64_t a, uint64_t b)
67056711 {
6706− int64_t a = (*(struct case_t**) pa)->v1;
6707− int64_t b = (*(struct case_t**) pb)->v1;
6708− return a < b ? -1 : a > b;
6712+ if (cur_switch->sv.type.t & VT_UNSIGNED)
6713+ return a < b ? -1 : a > b;
6714+ else
6715+ return (int64_t)a < (int64_t)b ? -1 : (int64_t)a > (int64_t)b;
67096716 }
67106717
6711−static int case_cmpu(const void *pa, const void *pb)
6718+static int case_cmp_qs(const void *pa, const void *pb)
67126719 {
6713− uint64_t a = (uint64_t)(*(struct case_t**) pa)->v1;
6714− uint64_t b = (uint64_t)(*(struct case_t**) pb)->v1;
6715− return a < b ? -1 : a > b;
6720+ return case_cmp((*(struct case_t**)pa)->v1, (*(struct case_t**)pb)->v1);
67166721 }
67176722
6718−static void gtst_addr(int t, int a)
6723+static void case_sort(struct switch_t *sw)
67196724 {
6720− gsym_addr(gvtst(0, t), a);
6725+ struct case_t **p;
6726+ if (sw->n < 2)
6727+ return;
6728+ qsort(sw->p, sw->n, sizeof *sw->p, case_cmp_qs);
6729+ p = sw->p;
6730+ while (p < sw->p + sw->n - 1) {
6731+ if (case_cmp(p[0]->v2, p[1]->v1) >= 0) {
6732+ int l1 = p[0]->line, l2 = p[1]->line;
6733+ /* using special format "%i:..." to show specific line */
6734+ tcc_error("%i:duplicate case value", l1 > l2 ? l1 : l2);
6735+ } else if (p[0]->v2 + 1 == p[1]->v1 && p[0]->ind == p[1]->ind) {
6736+ /* treat "case 1: case 2: case 3:" like "case 1 ... 3: */
6737+ p[1]->v1 = p[0]->v1;
6738+ tcc_free(p[0]);
6739+ memmove(p, p + 1, (--sw->n - (p - sw->p)) * sizeof *p);
6740+ } else
6741+ ++p;
6742+ }
67216743 }
67226744
6723−static void gcase(struct case_t **base, int len, int *bsym)
6745+static int gcase(struct case_t **base, int len, int dsym)
67246746 {
67256747 struct case_t *p;
6726− int e;
6727− int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
6728− while (len > 8) {
6729− /* binary search */
6730− p = base[len/2];
6731− vdup();
6732− if (ll)
6733− vpushll(p->v2);
6734− else
6735− vpushi(p->v2);
6736− gen_op(TOK_LE);
6737− e = gvtst(1, 0);
6738− vdup();
6739− if (ll)
6740− vpushll(p->v1);
6741− else
6742− vpushi(p->v1);
6743− gen_op(TOK_GE);
6744− gtst_addr(0, p->sym); /* v1 <= x <= v2 */
6745− /* x < v1 */
6746− gcase(base, len/2, bsym);
6747− /* x > v2 */
6748− gsym(e);
6749− e = len/2 + 1;
6750− base += e; len -= e;
6751− }
6752− /* linear scan */
6753− while (len--) {
6754− p = *base++;
6755− vdup();
6756− if (ll)
6757− vpushll(p->v2);
6758− else
6759− vpushi(p->v2);
6760− if (p->v1 == p->v2) {
6761− gen_op(TOK_EQ);
6762− gtst_addr(0, p->sym);
6748+ int t, l2, e;
6749+
6750+ t = vtop->type.t & VT_BTYPE;
6751+ if (t != VT_LLONG)
6752+ t = VT_INT;
6753+ while (len) {
6754+ /* binary search while len > 8, else linear */
6755+ l2 = len > 8 ? len/2 : 0;
6756+ p = base[l2];
6757+ vdup(), vpush64(t, p->v2);
6758+ if (l2 == 0 && p->v1 == p->v2) {
6759+ gen_op(TOK_EQ); /* jmp to case when equal */
6760+ gsym_addr(gvtst(0, 0), p->ind);
67636761 } else {
6764− gen_op(TOK_LE);
6765− e = gvtst(1, 0);
6766− vdup();
6767− if (ll)
6768− vpushll(p->v1);
6769− else
6770− vpushi(p->v1);
6771− gen_op(TOK_GE);
6772− gtst_addr(0, p->sym);
6762+ /* case v1 ... v2 */
6763+ gen_op(TOK_GT); /* jmp over when > V2 */
6764+ if (len == 1) /* last case test jumps to default when false */
6765+ dsym = gvtst(0, dsym), e = 0;
6766+ else
6767+ e = gvtst(0, 0);
6768+ vdup(), vpush64(t, p->v1);
6769+ gen_op(TOK_GE); /* jmp to case when >= V1 */
6770+ gsym_addr(gvtst(0, 0), p->ind);
6771+ dsym = gcase(base, l2, dsym);
67736772 gsym(e);
67746773 }
6774+ ++l2, base += l2, len -= l2;
67756775 }
6776− *bsym = gjmp(*bsym);
6776+ /* jump automagically will suppress more jumps */
6777+ return gjmp(dsym);
67776778 }
67786779
67796780 static void end_switch(void)
@@ -6791,8 +6792,8 @@ static void try_call_scope_cleanup(Sym *stop) · 11 unmodified lines
67916792 {
67926793 Sym *cls = cur_scope->cl.s;
67936794
6794− for (; cls != stop; cls = cls->ncl) {
6795− Sym *fs = cls->next;
6795+ for (; cls != stop; cls = cls->next) {
6796+ Sym *fs = cls->cleanup_func;
67966797 Sym *vs = cls->prev_tok;
67976798
67986799 vpushsym(&fs->type, fs);
@@ -6814,11 +6815,11 @@ static void try_call_cleanup_goto(Sym *cleanupstate) · 15 unmodified lines
68146815
68156816 /* search NCA of both cleanup chains given parents and initial depth */
68166817 ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
6817− for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
6818+ for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->next)
68186819 ;
6819− for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl)
6820+ for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->next)
68206821 ;
6821− for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
6822+ for (; cc != oc; cc = cc->next, oc = oc->next, --ccd)
68226823 ;
68236824
68246825 try_call_scope_cleanup(cc);
@@ -7153,6 +7154,8 @@ again: · 328 unmodified lines
71537154 skip('(');
71547155 gexpr();
71557156 skip(')');
7157+ if (!is_integer_btype(vtop->type.t & VT_BTYPE))
7158+ tcc_error("switch value not an integer");
71567159 sw->sv = *vtop--; /* save switch value */
71577160 a = 0;
71587161 b = gjmp(0); /* jump to first case */
@@ -7161,21 +7164,13 @@ again: · 2 unmodified lines
71617164 /* case lookup */
71627165 gsym(b);
71637166 prev_scope_s(&o);
7164−
71657167 if (sw->nocode_wanted)
71667168 goto skip_switch;
7167− if (sw->sv.type.t & VT_UNSIGNED)
7168− qsort(sw->p, sw->n, sizeof(void*), case_cmpu);
7169− else
7170− qsort(sw->p, sw->n, sizeof(void*), case_cmpi);
7171− for (b = 1; b < sw->n; b++)
7172− if (sw->sv.type.t & VT_UNSIGNED
7173− ? (uint64_t)sw->p[b - 1]->v2 >= (uint64_t)sw->p[b]->v1
7174− : sw->p[b - 1]->v2 >= sw->p[b]->v1)
7175− tcc_error("duplicate case value");
7169+ case_sort(sw);
7170+ sw->bsym = NULL; /* marker for 32bit:gen_opl() */
71767171 vpushv(&sw->sv);
71777172 gv(RC_INT);
7178− d = 0, gcase(sw->p, sw->n, &d);
7173+ d = gcase(sw->p, sw->n, 0);
71797174 vpop();
71807175 if (sw->def_sym)
71817176 gsym_addr(d, sw->def_sym);
@@ -7192,17 +7187,18 @@ again: · 10 unmodified lines
71927187 expect("switch");
71937188 cr = tcc_malloc(sizeof(struct case_t));
71947189 dynarray_add(&cur_switch->p, &cur_switch->n, cr);
7195− cr->v1 = cr->v2 = expr_const64();
7196− if (gnu_ext && tok == TOK_DOTS) {
7190+ t = cur_switch->sv.type.t;
7191+ cr->v1 = cr->v2 = value64(expr_const64(), t);
7192+ if (tok == TOK_DOTS && gnu_ext) {
71977193 next();
7198− cr->v2 = expr_const64();
7199− if ((!(cur_switch->sv.type.t & VT_UNSIGNED) && cr->v2 < cr->v1)
7200− || (cur_switch->sv.type.t & VT_UNSIGNED && (uint64_t)cr->v2 < (uint64_t)cr->v1))
7194+ cr->v2 = value64(expr_const64(), t);
7195+ if (case_cmp(cr->v2, cr->v1) < 0)
72017196 tcc_warning("empty case range");
72027197 }
72037198 /* case and default are unreachable from a switch under nocode_wanted */
72047199 if (!cur_switch->nocode_wanted)
7205− cr->sym = gind();
7200+ cr->ind = gind();
7201+ cr->line = file->line_num;
72067202 skip(':');
72077203 goto block_after_label;
72087204
@@ -7211,7 +7207,7 @@ again: · 2 unmodified lines
72117207 expect("switch");
72127208 if (cur_switch->def_sym)
72137209 tcc_error("too many 'default'");
7214− cur_switch->def_sym = cur_switch->nocode_wanted ? 1 : gind();
7210+ cur_switch->def_sym = cur_switch->nocode_wanted ? -1 : gind();
72157211 skip(':');
72167212 goto block_after_label;
72177213
@@ -7244,7 +7240,7 @@ again: · 26 unmodified lines
72447240 s->jnext = gjmp(s->jnext);
72457241 } else {
72467242 try_call_cleanup_goto(s->cleanupstate);
7247− gjmp_addr(s->jnext);
7243+ gjmp_addr(s->jind);
72487244 }
72497245 next();
72507246
@@ -7275,7 +7271,7 @@ again: · 24 unmodified lines
72757271 } else {
72767272 s = label_push(&global_label_stack, t, LABEL_DEFINED);
72777273 }
7278− s->jnext = gind();
7274+ s->jind = gind();
72797275 s->cleanupstate = cur_scope->cl.s;
72807276
72817277 block_after_label:
@@ -8132,8 +8128,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 850 unmodified lines
81328128 Sym *cls = sym_push2(&all_cleanups,
81338129 SYM_FIELD | ++cur_scope->cl.n, 0, 0);
81348130 cls->prev_tok = sym;
8135− cls->next = ad->cleanup_func;
8136− cls->ncl = cur_scope->cl.s;
8131+ cls->cleanup_func = ad->cleanup_func;
8132+ cls->next = cur_scope->cl.s;
81378133 cur_scope->cl.s = cls;
81388134 }
81398135
tests/tests2/60_errors_and_warnings.c+16−0
@@ -490,4 +490,20 @@ int *invalid_operation(int *p, double d) · 489 unmodified lines
490490 return p + d;
491491 }
492492
493+#elif defined test_duplicate_case
494+
495+int main()
496+{
497+ unsigned int x;
498+ switch (x) {
499+ case -1 ... 0: /* empty case range with unsigned */
500+ case 3:
501+ case 1:
502+ case 2:
503+ case 3: /* show this line number in error */
504+ case 4:
505+ case 5:
506+ }
507+}
508+
493509 #endif
tests/tests2/60_errors_and_warnings.expect+4−0
@@ -240,3 +240,7 @@ arg[1] = "Y" · 239 unmodified lines
240240
241241 [test_pointer_plus_double]
242242 60_errors_and_warnings.c:490: error: invalid operand types for binary operation
243+
244+[test_duplicate_case]
245+60_errors_and_warnings.c:499: warning: empty case range
246+60_errors_and_warnings.c:507: error: duplicate case value

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t