diff --git a/src/all_types.hpp b/src/all_types.hpp index 8cda62d287..0672f0c603 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -404,6 +404,7 @@ enum CastOp { CastOpBoolToInt, CastOpResizeSlice, CastOpIntToEnum, + CastOpEnumToInt, CastOpBytesToSlice, }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 597c07f8e2..5ffce5bdb8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2641,7 +2641,12 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry codegen->type_entry = fixed_size_array_type; codegen->source_node = node; if (!const_val->ok) { - context->fn_entry->struct_val_expr_alloca_list.append(codegen); + if (!context->fn_entry) { + add_node_error(g, node, + buf_sprintf("unable to evaluate constant expression")); + } else { + context->fn_entry->struct_val_expr_alloca_list.append(codegen); + } } return fixed_size_array_type; @@ -4601,6 +4606,14 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToEnum, false); } + // explicit cast from enum type with no payload to integer + if (wanted_type->id == TypeTableEntryIdInt && + actual_type->id == TypeTableEntryIdEnum && + actual_type->data.enumeration.gen_field_count == 0) + { + return resolve_cast(g, context, node, expr_node, wanted_type, CastOpEnumToInt, false); + } + add_node_error(g, node, buf_sprintf("invalid cast from type '%s' to '%s'", buf_ptr(&actual_type->name), diff --git a/src/codegen.cpp b/src/codegen.cpp index 82f7084159..bf13ba3036 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1062,6 +1062,8 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { case CastOpIntToEnum: return gen_widen_or_shorten(g, node, actual_type, wanted_type->data.enumeration.tag_type, expr_val); + case CastOpEnumToInt: + return gen_widen_or_shorten(g, node, actual_type->data.enumeration.tag_type, wanted_type, expr_val); } zig_unreachable(); } diff --git a/src/eval.cpp b/src/eval.cpp index 31683a4873..b3b8b81b35 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -694,6 +694,9 @@ void eval_const_expr_implicit_cast(CastOp cast_op, const_val->ok = true; break; } + case CastOpEnumToInt: + bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag); + const_val->ok = true; } } diff --git a/test/cases/enum_to_int.zig b/test/cases/enum_to_int.zig new file mode 100644 index 0000000000..54994754dd --- /dev/null +++ b/test/cases/enum_to_int.zig @@ -0,0 +1,24 @@ +const assert = @import("std").debug.assert; + +enum Number { + Zero, + One, + Two, + Three, + Four, +} + +#attribute("test") +fn enumToInt() { + shouldEqual(Number.Zero, 0); + shouldEqual(Number.One, 1); + shouldEqual(Number.Two, 2); + shouldEqual(Number.Three, 3); + shouldEqual(Number.Four, 4); +} + +// TODO add test with this disabled +#static_eval_enable(false) +fn shouldEqual(n: Number, expected: usize) { + assert(usize(n) == expected); +}