aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp281
1 files changed, 181 insertions, 100 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index b1412b2b59..4f100d75ad 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
buf_resize(&g->global_asm, 0);
- // reserve index 0 to indicate no error
- g->error_decls.append(nullptr);
-
if (root_src_path) {
Buf *src_basename = buf_alloc();
Buf *src_dir = buf_alloc();
@@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {
return add_link_lib(g, name);
}
+void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib) {
+ codegen->forbidden_libs.append(lib);
+}
+
void codegen_add_framework(CodeGen *g, const char *framework) {
g->darwin_frameworks.append(buf_create_from_str(framework));
}
@@ -282,9 +283,9 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) {
}
-static void render_const_val(CodeGen *g, ConstExprValue *const_val);
+static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char *name);
static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name);
-static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val);
+static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name);
static void generate_error_name_table(CodeGen *g);
static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {
@@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
}
TypeTableEntry *fn_type = fn_table_entry->type_entry;
TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
- if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) {
+ if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) {
return UINT32_MAX;
}
bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
@@ -873,7 +874,7 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
ConstExprValue *array_val = create_const_str_lit(g, buf_msg);
init_const_slice(g, val, array_val, 0, buf_len(buf_msg), true);
- render_const_val(g, val);
+ render_const_val(g, val, "");
render_const_val_global(g, val, "");
assert(val->global_refs->llvm_global);
@@ -1412,7 +1413,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
if (!instruction->llvm_value) {
assert(instruction->value.special != ConstValSpecialRuntime);
assert(instruction->value.type);
- render_const_val(g, &instruction->value);
+ render_const_val(g, &instruction->value, "");
// we might have to do some pointer casting here due to the way union
// values are rendered with a type other than the one we expect
if (handle_is_ptr(instruction->value.type)) {
@@ -1442,7 +1443,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
// TODO: emit a branch to check if the return value is an error
}
- } else if (return_type->id == TypeTableEntryIdPureError) {
+ } else if (return_type->id == TypeTableEntryIdErrorSet) {
is_err_return = true;
}
if (is_err_return) {
@@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
- op_id == IrBinOpBitShiftRightExact);
+ op_id == IrBinOpBitShiftRightExact ||
+ (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet));
TypeTableEntry *type_entry = op1->value.type;
bool want_runtime_safety = bin_op_instruction->safety_check_on &&
@@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
case IrBinOpArrayCat:
case IrBinOpArrayMult:
case IrBinOpRemUnspecified:
+ case IrBinOpMergeErrorSets:
zig_unreachable();
case IrBinOpBoolOr:
return LLVMBuildOr(g->builder, op1_value, op2_value, "");
@@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
} else if (type_entry->id == TypeTableEntryIdEnum) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
- } else if (type_entry->id == TypeTableEntryIdPureError ||
+ } else if (type_entry->id == TypeTableEntryIdErrorSet ||
type_entry->id == TypeTableEntryIdPointer ||
type_entry->id == TypeTableEntryIdBool)
{
@@ -1955,6 +1958,54 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
+static void add_error_range_check(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *int_type, LLVMValueRef target_val) {
+ assert(err_set_type->id == TypeTableEntryIdErrorSet);
+
+ if (type_is_global_error_set(err_set_type)) {
+ LLVMValueRef zero = LLVMConstNull(int_type->type_ref);
+ LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
+ LLVMValueRef ok_bit;
+
+ BigInt biggest_possible_err_val = {0};
+ eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true);
+
+ if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) &&
+ bigint_as_unsigned(&biggest_possible_err_val) < g->errors_by_index.length)
+ {
+ ok_bit = neq_zero_bit;
+ } else {
+ LLVMValueRef error_value_count = LLVMConstInt(int_type->type_ref, g->errors_by_index.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_safety_crash(g, PanicMsgIdInvalidErrorCode);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ } else {
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail");
+
+ uint32_t err_count = err_set_type->data.error_set.err_count;
+ LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_val, fail_block, err_count);
+ for (uint32_t i = 0; i < err_count; i += 1) {
+ LLVMValueRef case_value = LLVMConstInt(g->err_tag_type->type_ref, err_set_type->data.error_set.errors[i]->value, false);
+ LLVMAddCase(switch_instr, case_value, ok_block);
+ }
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdInvalidErrorCode);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+}
+
static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
IrInstructionCast *cast_instruction)
{
@@ -2078,6 +2129,11 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
assert(wanted_type->id == TypeTableEntryIdInt);
assert(actual_type->id == TypeTableEntryIdBool);
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+ case CastOpErrSet:
+ if (ir_want_runtime_safety(g, &cast_instruction->base)) {
+ add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
+ }
+ return expr_val;
}
zig_unreachable();
}
@@ -2139,7 +2195,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
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);
+ assert(wanted_type->id == TypeTableEntryIdErrorSet);
TypeTableEntry *actual_type = instruction->target->value.type;
assert(actual_type->id == TypeTableEntryIdInt);
@@ -2148,32 +2204,7 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
if (ir_want_runtime_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;
-
- BigInt biggest_possible_err_val = {0};
- eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true);
-
- if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) &&
- bigint_as_unsigned(&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_safety_crash(g, PanicMsgIdInvalidErrorCode);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ add_error_range_check(g, wanted_type, actual_type, target_val);
}
return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val);
@@ -2187,15 +2218,18 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I
TypeTableEntry *actual_type = instruction->target->value.type;
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
- if (actual_type->id == TypeTableEntryIdPureError) {
+ if (actual_type->id == TypeTableEntryIdErrorSet) {
return gen_widen_or_shorten(g, ir_want_runtime_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)) {
+ // this should have been a compile time constant
+ assert(type_has_bits(actual_type->data.error_union.err_set_type));
+
+ if (!type_has_bits(actual_type->data.error_union.payload_type)) {
return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
g->err_tag_type, wanted_type, target_val);
} else {
- zig_panic("TODO");
+ zig_panic("TODO err to int when error union payload type not void");
}
} else {
zig_unreachable();
@@ -2235,7 +2269,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
switch (op_id) {
case IrUnOpInvalid:
- case IrUnOpError:
case IrUnOpMaybe:
case IrUnOpDereference:
zig_unreachable();
@@ -2489,7 +2522,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
TypeTableEntry *src_return_type = fn_type_id->return_type;
bool ret_has_bits = type_has_bits(src_return_type);
bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
- bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError);
+ bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet);
size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
bool is_var_args = fn_type_id->is_var_args;
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
@@ -2907,7 +2940,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) {
assert(g->generate_error_name_table);
- if (g->error_decls.length == 1) {
+ if (g->errors_by_index.length == 1) {
LLVMBuildUnreachable(g->builder);
return nullptr;
}
@@ -2915,7 +2948,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
if (ir_want_runtime_safety(g, &instruction->base)) {
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val));
- LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false);
+ LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false);
add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
}
@@ -3393,11 +3426,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
TypeTableEntry *err_union_type = instruction->value->value.type;
- TypeTableEntry *child_type = err_union_type->data.error.child_type;
+ TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
LLVMValueRef err_val;
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
} else {
@@ -3412,11 +3445,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
- TypeTableEntry *child_type = err_union_type->data.error.child_type;
+ TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
return gen_load_untyped(g, err_val_ptr, 0, false, "");
} else {
@@ -3428,13 +3461,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
- TypeTableEntry *child_type = err_union_type->data.error.child_type;
+ TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
- if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) {
+ if (!type_has_bits(err_union_type->data.error_union.err_set_type)) {
+ return err_union_handle;
+ }
+
+ if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
LLVMValueRef err_val;
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
} else {
@@ -3452,7 +3489,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
} else {
return nullptr;
@@ -3493,10 +3530,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = wanted_type->data.error.child_type;
+ TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
+ TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
+
LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
- if (!type_has_bits(child_type))
+ if (!type_has_bits(payload_type) || !type_has_bits(err_set_type))
return err_val;
assert(instruction->tmp_ptr);
@@ -3512,11 +3551,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = wanted_type->data.error.child_type;
+ TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
+ TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
+
+ if (!type_has_bits(err_set_type)) {
+ return ir_llvm_value(g, instruction->value);
+ }
LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
- if (!type_has_bits(child_type))
+ if (!type_has_bits(payload_type))
return ok_err_val;
assert(instruction->tmp_ptr);
@@ -3527,7 +3571,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
- gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, child_type, false), payload_val);
+ gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val);
return instruction->tmp_ptr;
}
@@ -3700,6 +3744,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdArgType:
case IrInstructionIdTagType:
case IrInstructionIdExport:
+ case IrInstructionIdErrorUnion:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -3847,7 +3892,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *ar
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
case ConstParentIdNone:
- render_const_val(g, val);
+ render_const_val(g, val, "");
render_const_val_global(g, val, "");
return val->global_refs->llvm_global;
case ConstParentIdStruct:
@@ -3933,7 +3978,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -3946,17 +3991,17 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdEnum:
{
assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr);
- LLVMValueRef int_val = gen_const_val(g, const_val);
+ LLVMValueRef int_val = gen_const_val(g, const_val, "");
return LLVMConstZExt(int_val, big_int_type_ref);
}
case TypeTableEntryIdInt:
{
- LLVMValueRef int_val = gen_const_val(g, const_val);
+ LLVMValueRef int_val = gen_const_val(g, const_val, "");
return LLVMConstZExt(int_val, big_int_type_ref);
}
case TypeTableEntryIdFloat:
{
- LLVMValueRef float_val = gen_const_val(g, const_val);
+ LLVMValueRef float_val = gen_const_val(g, const_val, "");
LLVMValueRef int_val = LLVMConstFPToUI(float_val,
LLVMIntType((unsigned)type_entry->data.floating.bit_count));
return LLVMConstZExt(int_val, big_int_type_ref);
@@ -3965,7 +4010,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdFn:
case TypeTableEntryIdMaybe:
{
- LLVMValueRef ptr_val = gen_const_val(g, const_val);
+ LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);
return LLVMConstZExt(ptr_size_int_val, big_int_type_ref);
}
@@ -4010,7 +4055,7 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef
return LLVMTypeOf(val) != type_entry->type_ref;
}
-static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
+static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
TypeTableEntry *type_entry = const_val->type;
assert(!type_entry->zero_bits);
@@ -4026,10 +4071,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
switch (type_entry->id) {
case TypeTableEntryIdInt:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
- case TypeTableEntryIdPureError:
- assert(const_val->data.x_pure_err);
- return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
- const_val->data.x_pure_err->value, false);
+ case TypeTableEntryIdErrorSet:
+ assert(const_val->data.x_err_set != nullptr);
+ return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
+ const_val->data.x_err_set->value, false);
case TypeTableEntryIdFloat:
switch (type_entry->data.floating.bit_count) {
case 32:
@@ -4063,7 +4108,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
child_type->id == TypeTableEntryIdFn)
{
if (const_val->data.x_maybe) {
- return gen_const_val(g, const_val->data.x_maybe);
+ return gen_const_val(g, const_val->data.x_maybe, "");
} else {
return LLVMConstNull(child_type->type_ref);
}
@@ -4072,7 +4117,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
LLVMValueRef maybe_val;
bool make_unnamed_struct;
if (const_val->data.x_maybe) {
- child_val = gen_const_val(g, const_val->data.x_maybe);
+ child_val = gen_const_val(g, const_val->data.x_maybe, "");
maybe_val = LLVMConstAllOnes(LLVMInt1Type());
make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
@@ -4116,7 +4161,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
if (src_field_index + 1 == src_field_index_end) {
ConstExprValue *field_val = &const_val->data.x_struct.fields[src_field_index];
- LLVMValueRef val = gen_const_val(g, field_val);
+ LLVMValueRef val = gen_const_val(g, field_val, "");
fields[type_struct_field->gen_index] = val;
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
} else {
@@ -4156,7 +4201,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
continue;
}
ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
- LLVMValueRef val = gen_const_val(g, field_val);
+ LLVMValueRef val = gen_const_val(g, field_val, "");
fields[type_struct_field->gen_index] = val;
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
}
@@ -4180,7 +4225,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
bool make_unnamed_struct = false;
for (uint64_t i = 0; i < len; i += 1) {
ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i];
- LLVMValueRef val = gen_const_val(g, elem_value);
+ LLVMValueRef val = gen_const_val(g, elem_value, "");
values[i] = val;
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val);
}
@@ -4215,7 +4260,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
} else {
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
- LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
+ LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, "");
make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
payload_value->type != type_entry->data.unionation.most_aligned_union_member;
@@ -4260,7 +4305,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
return fn_llvm_value(g, const_val->data.x_fn.fn_entry);
case TypeTableEntryIdPointer:
{
- render_const_val_global(g, const_val, "");
+ render_const_val_global(g, const_val, name);
switch (const_val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
case ConstPtrSpecialDiscard:
@@ -4268,7 +4313,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
case ConstPtrSpecialRef:
{
ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
- render_const_val(g, pointee);
+ render_const_val(g, pointee, "");
render_const_val_global(g, pointee, "");
ConstExprValue *other_val = pointee;
const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
@@ -4330,22 +4375,27 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
}
case TypeTableEntryIdErrorUnion:
{
- TypeTableEntry *child_type = type_entry->data.error.child_type;
- if (!type_has_bits(child_type)) {
+ TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
+ TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
+ if (!type_has_bits(payload_type)) {
+ assert(type_has_bits(err_set_type));
uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
+ } else if (!type_has_bits(err_set_type)) {
+ assert(type_has_bits(payload_type));
+ return gen_const_val(g, const_val->data.x_err_union.payload, "");
} else {
LLVMValueRef err_tag_value;
LLVMValueRef err_payload_value;
bool make_unnamed_struct;
if (const_val->data.x_err_union.err) {
err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
- err_payload_value = LLVMConstNull(child_type->type_ref);
+ err_payload_value = LLVMConstNull(payload_type->type_ref);
make_unnamed_struct = false;
} else {
err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
ConstExprValue *payload_val = const_val->data.x_err_union.payload;
- err_payload_value = gen_const_val(g, payload_val);
+ err_payload_value = gen_const_val(g, payload_val, "");
make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value);
}
LLVMValueRef fields[] = {
@@ -4380,11 +4430,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
zig_unreachable();
}
-static void render_const_val(CodeGen *g, ConstExprValue *const_val) {
+static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
if (!const_val->global_refs)
const_val->global_refs = allocate<ConstGlobalRefs>(1);
if (!const_val->global_refs->llvm_value)
- const_val->global_refs->llvm_value = gen_const_val(g, const_val);
+ const_val->global_refs->llvm_value = gen_const_val(g, const_val, name);
if (const_val->global_refs->llvm_global)
LLVMSetInitializer(const_val->global_refs->llvm_global, const_val->global_refs->llvm_value);
@@ -4410,21 +4460,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const
}
static void generate_error_name_table(CodeGen *g) {
- if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) {
+ if (g->err_name_table != nullptr || !g->generate_error_name_table || g->errors_by_index.length == 1) {
return;
}
- assert(g->error_decls.length > 0);
+ assert(g->errors_by_index.length > 0);
TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
- LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length);
+ LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
values[0] = LLVMGetUndef(str_type->type_ref);
- for (size_t i = 1; i < g->error_decls.length; i += 1) {
- AstNode *error_decl_node = g->error_decls.at(i);
- assert(error_decl_node->type == NodeTypeErrorValueDecl);
- Buf *name = error_decl_node->data.error_value_decl.name;
+ for (size_t i = 1; i < g->errors_by_index.length; i += 1) {
+ ErrorTableEntry *err_entry = g->errors_by_index.at(i);
+ Buf *name = &err_entry->name;
g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name));
@@ -4443,7 +4492,7 @@ static void generate_error_name_table(CodeGen *g) {
values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
}
- LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length);
+ LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->errors_by_index.length);
g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));
@@ -4575,6 +4624,28 @@ static void do_code_gen(CodeGen *g) {
codegen_add_time_event(g, "Code Generation");
+ {
+ // create debug type for error sets
+ assert(g->err_enumerators.length == g->errors_by_index.length);
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, g->err_tag_type->type_ref);
+ ZigLLVMDIFile *err_set_di_file = nullptr;
+ ZigLLVMDIType *err_set_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&g->builtin_types.entry_global_error_set->name),
+ err_set_di_file, 0,
+ tag_debug_size_in_bits,
+ tag_debug_align_in_bits,
+ g->err_enumerators.items, g->err_enumerators.length,
+ g->err_tag_type->di_type, "");
+ ZigLLVMReplaceTemporary(g->dbuilder, g->builtin_types.entry_global_error_set->di_type, err_set_di_type);
+ g->builtin_types.entry_global_error_set->di_type = err_set_di_type;
+
+ for (size_t i = 0; i < g->error_di_types.length; i += 1) {
+ ZigLLVMDIType **di_type_ptr = g->error_di_types.at(i);
+ *di_type_ptr = err_set_di_type;
+ }
+ }
+
generate_error_name_table(g);
generate_enum_name_tables(g);
@@ -4592,7 +4663,7 @@ static void do_code_gen(CodeGen *g) {
coerced_value.special = ConstValSpecialStatic;
coerced_value.type = var_type;
coerced_value.data.x_f128 = bigfloat_to_f128(&const_val->data.x_bigfloat);
- LLVMValueRef init_val = gen_const_val(g, &coerced_value);
+ LLVMValueRef init_val = gen_const_val(g, &coerced_value, "");
gen_global_var(g, var, init_val, var_type);
continue;
}
@@ -4626,8 +4697,9 @@ static void do_code_gen(CodeGen *g) {
LLVMSetAlignment(global_value, var->align_bytes);
} else {
bool exported = (var->linkage == VarLinkageExport);
- render_const_val(g, var->value);
- render_const_val_global(g, var->value, buf_ptr(get_mangled_name(g, &var->name, exported)));
+ const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
+ render_const_val(g, var->value, mangled_name);
+ render_const_val_global(g, var->value, mangled_name);
global_value = var->value->global_refs->llvm_global;
if (exported) {
@@ -5176,16 +5248,24 @@ static void define_builtin_types(CodeGen *g) {
}
{
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorSet);
buf_init_from_str(&entry->name, "error");
+ entry->data.error_set.err_count = UINT32_MAX;
// TODO allow overriding this type and keep track of max value and emit an
// error if there are too many errors declared
g->err_tag_type = g->builtin_types.entry_u16;
- g->builtin_types.entry_pure_error = entry;
+ g->builtin_types.entry_global_error_set = entry;
entry->type_ref = g->err_tag_type->type_ref;
- entry->di_type = g->err_tag_type->di_type;
+
+ entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+ ZigLLVMTag_DW_enumeration_type(), "error",
+ ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0);
+
+ // reserve index 0 to indicate no error
+ g->err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0));
+ g->errors_by_index.append(nullptr);
g->primitive_type_table.put(&entry->name, entry);
}
@@ -5815,7 +5895,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
zig_unreachable();
case TypeTableEntryIdVoid:
case TypeTableEntryIdUnreachable:
@@ -5988,7 +6068,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
return;
}
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
zig_panic("TODO implement get_c_type for more types");
case TypeTableEntryIdInvalid:
@@ -6155,7 +6235,7 @@ static void gen_h_file(CodeGen *g) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -6265,3 +6345,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
}
return pkg;
}
+