diff --git a/src/check_expr.cpp b/src/check_expr.cpp index be135ce68..2cb462b9a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2552,6 +2552,45 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { 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) { GB_ASSERT_NOT_NULL(target_type); if (operand->mode == Addressing_Invalid || @@ -2640,6 +2679,14 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { 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: if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) { isize count = t->Union.variants.count; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 9a62f4beb..a14aeeaaf 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -172,6 +172,9 @@ bool check_is_terminating(Ast *node) { return false; } + + + Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) { if (rhs->mode == Addressing_Invalid) { return nullptr; @@ -249,48 +252,19 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) case Addressing_Invalid: return nullptr; - case Addressing_Variable: { + case Addressing_Variable: if (is_type_bit_field_value(lhs->type)) { - Type *lt = base_type(lhs->type); - i64 lhs_bits = lt->BitFieldValue.bits; - if (rhs->mode == Addressing_Constant) { - ExactValue v = exact_value_to_integer(rhs->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 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; - } + Type *res = check_assignment_bit_field(ctx, rhs, lhs->type); + if (res == nullptr) { + gbString lhs_expr = expr_to_string(lhs->expr); + 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); } - gbString lhs_expr = expr_to_string(lhs->expr); - 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; + return res; } break; - } case Addressing_MapIndex: { Ast *ln = unparen_expr(lhs->expr);