more precise C type check support (const warnings) - added generic -W option support
This commit is contained in:
parent
0eef235475
commit
9791bfaf48
1 changed files with 272 additions and 91 deletions
327
tcc.c
327
tcc.c
|
@ -398,6 +398,11 @@ struct TCCState {
|
||||||
/* if true, static linking is performed */
|
/* if true, static linking is performed */
|
||||||
int static_link;
|
int static_link;
|
||||||
|
|
||||||
|
/* warning switches */
|
||||||
|
int warn_write_strings;
|
||||||
|
int warn_unsupported;
|
||||||
|
int warn_error;
|
||||||
|
|
||||||
/* error handling */
|
/* error handling */
|
||||||
void *error_opaque;
|
void *error_opaque;
|
||||||
void (*error_func)(void *opaque, const char *msg);
|
void (*error_func)(void *opaque, const char *msg);
|
||||||
|
@ -438,8 +443,6 @@ struct TCCState {
|
||||||
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
|
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
#define VT_STRUCT_SHIFT 12 /* structure/enum name shift (20 bits left) */
|
|
||||||
|
|
||||||
#define VT_INT 0 /* integer type */
|
#define VT_INT 0 /* integer type */
|
||||||
#define VT_BYTE 1 /* signed byte type */
|
#define VT_BYTE 1 /* signed byte type */
|
||||||
#define VT_SHORT 2 /* short type */
|
#define VT_SHORT 2 /* short type */
|
||||||
|
@ -459,6 +462,8 @@ struct TCCState {
|
||||||
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
||||||
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
|
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
|
||||||
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
||||||
|
#define VT_CONSTANT 0x0800 /* const modifier */
|
||||||
|
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
||||||
|
|
||||||
/* storage */
|
/* storage */
|
||||||
#define VT_EXTERN 0x00000080 /* extern definition */
|
#define VT_EXTERN 0x00000080 /* extern definition */
|
||||||
|
@ -466,6 +471,8 @@ struct TCCState {
|
||||||
#define VT_TYPEDEF 0x00000200 /* typedef definition */
|
#define VT_TYPEDEF 0x00000200 /* typedef definition */
|
||||||
#define VT_INLINE 0x00000400 /* inline definition */
|
#define VT_INLINE 0x00000400 /* inline definition */
|
||||||
|
|
||||||
|
#define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */
|
||||||
|
|
||||||
/* type mask (except storage) */
|
/* type mask (except storage) */
|
||||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
||||||
#define VT_TYPE (~(VT_STORAGE))
|
#define VT_TYPE (~(VT_STORAGE))
|
||||||
|
@ -531,6 +538,14 @@ struct TCCState {
|
||||||
#define TOK_A_SHL 0x81
|
#define TOK_A_SHL 0x81
|
||||||
#define TOK_A_SAR 0x82
|
#define TOK_A_SAR 0x82
|
||||||
|
|
||||||
|
#ifndef offsetof
|
||||||
|
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef countof
|
||||||
|
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
/* WARNING: the content of this string encodes token numbers */
|
/* WARNING: the content of this string encodes token numbers */
|
||||||
static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";
|
static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";
|
||||||
|
|
||||||
|
@ -678,9 +693,9 @@ static int type_size(CType *type, int *a);
|
||||||
static inline CType *pointed_type(CType *type);
|
static inline CType *pointed_type(CType *type);
|
||||||
static int pointed_size(CType *type);
|
static int pointed_size(CType *type);
|
||||||
static int lvalue_type(int t);
|
static int lvalue_type(int t);
|
||||||
static int is_compatible_types(CType *type1, CType *type2);
|
|
||||||
static int parse_btype(CType *type, AttributeDef *ad);
|
static int parse_btype(CType *type, AttributeDef *ad);
|
||||||
static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
|
static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
|
||||||
|
static int is_compatible_types(CType *type1, CType *type2);
|
||||||
|
|
||||||
void error(const char *fmt, ...);
|
void error(const char *fmt, ...);
|
||||||
void vpushi(int v);
|
void vpushi(int v);
|
||||||
|
@ -1166,7 +1181,7 @@ void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
|
||||||
} else {
|
} else {
|
||||||
s1->error_func(s1->error_opaque, buf);
|
s1->error_func(s1->error_opaque, buf);
|
||||||
}
|
}
|
||||||
if (!is_warning)
|
if (!is_warning || s1->warn_error)
|
||||||
s1->nb_errors++;
|
s1->nb_errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5085,20 +5100,66 @@ static int pointed_size(CType *type)
|
||||||
return type_size(pointed_type(type), &align);
|
return type_size(pointed_type(type), &align);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static inline int is_null_pointer(SValue *p)
|
||||||
void check_pointer_types(SValue *p1, SValue *p2)
|
|
||||||
{
|
{
|
||||||
char buf1[256], buf2[256];
|
if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
|
||||||
int t1, t2;
|
return 0;
|
||||||
t1 = p1->t;
|
return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) ||
|
||||||
t2 = p2->t;
|
((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0);
|
||||||
if (!is_compatible_types(t1, t2)) {
|
}
|
||||||
type_to_str(buf1, sizeof(buf1), t1, NULL);
|
|
||||||
type_to_str(buf2, sizeof(buf2), t2, NULL);
|
static inline int is_integer_btype(int bt)
|
||||||
error("incompatible pointers '%s' and '%s'", buf1, buf2);
|
{
|
||||||
|
return (bt == VT_BYTE || bt == VT_SHORT ||
|
||||||
|
bt == VT_INT || bt == VT_LLONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check types for comparison or substraction of pointers */
|
||||||
|
static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
|
||||||
|
{
|
||||||
|
CType *type1, *type2, tmp_type1, tmp_type2;
|
||||||
|
int bt1, bt2;
|
||||||
|
|
||||||
|
/* null pointers are accepted for all comparisons as gcc */
|
||||||
|
if (is_null_pointer(p1) || is_null_pointer(p2))
|
||||||
|
return;
|
||||||
|
type1 = &p1->type;
|
||||||
|
type2 = &p2->type;
|
||||||
|
bt1 = type1->t & VT_BTYPE;
|
||||||
|
bt2 = type2->t & VT_BTYPE;
|
||||||
|
/* accept comparison between pointer and integer with a warning */
|
||||||
|
if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') {
|
||||||
|
warning("comparison between pointer and integer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* both must be pointers or implicit function pointers */
|
||||||
|
if (bt1 == VT_PTR) {
|
||||||
|
type1 = pointed_type(type1);
|
||||||
|
} else if (bt1 != VT_FUNC)
|
||||||
|
goto invalid_operands;
|
||||||
|
|
||||||
|
if (bt2 == VT_PTR) {
|
||||||
|
type2 = pointed_type(type2);
|
||||||
|
} else if (bt2 != VT_FUNC) {
|
||||||
|
invalid_operands:
|
||||||
|
error("invalid operands to binary %s", get_tok_str(op, NULL));
|
||||||
|
}
|
||||||
|
if ((type1->t & VT_BTYPE) == VT_VOID ||
|
||||||
|
(type2->t & VT_BTYPE) == VT_VOID)
|
||||||
|
return;
|
||||||
|
tmp_type1 = *type1;
|
||||||
|
tmp_type2 = *type2;
|
||||||
|
tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
|
||||||
|
tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
|
||||||
|
if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
|
||||||
|
/* gcc-like error if '-' is used */
|
||||||
|
if (op == '-')
|
||||||
|
goto invalid_operands;
|
||||||
|
else
|
||||||
|
warning("comparison of distinct pointer types lacks a cast");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* generic gen_op: handles types problems */
|
/* generic gen_op: handles types problems */
|
||||||
void gen_op(int op)
|
void gen_op(int op)
|
||||||
|
@ -5115,7 +5176,7 @@ void gen_op(int op)
|
||||||
/* at least one operand is a pointer */
|
/* at least one operand is a pointer */
|
||||||
/* relationnal op: must be both pointers */
|
/* relationnal op: must be both pointers */
|
||||||
if (op >= TOK_ULT && op <= TOK_GT) {
|
if (op >= TOK_ULT && op <= TOK_GT) {
|
||||||
// check_pointer_types(vtop, vtop - 1);
|
check_comparison_pointer_types(vtop - 1, vtop, op);
|
||||||
/* pointers are handled are unsigned */
|
/* pointers are handled are unsigned */
|
||||||
t = VT_INT | VT_UNSIGNED;
|
t = VT_INT | VT_UNSIGNED;
|
||||||
goto std_op;
|
goto std_op;
|
||||||
|
@ -5124,7 +5185,7 @@ void gen_op(int op)
|
||||||
if (bt1 == VT_PTR && bt2 == VT_PTR) {
|
if (bt1 == VT_PTR && bt2 == VT_PTR) {
|
||||||
if (op != '-')
|
if (op != '-')
|
||||||
error("cannot use pointers here");
|
error("cannot use pointers here");
|
||||||
// check_pointer_types(vtop - 1, vtop);
|
check_comparison_pointer_types(vtop - 1, vtop, op);
|
||||||
/* XXX: check that types are compatible */
|
/* XXX: check that types are compatible */
|
||||||
u = pointed_size(&vtop[-1].type);
|
u = pointed_size(&vtop[-1].type);
|
||||||
gen_opic(op);
|
gen_opic(op);
|
||||||
|
@ -5511,33 +5572,11 @@ static void mk_pointer(CType *type)
|
||||||
type->ref = s;
|
type->ref = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_compatible_types(CType *type1, CType *type2)
|
/* compare function types. OLD functions match any new functions */
|
||||||
|
static int is_compatible_func(CType *type1, CType *type2)
|
||||||
{
|
{
|
||||||
Sym *s1, *s2;
|
Sym *s1, *s2;
|
||||||
int bt1, bt2, t1, t2;
|
|
||||||
|
|
||||||
t1 = type1->t & VT_TYPE;
|
|
||||||
t2 = type2->t & VT_TYPE;
|
|
||||||
bt1 = t1 & VT_BTYPE;
|
|
||||||
bt2 = t2 & VT_BTYPE;
|
|
||||||
if (bt1 == VT_PTR) {
|
|
||||||
type1 = pointed_type(type1);
|
|
||||||
/* if function, then convert implicitely to function pointer */
|
|
||||||
if (bt2 != VT_FUNC) {
|
|
||||||
if (bt2 != VT_PTR)
|
|
||||||
return 0;
|
|
||||||
type2 = pointed_type(type2);
|
|
||||||
}
|
|
||||||
/* void matches everything */
|
|
||||||
/* XXX: not fully compliant */
|
|
||||||
if ((type1->t & VT_TYPE) == VT_VOID || (type2->t & VT_TYPE) == VT_VOID)
|
|
||||||
return 1;
|
|
||||||
return is_compatible_types(type1, type2);
|
|
||||||
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
|
|
||||||
return (type1->ref == type2->ref);
|
|
||||||
} else if (bt1 == VT_FUNC) {
|
|
||||||
if (bt2 != VT_FUNC)
|
|
||||||
return 0;
|
|
||||||
s1 = type1->ref;
|
s1 = type1->ref;
|
||||||
s2 = type2->ref;
|
s2 = type2->ref;
|
||||||
if (!is_compatible_types(&s1->type, &s2->type))
|
if (!is_compatible_types(&s1->type, &s2->type))
|
||||||
|
@ -5558,8 +5597,33 @@ static int is_compatible_types(CType *type1, CType *type2)
|
||||||
if (s2)
|
if (s2)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return true if type1 and type2 are exactly the same (including
|
||||||
|
qualifiers).
|
||||||
|
|
||||||
|
- enums are not checked as gcc __builtin_types_compatible_p ()
|
||||||
|
*/
|
||||||
|
static int is_compatible_types(CType *type1, CType *type2)
|
||||||
|
{
|
||||||
|
int bt1, t1, t2;
|
||||||
|
|
||||||
|
t1 = type1->t & VT_TYPE;
|
||||||
|
t2 = type2->t & VT_TYPE;
|
||||||
|
/* XXX: bitfields ? */
|
||||||
|
if (t1 != t2)
|
||||||
|
return 0;
|
||||||
|
/* test more complicated cases */
|
||||||
|
bt1 = t1 & VT_BTYPE;
|
||||||
|
if (bt1 == VT_PTR) {
|
||||||
|
type1 = pointed_type(type1);
|
||||||
|
type2 = pointed_type(type2);
|
||||||
|
return is_compatible_types(type1, type2);
|
||||||
|
} else if (bt1 == VT_STRUCT) {
|
||||||
|
return (type1->ref == type2->ref);
|
||||||
|
} else if (bt1 == VT_FUNC) {
|
||||||
|
return is_compatible_func(type1, type2);
|
||||||
} else {
|
} else {
|
||||||
/* XXX: not complete */
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5579,6 +5643,10 @@ void type_to_str(char *buf, int buf_size,
|
||||||
t = type->t & VT_TYPE;
|
t = type->t & VT_TYPE;
|
||||||
bt = t & VT_BTYPE;
|
bt = t & VT_BTYPE;
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
|
if (t & VT_CONSTANT)
|
||||||
|
pstrcat(buf, buf_size, "const ");
|
||||||
|
if (t & VT_VOLATILE)
|
||||||
|
pstrcat(buf, buf_size, "volatile ");
|
||||||
if (t & VT_UNSIGNED)
|
if (t & VT_UNSIGNED)
|
||||||
pstrcat(buf, buf_size, "unsigned ");
|
pstrcat(buf, buf_size, "unsigned ");
|
||||||
switch(bt) {
|
switch(bt) {
|
||||||
|
@ -5660,46 +5728,73 @@ void type_to_str(char *buf, int buf_size,
|
||||||
casts if needed. */
|
casts if needed. */
|
||||||
static void gen_assign_cast(CType *dt)
|
static void gen_assign_cast(CType *dt)
|
||||||
{
|
{
|
||||||
CType *st;
|
CType *st, *type1, *type2, tmp_type1, tmp_type2;
|
||||||
char buf1[256], buf2[256];
|
char buf1[256], buf2[256];
|
||||||
int dbt, sbt;
|
int dbt, sbt;
|
||||||
|
|
||||||
st = &vtop->type; /* source type */
|
st = &vtop->type; /* source type */
|
||||||
dbt = dt->t & VT_BTYPE;
|
dbt = dt->t & VT_BTYPE;
|
||||||
sbt = st->t & VT_BTYPE;
|
sbt = st->t & VT_BTYPE;
|
||||||
if (dbt == VT_PTR) {
|
if (dt->t & VT_CONSTANT)
|
||||||
|
warning("assignment of read-only location");
|
||||||
|
switch(dbt) {
|
||||||
|
case VT_PTR:
|
||||||
/* special cases for pointers */
|
/* special cases for pointers */
|
||||||
|
/* '0' can also be a pointer */
|
||||||
|
if (is_null_pointer(vtop))
|
||||||
|
goto type_ok;
|
||||||
|
/* accept implicit pointer to integer cast with warning */
|
||||||
|
if (is_integer_btype(sbt)) {
|
||||||
|
warning("assignment makes pointer from integer without a cast");
|
||||||
|
goto type_ok;
|
||||||
|
}
|
||||||
|
type1 = pointed_type(dt);
|
||||||
/* a function is implicitely a function pointer */
|
/* a function is implicitely a function pointer */
|
||||||
if (sbt == VT_FUNC) {
|
if (sbt == VT_FUNC) {
|
||||||
if (!is_compatible_types(pointed_type(dt), st))
|
if ((type1->t & VT_BTYPE) != VT_VOID &&
|
||||||
|
!is_compatible_types(pointed_type(dt), st))
|
||||||
goto error;
|
goto error;
|
||||||
else
|
else
|
||||||
goto type_ok;
|
goto type_ok;
|
||||||
}
|
}
|
||||||
/* '0' can also be a pointer */
|
if (sbt != VT_PTR)
|
||||||
if (sbt == VT_INT &&
|
goto error;
|
||||||
((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) &&
|
type2 = pointed_type(st);
|
||||||
vtop->c.i == 0)
|
if ((type1->t & VT_BTYPE) == VT_VOID ||
|
||||||
goto type_ok;
|
(type2->t & VT_BTYPE) == VT_VOID) {
|
||||||
/* accept implicit pointer to integer cast with warning */
|
/* void * can match anything */
|
||||||
if (sbt == VT_BYTE || sbt == VT_SHORT ||
|
} else {
|
||||||
sbt == VT_INT || sbt == VT_LLONG) {
|
/* exact type match, except for unsigned */
|
||||||
warning("assignment makes pointer from integer without a cast");
|
tmp_type1 = *type1;
|
||||||
goto type_ok;
|
tmp_type2 = *type2;
|
||||||
|
tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
|
||||||
|
tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
|
||||||
|
if (!is_compatible_types(&tmp_type1, &tmp_type2))
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
} else if (dbt == VT_BYTE || dbt == VT_SHORT ||
|
/* check const and volatile */
|
||||||
dbt == VT_INT || dbt == VT_LLONG) {
|
if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) ||
|
||||||
|
(!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE)))
|
||||||
|
warning("assignment discards qualifiers from pointer target type");
|
||||||
|
break;
|
||||||
|
case VT_BYTE:
|
||||||
|
case VT_SHORT:
|
||||||
|
case VT_INT:
|
||||||
|
case VT_LLONG:
|
||||||
if (sbt == VT_PTR || sbt == VT_FUNC) {
|
if (sbt == VT_PTR || sbt == VT_FUNC) {
|
||||||
warning("assignment makes integer from pointer without a cast");
|
warning("assignment makes integer from pointer without a cast");
|
||||||
goto type_ok;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* XXX: more tests */
|
||||||
|
break;
|
||||||
|
case VT_STRUCT:
|
||||||
if (!is_compatible_types(dt, st)) {
|
if (!is_compatible_types(dt, st)) {
|
||||||
error:
|
error:
|
||||||
type_to_str(buf1, sizeof(buf1), st, NULL);
|
type_to_str(buf1, sizeof(buf1), st, NULL);
|
||||||
type_to_str(buf2, sizeof(buf2), dt, NULL);
|
type_to_str(buf2, sizeof(buf2), dt, NULL);
|
||||||
error("cannot cast '%s' to '%s'", buf1, buf2);
|
error("cannot cast '%s' to '%s'", buf1, buf2);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
type_ok:
|
type_ok:
|
||||||
gen_cast(dt);
|
gen_cast(dt);
|
||||||
}
|
}
|
||||||
|
@ -5717,6 +5812,9 @@ void vstore(void)
|
||||||
/* optimize char/short casts */
|
/* optimize char/short casts */
|
||||||
delayed_cast = VT_MUSTCAST;
|
delayed_cast = VT_MUSTCAST;
|
||||||
vtop->type.t = ft & VT_TYPE;
|
vtop->type.t = ft & VT_TYPE;
|
||||||
|
/* XXX: factorize */
|
||||||
|
if (ft & VT_CONSTANT)
|
||||||
|
warning("assignment of read-only location");
|
||||||
} else {
|
} else {
|
||||||
delayed_cast = 0;
|
delayed_cast = 0;
|
||||||
gen_assign_cast(&vtop[-1].type);
|
gen_assign_cast(&vtop[-1].type);
|
||||||
|
@ -5899,7 +5997,8 @@ static void parse_attribute(AttributeDef *ad)
|
||||||
ad->func_call = FUNC_STDCALL;
|
ad->func_call = FUNC_STDCALL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// warning("'%s' attribute ignored", get_tok_str(t, NULL));
|
if (tcc_state->warn_unsupported)
|
||||||
|
warning("'%s' attribute ignored", get_tok_str(t, NULL));
|
||||||
/* skip parameters */
|
/* skip parameters */
|
||||||
/* XXX: skip parenthesis too */
|
/* XXX: skip parenthesis too */
|
||||||
if (tok == '(') {
|
if (tok == '(') {
|
||||||
|
@ -5946,7 +6045,9 @@ static void struct_decl(CType *type, int u)
|
||||||
v = anon_sym++;
|
v = anon_sym++;
|
||||||
}
|
}
|
||||||
type1.t = a;
|
type1.t = a;
|
||||||
s = sym_push(v | SYM_STRUCT, &type1, 0, 0);
|
/* we put an undefined size for struct/union */
|
||||||
|
s = sym_push(v | SYM_STRUCT, &type1, 0, -1);
|
||||||
|
s->r = 0; /* default alignment is zero as gcc */
|
||||||
/* put struct/union/enum name in type */
|
/* put struct/union/enum name in type */
|
||||||
do_decl:
|
do_decl:
|
||||||
type->t = u;
|
type->t = u;
|
||||||
|
@ -5954,7 +6055,7 @@ static void struct_decl(CType *type, int u)
|
||||||
|
|
||||||
if (tok == '{') {
|
if (tok == '{') {
|
||||||
next();
|
next();
|
||||||
if (s->c)
|
if (s->c != -1)
|
||||||
error("struct/union/enum already defined");
|
error("struct/union/enum already defined");
|
||||||
/* cannot be empty */
|
/* cannot be empty */
|
||||||
c = 0;
|
c = 0;
|
||||||
|
@ -6169,9 +6270,15 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||||
case TOK_CONST1:
|
case TOK_CONST1:
|
||||||
case TOK_CONST2:
|
case TOK_CONST2:
|
||||||
case TOK_CONST3:
|
case TOK_CONST3:
|
||||||
|
t |= VT_CONSTANT;
|
||||||
|
next();
|
||||||
|
break;
|
||||||
case TOK_VOLATILE1:
|
case TOK_VOLATILE1:
|
||||||
case TOK_VOLATILE2:
|
case TOK_VOLATILE2:
|
||||||
case TOK_VOLATILE3:
|
case TOK_VOLATILE3:
|
||||||
|
t |= VT_VOLATILE;
|
||||||
|
next();
|
||||||
|
break;
|
||||||
case TOK_REGISTER:
|
case TOK_REGISTER:
|
||||||
case TOK_SIGNED1:
|
case TOK_SIGNED1:
|
||||||
case TOK_SIGNED2:
|
case TOK_SIGNED2:
|
||||||
|
@ -6303,7 +6410,9 @@ static void post_type(CType *type, AttributeDef *ad)
|
||||||
l = FUNC_OLD;
|
l = FUNC_OLD;
|
||||||
skip(')');
|
skip(')');
|
||||||
t1 = type->t & VT_STORAGE;
|
t1 = type->t & VT_STORAGE;
|
||||||
type->t &= ~VT_STORAGE;
|
/* NOTE: const is ignored in returned type as it has a special
|
||||||
|
meaning in gcc / C++ */
|
||||||
|
type->t &= ~(VT_STORAGE | VT_CONSTANT);
|
||||||
post_type(type, ad);
|
post_type(type, ad);
|
||||||
/* we push a anonymous symbol which will contain the function prototype */
|
/* we push a anonymous symbol which will contain the function prototype */
|
||||||
s = sym_push(SYM_FIELD, type, ad->func_call, l);
|
s = sym_push(SYM_FIELD, type, ad->func_call, l);
|
||||||
|
@ -6343,24 +6452,30 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td)
|
||||||
{
|
{
|
||||||
Sym *s;
|
Sym *s;
|
||||||
CType type1, *type2;
|
CType type1, *type2;
|
||||||
|
int qualifiers;
|
||||||
|
|
||||||
while (tok == '*') {
|
while (tok == '*') {
|
||||||
next();
|
qualifiers = 0;
|
||||||
redo:
|
redo:
|
||||||
|
next();
|
||||||
switch(tok) {
|
switch(tok) {
|
||||||
case TOK_CONST1:
|
case TOK_CONST1:
|
||||||
case TOK_CONST2:
|
case TOK_CONST2:
|
||||||
case TOK_CONST3:
|
case TOK_CONST3:
|
||||||
|
qualifiers |= VT_CONSTANT;
|
||||||
|
goto redo;
|
||||||
case TOK_VOLATILE1:
|
case TOK_VOLATILE1:
|
||||||
case TOK_VOLATILE2:
|
case TOK_VOLATILE2:
|
||||||
case TOK_VOLATILE3:
|
case TOK_VOLATILE3:
|
||||||
|
qualifiers |= VT_VOLATILE;
|
||||||
|
goto redo;
|
||||||
case TOK_RESTRICT1:
|
case TOK_RESTRICT1:
|
||||||
case TOK_RESTRICT2:
|
case TOK_RESTRICT2:
|
||||||
case TOK_RESTRICT3:
|
case TOK_RESTRICT3:
|
||||||
next();
|
|
||||||
goto redo;
|
goto redo;
|
||||||
}
|
}
|
||||||
mk_pointer(type);
|
mk_pointer(type);
|
||||||
|
type->t |= qualifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: clarify attribute handling */
|
/* XXX: clarify attribute handling */
|
||||||
|
@ -6557,6 +6672,8 @@ static void unary(void)
|
||||||
/* string parsing */
|
/* string parsing */
|
||||||
t = VT_BYTE;
|
t = VT_BYTE;
|
||||||
str_init:
|
str_init:
|
||||||
|
if (tcc_state->warn_write_strings)
|
||||||
|
t |= VT_CONSTANT;
|
||||||
type.t = t;
|
type.t = t;
|
||||||
mk_pointer(&type);
|
mk_pointer(&type);
|
||||||
type.t |= VT_ARRAY;
|
type.t |= VT_ARRAY;
|
||||||
|
@ -6652,10 +6769,13 @@ static void unary(void)
|
||||||
unary_type(&type);
|
unary_type(&type);
|
||||||
}
|
}
|
||||||
size = type_size(&type, &align);
|
size = type_size(&type, &align);
|
||||||
if (t == TOK_SIZEOF)
|
if (t == TOK_SIZEOF) {
|
||||||
|
if (size < 0)
|
||||||
|
error("sizeof applied to an incomplete type");
|
||||||
vpushi(size);
|
vpushi(size);
|
||||||
else
|
} else {
|
||||||
vpushi(align);
|
vpushi(align);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_INC:
|
case TOK_INC:
|
||||||
|
@ -7658,6 +7778,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c,
|
||||||
int saved_global_expr, bt, bit_pos, bit_size;
|
int saved_global_expr, bt, bit_pos, bit_size;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
unsigned long long bit_mask;
|
unsigned long long bit_mask;
|
||||||
|
CType dtype;
|
||||||
|
|
||||||
switch(expr_type) {
|
switch(expr_type) {
|
||||||
case EXPR_VAL:
|
case EXPR_VAL:
|
||||||
|
@ -7678,10 +7799,13 @@ static void init_putv(CType *type, Section *sec, unsigned long c,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtype = *type;
|
||||||
|
dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
|
||||||
|
|
||||||
if (sec) {
|
if (sec) {
|
||||||
/* XXX: not portable */
|
/* XXX: not portable */
|
||||||
/* XXX: generate error if incorrect relocation */
|
/* XXX: generate error if incorrect relocation */
|
||||||
gen_assign_cast(type);
|
gen_assign_cast(&dtype);
|
||||||
bt = type->t & VT_BTYPE;
|
bt = type->t & VT_BTYPE;
|
||||||
ptr = sec->data + c;
|
ptr = sec->data + c;
|
||||||
/* XXX: make code faster ? */
|
/* XXX: make code faster ? */
|
||||||
|
@ -7727,7 +7851,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c,
|
||||||
}
|
}
|
||||||
vtop--;
|
vtop--;
|
||||||
} else {
|
} else {
|
||||||
vset(type, VT_LOCAL, c);
|
vset(&dtype, VT_LOCAL, c);
|
||||||
vswap();
|
vswap();
|
||||||
vstore();
|
vstore();
|
||||||
vpop();
|
vpop();
|
||||||
|
@ -7884,8 +8008,10 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
||||||
if (!parse_btype(&type1, &ad1))
|
if (!parse_btype(&type1, &ad1))
|
||||||
expect("cast");
|
expect("cast");
|
||||||
type_decl(&type1, &ad1, &n, TYPE_ABSTRACT);
|
type_decl(&type1, &ad1, &n, TYPE_ABSTRACT);
|
||||||
if (!is_compatible_types(type, &type1))
|
#if 0
|
||||||
|
if (!is_assignable_types(type, &type1))
|
||||||
error("invalid type for cast");
|
error("invalid type for cast");
|
||||||
|
#endif
|
||||||
skip(')');
|
skip(')');
|
||||||
}
|
}
|
||||||
no_oblock = 1;
|
no_oblock = 1;
|
||||||
|
@ -8545,7 +8671,7 @@ static int tcc_compile(TCCState *s1)
|
||||||
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
|
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
|
||||||
next();
|
next();
|
||||||
decl(VT_CONST);
|
decl(VT_CONST);
|
||||||
if (tok != -1)
|
if (tok != TOK_EOF)
|
||||||
expect("declaration");
|
expect("declaration");
|
||||||
|
|
||||||
/* end of translation unit info */
|
/* end of translation unit info */
|
||||||
|
@ -9321,6 +9447,43 @@ int tcc_set_output_type(TCCState *s, int output_type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WD_ALL 0x0001 /* warning is activated when using -Wall */
|
||||||
|
|
||||||
|
typedef struct WarningDef {
|
||||||
|
int offset;
|
||||||
|
int flags;
|
||||||
|
const char *name;
|
||||||
|
} WarningDef;
|
||||||
|
|
||||||
|
static const WarningDef warning_defs[] = {
|
||||||
|
{ offsetof(TCCState, warn_unsupported), 0, "unsupported" },
|
||||||
|
{ offsetof(TCCState, warn_write_strings), 0, "write-strings" },
|
||||||
|
{ offsetof(TCCState, warn_error), 0, "error" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* set/reset a warning */
|
||||||
|
int tcc_set_warning(TCCState *s, const char *warning_name, int value)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const WarningDef *p;
|
||||||
|
if (!strcmp(warning_name, "all")) {
|
||||||
|
for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
|
||||||
|
if (p->flags & WD_ALL)
|
||||||
|
*(int *)((uint8_t *)s + p->offset) = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
|
||||||
|
if (!strcmp(warning_name, p->name))
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
found:
|
||||||
|
*(int *)((uint8_t *)s + p->offset) = value;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !defined(LIBTCC)
|
#if !defined(LIBTCC)
|
||||||
|
|
||||||
/* extract the basename of a file */
|
/* extract the basename of a file */
|
||||||
|
@ -9354,9 +9517,9 @@ static int64_t getclock_us(void)
|
||||||
|
|
||||||
void help(void)
|
void help(void)
|
||||||
{
|
{
|
||||||
printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2003 Fabrice Bellard\n"
|
||||||
"usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
|
"usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
|
||||||
" [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n"
|
" [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n"
|
||||||
" [infile1 infile2...] [-run infile args...]\n"
|
" [infile1 infile2...] [-run infile args...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"General options:\n"
|
"General options:\n"
|
||||||
|
@ -9366,6 +9529,7 @@ void help(void)
|
||||||
" -Bdir set tcc internal library path\n"
|
" -Bdir set tcc internal library path\n"
|
||||||
" -bench output compilation statistics\n"
|
" -bench output compilation statistics\n"
|
||||||
" -run run compiled source\n"
|
" -run run compiled source\n"
|
||||||
|
" -Wwarning set or reset (with 'no-' prefix) 'warning'\n"
|
||||||
"Preprocessor options:\n"
|
"Preprocessor options:\n"
|
||||||
" -Idir add include path 'dir'\n"
|
" -Idir add include path 'dir'\n"
|
||||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||||
|
@ -9610,7 +9774,24 @@ int main(int argc, char **argv)
|
||||||
case TCC_OPTION_v:
|
case TCC_OPTION_v:
|
||||||
printf("tcc version %s\n", TCC_VERSION);
|
printf("tcc version %s\n", TCC_VERSION);
|
||||||
return 0;
|
return 0;
|
||||||
|
case TCC_OPTION_W:
|
||||||
|
{
|
||||||
|
const char *p = optarg;
|
||||||
|
int value;
|
||||||
|
value = 1;
|
||||||
|
if (p[0] == 'n' && p[1] == 'o' && p[2] == '-') {
|
||||||
|
p += 2;
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
if (tcc_set_warning(s, p, value) < 0 && s->warn_unsupported)
|
||||||
|
goto unsupported_option;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (s->warn_unsupported) {
|
||||||
|
unsupported_option:
|
||||||
|
warning("unsupported option '%s'", r);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue