mirror of
https://github.com/mirror/tinycc.git
synced 2025-03-26 12:04:59 +08:00
Factor out common type combination
as there's overlap between handling types for binary and ternay operations. Factor this into a single routine (combine_types). This uses the structure that gen_op was following, and expr_cond was using as well in the past, which I find easier to reconvene with the standard language. But it reuses the new functions for diagnostics to improve (a little) on what GCC or clang produce :)
This commit is contained in:
parent
c085645f98
commit
38ab621b55
704
tccgen.c
704
tccgen.c
@ -2608,59 +2608,208 @@ static inline int is_null_pointer(SValue *p)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check types for comparison or subtraction of pointers */
|
/* compare function types. OLD functions match any new functions */
|
||||||
static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
|
static int is_compatible_func(CType *type1, CType *type2)
|
||||||
{
|
{
|
||||||
CType *type1, *type2, tmp_type1, tmp_type2;
|
Sym *s1, *s2;
|
||||||
int bt1, bt2;
|
|
||||||
|
s1 = type1->ref;
|
||||||
/* null pointers are accepted for all comparisons as gcc */
|
s2 = type2->ref;
|
||||||
if (is_null_pointer(p1) || is_null_pointer(p2))
|
if (s1->f.func_call != s2->f.func_call)
|
||||||
return;
|
return 0;
|
||||||
type1 = &p1->type;
|
if (s1->f.func_type != s2->f.func_type
|
||||||
type2 = &p2->type;
|
&& s1->f.func_type != FUNC_OLD
|
||||||
bt1 = type1->t & VT_BTYPE;
|
&& s2->f.func_type != FUNC_OLD)
|
||||||
bt2 = type2->t & VT_BTYPE;
|
return 0;
|
||||||
/* accept comparison between pointer and integer with a warning */
|
/* we should check the function return type for FUNC_OLD too
|
||||||
if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') {
|
but that causes problems with the internally used support
|
||||||
if (op != TOK_LOR && op != TOK_LAND )
|
functions such as TOK_memmove */
|
||||||
tcc_warning("comparison between pointer and integer");
|
if (s1->f.func_type == FUNC_OLD && !s1->next)
|
||||||
return;
|
return 1;
|
||||||
|
if (s2->f.func_type == FUNC_OLD && !s2->next)
|
||||||
|
return 1;
|
||||||
|
for (;;) {
|
||||||
|
if (!is_compatible_unqualified_types(&s1->type, &s2->type))
|
||||||
|
return 0;
|
||||||
|
s1 = s1->next;
|
||||||
|
s2 = s2->next;
|
||||||
|
if (!s1)
|
||||||
|
return !s2;
|
||||||
|
if (!s2)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return true if type1 and type2 are the same. If unqualified is
|
||||||
|
true, qualifiers on the types are ignored.
|
||||||
|
*/
|
||||||
|
static int compare_types(CType *type1, CType *type2, int unqualified)
|
||||||
|
{
|
||||||
|
int bt1, t1, t2;
|
||||||
|
|
||||||
|
t1 = type1->t & VT_TYPE;
|
||||||
|
t2 = type2->t & VT_TYPE;
|
||||||
|
if (unqualified) {
|
||||||
|
/* strip qualifiers before comparing */
|
||||||
|
t1 &= ~(VT_CONSTANT | VT_VOLATILE);
|
||||||
|
t2 &= ~(VT_CONSTANT | VT_VOLATILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* both must be pointers or implicit function pointers */
|
/* Default Vs explicit signedness only matters for char */
|
||||||
|
if ((t1 & VT_BTYPE) != VT_BYTE) {
|
||||||
|
t1 &= ~VT_DEFSIGN;
|
||||||
|
t2 &= ~VT_DEFSIGN;
|
||||||
|
}
|
||||||
|
/* XXX: bitfields ? */
|
||||||
|
if (t1 != t2)
|
||||||
|
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 */
|
||||||
|
bt1 = t1 & VT_BTYPE;
|
||||||
if (bt1 == VT_PTR) {
|
if (bt1 == VT_PTR) {
|
||||||
type1 = pointed_type(type1);
|
type1 = pointed_type(type1);
|
||||||
} else if (bt1 != VT_FUNC)
|
|
||||||
goto invalid_operands;
|
|
||||||
|
|
||||||
if (bt2 == VT_PTR) {
|
|
||||||
type2 = pointed_type(type2);
|
type2 = pointed_type(type2);
|
||||||
} else if (bt2 != VT_FUNC) {
|
return is_compatible_types(type1, type2);
|
||||||
invalid_operands:
|
} else if (bt1 == VT_STRUCT) {
|
||||||
tcc_error("invalid operands to binary %s", get_tok_str(op, NULL));
|
return (type1->ref == type2->ref);
|
||||||
|
} else if (bt1 == VT_FUNC) {
|
||||||
|
return is_compatible_func(type1, type2);
|
||||||
|
} else if (IS_ENUM(type1->t) || IS_ENUM(type2->t)) {
|
||||||
|
return type1->ref == type2->ref;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
if ((type1->t & VT_BTYPE) == VT_VOID ||
|
}
|
||||||
(type2->t & VT_BTYPE) == VT_VOID)
|
|
||||||
return;
|
/* Check if OP1 and OP2 can be "combined" with operation OP, the combined
|
||||||
tmp_type1 = *type1;
|
type is stored in DEST if non-null (except for pointer plus/minus) . */
|
||||||
tmp_type2 = *type2;
|
static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
|
||||||
tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
|
{
|
||||||
tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
|
CType *type1 = &op1->type, *type2 = &op2->type, type;
|
||||||
if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
|
int t1 = type1->t, t2 = type2->t, bt1 = t1 & VT_BTYPE, bt2 = t2 & VT_BTYPE;
|
||||||
/* gcc-like error if '-' is used */
|
int ret = 1;
|
||||||
if (op == '-')
|
|
||||||
goto invalid_operands;
|
type.t = VT_VOID;
|
||||||
else
|
type.ref = NULL;
|
||||||
tcc_warning("comparison of distinct pointer types lacks a cast");
|
|
||||||
|
if (bt1 == VT_VOID || bt2 == VT_VOID) {
|
||||||
|
ret = op == '?' ? 1 : 0;
|
||||||
|
/* NOTE: as an extension, we accept void on only one side */
|
||||||
|
type.t = VT_VOID;
|
||||||
|
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
||||||
|
if (op == '+') ; /* Handled in caller */
|
||||||
|
/* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
|
||||||
|
/* If one is a null ptr constant the result type is the other. */
|
||||||
|
else if (is_null_pointer (op2)) type = *type1;
|
||||||
|
else if (is_null_pointer (op1)) type = *type2;
|
||||||
|
else if (bt1 != bt2) {
|
||||||
|
/* accept comparison or cond-expr between pointer and integer
|
||||||
|
with a warning */
|
||||||
|
if ((op == '?' || (op >= TOK_ULT && op <= TOK_LOR))
|
||||||
|
&& (is_integer_btype(bt1) || is_integer_btype(bt2)))
|
||||||
|
tcc_warning("pointer/integer mismatch in %s",
|
||||||
|
op == '?' ? "conditional expression" : "comparison");
|
||||||
|
else if (op != '-' || !is_integer_btype(bt2))
|
||||||
|
ret = 0;
|
||||||
|
type = *(bt1 == VT_PTR ? type1 : type2);
|
||||||
|
} else {
|
||||||
|
CType *pt1 = pointed_type(type1);
|
||||||
|
CType *pt2 = pointed_type(type2);
|
||||||
|
int pbt1 = pt1->t & VT_BTYPE;
|
||||||
|
int pbt2 = pt2->t & VT_BTYPE;
|
||||||
|
int newquals, copied = 0;
|
||||||
|
if (pbt1 != VT_VOID && pbt2 != VT_VOID
|
||||||
|
&& !compare_types(pt1, pt2, 1/*unqualif*/)) {
|
||||||
|
if (op != '?' && (op < TOK_ULT || op > TOK_LOR))
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
type_incompatibility_warning(type1, type2,
|
||||||
|
op == '?'
|
||||||
|
? "pointer type mismatch in conditional expression ('%s' and '%s')"
|
||||||
|
: "pointer type mismatch in comparison('%s' and '%s')");
|
||||||
|
}
|
||||||
|
if (op == '?') {
|
||||||
|
/* pointers to void get preferred, otherwise the
|
||||||
|
pointed to types minus qualifs should be compatible */
|
||||||
|
type = *((pbt1 == VT_VOID) ? type1 : type2);
|
||||||
|
/* combine qualifs */
|
||||||
|
newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
|
||||||
|
if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
|
||||||
|
& newquals)
|
||||||
|
{
|
||||||
|
/* copy the pointer target symbol */
|
||||||
|
type.ref = sym_push(SYM_FIELD, &type.ref->type,
|
||||||
|
0, type.ref->c);
|
||||||
|
copied = 1;
|
||||||
|
pointed_type(&type)->t |= newquals;
|
||||||
|
}
|
||||||
|
/* pointers to incomplete arrays get converted to
|
||||||
|
pointers to completed ones if possible */
|
||||||
|
if (pt1->t & VT_ARRAY
|
||||||
|
&& pt2->t & VT_ARRAY
|
||||||
|
&& pointed_type(&type)->ref->c < 0
|
||||||
|
&& (pt1->ref->c > 0 || pt2->ref->c > 0))
|
||||||
|
{
|
||||||
|
if (!copied)
|
||||||
|
type.ref = sym_push(SYM_FIELD, &type.ref->type,
|
||||||
|
0, type.ref->c);
|
||||||
|
pointed_type(&type)->ref =
|
||||||
|
sym_push(SYM_FIELD, &pointed_type(&type)->ref->type,
|
||||||
|
0, pointed_type(&type)->ref->c);
|
||||||
|
pointed_type(&type)->ref->c =
|
||||||
|
0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (op >= TOK_ULT && op <= TOK_LOR)
|
||||||
|
type.t = VT_SIZE_T;
|
||||||
|
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
|
||||||
|
if (op != '?' || !compare_types(type1, type2, 1))
|
||||||
|
ret = 0;
|
||||||
|
type = *type1;
|
||||||
|
} else if (is_float(bt1) || is_float(bt2)) {
|
||||||
|
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
|
||||||
|
type.t = VT_LDOUBLE;
|
||||||
|
} else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
|
||||||
|
type.t = VT_DOUBLE;
|
||||||
|
} else {
|
||||||
|
type.t = VT_FLOAT;
|
||||||
|
}
|
||||||
|
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
|
||||||
|
/* cast to biggest op */
|
||||||
|
type.t = VT_LLONG | VT_LONG;
|
||||||
|
if (bt1 == VT_LLONG)
|
||||||
|
type.t &= t1;
|
||||||
|
if (bt2 == VT_LLONG)
|
||||||
|
type.t &= t2;
|
||||||
|
/* convert to unsigned if it does not fit in a long long */
|
||||||
|
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
|
||||||
|
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
|
||||||
|
type.t |= VT_UNSIGNED;
|
||||||
|
} else {
|
||||||
|
/* integer operations */
|
||||||
|
type.t = VT_INT | (VT_LONG & (t1 | t2));
|
||||||
|
/* convert to unsigned if it does not fit in an integer */
|
||||||
|
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
|
||||||
|
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
|
||||||
|
type.t |= VT_UNSIGNED;
|
||||||
}
|
}
|
||||||
|
if (dest)
|
||||||
|
*dest = type;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generic gen_op: handles types problems */
|
/* generic gen_op: handles types problems */
|
||||||
ST_FUNC void gen_op(int op)
|
ST_FUNC void gen_op(int op)
|
||||||
{
|
{
|
||||||
int u, t1, t2, bt1, bt2, t;
|
int u, t1, t2, bt1, bt2, t;
|
||||||
CType type1;
|
CType type1, combtype;
|
||||||
|
|
||||||
redo:
|
redo:
|
||||||
t1 = vtop[-1].type.t;
|
t1 = vtop[-1].type.t;
|
||||||
@ -2668,9 +2817,7 @@ redo:
|
|||||||
bt1 = t1 & VT_BTYPE;
|
bt1 = t1 & VT_BTYPE;
|
||||||
bt2 = t2 & VT_BTYPE;
|
bt2 = t2 & VT_BTYPE;
|
||||||
|
|
||||||
if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
|
if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
|
||||||
tcc_error("operation on a struct");
|
|
||||||
} else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
|
|
||||||
if (bt2 == VT_FUNC) {
|
if (bt2 == VT_FUNC) {
|
||||||
mk_pointer(&vtop->type);
|
mk_pointer(&vtop->type);
|
||||||
gaddrof();
|
gaddrof();
|
||||||
@ -2682,25 +2829,18 @@ redo:
|
|||||||
vswap();
|
vswap();
|
||||||
}
|
}
|
||||||
goto redo;
|
goto redo;
|
||||||
|
} else if (!combine_types(&combtype, vtop - 1, vtop, op)) {
|
||||||
|
tcc_error_noabort("invalid operand types for binary operation");
|
||||||
|
vpop();
|
||||||
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
||||||
/* at least one operand is a pointer */
|
/* at least one operand is a pointer */
|
||||||
/* relational op: must be both pointers */
|
/* relational op: must be both pointers */
|
||||||
if (op >= TOK_ULT && op <= TOK_LOR) {
|
if (op >= TOK_ULT && op <= TOK_LOR)
|
||||||
check_comparison_pointer_types(vtop - 1, vtop, op);
|
|
||||||
/* pointers are handled are unsigned */
|
|
||||||
#if PTR_SIZE == 8
|
|
||||||
t = VT_LLONG | VT_UNSIGNED;
|
|
||||||
#else
|
|
||||||
t = VT_INT | VT_UNSIGNED;
|
|
||||||
#endif
|
|
||||||
goto std_op;
|
goto std_op;
|
||||||
}
|
|
||||||
/* if both pointers, then it must be the '-' op */
|
/* if both pointers, then it must be the '-' op */
|
||||||
if (bt1 == VT_PTR && bt2 == VT_PTR) {
|
if (bt1 == VT_PTR && bt2 == VT_PTR) {
|
||||||
if (op != '-')
|
if (op != '-')
|
||||||
tcc_error("cannot use pointers here");
|
tcc_error("cannot use pointers here");
|
||||||
check_comparison_pointer_types(vtop - 1, vtop, op);
|
|
||||||
/* XXX: check that types are compatible */
|
|
||||||
if (vtop[-1].type.t & VT_VLA) {
|
if (vtop[-1].type.t & VT_VLA) {
|
||||||
vla_runtime_pointed_size(&vtop[-1].type);
|
vla_runtime_pointed_size(&vtop[-1].type);
|
||||||
} else {
|
} else {
|
||||||
@ -2759,46 +2899,21 @@ redo:
|
|||||||
/* put again type if gen_opic() swaped operands */
|
/* put again type if gen_opic() swaped operands */
|
||||||
vtop->type = type1;
|
vtop->type = type1;
|
||||||
}
|
}
|
||||||
} else if (is_float(bt1) || is_float(bt2)) {
|
|
||||||
/* compute bigger type and do implicit casts */
|
|
||||||
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
|
|
||||||
t = VT_LDOUBLE;
|
|
||||||
} else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
|
|
||||||
t = VT_DOUBLE;
|
|
||||||
} else {
|
|
||||||
t = VT_FLOAT;
|
|
||||||
}
|
|
||||||
/* floats can only be used for a few operations */
|
|
||||||
if (op != '+' && op != '-' && op != '*' && op != '/' &&
|
|
||||||
(op < TOK_ULT || op > TOK_GT))
|
|
||||||
tcc_error("invalid operands for binary operation");
|
|
||||||
goto std_op;
|
|
||||||
} else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) {
|
|
||||||
t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
|
|
||||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
|
|
||||||
t |= VT_UNSIGNED;
|
|
||||||
t |= (VT_LONG & t1);
|
|
||||||
goto std_op;
|
|
||||||
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
|
|
||||||
/* cast to biggest op */
|
|
||||||
t = VT_LLONG | VT_LONG;
|
|
||||||
if (bt1 == VT_LLONG)
|
|
||||||
t &= t1;
|
|
||||||
if (bt2 == VT_LLONG)
|
|
||||||
t &= t2;
|
|
||||||
/* convert to unsigned if it does not fit in a long long */
|
|
||||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
|
|
||||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
|
|
||||||
t |= VT_UNSIGNED;
|
|
||||||
goto std_op;
|
|
||||||
} else {
|
} else {
|
||||||
/* integer operations */
|
/* floats can only be used for a few operations */
|
||||||
t = VT_INT | (VT_LONG & (t1 | t2));
|
if (is_float(combtype.t)
|
||||||
/* convert to unsigned if it does not fit in an integer */
|
&& op != '+' && op != '-' && op != '*' && op != '/'
|
||||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
|
&& (op < TOK_ULT || op > TOK_LOR))
|
||||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
|
tcc_error("invalid operands for binary operation");
|
||||||
t |= VT_UNSIGNED;
|
else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) {
|
||||||
|
t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
|
||||||
|
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
|
||||||
|
t |= VT_UNSIGNED;
|
||||||
|
t |= (VT_LONG & t1);
|
||||||
|
combtype.t = t;
|
||||||
|
}
|
||||||
std_op:
|
std_op:
|
||||||
|
t = t2 = combtype.t;
|
||||||
/* XXX: currently, some unsigned operations are explicit, so
|
/* XXX: currently, some unsigned operations are explicit, so
|
||||||
we modify them here */
|
we modify them here */
|
||||||
if (t & VT_UNSIGNED) {
|
if (t & VT_UNSIGNED) {
|
||||||
@ -2818,20 +2933,18 @@ redo:
|
|||||||
op = TOK_UGE;
|
op = TOK_UGE;
|
||||||
}
|
}
|
||||||
vswap();
|
vswap();
|
||||||
type1.t = t;
|
gen_cast_s(t);
|
||||||
type1.ref = NULL;
|
|
||||||
gen_cast(&type1);
|
|
||||||
vswap();
|
vswap();
|
||||||
/* special case for shifts and long long: we keep the shift as
|
/* special case for shifts and long long: we keep the shift as
|
||||||
an integer */
|
an integer */
|
||||||
if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL)
|
if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL)
|
||||||
type1.t = VT_INT;
|
t2 = VT_INT;
|
||||||
gen_cast(&type1);
|
gen_cast_s(t2);
|
||||||
if (is_float(t))
|
if (is_float(t))
|
||||||
gen_opif(op);
|
gen_opif(op);
|
||||||
else
|
else
|
||||||
gen_opic(op);
|
gen_opic(op);
|
||||||
if (op >= TOK_ULT && op <= TOK_GT) {
|
if (op >= TOK_ULT && op <= TOK_LOR) {
|
||||||
/* relational op: the result is an int */
|
/* relational op: the result is an int */
|
||||||
vtop->type.t = VT_INT;
|
vtop->type.t = VT_INT;
|
||||||
} else {
|
} else {
|
||||||
@ -3235,85 +3348,6 @@ ST_FUNC void mk_pointer(CType *type)
|
|||||||
type->ref = s;
|
type->ref = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compare function types. OLD functions match any new functions */
|
|
||||||
static int is_compatible_func(CType *type1, CType *type2)
|
|
||||||
{
|
|
||||||
Sym *s1, *s2;
|
|
||||||
|
|
||||||
s1 = type1->ref;
|
|
||||||
s2 = type2->ref;
|
|
||||||
if (s1->f.func_call != s2->f.func_call)
|
|
||||||
return 0;
|
|
||||||
if (s1->f.func_type != s2->f.func_type
|
|
||||||
&& 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;
|
|
||||||
if (s2->f.func_type == FUNC_OLD && !s2->next)
|
|
||||||
return 1;
|
|
||||||
for (;;) {
|
|
||||||
if (!is_compatible_unqualified_types(&s1->type, &s2->type))
|
|
||||||
return 0;
|
|
||||||
s1 = s1->next;
|
|
||||||
s2 = s2->next;
|
|
||||||
if (!s1)
|
|
||||||
return !s2;
|
|
||||||
if (!s2)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return true if type1 and type2 are the same. If unqualified is
|
|
||||||
true, qualifiers on the types are ignored.
|
|
||||||
*/
|
|
||||||
static int compare_types(CType *type1, CType *type2, int unqualified)
|
|
||||||
{
|
|
||||||
int bt1, t1, t2;
|
|
||||||
|
|
||||||
t1 = type1->t & VT_TYPE;
|
|
||||||
t2 = type2->t & VT_TYPE;
|
|
||||||
if (unqualified) {
|
|
||||||
/* strip qualifiers before comparing */
|
|
||||||
t1 &= ~(VT_CONSTANT | VT_VOLATILE);
|
|
||||||
t2 &= ~(VT_CONSTANT | VT_VOLATILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default Vs explicit signedness only matters for char */
|
|
||||||
if ((t1 & VT_BTYPE) != VT_BYTE) {
|
|
||||||
t1 &= ~VT_DEFSIGN;
|
|
||||||
t2 &= ~VT_DEFSIGN;
|
|
||||||
}
|
|
||||||
/* XXX: bitfields ? */
|
|
||||||
if (t1 != t2)
|
|
||||||
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 */
|
|
||||||
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 if (IS_ENUM(type1->t) || IS_ENUM(type2->t)) {
|
|
||||||
return type1->ref == type2->ref;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return true if type1 and type2 are exactly the same (including
|
/* return true if type1 and type2 are exactly the same (including
|
||||||
qualifiers).
|
qualifiers).
|
||||||
*/
|
*/
|
||||||
@ -5930,16 +5964,15 @@ static int is_cond_bool(SValue *sv)
|
|||||||
|
|
||||||
static void expr_cond(void)
|
static void expr_cond(void)
|
||||||
{
|
{
|
||||||
int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g;
|
int tt, u, r1, r2, rc, t1, t2, islv, c, g;
|
||||||
SValue sv;
|
SValue sv;
|
||||||
CType type, type1, type2;
|
CType type;
|
||||||
int ncw_prev;
|
int ncw_prev;
|
||||||
|
|
||||||
expr_lor();
|
expr_lor();
|
||||||
if (tok == '?') {
|
if (tok == '?') {
|
||||||
next();
|
next();
|
||||||
c = condition_3way();
|
c = condition_3way();
|
||||||
ncw_prev = nocode_wanted;
|
|
||||||
g = (tok == ':' && gnu_ext);
|
g = (tok == ':' && gnu_ext);
|
||||||
tt = 0;
|
tt = 0;
|
||||||
if (!g) {
|
if (!g) {
|
||||||
@ -5957,218 +5990,111 @@ static void expr_cond(void)
|
|||||||
tt = gvtst(0, 0);
|
tt = gvtst(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1) {
|
ncw_prev = nocode_wanted;
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
nocode_wanted++;
|
nocode_wanted++;
|
||||||
if (!g)
|
if (!g)
|
||||||
gexpr();
|
gexpr();
|
||||||
|
|
||||||
if (c < 0 && vtop->r == VT_CMP) {
|
if (c < 0 && vtop->r == VT_CMP) {
|
||||||
t1 = gvtst(0, 0);
|
t1 = gvtst(0, 0);
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
gvtst_set(0, t1);
|
gvtst_set(0, t1);
|
||||||
}
|
gv(RC_INT);
|
||||||
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
|
|
||||||
mk_pointer(&vtop->type);
|
|
||||||
type1 = vtop->type;
|
|
||||||
sv = *vtop; /* save value to handle it later */
|
|
||||||
vtop--; /* no vpop so that FP stack is not flushed */
|
|
||||||
|
|
||||||
if (g) {
|
|
||||||
u = tt;
|
|
||||||
} else if (c < 0) {
|
|
||||||
u = gjmp(0);
|
|
||||||
gsym(tt);
|
|
||||||
} else
|
|
||||||
u = 0;
|
|
||||||
|
|
||||||
nocode_wanted = ncw_prev;
|
|
||||||
if (c == 1)
|
|
||||||
nocode_wanted++;
|
|
||||||
skip(':');
|
|
||||||
expr_cond();
|
|
||||||
|
|
||||||
if (c < 0 && is_cond_bool(vtop) && is_cond_bool(&sv)) {
|
|
||||||
if (sv.r == VT_CMP) {
|
|
||||||
t1 = sv.jtrue;
|
|
||||||
t2 = u;
|
|
||||||
} else {
|
|
||||||
t1 = gvtst(0, 0);
|
|
||||||
t2 = gjmp(0);
|
|
||||||
gsym(u);
|
|
||||||
vpushv(&sv);
|
|
||||||
}
|
|
||||||
gvtst_set(0, t1);
|
|
||||||
gvtst_set(1, t2);
|
|
||||||
nocode_wanted = ncw_prev;
|
|
||||||
// tcc_warning("two conditions expr_cond");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
|
|
||||||
mk_pointer(&vtop->type);
|
|
||||||
type2=vtop->type;
|
|
||||||
t1 = type1.t;
|
|
||||||
bt1 = t1 & VT_BTYPE;
|
|
||||||
t2 = type2.t;
|
|
||||||
bt2 = t2 & VT_BTYPE;
|
|
||||||
type.ref = NULL;
|
|
||||||
|
|
||||||
/* cast operands to correct type according to ISOC rules */
|
|
||||||
if (bt1 == VT_VOID || bt2 == VT_VOID) {
|
|
||||||
type.t = VT_VOID; /* NOTE: as an extension, we accept void on only one side */
|
|
||||||
} else if (bt1 == VT_BOOL && bt2 == VT_BOOL) {
|
|
||||||
type = type1;
|
|
||||||
} else if (is_float(bt1) && is_integer_btype(bt2)) {
|
|
||||||
type = type1;
|
|
||||||
} else if (is_integer_btype(bt1) && is_float(bt2)) {
|
|
||||||
type = type2;
|
|
||||||
} else if (is_float(bt1) && is_float(bt2)) {
|
|
||||||
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
|
|
||||||
type.t = VT_LDOUBLE;
|
|
||||||
|
|
||||||
} else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
|
|
||||||
type.t = VT_DOUBLE;
|
|
||||||
} else {
|
|
||||||
type.t = VT_FLOAT;
|
|
||||||
}
|
|
||||||
} else if ((bt1 == VT_LLONG && is_integer_btype(bt2)) ||
|
|
||||||
(bt2 == VT_LLONG && is_integer_btype(bt1))) {
|
|
||||||
/* cast to biggest op */
|
|
||||||
type.t = VT_LLONG | VT_LONG;
|
|
||||||
if (bt1 == VT_LLONG)
|
|
||||||
type.t &= t1;
|
|
||||||
if (bt2 == VT_LLONG)
|
|
||||||
type.t &= t2;
|
|
||||||
/* convert to unsigned if it does not fit in a long long */
|
|
||||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
|
|
||||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
|
|
||||||
type.t |= VT_UNSIGNED;
|
|
||||||
}
|
|
||||||
/* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
|
|
||||||
/* If one is a null ptr constant the result type
|
|
||||||
is the other. */
|
|
||||||
else if (bt1 == VT_PTR && is_null_pointer(vtop)) {
|
|
||||||
type = type1;
|
|
||||||
} else if (is_null_pointer(&sv) && bt2 == VT_PTR) {
|
|
||||||
type = type2;
|
|
||||||
} else if (bt1 == VT_PTR && is_integer_btype(bt2)) {
|
|
||||||
type = type1;
|
|
||||||
tcc_warning("pointer/integer mismatch");
|
|
||||||
} else if (is_integer_btype(bt1) && bt2 == VT_PTR) {
|
|
||||||
type = type2;
|
|
||||||
tcc_warning("pointer/integer mismatch");
|
|
||||||
} else if (bt1==VT_PTR && bt2 == VT_PTR) {
|
|
||||||
CType *pt1 = pointed_type(&type1);
|
|
||||||
CType *pt2 = pointed_type(&type2);
|
|
||||||
int pbt1 = pt1->t & VT_BTYPE;
|
|
||||||
int pbt2 = pt2->t & VT_BTYPE;
|
|
||||||
int newquals, copied = 0;
|
|
||||||
/* pointers to void get preferred, otherwise the
|
|
||||||
pointed to types minus qualifs should be compatible */
|
|
||||||
type = (pbt1 == VT_VOID) ? type1 : type2;
|
|
||||||
if (pbt1 != VT_VOID && pbt2 != VT_VOID && ! compare_types(pt1, pt2, 1/*unqualif*/)) {
|
|
||||||
type_incompatibility_warning(&type1, &type2, "incompatible pointer types");
|
|
||||||
// result is void*
|
|
||||||
type.t = VT_VOID;
|
|
||||||
mk_pointer(&type);
|
|
||||||
}
|
|
||||||
/* combine qualifs */
|
|
||||||
newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
|
|
||||||
if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
|
|
||||||
& newquals)
|
|
||||||
{
|
|
||||||
/* copy the pointer target symbol */
|
|
||||||
type.ref = sym_push(SYM_FIELD, &type.ref->type,
|
|
||||||
0, type.ref->c);
|
|
||||||
copied = 1;
|
|
||||||
pointed_type(&type)->t |= newquals;
|
|
||||||
}
|
|
||||||
/* pointers to incomplete arrays get converted to
|
|
||||||
pointers to completed ones if possible */
|
|
||||||
if (pt1->t & VT_ARRAY
|
|
||||||
&& pt2->t & VT_ARRAY
|
|
||||||
&& pointed_type(&type)->ref->c < 0
|
|
||||||
&& (pt1->ref->c > 0 || pt2->ref->c > 0))
|
|
||||||
{
|
|
||||||
if (!copied)
|
|
||||||
type.ref = sym_push(SYM_FIELD, &type.ref->type,
|
|
||||||
0, type.ref->c);
|
|
||||||
pointed_type(&type)->ref =
|
|
||||||
sym_push(SYM_FIELD, &pointed_type(&type)->ref->type,
|
|
||||||
0, pointed_type(&type)->ref->c);
|
|
||||||
pointed_type(&type)->ref->c =
|
|
||||||
0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c;
|
|
||||||
}
|
|
||||||
} else if (bt1 == VT_STRUCT && bt2 == VT_STRUCT) {
|
|
||||||
/* test structure compatibility */
|
|
||||||
if (type1.ref != type2.ref) {
|
|
||||||
type_incompatibility_error(&type1, &type2,"different struct/union types '%s' vs. '%s'");
|
|
||||||
} else {
|
|
||||||
type = bt1 == VT_STRUCT ? type1 : type2;
|
|
||||||
}
|
|
||||||
} else if (is_integer_btype(bt1) && is_integer_btype(bt2)) {
|
|
||||||
/* integer operations */
|
|
||||||
type.t = VT_INT | (VT_LONG & (t1 | t2));
|
|
||||||
/* convert to unsigned if one of both is unsigned */
|
|
||||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
|
|
||||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
|
|
||||||
type.t |= VT_UNSIGNED;
|
|
||||||
} else {
|
|
||||||
type_incompatibility_error(&type1, &type2, "type '%s' is incompatible to '%s'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
|
|
||||||
that `(expr ? a : b).mem` does not error with "lvalue expected" */
|
|
||||||
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
|
|
||||||
|
|
||||||
/* now we convert second operand */
|
|
||||||
if (c != 1) {
|
|
||||||
gen_cast(&type);
|
|
||||||
if (islv) {
|
|
||||||
mk_pointer(&vtop->type);
|
|
||||||
gaddrof();
|
|
||||||
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
|
||||||
gaddrof();
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = RC_TYPE(type.t);
|
|
||||||
/* for long longs, we use fixed registers to avoid having
|
|
||||||
to handle a complicated move */
|
|
||||||
if (USING_TWO_WORDS(type.t))
|
|
||||||
rc = RC_RET(type.t);
|
|
||||||
|
|
||||||
tt = r2 = 0;
|
|
||||||
if (c < 0) {
|
|
||||||
r2 = gv(rc);
|
|
||||||
tt = gjmp(0);
|
|
||||||
}
|
|
||||||
gsym(u);
|
|
||||||
nocode_wanted = ncw_prev;
|
|
||||||
|
|
||||||
/* this is horrible, but we must also convert first
|
|
||||||
operand */
|
|
||||||
if (c != 0) {
|
|
||||||
*vtop = sv;
|
|
||||||
gen_cast(&type);
|
|
||||||
if (islv) {
|
|
||||||
mk_pointer(&vtop->type);
|
|
||||||
gaddrof();
|
|
||||||
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
|
||||||
gaddrof();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c < 0) {
|
|
||||||
r1 = gv(rc);
|
|
||||||
move_reg(r2, r1, islv ? VT_PTR : type.t);
|
|
||||||
vtop->r = r2;
|
|
||||||
gsym(tt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (islv)
|
|
||||||
indir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
|
||||||
|
mk_pointer(&vtop->type);
|
||||||
|
sv = *vtop; /* save value to handle it later */
|
||||||
|
vtop--; /* no vpop so that FP stack is not flushed */
|
||||||
|
|
||||||
|
if (g) {
|
||||||
|
u = tt;
|
||||||
|
} else if (c < 0) {
|
||||||
|
u = gjmp(0);
|
||||||
|
gsym(tt);
|
||||||
|
} else
|
||||||
|
u = 0;
|
||||||
|
|
||||||
|
nocode_wanted = ncw_prev;
|
||||||
|
if (c == 1)
|
||||||
|
nocode_wanted++;
|
||||||
|
skip(':');
|
||||||
|
expr_cond();
|
||||||
|
|
||||||
|
if (c < 0 && is_cond_bool(vtop) && is_cond_bool(&sv)) {
|
||||||
|
if (sv.r == VT_CMP) {
|
||||||
|
t1 = sv.jtrue;
|
||||||
|
t2 = u;
|
||||||
|
} else {
|
||||||
|
t1 = gvtst(0, 0);
|
||||||
|
t2 = gjmp(0);
|
||||||
|
gsym(u);
|
||||||
|
vpushv(&sv);
|
||||||
|
}
|
||||||
|
gvtst_set(0, t1);
|
||||||
|
gvtst_set(1, t2);
|
||||||
|
nocode_wanted = ncw_prev;
|
||||||
|
// tcc_warning("two conditions expr_cond");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
|
||||||
|
mk_pointer(&vtop->type);
|
||||||
|
|
||||||
|
/* cast operands to correct type according to ISOC rules */
|
||||||
|
if (!combine_types(&type, &sv, vtop, '?'))
|
||||||
|
type_incompatibility_error(&sv.type, &vtop->type,
|
||||||
|
"type mismatch in conditional expression (have '%s' and '%s')");
|
||||||
|
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
|
||||||
|
that `(expr ? a : b).mem` does not error with "lvalue expected" */
|
||||||
|
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
|
||||||
|
|
||||||
|
/* now we convert second operand */
|
||||||
|
if (c != 1) {
|
||||||
|
gen_cast(&type);
|
||||||
|
if (islv) {
|
||||||
|
mk_pointer(&vtop->type);
|
||||||
|
gaddrof();
|
||||||
|
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
||||||
|
gaddrof();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = RC_TYPE(type.t);
|
||||||
|
/* for long longs, we use fixed registers to avoid having
|
||||||
|
to handle a complicated move */
|
||||||
|
if (USING_TWO_WORDS(type.t))
|
||||||
|
rc = RC_RET(type.t);
|
||||||
|
|
||||||
|
tt = r2 = 0;
|
||||||
|
if (c < 0) {
|
||||||
|
r2 = gv(rc);
|
||||||
|
tt = gjmp(0);
|
||||||
|
}
|
||||||
|
gsym(u);
|
||||||
|
nocode_wanted = ncw_prev;
|
||||||
|
|
||||||
|
/* this is horrible, but we must also convert first
|
||||||
|
operand */
|
||||||
|
if (c != 0) {
|
||||||
|
*vtop = sv;
|
||||||
|
gen_cast(&type);
|
||||||
|
if (islv) {
|
||||||
|
mk_pointer(&vtop->type);
|
||||||
|
gaddrof();
|
||||||
|
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
||||||
|
gaddrof();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c < 0) {
|
||||||
|
r1 = gv(rc);
|
||||||
|
move_reg(r2, r1, islv ? VT_PTR : type.t);
|
||||||
|
vtop->r = r2;
|
||||||
|
gsym(tt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (islv)
|
||||||
|
indir();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
33_ternary_op.c:26: warning: pointer/integer mismatch
|
33_ternary_op.c:26: warning: pointer/integer mismatch in conditional expression
|
||||||
0
|
0
|
||||||
1
|
1
|
||||||
4
|
4
|
||||||
@ -9,4 +9,4 @@
|
|||||||
21
|
21
|
||||||
24
|
24
|
||||||
27
|
27
|
||||||
152
|
152
|
||||||
|
Loading…
Reference in New Issue
Block a user