authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-06 19:23:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-06 19:23:21-07:00
log6131b3716322d60cf26f7aad1a654dc6c4414051
tree4074ccc95115627bd87d319880526c5278fe7e09
parent9db45ac36230c80c68af7b66827b6c73fc96c147

fix eval integer wrapping and add tests

See #46

5 files changed, 269 insertions(+), 98 deletions(-)

src/analyze.cpp+16-8
...@@ -105,11 +105,25 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -105,11 +105,25 @@ static AstNode *first_executing_node(AstNode *node) {
105 zig_unreachable();105 zig_unreachable();
106}106}
107107
108static void mark_impure_fn(BlockContext *context) {
109 if (context->fn_entry) {
110 context->fn_entry->is_pure = false;
111 }
112}
113
108ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {114ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
109 // if this assert fails, then parseh generated code that115 // if this assert fails, then parseh generated code that
110 // failed semantic analysis, which isn't supposed to happen116 // failed semantic analysis, which isn't supposed to happen
111 assert(!node->owner->c_import_node);117 assert(!node->owner->c_import_node);
112118
119 // if an error occurs in a function then it becomes impure
120 if (node->block_context) {
121 FnTableEntry *fn_entry = node->block_context->fn_entry;
122 if (fn_entry) {
123 fn_entry->is_pure = false;
124 }
125 }
126
113 ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,127 ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
114 node->owner->source_code, node->owner->line_offsets, msg);128 node->owner->source_code, node->owner->line_offsets, msg);
115129
...@@ -2620,12 +2634,6 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,...@@ -2620,12 +2634,6 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
2620 return return_type;2634 return return_type;
2621}2635}
26222636
2623static void mark_impure_fn(BlockContext *context) {
2624 if (context->fn_entry) {
2625 context->fn_entry->is_pure = false;
2626 }
2627}
2628
2629static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2637static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2630 AstNode *node)2638 AstNode *node)
2631{2639{
...@@ -5149,7 +5157,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -5149,7 +5157,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
5149 }5157 }
5150 case PrefixOpNegation:5158 case PrefixOpNegation:
5151 {5159 {
5152 TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, *expr_node);5160 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
5153 if (expr_type->id == TypeTableEntryIdInvalid) {5161 if (expr_type->id == TypeTableEntryIdInvalid) {
5154 return expr_type;5162 return expr_type;
5155 } else if ((expr_type->id == TypeTableEntryIdInt &&5163 } else if ((expr_type->id == TypeTableEntryIdInt &&
...@@ -5762,6 +5770,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn...@@ -5762,6 +5770,7 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
5762{5770{
5763 assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);5771 assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
5764 TypeTableEntry *return_type = nullptr;5772 TypeTableEntry *return_type = nullptr;
5773 node->block_context = context;
5765 switch (node->type) {5774 switch (node->type) {
5766 case NodeTypeBlock:5775 case NodeTypeBlock:
5767 return_type = analyze_block_expr(g, import, context, expected_type, node);5776 return_type = analyze_block_expr(g, import, context, expected_type, node);
...@@ -5889,7 +5898,6 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn...@@ -5889,7 +5898,6 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
58895898
5890 Expr *expr = get_resolved_expr(node);5899 Expr *expr = get_resolved_expr(node);
5891 expr->type_entry = return_type;5900 expr->type_entry = return_type;
5892 node->block_context = context;
58935901
5894 add_global_const_expr(g, node);5902 add_global_const_expr(g, node);
58955903
src/bignum.cpp+14-3
...@@ -45,11 +45,21 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {...@@ -45,11 +45,21 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
45 assert(bn->kind == BigNumKindInt);45 assert(bn->kind == BigNumKindInt);
4646
47 if (is_signed) {47 if (is_signed) {
48 if (bn->data.x_uint <= ((uint64_t)(INT8_MAX)) + 1) {48 if (bn->is_negative) {
49 if (bn->data.x_uint <= ((uint64_t)INT8_MAX) + 1) {
50 return bit_count >= 8;
51 } else if (bn->data.x_uint <= ((uint64_t)INT16_MAX) + 1) {
52 return bit_count >= 16;
53 } else if (bn->data.x_uint <= ((uint64_t)INT32_MAX) + 1) {
54 return bit_count >= 32;
55 } else {
56 return bit_count >= 64;
57 }
58 } else if (bn->data.x_uint <= (uint64_t)INT8_MAX) {
49 return bit_count >= 8;59 return bit_count >= 8;
50 } else if (bn->data.x_uint <= ((uint64_t)(INT16_MAX)) + 1) {60 } else if (bn->data.x_uint <= (uint64_t)INT16_MAX) {
51 return bit_count >= 16;61 return bit_count >= 16;
52 } else if (bn->data.x_uint <= ((uint64_t)(INT32_MAX)) + 1) {62 } else if (bn->data.x_uint <= (uint64_t)INT32_MAX) {
53 return bit_count >= 32;63 return bit_count >= 32;
54 } else {64 } else {
55 return bit_count >= 64;65 return bit_count >= 64;
...@@ -98,6 +108,7 @@ bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) {...@@ -98,6 +108,7 @@ bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) {
98 }108 }
99109
100 if (op1->is_negative == op2->is_negative) {110 if (op1->is_negative == op2->is_negative) {
111 dest->is_negative = op1->is_negative;
101 return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint);112 return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint);
102 } else if (!op1->is_negative && op2->is_negative) {113 } else if (!op1->is_negative && op2->is_negative) {
103 if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {114 if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
src/eval.cpp+152-53
...@@ -99,14 +99,78 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {...@@ -99,14 +99,78 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
99 }99 }
100}100}
101101
102static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
103 assert(type_entry->id == TypeTableEntryIdInt);
104 if (type_entry->data.integral.bit_count == 64) {
105 return UINT64_MAX;
106 } else if (type_entry->data.integral.bit_count == 32) {
107 return UINT32_MAX;
108 } else if (type_entry->data.integral.bit_count == 16) {
109 return UINT16_MAX;
110 } else if (type_entry->data.integral.bit_count == 8) {
111 return UINT8_MAX;
112 } else {
113 zig_unreachable();
114 }
115}
116
117static int64_t max_signed_val(TypeTableEntry *type_entry) {
118 assert(type_entry->id == TypeTableEntryIdInt);
119 if (type_entry->data.integral.bit_count == 64) {
120 return INT64_MAX;
121 } else if (type_entry->data.integral.bit_count == 32) {
122 return INT32_MAX;
123 } else if (type_entry->data.integral.bit_count == 16) {
124 return INT16_MAX;
125 } else if (type_entry->data.integral.bit_count == 8) {
126 return INT8_MAX;
127 } else {
128 zig_unreachable();
129 }
130}
131
132static int64_t min_signed_val(TypeTableEntry *type_entry) {
133 assert(type_entry->id == TypeTableEntryIdInt);
134 if (type_entry->data.integral.bit_count == 64) {
135 return INT64_MIN;
136 } else if (type_entry->data.integral.bit_count == 32) {
137 return INT32_MIN;
138 } else if (type_entry->data.integral.bit_count == 16) {
139 return INT16_MIN;
140 } else if (type_entry->data.integral.bit_count == 8) {
141 return INT8_MIN;
142 } else {
143 zig_unreachable();
144 }
145}
146
102static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,147static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
103 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))148 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
149 TypeTableEntry *type)
104{150{
105 bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);151 bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
106 if (overflow) {152 if (overflow) {
107 return ErrorOverflow;153 return ErrorOverflow;
108 }154 }
109155
156 if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
157 type->data.integral.bit_count, type->data.integral.is_signed))
158 {
159 if (type->data.integral.is_wrapping) {
160 if (type->data.integral.is_signed) {
161 out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
162 out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
163 } else if (out_val->data.x_bignum.is_negative) {
164 out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
165 out_val->data.x_bignum.is_negative = false;
166 } else {
167 bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count);
168 }
169 } else {
170 return ErrorOverflow;
171 }
172 }
173
110 out_val->ok = true;174 out_val->ok = true;
111 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;175 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
112 return 0;176 return 0;
...@@ -117,6 +181,8 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -117,6 +181,8 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
117{181{
118 assert(op1_val->ok);182 assert(op1_val->ok);
119 assert(op2_val->ok);183 assert(op2_val->ok);
184 assert(op1_type->id != TypeTableEntryIdInvalid);
185 assert(op2_type->id != TypeTableEntryIdInvalid);
120186
121 switch (bin_op) {187 switch (bin_op) {
122 case BinOpTypeAssign:188 case BinOpTypeAssign:
...@@ -132,8 +198,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -132,8 +198,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
132 case BinOpTypeAssignBitOr:198 case BinOpTypeAssignBitOr:
133 case BinOpTypeAssignBoolAnd:199 case BinOpTypeAssignBoolAnd:
134 case BinOpTypeAssignBoolOr:200 case BinOpTypeAssignBoolOr:
135 out_val->ok = true;201 zig_unreachable();
136 return 0;
137 case BinOpTypeBoolOr:202 case BinOpTypeBoolOr:
138 case BinOpTypeBoolAnd:203 case BinOpTypeBoolAnd:
139 assert(op1_type->id == TypeTableEntryIdBool);204 assert(op1_type->id == TypeTableEntryIdBool);
...@@ -191,21 +256,21 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -191,21 +256,21 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
191 return 0;256 return 0;
192 }257 }
193 case BinOpTypeAdd:258 case BinOpTypeAdd:
194 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add);259 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type);
195 case BinOpTypeBinOr:260 case BinOpTypeBinOr:
196 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or);261 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type);
197 case BinOpTypeBinXor:262 case BinOpTypeBinXor:
198 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor);263 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type);
199 case BinOpTypeBinAnd:264 case BinOpTypeBinAnd:
200 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and);265 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type);
201 case BinOpTypeBitShiftLeft:266 case BinOpTypeBitShiftLeft:
202 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl);267 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type);
203 case BinOpTypeBitShiftRight:268 case BinOpTypeBitShiftRight:
204 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr);269 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type);
205 case BinOpTypeSub:270 case BinOpTypeSub:
206 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub);271 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type);
207 case BinOpTypeMult:272 case BinOpTypeMult:
208 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul);273 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type);
209 case BinOpTypeDiv:274 case BinOpTypeDiv:
210 {275 {
211 bool is_int = false;276 bool is_int = false;
...@@ -224,11 +289,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,...@@ -224,11 +289,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
224 {289 {
225 return ErrorDivByZero;290 return ErrorDivByZero;
226 } else {291 } else {
227 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);292 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type);
228 }293 }
229 }294 }
230 case BinOpTypeMod:295 case BinOpTypeMod:
231 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod);296 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type);
232 case BinOpTypeUnwrapMaybe:297 case BinOpTypeUnwrapMaybe:
233 zig_panic("TODO");298 zig_panic("TODO");
234 case BinOpTypeStrCat:299 case BinOpTypeStrCat:
...@@ -244,18 +309,61 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)...@@ -244,18 +309,61 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
244309
245 AstNode *op1 = node->data.bin_op_expr.op1;310 AstNode *op1 = node->data.bin_op_expr.op1;
246 AstNode *op2 = node->data.bin_op_expr.op2;311 AstNode *op2 = node->data.bin_op_expr.op2;
312 BinOpType bin_op = node->data.bin_op_expr.bin_op;
313
314 switch (bin_op) {
315 case BinOpTypeAssign:
316 case BinOpTypeAssignTimes:
317 case BinOpTypeAssignDiv:
318 case BinOpTypeAssignMod:
319 case BinOpTypeAssignPlus:
320 case BinOpTypeAssignMinus:
321 case BinOpTypeAssignBitShiftLeft:
322 case BinOpTypeAssignBitShiftRight:
323 case BinOpTypeAssignBitAnd:
324 case BinOpTypeAssignBitXor:
325 case BinOpTypeAssignBitOr:
326 case BinOpTypeAssignBoolAnd:
327 case BinOpTypeAssignBoolOr:
328 zig_panic("TODO");
329 case BinOpTypeBoolOr:
330 case BinOpTypeBoolAnd:
331 case BinOpTypeCmpEq:
332 case BinOpTypeCmpNotEq:
333 case BinOpTypeCmpLessThan:
334 case BinOpTypeCmpGreaterThan:
335 case BinOpTypeCmpLessOrEq:
336 case BinOpTypeCmpGreaterOrEq:
337 case BinOpTypeBinOr:
338 case BinOpTypeBinXor:
339 case BinOpTypeBinAnd:
340 case BinOpTypeBitShiftLeft:
341 case BinOpTypeBitShiftRight:
342 case BinOpTypeAdd:
343 case BinOpTypeSub:
344 case BinOpTypeMult:
345 case BinOpTypeDiv:
346 case BinOpTypeMod:
347 case BinOpTypeUnwrapMaybe:
348 case BinOpTypeStrCat:
349 case BinOpTypeArrayMult:
350 break;
351 case BinOpTypeInvalid:
352 zig_unreachable();
353 }
247354
248 TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry;355 TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry;
249 TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry;356 TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry;
250357
358 assert(op1_type);
359 assert(op2_type);
360
251 ConstExprValue op1_val = {0};361 ConstExprValue op1_val = {0};
252 if (eval_expr(ef, op1, &op1_val)) return true;362 if (eval_expr(ef, op1, &op1_val)) return true;
253363
254 ConstExprValue op2_val = {0};364 ConstExprValue op2_val = {0};
255 if (eval_expr(ef, op2, &op2_val)) return true;365 if (eval_expr(ef, op2, &op2_val)) return true;
256366
257 BinOpType bin_op = node->data.bin_op_expr.bin_op;
258
259 int err;367 int err;
260 if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) {368 if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) {
261 ef->root->abort = true;369 ef->root->abort = true;
...@@ -568,48 +676,15 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *...@@ -568,48 +676,15 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
568 const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);676 const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
569 if (is_max) {677 if (is_max) {
570 if (type_entry->data.integral.is_signed) {678 if (type_entry->data.integral.is_signed) {
571 int64_t val;679 int64_t val = max_signed_val(type_entry);
572 if (type_entry->data.integral.bit_count == 64) {
573 val = INT64_MAX;
574 } else if (type_entry->data.integral.bit_count == 32) {
575 val = INT32_MAX;
576 } else if (type_entry->data.integral.bit_count == 16) {
577 val = INT16_MAX;
578 } else if (type_entry->data.integral.bit_count == 8) {
579 val = INT8_MAX;
580 } else {
581 zig_unreachable();
582 }
583 bignum_init_signed(&const_val->data.x_bignum, val);680 bignum_init_signed(&const_val->data.x_bignum, val);
584 } else {681 } else {
585 uint64_t val;682 uint64_t val = max_unsigned_val(type_entry);
586 if (type_entry->data.integral.bit_count == 64) {
587 val = UINT64_MAX;
588 } else if (type_entry->data.integral.bit_count == 32) {
589 val = UINT32_MAX;
590 } else if (type_entry->data.integral.bit_count == 16) {
591 val = UINT16_MAX;
592 } else if (type_entry->data.integral.bit_count == 8) {
593 val = UINT8_MAX;
594 } else {
595 zig_unreachable();
596 }
597 bignum_init_unsigned(&const_val->data.x_bignum, val);683 bignum_init_unsigned(&const_val->data.x_bignum, val);
598 }684 }
599 } else {685 } else {
600 if (type_entry->data.integral.is_signed) {686 if (type_entry->data.integral.is_signed) {
601 int64_t val;687 int64_t val = min_signed_val(type_entry);
602 if (type_entry->data.integral.bit_count == 64) {
603 val = INT64_MIN;
604 } else if (type_entry->data.integral.bit_count == 32) {
605 val = INT32_MIN;
606 } else if (type_entry->data.integral.bit_count == 16) {
607 val = INT16_MIN;
608 } else if (type_entry->data.integral.bit_count == 8) {
609 val = INT8_MIN;
610 } else {
611 zig_unreachable();
612 }
613 bignum_init_signed(&const_val->data.x_bignum, val);688 bignum_init_signed(&const_val->data.x_bignum, val);
614 } else {689 } else {
615 bignum_init_unsigned(&const_val->data.x_bignum, 0);690 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_...@@ -687,6 +762,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
687 return eval_fn_with_overflow(ef, node, out_val, bignum_add);762 return eval_fn_with_overflow(ef, node, out_val, bignum_add);
688 case BuiltinFnIdSubWithOverflow:763 case BuiltinFnIdSubWithOverflow:
689 return eval_fn_with_overflow(ef, node, out_val, bignum_sub);764 return eval_fn_with_overflow(ef, node, out_val, bignum_sub);
765 case BuiltinFnIdShlWithOverflow:
766 return eval_fn_with_overflow(ef, node, out_val, bignum_shl);
690 case BuiltinFnIdFence:767 case BuiltinFnIdFence:
691 return false;768 return false;
692 case BuiltinFnIdMemcpy:769 case BuiltinFnIdMemcpy:
...@@ -707,7 +784,6 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_...@@ -707,7 +784,6 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
707 case BuiltinFnIdErrName:784 case BuiltinFnIdErrName:
708 case BuiltinFnIdEmbedFile:785 case BuiltinFnIdEmbedFile:
709 case BuiltinFnIdCmpExchange:786 case BuiltinFnIdCmpExchange:
710 case BuiltinFnIdShlWithOverflow:
711 zig_panic("TODO");787 zig_panic("TODO");
712 case BuiltinFnIdBreakpoint:788 case BuiltinFnIdBreakpoint:
713 case BuiltinFnIdInvalid:789 case BuiltinFnIdInvalid:
...@@ -962,8 +1038,31 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v...@@ -962,8 +1038,31 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
962 out_val->ok = true;1038 out_val->ok = true;
963 break;1039 break;
964 }1040 }
965 case PrefixOpBinNot:
966 case PrefixOpNegation:1041 case PrefixOpNegation:
1042 if (expr_type->id == TypeTableEntryIdInt) {
1043 assert(expr_type->data.integral.is_signed);
1044 bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum);
1045 out_val->ok = true;
1046 bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum,
1047 expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
1048 if (expr_type->data.integral.is_wrapping) {
1049 if (overflow) {
1050 out_val->data.x_bignum.is_negative = true;
1051 }
1052 } else if (overflow) {
1053 ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
1054 buf_sprintf("function evaluation caused overflow"));
1055 add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
1056 add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here"));
1057 return true;
1058 }
1059 } else if (expr_type->id == TypeTableEntryIdFloat) {
1060 zig_panic("TODO");
1061 } else {
1062 zig_unreachable();
1063 }
1064 break;
1065 case PrefixOpBinNot:
967 case PrefixOpMaybe:1066 case PrefixOpMaybe:
968 case PrefixOpError:1067 case PrefixOpError:
969 case PrefixOpUnwrapError:1068 case PrefixOpUnwrapError:
test/run_tests.cpp+49
...@@ -1305,6 +1305,55 @@ fn f() {...@@ -1305,6 +1305,55 @@ fn f() {
1305 )SOURCE", 2,1305 )SOURCE", 2,
1306 ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success",1306 ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success",
1307 ".tmp_source.zig:5:49: error: success atomic ordering must be Monotonic or stricter");1307 ".tmp_source.zig:5:49: error: success atomic ordering must be Monotonic or stricter");
1308
1309 add_compile_fail_case("negation overflow in function evaluation", R"SOURCE(
1310fn f() {
1311 const x = neg(-128);
1312}
1313fn neg(x: i8) -> i8 {
1314 -x
1315}
1316 )SOURCE", 3,
1317 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1318 ".tmp_source.zig:3:18: note: called from here",
1319 ".tmp_source.zig:6:5: note: overflow occurred here");
1320
1321 add_compile_fail_case("add overflow in function evaluation", R"SOURCE(
1322fn f() {
1323 const x = add(65530, 10);
1324}
1325fn add(a: u16, b: u16) -> u16 {
1326 a + b
1327}
1328 )SOURCE", 3,
1329 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1330 ".tmp_source.zig:3:18: note: called from here",
1331 ".tmp_source.zig:6:7: note: overflow occurred here");
1332
1333
1334 add_compile_fail_case("sub overflow in function evaluation", R"SOURCE(
1335fn f() {
1336 const x = sub(10, 20);
1337}
1338fn sub(a: u16, b: u16) -> u16 {
1339 a - b
1340}
1341 )SOURCE", 3,
1342 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1343 ".tmp_source.zig:3:18: note: called from here",
1344 ".tmp_source.zig:6:7: note: overflow occurred here");
1345
1346 add_compile_fail_case("mul overflow in function evaluation", R"SOURCE(
1347fn f() {
1348 const x = mul(300, 6000);
1349}
1350fn mul(a: u16, b: u16) -> u16 {
1351 a * b
1352}
1353 )SOURCE", 3,
1354 ".tmp_source.zig:5:1: error: function evaluation caused overflow",
1355 ".tmp_source.zig:3:18: note: called from here",
1356 ".tmp_source.zig:6:7: note: overflow occurred here");
1308}1357}
13091358
1310//////////////////////////////////////////////////////////////////////////////1359//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+38-34
...@@ -1459,68 +1459,72 @@ fn fence() {...@@ -1459,68 +1459,72 @@ fn fence() {
14591459
1460#attribute("test")1460#attribute("test")
1461fn unsigned_wrapping() {1461fn unsigned_wrapping() {
1462 var x_u32: u32w = @max_value(u32);1462 test_unsigned_wrapping_eval(@max_value(u32));
1463 x_u32 += 1;
1464 assert(x_u32 == 0);
1465 x_u32 -= 1;
1466 assert(x_u32 == @max_value(u32));
1467 test_unsigned_wrapping_noeval(@max_value(u32));1463 test_unsigned_wrapping_noeval(@max_value(u32));
1468}1464}
1465fn test_unsigned_wrapping_eval(x: u32w) {
1466 const zero = x + 1;
1467 assert(zero == 0);
1468 const orig = zero - 1;
1469 assert(orig == @max_value(u32));
1470}
1469#static_eval_enable(false)1471#static_eval_enable(false)
1470fn test_unsigned_wrapping_noeval(x: u32w) {1472fn test_unsigned_wrapping_noeval(x: u32w) {
1471 var x_u32 = x;1473 const zero = x + 1;
1472 x_u32 += 1;1474 assert(zero == 0);
1473 assert(x_u32 == 0);1475 const orig = zero - 1;
1474 x_u32 -= 1;1476 assert(orig == @max_value(u32));
1475 assert(x_u32 == @max_value(u32));
1476}1477}
14771478
1478#attribute("test")1479#attribute("test")
1479fn signed_wrapping() {1480fn signed_wrapping() {
1480 var x_i32: i32w = @max_value(i32);1481 test_signed_wrapping_eval(@max_value(i32));
1481 x_i32 += 1;
1482 assert(x_i32 == @min_value(i32));
1483 x_i32 -= 1;
1484 assert(x_i32 == @max_value(i32));
1485 test_signed_wrapping_noeval(@max_value(i32));1482 test_signed_wrapping_noeval(@max_value(i32));
1486}1483}
1484fn test_signed_wrapping_eval(x: i32w) {
1485 const min_val = x + 1;
1486 assert(min_val == @min_value(i32));
1487 const max_val = min_val - 1;
1488 assert(max_val == @max_value(i32));
1489}
1487#static_eval_enable(false)1490#static_eval_enable(false)
1488fn test_signed_wrapping_noeval(x: i32w) {1491fn test_signed_wrapping_noeval(x: i32w) {
1489 var x_i32 = x;1492 const min_val = x + 1;
1490 x_i32 += 1;1493 assert(min_val == @min_value(i32));
1491 assert(x_i32 == @min_value(i32));1494 const max_val = min_val - 1;
1492 x_i32 -= 1;1495 assert(max_val == @max_value(i32));
1493 assert(x_i32 == @max_value(i32));
1494}1496}
14951497
1496#attribute("test")1498#attribute("test")
1497fn negation_wrapping() {1499fn negation_wrapping() {
1498 var x_i16 = @min_value(i16w);1500 test_negation_wrapping_eval(@min_value(i16));
1499 assert(x_i16 == -32768);
1500 x_i16 = -x_i16;
1501 assert(x_i16 == -32768);
1502 test_negation_wrapping_noeval(@min_value(i16));1501 test_negation_wrapping_noeval(@min_value(i16));
1503}1502}
1503fn test_negation_wrapping_eval(x: i16w) {
1504 assert(x == -32768);
1505 const neg = -x;
1506 assert(neg == -32768);
1507}
1504#static_eval_enable(false)1508#static_eval_enable(false)
1505fn test_negation_wrapping_noeval(x: i16w) {1509fn test_negation_wrapping_noeval(x: i16w) {
1506 var x_i16 = x;1510 assert(x == -32768);
1507 assert(x_i16 == -32768);1511 const neg = -x;
1508 x_i16 = -x_i16;1512 assert(neg == -32768);
1509 assert(x_i16 == -32768);
1510}1513}
15111514
1512#attribute("test")1515#attribute("test")
1513fn shl_wrapping() {1516fn shl_wrapping() {
1514 var x_u16 = @max_value(u16w);1517 test_shl_wrapping_eval(@max_value(u16));
1515 x_u16 <<= 1;
1516 assert(x_u16 == 65534);
1517 test_shl_wrapping_noeval(@max_value(u16));1518 test_shl_wrapping_noeval(@max_value(u16));
1518}1519}
1520fn test_shl_wrapping_eval(x: u16w) {
1521 const shifted = x << 1;
1522 assert(shifted == 65534);
1523}
1519#static_eval_enable(false)1524#static_eval_enable(false)
1520fn test_shl_wrapping_noeval(x: u16w) {1525fn test_shl_wrapping_noeval(x: u16w) {
1521 var x_u16 = x;1526 const shifted = x << 1;
1522 x_u16 <<= 1;1527 assert(shifted == 65534);
1523 assert(x_u16 == 65534);
1524}1528}
15251529
1526#attribute("test")1530#attribute("test")