add runtime safety for @intToEnum; add docs for runtime safety

See #367
This commit is contained in:
Andrew Kelley
2018-07-02 15:49:49 -04:00
parent 2759c7951d
commit 35463526cc
3 changed files with 233 additions and 29 deletions

View File

@@ -2673,8 +2673,25 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
instruction->target->value.type, tag_int_type, target_val);
if (ir_want_runtime_safety(g, &instruction->base)) {
LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
size_t field_count = wanted_type->data.enumeration.src_field_count;
LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
&wanted_type->data.enumeration.fields[field_i].value);
LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
}
LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
gen_safety_crash(g, PanicMsgIdBadEnumValue);
LLVMPositionBuilderAtEnd(g->builder, ok_value_block);
}
return tag_int_value;
}
static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {