| author | |
| committer | |
| log | 66a83d87383cd8de62898171b6665cb1d70af231 |
| tree | ff09db18060a350166cd07a9fb039b43d1a63e37 |
| parent | c8a7ab7eff0f261c47926cf0637e919d42e41940 |
6 files changed, 93 insertions(+), 33 deletions(-)
src/all_types.hpp+7-1| ... | ... | @@ -437,7 +437,6 @@ enum CastOp { |
| 437 | 437 | CastOpFloatToInt, |
| 438 | 438 | CastOpBoolToInt, |
| 439 | 439 | CastOpResizeSlice, |
| 440 | CastOpIntToEnum, | |
| 441 | 440 | CastOpBytesToSlice, |
| 442 | 441 | }; |
| 443 | 442 | |
| ... | ... | @@ -1458,6 +1457,7 @@ enum IrInstructionId { |
| 1458 | 1457 | IrInstructionIdWidenOrShorten, |
| 1459 | 1458 | IrInstructionIdIntToPtr, |
| 1460 | 1459 | IrInstructionIdPtrToInt, |
| 1460 | IrInstructionIdIntToEnum, | |
| 1461 | 1461 | }; |
| 1462 | 1462 | |
| 1463 | 1463 | struct IrInstruction { |
| ... | ... | @@ -2118,6 +2118,12 @@ struct IrInstructionIntToPtr { |
| 2118 | 2118 | IrInstruction *target; |
| 2119 | 2119 | }; |
| 2120 | 2120 | |
| 2121 | struct IrInstructionIntToEnum { | |
| 2122 | IrInstruction base; | |
| 2123 | ||
| 2124 | IrInstruction *target; | |
| 2125 | }; | |
| 2126 | ||
| 2121 | 2127 | enum LValPurpose { |
| 2122 | 2128 | LValPurposeNone, |
| 2123 | 2129 | LValPurposeAssign, |
src/codegen.cpp+20-4| ... | ... | @@ -1075,10 +1075,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 1075 | 1075 | assert(wanted_type->id == TypeTableEntryIdInt); |
| 1076 | 1076 | assert(actual_type->id == TypeTableEntryIdBool); |
| 1077 | 1077 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); |
| 1078 | ||
| 1079 | case CastOpIntToEnum: | |
| 1080 | return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base), | |
| 1081 | actual_type, wanted_type->data.enumeration.tag_type, expr_val); | |
| 1082 | 1078 | } |
| 1083 | 1079 | zig_unreachable(); |
| 1084 | 1080 | } |
| ... | ... | @@ -1122,6 +1118,24 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I |
| 1122 | 1118 | return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, ""); |
| 1123 | 1119 | } |
| 1124 | 1120 | |
| 1121 | static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) { | |
| 1122 | TypeTableEntry *wanted_type = instruction->base.value.type; | |
| 1123 | assert(wanted_type->id == TypeTableEntryIdEnum); | |
| 1124 | TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type; | |
| 1125 | TypeTableEntry *wanted_int_type; | |
| 1126 | if (tag_type->id == TypeTableEntryIdEnumTag) { | |
| 1127 | wanted_int_type = tag_type->data.enum_tag.int_type; | |
| 1128 | } else if (tag_type->id == TypeTableEntryIdInt) { | |
| 1129 | wanted_int_type = tag_type; | |
| 1130 | } else { | |
| 1131 | zig_unreachable(); | |
| 1132 | } | |
| 1133 | ||
| 1134 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); | |
| 1135 | return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), | |
| 1136 | instruction->target->value.type, wanted_int_type, target_val); | |
| 1137 | } | |
| 1138 | ||
| 1125 | 1139 | static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable, |
| 1126 | 1140 | IrInstructionUnreachable *unreachable_instruction) |
| 1127 | 1141 | { |
| ... | ... | @@ -2359,6 +2373,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2359 | 2373 | return ir_render_ptr_to_int(g, executable, (IrInstructionPtrToInt *)instruction); |
| 2360 | 2374 | case IrInstructionIdIntToPtr: |
| 2361 | 2375 | return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction); |
| 2376 | case IrInstructionIdIntToEnum: | |
| 2377 | return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction); | |
| 2362 | 2378 | case IrInstructionIdContainerInitList: |
| 2363 | 2379 | return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); |
| 2364 | 2380 | case IrInstructionIdSwitchVar: |
src/ir.cpp+40-11| ... | ... | @@ -468,6 +468,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToPtr *) { |
| 468 | 468 | return IrInstructionIdIntToPtr; |
| 469 | 469 | } |
| 470 | 470 | |
| 471 | static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) { | |
| 472 | return IrInstructionIdIntToEnum; | |
| 473 | } | |
| 474 | ||
| 471 | 475 | template<typename T> |
| 472 | 476 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 473 | 477 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1932,6 +1936,18 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode |
| 1932 | 1936 | return &instruction->base; |
| 1933 | 1937 | } |
| 1934 | 1938 | |
| 1939 | static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1940 | IrInstruction *target) | |
| 1941 | { | |
| 1942 | IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>( | |
| 1943 | irb, scope, source_node); | |
| 1944 | instruction->target = target; | |
| 1945 | ||
| 1946 | ir_ref_instruction(target); | |
| 1947 | ||
| 1948 | return &instruction->base; | |
| 1949 | } | |
| 1950 | ||
| 1935 | 1951 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 1936 | 1952 | results[ReturnKindUnconditional] = 0; |
| 1937 | 1953 | results[ReturnKindError] = 0; |
| ... | ... | @@ -4720,16 +4736,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, |
| 4720 | 4736 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); |
| 4721 | 4737 | const_val->special = ConstValSpecialStatic; |
| 4722 | 4738 | break; |
| 4723 | case CastOpIntToEnum: | |
| 4724 | { | |
| 4725 | uint64_t value = other_val->data.x_bignum.data.x_uint; | |
| 4726 | assert(new_type->id == TypeTableEntryIdEnum); | |
| 4727 | assert(value < new_type->data.enumeration.src_field_count); | |
| 4728 | const_val->data.x_enum.tag = value; | |
| 4729 | const_val->data.x_enum.payload = NULL; | |
| 4730 | const_val->special = ConstValSpecialStatic; | |
| 4731 | break; | |
| 4732 | } | |
| 4733 | 4739 | } |
| 4734 | 4740 | } |
| 4735 | 4741 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| ... | ... | @@ -5311,6 +5317,27 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc |
| 5311 | 5317 | return result; |
| 5312 | 5318 | } |
| 5313 | 5319 | |
| 5320 | static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr, | |
| 5321 | IrInstruction *target, TypeTableEntry *wanted_type) | |
| 5322 | { | |
| 5323 | assert(wanted_type->id == TypeTableEntryIdEnum); | |
| 5324 | ||
| 5325 | if (instr_is_comptime(target)) { | |
| 5326 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | |
| 5327 | if (!val) | |
| 5328 | return ira->codegen->invalid_instruction; | |
| 5329 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 5330 | source_instr->source_node, wanted_type, val->depends_on_compile_var); | |
| 5331 | result->value.data.x_enum.tag = val->data.x_bignum.data.x_uint; | |
| 5332 | return result; | |
| 5333 | } | |
| 5334 | ||
| 5335 | IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope, | |
| 5336 | source_instr->source_node, target); | |
| 5337 | result->value.type = wanted_type; | |
| 5338 | return result; | |
| 5339 | } | |
| 5340 | ||
| 5314 | 5341 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 5315 | 5342 | TypeTableEntry *wanted_type, IrInstruction *value) |
| 5316 | 5343 | { |
| ... | ... | @@ -5533,7 +5560,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 5533 | 5560 | wanted_type->id == TypeTableEntryIdEnum && |
| 5534 | 5561 | wanted_type->data.enumeration.gen_field_count == 0) |
| 5535 | 5562 | { |
| 5536 | return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToEnum, false); | |
| 5563 | return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type); | |
| 5537 | 5564 | } |
| 5538 | 5565 | |
| 5539 | 5566 | // explicit cast from enum type with no payload to integer |
| ... | ... | @@ -10016,6 +10043,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 10016 | 10043 | case IrInstructionIdWidenOrShorten: |
| 10017 | 10044 | case IrInstructionIdIntToPtr: |
| 10018 | 10045 | case IrInstructionIdPtrToInt: |
| 10046 | case IrInstructionIdIntToEnum: | |
| 10019 | 10047 | case IrInstructionIdStructInit: |
| 10020 | 10048 | case IrInstructionIdStructFieldPtr: |
| 10021 | 10049 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -10325,6 +10353,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 10325 | 10353 | case IrInstructionIdWidenOrShorten: |
| 10326 | 10354 | case IrInstructionIdPtrToInt: |
| 10327 | 10355 | case IrInstructionIdIntToPtr: |
| 10356 | case IrInstructionIdIntToEnum: | |
| 10328 | 10357 | return false; |
| 10329 | 10358 | case IrInstructionIdAsm: |
| 10330 | 10359 | { |
src/ir_print.cpp+9| ... | ... | @@ -952,6 +952,12 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction |
| 952 | 952 | fprintf(irp->f, ")"); |
| 953 | 953 | } |
| 954 | 954 | |
| 955 | static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) { | |
| 956 | fprintf(irp->f, "@intToEnum("); | |
| 957 | ir_print_other_instruction(irp, instruction->target); | |
| 958 | fprintf(irp->f, ")"); | |
| 959 | } | |
| 960 | ||
| 955 | 961 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 956 | 962 | ir_print_prefix(irp, instruction); |
| 957 | 963 | switch (instruction->id) { |
| ... | ... | @@ -1203,6 +1209,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1203 | 1209 | case IrInstructionIdIntToPtr: |
| 1204 | 1210 | ir_print_int_to_ptr(irp, (IrInstructionIntToPtr *)instruction); |
| 1205 | 1211 | break; |
| 1212 | case IrInstructionIdIntToEnum: | |
| 1213 | ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction); | |
| 1214 | break; | |
| 1206 | 1215 | } |
| 1207 | 1216 | fprintf(irp->f, "\n"); |
| 1208 | 1217 | } |
test/cases/enum.zig+17| ... | ... | @@ -96,6 +96,23 @@ fn shouldEqual(n: Number, expected: usize) { |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | |
| 99 | fn intToEnum() { | |
| 100 | @setFnTest(this); | |
| 101 | ||
| 102 | testIntToEnumEval(3); | |
| 103 | } | |
| 104 | fn testIntToEnumEval(x: i32) { | |
| 105 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | |
| 106 | } | |
| 107 | const IntToEnumNumber = enum { | |
| 108 | Zero, | |
| 109 | One, | |
| 110 | Two, | |
| 111 | Three, | |
| 112 | Four, | |
| 113 | }; | |
| 114 | ||
| 115 | ||
| 99 | 116 | // TODO import from std |
| 100 | 117 | fn assert(ok: bool) { |
| 101 | 118 | if (!ok) |
test/self_hosted.zig-17| ... | ... | @@ -80,20 +80,3 @@ fn castSliceToU8Slice() { |
| 80 | 80 | assert(bytes[10] == @maxValue(u8)); |
| 81 | 81 | assert(bytes[11] == @maxValue(u8)); |
| 82 | 82 | } |
| 83 | ||
| 84 | // TODO not passing | |
| 85 | fn intToEnum() { | |
| 86 | @setFnTest(this); | |
| 87 | ||
| 88 | testIntToEnumEval(3); | |
| 89 | } | |
| 90 | fn testIntToEnumEval(x: i32) { | |
| 91 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | |
| 92 | } | |
| 93 | const IntToEnumNumber = enum { | |
| 94 | Zero, | |
| 95 | One, | |
| 96 | Two, | |
| 97 | Three, | |
| 98 | Four, | |
| 99 | }; |