mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 00:35:10 +00:00
parent
9db45ac362
commit
6131b37163
@ -105,11 +105,25 @@ static AstNode *first_executing_node(AstNode *node) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void mark_impure_fn(BlockContext *context) {
|
||||
if (context->fn_entry) {
|
||||
context->fn_entry->is_pure = false;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
// if this assert fails, then parseh generated code that
|
||||
// failed semantic analysis, which isn't supposed to happen
|
||||
assert(!node->owner->c_import_node);
|
||||
|
||||
// if an error occurs in a function then it becomes impure
|
||||
if (node->block_context) {
|
||||
FnTableEntry *fn_entry = node->block_context->fn_entry;
|
||||
if (fn_entry) {
|
||||
fn_entry->is_pure = false;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
|
||||
node->owner->source_code, node->owner->line_offsets, msg);
|
||||
|
||||
@ -2620,12 +2634,6 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
|
||||
return return_type;
|
||||
}
|
||||
|
||||
static void mark_impure_fn(BlockContext *context) {
|
||||
if (context->fn_entry) {
|
||||
context->fn_entry->is_pure = false;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
AstNode *node)
|
||||
{
|
||||
@ -5149,7 +5157,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
||||
}
|
||||
case PrefixOpNegation:
|
||||
{
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, *expr_node);
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
|
||||
if (expr_type->id == TypeTableEntryIdInvalid) {
|
||||
return expr_type;
|
||||
} else if ((expr_type->id == TypeTableEntryIdInt &&
|
||||
@ -5762,6 +5770,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
|
||||
{
|
||||
assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
|
||||
TypeTableEntry *return_type = nullptr;
|
||||
node->block_context = context;
|
||||
switch (node->type) {
|
||||
case NodeTypeBlock:
|
||||
return_type = analyze_block_expr(g, import, context, expected_type, node);
|
||||
@ -5889,7 +5898,6 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
|
||||
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->type_entry = return_type;
|
||||
node->block_context = context;
|
||||
|
||||
add_global_const_expr(g, node);
|
||||
|
||||
|
||||
@ -45,11 +45,21 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
|
||||
assert(bn->kind == BigNumKindInt);
|
||||
|
||||
if (is_signed) {
|
||||
if (bn->data.x_uint <= ((uint64_t)(INT8_MAX)) + 1) {
|
||||
if (bn->is_negative) {
|
||||
if (bn->data.x_uint <= ((uint64_t)INT8_MAX) + 1) {
|
||||
return bit_count >= 8;
|
||||
} else if (bn->data.x_uint <= ((uint64_t)INT16_MAX) + 1) {
|
||||
return bit_count >= 16;
|
||||
} else if (bn->data.x_uint <= ((uint64_t)INT32_MAX) + 1) {
|
||||
return bit_count >= 32;
|
||||
} else {
|
||||
return bit_count >= 64;
|
||||
}
|
||||
} else if (bn->data.x_uint <= (uint64_t)INT8_MAX) {
|
||||
return bit_count >= 8;
|
||||
} else if (bn->data.x_uint <= ((uint64_t)(INT16_MAX)) + 1) {
|
||||
} else if (bn->data.x_uint <= (uint64_t)INT16_MAX) {
|
||||
return bit_count >= 16;
|
||||
} else if (bn->data.x_uint <= ((uint64_t)(INT32_MAX)) + 1) {
|
||||
} else if (bn->data.x_uint <= (uint64_t)INT32_MAX) {
|
||||
return bit_count >= 32;
|
||||
} else {
|
||||
return bit_count >= 64;
|
||||
@ -98,6 +108,7 @@ bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
}
|
||||
|
||||
if (op1->is_negative == op2->is_negative) {
|
||||
dest->is_negative = op1->is_negative;
|
||||
return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint);
|
||||
} else if (!op1->is_negative && op2->is_negative) {
|
||||
if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
|
||||
|
||||
205
src/eval.cpp
205
src/eval.cpp
@ -99,14 +99,78 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
if (type_entry->data.integral.bit_count == 64) {
|
||||
return UINT64_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 32) {
|
||||
return UINT32_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 16) {
|
||||
return UINT16_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 8) {
|
||||
return UINT8_MAX;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t max_signed_val(TypeTableEntry *type_entry) {
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
if (type_entry->data.integral.bit_count == 64) {
|
||||
return INT64_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 32) {
|
||||
return INT32_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 16) {
|
||||
return INT16_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 8) {
|
||||
return INT8_MAX;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t min_signed_val(TypeTableEntry *type_entry) {
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
if (type_entry->data.integral.bit_count == 64) {
|
||||
return INT64_MIN;
|
||||
} else if (type_entry->data.integral.bit_count == 32) {
|
||||
return INT32_MIN;
|
||||
} else if (type_entry->data.integral.bit_count == 16) {
|
||||
return INT16_MIN;
|
||||
} else if (type_entry->data.integral.bit_count == 8) {
|
||||
return INT8_MIN;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
|
||||
ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))
|
||||
ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
|
||||
TypeTableEntry *type)
|
||||
{
|
||||
bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
|
||||
if (overflow) {
|
||||
return ErrorOverflow;
|
||||
}
|
||||
|
||||
if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
|
||||
type->data.integral.bit_count, type->data.integral.is_signed))
|
||||
{
|
||||
if (type->data.integral.is_wrapping) {
|
||||
if (type->data.integral.is_signed) {
|
||||
out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
|
||||
out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
|
||||
} else if (out_val->data.x_bignum.is_negative) {
|
||||
out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
|
||||
out_val->data.x_bignum.is_negative = false;
|
||||
} else {
|
||||
bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count);
|
||||
}
|
||||
} else {
|
||||
return ErrorOverflow;
|
||||
}
|
||||
}
|
||||
|
||||
out_val->ok = true;
|
||||
out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
|
||||
return 0;
|
||||
@ -117,6 +181,8 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
{
|
||||
assert(op1_val->ok);
|
||||
assert(op2_val->ok);
|
||||
assert(op1_type->id != TypeTableEntryIdInvalid);
|
||||
assert(op2_type->id != TypeTableEntryIdInvalid);
|
||||
|
||||
switch (bin_op) {
|
||||
case BinOpTypeAssign:
|
||||
@ -132,8 +198,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
case BinOpTypeAssignBitOr:
|
||||
case BinOpTypeAssignBoolAnd:
|
||||
case BinOpTypeAssignBoolOr:
|
||||
out_val->ok = true;
|
||||
return 0;
|
||||
zig_unreachable();
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
assert(op1_type->id == TypeTableEntryIdBool);
|
||||
@ -191,21 +256,21 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
return 0;
|
||||
}
|
||||
case BinOpTypeAdd:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type);
|
||||
case BinOpTypeBinOr:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type);
|
||||
case BinOpTypeBinXor:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type);
|
||||
case BinOpTypeBinAnd:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type);
|
||||
case BinOpTypeBitShiftLeft:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type);
|
||||
case BinOpTypeBitShiftRight:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type);
|
||||
case BinOpTypeSub:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type);
|
||||
case BinOpTypeMult:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type);
|
||||
case BinOpTypeDiv:
|
||||
{
|
||||
bool is_int = false;
|
||||
@ -224,11 +289,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
{
|
||||
return ErrorDivByZero;
|
||||
} else {
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type);
|
||||
}
|
||||
}
|
||||
case BinOpTypeMod:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type);
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
zig_panic("TODO");
|
||||
case BinOpTypeStrCat:
|
||||
@ -244,18 +309,61 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
|
||||
|
||||
AstNode *op1 = node->data.bin_op_expr.op1;
|
||||
AstNode *op2 = node->data.bin_op_expr.op2;
|
||||
BinOpType bin_op = node->data.bin_op_expr.bin_op;
|
||||
|
||||
switch (bin_op) {
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignDiv:
|
||||
case BinOpTypeAssignMod:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
case BinOpTypeAssignBitXor:
|
||||
case BinOpTypeAssignBitOr:
|
||||
case BinOpTypeAssignBoolAnd:
|
||||
case BinOpTypeAssignBoolOr:
|
||||
zig_panic("TODO");
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
case BinOpTypeCmpEq:
|
||||
case BinOpTypeCmpNotEq:
|
||||
case BinOpTypeCmpLessThan:
|
||||
case BinOpTypeCmpGreaterThan:
|
||||
case BinOpTypeCmpLessOrEq:
|
||||
case BinOpTypeCmpGreaterOrEq:
|
||||
case BinOpTypeBinOr:
|
||||
case BinOpTypeBinXor:
|
||||
case BinOpTypeBinAnd:
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeMod:
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
case BinOpTypeStrCat:
|
||||
case BinOpTypeArrayMult:
|
||||
break;
|
||||
case BinOpTypeInvalid:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry;
|
||||
TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry;
|
||||
|
||||
assert(op1_type);
|
||||
assert(op2_type);
|
||||
|
||||
ConstExprValue op1_val = {0};
|
||||
if (eval_expr(ef, op1, &op1_val)) return true;
|
||||
|
||||
ConstExprValue op2_val = {0};
|
||||
if (eval_expr(ef, op2, &op2_val)) return true;
|
||||
|
||||
BinOpType bin_op = node->data.bin_op_expr.bin_op;
|
||||
|
||||
int err;
|
||||
if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) {
|
||||
ef->root->abort = true;
|
||||
@ -568,48 +676,15 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
|
||||
const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
|
||||
if (is_max) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
int64_t val;
|
||||
if (type_entry->data.integral.bit_count == 64) {
|
||||
val = INT64_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 32) {
|
||||
val = INT32_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 16) {
|
||||
val = INT16_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 8) {
|
||||
val = INT8_MAX;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
int64_t val = max_signed_val(type_entry);
|
||||
bignum_init_signed(&const_val->data.x_bignum, val);
|
||||
} else {
|
||||
uint64_t val;
|
||||
if (type_entry->data.integral.bit_count == 64) {
|
||||
val = UINT64_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 32) {
|
||||
val = UINT32_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 16) {
|
||||
val = UINT16_MAX;
|
||||
} else if (type_entry->data.integral.bit_count == 8) {
|
||||
val = UINT8_MAX;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
uint64_t val = max_unsigned_val(type_entry);
|
||||
bignum_init_unsigned(&const_val->data.x_bignum, val);
|
||||
}
|
||||
} else {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
int64_t val;
|
||||
if (type_entry->data.integral.bit_count == 64) {
|
||||
val = INT64_MIN;
|
||||
} else if (type_entry->data.integral.bit_count == 32) {
|
||||
val = INT32_MIN;
|
||||
} else if (type_entry->data.integral.bit_count == 16) {
|
||||
val = INT16_MIN;
|
||||
} else if (type_entry->data.integral.bit_count == 8) {
|
||||
val = INT8_MIN;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
int64_t val = min_signed_val(type_entry);
|
||||
bignum_init_signed(&const_val->data.x_bignum, val);
|
||||
} else {
|
||||
bignum_init_unsigned(&const_val->data.x_bignum, 0);
|
||||
@ -687,6 +762,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
|
||||
return eval_fn_with_overflow(ef, node, out_val, bignum_add);
|
||||
case BuiltinFnIdSubWithOverflow:
|
||||
return eval_fn_with_overflow(ef, node, out_val, bignum_sub);
|
||||
case BuiltinFnIdShlWithOverflow:
|
||||
return eval_fn_with_overflow(ef, node, out_val, bignum_shl);
|
||||
case BuiltinFnIdFence:
|
||||
return false;
|
||||
case BuiltinFnIdMemcpy:
|
||||
@ -707,7 +784,6 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
|
||||
case BuiltinFnIdErrName:
|
||||
case BuiltinFnIdEmbedFile:
|
||||
case BuiltinFnIdCmpExchange:
|
||||
case BuiltinFnIdShlWithOverflow:
|
||||
zig_panic("TODO");
|
||||
case BuiltinFnIdBreakpoint:
|
||||
case BuiltinFnIdInvalid:
|
||||
@ -962,8 +1038,31 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
|
||||
out_val->ok = true;
|
||||
break;
|
||||
}
|
||||
case PrefixOpBinNot:
|
||||
case PrefixOpNegation:
|
||||
if (expr_type->id == TypeTableEntryIdInt) {
|
||||
assert(expr_type->data.integral.is_signed);
|
||||
bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum);
|
||||
out_val->ok = true;
|
||||
bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum,
|
||||
expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
|
||||
if (expr_type->data.integral.is_wrapping) {
|
||||
if (overflow) {
|
||||
out_val->data.x_bignum.is_negative = true;
|
||||
}
|
||||
} else if (overflow) {
|
||||
ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
|
||||
buf_sprintf("function evaluation caused overflow"));
|
||||
add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
|
||||
add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here"));
|
||||
return true;
|
||||
}
|
||||
} else if (expr_type->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
break;
|
||||
case PrefixOpBinNot:
|
||||
case PrefixOpMaybe:
|
||||
case PrefixOpError:
|
||||
case PrefixOpUnwrapError:
|
||||
|
||||
@ -1305,6 +1305,55 @@ fn f() {
|
||||
)SOURCE", 2,
|
||||
".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success",
|
||||
".tmp_source.zig:5:49: error: success atomic ordering must be Monotonic or stricter");
|
||||
|
||||
add_compile_fail_case("negation overflow in function evaluation", R"SOURCE(
|
||||
fn f() {
|
||||
const x = neg(-128);
|
||||
}
|
||||
fn neg(x: i8) -> i8 {
|
||||
-x
|
||||
}
|
||||
)SOURCE", 3,
|
||||
".tmp_source.zig:5:1: error: function evaluation caused overflow",
|
||||
".tmp_source.zig:3:18: note: called from here",
|
||||
".tmp_source.zig:6:5: note: overflow occurred here");
|
||||
|
||||
add_compile_fail_case("add overflow in function evaluation", R"SOURCE(
|
||||
fn f() {
|
||||
const x = add(65530, 10);
|
||||
}
|
||||
fn add(a: u16, b: u16) -> u16 {
|
||||
a + b
|
||||
}
|
||||
)SOURCE", 3,
|
||||
".tmp_source.zig:5:1: error: function evaluation caused overflow",
|
||||
".tmp_source.zig:3:18: note: called from here",
|
||||
".tmp_source.zig:6:7: note: overflow occurred here");
|
||||
|
||||
|
||||
add_compile_fail_case("sub overflow in function evaluation", R"SOURCE(
|
||||
fn f() {
|
||||
const x = sub(10, 20);
|
||||
}
|
||||
fn sub(a: u16, b: u16) -> u16 {
|
||||
a - b
|
||||
}
|
||||
)SOURCE", 3,
|
||||
".tmp_source.zig:5:1: error: function evaluation caused overflow",
|
||||
".tmp_source.zig:3:18: note: called from here",
|
||||
".tmp_source.zig:6:7: note: overflow occurred here");
|
||||
|
||||
add_compile_fail_case("mul overflow in function evaluation", R"SOURCE(
|
||||
fn f() {
|
||||
const x = mul(300, 6000);
|
||||
}
|
||||
fn mul(a: u16, b: u16) -> u16 {
|
||||
a * b
|
||||
}
|
||||
)SOURCE", 3,
|
||||
".tmp_source.zig:5:1: error: function evaluation caused overflow",
|
||||
".tmp_source.zig:3:18: note: called from here",
|
||||
".tmp_source.zig:6:7: note: overflow occurred here");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -1459,68 +1459,72 @@ fn fence() {
|
||||
|
||||
#attribute("test")
|
||||
fn unsigned_wrapping() {
|
||||
var x_u32: u32w = @max_value(u32);
|
||||
x_u32 += 1;
|
||||
assert(x_u32 == 0);
|
||||
x_u32 -= 1;
|
||||
assert(x_u32 == @max_value(u32));
|
||||
test_unsigned_wrapping_eval(@max_value(u32));
|
||||
test_unsigned_wrapping_noeval(@max_value(u32));
|
||||
}
|
||||
fn test_unsigned_wrapping_eval(x: u32w) {
|
||||
const zero = x + 1;
|
||||
assert(zero == 0);
|
||||
const orig = zero - 1;
|
||||
assert(orig == @max_value(u32));
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_unsigned_wrapping_noeval(x: u32w) {
|
||||
var x_u32 = x;
|
||||
x_u32 += 1;
|
||||
assert(x_u32 == 0);
|
||||
x_u32 -= 1;
|
||||
assert(x_u32 == @max_value(u32));
|
||||
const zero = x + 1;
|
||||
assert(zero == 0);
|
||||
const orig = zero - 1;
|
||||
assert(orig == @max_value(u32));
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn signed_wrapping() {
|
||||
var x_i32: i32w = @max_value(i32);
|
||||
x_i32 += 1;
|
||||
assert(x_i32 == @min_value(i32));
|
||||
x_i32 -= 1;
|
||||
assert(x_i32 == @max_value(i32));
|
||||
test_signed_wrapping_eval(@max_value(i32));
|
||||
test_signed_wrapping_noeval(@max_value(i32));
|
||||
}
|
||||
fn test_signed_wrapping_eval(x: i32w) {
|
||||
const min_val = x + 1;
|
||||
assert(min_val == @min_value(i32));
|
||||
const max_val = min_val - 1;
|
||||
assert(max_val == @max_value(i32));
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_signed_wrapping_noeval(x: i32w) {
|
||||
var x_i32 = x;
|
||||
x_i32 += 1;
|
||||
assert(x_i32 == @min_value(i32));
|
||||
x_i32 -= 1;
|
||||
assert(x_i32 == @max_value(i32));
|
||||
const min_val = x + 1;
|
||||
assert(min_val == @min_value(i32));
|
||||
const max_val = min_val - 1;
|
||||
assert(max_val == @max_value(i32));
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn negation_wrapping() {
|
||||
var x_i16 = @min_value(i16w);
|
||||
assert(x_i16 == -32768);
|
||||
x_i16 = -x_i16;
|
||||
assert(x_i16 == -32768);
|
||||
test_negation_wrapping_eval(@min_value(i16));
|
||||
test_negation_wrapping_noeval(@min_value(i16));
|
||||
}
|
||||
fn test_negation_wrapping_eval(x: i16w) {
|
||||
assert(x == -32768);
|
||||
const neg = -x;
|
||||
assert(neg == -32768);
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_negation_wrapping_noeval(x: i16w) {
|
||||
var x_i16 = x;
|
||||
assert(x_i16 == -32768);
|
||||
x_i16 = -x_i16;
|
||||
assert(x_i16 == -32768);
|
||||
assert(x == -32768);
|
||||
const neg = -x;
|
||||
assert(neg == -32768);
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn shl_wrapping() {
|
||||
var x_u16 = @max_value(u16w);
|
||||
x_u16 <<= 1;
|
||||
assert(x_u16 == 65534);
|
||||
test_shl_wrapping_eval(@max_value(u16));
|
||||
test_shl_wrapping_noeval(@max_value(u16));
|
||||
}
|
||||
fn test_shl_wrapping_eval(x: u16w) {
|
||||
const shifted = x << 1;
|
||||
assert(shifted == 65534);
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_shl_wrapping_noeval(x: u16w) {
|
||||
var x_u16 = x;
|
||||
x_u16 <<= 1;
|
||||
assert(x_u16 == 65534);
|
||||
const shifted = x << 1;
|
||||
assert(shifted == 65534);
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user