| author | |
| committer | |
| log | 49a4b1b9309de06f7a359836788dfff447003f1b |
| tree | 4ee4ce61cf93e17f0b6cdcbfd35a0935995897ee |
| parent | a5251a1c102334a5dcb07e4fcc2b676be55fe2be |
This commit also fixes a bug where pure functions are marked with
the read-only attribute in debug mode. This resulted in incorrect
codegen because calls to read-only functions with unused values
were not generated.
For example, a call to assert() would not be generated if assert
is marked with read-only. Which it *is* marked with in release
mode.5 files changed, 42 insertions(+), 1 deletions(-)
src/all_types.hpp+1| ... | ... | @@ -383,6 +383,7 @@ enum CastOp { |
| 383 | 383 | CastOpFloatToInt, |
| 384 | 384 | CastOpBoolToInt, |
| 385 | 385 | CastOpResizeSlice, |
| 386 | CastOpIntToEnum, | |
| 386 | 387 | }; |
| 387 | 388 | |
| 388 | 389 | struct AstNodeFnCallExpr { |
src/analyze.cpp+8| ... | ... | @@ -4428,6 +4428,14 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 4428 | 4428 | } |
| 4429 | 4429 | } |
| 4430 | 4430 | |
| 4431 | // explicit cast from integer to enum type with no payload | |
| 4432 | if (actual_type->id == TypeTableEntryIdInt && | |
| 4433 | wanted_type->id == TypeTableEntryIdEnum && | |
| 4434 | wanted_type->data.enumeration.gen_field_count == 0) | |
| 4435 | { | |
| 4436 | return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToEnum, false); | |
| 4437 | } | |
| 4438 | ||
| 4431 | 4439 | add_node_error(g, node, |
| 4432 | 4440 | buf_sprintf("invalid cast from type '%s' to '%s'", |
| 4433 | 4441 | buf_ptr(&actual_type->name), |
src/codegen.cpp+3-1| ... | ... | @@ -1032,6 +1032,8 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 1032 | 1032 | set_debug_source_node(g, node); |
| 1033 | 1033 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); |
| 1034 | 1034 | |
| 1035 | case CastOpIntToEnum: | |
| 1036 | return gen_widen_or_shorten(g, node, actual_type, wanted_type->data.enumeration.tag_type, expr_val); | |
| 1035 | 1037 | } |
| 1036 | 1038 | zig_unreachable(); |
| 1037 | 1039 | } |
| ... | ... | @@ -3913,7 +3915,7 @@ static void do_code_gen(CodeGen *g) { |
| 3913 | 3915 | LLVMZigAddNonNullAttr(fn_table_entry->fn_value, 1); |
| 3914 | 3916 | is_sret = true; |
| 3915 | 3917 | } |
| 3916 | if (fn_table_entry->is_pure && !is_sret) { | |
| 3918 | if (fn_table_entry->is_pure && !is_sret && g->is_release_build) { | |
| 3917 | 3919 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMReadOnlyAttribute); |
| 3918 | 3920 | } |
| 3919 | 3921 |
src/eval.cpp+10| ... | ... | @@ -657,6 +657,16 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 657 | 657 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); |
| 658 | 658 | const_val->ok = true; |
| 659 | 659 | break; |
| 660 | case CastOpIntToEnum: | |
| 661 | { | |
| 662 | uint64_t value = other_val->data.x_bignum.data.x_uint; | |
| 663 | assert(new_type->id == TypeTableEntryIdEnum); | |
| 664 | assert(value < new_type->data.enumeration.field_count); | |
| 665 | const_val->data.x_enum.tag = value; | |
| 666 | const_val->data.x_enum.payload = NULL; | |
| 667 | const_val->ok = true; | |
| 668 | break; | |
| 669 | } | |
| 660 | 670 | } |
| 661 | 671 | } |
| 662 | 672 |
test/self_hosted.zig+20| ... | ... | @@ -1740,3 +1740,23 @@ fn int_type_builtin() { |
| 1740 | 1740 | assert(!usize.is_signed); |
| 1741 | 1741 | |
| 1742 | 1742 | } |
| 1743 | ||
| 1744 | #attribute("test") | |
| 1745 | fn int_to_enum() { | |
| 1746 | test_int_to_enum_eval(3); | |
| 1747 | test_int_to_enum_noeval(3); | |
| 1748 | } | |
| 1749 | fn test_int_to_enum_eval(x: i32) { | |
| 1750 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | |
| 1751 | } | |
| 1752 | #static_eval_enable(false) | |
| 1753 | fn test_int_to_enum_noeval(x: i32) { | |
| 1754 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | |
| 1755 | } | |
| 1756 | enum IntToEnumNumber { | |
| 1757 | Zero, | |
| 1758 | One, | |
| 1759 | Two, | |
| 1760 | Three, | |
| 1761 | Four, | |
| 1762 | } |