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
567 BufferedFile **pf, *f;567 BufferedFile **pf, *f;
568 TCCState *s1 = tcc_state;568 TCCState *s1 = tcc_state;
569 CString cs;569 CString cs;
570 int line = 0;
570 571
571 tcc_exit_state(s1);572 tcc_exit_state(s1);
572 573
@@ -589,6 +590,8 @@ static void error1(int mode, const char *fmt, va_list ap) · 16 unmodified lines
589 }590 }
590 591
591 cstr_new(&cs);592 cstr_new(&cs);
593 if (fmt[0] == '%' && fmt[1] == 'i' && fmt[2] == ':')
594 line = va_arg(ap, int), fmt += 3;
592 f = NULL;595 f = NULL;
593 if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */596 if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */
594 /* use upper file if inline ":asm:" or token ":paste:" */597 /* 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
599 for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)602 for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
600 cstr_printf(&cs, "In file included from %s:%d:\n",603 cstr_printf(&cs, "In file included from %s:%d:\n",
601 (*pf)->filename, (*pf)->line_num - 1);604 (*pf)->filename, (*pf)->line_num - 1);
602 cstr_printf(&cs, "%s:%d: ",605 if (0 == line)
603 f->filename, f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr));606 line = f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr);
607 cstr_printf(&cs, "%s:%d: ", f->filename, line);
604 } else if (s1->current_filename) {608 } else if (s1->current_filename) {
605 cstr_printf(&cs, "%s: ", s1->current_filename);609 cstr_printf(&cs, "%s: ", s1->current_filename);
606 } else {610 } else {
tcc.h+3−1
@@ -564,14 +564,16 @@ typedef struct Sym { · 563 unmodified lines
564 union {564 union {
565 int sym_scope; /* scope level for locals */565 int sym_scope; /* scope level for locals */
566 int jnext; /* next jump label */566 int jnext; /* next jump label */
567 int jind; /* label position */
567 struct FuncAttr f; /* function attributes */568 struct FuncAttr f; /* function attributes */
568 int auxtype; /* bitfield access type */569 int auxtype; /* bitfield access type */
569 };570 };
570 };571 };
571 long long enum_val; /* enum constant if IS_ENUM_VAL */572 long long enum_val; /* enum constant if IS_ENUM_VAL */
572 int *d; /* define token stream */573 int *d; /* define token stream */
573 struct Sym *ncl; /* next cleanup */574 struct Sym *cleanup_func;
574 };575 };
576
575 CType type; /* associated type */577 CType type; /* associated type */
576 union {578 union {
577 struct Sym *next; /* next related symbol (for fields and anoms) */579 struct Sym *next; /* next related symbol (for fields and anoms) */
tccgen.c+96−100
@@ -90,7 +90,7 @@ static CString initstr; · 89 unmodified lines
90static struct switch_t {90static struct switch_t {
91 struct case_t {91 struct case_t {
92 int64_t v1, v2;92 int64_t v1, v2;
93 int sym;93 int ind, line;
94 } **p; int n; /* list of case ranges */94 } **p; int n; /* list of case ranges */
95 int def_sym; /* default symbol */95 int def_sym; /* default symbol */
96 int nocode_wanted;96 int nocode_wanted;
@@ -2236,7 +2236,11 @@ static void gen_opl(int op) · 2139 unmodified lines
2236 vtop[-1] = vtop[-2];2236 vtop[-1] = vtop[-2];
2237 vtop[-2] = tmp;2237 vtop[-2] = tmp;
2238 /* stack: L1 L2 H1 H2 */2238 /* 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 }
2240 /* compare high */2244 /* compare high */
2241 op1 = op;2245 op1 = op;
2242 /* when values are equal, we need to compare low words. since2246 /* when values are equal, we need to compare low words. since
@@ -2285,6 +2289,18 @@ static void gen_opl(int op) · 42 unmodified lines
2285}2289}
2286#endif2290#endif
2287 2291
2292/* normalize values */
2293static 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
2288static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b)2304static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b)
2289{2305{
2290 uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b);2306 uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b);
@@ -2306,18 +2322,11 @@ static void gen_opic(int op) · 15 unmodified lines
2306 int t2 = v2->type.t & VT_BTYPE;2322 int t2 = v2->type.t & VT_BTYPE;
2307 int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;2323 int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
2308 int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;2324 int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
2309 uint64_t l1 = c1 ? v1->c.i : 0;2325 uint64_t l1 = c1 ? value64(v1->c.i, v1->type.t) : 0;
2310 uint64_t l2 = c2 ? v2->c.i : 0;2326 uint64_t l2 = c2 ? value64(v2->c.i, v2->type.t) : 0;
2311 int shm = (t1 == VT_LLONG) ? 63 : 31;2327 int shm = (t1 == VT_LLONG) ? 63 : 31;
2312 int r;2328 int r;
2313 2329
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
2321 if (c1 && c2) {2330 if (c1 && c2) {
2322 switch(op) {2331 switch(op) {
2323 case '+': l1 += l2; break;2332 case '+': l1 += l2; break;
@@ -2367,10 +2376,7 @@ static void gen_opic(int op) · 43 unmodified lines
2367 default:2376 default:
2368 goto general_case;2377 goto general_case;
2369 }2378 }
2370 if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR))2379 v1->c.i = value64(l1, v1->type.t);
2371 l1 = ((uint32_t)l1 |
2372 (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000)));
2373 v1->c.i = l1;
2374 v1->r |= v2->r & VT_NONCONST;2380 v1->r |= v2->r & VT_NONCONST;
2375 vtop--;2381 vtop--;
2376 } else {2382 } else {
@@ -6701,79 +6707,74 @@ static void check_func_return(void) · 4324 unmodified lines
6701/* ------------------------------------------------------------------------- */6707/* ------------------------------------------------------------------------- */
6702/* switch/case */6708/* switch/case */
6703 6709
6704static int case_cmpi(const void *pa, const void *pb)6710static int case_cmp(uint64_t a, uint64_t b)
6705{6711{
6706 int64_t a = (*(struct case_t**) pa)->v1;6712 if (cur_switch->sv.type.t & VT_UNSIGNED)
6707 int64_t b = (*(struct case_t**) pb)->v1;6713 return a < b ? -1 : a > b;
6708 return a < b ? -1 : a > b;6714 else
6715 return (int64_t)a < (int64_t)b ? -1 : (int64_t)a > (int64_t)b;
6709}6716}
6710 6717
6711static int case_cmpu(const void *pa, const void *pb)6718static int case_cmp_qs(const void *pa, const void *pb)
6712{6719{
6713 uint64_t a = (uint64_t)(*(struct case_t**) pa)->v1;6720 return case_cmp((*(struct case_t**)pa)->v1, (*(struct case_t**)pb)->v1);
6714 uint64_t b = (uint64_t)(*(struct case_t**) pb)->v1;
6715 return a < b ? -1 : a > b;
6716}6721}
6717 6722
6718static void gtst_addr(int t, int a)6723static void case_sort(struct switch_t *sw)
6719{6724{
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 }
6721}6743}
6722 6744
6723static void gcase(struct case_t **base, int len, int *bsym)6745static int gcase(struct case_t **base, int len, int dsym)
6724{6746{
6725 struct case_t *p;6747 struct case_t *p;
6726 int e;6748 int t, l2, e;
6727 int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;6749
6728 while (len > 8) {6750 t = vtop->type.t & VT_BTYPE;
6729 /* binary search */6751 if (t != VT_LLONG)
6730 p = base[len/2];6752 t = VT_INT;
6731 vdup();6753 while (len) {
6732 if (ll)6754 /* binary search while len > 8, else linear */
6733 vpushll(p->v2);6755 l2 = len > 8 ? len/2 : 0;
6734 else6756 p = base[l2];
6735 vpushi(p->v2);6757 vdup(), vpush64(t, p->v2);
6736 gen_op(TOK_LE);6758 if (l2 == 0 && p->v1 == p->v2) {
6737 e = gvtst(1, 0);6759 gen_op(TOK_EQ); /* jmp to case when equal */
6738 vdup();6760 gsym_addr(gvtst(0, 0), p->ind);
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);
6763 } else {6761 } else {
6764 gen_op(TOK_LE);6762 /* case v1 ... v2 */
6765 e = gvtst(1, 0);6763 gen_op(TOK_GT); /* jmp over when > V2 */
6766 vdup();6764 if (len == 1) /* last case test jumps to default when false */
6767 if (ll)6765 dsym = gvtst(0, dsym), e = 0;
6768 vpushll(p->v1);6766 else
6769 else6767 e = gvtst(0, 0);
6770 vpushi(p->v1);6768 vdup(), vpush64(t, p->v1);
6771 gen_op(TOK_GE);6769 gen_op(TOK_GE); /* jmp to case when >= V1 */
6772 gtst_addr(0, p->sym);6770 gsym_addr(gvtst(0, 0), p->ind);
6771 dsym = gcase(base, l2, dsym);
6773 gsym(e);6772 gsym(e);
6774 }6773 }
6774 ++l2, base += l2, len -= l2;
6775 }6775 }
6776 *bsym = gjmp(*bsym);6776 /* jump automagically will suppress more jumps */
6777 return gjmp(dsym);
6777}6778}
6778 6779
6779static void end_switch(void)6780static void end_switch(void)
@@ -6791,8 +6792,8 @@ static void try_call_scope_cleanup(Sym *stop) · 11 unmodified lines
6791{6792{
6792 Sym *cls = cur_scope->cl.s;6793 Sym *cls = cur_scope->cl.s;
6793 6794
6794 for (; cls != stop; cls = cls->ncl) {6795 for (; cls != stop; cls = cls->next) {
6795 Sym *fs = cls->next;6796 Sym *fs = cls->cleanup_func;
6796 Sym *vs = cls->prev_tok;6797 Sym *vs = cls->prev_tok;
6797 6798
6798 vpushsym(&fs->type, fs);6799 vpushsym(&fs->type, fs);
@@ -6814,11 +6815,11 @@ static void try_call_cleanup_goto(Sym *cleanupstate) · 15 unmodified lines
6814 6815
6815 /* search NCA of both cleanup chains given parents and initial depth */6816 /* search NCA of both cleanup chains given parents and initial depth */
6816 ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;6817 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)
6818 ;6819 ;
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)
6820 ;6821 ;
6821 for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)6822 for (; cc != oc; cc = cc->next, oc = oc->next, --ccd)
6822 ;6823 ;
6823 6824
6824 try_call_scope_cleanup(cc);6825 try_call_scope_cleanup(cc);
@@ -7153,6 +7154,8 @@ again: · 328 unmodified lines
7153 skip('(');7154 skip('(');
7154 gexpr();7155 gexpr();
7155 skip(')');7156 skip(')');
7157 if (!is_integer_btype(vtop->type.t & VT_BTYPE))
7158 tcc_error("switch value not an integer");
7156 sw->sv = *vtop--; /* save switch value */7159 sw->sv = *vtop--; /* save switch value */
7157 a = 0;7160 a = 0;
7158 b = gjmp(0); /* jump to first case */7161 b = gjmp(0); /* jump to first case */
@@ -7161,21 +7164,13 @@ again: · 2 unmodified lines
7161 /* case lookup */7164 /* case lookup */
7162 gsym(b);7165 gsym(b);
7163 prev_scope_s(&o);7166 prev_scope_s(&o);
7164
7165 if (sw->nocode_wanted)7167 if (sw->nocode_wanted)
7166 goto skip_switch;7168 goto skip_switch;
7167 if (sw->sv.type.t & VT_UNSIGNED)7169 case_sort(sw);
7168 qsort(sw->p, sw->n, sizeof(void*), case_cmpu);7170 sw->bsym = NULL; /* marker for 32bit:gen_opl() */
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");
7176 vpushv(&sw->sv);7171 vpushv(&sw->sv);
7177 gv(RC_INT);7172 gv(RC_INT);
7178 d = 0, gcase(sw->p, sw->n, &d);7173 d = gcase(sw->p, sw->n, 0);
7179 vpop();7174 vpop();
7180 if (sw->def_sym)7175 if (sw->def_sym)
7181 gsym_addr(d, sw->def_sym);7176 gsym_addr(d, sw->def_sym);
@@ -7192,17 +7187,18 @@ again: · 10 unmodified lines
7192 expect("switch");7187 expect("switch");
7193 cr = tcc_malloc(sizeof(struct case_t));7188 cr = tcc_malloc(sizeof(struct case_t));
7194 dynarray_add(&cur_switch->p, &cur_switch->n, cr);7189 dynarray_add(&cur_switch->p, &cur_switch->n, cr);
7195 cr->v1 = cr->v2 = expr_const64();7190 t = cur_switch->sv.type.t;
7196 if (gnu_ext && tok == TOK_DOTS) {7191 cr->v1 = cr->v2 = value64(expr_const64(), t);
7192 if (tok == TOK_DOTS && gnu_ext) {
7197 next();7193 next();
7198 cr->v2 = expr_const64();7194 cr->v2 = value64(expr_const64(), t);
7199 if ((!(cur_switch->sv.type.t & VT_UNSIGNED) && cr->v2 < cr->v1)7195 if (case_cmp(cr->v2, cr->v1) < 0)
7200 || (cur_switch->sv.type.t & VT_UNSIGNED && (uint64_t)cr->v2 < (uint64_t)cr->v1))
7201 tcc_warning("empty case range");7196 tcc_warning("empty case range");
7202 }7197 }
7203 /* case and default are unreachable from a switch under nocode_wanted */7198 /* case and default are unreachable from a switch under nocode_wanted */
7204 if (!cur_switch->nocode_wanted)7199 if (!cur_switch->nocode_wanted)
7205 cr->sym = gind();7200 cr->ind = gind();
7201 cr->line = file->line_num;
7206 skip(':');7202 skip(':');
7207 goto block_after_label;7203 goto block_after_label;
7208 7204
@@ -7211,7 +7207,7 @@ again: · 2 unmodified lines
7211 expect("switch");7207 expect("switch");
7212 if (cur_switch->def_sym)7208 if (cur_switch->def_sym)
7213 tcc_error("too many 'default'");7209 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();
7215 skip(':');7211 skip(':');
7216 goto block_after_label;7212 goto block_after_label;
7217 7213
@@ -7244,7 +7240,7 @@ again: · 26 unmodified lines
7244 s->jnext = gjmp(s->jnext);7240 s->jnext = gjmp(s->jnext);
7245 } else {7241 } else {
7246 try_call_cleanup_goto(s->cleanupstate);7242 try_call_cleanup_goto(s->cleanupstate);
7247 gjmp_addr(s->jnext);7243 gjmp_addr(s->jind);
7248 }7244 }
7249 next();7245 next();
7250 7246
@@ -7275,7 +7271,7 @@ again: · 24 unmodified lines
7275 } else {7271 } else {
7276 s = label_push(&global_label_stack, t, LABEL_DEFINED);7272 s = label_push(&global_label_stack, t, LABEL_DEFINED);
7277 }7273 }
7278 s->jnext = gind();7274 s->jind = gind();
7279 s->cleanupstate = cur_scope->cl.s;7275 s->cleanupstate = cur_scope->cl.s;
7280 7276
7281 block_after_label:7277 block_after_label:
@@ -8132,8 +8128,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 850 unmodified lines
8132 Sym *cls = sym_push2(&all_cleanups,8128 Sym *cls = sym_push2(&all_cleanups,
8133 SYM_FIELD | ++cur_scope->cl.n, 0, 0);8129 SYM_FIELD | ++cur_scope->cl.n, 0, 0);
8134 cls->prev_tok = sym;8130 cls->prev_tok = sym;
8135 cls->next = ad->cleanup_func;8131 cls->cleanup_func = ad->cleanup_func;
8136 cls->ncl = cur_scope->cl.s;8132 cls->next = cur_scope->cl.s;
8137 cur_scope->cl.s = cls;8133 cur_scope->cl.s = cls;
8138 }8134 }
8139 8135
tests/tests2/60_errors_and_warnings.c+16−0
@@ -490,4 +490,20 @@ int *invalid_operation(int *p, double d) · 489 unmodified lines
490 return p + d;490 return p + d;
491}491}
492 492
493#elif defined test_duplicate_case
494
495int 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
493#endif509#endif
tests/tests2/60_errors_and_warnings.expect+4−0
@@ -240,3 +240,7 @@ arg[1] = "Y" · 239 unmodified lines
240 240
241[test_pointer_plus_double]241[test_pointer_plus_double]
24260_errors_and_warnings.c:490: error: invalid operand types for binary operation24260_errors_and_warnings.c:490: error: invalid operand types for binary operation
243
244[test_duplicate_case]
24560_errors_and_warnings.c:499: warning: empty case range
24660_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