From 8460d5617cc12d614abf39f55ab85c783c4b35a8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 12:07:56 -0400 Subject: introduce lazy values see #2174 --- src/codegen.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 622ade712a..2be4ebbbc9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3386,6 +3386,8 @@ static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { static bool value_is_all_undef(ConstExprValue *const_val) { switch (const_val->special) { + case ConstValSpecialLazy: + zig_unreachable(); case ConstValSpecialRuntime: return false; case ConstValSpecialUndef: @@ -3686,7 +3688,7 @@ static void render_async_spills(CodeGen *g) { } if (ir_get_var_is_comptime(var)) continue; - switch (type_requires_comptime(g, var->var_type)) { + switch (type_requires_comptime(g, var->var_type, nullptr)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeYes: @@ -6041,6 +6043,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { switch (const_val->special) { + case ConstValSpecialLazy: case ConstValSpecialRuntime: zig_unreachable(); case ConstValSpecialUndef: @@ -6300,6 +6303,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c assert(type_has_bits(type_entry)); switch (const_val->special) { + case ConstValSpecialLazy: + zig_unreachable(); case ConstValSpecialRuntime: zig_unreachable(); case ConstValSpecialUndef: @@ -7044,7 +7049,7 @@ static void do_code_gen(CodeGen *g) { } if (ir_get_var_is_comptime(var)) continue; - switch (type_requires_comptime(g, var->var_type)) { + switch (type_requires_comptime(g, var->var_type, nullptr)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeYes: -- cgit v1.2.3 From 1dd658d1d02f8dfc432bcda88fdb542189c31725 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 14:07:34 -0400 Subject: allow top level declarations to be lazy this case now works: ```zig const A = struct { b: B, }; const B = fn (A) void; ``` --- src/all_types.hpp | 1 + src/analyze.cpp | 74 ++++++++++++++++++++++++++++++------------------------- src/analyze.hpp | 2 +- src/codegen.cpp | 2 +- src/ir.cpp | 6 ++--- 5 files changed, 47 insertions(+), 38 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 595df7460f..11bed48e8f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -423,6 +423,7 @@ enum TldResolution { TldResolutionUnresolved, TldResolutionResolving, TldResolutionInvalid, + TldResolutionOkLazy, TldResolutionOk, }; diff --git a/src/analyze.cpp b/src/analyze.cpp index c08f954e18..bfdeb5d41a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3091,7 +3091,7 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name); - resolve_top_level_decl(g, tld, tld->source_node); + resolve_top_level_decl(g, tld, tld->source_node, false); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; tld_var->var->const_value = value; @@ -3333,7 +3333,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf return variable_entry; } -static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { +static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { AstNode *source_node = tld_var->base.source_node; AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; @@ -3364,7 +3364,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { if (explicit_type && explicit_type->id == ZigTypeIdInvalid) { implicit_type = explicit_type; } else if (var_decl->expr) { - init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); + init_value = analyze_const_value_allow_lazy(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, + var_decl->symbol, allow_lazy); assert(init_value); implicit_type = init_value->type; @@ -3539,50 +3540,57 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco } } -void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) { - if (tld->resolution != TldResolutionUnresolved) +void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) { + bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy; + if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy) return; - assert(tld->resolution != TldResolutionResolving); tld->resolution = TldResolutionResolving; switch (tld->id) { - case TldIdVar: - { - TldVar *tld_var = (TldVar *)tld; - resolve_decl_var(g, tld_var); - break; - } - case TldIdFn: - { - TldFn *tld_fn = (TldFn *)tld; - resolve_decl_fn(g, tld_fn); - break; - } - case TldIdContainer: - { - TldContainer *tld_container = (TldContainer *)tld; - resolve_decl_container(g, tld_container); - break; - } - case TldIdCompTime: - { - TldCompTime *tld_comptime = (TldCompTime *)tld; - resolve_decl_comptime(g, tld_comptime); - break; + case TldIdVar: { + TldVar *tld_var = (TldVar *)tld; + if (want_resolve_lazy) { + ir_resolve_lazy(g, source_node, tld_var->var->const_value); + } else { + resolve_decl_var(g, tld_var, allow_lazy); } + tld->resolution = allow_lazy ? TldResolutionOkLazy : TldResolutionOk; + break; + } + case TldIdFn: { + TldFn *tld_fn = (TldFn *)tld; + resolve_decl_fn(g, tld_fn); + + tld->resolution = TldResolutionOk; + break; + } + case TldIdContainer: { + TldContainer *tld_container = (TldContainer *)tld; + resolve_decl_container(g, tld_container); + + tld->resolution = TldResolutionOk; + break; + } + case TldIdCompTime: { + TldCompTime *tld_comptime = (TldCompTime *)tld; + resolve_decl_comptime(g, tld_comptime); + + tld->resolution = TldResolutionOk; + break; + } case TldIdUsingNamespace: { TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld; assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls); ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope; preview_use_decl(g, tld_using_namespace, dest_decls_scope); resolve_use_decl(g, tld_using_namespace, dest_decls_scope); + + tld->resolution = TldResolutionOk; break; } } - tld->resolution = TldResolutionOk; - if (g->trace_err != nullptr && source_node != nullptr) { g->trace_err = add_error_note(g, g->trace_err, source_node, buf_create_from_str("referenced here")); } @@ -4254,7 +4262,7 @@ void semantic_analyze(CodeGen *g) { Tld *tld = g->resolve_queue.at(g->resolve_queue_index); g->trace_err = nullptr; AstNode *source_node = nullptr; - resolve_top_level_decl(g, tld, source_node); + resolve_top_level_decl(g, tld, source_node, false); } for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { @@ -6602,7 +6610,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) { ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name)); - resolve_top_level_decl(codegen, tld, nullptr); + resolve_top_level_decl(codegen, tld, nullptr, false); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; ConstExprValue *var_value = tld_var->var->const_value; diff --git a/src/analyze.hpp b/src/analyze.hpp index 740b47ac1d..cd855522f3 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -58,7 +58,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Bu ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name); -void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node); +void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy); ZigType *get_src_ptr_type(ZigType *type); ZigType *get_codegen_ptr_type(ZigType *type); diff --git a/src/codegen.cpp b/src/codegen.cpp index cfeb0187eb..29c3a30158 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8896,7 +8896,7 @@ static void gen_root_source(CodeGen *g) { } Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic")); assert(panic_tld != nullptr); - resolve_top_level_decl(g, panic_tld, nullptr); + resolve_top_level_decl(g, panic_tld, nullptr, false); } diff --git a/src/ir.cpp b/src/ir.cpp index 2970f536b9..5f4cce328a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17074,7 +17074,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, auto entry = container_scope->decl_table.maybe_get(field_name); Tld *tld = entry ? entry->value : nullptr; if (tld && tld->id == TldIdFn) { - resolve_top_level_decl(ira->codegen, tld, source_instr->source_node); + resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false); if (tld->resolution == TldResolutionInvalid) return ira->codegen->invalid_instruction; TldFn *tld_fn = (TldFn *)tld; @@ -17317,7 +17317,7 @@ static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *so } static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { - resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node); + resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node, true); if (tld->resolution == TldResolutionInvalid) { return ira->codegen->invalid_instruction; } @@ -19682,7 +19682,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr while ((curr_entry = decl_it.next()) != nullptr) { // If the declaration is unresolved, force it to be resolved again. if (curr_entry->value->resolution == TldResolutionUnresolved) { - resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node); + resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node, false); if (curr_entry->value->resolution != TldResolutionOk) { return ErrorSemanticAnalyzeFail; } -- cgit v1.2.3 From ac4dd9d665ba195a6b21b3b033f27c865015ccac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 15:54:51 -0400 Subject: better handling of lazy structs this case works now: ```zig const A = struct { b_list_pointer: *const []B, }; const B = struct { a_pointer: *const A, }; const b_list: []B = [_]B{}; const a = A{ .b_list_pointer = &b_list }; const obj = B{ .a_pointer = &a }; ``` --- src/all_types.hpp | 3 ++- src/analyze.cpp | 57 ++++++++++++++++++++++++++++--------------------------- src/analyze.hpp | 2 +- src/codegen.cpp | 4 ++-- src/ir.cpp | 20 +++++++++---------- 5 files changed, 44 insertions(+), 42 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d23020593d..2a20d3c860 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1190,7 +1190,8 @@ struct ZigTypeStruct { // whether any of the fields require comptime // known after ResolveStatusZeroBitsKnown bool requires_comptime; - bool resolve_loop_flag; + bool resolve_loop_flag_zero_bits; + bool resolve_loop_flag_other; }; struct ZigTypeOptional { diff --git a/src/analyze.cpp b/src/analyze.cpp index f140489ab3..f6e8a77770 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -685,7 +685,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]); entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]); - switch (type_requires_comptime(g, ptr_type, entry)) { + switch (type_requires_comptime(g, ptr_type)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeNo: @@ -1016,9 +1016,9 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool zig_unreachable(); } -static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type) { +static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue *type_val) { if (type_val->special != ConstValSpecialLazy) { - return type_requires_comptime(g, type_val->data.x_type, parent_type); + return type_requires_comptime(g, type_val->data.x_type); } switch (type_val->data.x_lazy->id) { case LazyValueIdInvalid: @@ -1028,17 +1028,17 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); if (type_is_invalid(lazy_slice_type->elem_type)) return ReqCompTimeInvalid; - return type_requires_comptime(g, lazy_slice_type->elem_type, parent_type); + return type_requires_comptime(g, lazy_slice_type->elem_type); } case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type_val, parent_type); + return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type_val); } case LazyValueIdFnType: { LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); if (lazy_fn_type->is_generic) return ReqCompTimeYes; - switch (type_val_resolve_requires_comptime(g, lazy_fn_type->return_type, parent_type)) { + switch (type_val_resolve_requires_comptime(g, lazy_fn_type->return_type)) { case ReqCompTimeInvalid: return ReqCompTimeInvalid; case ReqCompTimeYes: @@ -1051,7 +1051,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue AstNode *param_node = lazy_fn_type->proto_node->data.fn_proto.params.at(i); bool param_is_var_args = param_node->data.param_decl.is_var_args; if (param_is_var_args) break; - switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i], parent_type)) { + switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i])) { case ReqCompTimeInvalid: return ReqCompTimeInvalid; case ReqCompTimeYes: @@ -1517,7 +1517,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdVector: case ZigTypeIdFnFrame: case ZigTypeIdAnyFrame: - switch (type_requires_comptime(g, type_entry, fn_entry->type_entry)) { + switch (type_requires_comptime(g, type_entry)) { case ReqCompTimeNo: break; case ReqCompTimeYes: @@ -1613,7 +1613,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdVector: case ZigTypeIdFnFrame: case ZigTypeIdAnyFrame: - switch (type_requires_comptime(g, fn_type_id.return_type, fn_entry->type_entry)) { + switch (type_requires_comptime(g, fn_type_id.return_type)) { case ReqCompTimeInvalid: return g->builtin_types.entry_invalid; case ReqCompTimeYes: @@ -1745,7 +1745,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { AstNode *decl_node = struct_type->data.structure.decl_node; - if (struct_type->data.structure.resolve_loop_flag) { + if (struct_type->data.structure.resolve_loop_flag_other) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, @@ -1760,7 +1760,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { size_t field_count = struct_type->data.structure.src_field_count; bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); - struct_type->data.structure.resolve_loop_flag = true; + struct_type->data.structure.resolve_loop_flag_other = true; uint32_t *host_int_bytes = packed ? allocate(struct_type->data.structure.gen_field_count) : nullptr; @@ -1877,7 +1877,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { struct_type->size_in_bits = size_in_bits; struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; - struct_type->data.structure.resolve_loop_flag = false; + struct_type->data.structure.resolve_loop_flag_other = false; struct_type->data.structure.host_int_bytes = host_int_bytes; return ErrorNone; @@ -2275,7 +2275,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { AstNode *decl_node = struct_type->data.structure.decl_node; assert(decl_node->type == NodeTypeContainerDecl); - if (struct_type->data.structure.resolve_loop_flag) { + if (struct_type->data.structure.resolve_loop_flag_zero_bits) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, @@ -2285,7 +2285,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - struct_type->data.structure.resolve_loop_flag = true; + struct_type->data.structure.resolve_loop_flag_zero_bits = true; assert(!struct_type->data.structure.fields); size_t field_count = decl_node->data.container_decl.fields.length; @@ -2343,7 +2343,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { type_struct_field->src_index = i; type_struct_field->gen_index = SIZE_MAX; - switch (type_val_resolve_requires_comptime(g, field_type_val, struct_type)) { + switch (type_val_resolve_requires_comptime(g, field_type_val)) { case ReqCompTimeYes: struct_type->data.structure.requires_comptime = true; break; @@ -2370,7 +2370,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { gen_field_index += 1; } - struct_type->data.structure.resolve_loop_flag = false; + struct_type->data.structure.resolve_loop_flag_zero_bits = false; struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; if (gen_field_index != 0) { struct_type->abi_size = SIZE_MAX; @@ -2400,7 +2400,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { AstNode *decl_node = struct_type->data.structure.decl_node; - if (struct_type->data.structure.resolve_loop_flag) { + if (struct_type->data.structure.resolve_loop_flag_other) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, @@ -2409,7 +2409,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - struct_type->data.structure.resolve_loop_flag = true; + struct_type->data.structure.resolve_loop_flag_other = true; assert(decl_node->type == NodeTypeContainerDecl); size_t field_count = struct_type->data.structure.src_field_count; @@ -2444,7 +2444,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } } - struct_type->data.structure.resolve_loop_flag = false; + struct_type->data.structure.resolve_loop_flag_other = false; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { return ErrorSemanticAnalyzeFail; @@ -2614,7 +2614,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } - switch (type_requires_comptime(g, field_type, union_type)) { + switch (type_requires_comptime(g, field_type)) { case ReqCompTimeInvalid: union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; @@ -4959,11 +4959,8 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { zig_unreachable(); } -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty, ZigType *parent_type) { +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { Error err; - if (ty == parent_type) { - return ReqCompTimeNo; - } switch (ty->id) { case ZigTypeIdInvalid: zig_unreachable(); @@ -4977,8 +4974,12 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty, ZigType *parent_type case ZigTypeIdArgTuple: return ReqCompTimeYes; case ZigTypeIdArray: - return type_requires_comptime(g, ty->data.array.child_type, parent_type); + return type_requires_comptime(g, ty->data.array.child_type); case ZigTypeIdStruct: + if (ty->data.structure.resolve_loop_flag_zero_bits) { + // Does a struct which contains a pointer field to itself require comptime? No. + return ReqCompTimeNo; + } if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) return ReqCompTimeInvalid; return ty->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; @@ -4987,14 +4988,14 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty, ZigType *parent_type return ReqCompTimeInvalid; return ty->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdOptional: - return type_requires_comptime(g, ty->data.maybe.child_type, parent_type); + return type_requires_comptime(g, ty->data.maybe.child_type); case ZigTypeIdErrorUnion: - return type_requires_comptime(g, ty->data.error_union.payload_type, parent_type); + return type_requires_comptime(g, ty->data.error_union.payload_type); case ZigTypeIdPointer: if (ty->data.pointer.child_type->id == ZigTypeIdOpaque) { return ReqCompTimeNo; } else { - return type_requires_comptime(g, ty->data.pointer.child_type, parent_type); + return type_requires_comptime(g, ty->data.pointer.child_type); } case ZigTypeIdFn: return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; diff --git a/src/analyze.hpp b/src/analyze.hpp index cd855522f3..0da9ec09af 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -221,7 +221,7 @@ enum ReqCompTime { ReqCompTimeNo, ReqCompTimeYes, }; -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry, ZigType *parent_type); +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); diff --git a/src/codegen.cpp b/src/codegen.cpp index 29c3a30158..930818ab42 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3688,7 +3688,7 @@ static void render_async_spills(CodeGen *g) { } if (ir_get_var_is_comptime(var)) continue; - switch (type_requires_comptime(g, var->var_type, nullptr)) { + switch (type_requires_comptime(g, var->var_type)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeYes: @@ -7049,7 +7049,7 @@ static void do_code_gen(CodeGen *g) { } if (ir_get_var_is_comptime(var)) continue; - switch (type_requires_comptime(g, var->var_type, nullptr)) { + switch (type_requires_comptime(g, var->var_type)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeYes: diff --git a/src/ir.cpp b/src/ir.cpp index 13ae0715a4..70dc894f86 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14234,7 +14234,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } } - switch (type_requires_comptime(ira->codegen, result_type, nullptr)) { + switch (type_requires_comptime(ira->codegen, result_type)) { case ReqCompTimeInvalid: result_type = ira->codegen->builtin_types.entry_invalid; break; @@ -15200,7 +15200,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod } if (!comptime_arg) { - switch (type_requires_comptime(ira->codegen, casted_arg->value.type, nullptr)) { + switch (type_requires_comptime(ira->codegen, casted_arg->value.type)) { case ReqCompTimeYes: ir_add_error(ira, casted_arg, buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name))); @@ -15401,7 +15401,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source } } - switch (type_requires_comptime(ira->codegen, child_type, nullptr)) { + switch (type_requires_comptime(ira->codegen, child_type)) { case ReqCompTimeInvalid: return ira->codegen->invalid_instruction; case ReqCompTimeYes: @@ -15794,7 +15794,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c inst_fn_type_id.return_type = specified_return_type; } - switch (type_requires_comptime(ira->codegen, specified_return_type, nullptr)) { + switch (type_requires_comptime(ira->codegen, specified_return_type)) { case ReqCompTimeYes: // Throw out our work and call the function as if it were comptime. return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, @@ -16601,7 +16601,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh break; } - switch (type_requires_comptime(ira->codegen, resolved_type, nullptr)) { + switch (type_requires_comptime(ira->codegen, resolved_type)) { case ReqCompTimeInvalid: return ira->codegen->invalid_instruction; case ReqCompTimeYes: @@ -17049,7 +17049,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } } else { // runtime known element index - switch (type_requires_comptime(ira->codegen, return_type, nullptr)) { + switch (type_requires_comptime(ira->codegen, return_type)) { case ReqCompTimeYes: ir_add_error(ira, elem_index, buf_sprintf("values of type '%s' must be comptime known, but index value is runtime known", @@ -19034,7 +19034,7 @@ static IrInstruction *ir_analyze_union_init(IrAnalyze *ira, IrInstruction *sourc } bool is_comptime = ir_should_inline(ira->new_irb.exec, source_instruction->scope) - || type_requires_comptime(ira->codegen, union_type, nullptr) == ReqCompTimeYes; + || type_requires_comptime(ira->codegen, union_type) == ReqCompTimeYes; IrInstruction *result = ir_get_deref(ira, source_instruction, result_loc, nullptr); if (is_comptime && !instr_is_comptime(result)) { @@ -19082,7 +19082,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc ZigList const_ptrs = {}; bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) - || type_requires_comptime(ira->codegen, container_type, nullptr) == ReqCompTimeYes; + || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; // Here we iterate over the fields that have been initialized, and emit @@ -19260,7 +19260,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, } bool is_comptime; - switch (type_requires_comptime(ira->codegen, container_type, nullptr)) { + switch (type_requires_comptime(ira->codegen, container_type)) { case ReqCompTimeInvalid: return ira->codegen->invalid_instruction; case ReqCompTimeNo: @@ -25502,7 +25502,7 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As lazy_fn_type->param_types[fn_type_id.next_param_index]); if (type_is_invalid(param_type)) return nullptr; - switch (type_requires_comptime(codegen, param_type, nullptr)) { + switch (type_requires_comptime(codegen, param_type)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { exec_add_error_node(codegen, exec, source_node, -- cgit v1.2.3 From fa6c20a02d2ee7648f69d9ba3b19fa600e8dd0e9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 11:34:07 -0400 Subject: hook up unions with lazy values this case works now: ```zig const Expr = union(enum) { Literal: u8, Question: *Expr, }; ``` --- src/all_types.hpp | 9 ++- src/analyze.cpp | 179 ++++++++++++++++++++++++++++++++---------------------- src/codegen.cpp | 2 +- 3 files changed, 112 insertions(+), 78 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 61dde995af..4b8a9c4308 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -489,10 +489,12 @@ struct TypeEnumField { struct TypeUnionField { Buf *name; + ZigType *type_entry; // available after ResolveStatusSizeKnown + ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown TypeEnumField *enum_field; - ZigType *type_entry; AstNode *decl_node; uint32_t gen_index; + uint32_t align; }; enum NodeType { @@ -1247,7 +1249,7 @@ struct ZigTypeUnion { HashMap fields_by_name; ZigType *tag_type; // always an enum or null LLVMTypeRef union_llvm_type; - ZigType *most_aligned_union_member; + TypeUnionField *most_aligned_union_member; size_t gen_union_index; size_t gen_tag_index; size_t union_abi_size; @@ -1262,7 +1264,8 @@ struct ZigTypeUnion { // whether any of the fields require comptime // the value is not valid until zero_bits_known == true bool requires_comptime; - bool resolve_loop_flag; + bool resolve_loop_flag_zero_bits; + bool resolve_loop_flag_other; }; struct FnGenParamInfo { diff --git a/src/analyze.cpp b/src/analyze.cpp index 5159dbb05a..7c967b4e5c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -961,10 +961,12 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi Error err; if (type_val->special != ConstValSpecialLazy) { assert(type_val->special == ConstValSpecialStatic); - if (type_val->data.x_type->id == ZigTypeIdStruct && - type_val->data.x_type->data.structure.resolve_loop_flag_zero_bits) + if ((type_val->data.x_type->id == ZigTypeIdStruct && + type_val->data.x_type->data.structure.resolve_loop_flag_zero_bits) || + (type_val->data.x_type->id == ZigTypeIdUnion && + type_val->data.x_type->data.unionation.resolve_loop_flag_zero_bits)) { - // Does a struct which contains a pointer field to itself have bits? Yes. + // Does a struct/union which contains a pointer field to itself have bits? Yes. *is_zero_bits = false; return ErrorNone; } @@ -1079,7 +1081,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue zig_unreachable(); } -static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, size_t *abi_align) { +static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) { Error err; if (type_val->special != ConstValSpecialLazy) { assert(type_val->special == ConstValSpecialStatic); @@ -1917,7 +1919,7 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { AstNode *decl_node = union_type->data.structure.decl_node; - if (union_type->data.unionation.resolve_loop_flag) { + if (union_type->data.unionation.resolve_loop_flag_other) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, @@ -1927,9 +1929,9 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { } // set temporary flag - union_type->data.unionation.resolve_loop_flag = true; + union_type->data.unionation.resolve_loop_flag_other = true; - ZigType *most_aligned_union_member = nullptr; + TypeUnionField *most_aligned_union_member = nullptr; uint32_t field_count = union_type->data.unionation.src_field_count; bool packed = union_type->data.unionation.layout == ContainerLayoutPacked; @@ -1938,33 +1940,32 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { if (field->gen_index == UINT32_MAX) continue; - src_assert(field->type_entry != nullptr, decl_node); - - size_t this_field_align; - if (packed) { - // TODO: https://github.com/ziglang/zig/issues/1512 - this_field_align = 1; + AstNode *align_expr = field->decl_node->data.struct_field.align_expr; + if (align_expr != nullptr) { + if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, + &field->align)) + { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return err; + } + } else if (packed) { + field->align = 1; } else { - if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { + if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; + return err; } - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - - this_field_align = field->type_entry->abi_align; } - if (most_aligned_union_member == nullptr || - this_field_align > most_aligned_union_member->abi_align) - { - most_aligned_union_member = field->type_entry; + if (most_aligned_union_member == nullptr || field->align > most_aligned_union_member->align) { + most_aligned_union_member = field; } } // unset temporary flag - union_type->data.unionation.resolve_loop_flag = false; + union_type->data.unionation.resolve_loop_flag_other = false; union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown; union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; @@ -1978,18 +1979,18 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { union_type->abi_align = tag_type->abi_align; union_type->data.unionation.gen_tag_index = SIZE_MAX; union_type->data.unionation.gen_union_index = SIZE_MAX; - } else if (tag_type->abi_align > most_aligned_union_member->abi_align) { + } else if (tag_type->abi_align > most_aligned_union_member->align) { union_type->abi_align = tag_type->abi_align; union_type->data.unionation.gen_tag_index = 0; union_type->data.unionation.gen_union_index = 1; } else { - union_type->abi_align = most_aligned_union_member->abi_align; + union_type->abi_align = most_aligned_union_member->align; union_type->data.unionation.gen_union_index = 0; union_type->data.unionation.gen_tag_index = 1; } } else { assert(most_aligned_union_member != nullptr); - union_type->abi_align = most_aligned_union_member->abi_align; + union_type->abi_align = most_aligned_union_member->align; union_type->data.unionation.gen_union_index = SIZE_MAX; union_type->data.unionation.gen_tag_index = SIZE_MAX; } @@ -2016,14 +2017,14 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { assert(decl_node->type == NodeTypeContainerDecl); uint32_t field_count = union_type->data.unionation.src_field_count; - ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; + TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; assert(union_type->data.unionation.fields); size_t union_abi_size = 0; size_t union_size_in_bits = 0; - if (union_type->data.unionation.resolve_loop_flag) { + if (union_type->data.unionation.resolve_loop_flag_other) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, @@ -2033,11 +2034,18 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { } // set temporary flag - union_type->data.unionation.resolve_loop_flag = true; + union_type->data.unionation.resolve_loop_flag_other = true; for (uint32_t i = 0; i < field_count; i += 1) { + AstNode *field_source_node = decl_node->data.container_decl.fields.at(i); TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - ZigType *field_type = union_field->type_entry; + + if ((err = ir_resolve_lazy(g, field_source_node, union_field->type_val))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return err; + } + ZigType *field_type = union_field->type_val->data.x_type; + union_field->type_entry = field_type; if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -2057,11 +2065,11 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { // The union itself for now has to be treated as being independently aligned. // See https://github.com/ziglang/zig/issues/2166. if (most_aligned_union_member != nullptr) { - union_abi_size = align_forward(union_abi_size, most_aligned_union_member->abi_align); + union_abi_size = align_forward(union_abi_size, most_aligned_union_member->align); } // unset temporary flag - union_type->data.unionation.resolve_loop_flag = false; + union_type->data.unionation.resolve_loop_flag_other = false; union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; union_type->data.unionation.union_abi_size = union_abi_size; @@ -2080,7 +2088,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size; field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align; field_sizes[union_type->data.unionation.gen_union_index] = union_abi_size; - field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->abi_align; + field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->align; size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[1]); union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], union_type->abi_align); union_type->size_in_bits = union_type->abi_size * 8; @@ -2449,12 +2457,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } else if (packed) { field->align = 1; } else { - size_t result_abi_align; - if ((err = type_val_resolve_abi_align(g, field->type_val, &result_abi_align))) { + if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return err; } - field->align = result_abi_align; + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; } if (field->align > struct_type->abi_align) { @@ -2486,7 +2494,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { AstNode *decl_node = union_type->data.unionation.decl_node; assert(decl_node->type == NodeTypeContainerDecl); - if (union_type->data.unionation.resolve_loop_flag) { + if (union_type->data.unionation.resolve_loop_flag_zero_bits) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, @@ -2496,7 +2504,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } - union_type->data.unionation.resolve_loop_flag = true; + union_type->data.unionation.resolve_loop_flag_zero_bits = true; assert(union_type->data.unionation.fields == nullptr); uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; @@ -2605,49 +2613,68 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } - ZigType *field_type; + bool field_is_zero_bits; if (field_node->data.struct_field.type == nullptr) { - if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { - field_type = g->builtin_types.entry_void; + if (decl_node->data.container_decl.auto_enum || + decl_node->data.container_decl.init_arg_expr != nullptr) + { + union_field->type_entry = g->builtin_types.entry_void; + field_is_zero_bits = false; } else { add_node_error(g, field_node, buf_sprintf("union field missing type")); union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } } else { - field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); - if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) { + ConstExprValue *field_type_val = analyze_const_value_allow_lazy(g, scope, + field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, true); + if (type_is_invalid(field_type_val->type)) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } + assert(field_type_val->special != ConstValSpecialRuntime); + union_field->type_val = field_type_val; if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - } - union_field->type_entry = field_type; - if (field_type->id == ZigTypeIdOpaque) { - add_node_error(g, field_node->data.struct_field.type, - buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + if (field_is_opaque_type) { + add_node_error(g, field_node->data.struct_field.type, + buf_create_from_str( + "opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } - switch (type_requires_comptime(g, field_type)) { - case ReqCompTimeInvalid: + switch (type_val_resolve_requires_comptime(g, field_type_val)) { + case ReqCompTimeInvalid: + if (g->trace_err != nullptr) { + g->trace_err = add_error_note(g, g->trace_err, field_node, + buf_create_from_str("while checking this field")); + } + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + case ReqCompTimeYes: + union_type->data.unionation.requires_comptime = true; + break; + case ReqCompTimeNo: + break; + } + + if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; + } } if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, - buf_sprintf("non-enum union field assignment")); - add_error_note(g, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); + buf_create_from_str("untagged union field assignment")); + add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); } if (create_enum_type) { @@ -2706,7 +2733,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } assert(union_field->enum_field != nullptr); - if (!type_has_bits(field_type)) + if (field_is_zero_bits) continue; union_field->gen_index = gen_field_index; @@ -2783,7 +2810,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } - union_type->data.unionation.resolve_loop_flag = false; + union_type->data.unionation.resolve_loop_flag_zero_bits = false; union_type->data.unionation.gen_field_count = gen_field_index; bool zero_bits = gen_field_index == 0 && (field_count < 2 || !src_have_tag); @@ -5002,6 +5029,10 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { return ReqCompTimeInvalid; return ty->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdUnion: + if (ty->data.unionation.resolve_loop_flag_zero_bits) { + // Does a union which contains a pointer field to itself require comptime? No. + return ReqCompTimeNo; + } if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) return ReqCompTimeInvalid; return ty->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; @@ -7308,7 +7339,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; - ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; + TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; ZigType *tag_type = union_type->data.unionation.tag_type; if (most_aligned_union_member == nullptr) { union_type->llvm_type = get_llvm_type(g, tag_type); @@ -7361,17 +7392,17 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta if (tag_type == nullptr || !type_has_bits(tag_type)) { assert(most_aligned_union_member != nullptr); - size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->abi_size; + size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; if (padding_bytes > 0) { ZigType *u8_type = get_int_type(g, false, 8); ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); LLVMTypeRef union_element_types[] = { - most_aligned_union_member->llvm_type, + most_aligned_union_member->type_entry->llvm_type, get_llvm_type(g, padding_array), }; LLVMStructSetBody(union_type->llvm_type, union_element_types, 2, false); } else { - LLVMStructSetBody(union_type->llvm_type, &most_aligned_union_member->llvm_type, 1, false); + LLVMStructSetBody(union_type->llvm_type, &most_aligned_union_member->type_entry->llvm_type, 1, false); } union_type->data.unionation.union_llvm_type = union_type->llvm_type; union_type->data.unionation.gen_tag_index = SIZE_MAX; @@ -7382,7 +7413,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), union_type->data.unionation.union_abi_size * 8, - most_aligned_union_member->abi_align * 8, + most_aligned_union_member->align * 8, ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); @@ -7393,14 +7424,14 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta } LLVMTypeRef union_type_ref; - size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->abi_size; + size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; if (padding_bytes == 0) { - union_type_ref = get_llvm_type(g, most_aligned_union_member); + union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry); } else { ZigType *u8_type = get_int_type(g, false, 8); ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); LLVMTypeRef union_element_types[] = { - get_llvm_type(g, most_aligned_union_member), + get_llvm_type(g, most_aligned_union_member->type_entry), get_llvm_type(g, padding_array), }; union_type_ref = LLVMStructType(union_element_types, 2, false); @@ -7416,7 +7447,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), - most_aligned_union_member->size_in_bits, 8*most_aligned_union_member->abi_align, + most_aligned_union_member->type_entry->size_in_bits, 8*most_aligned_union_member->align, ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, @@ -7427,8 +7458,8 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), - most_aligned_union_member->size_in_bits, - 8*most_aligned_union_member->abi_align, + most_aligned_union_member->type_entry->size_in_bits, + 8*most_aligned_union_member->align, union_offset_in_bits, ZigLLVM_DIFlags_Zero, union_di_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index 930818ab42..ed6ef6367d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6568,7 +6568,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes; LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, ""); make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_value->type, correctly_typed_value) || - payload_value->type != type_entry->data.unionation.most_aligned_union_member; + payload_value->type != type_entry->data.unionation.most_aligned_union_member->type_entry; { if (pad_bytes == 0) { -- cgit v1.2.3 From ae65c236c55a1e22e63bb9f03c1ff925268646f1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 15:24:24 -0400 Subject: fix regression with global variable assignment... ...with optional unwrapping with var initialized to undefined --- src/codegen.cpp | 2 ++ src/ir.cpp | 44 +++++++++++++++++++++---------------------- test/stage1/behavior/misc.zig | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 23 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index ed6ef6367d..e8724f0d22 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3527,6 +3527,8 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir } static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return ir_llvm_value(g, &instruction->base); ZigVar *var = instruction->var; if (type_has_bits(var->var_type)) { assert(var->value_ref); diff --git a/src/ir.cpp b/src/ir.cpp index c61815b3bb..db7c2f1b53 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15259,23 +15259,25 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, bool comptime_var_mem = ir_get_var_is_comptime(var); bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern; - bool is_const = var->src_is_const; bool is_volatile = false; + IrInstruction *result = ir_build_var_ptr(&ira->new_irb, + instruction->scope, instruction->source_node, var); + result->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, + var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false); + if (linkage_makes_it_runtime) goto no_mem_slot; if (value_is_comptime(var->const_value)) { mem_slot = var->const_value; - } else { - if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { - // find the relevant exec_context - assert(var->owner_exec != nullptr); - assert(var->owner_exec->analysis != nullptr); - IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; - assert(var->mem_slot_index < exec_context->mem_slot_list.length); - mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); - } + } else if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { + // find the relevant exec_context + assert(var->owner_exec != nullptr); + assert(var->owner_exec->analysis != nullptr); + IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; + assert(var->mem_slot_index < exec_context->mem_slot_list.length); + mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); } if (mem_slot != nullptr) { @@ -15294,8 +15296,11 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, assert(!comptime_var_mem); ptr_mut = ConstPtrMutRuntimeVar; } - return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type, - ptr_mut, is_const, is_volatile, var->align_bytes); + result->value.special = ConstValSpecialStatic; + result->value.data.x_ptr.mut = ptr_mut; + result->value.data.x_ptr.special = ConstPtrSpecialRef; + result->value.data.x_ptr.data.ref.pointee = mem_slot; + return result; } } zig_unreachable(); @@ -15303,15 +15308,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, no_mem_slot: - IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, - instruction->scope, instruction->source_node, var); - var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, - var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false); - bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); - var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; + result->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; - return var_ptr_instruction; + return result; } // This function is called when a comptime value becomes accessible at runtime. @@ -17317,8 +17317,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ case TldIdCompTime: case TldIdUsingNamespace: zig_unreachable(); - case TldIdVar: - { + case TldIdVar: { TldVar *tld_var = (TldVar *)tld; ZigVar *var = tld_var->var; if (var == nullptr) { @@ -17330,8 +17329,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ return ir_get_var_ptr(ira, source_instruction, var); } - case TldIdFn: - { + case TldIdFn: { TldFn *tld_fn = (TldFn *)tld; ZigFn *fn_entry = tld_fn->fn_entry; assert(fn_entry->type_entry); diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index ab58f2ed08..c122b18e0a 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -706,3 +706,18 @@ test "result location zero sized array inside struct field implicit cast to slic var foo = E{ .entries = [_]u32{} }; expect(foo.entries.len == 0); } + +var global_foo: *i32 = undefined; + +test "global variable assignment with optional unwrapping with var initialized to undefined" { + const S = struct { + var data: i32 = 1234; + fn foo() ?*i32 { + return &data; + } + }; + global_foo = S.foo() orelse { + @panic("bad"); + }; + expect(global_foo.* == 1234); +} -- cgit v1.2.3