aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp187
1 files changed, 131 insertions, 56 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index d871aa27a0..db1faac37c 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -2392,9 +2392,10 @@ static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *so
return &instruction->base;
}
-static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
+static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, bool bit_size) {
IrInstructionSizeOf *instruction = ir_build_instruction<IrInstructionSizeOf>(irb, scope, source_node);
instruction->type_value = type_value;
+ instruction->bit_size = bit_size;
ir_ref_instruction(type_value, irb->current_basic_block);
@@ -3451,7 +3452,7 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count,
- bool have_else_prong)
+ bool have_else_prong, bool have_underscore_prong)
{
IrInstructionCheckSwitchProngs *instruction = ir_build_instruction<IrInstructionCheckSwitchProngs>(
irb, scope, source_node);
@@ -3459,6 +3460,7 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,
instruction->ranges = ranges;
instruction->range_count = range_count;
instruction->have_else_prong = have_else_prong;
+ instruction->have_underscore_prong = have_underscore_prong;
ir_ref_instruction(target_value, irb->current_basic_block);
for (size_t i = 0; i < range_count; i += 1) {
@@ -5249,13 +5251,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc);
}
case BuiltinFnIdSizeof:
+ case BuiltinFnIdBitSizeof:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
+ IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof);
return ir_lval_wrap(irb, scope, size_of, lval, result_loc);
}
case BuiltinFnIdImport:
@@ -6027,8 +6030,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
- IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
+ IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, arg0_value);
return ir_lval_wrap(irb, scope, tag_name, lval, result_loc);
}
case BuiltinFnIdTagType:
@@ -8090,34 +8092,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
AstNode *else_prong = nullptr;
+ AstNode *underscore_prong = nullptr;
for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
size_t prong_item_count = prong_node->data.switch_prong.items.length;
- if (prong_item_count == 0) {
- ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
- if (else_prong) {
- ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
- buf_sprintf("multiple else prongs in switch expression"));
- add_error_note(irb->codegen, msg, else_prong,
- buf_sprintf("previous else prong is here"));
- return irb->codegen->invalid_instruction;
- }
- else_prong = prong_node;
-
- IrBasicBlock *prev_block = irb->current_basic_block;
- if (peer_parent->peers.length > 0) {
- peer_parent->peers.last()->next_bb = else_block;
- }
- peer_parent->peers.append(this_peer_result_loc);
- ir_set_cursor_at_end_and_append_block(irb, else_block);
- if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
- &switch_else_var, LValNone, &this_peer_result_loc->base))
- {
- return irb->codegen->invalid_instruction;
- }
- ir_set_cursor_at_end(irb, prev_block);
- } else if (prong_node->data.switch_prong.any_items_are_range) {
+ if (prong_node->data.switch_prong.any_items_are_range) {
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
IrInstruction *ok_bit = nullptr;
@@ -8195,6 +8174,56 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
ir_set_cursor_at_end_and_append_block(irb, range_block_no);
+ } else {
+ if (prong_item_count == 0) {
+ if (else_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("multiple else prongs in switch expression"));
+ add_error_note(irb->codegen, msg, else_prong,
+ buf_sprintf("previous else prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ else_prong = prong_node;
+ } else if (prong_item_count == 1 &&
+ prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
+ buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
+ if (underscore_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("multiple '_' prongs in switch expression"));
+ add_error_note(irb->codegen, msg, underscore_prong,
+ buf_sprintf("previous '_' prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ underscore_prong = prong_node;
+ } else {
+ continue;
+ }
+ if (underscore_prong && else_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("else and '_' prong in switch expression"));
+ if (underscore_prong == prong_node)
+ add_error_note(irb->codegen, msg, else_prong,
+ buf_sprintf("else prong is here"));
+ else
+ add_error_note(irb->codegen, msg, underscore_prong,
+ buf_sprintf("'_' prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
+
+ IrBasicBlock *prev_block = irb->current_basic_block;
+ if (peer_parent->peers.length > 0) {
+ peer_parent->peers.last()->next_bb = else_block;
+ }
+ peer_parent->peers.append(this_peer_result_loc);
+ ir_set_cursor_at_end_and_append_block(irb, else_block);
+ if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
+ is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
+ &switch_else_var, LValNone, &this_peer_result_loc->base))
+ {
+ return irb->codegen->invalid_instruction;
+ }
+ ir_set_cursor_at_end(irb, prev_block);
}
}
@@ -8206,6 +8235,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
continue;
if (prong_node->data.switch_prong.any_items_are_range)
continue;
+ if (underscore_prong == prong_node)
+ continue;
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
@@ -8249,7 +8280,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,
- check_ranges.items, check_ranges.length, else_prong != nullptr);
+ check_ranges.items, check_ranges.length, else_prong != nullptr, underscore_prong != nullptr);
IrInstruction *br_instruction;
if (cases.length == 0) {
@@ -8269,7 +8300,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction;
}
- if (!else_prong) {
+ if (!else_prong && !underscore_prong) {
if (peer_parent->peers.length != 0) {
peer_parent->peers.last()->next_bb = else_block;
}
@@ -12790,7 +12821,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
- if (field == nullptr && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
+ if (field == nullptr && !wanted_type->data.enumeration.non_exhaustive) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -21065,6 +21096,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi
lazy_size_of->ira = ira; ira_ref(ira);
result->value->data.x_lazy = &lazy_size_of->base;
lazy_size_of->base.id = LazyValueIdSizeOf;
+ lazy_size_of->bit_size = instruction->bit_size;
lazy_size_of->target_type = instruction->type_value->child;
if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr)
@@ -21356,10 +21388,6 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
if (type_is_invalid(value->value->type))
return ira->codegen->invalid_instruction;
- if (value->value->type->id == ZigTypeIdEnum) {
- return value;
- }
-
if (value->value->type->id != ZigTypeIdUnion) {
ir_add_error(ira, value,
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name)));
@@ -21427,12 +21455,6 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
if (type_is_invalid(case_value->value->type))
return ir_unreach_error(ira);
- if (case_value->value->type->id == ZigTypeIdEnum) {
- case_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, case_value);
- if (type_is_invalid(case_value->value->type))
- return ir_unreach_error(ira);
- }
-
IrInstruction *casted_case_value = ir_implicit_cast(ira, case_value, target_value->value->type);
if (type_is_invalid(casted_case_value->value->type))
return ir_unreach_error(ira);
@@ -21477,12 +21499,6 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
if (type_is_invalid(new_value->value->type))
continue;
- if (new_value->value->type->id == ZigTypeIdEnum) {
- new_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, new_value);
- if (type_is_invalid(new_value->value->type))
- continue;
- }
-
IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->value->type);
if (type_is_invalid(casted_new_value->value->type))
continue;
@@ -21598,7 +21614,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case ZigTypeIdEnum: {
if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
- if (target_type->data.enumeration.src_field_count < 2) {
+ if (target_type->data.enumeration.src_field_count == 1) {
TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
IrInstruction *result = ir_const(ira, &switch_target_instruction->base, target_type);
bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);
@@ -22319,11 +22335,39 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_instruction;
+ if (target->value->type->id == ZigTypeIdEnumLiteral) {
+ IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
+ Buf *field_name = target->value->data.x_enum_literal;
+ ZigValue *array_val = create_const_str_lit(ira->codegen, field_name)->data.x_ptr.data.ref.pointee;
+ init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field_name), true);
+ return result;
+ }
+
+ if (target->value->type->id == ZigTypeIdUnion) {
+ target = ir_analyze_union_tag(ira, &instruction->base, target);
+ if (type_is_invalid(target->value->type))
+ return ira->codegen->invalid_instruction;
+ }
+
assert(target->value->type->id == ZigTypeIdEnum);
+ if (target->value->type->data.enumeration.src_field_count == 1 &&
+ !target->value->type->data.enumeration.non_exhaustive) {
+ TypeEnumField *only_field = &target->value->type->data.enumeration.fields[0];
+ ZigValue *array_val = create_const_str_lit(ira->codegen, only_field->name)->data.x_ptr.data.ref.pointee;
+ IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
+ init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(only_field->name), true);
+ return result;
+ }
+
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
+ if (target->value->type->data.enumeration.non_exhaustive) {
+ add_node_error(ira->codegen, instruction->base.source_node,
+ buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
+ return ira->codegen->invalid_instruction;
+ }
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
@@ -23074,7 +23118,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
result->special = ConstValSpecialStatic;
result->type = ir_type_info_get_type(ira, "Enum", nullptr);
- ZigValue **fields = alloc_const_vals_ptrs(4);
+ ZigValue **fields = alloc_const_vals_ptrs(5);
result->data.x_struct.fields = fields;
// layout: ContainerLayout
@@ -23120,6 +23164,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
{
return err;
}
+ // is_exhaustive: bool
+ ensure_field_index(result->type, "is_exhaustive", 4);
+ fields[4]->special = ConstValSpecialStatic;
+ fields[4]->type = ira->codegen->builtin_types.entry_bool;
+ fields[4]->data.x_bool = !type_entry->data.enumeration.non_exhaustive;
break;
}
@@ -23335,7 +23384,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
struct_field_val->special = ConstValSpecialStatic;
struct_field_val->type = type_info_struct_field_type;
- ZigValue **inner_fields = alloc_const_vals_ptrs(3);
+ ZigValue **inner_fields = alloc_const_vals_ptrs(4);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int);
@@ -23358,6 +23407,12 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
inner_fields[2]->data.x_type = struct_field->type_entry;
+ // default_value: var
+ inner_fields[3]->special = ConstValSpecialStatic;
+ inner_fields[3]->type = get_optional_type(ira->codegen, struct_field->type_entry);
+ memoize_field_init_val(ira->codegen, type_entry, struct_field);
+ set_optional_payload(inner_fields[3], struct_field->init_val);
+
ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
@@ -26433,10 +26488,27 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
bigint_incr(&field_index);
}
}
- if (!instruction->have_else_prong) {
- if (switch_type->data.enumeration.layout == ContainerLayoutExtern) {
+ if (instruction->have_underscore_prong) {
+ if (!switch_type->data.enumeration.non_exhaustive){
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("switch on non-exhaustive enum has `_` prong"));
+ }
+ for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
+ TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
+ if (buf_eql_str(enum_field->name, "_"))
+ continue;
+
+ auto entry = field_prev_uses.maybe_get(enum_field->value);
+ if (!entry) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name),
+ buf_ptr(enum_field->name)));
+ }
+ }
+ } else if (!instruction->have_else_prong) {
+ if (switch_type->data.enumeration.non_exhaustive) {
ir_add_error(ira, &instruction->base,
- buf_sprintf("switch on an extern enum must have an else prong"));
+ buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong"));
}
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
@@ -29415,7 +29487,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
val->special = ConstValSpecialStatic;
assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
- bigint_init_unsigned(&val->data.x_bigint, abi_size);
+ if (lazy_size_of->bit_size)
+ bigint_init_unsigned(&val->data.x_bigint, size_in_bits);
+ else
+ bigint_init_unsigned(&val->data.x_bigint, abi_size);
// We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
return ErrorNone;