authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-18 09:58:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-18 10:18:09-07:00
log7c7d9e13d77de7b9321623c73b6566a3bcbe367c
treea909b0c8d1cdc166f48d95db40e2fd20cd76da3c
parentd0a5ad0e4c74d36982dbc823dd80dc62395fe2bd

Sema: fix runtime int to enum with one possible value


2 files changed, 23 insertions(+), 1 deletions(-)

src/Sema.zig+15-1
...@@ -7372,9 +7372,23 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -7372,9 +7372,23 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
7372 return sema.addConstant(dest_ty, int_val);7372 return sema.addConstant(dest_ty, int_val);
7373 }7373 }
73747374
7375 if (try sema.typeHasOnePossibleValue(block, operand_src, dest_ty)) |opv| {
7376 const result = try sema.addConstant(dest_ty, opv);
7377 // The operand is runtime-known but the result is comptime-known. In
7378 // this case we still need a safety check.
7379 // TODO add a safety check here. we can't use is_named_enum_value -
7380 // it needs to convert the enum back to int and make sure it equals the operand int.
7381 return result;
7382 }
7383
7375 try sema.requireRuntimeBlock(block, src, operand_src);7384 try sema.requireRuntimeBlock(block, src, operand_src);
7376 const result = try block.addTyOp(.intcast, dest_ty, operand);7385 const result = try block.addTyOp(.intcast, dest_ty, operand);
7377 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and sema.mod.comp.bin_file.options.use_llvm) {7386 if (block.wantSafety() and
7387 !dest_ty.isNonexhaustiveEnum() and
7388 // TODO instead of "use_llvm", check a different condition so that backends
7389 // can advertise themselves as supporting these extra AIR instructions for safety.
7390 sema.mod.comp.bin_file.options.use_llvm)
7391 {
7378 const ok = try block.addUnOp(.is_named_enum_value, result);7392 const ok = try block.addUnOp(.is_named_enum_value, result);
7379 try sema.addSafetyCheck(block, ok, .invalid_enum_value);7393 try sema.addSafetyCheck(block, ok, .invalid_enum_value);
7380 }7394 }
test/behavior/enum.zig+8
...@@ -1169,3 +1169,11 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" {...@@ -1169,3 +1169,11 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" {
1169 const E = enum(u15) { _ };1169 const E = enum(u15) { _ };
1170 try expect(@sizeOf(E) == @sizeOf(u15));1170 try expect(@sizeOf(E) == @sizeOf(u15));
1171}1171}
1172
1173test "runtime int to enum with one possible value" {
1174 const E = enum { one };
1175 var runtime: usize = 0;
1176 if (@intToEnum(E, runtime) != .one) {
1177 @compileError("test failed");
1178 }
1179}