aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/all_types.hpp16
-rw-r--r--src/codegen.cpp74
-rw-r--r--src/ir.cpp176
-rw-r--r--src/ir_print.cpp16
4 files changed, 245 insertions, 37 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp
index e682255602..5d8a823e75 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -520,7 +520,6 @@ struct AstNodeUnwrapErrorExpr {
enum CastOp {
CastOpNoCast, // signifies the function call expression is not a cast
CastOpNoop, // fn call expr is a cast, but does nothing
- CastOpErrToInt,
CastOpIntToFloat,
CastOpFloatToInt,
CastOpBoolToInt,
@@ -1223,6 +1222,7 @@ enum PanicMsgId {
PanicMsgIdSliceWidenRemainder,
PanicMsgIdUnwrapMaybeFail,
PanicMsgIdUnwrapErrFail,
+ PanicMsgIdInvalidErrorCode,
PanicMsgIdCount,
};
@@ -1728,6 +1728,8 @@ enum IrInstructionId {
IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt,
IrInstructionIdIntToEnum,
+ IrInstructionIdIntToErr,
+ IrInstructionIdErrToInt,
IrInstructionIdCheckSwitchProngs,
IrInstructionIdTestType,
IrInstructionIdTypeName,
@@ -2404,6 +2406,18 @@ struct IrInstructionIntToEnum {
IrInstruction *target;
};
+struct IrInstructionIntToErr {
+ IrInstruction base;
+
+ IrInstruction *target;
+};
+
+struct IrInstructionErrToInt {
+ IrInstruction base;
+
+ IrInstruction *target;
+};
+
struct IrInstructionCheckSwitchProngsRange {
IrInstruction *start;
IrInstruction *end;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index cbc0d4c0b0..ed4b0e0df2 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -570,6 +570,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("attempt to unwrap error");
case PanicMsgIdUnreachable:
return buf_create_from_str("reached unreachable code");
+ case PanicMsgIdInvalidErrorCode:
+ return buf_create_from_str("invalid error code");
}
zig_unreachable();
}
@@ -1227,14 +1229,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
zig_unreachable();
case CastOpNoop:
return expr_val;
- case CastOpErrToInt:
- assert(actual_type->id == TypeTableEntryIdErrorUnion);
- if (!type_has_bits(actual_type->data.error.child_type)) {
- return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
- g->err_tag_type, wanted_type, expr_val);
- } else {
- zig_panic("TODO");
- }
case CastOpResizeSlice:
{
assert(cast_instruction->tmp_ptr);
@@ -1402,6 +1396,66 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
instruction->target->value.type, wanted_int_type, target_val);
}
+static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
+ TypeTableEntry *wanted_type = instruction->base.value.type;
+ assert(wanted_type->id == TypeTableEntryIdPureError);
+
+ TypeTableEntry *actual_type = instruction->target->value.type;
+ assert(actual_type->id == TypeTableEntryIdInt);
+ assert(!actual_type->data.integral.is_signed);
+
+ LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
+
+ if (ir_want_debug_safety(g, &instruction->base)) {
+ LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
+ LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
+ LLVMValueRef ok_bit;
+ uint64_t biggest_possible_err_val = max_unsigned_val(actual_type);
+ if (biggest_possible_err_val < g->error_decls.length) {
+ ok_bit = neq_zero_bit;
+ } else {
+ LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false);
+ LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, "");
+ ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, "");
+ }
+
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail");
+
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_debug_safety_crash(g, PanicMsgIdInvalidErrorCode);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+
+ return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val);
+}
+
+static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, IrInstructionErrToInt *instruction) {
+ TypeTableEntry *wanted_type = instruction->base.value.type;
+ assert(wanted_type->id == TypeTableEntryIdInt);
+ assert(!wanted_type->data.integral.is_signed);
+
+ TypeTableEntry *actual_type = instruction->target->value.type;
+ LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
+
+ if (actual_type->id == TypeTableEntryIdPureError) {
+ return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
+ g->err_tag_type, wanted_type, target_val);
+ } else if (actual_type->id == TypeTableEntryIdErrorUnion) {
+ if (!type_has_bits(actual_type->data.error.child_type)) {
+ return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
+ g->err_tag_type, wanted_type, target_val);
+ } else {
+ zig_panic("TODO");
+ }
+ } else {
+ zig_unreachable();
+ }
+}
+
static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
IrInstructionUnreachable *unreachable_instruction)
{
@@ -2786,6 +2840,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction);
case IrInstructionIdIntToEnum:
return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction);
+ case IrInstructionIdIntToErr:
+ return ir_render_int_to_err(g, executable, (IrInstructionIntToErr *)instruction);
+ case IrInstructionIdErrToInt:
+ return ir_render_err_to_int(g, executable, (IrInstructionErrToInt *)instruction);
case IrInstructionIdContainerInitList:
return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdPanic:
diff --git a/src/ir.cpp b/src/ir.cpp
index 1fdb8f2e3b..a33fb3cd22 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -500,6 +500,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {
return IrInstructionIdIntToEnum;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) {
+ return IrInstructionIdIntToErr;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrToInt *) {
+ return IrInstructionIdErrToInt;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProngs *) {
return IrInstructionIdCheckSwitchProngs;
}
@@ -2002,6 +2010,30 @@ static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
+static IrInstruction *ir_build_int_to_err(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *target)
+{
+ IrInstructionIntToErr *instruction = ir_build_instruction<IrInstructionIntToErr>(
+ irb, scope, source_node);
+ instruction->target = target;
+
+ ir_ref_instruction(target, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *target)
+{
+ IrInstructionErrToInt *instruction = ir_build_instruction<IrInstructionErrToInt>(
+ irb, scope, source_node);
+ instruction->target = target;
+
+ ir_ref_instruction(target, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count)
{
@@ -2704,6 +2736,20 @@ static IrInstruction *ir_instruction_inttoenum_get_dep(IrInstructionIntToEnum *i
}
}
+static IrInstruction *ir_instruction_inttoerr_get_dep(IrInstructionIntToErr *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->target;
+ default: return nullptr;
+ }
+}
+
+static IrInstruction *ir_instruction_errtoint_get_dep(IrInstructionErrToInt *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->target;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionCheckSwitchProngs *instruction,
size_t index)
{
@@ -2938,6 +2984,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_ptrtoint_get_dep((IrInstructionPtrToInt *) instruction, index);
case IrInstructionIdIntToEnum:
return ir_instruction_inttoenum_get_dep((IrInstructionIntToEnum *) instruction, index);
+ case IrInstructionIdIntToErr:
+ return ir_instruction_inttoerr_get_dep((IrInstructionIntToErr *) instruction, index);
+ case IrInstructionIdErrToInt:
+ return ir_instruction_errtoint_get_dep((IrInstructionErrToInt *) instruction, index);
case IrInstructionIdCheckSwitchProngs:
return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);
case IrInstructionIdTestType:
@@ -6001,20 +6051,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
case CastOpBytesToSlice:
// can't do it
break;
- case CastOpErrToInt:
- {
- uint64_t value;
- if (other_type->id == TypeTableEntryIdErrorUnion) {
- value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0;
- } else if (other_type->id == TypeTableEntryIdPureError) {
- value = other_val->data.x_pure_err->value;
- } else {
- zig_unreachable();
- }
- bignum_init_unsigned(&const_val->data.x_bignum, value);
- const_val->special = ConstValSpecialStatic;
- break;
- }
case CastOpIntToFloat:
bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
const_val->special = ConstValSpecialStatic;
@@ -6707,6 +6743,87 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
return result;
}
+static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
+ assert(target->value.type->id == TypeTableEntryIdInt);
+ assert(!target->value.type->data.integral.is_signed);
+
+ if (instr_is_comptime(target)) {
+ ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, ira->codegen->builtin_types.entry_pure_error);
+
+ uint64_t index = val->data.x_bignum.data.x_uint;
+ if (index == 0 || index >= ira->codegen->error_decls.length) {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("integer value %" PRIu64 " represents no error", index));
+ return ira->codegen->invalid_instruction;
+ }
+
+ AstNode *error_decl_node = ira->codegen->error_decls.at(index);
+ result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err;
+ return result;
+ }
+
+ IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target);
+ result->value.type = ira->codegen->builtin_types.entry_pure_error;
+ return result;
+}
+
+static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
+ TypeTableEntry *wanted_type)
+{
+ assert(wanted_type->id == TypeTableEntryIdInt);
+
+ TypeTableEntry *err_type = target->value.type;
+
+ if (instr_is_comptime(target)) {
+ ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, wanted_type);
+
+ ErrorTableEntry *err;
+ if (err_type->id == TypeTableEntryIdErrorUnion) {
+ err = val->data.x_err_union.err;
+ } else if (err_type->id == TypeTableEntryIdPureError) {
+ err = val->data.x_pure_err;
+ } else {
+ zig_unreachable();
+ }
+ result->value.type = wanted_type;
+ uint64_t err_value = err ? err->value : 0;
+ bignum_init_unsigned(&result->value.data.x_bignum, err_value);
+
+ if (!bignum_fits_in_bits(&result->value.data.x_bignum,
+ wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed))
+ {
+ ir_add_error_node(ira, source_instr->source_node,
+ buf_sprintf("error code '%s' does not fit in '%s'",
+ buf_ptr(&err->name), buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ return result;
+ }
+
+ BigNum bn;
+ bignum_init_unsigned(&bn, ira->codegen->error_decls.length);
+ if (!bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) {
+ ir_add_error_node(ira, source_instr->source_node,
+ buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *result = ir_build_err_to_int(&ira->new_irb, source_instr->scope, source_instr->source_node, target);
+ result->value.type = wanted_type;
+ return result;
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
TypeTableEntry *wanted_type, IrInstruction *value)
{
@@ -6781,7 +6898,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpFloatToInt, false);
}
- // explicit cast from array to slice
+ // explicit cast from [N]T to []const T
if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
@@ -6909,17 +7026,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if ((actual_type_is_void_err || actual_type_is_pure_err) &&
wanted_type->id == TypeTableEntryIdInt)
{
- BigNum bn;
- bignum_init_unsigned(&bn, ira->codegen->error_decls.length);
- if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
- wanted_type->data.integral.is_signed))
- {
- return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpErrToInt, false);
- } else {
- ir_add_error_node(ira, source_instr->source_node,
- buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
- return ira->codegen->invalid_instruction;
- }
+ return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
+ }
+
+ // explicit cast from integer to pure error
+ if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt &&
+ !actual_type->data.integral.is_signed)
+ {
+ return ir_analyze_int_to_err(ira, source_instr, value);
}
// explicit cast from integer to enum type with no payload
@@ -7843,7 +7957,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
result_type = ira->codegen->builtin_types.entry_invalid;
}
- bool is_comptime_var = ir_get_var_is_comptime(var);
+ bool is_comptime_var = ir_get_var_is_comptime(var);
switch (result_type->id) {
case TypeTableEntryIdTypeDecl:
@@ -7852,6 +7966,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
break; // handled above
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdUndefLit:
if (is_export || is_extern || (!var->src_is_const && !is_comptime_var)) {
ir_add_error_node(ira, source_node, buf_sprintf("unable to infer variable type"));
result_type = ira->codegen->builtin_types.entry_invalid;
@@ -7873,7 +7988,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
result_type = ira->codegen->builtin_types.entry_invalid;
}
break;
- case TypeTableEntryIdUndefLit:
case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
@@ -10765,6 +10879,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
TypeTableEntry *this_field_type = field->type_entry;
IrInstruction *init_value = instruction->items[0]->other;
+ if (type_is_invalid(init_value->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type);
if (casted_init_value == ira->codegen->invalid_instruction)
@@ -12311,6 +12427,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
case IrInstructionIdIntToPtr:
case IrInstructionIdPtrToInt:
case IrInstructionIdIntToEnum:
+ case IrInstructionIdIntToErr:
+ case IrInstructionIdErrToInt:
case IrInstructionIdStructInit:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
@@ -12650,6 +12768,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdPtrToInt:
case IrInstructionIdIntToPtr:
case IrInstructionIdIntToEnum:
+ case IrInstructionIdIntToErr:
+ case IrInstructionIdErrToInt:
case IrInstructionIdTestType:
case IrInstructionIdTypeName:
case IrInstructionIdCanImplicitCast:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 7814064f85..fd912d6919 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -799,6 +799,16 @@ static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instructi
fprintf(irp->f, ")");
}
+static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
+ fprintf(irp->f, "inttoerr ");
+ ir_print_other_instruction(irp, instruction->target);
+}
+
+static void ir_print_err_to_int(IrPrint *irp, IrInstructionErrToInt *instruction) {
+ fprintf(irp->f, "errtoint ");
+ ir_print_other_instruction(irp, instruction->target);
+}
+
static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchProngs *instruction) {
fprintf(irp->f, "@checkSwitchProngs(");
ir_print_other_instruction(irp, instruction->target_value);
@@ -1117,6 +1127,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdIntToEnum:
ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction);
break;
+ case IrInstructionIdIntToErr:
+ ir_print_int_to_err(irp, (IrInstructionIntToErr *)instruction);
+ break;
+ case IrInstructionIdErrToInt:
+ ir_print_err_to_int(irp, (IrInstructionErrToInt *)instruction);
+ break;
case IrInstructionIdCheckSwitchProngs:
ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);
break;