authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-12 16:18:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-12 16:18:41-07:00
log69109bc270c3167a3534dd32fc4f4def855e0be9
treeb9839d8b4f0a5475328e6c1988bdb9ccf5c862ad
parentbe4df96e4b80a3307b3661fd5ca3114478499daf

add error for dividing by zero in static function evaluation


6 files changed, 65 insertions(+), 58 deletions(-)

src/analyze.cpp+13-47
...@@ -2653,26 +2653,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo...@@ -2653,26 +2653,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo
2653 return g->builtin_types.entry_num_lit_float;2653 return g->builtin_types.entry_num_lit_float;
2654}2654}
26552655
2656static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *node,
2657 bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), AstNode *op1, AstNode *op2,
2658 TypeTableEntry *resolved_type)
2659{
2660 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
2661 ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
2662 ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
2663
2664 const_val->ok = true;
2665
2666 if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
2667 add_node_error(g, node,
2668 buf_sprintf("value cannot be represented in any integer type"));
2669 } else {
2670 num_lit_fits_in_other_type(g, node, resolved_type);
2671 }
2672
2673 return resolved_type;
2674}
2675
2676static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,2656static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
2677 BlockContext *context, AstNode *node, Buf *err_name)2657 BlockContext *context, AstNode *node, Buf *err_name)
2678{2658{
...@@ -3074,37 +3054,23 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -3074,37 +3054,23 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
3074 return resolved_type;3054 return resolved_type;
3075 }3055 }
30763056
3077 if (bin_op_type == BinOpTypeAdd) {3057 ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
3078 return resolve_expr_const_val_as_bignum_op(g, node, bignum_add, *op1, *op2, resolved_type);3058 int err;
3079 } else if (bin_op_type == BinOpTypeSub) {3059 if ((err = eval_const_expr_bin_op(op1_val, resolved_type, bin_op_type,
3080 return resolve_expr_const_val_as_bignum_op(g, node, bignum_sub, *op1, *op2, resolved_type);3060 op2_val, resolved_type, out_val)))
3081 } else if (bin_op_type == BinOpTypeMult) {3061 {
3082 return resolve_expr_const_val_as_bignum_op(g, node, bignum_mul, *op1, *op2, resolved_type);3062 if (err == ErrorDivByZero) {
3083 } else if (bin_op_type == BinOpTypeDiv) {
3084 ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val;
3085 if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
3086 (is_float && op2_val->data.x_bignum.data.x_float == 0.0))
3087 {
3088 add_node_error(g, node, buf_sprintf("division by zero is undefined"));3063 add_node_error(g, node, buf_sprintf("division by zero is undefined"));
3089 return g->builtin_types.entry_invalid;3064 return g->builtin_types.entry_invalid;
3090 } else {3065 } else if (err == ErrorOverflow) {
3091 return resolve_expr_const_val_as_bignum_op(g, node, bignum_div, *op1, *op2, resolved_type);3066 add_node_error(g, node, buf_sprintf("value cannot be represented in any integer type"));
3067 return g->builtin_types.entry_invalid;
3092 }3068 }
3093 } else if (bin_op_type == BinOpTypeMod) {3069 return g->builtin_types.entry_invalid;
3094 return resolve_expr_const_val_as_bignum_op(g, node, bignum_mod, *op1, *op2, resolved_type);
3095 } else if (bin_op_type == BinOpTypeBinOr) {
3096 return resolve_expr_const_val_as_bignum_op(g, node, bignum_or, *op1, *op2, resolved_type);
3097 } else if (bin_op_type == BinOpTypeBinAnd) {
3098 return resolve_expr_const_val_as_bignum_op(g, node, bignum_and, *op1, *op2, resolved_type);
3099 } else if (bin_op_type == BinOpTypeBinXor) {
3100 return resolve_expr_const_val_as_bignum_op(g, node, bignum_xor, *op1, *op2, resolved_type);
3101 } else if (bin_op_type == BinOpTypeBitShiftLeft) {
3102 return resolve_expr_const_val_as_bignum_op(g, node, bignum_shl, *op1, *op2, resolved_type);
3103 } else if (bin_op_type == BinOpTypeBitShiftRight) {
3104 return resolve_expr_const_val_as_bignum_op(g, node, bignum_shr, *op1, *op2, resolved_type);
3105 } else {
3106 zig_unreachable();
3107 }3070 }
3071
3072 num_lit_fits_in_other_type(g, node, resolved_type);
3073 return resolved_type;
3108 }3074 }
3109 case BinOpTypeUnwrapMaybe:3075 case BinOpTypeUnwrapMaybe:
3110 {3076 {
src/error.cpp+2
...@@ -12,6 +12,8 @@ const char *err_str(int err) {...@@ -12,6 +12,8 @@ const char *err_str(int err) {
12 case ErrorFileNotFound: return "file not found";12 case ErrorFileNotFound: return "file not found";
13 case ErrorFileSystem: return "file system error";13 case ErrorFileSystem: return "file system error";
14 case ErrorFileTooBig: return "file too big";14 case ErrorFileTooBig: return "file too big";
15 case ErrorDivByZero: return "division by zero";
16 case ErrorOverflow: return "overflow";
15 }17 }
16 return "(invalid error)";18 return "(invalid error)";
17}19}
src/error.hpp+2
...@@ -19,6 +19,8 @@ enum Error {...@@ -19,6 +19,8 @@ enum Error {
19 ErrorFileNotFound,19 ErrorFileNotFound,
20 ErrorFileSystem,20 ErrorFileSystem,
21 ErrorFileTooBig,21 ErrorFileTooBig,
22 ErrorDivByZero,
23 ErrorOverflow
22};24};
2325
24const char *err_str(int err);26const char *err_str(int err);
src/eval.cpp+37-10
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1#include "eval.hpp"1#include "eval.hpp"
2#include "analyze.hpp"2#include "analyze.hpp"
3#include "error.hpp"
34
4static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val);5static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val);
56
...@@ -96,16 +97,20 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {...@@ -96,16 +97,20 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
96 }97 }
97}98}
9899
99static void eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,100static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
100 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))101 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))
101{102{
102 bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);103 bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
103 assert(!overflow);104 if (overflow) {
105 return ErrorOverflow;
106 }
107
104 out_val->ok = true;108 out_val->ok = true;
105 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;109 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
110 return 0;
106}111}
107112
108void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,113int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
109 BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)114 BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
110{115{
111 assert(op1_val->ok);116 assert(op1_val->ok);
...@@ -126,7 +131,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -126,7 +131,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
126 case BinOpTypeAssignBoolAnd:131 case BinOpTypeAssignBoolAnd:
127 case BinOpTypeAssignBoolOr:132 case BinOpTypeAssignBoolOr:
128 out_val->ok = true;133 out_val->ok = true;
129 return;134 return 0;
130 case BinOpTypeBoolOr:135 case BinOpTypeBoolOr:
131 case BinOpTypeBoolAnd:136 case BinOpTypeBoolAnd:
132 assert(op1_type->id == TypeTableEntryIdBool);137 assert(op1_type->id == TypeTableEntryIdBool);
...@@ -134,7 +139,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -134,7 +139,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
134 out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool);139 out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool);
135 out_val->ok = true;140 out_val->ok = true;
136 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;141 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
137 return;142 return 0;
138 case BinOpTypeCmpEq:143 case BinOpTypeCmpEq:
139 case BinOpTypeCmpNotEq:144 case BinOpTypeCmpNotEq:
140 case BinOpTypeCmpLessThan:145 case BinOpTypeCmpLessThan:
...@@ -181,7 +186,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -181,7 +186,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
181 op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;186 op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
182 out_val->data.x_bool = answer;187 out_val->data.x_bool = answer;
183 out_val->ok = true;188 out_val->ok = true;
184 return;189 return 0;
185 }190 }
186 case BinOpTypeAdd:191 case BinOpTypeAdd:
187 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add);192 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,...@@ -215,7 +220,7 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
215 if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||220 if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
216 (is_float && op2_val->data.x_bignum.data.x_float == 0.0))221 (is_float && op2_val->data.x_bignum.data.x_float == 0.0))
217 {222 {
218 zig_panic("TODO handle errors in eval");223 return ErrorDivByZero;
219 } else {224 } else {
220 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);225 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);
221 }226 }
...@@ -249,7 +254,26 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)...@@ -249,7 +254,26 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
249254
250 BinOpType bin_op = node->data.bin_op_expr.bin_op;255 BinOpType bin_op = node->data.bin_op_expr.bin_op;
251256
252 eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val);257 int err;
258 if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) {
259 ef->root->abort = true;
260 if (err == ErrorDivByZero) {
261 ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
262 buf_sprintf("function evaluation caused division by zero"));
263 add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
264 add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here"));
265 } else if (err == ErrorOverflow) {
266 ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
267 buf_sprintf("function evaluation caused overflow"));
268 add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
269 add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here"));
270 } else {
271 zig_unreachable();
272 }
273 return true;
274 }
275
276 assert(out_val->ok);
253277
254 return false;278 return false;
255}279}
...@@ -1133,8 +1157,11 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va...@@ -1133,8 +1157,11 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
1133 return true;1157 return true;
1134 }1158 }
11351159
1136 assert(out_val->ok);1160 if (efr.abort) {
1161 return true;
1162 }
11371163
1138 return efr.abort;1164 assert(out_val->ok);
1165 return false;
1139}1166}
11401167
src/eval.hpp+1-1
...@@ -14,7 +14,7 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va...@@ -14,7 +14,7 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
14 AstNode *struct_node);14 AstNode *struct_node);
1515
16bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);16bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
17void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,17int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
18 BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val);18 BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val);
1919
20void eval_const_expr_implicit_cast(CastOp cast_op,20void eval_const_expr_implicit_cast(CastOp cast_op,
test/run_tests.cpp+10
...@@ -1481,6 +1481,16 @@ fn foo() {...@@ -1481,6 +1481,16 @@ fn foo() {
1481 const pointer = &array[0];1481 const pointer = &array[0];
1482}1482}
1483 )SOURCE", 1, ".tmp_source.zig:4:27: error: out of bounds array access");1483 )SOURCE", 1, ".tmp_source.zig:4:27: error: out of bounds array access");
1484
1485 add_compile_fail_case("compile time division by zero", R"SOURCE(
1486const x = foo(0);
1487fn foo(x: i32) -> i32 {
1488 1 / x
1489}
1490 )SOURCE", 3,
1491 ".tmp_source.zig:3:1: error: function evaluation caused division by zero",
1492 ".tmp_source.zig:2:14: note: called from here",
1493 ".tmp_source.zig:4:7: note: division by zero here");
1484}1494}
14851495
1486//////////////////////////////////////////////////////////////////////////////1496//////////////////////////////////////////////////////////////////////////////