mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
add error for dividing by zero in static function evaluation
This commit is contained in:
parent
be4df96e4b
commit
69109bc270
@ -2653,26 +2653,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo
|
||||
return g->builtin_types.entry_num_lit_float;
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *node,
|
||||
bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), AstNode *op1, AstNode *op2,
|
||||
TypeTableEntry *resolved_type)
|
||||
{
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
|
||||
ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
|
||||
|
||||
const_val->ok = true;
|
||||
|
||||
if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("value cannot be represented in any integer type"));
|
||||
} else {
|
||||
num_lit_fits_in_other_type(g, node, resolved_type);
|
||||
}
|
||||
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *context, AstNode *node, Buf *err_name)
|
||||
{
|
||||
@ -3074,37 +3054,23 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
if (bin_op_type == BinOpTypeAdd) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_add, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeSub) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_sub, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeMult) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_mul, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeDiv) {
|
||||
ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
|
||||
if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
|
||||
(is_float && op2_val->data.x_bignum.data.x_float == 0.0))
|
||||
{
|
||||
ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
|
||||
int err;
|
||||
if ((err = eval_const_expr_bin_op(op1_val, resolved_type, bin_op_type,
|
||||
op2_val, resolved_type, out_val)))
|
||||
{
|
||||
if (err == ErrorDivByZero) {
|
||||
add_node_error(g, node, buf_sprintf("division by zero is undefined"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_div, *op1, *op2, resolved_type);
|
||||
} else if (err == ErrorOverflow) {
|
||||
add_node_error(g, node, buf_sprintf("value cannot be represented in any integer type"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (bin_op_type == BinOpTypeMod) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_mod, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBinOr) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_or, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBinAnd) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_and, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBinXor) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_xor, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBitShiftLeft) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_shl, *op1, *op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBitShiftRight) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_shr, *op1, *op2, resolved_type);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
num_lit_fits_in_other_type(g, node, resolved_type);
|
||||
return resolved_type;
|
||||
}
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
{
|
||||
|
||||
@ -12,6 +12,8 @@ const char *err_str(int err) {
|
||||
case ErrorFileNotFound: return "file not found";
|
||||
case ErrorFileSystem: return "file system error";
|
||||
case ErrorFileTooBig: return "file too big";
|
||||
case ErrorDivByZero: return "division by zero";
|
||||
case ErrorOverflow: return "overflow";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ enum Error {
|
||||
ErrorFileNotFound,
|
||||
ErrorFileSystem,
|
||||
ErrorFileTooBig,
|
||||
ErrorDivByZero,
|
||||
ErrorOverflow
|
||||
};
|
||||
|
||||
const char *err_str(int err);
|
||||
|
||||
47
src/eval.cpp
47
src/eval.cpp
@ -1,5 +1,6 @@
|
||||
#include "eval.hpp"
|
||||
#include "analyze.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val);
|
||||
|
||||
@ -96,16 +97,20 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
|
||||
}
|
||||
}
|
||||
|
||||
static void eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
|
||||
static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
|
||||
ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))
|
||||
{
|
||||
bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
|
||||
assert(!overflow);
|
||||
if (overflow) {
|
||||
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;
|
||||
}
|
||||
|
||||
void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
|
||||
{
|
||||
assert(op1_val->ok);
|
||||
@ -126,7 +131,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
case BinOpTypeAssignBoolAnd:
|
||||
case BinOpTypeAssignBoolOr:
|
||||
out_val->ok = true;
|
||||
return;
|
||||
return 0;
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
assert(op1_type->id == TypeTableEntryIdBool);
|
||||
@ -134,7 +139,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool);
|
||||
out_val->ok = true;
|
||||
out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
|
||||
return;
|
||||
return 0;
|
||||
case BinOpTypeCmpEq:
|
||||
case BinOpTypeCmpNotEq:
|
||||
case BinOpTypeCmpLessThan:
|
||||
@ -181,7 +186,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
|
||||
out_val->data.x_bool = answer;
|
||||
out_val->ok = true;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
case BinOpTypeAdd:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add);
|
||||
@ -215,7 +220,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
|
||||
(is_float && op2_val->data.x_bignum.data.x_float == 0.0))
|
||||
{
|
||||
zig_panic("TODO handle errors in eval");
|
||||
return ErrorDivByZero;
|
||||
} else {
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);
|
||||
}
|
||||
@ -249,7 +254,26 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
|
||||
|
||||
BinOpType bin_op = node->data.bin_op_expr.bin_op;
|
||||
|
||||
eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val);
|
||||
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;
|
||||
if (err == ErrorDivByZero) {
|
||||
ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
|
||||
buf_sprintf("function evaluation caused division by zero"));
|
||||
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("division by zero here"));
|
||||
} else if (err == ErrorOverflow) {
|
||||
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"));
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(out_val->ok);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1133,8 +1157,11 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(out_val->ok);
|
||||
if (efr.abort) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return efr.abort;
|
||||
assert(out_val->ok);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
|
||||
AstNode *struct_node);
|
||||
|
||||
bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
|
||||
void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val);
|
||||
|
||||
void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
|
||||
@ -1481,6 +1481,16 @@ fn foo() {
|
||||
const pointer = &array[0];
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:4:27: error: out of bounds array access");
|
||||
|
||||
add_compile_fail_case("compile time division by zero", R"SOURCE(
|
||||
const x = foo(0);
|
||||
fn foo(x: i32) -> i32 {
|
||||
1 / x
|
||||
}
|
||||
)SOURCE", 3,
|
||||
".tmp_source.zig:3:1: error: function evaluation caused division by zero",
|
||||
".tmp_source.zig:2:14: note: called from here",
|
||||
".tmp_source.zig:4:7: note: division by zero here");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user