mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Fix comparison for bit field values #386
This commit is contained in:
@@ -2552,6 +2552,45 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *check_assignment_bit_field(CheckerContext *ctx, Operand *operand, Type *target_type) {
|
||||||
|
if (is_type_bit_field_value(target_type)) {
|
||||||
|
Type *lt = base_type(target_type);
|
||||||
|
i64 lhs_bits = lt->BitFieldValue.bits;
|
||||||
|
if (operand->mode == Addressing_Constant) {
|
||||||
|
ExactValue v = exact_value_to_integer(operand->value);
|
||||||
|
if (v.kind == ExactValue_Integer) {
|
||||||
|
BigInt i = v.value_integer;
|
||||||
|
if (!i.neg) {
|
||||||
|
u64 imax_ = ~cast(u64)0ull;
|
||||||
|
if (lhs_bits < 64) {
|
||||||
|
imax_ = (1ull << cast(u64)lhs_bits) - 1ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInt imax = big_int_make_u64(imax_);
|
||||||
|
if (big_int_cmp(&i, &imax) <= 0) {
|
||||||
|
return operand->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (operand->value.kind == ExactValue_Bool) {
|
||||||
|
bool b = operand->value.value_bool;
|
||||||
|
if (lhs_bits == 1) {
|
||||||
|
return operand->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is_type_integer(operand->type)) {
|
||||||
|
// TODO(bill): Any other checks?
|
||||||
|
return operand->type;
|
||||||
|
} else if (is_type_boolean(operand->type)) {
|
||||||
|
if (lhs_bits == 1) {
|
||||||
|
return operand->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
||||||
GB_ASSERT_NOT_NULL(target_type);
|
GB_ASSERT_NOT_NULL(target_type);
|
||||||
if (operand->mode == Addressing_Invalid ||
|
if (operand->mode == Addressing_Invalid ||
|
||||||
@@ -2640,6 +2679,14 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Type_BitFieldValue: {
|
||||||
|
Type *res = check_assignment_bit_field(c, operand, target_type);
|
||||||
|
if (res == nullptr) {
|
||||||
|
convert_untyped_error(c, operand, target_type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) {
|
if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) {
|
||||||
isize count = t->Union.variants.count;
|
isize count = t->Union.variants.count;
|
||||||
|
|||||||
+12
-38
@@ -172,6 +172,9 @@ bool check_is_terminating(Ast *node) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
|
Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
|
||||||
if (rhs->mode == Addressing_Invalid) {
|
if (rhs->mode == Addressing_Invalid) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -249,48 +252,19 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
|||||||
case Addressing_Invalid:
|
case Addressing_Invalid:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
case Addressing_Variable: {
|
case Addressing_Variable:
|
||||||
if (is_type_bit_field_value(lhs->type)) {
|
if (is_type_bit_field_value(lhs->type)) {
|
||||||
Type *lt = base_type(lhs->type);
|
Type *res = check_assignment_bit_field(ctx, rhs, lhs->type);
|
||||||
i64 lhs_bits = lt->BitFieldValue.bits;
|
if (res == nullptr) {
|
||||||
if (rhs->mode == Addressing_Constant) {
|
gbString lhs_expr = expr_to_string(lhs->expr);
|
||||||
ExactValue v = exact_value_to_integer(rhs->value);
|
gbString rhs_expr = expr_to_string(rhs->expr);
|
||||||
if (v.kind == ExactValue_Integer) {
|
error(rhs->expr, "Cannot assign '%s' to bit field '%s'", rhs_expr, lhs_expr);
|
||||||
BigInt i = v.value_integer;
|
gb_string_free(rhs_expr);
|
||||||
if (!i.neg) {
|
gb_string_free(lhs_expr);
|
||||||
u64 imax_ = ~cast(u64)0ull;
|
|
||||||
if (lhs_bits < 64) {
|
|
||||||
imax_ = (1ull << cast(u64)lhs_bits) - 1ull;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInt imax = big_int_make_u64(imax_);
|
|
||||||
if (big_int_cmp(&i, &imax) <= 0) {
|
|
||||||
return rhs->type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (rhs->value.kind == ExactValue_Bool) {
|
|
||||||
bool b = rhs->value.value_bool;
|
|
||||||
if (lhs_bits == 1) {
|
|
||||||
return rhs->type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (is_type_integer(rhs->type)) {
|
|
||||||
// TODO(bill): Any other checks?
|
|
||||||
return rhs->type;
|
|
||||||
} else if (is_type_boolean(rhs->type)) {
|
|
||||||
if (lhs_bits == 1) {
|
|
||||||
return rhs->type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
gbString lhs_expr = expr_to_string(lhs->expr);
|
return res;
|
||||||
gbString rhs_expr = expr_to_string(rhs->expr);
|
|
||||||
error(rhs->expr, "Cannot assign '%s' to bit field '%s'", rhs_expr, lhs_expr);
|
|
||||||
gb_string_free(rhs_expr);
|
|
||||||
gb_string_free(lhs_expr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case Addressing_MapIndex: {
|
case Addressing_MapIndex: {
|
||||||
Ast *ln = unparen_expr(lhs->expr);
|
Ast *ln = unparen_expr(lhs->expr);
|
||||||
|
|||||||
Reference in New Issue
Block a user