From efdbede7abf91d5fe2836d95987a83e95e9fcf8e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 21 Aug 2019 19:20:18 -0400 Subject: breaking: remove field alignment kludge This breaks behavior tests as well as compile error notes for generic function calls. However it introduces better circular dependency compile errors. The next step is to add Lazy Values to fix the regressions. --- src/all_types.hpp | 29 ++--- src/analyze.cpp | 343 +++++++++++++++++++----------------------------------- src/analyze.hpp | 6 +- src/ir.cpp | 133 +++++++++++---------- src/ir.hpp | 2 - 5 files changed, 201 insertions(+), 312 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 559ebe8cda..c5a30b75cc 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -69,9 +69,9 @@ struct IrExecutable { IrExecutable *source_exec; IrAnalyze *analysis; Scope *begin_scope; + ErrorMsg *first_err_trace_msg; ZigList tld_list; - bool invalid; bool is_inline; bool is_generic_instantiation; bool need_err_code_spill; @@ -1129,11 +1129,10 @@ struct ZigTypeStruct { ResolveStatus resolve_status; bool is_slice; - bool resolve_loop_flag; // set this flag temporarily to detect infinite loops - bool reported_infinite_err; // whether any of the fields require comptime // known after ResolveStatusZeroBitsKnown bool requires_comptime; + bool resolve_loop_flag; }; struct ZigTypeOptional { @@ -1155,26 +1154,20 @@ struct ZigTypeErrorSet { struct ZigTypeEnum { AstNode *decl_node; - ContainerLayout layout; - uint32_t src_field_count; TypeEnumField *fields; - bool is_invalid; // true if any fields are invalid ZigType *tag_int_type; ScopeDecls *decls_scope; - // set this flag temporarily to detect infinite loops - bool embedded_in_current; - bool reported_infinite_err; - // whether we've finished resolving it - bool complete; - - bool zero_bits_loop_flag; - bool zero_bits_known; - LLVMValueRef name_function; HashMap fields_by_name; + uint32_t src_field_count; + + ContainerLayout layout; + ResolveStatus resolve_status; + + bool resolve_loop_flag; }; uint32_t type_ptr_hash(const ZigType *ptr); @@ -1199,11 +1192,10 @@ struct ZigTypeUnion { ResolveStatus resolve_status; bool have_explicit_tag_type; - bool resolve_loop_flag; // set this flag temporarily to detect infinite loops - bool reported_infinite_err; // whether any of the fields require comptime // the value is not valid until zero_bits_known == true bool requires_comptime; + bool resolve_loop_flag; }; struct FnGenParamInfo { @@ -1715,6 +1707,7 @@ struct CodeGen { //////////////////////////// Runtime State LLVMModuleRef module; ZigList errors; + ErrorMsg *trace_err; LLVMBuilderRef builder; ZigLLVMDIBuilder *dbuilder; ZigLLVMDICompileUnit *compile_unit; @@ -1767,7 +1760,6 @@ struct CodeGen { ZigList resolve_queue; size_t resolve_queue_index; ZigList timing_events; - ZigList tld_ref_source_node_stack; ZigList inline_fns; ZigList test_fns; ZigList errors_by_index; @@ -1852,7 +1844,6 @@ struct CodeGen { ZigFn *main_fn; ZigFn *panic_fn; TldFn *panic_tld_fn; - AstNode *root_export_decl; WantPIC want_pic; WantStackCheck want_stack_check; diff --git a/src/analyze.cpp b/src/analyze.cpp index a06bba3f2a..8fd80d0a08 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -20,7 +20,7 @@ static const size_t default_backward_branch_quota = 1000; -static Error resolve_struct_type(CodeGen *g, ZigType *struct_type); +static Error ATTRIBUTE_MUST_USE resolve_struct_type(CodeGen *g, ZigType *struct_type); static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type); @@ -271,6 +271,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { return type_entry->data.structure.resolve_status >= status; case ZigTypeIdUnion: return type_entry->data.unionation.resolve_status >= status; + case ZigTypeIdEnum: + return type_entry->data.enumeration.resolve_status >= status; case ZigTypeIdFnFrame: switch (status) { case ResolveStatusInvalid: @@ -285,23 +287,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ResolveStatusLLVMFull: return type_entry->llvm_type != nullptr; } - case ZigTypeIdEnum: - switch (status) { - case ResolveStatusUnstarted: - return true; - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusZeroBitsKnown: - return type_entry->data.enumeration.zero_bits_known; - case ResolveStatusAlignmentKnown: - return type_entry->data.enumeration.zero_bits_known; - case ResolveStatusSizeKnown: - return type_entry->data.enumeration.complete; - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - return type_entry->llvm_di_type != nullptr; - } - zig_unreachable(); case ZigTypeIdOpaque: return status < ResolveStatusSizeKnown; case ZigTypeIdMetaType: @@ -865,7 +850,7 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { return table_entry->value; } if (fn_type_id->return_type != nullptr) { - if ((err = ensure_complete_type(g, fn_type_id->return_type))) + if ((err = type_resolve(g, fn_type_id->return_type, ResolveStatusSizeKnown))) return g->builtin_types.entry_invalid; assert(fn_type_id->return_type->id != ZigTypeIdOpaque); } else { @@ -1404,7 +1389,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc add_node_error(g, proto_node, buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); return g->builtin_types.entry_invalid; - //return get_generic_fn_type(g, &fn_type_id); } ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); @@ -1490,7 +1474,7 @@ bool type_is_invalid(ZigType *type_entry) { case ZigTypeIdUnion: return type_entry->data.unionation.resolve_status == ResolveStatusInvalid; case ZigTypeIdEnum: - return type_entry->data.enumeration.is_invalid; + return type_entry->data.enumeration.resolve_status == ResolveStatusInvalid; default: return false; } @@ -1602,9 +1586,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.resolve_loop_flag) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - ErrorMsg *msg = add_node_error(g, decl_node, - buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); - emit_error_notes_for_ref_stack(g, msg); + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("struct '%s' depends on its own size", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -1728,14 +1711,13 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) return ErrorNone; + AstNode *decl_node = union_type->data.structure.decl_node; + if (union_type->data.unionation.resolve_loop_flag) { - if (!union_type->data.unionation.reported_infinite_err) { - AstNode *decl_node = union_type->data.unionation.decl_node; - union_type->data.unionation.reported_infinite_err = true; + if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; - ErrorMsg *msg = add_node_error(g, decl_node, - buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); - emit_error_notes_for_ref_stack(g, msg); + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("union '%s' depends on its own alignment", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -1752,13 +1734,12 @@ 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; - // This is the same hack as resolve_struct_alignment. See the comment there. - } else if (field->type_entry == nullptr) { - this_field_align = g->builtin_types.entry_usize->abi_align; } else { if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -1839,12 +1820,10 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { size_t union_size_in_bits = 0; if (union_type->data.unionation.resolve_loop_flag) { - if (!union_type->data.unionation.reported_infinite_err) { - union_type->data.unionation.reported_infinite_err = true; + if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; - ErrorMsg *msg = add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name))); - emit_error_notes_for_ref_stack(g, msg); + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -1925,24 +1904,25 @@ static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) { static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { assert(enum_type->id == ZigTypeIdEnum); - if (enum_type->data.enumeration.is_invalid) + if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - - if (enum_type->data.enumeration.zero_bits_known) + if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown) return ErrorNone; - if (enum_type->data.enumeration.zero_bits_loop_flag) { - ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node, - buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name))); - emit_error_notes_for_ref_stack(g, msg); - enum_type->data.enumeration.is_invalid = true; + AstNode *decl_node = enum_type->data.enumeration.decl_node; + assert(decl_node->type == NodeTypeContainerDecl); + + if (enum_type->data.enumeration.resolve_loop_flag) { + if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("circular dependency: whether enum '%s' has non-zero size", + buf_ptr(&enum_type->name))); + } return ErrorSemanticAnalyzeFail; } - enum_type->data.enumeration.zero_bits_loop_flag = true; - - AstNode *decl_node = enum_type->data.enumeration.decl_node; - assert(decl_node->type == NodeTypeContainerDecl); + enum_type->data.enumeration.resolve_loop_flag = true; assert(!enum_type->data.enumeration.fields); uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; @@ -1951,9 +1931,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { enum_type->data.enumeration.src_field_count = field_count; enum_type->data.enumeration.fields = nullptr; - enum_type->data.enumeration.is_invalid = true; - enum_type->data.enumeration.zero_bits_loop_flag = false; - enum_type->data.enumeration.zero_bits_known = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } @@ -1982,14 +1960,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (decl_node->data.container_decl.init_arg_expr != nullptr) { ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); if (type_is_invalid(wanted_tag_int_type)) { - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; } else if (wanted_tag_int_type->id != ZigTypeIdInt) { - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node->data.container_decl.init_arg_expr, buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern && !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) { - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, buf_sprintf("'%s' is not a valid tag type for an extern enum", buf_ptr(&wanted_tag_int_type->name))); @@ -2029,7 +2007,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { ErrorMsg *msg = add_node_error(g, field_node, buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name))); add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; continue; } @@ -2039,7 +2017,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { // A user-specified value is available ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); if (type_is_invalid(result->type)) { - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; continue; } @@ -2060,7 +2038,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (!bigint_fits_in_bits(&type_enum_field->value, tag_int_type->size_in_bits, tag_int_type->data.integral.is_signed)) { - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; Buf *val_buf = buf_alloc(); bigint_append_buf(val_buf, &type_enum_field->value, 10); @@ -2075,7 +2053,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { // Make sure the value is unique auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); if (entry != nullptr) { - enum_type->data.enumeration.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; Buf *val_buf = buf_alloc(); bigint_append_buf(val_buf, &type_enum_field->value, 10); @@ -2089,13 +2067,12 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { last_enum_field = type_enum_field; } - enum_type->data.enumeration.zero_bits_loop_flag = false; - enum_type->data.enumeration.zero_bits_known = true; - enum_type->data.enumeration.complete = true; - - if (enum_type->data.enumeration.is_invalid) + if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; + enum_type->data.enumeration.resolve_loop_flag = false; + enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; + return ErrorNone; } @@ -2113,12 +2090,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { assert(decl_node->type == NodeTypeContainerDecl); if (struct_type->data.structure.resolve_loop_flag) { - // TODO This is a problem. I believe it can be solved with lazy values. - struct_type->size_in_bits = SIZE_MAX; - struct_type->abi_size = SIZE_MAX; - struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; - struct_type->data.structure.resolve_loop_flag = false; - return ErrorNone; + if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("circular dependency: whether struct '%s' has non-zero size", + buf_ptr(&struct_type->name))); + } + return ErrorSemanticAnalyzeFail; } struct_type->data.structure.resolve_loop_flag = true; @@ -2237,9 +2215,8 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.resolve_loop_flag) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - ErrorMsg *msg = add_node_error(g, decl_node, - buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); - emit_error_notes_for_ref_stack(g, msg); + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("struct '%s' depends on its own alignment", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -2255,20 +2232,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { if (field->gen_index == SIZE_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; - // TODO If we have no type_entry for the field, we've already failed to - // compile the program correctly. This stage1 compiler needs a deeper - // reworking to make this correct, or we can ignore the problem - // and make sure it is fixed in stage2. This workaround is for when - // there is a false positive of a dependency loop, of alignment depending - // on itself. When this false positive happens we assume a pointer-aligned - // field, which is usually fine but could be incorrectly over-aligned or - // even under-aligned. See https://github.com/ziglang/zig/issues/1512 - } else if (field->type_entry == nullptr) { - this_field_align = g->builtin_types.entry_usize->abi_align; } else { if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; @@ -2304,23 +2273,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) return ErrorNone; + AstNode *decl_node = union_type->data.unionation.decl_node; + assert(decl_node->type == NodeTypeContainerDecl); + if (union_type->data.unionation.resolve_loop_flag) { - // If we get here it's due to recursion. From this we conclude that the struct is - // not zero bits. - // TODO actually it could still be zero bits. Here we should continue analyzing - // the union from the next field index. - union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown; - union_type->data.unionation.resolve_loop_flag = false; - union_type->abi_size = SIZE_MAX; - union_type->size_in_bits = SIZE_MAX; - return ErrorNone; + if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + g->trace_err = add_node_error(g, decl_node, + buf_sprintf("circular dependency: whether union '%s' has non-zero size", + buf_ptr(&union_type->name))); + } + return ErrorSemanticAnalyzeFail; } union_type->data.unionation.resolve_loop_flag = true; - AstNode *decl_node = union_type->data.unionation.decl_node; - assert(decl_node->type == NodeTypeContainerDecl); - assert(union_type->data.unionation.fields == nullptr); uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; if (field_count == 0) { @@ -2380,14 +2347,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { tag_type->size_in_bits = tag_int_type->size_in_bits; tag_type->data.enumeration.tag_int_type = tag_int_type; - tag_type->data.enumeration.zero_bits_known = true; + tag_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; tag_type->data.enumeration.decl_node = decl_node; tag_type->data.enumeration.layout = ContainerLayoutAuto; tag_type->data.enumeration.src_field_count = field_count; tag_type->data.enumeration.fields = allocate(field_count); tag_type->data.enumeration.fields_by_name.init(field_count); tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope; - tag_type->data.enumeration.complete = true; } else if (enum_type_node != nullptr) { ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node); if (type_is_invalid(enum_type)) { @@ -3185,9 +3151,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { ZigType *explicit_type = nullptr; if (var_decl->type) { if (tld_var->analyzing_type) { - ErrorMsg *msg = add_node_error(g, var_decl->type, + g->trace_err = add_node_error(g, var_decl->type, buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name))); - emit_error_notes_for_ref_stack(g, msg); explicit_type = g->builtin_types.entry_invalid; } else { tld_var->analyzing_type = true; @@ -3386,7 +3351,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) { assert(tld->resolution != TldResolutionResolving); tld->resolution = TldResolutionResolving; - g->tld_ref_source_node_stack.append(source_node); switch (tld->id) { case TldIdVar: @@ -3424,7 +3388,10 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) { } tld->resolution = TldResolutionOk; - g->tld_ref_source_node_stack.pop(); + + 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")); + } } Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) { @@ -3550,7 +3517,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag) } TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) { - assert(enum_type->data.enumeration.zero_bits_known); + assert(type_is_resolved(enum_type, ResolveStatusZeroBitsKnown)); for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { TypeEnumField *field = &enum_type->data.enumeration.fields[i]; if (bigint_cmp(&field->value, tag) == CmpEQ) { @@ -3619,43 +3586,6 @@ ZigType *container_ref_type(ZigType *type_entry) { type_entry->data.pointer.child_type : type_entry; } -Error resolve_container_type(CodeGen *g, ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdStruct: - return resolve_struct_type(g, type_entry); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, type_entry); - case ZigTypeIdUnion: - return resolve_union_type(g, type_entry); - case ZigTypeIdPointer: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdInvalid: - case ZigTypeIdArgTuple: - case ZigTypeIdOpaque: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - zig_unreachable(); - } - zig_unreachable(); -} - ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdPointer) return type; if (type->id == ZigTypeIdFn) return type; @@ -3906,7 +3836,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { &fn->analyzed_executable, fn_type_id->return_type, return_type_node); fn->src_implicit_return_type = block_return_type; - if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) { + if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) { assert(g->errors.length > 0); fn->anal_state = FnAnalStateInvalid; return; @@ -3990,7 +3920,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { assert(!fn_type->data.fn.is_generic); ir_gen_fn(g, fn_table_entry); - if (fn_table_entry->ir_executable.invalid) { + if (fn_table_entry->ir_executable.first_err_trace_msg != nullptr) { fn_table_entry->anal_state = FnAnalStateInvalid; return; } @@ -4128,12 +4058,14 @@ void semantic_analyze(CodeGen *g) { { for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { 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); } for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); + g->trace_err = nullptr; analyze_fn_body(g, fn_entry); } } @@ -4145,6 +4077,7 @@ void semantic_analyze(CodeGen *g) { // second pass over functions for detecting async for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { ZigFn *fn = g->fn_defs.at(g->fn_defs_index); + g->trace_err = nullptr; analyze_fn_async(g, fn, true); if (fn_is_async(fn) && fn->non_async_node != nullptr) { ErrorMsg *msg = add_node_error(g, fn->proto_node, @@ -5143,34 +5076,6 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ } -void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { - Error err; - ZigType *wanted_type = const_val->type; - if (wanted_type->id == ZigTypeIdArray) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_array.special = ConstArraySpecialUndef; - } else if (wanted_type->id == ZigTypeIdStruct) { - if ((err = ensure_complete_type(g, wanted_type))) { - return; - } - - const_val->special = ConstValSpecialStatic; - size_t field_count = wanted_type->data.structure.src_field_count; - const_val->data.x_struct.fields = create_const_vals(field_count); - for (size_t i = 0; i < field_count; i += 1) { - ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; - field_val->type = wanted_type->data.structure.fields[i].type_entry; - assert(field_val->type); - init_const_undefined(g, field_val); - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = const_val; - field_val->parent.data.p_struct.field_index = i; - } - } else { - const_val->special = ConstValSpecialUndef; - } -} - ConstExprValue *create_const_vals(size_t count) { ConstGlobalRefs *global_refs = allocate(count); ConstExprValue *vals = allocate(count); @@ -5180,10 +5085,6 @@ ConstExprValue *create_const_vals(size_t count) { return vals; } -Error ensure_complete_type(CodeGen *g, ZigType *type_entry) { - return type_resolve(g, type_entry, ResolveStatusSizeKnown); -} - static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) return orig_fn_type; @@ -5197,27 +5098,6 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { return fn_type; } -static void emit_error_notes_for_type_loop(CodeGen *g, ErrorMsg *msg, ZigType *stop_type, - ZigType *ty, AstNode *src_node) -{ - ErrorMsg *note = add_error_note(g, msg, src_node, - buf_sprintf("when analyzing type '%s' here", buf_ptr(&ty->name))); - if (ty == stop_type) - return; - switch (ty->id) { - case ZigTypeIdFnFrame: { - ty->data.frame.reported_loop_err = true; - ZigType *depending_type = ty->data.frame.resolve_loop_type; - if (depending_type == nullptr) - return; - emit_error_notes_for_type_loop(g, note, stop_type, - depending_type, ty->data.frame.resolve_loop_src_node); - } - default: - return; - } -} - static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { Error err; @@ -5230,13 +5110,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { if (frame_type->data.frame.resolve_loop_type != nullptr) { if (!frame_type->data.frame.reported_loop_err) { frame_type->data.frame.reported_loop_err = true; - ErrorMsg *msg = add_node_error(g, fn->proto_node, + g->trace_err = add_node_error(g, fn->proto_node, buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name))); - emit_error_notes_for_type_loop(g, msg, - frame_type, - frame_type->data.frame.resolve_loop_type, - frame_type->data.frame.resolve_loop_src_node); - emit_error_notes_for_ref_stack(g, msg); } return ErrorSemanticAnalyzeFail; } @@ -5252,11 +5127,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { return ErrorSemanticAnalyzeFail; break; case FnAnalStateProbing: { - ErrorMsg *msg = add_node_error(g, fn->proto_node, + g->trace_err = add_node_error(g, fn->proto_node, buf_sprintf("cannot resolve '%s': function not fully analyzed yet", buf_ptr(&frame_type->name))); - ir_add_analysis_trace(fn->ir_executable.analysis, msg, - buf_sprintf("depends on its own frame here")); return ErrorSemanticAnalyzeFail; } } @@ -5327,10 +5200,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { if (callee->anal_state == FnAnalStateProbing) { ErrorMsg *msg = add_node_error(g, fn->proto_node, buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name))); - ErrorMsg *note = add_error_note(g, msg, call->base.source_node, + g->trace_err = add_error_note(g, msg, call->base.source_node, buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name))); - ir_add_analysis_trace(callee->ir_executable.analysis, note, - buf_sprintf("depends on the frame here")); return ErrorSemanticAnalyzeFail; } @@ -6229,6 +6100,40 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { zig_unreachable(); } +static void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { + Error err; + ZigType *wanted_type = const_val->type; + if (wanted_type->id == ZigTypeIdArray) { + const_val->special = ConstValSpecialStatic; + const_val->data.x_array.special = ConstArraySpecialUndef; + } else if (wanted_type->id == ZigTypeIdStruct) { + if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { + return; + } + + const_val->special = ConstValSpecialStatic; + size_t field_count = wanted_type->data.structure.src_field_count; + const_val->data.x_struct.fields = create_const_vals(field_count); + for (size_t i = 0; i < field_count; i += 1) { + ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; + field_val->type = wanted_type->data.structure.fields[i].type_entry; + assert(field_val->type); + init_const_undefined(g, field_val); + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = const_val; + field_val->parent.data.p_struct.field_index = i; + } + } else { + const_val->special = ConstValSpecialUndef; + } +} + +void expand_undef_struct(CodeGen *g, ConstExprValue *const_val) { + if (const_val->special == ConstValSpecialUndef) { + init_const_undefined(g, const_val); + } +} + // Canonicalize the array value as ConstArraySpecialNone void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { size_t elem_count; @@ -6707,19 +6612,6 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) { return false; } -void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg) { - size_t i = g->tld_ref_source_node_stack.length; - for (;;) { - if (i == 0) - break; - i -= 1; - AstNode *source_node = g->tld_ref_source_node_stack.at(i); - if (source_node) { - msg = add_error_note(g, msg, source_node, buf_sprintf("referenced here")); - } - } -} - Buf *type_bare_name(ZigType *type_entry) { if (is_slice(type_entry)) { return &type_entry->name; @@ -7122,10 +7014,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; } -static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { - assert(!enum_type->data.enumeration.is_invalid); - assert(enum_type->data.enumeration.complete); - if (enum_type->llvm_di_type != nullptr) return; +static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) { + assert(enum_type->data.enumeration.resolve_status >= ResolveStatusSizeKnown); + if (enum_type->data.enumeration.resolve_status >= wanted_resolve_status) return; Scope *scope = &enum_type->data.enumeration.decls_scope->base; ZigType *import = get_scope_import(scope); @@ -7146,6 +7037,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { debug_align_in_bits, ZigLLVM_DIFlags_Zero, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); + enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; return; } @@ -7178,6 +7070,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { get_llvm_di_type(g, tag_int_type), ""); enum_type->llvm_di_type = tag_di_type; + enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; } static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { @@ -7909,7 +7802,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r else return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr); case ZigTypeIdEnum: - return resolve_llvm_types_enum(g, type); + return resolve_llvm_types_enum(g, type, wanted_resolve_status); case ZigTypeIdUnion: return resolve_llvm_types_union(g, type, wanted_resolve_status); case ZigTypeIdPointer: diff --git a/src/analyze.hpp b/src/analyze.hpp index 5752c74751..5613c18231 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -14,7 +14,6 @@ void semantic_analyze(CodeGen *g); ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg); ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg); ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); -void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg); ZigType *new_type_table_entry(ZigTypeId id); ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); @@ -71,7 +70,6 @@ bool type_is_complete(ZigType *type_entry); bool type_is_resolved(ZigType *type_entry, ResolveStatus status); bool type_is_invalid(ZigType *type_entry); bool type_is_global_error_set(ZigType *err_set_type); -Error resolve_container_type(CodeGen *g, ZigType *type_entry); ScopeDecls *get_container_scope(ZigType *type_entry); TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name); TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name); @@ -95,7 +93,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node); ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc); AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); -Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry); Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); void complete_enum(CodeGen *g, ZigType *enum_type); bool ir_get_var_is_comptime(ZigVar *var); @@ -169,12 +166,11 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end); ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); -void init_const_undefined(CodeGen *g, ConstExprValue *const_val); - ConstExprValue *create_const_vals(size_t count); ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); void expand_undef_array(CodeGen *g, ConstExprValue *const_val); +void expand_undef_struct(CodeGen *g, ConstExprValue *const_val); void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); const char *type_id_name(ZigTypeId id); diff --git a/src/ir.cpp b/src/ir.cpp index cdddce1b18..aa5b69649d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -234,6 +234,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c } case ConstPtrSpecialBaseStruct: { ConstExprValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; + expand_undef_struct(g, struct_val); result = &struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index]; break; } @@ -8111,7 +8112,9 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc ir_build_reset_result(irb, scope, node, result_loc); } IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); - irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); + if (result == irb->codegen->invalid_instruction) { + src_assert(irb->exec->first_err_trace_msg != nullptr, node); + } return result; } @@ -8119,21 +8122,20 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); } -static void invalidate_exec(IrExecutable *exec) { - if (exec->invalid) +static void invalidate_exec(IrExecutable *exec, ErrorMsg *msg) { + if (exec->first_err_trace_msg != nullptr) return; - exec->invalid = true; + exec->first_err_trace_msg = msg; for (size_t i = 0; i < exec->tld_list.length; i += 1) { exec->tld_list.items[i]->resolution = TldResolutionInvalid; } if (exec->source_exec != nullptr) - invalidate_exec(exec->source_exec); + invalidate_exec(exec->source_exec, msg); } - bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { assert(node->owner); @@ -8151,8 +8153,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); assert(result); - if (irb->exec->invalid) + if (irb->exec->first_err_trace_msg != nullptr) { + codegen->trace_err = irb->exec->first_err_trace_msg; return false; + } if (!instr_is_unreachable(result)) { ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result)); @@ -8174,25 +8178,9 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable); } -static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) { - if (!exec || !exec->source_node || limit < 0) return; - add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); - - ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1); -} - -void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text) { - IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); - add_error_note(ira->codegen, err_msg, old_instruction->source_node, text); - ir_add_call_stack_errors(ira->codegen, ira->new_irb.exec, err_msg, 10); -} - static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { - invalidate_exec(exec); ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); - if (exec->parent_exec) { - ir_add_call_stack_errors(codegen, exec, err_msg, 10); - } + invalidate_exec(exec, err_msg); return err_msg; } @@ -10634,7 +10622,7 @@ static void ir_finish_bb(IrAnalyze *ira) { static IrInstruction *ir_unreach_error(IrAnalyze *ira) { ira->old_bb_index = SIZE_MAX; - ira->new_irb.exec->invalid = true; + assert(ira->new_irb.exec->first_err_trace_msg != nullptr); return ira->codegen->unreach_instruction; } @@ -10761,8 +10749,11 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod ir_executable->begin_scope = scope; ir_gen(codegen, node, scope, ir_executable); - if (ir_executable->invalid) + if (ir_executable->first_err_trace_msg != nullptr) { + codegen->trace_err = add_error_note(codegen, ir_executable->first_err_trace_msg, + source_node, buf_create_from_str("called from here")); return &codegen->invalid_instruction->value; + } if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); @@ -10783,8 +10774,9 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod analyzed_executable->backward_branch_quota = backward_branch_quota; analyzed_executable->begin_scope = scope; ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node); - if (type_is_invalid(result_type)) + if (type_is_invalid(result_type)) { return &codegen->invalid_instruction->value; + } if (codegen->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); @@ -11322,7 +11314,7 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc IrInstruction *target, ZigType *wanted_type) { IrInstruction *result = ir_const(ira, source_instr, wanted_type); - init_const_undefined(ira->codegen, &result->value); + result->value.special = ConstValSpecialUndef; return result; } @@ -11461,7 +11453,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour ZigType *actual_type = target->value.type; - if ((err = ensure_complete_type(ira->codegen, wanted_type))) + if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; if (actual_type != wanted_type->data.enumeration.tag_int_type) { @@ -12719,7 +12711,9 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio if (type_is_invalid(operand->value.type)) return ir_unreach_error(ira); - if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) { + if (!instr_is_comptime(operand) && ira->explicit_return_type != nullptr && + handle_is_ptr(ira->explicit_return_type)) + { // result location mechanism took care of it. IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, instruction->base.source_node, nullptr); @@ -15513,8 +15507,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c ira->codegen->memoized_fn_eval_table.put(exec_scope, result); } - if (type_is_invalid(result->type)) + if (type_is_invalid(result->type)) { return ira->codegen->invalid_instruction; + } } IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); @@ -16727,7 +16722,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; bool safety_check_on = elem_ptr_instruction->safety_check_on; - if ((err = ensure_complete_type(ira->codegen, return_type->data.pointer.child_type))) + if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); @@ -17113,7 +17108,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ Error err; ZigType *bare_type = container_ref_type(container_type); - if ((err = ensure_complete_type(ira->codegen, bare_type))) + if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); @@ -17243,15 +17238,15 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, } static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { - ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); - emit_error_notes_for_ref_stack(ira->codegen, msg); + ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); return ira->codegen->invalid_instruction; } static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node); - if (tld->resolution == TldResolutionInvalid) + if (tld->resolution == TldResolutionInvalid) { return ira->codegen->invalid_instruction; + } switch (tld->id) { case TldIdContainer: @@ -17396,7 +17391,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; } else if (is_container(child_type)) { if (child_type->id == ZigTypeIdEnum) { - if ((err = ensure_complete_type(ira->codegen, child_type))) + if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; TypeEnumField *field = find_enum_type_field(child_type, field_name); @@ -17425,7 +17420,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || child_type->data.unionation.decl_node->data.container_decl.auto_enum)) { - if ((err = ensure_complete_type(ira->codegen, child_type))) + if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; TypeUnionField *field = find_union_type_field(child_type, field_name); if (field) { @@ -18008,7 +18003,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, case ZigTypeIdFnFrame: case ZigTypeIdAnyFrame: { - if ((err = ensure_complete_type(ira->codegen, child_type))) + if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; ZigType *result_type = get_array_type(ira->codegen, child_type, size); return ir_const_type(ira, &array_type_instruction->base, result_type); @@ -18024,7 +18019,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstruction *type_value = size_of_instruction->type_value->child; ZigType *type_entry = ir_resolve_type(ira, type_value); - if ((err = ensure_complete_type(ira->codegen, type_entry))) + if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; switch (type_entry->id) { @@ -18529,7 +18524,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, if (pointee_val->special == ConstValSpecialRuntime) pointee_val = nullptr; } - if ((err = ensure_complete_type(ira->codegen, target_type))) + if ((err = type_resolve(ira->codegen, target_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; switch (target_type->id) { @@ -19276,8 +19271,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, if (!msg_buf) return ira->codegen->invalid_instruction; - ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf); - emit_error_notes_for_ref_stack(ira->codegen, msg); + ir_add_error(ira, &instruction->base, msg_buf); return ira->codegen->invalid_instruction; } @@ -19391,7 +19385,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; TypeStructField *field = find_struct_type_field(container_type, field_name); @@ -19470,7 +19464,7 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, return nullptr; Error err; - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return nullptr; Buf *field_name = ir_resolve_str(ira, field_name_value); @@ -19574,7 +19568,7 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig ZigVar *var = tld->var; - if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) + if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown))) return ira->codegen->builtin_types.entry_invalid; assert(var->const_value->type->id == ZigTypeIdMetaType); @@ -19594,15 +19588,15 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr ensure_field_index(type_info_declaration_type, "data", 2); ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type); - if ((err = ensure_complete_type(ira->codegen, type_info_declaration_data_type))) + if ((err = type_resolve(ira->codegen, type_info_declaration_data_type, ResolveStatusSizeKnown))) return err; ZigType *type_info_fn_decl_type = ir_type_info_get_type(ira, "FnDecl", type_info_declaration_data_type); - if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_type))) + if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown))) return err; ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type); - if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_inline_type))) + if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown))) return err; // Loop through our declarations once to figure out how many declarations we will generate info for. @@ -19673,7 +19667,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr case TldIdVar: { ZigVar *var = ((TldVar *)curr_entry->value)->var; - if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) + if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; if (var->const_value->type->id == ZigTypeIdMetaType) { @@ -19799,7 +19793,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr case TldIdContainer: { ZigType *type_entry = ((TldContainer *)curr_entry->value)->type_entry; - if ((err = ensure_complete_type(ira->codegen, type_entry))) + if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; // This is a type. @@ -19855,7 +19849,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty return nullptr; ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); - assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_type)); + assertNoError(type_resolve(ira->codegen, type_info_pointer_type, ResolveStatusSizeKnown)); ConstExprValue *result = create_const_vals(1); result->special = ConstValSpecialStatic; @@ -19867,7 +19861,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty // size: Size ensure_field_index(result->type, "size", 0); ZigType *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); - assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_size_type)); + assertNoError(type_resolve(ira->codegen, type_info_pointer_size_type, ResolveStatusSizeKnown)); fields[0].special = ConstValSpecialStatic; fields[0].type = type_info_pointer_size_type; bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index); @@ -22021,7 +22015,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst return ira->codegen->invalid_instruction; ZigType *container_type = ir_resolve_type(ira, container); - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; uint64_t result; @@ -22057,7 +22051,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; @@ -22100,7 +22094,7 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; uint64_t member_index; @@ -23309,8 +23303,10 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExp } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { - if (val->special == ConstValSpecialUndef) + if (val->special == ConstValSpecialUndef) { + expand_undef_struct(codegen, val); val->special = ConstValSpecialStatic; + } assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: @@ -23746,8 +23742,9 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstructionDeclRef *instruction) { IrInstruction *ref_instruction = ir_analyze_decl_ref(ira, &instruction->base, instruction->tld); - if (type_is_invalid(ref_instruction->value.type)) + if (type_is_invalid(ref_instruction->value.type)) { return ira->codegen->invalid_instruction; + } if (instruction->lval == LValPtr) { return ref_instruction; @@ -23954,7 +23951,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if (enum_type->id == ZigTypeIdEnum) { - if ((err = ensure_complete_type(ira->codegen, enum_type))) + if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type); @@ -25100,7 +25097,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, ZigType *expected_type, AstNode *expected_type_source_node) { - assert(!old_exec->invalid); + assert(old_exec->first_err_trace_msg == nullptr); assert(expected_type == nullptr || !type_is_invalid(expected_type)); IrAnalyze *ira = allocate(1); @@ -25147,6 +25144,15 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ old_instruction->child = new_instruction; if (type_is_invalid(new_instruction->value.type)) { + if (new_exec->first_err_trace_msg != nullptr) { + ira->codegen->trace_err = new_exec->first_err_trace_msg; + } else { + new_exec->first_err_trace_msg = ira->codegen->trace_err; + } + if (new_exec->first_err_trace_msg != nullptr) { + new_exec->first_err_trace_msg = add_error_note(ira->codegen, new_exec->first_err_trace_msg, + old_instruction->source_node, buf_create_from_str("referenced here")); + } return ira->codegen->builtin_types.entry_invalid; } @@ -25158,7 +25164,12 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ ira->instruction_index += 1; } - if (new_exec->invalid) { + if (new_exec->first_err_trace_msg != nullptr) { + codegen->trace_err = new_exec->first_err_trace_msg; + if (codegen->trace_err != nullptr) { + codegen->trace_err = add_error_note(codegen, codegen->trace_err, + new_exec->source_node, buf_create_from_str("referenced here")); + } return ira->codegen->builtin_types.entry_invalid; } else if (ira->src_implicit_return_type_list.length == 0) { return codegen->builtin_types.entry_unreachable; diff --git a/src/ir.hpp b/src/ir.hpp index 3761c5a97d..597624e2e6 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -28,6 +28,4 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal AstNode *source_node); const char *float_op_to_name(BuiltinFnId op, bool llvm_name); -void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text); - #endif -- cgit v1.2.3 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 --- BRANCH_TODO | 3 + src/all_types.hpp | 61 +++++++++-- src/analyze.cpp | 56 ++++++---- src/analyze.hpp | 4 +- src/codegen.cpp | 9 +- src/ir.cpp | 319 +++++++++++++++++++++++++++++++++++++----------------- src/ir.hpp | 4 +- 7 files changed, 320 insertions(+), 136 deletions(-) create mode 100644 BRANCH_TODO (limited to 'src') diff --git a/BRANCH_TODO b/BRANCH_TODO new file mode 100644 index 0000000000..9df8ba2ca7 --- /dev/null +++ b/BRANCH_TODO @@ -0,0 +1,3 @@ +* slice type and ptr type instructions need to implicit cast alignment +* fix regressions of error notes with "called from here" +* fix tests diff --git a/src/all_types.hpp b/src/all_types.hpp index c5a30b75cc..de82159d27 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -47,6 +47,12 @@ struct ResultLocPeer; struct ResultLocPeerParent; struct ResultLocBitCast; +enum PtrLen { + PtrLenUnknown, + PtrLenSingle, + PtrLenC, +}; + enum X64CABIClass { X64CABIClass_Unknown, X64CABIClass_MEMORY, @@ -255,6 +261,7 @@ enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, ConstValSpecialUndef, + ConstValSpecialLazy, }; enum RuntimeHintErrorUnion { @@ -291,6 +298,44 @@ struct ConstGlobalRefs { uint32_t align; }; +enum LazyValueId { + LazyValueIdInvalid, + LazyValueIdAlignOf, + LazyValueIdPtrType, + LazyValueIdSliceType, +}; + +struct LazyValue { + LazyValueId id; + IrExecutable *exec; +}; + +struct LazyValueAlignOf { + LazyValue base; + ZigType *target_type; +}; + +struct LazyValueSliceType { + LazyValue base; + ZigType *elem_type; + ConstExprValue *align_val; // can be null + bool is_const; + bool is_volatile; + bool is_allowzero; +}; + +struct LazyValuePtrType { + LazyValue base; + ZigType *elem_type; + ConstExprValue *align_val; // can be null + PtrLen ptr_len; + uint32_t bit_offset_in_host; + uint32_t host_int_bytes; + bool is_const; + bool is_volatile; + bool is_allowzero; +}; + struct ConstExprValue { ZigType *type; ConstValSpecial special; @@ -318,6 +363,7 @@ struct ConstExprValue { ConstPtrValue x_ptr; ConstArgTuple x_arg_tuple; Buf *x_enum_literal; + LazyValue *x_lazy; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -1039,12 +1085,6 @@ struct FnTypeId { uint32_t fn_type_id_hash(FnTypeId*); bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); -enum PtrLen { - PtrLenUnknown, - PtrLenSingle, - PtrLenC, -}; - struct ZigTypePointer { ZigType *child_type; ZigType *slice_parent; @@ -1073,7 +1113,8 @@ struct ZigTypeArray { struct TypeStructField { Buf *name; - ZigType *type_entry; + ZigType *type_entry; // available after ResolveStatusSizeKnown + ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown size_t src_index; size_t gen_index; size_t offset; // byte offset from beginning of struct @@ -1931,7 +1972,7 @@ struct CodeGen { Buf *zig_lib_dir; Buf *zig_std_dir; Buf *dynamic_linker_path; - Buf *version_script_path; + Buf *version_script_path; const char **llvm_argv; size_t llvm_argv_len; @@ -3648,13 +3689,13 @@ enum ResultLocId { ResultLocIdBitCast, }; -// Additions to this struct may need to be handled in +// Additions to this struct may need to be handled in // ir_reset_result struct ResultLoc { ResultLocId id; bool written; bool allow_write_through_const; - IrInstruction *resolved_loc; // result ptr + IrInstruction *resolved_loc; // result ptr IrInstruction *source_instruction; IrInstruction *gen_instruction; // value to store to the result loc ZigType *implicit_elem_type; diff --git a/src/analyze.cpp b/src/analyze.cpp index 8fd80d0a08..0a5de5fd36 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -445,8 +445,6 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons } } - assert(type_is_resolved(child_type, ResolveStatusZeroBitsKnown)); - ZigType *entry = new_type_table_entry(ZigTypeIdPointer); const char *star_str = ptr_len_to_star_str(ptr_len); @@ -476,8 +474,6 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons buf_ptr(&child_type->name)); } - assert(child_type->id != ZigTypeIdInvalid); - if (type_has_bits(child_type)) { entry->abi_size = g->builtin_types.entry_usize->abi_size; entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; @@ -689,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)) { + switch (type_requires_comptime(g, ptr_type, entry)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeNo: @@ -945,12 +941,18 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind return entry; } -ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { +ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name, bool allow_lazy) +{ size_t backward_branch_count = 0; size_t backward_branch_quota = default_backward_branch_quota; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, &backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr, nullptr); + nullptr, nullptr, node, type_name, nullptr, nullptr, allow_lazy); +} + +ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { + return analyze_const_value_allow_lazy(g, scope, node, type_entry, type_name, false); } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { @@ -1355,7 +1357,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)) { + switch (type_requires_comptime(g, type_entry, fn_entry->type_entry)) { case ReqCompTimeNo: break; case ReqCompTimeYes: @@ -1451,7 +1453,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)) { + switch (type_requires_comptime(g, fn_type_id.return_type, fn_entry->type_entry)) { case ReqCompTimeInvalid: return g->builtin_types.entry_invalid; case ReqCompTimeYes: @@ -2164,7 +2166,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - switch (type_requires_comptime(g, field_type)) { + switch (type_requires_comptime(g, field_type, struct_type)) { case ReqCompTimeYes: struct_type->data.structure.requires_comptime = true; break; @@ -2422,7 +2424,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } - switch (type_requires_comptime(g, field_type)) { + switch (type_requires_comptime(g, field_type, union_type)) { case ReqCompTimeInvalid: union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; @@ -4754,11 +4756,12 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { zig_unreachable(); } -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty, ZigType *parent_type) { Error err; - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return ReqCompTimeInvalid; - switch (type_entry->id) { + if (ty == parent_type) { + return ReqCompTimeNo; + } + switch (ty->id) { case ZigTypeIdInvalid: case ZigTypeIdOpaque: zig_unreachable(); @@ -4772,23 +4775,27 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArgTuple: return ReqCompTimeYes; case ZigTypeIdArray: - return type_requires_comptime(g, type_entry->data.array.child_type); + return type_requires_comptime(g, ty->data.array.child_type, parent_type); case ZigTypeIdStruct: - return type_entry->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; + if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) + return ReqCompTimeInvalid; + return ty->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdUnion: - return type_entry->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; + if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) + return ReqCompTimeInvalid; + return ty->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdOptional: - return type_requires_comptime(g, type_entry->data.maybe.child_type); + return type_requires_comptime(g, ty->data.maybe.child_type, parent_type); case ZigTypeIdErrorUnion: - return type_requires_comptime(g, type_entry->data.error_union.payload_type); + return type_requires_comptime(g, ty->data.error_union.payload_type, parent_type); case ZigTypeIdPointer: - if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { + if (ty->data.pointer.child_type->id == ZigTypeIdOpaque) { return ReqCompTimeNo; } else { - return type_requires_comptime(g, type_entry->data.pointer.child_type); + return type_requires_comptime(g, ty->data.pointer.child_type, parent_type); } case ZigTypeIdFn: - return type_entry->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; + return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdEnum: case ZigTypeIdErrorSet: case ZigTypeIdBool: @@ -5726,6 +5733,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ConstValSpecialRuntime: buf_appendf(buf, "(runtime value)"); return; + case ConstValSpecialLazy: + buf_appendf(buf, "(lazy value)"); + return; case ConstValSpecialUndef: buf_appendf(buf, "undefined"); return; diff --git a/src/analyze.hpp b/src/analyze.hpp index 5613c18231..d62d176cc5 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); +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry, ZigType *parent_type); OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); @@ -241,6 +241,8 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); +ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name, bool allow_lazy); void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); bool fn_is_async(ZigFn *fn); 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: diff --git a/src/ir.cpp b/src/ir.cpp index aa5b69649d..9c9a28ee56 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -155,6 +155,7 @@ struct ConstCastBadAllowsZero { enum UndefAllowed { UndefOk, UndefBad, + LazyOk, }; static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); @@ -403,7 +404,7 @@ static void ir_ref_var(ZigVar *var) { ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { ConstExprValue *result = ir_eval_const_value(ira->codegen, scope, node, ira->codegen->builtin_types.entry_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, - node, nullptr, ira->new_irb.exec, nullptr); + node, nullptr, ira->new_irb.exec, nullptr, false); if (type_is_invalid(result->type)) return ira->codegen->builtin_types.entry_invalid; @@ -10710,32 +10711,57 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio return const_instr; } +static Error ir_resolve_const_val(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, + ConstExprValue *val, UndefAllowed undef_allowed) +{ + Error err; + for (;;) { + switch (val->special) { + case ConstValSpecialStatic: + return ErrorNone; + case ConstValSpecialRuntime: + if (!type_has_bits(val->type)) + return ErrorNone; + + exec_add_error_node(codegen, exec, source_node, + buf_sprintf("unable to evaluate constant expression")); + return ErrorSemanticAnalyzeFail; + case ConstValSpecialUndef: + if (undef_allowed == UndefOk) + return ErrorNone; + + exec_add_error_node(codegen, exec, source_node, + buf_sprintf("use of undefined value here causes undefined behavior")); + return ErrorSemanticAnalyzeFail; + case ConstValSpecialLazy: + if (undef_allowed == LazyOk) + return ErrorNone; + + if ((err = ir_resolve_lazy(codegen, source_node, val))) + return err; + + continue; + } + } +} + static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) { - switch (value->value.special) { - case ConstValSpecialStatic: - return &value->value; - case ConstValSpecialRuntime: - if (!type_has_bits(value->value.type)) { - return &value->value; - } - ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression")); - return nullptr; - case ConstValSpecialUndef: - if (undef_allowed == UndefOk) { - return &value->value; - } else { - ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior")); - return nullptr; - } + Error err; + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node, + &value->value, undef_allowed))) + { + return nullptr; } - zig_unreachable(); + return &value->value; } ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec, AstNode *expected_type_source_node) + IrExecutable *parent_exec, AstNode *expected_type_source_node, bool allow_lazy) { + Error err; + if (expected_type != nullptr && type_is_invalid(expected_type)) return &codegen->invalid_instruction->value; @@ -10784,7 +10810,14 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod fprintf(stderr, "}\n"); } - return ir_exec_const_result(codegen, analyzed_executable); + ConstExprValue *result = ir_exec_const_result(codegen, analyzed_executable); + + if (!allow_lazy) { + if ((err = ir_resolve_lazy(codegen, node, result))) + return &codegen->invalid_instruction->value; + } + + return result; } static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_value) { @@ -10805,6 +10838,17 @@ static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_valu return const_val->data.x_err_set; } +static ZigType *ir_resolve_const_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, + ConstExprValue *val) +{ + Error err; + if ((err = ir_resolve_const_val(codegen, exec, source_node, val, UndefBad))) + return codegen->builtin_types.entry_invalid; + + assert(val->data.x_type != nullptr); + return val->data.x_type; +} + static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { if (type_is_invalid(type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -10815,12 +10859,7 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { return ira->codegen->builtin_types.entry_invalid; } - ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad); - if (!const_val) - return ira->codegen->builtin_types.entry_invalid; - - assert(const_val->data.x_type != nullptr); - return const_val->data.x_type; + return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, &type_value->value); } static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { @@ -12500,26 +12539,22 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst); } -static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) { - if (type_is_invalid(value->value.type)) - return false; - - IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); - if (type_is_invalid(casted_value->value.type)) - return false; - - ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) +static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, + ConstExprValue *const_val, uint32_t *out) +{ + Error err; + if ((err = ir_resolve_const_val(codegen, exec, source_node, const_val, UndefBad))) return false; uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint); if (align_bytes == 0) { - ir_add_error(ira, value, buf_sprintf("alignment must be >= 1")); + exec_add_error_node(codegen, exec, source_node, buf_sprintf("alignment must be >= 1")); return false; } if (!is_power_of_2(align_bytes)) { - ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); + exec_add_error_node(codegen, exec, source_node, + buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); return false; } @@ -12527,6 +12562,18 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out return true; } +static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) { + if (type_is_invalid(value->value.type)) + return false; + + IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); + if (type_is_invalid(casted_value->value.type)) + return false; + + return ir_resolve_const_align(ira->codegen, ira->new_irb.exec, value->source_node, + &casted_value->value, out); +} + static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *int_type, uint64_t *out) { if (type_is_invalid(value->value.type)) return false; @@ -14151,7 +14198,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } } - switch (type_requires_comptime(ira->codegen, result_type)) { + switch (type_requires_comptime(ira->codegen, result_type, nullptr)) { case ReqCompTimeInvalid: result_type = ira->codegen->builtin_types.entry_invalid; break; @@ -15113,7 +15160,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)) { + switch (type_requires_comptime(ira->codegen, casted_arg->value.type, nullptr)) { case ReqCompTimeYes: ir_add_error(ira, casted_arg, buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name))); @@ -15192,6 +15239,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, case ConstValSpecialRuntime: goto no_mem_slot; case ConstValSpecialStatic: // fallthrough + case ConstValSpecialLazy: // fallthrough case ConstValSpecialUndef: { ConstPtrMut ptr_mut; if (comptime_var_mem) { @@ -15313,7 +15361,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source } } - switch (type_requires_comptime(ira->codegen, child_type)) { + switch (type_requires_comptime(ira->codegen, child_type, nullptr)) { case ReqCompTimeInvalid: return ira->codegen->invalid_instruction; case ReqCompTimeYes: @@ -15483,7 +15531,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c AstNode *body_node = fn_entry->body_node; result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, - nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node); + nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node, false); if (inferred_err_set_type != nullptr) { inferred_err_set_type->data.error_set.infer_fn = nullptr; @@ -15680,7 +15728,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, - nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); + nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, + nullptr, false); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); copy_const_val(&const_instruction->base.value, align_result, true); @@ -15705,7 +15754,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)) { + switch (type_requires_comptime(ira->codegen, specified_return_type, nullptr)) { 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, @@ -16512,7 +16561,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh break; } - switch (type_requires_comptime(ira->codegen, resolved_type)) { + switch (type_requires_comptime(ira->codegen, resolved_type, nullptr)) { case ReqCompTimeInvalid: return ira->codegen->invalid_instruction; case ReqCompTimeYes: @@ -16960,7 +17009,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } } else { // runtime known element index - switch (type_requires_comptime(ira->codegen, return_type)) { + switch (type_requires_comptime(ira->codegen, return_type, nullptr)) { case ReqCompTimeYes: ir_add_error(ira, elem_index, buf_sprintf("values of type '%s' must be comptime known, but index value is runtime known", @@ -17839,22 +17888,29 @@ static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, IrInstructionSliceType *slice_type_instruction) { - Error err; - uint32_t align_bytes = 0; + IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type); + result->value.special = ConstValSpecialLazy; + + LazyValueSliceType *lazy_slice_type = allocate(1); + result->value.data.x_lazy = &lazy_slice_type->base; + lazy_slice_type->base.id = LazyValueIdSliceType; + lazy_slice_type->base.exec = ira->new_irb.exec; + if (slice_type_instruction->align_value != nullptr) { - if (!ir_resolve_align(ira, slice_type_instruction->align_value->child, &align_bytes)) + lazy_slice_type->align_val = ir_resolve_const(ira, slice_type_instruction->align_value->child, LazyOk); + if (lazy_slice_type->align_val == nullptr) return ira->codegen->invalid_instruction; } - ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); - if (type_is_invalid(child_type)) + lazy_slice_type->elem_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); + if (type_is_invalid(lazy_slice_type->elem_type)) return ira->codegen->invalid_instruction; - bool is_const = slice_type_instruction->is_const; - bool is_volatile = slice_type_instruction->is_volatile; - bool is_allow_zero = slice_type_instruction->is_allow_zero; + lazy_slice_type->is_const = slice_type_instruction->is_const; + lazy_slice_type->is_volatile = slice_type_instruction->is_volatile; + lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero; - switch (child_type->id) { + switch (lazy_slice_type->elem_type->id) { case ZigTypeIdInvalid: // handled above zig_unreachable(); case ZigTypeIdUnreachable: @@ -17863,7 +17919,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdArgTuple: case ZigTypeIdOpaque: ir_add_error_node(ira, slice_type_instruction->base.source_node, - buf_sprintf("slice of type '%s' not allowed", buf_ptr(&child_type->name))); + buf_sprintf("slice of type '%s' not allowed", buf_ptr(&lazy_slice_type->elem_type->name))); return ira->codegen->invalid_instruction; case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -17886,18 +17942,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdVector: case ZigTypeIdFnFrame: case ZigTypeIdAnyFrame: - { - ResolveStatus needed_status = (align_bytes == 0) ? - ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; - if ((err = type_resolve(ira->codegen, child_type, needed_status))) - return ira->codegen->invalid_instruction; - ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, - is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero); - ZigType *result_type = get_slice_type(ira->codegen, slice_ptr_type); - return ir_const_type(ira, &slice_type_instruction->base, result_type); - } + break; } - zig_unreachable(); + return result; } static IrInstruction *ir_analyze_instruction_global_asm(IrAnalyze *ira, IrInstructionGlobalAsm *instruction) { @@ -18947,7 +18994,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) == ReqCompTimeYes; + || type_requires_comptime(ira->codegen, union_type, nullptr) == ReqCompTimeYes; IrInstruction *result = ir_get_deref(ira, source_instruction, result_loc, nullptr); if (is_comptime && !instr_is_comptime(result)) { @@ -18995,7 +19042,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) == ReqCompTimeYes; + || type_requires_comptime(ira->codegen, container_type, nullptr) == ReqCompTimeYes; // Here we iterate over the fields that have been initialized, and emit @@ -19173,7 +19220,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, } bool is_comptime; - switch (type_requires_comptime(ira->codegen, container_type)) { + switch (type_requires_comptime(ira->codegen, container_type, nullptr)) { case ReqCompTimeInvalid: return ira->codegen->invalid_instruction; case ReqCompTimeNo: @@ -20575,7 +20622,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct ZigType *void_type = ira->codegen->builtin_types.entry_void; ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node, nullptr, nullptr, nullptr); + &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, false); if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; @@ -22243,15 +22290,11 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { - Error err; IrInstruction *type_value = instruction->type_value->child; if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; ZigType *type_entry = ir_resolve_type(ira, type_value); - if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); @@ -22284,12 +22327,27 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct case ZigTypeIdVector: case ZigTypeIdFnFrame: case ZigTypeIdAnyFrame: - { - uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); - return ir_const_unsigned(ira, &instruction->base, align_in_bytes); - } + break; } - zig_unreachable(); + + if (type_is_resolved(type_entry, ResolveStatusAlignmentKnown)) { + uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); + return ir_const_unsigned(ira, &instruction->base, align_in_bytes); + } + + // Here we create a lazy value in order to avoid resolving the alignment of the type + // immediately. This avoids false positive dependency loops such as: + // const Node = struct { + // field: []align(@alignOf(Node)) Node, + // }; + LazyValueAlignOf *lazy_align_of = allocate(1); + lazy_align_of->base.id = LazyValueIdAlignOf; + lazy_align_of->base.exec = ira->new_irb.exec; + lazy_align_of->target_type = type_entry; + IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); + result->value.special = ConstValSpecialLazy; + result->value.data.x_lazy = &lazy_align_of->base; + return result; } static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) { @@ -22783,7 +22841,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; ZigType *param_type = ir_resolve_type(ira, param_type_value); - switch (type_requires_comptime(ira->codegen, param_type)) { + switch (type_requires_comptime(ira->codegen, param_type, nullptr)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { ir_add_error(ira, param_type_value, @@ -23792,10 +23850,18 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { - Error err; + IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); + result->value.special = ConstValSpecialLazy; + + LazyValuePtrType *lazy_ptr_type = allocate(1); + result->value.data.x_lazy = &lazy_ptr_type->base; + lazy_ptr_type->base.id = LazyValueIdPtrType; + lazy_ptr_type->base.exec = ira->new_irb.exec; + ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; + lazy_ptr_type->elem_type = child_type; if (child_type->id == ZigTypeIdUnreachable) { ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); @@ -23817,28 +23883,20 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct } } - uint32_t align_bytes; if (instruction->align_value != nullptr) { - if (!ir_resolve_align(ira, instruction->align_value->child, &align_bytes)) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - if (!type_has_bits(child_type)) { - align_bytes = 0; - } - } else { - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) + lazy_ptr_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk); + if (lazy_ptr_type->align_val == nullptr) return ira->codegen->invalid_instruction; - align_bytes = 0; } - bool allow_zero = instruction->is_allow_zero || instruction->ptr_len == PtrLenC; + lazy_ptr_type->ptr_len = instruction->ptr_len; + lazy_ptr_type->is_const = instruction->is_const; + lazy_ptr_type->is_volatile = instruction->is_volatile; + lazy_ptr_type->is_allowzero = instruction->is_allow_zero; + lazy_ptr_type->bit_offset_in_host = instruction->bit_offset_start; + lazy_ptr_type->host_int_bytes = instruction->host_int_bytes; - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, - instruction->is_const, instruction->is_volatile, - instruction->ptr_len, align_bytes, - instruction->bit_offset_start, instruction->host_int_bytes, allow_zero); - return ir_const_type(ira, &instruction->base, result_type); + return result; } static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) { @@ -25365,3 +25423,66 @@ bool ir_has_side_effects(IrInstruction *instruction) { } zig_unreachable(); } + +Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { + Error err; + if (val->special != ConstValSpecialLazy) + return ErrorNone; + IrExecutable *exec = val->data.x_lazy->exec; + switch (val->data.x_lazy->id) { + case LazyValueIdInvalid: + zig_unreachable(); + case LazyValueIdAlignOf: { + LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); + if ((err = type_resolve(codegen, lazy_align_of->target_type, ResolveStatusAlignmentKnown))) + return err; + uint64_t align_in_bytes = get_abi_alignment(codegen, lazy_align_of->target_type); + val->special = ConstValSpecialStatic; + assert(val->type->id == ZigTypeIdComptimeInt); + bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); + return ErrorNone; + } + case LazyValueIdSliceType: { + LazyValueSliceType *lazy_slice_type = reinterpret_cast(val->data.x_lazy); + uint32_t align_bytes = 0; + if (lazy_slice_type->align_val != nullptr) { + if (!ir_resolve_const_align(codegen, exec, source_node, lazy_slice_type->align_val, &align_bytes)) + return ErrorSemanticAnalyzeFail; + } + ResolveStatus needed_status = (align_bytes == 0) ? + ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; + if ((err = type_resolve(codegen, lazy_slice_type->elem_type, needed_status))) + return err; + ZigType *slice_ptr_type = get_pointer_to_type_extra(codegen, lazy_slice_type->elem_type, + lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes, + 0, 0, lazy_slice_type->is_allowzero); + val->special = ConstValSpecialStatic; + assert(val->type->id == ZigTypeIdMetaType); + val->data.x_type = get_slice_type(codegen, slice_ptr_type); + return ErrorNone; + } + case LazyValueIdPtrType: { + LazyValuePtrType *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); + uint32_t align_bytes = 0; + if (lazy_ptr_type->align_val != nullptr) { + if (!ir_resolve_const_align(codegen, exec, source_node, lazy_ptr_type->align_val, &align_bytes)) + return ErrorSemanticAnalyzeFail; + } + ResolveStatus needed_status = (align_bytes == 0) ? + ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; + if ((err = type_resolve(codegen, lazy_ptr_type->elem_type, needed_status))) + return err; + if (!type_has_bits(lazy_ptr_type->elem_type)) + align_bytes = 0; + bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; + assert(val->type->id == ZigTypeIdMetaType); + val->data.x_type = get_pointer_to_type_extra(codegen, lazy_ptr_type->elem_type, + lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, + lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, + allow_zero); + val->special = ConstValSpecialStatic; + return ErrorNone; + } + } + zig_unreachable(); +} diff --git a/src/ir.hpp b/src/ir.hpp index 597624e2e6..200a92b64f 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -16,7 +16,9 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec, AstNode *expected_type_source_node); + IrExecutable *parent_exec, AstNode *expected_type_source_node, bool allow_lazy); + +Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val); ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, ZigType *expected_type, AstNode *expected_type_source_node); -- cgit v1.2.3 From 0d6a6c76eabcd020c5f58dc4667766b0e2756dfa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 12:55:09 -0400 Subject: add missing "referenced here" notes for lazy values --- src/analyze.cpp | 6 +++--- src/ir.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 0a5de5fd36..ee67f259f0 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1918,7 +1918,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, - buf_sprintf("circular dependency: whether enum '%s' has non-zero size", + buf_sprintf("dependency loop: whether enum '%s' has non-zero size", buf_ptr(&enum_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2095,7 +2095,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, - buf_sprintf("circular dependency: whether struct '%s' has non-zero size", + buf_sprintf("dependency loop: whether struct '%s' has non-zero size", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2282,7 +2282,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, - buf_sprintf("circular dependency: whether union '%s' has non-zero size", + buf_sprintf("dependency loop: whether union '%s' has non-zero size", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; diff --git a/src/ir.cpp b/src/ir.cpp index 9c9a28ee56..e64098be01 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10813,8 +10813,13 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod ConstExprValue *result = ir_exec_const_result(codegen, analyzed_executable); if (!allow_lazy) { - if ((err = ir_resolve_lazy(codegen, node, result))) + if ((err = ir_resolve_lazy(codegen, node, result))) { + if (codegen->trace_err != nullptr) { + codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, + buf_create_from_str("referenced here")); + } return &codegen->invalid_instruction->value; + } } return result; -- cgit v1.2.3 From 26b79ac90ee8cf17f28b0584c773be759e0e49bd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 14:46:26 -0400 Subject: simple self-referential struct is working now --- src/analyze.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++++--------- src/ir.cpp | 18 +++-- 2 files changed, 182 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index ee67f259f0..a4ee17d56c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -955,6 +955,126 @@ ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, Zig return analyze_const_value_allow_lazy(g, scope, node, type_entry, type_name, false); } +static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, + bool *is_zero_bits) +{ + Error err; + if (type_val->special != ConstValSpecialLazy) { + assert(type_val->special == ConstValSpecialStatic); + if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown))) + return err; + *is_zero_bits = (type_val->data.x_type->abi_size == 0); + return ErrorNone; + } + switch (type_val->data.x_lazy->id) { + case LazyValueIdInvalid: + case LazyValueIdAlignOf: + zig_unreachable(); + case LazyValueIdPtrType: { + LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); + if (lazy_ptr_type->elem_type == parent_type) { + // Does a struct which contains a pointer field to itself have bits? Yes. + *is_zero_bits = false; + return ErrorNone; + } else { + if ((err = type_resolve(g, lazy_ptr_type->elem_type, ResolveStatusZeroBitsKnown))) + return err; + *is_zero_bits = type_has_bits(lazy_ptr_type->elem_type); + return ErrorNone; + } + } + case LazyValueIdSliceType: + *is_zero_bits = false; + return ErrorNone; + } + zig_unreachable(); +} + +static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) { + if (type_val->special != ConstValSpecialLazy) { + assert(type_val->special == ConstValSpecialStatic); + *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque); + return ErrorNone; + } + switch (type_val->data.x_lazy->id) { + case LazyValueIdInvalid: + case LazyValueIdAlignOf: + zig_unreachable(); + case LazyValueIdSliceType: + case LazyValueIdPtrType: + *is_opaque_type = false; + return ErrorNone; + } + zig_unreachable(); +} + +static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type) { + if (type_val->special != ConstValSpecialLazy) { + return type_requires_comptime(g, type_val->data.x_type, parent_type); + } + switch (type_val->data.x_lazy->id) { + case LazyValueIdInvalid: + case LazyValueIdAlignOf: + zig_unreachable(); + case LazyValueIdSliceType: { + LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); + return type_requires_comptime(g, lazy_slice_type->elem_type, parent_type); + } + case LazyValueIdPtrType: { + LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); + return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type); + } + } + zig_unreachable(); +} + +static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, size_t *abi_align) { + Error err; + if (type_val->special != ConstValSpecialLazy) { + assert(type_val->special == ConstValSpecialStatic); + if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusAlignmentKnown))) + return err; + *abi_align = type_val->data.x_type->abi_align; + return ErrorNone; + } + switch (type_val->data.x_lazy->id) { + case LazyValueIdInvalid: + case LazyValueIdAlignOf: + zig_unreachable(); + case LazyValueIdSliceType: + case LazyValueIdPtrType: + *abi_align = g->builtin_types.entry_usize->abi_align; + return ErrorNone; + } + zig_unreachable(); +} + +static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ConstExprValue *type_val) { + if (type_val->special != ConstValSpecialLazy) { + return type_has_one_possible_value(g, type_val->data.x_type); + } + switch (type_val->data.x_lazy->id) { + case LazyValueIdInvalid: + case LazyValueIdAlignOf: + zig_unreachable(); + case LazyValueIdSliceType: + return OnePossibleValueNo; // it has the len field + case LazyValueIdPtrType: { + Error err; + bool zero_bits; + if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, &zero_bits))) { + return OnePossibleValueInvalid; + } + if (zero_bits) { + return OnePossibleValueYes; + } else { + return OnePossibleValueNo; + } + } + } + zig_unreachable(); +} + ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); if (type_is_invalid(result->type)) @@ -1604,14 +1724,38 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { uint32_t *host_int_bytes = packed ? allocate(struct_type->data.structure.gen_field_count) : nullptr; - // Resolve sizes of all the field types. Done before the offset loop because the offset - // loop has to look ahead. + // Resolve types for fields and then resolve sizes of all the field types. + // This is done before the offset loop because the offset loop has to look ahead. for (size_t i = 0; i < field_count; i += 1) { + AstNode *field_source_node = decl_node->data.container_decl.fields.at(i); TypeStructField *field = &struct_type->data.structure.fields[i]; + + if ((err = ir_resolve_lazy(g, field_source_node, field->type_val))) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return err; + } + field->type_entry = field->type_val->data.x_type; + if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return err; + } + + if (struct_type->data.structure.layout == ContainerLayoutExtern && + !type_allowed_in_extern(g, field->type_entry)) + { + add_node_error(g, field_source_node, + buf_sprintf("extern structs cannot contain fields of type '%s'", + buf_ptr(&field->type_entry->name))); + struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; + } else if (packed) { + if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field_source_node))) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return err; + } } + } size_t packed_bits_offset = 0; @@ -2133,40 +2277,33 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - ZigType *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); - type_struct_field->type_entry = field_type; - if (type_is_invalid(field_type)) { + 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)) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } + assert(field_type_val->special != ConstValSpecialRuntime); + type_struct_field->type_val = field_type_val; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.layout == ContainerLayoutExtern && - !type_allowed_in_extern(g, field_type)) - { - add_node_error(g, field_node, - buf_sprintf("extern structs cannot contain fields of type '%s'", - buf_ptr(&field_type->name))); + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; - } else if (struct_type->data.structure.layout == ContainerLayoutPacked) { - if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_node))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } } - - type_struct_field->src_index = i; - type_struct_field->gen_index = SIZE_MAX; - - if (field_type->id == ZigTypeIdOpaque) { + if (field_is_opaque_type) { add_node_error(g, field_node->data.struct_field.type, buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - switch (type_requires_comptime(g, field_type, 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)) { case ReqCompTimeYes: struct_type->data.structure.requires_comptime = true; break; @@ -2177,7 +2314,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { break; } - if (!type_has_bits(field_type)) + bool field_is_zero_bits; + if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, &field_is_zero_bits))) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + if (field_is_zero_bits) continue; type_struct_field->gen_index = gen_field_index; @@ -2234,21 +2376,17 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { if (field->gen_index == SIZE_MAX) continue; - src_assert(field->type_entry != nullptr, decl_node); - + // TODO: https://github.com/ziglang/zig/issues/1512 size_t this_field_align; if (packed) { - // TODO: https://github.com/ziglang/zig/issues/1512 this_field_align = 1; } else { - if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { + if ((err = type_val_resolve_abi_align(g, field->type_val, &this_field_align))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; + return err; } - this_field_align = field->type_entry->abi_align; } - // TODO: https://github.com/ziglang/zig/issues/1512 if (this_field_align > struct_type->abi_align) { struct_type->abi_align = this_field_align; } @@ -4725,7 +4863,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdStruct: for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { TypeStructField *field = &type_entry->data.structure.fields[i]; - switch (type_has_one_possible_value(g, field->type_entry)) { + switch (type_val_resolve_has_one_possible_value(g, field->type_val)) { case OnePossibleValueInvalid: return OnePossibleValueInvalid; case OnePossibleValueNo: diff --git a/src/ir.cpp b/src/ir.cpp index e64098be01..92b8598442 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10814,10 +10814,6 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod if (!allow_lazy) { if ((err = ir_resolve_lazy(codegen, node, result))) { - if (codegen->trace_err != nullptr) { - codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, - buf_create_from_str("referenced here")); - } return &codegen->invalid_instruction->value; } } @@ -25429,7 +25425,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { zig_unreachable(); } -Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { +static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { Error err; if (val->special != ConstValSpecialLazy) return ErrorNone; @@ -25491,3 +25487,15 @@ Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *va } zig_unreachable(); } + +Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { + Error err; + if ((err = ir_resolve_lazy_raw(codegen, source_node, val))) { + if (codegen->trace_err != nullptr) { + codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, + buf_create_from_str("referenced here")); + } + return err; + } + return ErrorNone; +} -- cgit v1.2.3 From 79a4b7a2365dc50d01eb6bc29bbb77244a1620cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 18:24:15 -0400 Subject: fix regressions --- src/analyze.cpp | 19 ++- src/ir.cpp | 409 +++++++++++++++++++++++++++++++++----------------------- 2 files changed, 254 insertions(+), 174 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index a4ee17d56c..414ce09b2c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1018,10 +1018,14 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue zig_unreachable(); case LazyValueIdSliceType: { 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); } case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); + if (type_is_invalid(lazy_ptr_type->elem_type)) + return ReqCompTimeInvalid; return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type); } } @@ -2239,7 +2243,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, - buf_sprintf("dependency loop: whether struct '%s' has non-zero size", + buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2308,6 +2312,10 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { struct_type->data.structure.requires_comptime = true; break; 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")); + } struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; case ReqCompTimeNo: @@ -2770,6 +2778,8 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : proto_node->data.fn_proto.fn_def_node->data.fn_def.body; + fn_entry->analyzed_executable.source_node = fn_entry->body_node; + return fn_entry; } @@ -4863,7 +4873,10 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdStruct: for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { TypeStructField *field = &type_entry->data.structure.fields[i]; - switch (type_val_resolve_has_one_possible_value(g, field->type_val)) { + OnePossibleValue opv = (field->type_entry != nullptr) ? + type_has_one_possible_value(g, field->type_entry) : + type_val_resolve_has_one_possible_value(g, field->type_val); + switch (opv) { case OnePossibleValueInvalid: return OnePossibleValueInvalid; case OnePossibleValueNo: @@ -4901,7 +4914,6 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty, ZigType *parent_type } switch (ty->id) { case ZigTypeIdInvalid: - case ZigTypeIdOpaque: zig_unreachable(); case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -4934,6 +4946,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty, ZigType *parent_type } case ZigTypeIdFn: return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; + case ZigTypeIdOpaque: case ZigTypeIdEnum: case ZigTypeIdErrorSet: case ZigTypeIdBool: diff --git a/src/ir.cpp b/src/ir.cpp index 92b8598442..c545109d24 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11058,14 +11058,21 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou } static IrInstruction *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *wanted_type) + IrInstruction *frame_ptr, ZigType *wanted_type) { - if (instr_is_comptime(value)) { - zig_panic("TODO comptime frame pointer"); + if (instr_is_comptime(frame_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, frame_ptr, UndefBad); + if (ptr_val == nullptr) + return ira->codegen->invalid_instruction; + + ir_assert(ptr_val->type->id == ZigTypeIdPointer, source_instr); + if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { + zig_panic("TODO comptime frame pointer"); + } } IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, - wanted_type, value, CastOpBitCast); + wanted_type, frame_ptr, CastOpBitCast); result->value.type = wanted_type; return result; } @@ -13618,21 +13625,34 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp if (type_is_invalid(casted_op2->value.type)) return ira->codegen->invalid_instruction; - if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) { - IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); - result->value.special = ConstValSpecialUndef; - return result; + // If either operand is undef, result is undef. + ConstExprValue *op1_val = nullptr; + ConstExprValue *op2_val = nullptr; + if (instr_is_comptime(op1)) { + op1_val = ir_resolve_const(ira, op1, UndefOk); + if (op1_val == nullptr) + return ira->codegen->invalid_instruction; + if (op1_val->special == ConstValSpecialUndef) + return ir_const_undef(ira, &instruction->base, op1->value.type); } - if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic && + if (instr_is_comptime(casted_op2)) { + op2_val = ir_resolve_const(ira, casted_op2, UndefOk); + if (op2_val == nullptr) + return ira->codegen->invalid_instruction; + if (op2_val->special == ConstValSpecialUndef) + return ir_const_undef(ira, &instruction->base, op1->value.type); + } + + if (op2_val != nullptr && op1_val != nullptr && (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || op1->value.data.x_ptr.special == ConstPtrSpecialNull)) { - uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ? - 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr; + uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? + 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; uint64_t elem_offset; if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) return ira->codegen->invalid_instruction; - ZigType *elem_type = op1->value.type->data.pointer.child_type; + ZigType *elem_type = op1_val->type->data.pointer.child_type; if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; @@ -13644,7 +13664,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp } else { zig_unreachable(); } - IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); + IrInstruction *result = ir_const(ira, &instruction->base, op1_val->type); result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr; @@ -14213,9 +14233,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } break; case ReqCompTimeNo: - if (init_val != nullptr) { - if (init_val->special == ConstValSpecialStatic && - init_val->type->id == ZigTypeIdFn && + if (init_val != nullptr && value_is_comptime(init_val)) { + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, + decl_var_instruction->base.source_node, init_val, UndefOk))) + { + result_type = ira->codegen->builtin_types.entry_invalid; + } else if (init_val->type->id == ZigTypeIdFn && + init_val->special != ConstValSpecialUndef && init_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) { @@ -14273,7 +14297,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } } - if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) { + if (init_val != nullptr && value_is_comptime(init_val)) { // Resolve ConstPtrMutInfer if (var->gen_is_const) { var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst; @@ -14292,7 +14316,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref, false); } - if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) { + if (instr_is_comptime(var_ptr) && var->mem_slot_index != SIZE_MAX) { assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); @@ -15222,7 +15246,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, if (linkage_makes_it_runtime) goto no_mem_slot; - if (var->const_value->special == ConstValSpecialStatic) { + 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)) { @@ -19361,7 +19385,10 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, true, false, PtrLenUnknown, 0, 0, 0, false); ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); - if (casted_value->value.special == ConstValSpecialStatic) { + if (instr_is_comptime(casted_value)) { + ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_instruction; ErrorTableEntry *err = casted_value->value.data.x_err_set; if (!err->cached_error_name_val) { ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); @@ -21524,64 +21551,75 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio return ira->codegen->invalid_instruction; // TODO test this at comptime with u8 and non-u8 types - if (casted_dest_ptr->value.special == ConstValSpecialStatic && - casted_byte->value.special == ConstValSpecialStatic && - casted_count->value.special == ConstValSpecialStatic && - casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + if (instr_is_comptime(casted_dest_ptr) && + instr_is_comptime(casted_byte) && + instr_is_comptime(casted_count)) { - ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; + ConstExprValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); + if (dest_ptr_val == nullptr) + return ira->codegen->invalid_instruction; - ConstExprValue *dest_elements; - size_t start; - size_t bound_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - start = 0; - bound_end = 1; - break; - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - bound_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memset on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memset on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memset on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memset on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memset on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memset on null ptr"); - } + ConstExprValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); + if (byte_val == nullptr) + return ira->codegen->invalid_instruction; - size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); - size_t end = start + count; - if (end > bound_end) { - ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); + ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); + if (count_val == nullptr) return ira->codegen->invalid_instruction; - } - ConstExprValue *byte_val = &casted_byte->value; - for (size_t i = start; i < end; i += 1) { - copy_const_val(&dest_elements[i], byte_val, true); - } + if (casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && + casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + { + ConstExprValue *dest_elements; + size_t start; + size_t bound_end; + switch (dest_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; + start = 0; + bound_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(ira->codegen, array_val); + dest_elements = array_val->data.x_array.data.s_none.elements; + start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; + bound_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memset on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memset on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memset on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memset on const inner optional payload"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + case ConstPtrSpecialFunction: + zig_panic("TODO memset on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memset on null ptr"); + } - return ir_const_void(ira, &instruction->base); + size_t count = bigint_as_unsigned(&count_val->data.x_bigint); + size_t end = start + count; + if (end > bound_end) { + ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } + + for (size_t i = start; i < end; i += 1) { + copy_const_val(&dest_elements[i], byte_val, true); + } + + return ir_const_void(ira, &instruction->base); + } } IrInstruction *result = ir_build_memset(&ira->new_irb, instruction->base.scope, instruction->base.source_node, @@ -21649,107 +21687,118 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio // TODO test this at comptime with u8 and non-u8 types // TODO test with dest ptr being a global runtime variable - if (casted_dest_ptr->value.special == ConstValSpecialStatic && - casted_src_ptr->value.special == ConstValSpecialStatic && - casted_count->value.special == ConstValSpecialStatic && - casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) + if (instr_is_comptime(casted_dest_ptr) && + instr_is_comptime(casted_src_ptr) && + instr_is_comptime(casted_count)) { - size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); + ConstExprValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); + if (dest_ptr_val == nullptr) + return ira->codegen->invalid_instruction; - ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; - ConstExprValue *dest_elements; - size_t dest_start; - size_t dest_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - dest_start = 0; - dest_end = 1; - break; - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - dest_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } + ConstExprValue *src_ptr_val = ir_resolve_const(ira, casted_src_ptr, UndefBad); + if (src_ptr_val == nullptr) + return ira->codegen->invalid_instruction; - if (dest_start + count > dest_end) { - ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); + if (count_val == nullptr) return ira->codegen->invalid_instruction; - } - ConstExprValue *src_ptr_val = &casted_src_ptr->value; - ConstExprValue *src_elements; - size_t src_start; - size_t src_end; + if (dest_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + size_t count = bigint_as_unsigned(&count_val->data.x_bigint); - switch (src_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; - src_start = 0; - src_end = 1; - break; - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - src_elements = array_val->data.x_array.data.s_none.elements; - src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; - src_end = array_val->type->data.array.len; + ConstExprValue *dest_elements; + size_t dest_start; + size_t dest_end; + switch (dest_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; + dest_start = 0; + dest_end = 1; break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(ira->codegen, array_val); + dest_elements = array_val->data.x_array.data.s_none.elements; + dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; + dest_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + case ConstPtrSpecialFunction: + zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); + } - if (src_start + count > src_end) { - ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_instruction; - } + if (dest_start + count > dest_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } - // TODO check for noalias violations - this should be generalized to work for any function + ConstExprValue *src_elements; + size_t src_start; + size_t src_end; - for (size_t i = 0; i < count; i += 1) { - copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); - } + switch (src_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; + src_start = 0; + src_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(ira->codegen, array_val); + src_elements = array_val->data.x_array.data.s_none.elements; + src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; + src_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + case ConstPtrSpecialFunction: + zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); + } - return ir_const_void(ira, &instruction->base); + if (src_start + count > src_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } + + // TODO check for noalias violations - this should be generalized to work for any function + + for (size_t i = 0; i < count; i += 1) { + copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); + } + + return ir_const_void(ira, &instruction->base); + } } IrInstruction *result = ir_build_memcpy(&ira->new_irb, instruction->base.scope, instruction->base.source_node, @@ -22412,13 +22461,26 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr if (type_is_invalid(casted_result_ptr->value.type)) return ira->codegen->invalid_instruction; - if (casted_op1->value.special == ConstValSpecialStatic && - casted_op2->value.special == ConstValSpecialStatic && - casted_result_ptr->value.special == ConstValSpecialStatic) + if (instr_is_comptime(casted_op1) && + instr_is_comptime(casted_op2) && + instr_is_comptime(casted_result_ptr)) { - BigInt *op1_bigint = &casted_op1->value.data.x_bigint; - BigInt *op2_bigint = &casted_op2->value.data.x_bigint; - ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, &casted_result_ptr->value, casted_result_ptr->source_node); + ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); + if (op1_val == nullptr) + return ira->codegen->invalid_instruction; + + ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); + if (op2_val == nullptr) + return ira->codegen->invalid_instruction; + + ConstExprValue *result_val = ir_resolve_const(ira, casted_result_ptr, UndefBad); + if (result_val == nullptr) + return ira->codegen->invalid_instruction; + + BigInt *op1_bigint = &op1_val->data.x_bigint; + BigInt *op2_bigint = &op2_val->data.x_bigint; + ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, result_val, + casted_result_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; BigInt *dest_bigint = &pointee_val->data.x_bigint; @@ -22839,9 +22901,9 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); } else { IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; - if (type_is_invalid(param_type_value->value.type)) - return ira->codegen->invalid_instruction; ZigType *param_type = ir_resolve_type(ira, param_type_value); + if (type_is_invalid(param_type)) + return ira->codegen->invalid_instruction; switch (type_requires_comptime(ira->codegen, param_type, nullptr)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { @@ -23271,7 +23333,12 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ if (!val) return ira->codegen->invalid_instruction; - if (val->special == ConstValSpecialStatic) { + if (value_is_comptime(val)) { + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, + source_instr->source_node, val, UndefBad))) + { + return ira->codegen->invalid_instruction; + } bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && val->data.x_ptr.data.hard_coded_addr.addr == 0); -- cgit v1.2.3 From 20049caaba0354754811ae0d36a773c31cf4578a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 13:28:26 -0400 Subject: add lazy value for fn prototypes this case now works: ```zig const Node = struct { field: fn (*Node) *Node, }; ``` --- src/all_types.hpp | 25 ++++++-- src/analyze.cpp | 46 +++++++++++++-- src/analyze.hpp | 2 + src/ir.cpp | 173 +++++++++++++++++++++++++++++++++++++----------------- 4 files changed, 183 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 3e811311b0..595df7460f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -303,11 +303,12 @@ enum LazyValueId { LazyValueIdAlignOf, LazyValueIdPtrType, LazyValueIdSliceType, + LazyValueIdFnType, }; struct LazyValue { - LazyValueId id; IrExecutable *exec; + LazyValueId id; }; struct LazyValueAlignOf { @@ -317,23 +318,35 @@ struct LazyValueAlignOf { struct LazyValueSliceType { LazyValue base; - ZigType *elem_type; - ConstExprValue *align_val; // can be null bool is_const; bool is_volatile; bool is_allowzero; + + ZigType *elem_type; + ConstExprValue *align_val; // can be null }; struct LazyValuePtrType { LazyValue base; + bool is_const; + bool is_volatile; + bool is_allowzero; + ZigType *elem_type; ConstExprValue *align_val; // can be null PtrLen ptr_len; uint32_t bit_offset_in_host; uint32_t host_int_bytes; - bool is_const; - bool is_volatile; - bool is_allowzero; +}; + +struct LazyValueFnType { + LazyValue base; + bool is_generic; + + AstNode *proto_node; + ConstExprValue **param_types; + ConstExprValue *align_val; // can be null + ConstExprValue *return_type; }; struct ConstExprValue { diff --git a/src/analyze.cpp b/src/analyze.cpp index 84299a5c8b..c08f954e18 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -986,11 +986,16 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi case LazyValueIdSliceType: *is_zero_bits = false; return ErrorNone; + case LazyValueIdFnType: { + LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); + *is_zero_bits = lazy_fn_type->is_generic; + return ErrorNone; + } } zig_unreachable(); } -static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) { +Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) { if (type_val->special != ConstValSpecialLazy) { assert(type_val->special == ConstValSpecialStatic); *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque); @@ -1002,6 +1007,7 @@ static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_va zig_unreachable(); case LazyValueIdSliceType: case LazyValueIdPtrType: + case LazyValueIdFnType: *is_opaque_type = false; return ErrorNone; } @@ -1028,6 +1034,34 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue return ReqCompTimeInvalid; return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type); } + 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)) { + case ReqCompTimeInvalid: + return ReqCompTimeInvalid; + case ReqCompTimeYes: + return ReqCompTimeYes; + case ReqCompTimeNo: + break; + } + size_t param_count = lazy_fn_type->proto_node->data.fn_proto.params.length; + for (size_t i = 0; i < param_count; i += 1) { + 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)) { + case ReqCompTimeInvalid: + return ReqCompTimeInvalid; + case ReqCompTimeYes: + return ReqCompTimeYes; + case ReqCompTimeNo: + break; + } + } + return ReqCompTimeNo; + } } zig_unreachable(); } @@ -1047,6 +1081,7 @@ static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, si zig_unreachable(); case LazyValueIdSliceType: case LazyValueIdPtrType: + case LazyValueIdFnType: *abi_align = g->builtin_types.entry_usize->abi_align; return ErrorNone; } @@ -1061,8 +1096,9 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons case LazyValueIdInvalid: case LazyValueIdAlignOf: zig_unreachable(); - case LazyValueIdSliceType: - return OnePossibleValueNo; // it has the len field + case LazyValueIdSliceType: // it has the len field + case LazyValueIdFnType: + return OnePossibleValueNo; case LazyValueIdPtrType: { Error err; bool zero_bits; @@ -2395,10 +2431,12 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } else if (packed) { field->align = 1; } else { - if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) { + size_t result_abi_align; + if ((err = type_val_resolve_abi_align(g, field->type_val, &result_abi_align))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return err; } + field->align = result_abi_align; } if (field->align > struct_type->abi_align) { diff --git a/src/analyze.hpp b/src/analyze.hpp index d62d176cc5..740b47ac1d 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -247,4 +247,6 @@ ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); bool fn_is_async(ZigFn *fn); +Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type); + #endif diff --git a/src/ir.cpp b/src/ir.cpp index 789126cf67..2970f536b9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -22869,84 +22869,65 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct AstNode *proto_node = instruction->base.source_node; assert(proto_node->type == NodeTypeFnProto); + IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); + result->value.special = ConstValSpecialLazy; + + LazyValueFnType *lazy_fn_type = allocate(1); + result->value.data.x_lazy = &lazy_fn_type->base; + lazy_fn_type->base.id = LazyValueIdFnType; + lazy_fn_type->base.exec = ira->new_irb.exec; + if (proto_node->data.fn_proto.auto_err_set) { ir_add_error(ira, &instruction->base, buf_sprintf("inferring error set of return type valid only for function definitions")); return ira->codegen->invalid_instruction; } - FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); + size_t param_count = proto_node->data.fn_proto.params.length; + lazy_fn_type->proto_node = proto_node; + lazy_fn_type->param_types = allocate(param_count); - for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); + for (size_t param_index = 0; param_index < param_count; param_index += 1) { + AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); assert(param_node->type == NodeTypeParamDecl); bool param_is_var_args = param_node->data.param_decl.is_var_args; if (param_is_var_args) { - if (fn_type_id.cc == CallingConventionC) { - fn_type_id.param_count = fn_type_id.next_param_index; - continue; - } else if (fn_type_id.cc == CallingConventionUnspecified) { - return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); + if (proto_node->data.fn_proto.cc == CallingConventionC) { + break; + } else if (proto_node->data.fn_proto.cc == CallingConventionUnspecified) { + lazy_fn_type->is_generic = true; + return result; } else { zig_unreachable(); } } - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - if (instruction->param_types[fn_type_id.next_param_index] == nullptr) { - param_info->type = nullptr; - return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); - } else { - IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; - ZigType *param_type = ir_resolve_type(ira, param_type_value); - if (type_is_invalid(param_type)) - return ira->codegen->invalid_instruction; - switch (type_requires_comptime(ira->codegen, param_type, nullptr)) { - case ReqCompTimeYes: - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - ir_add_error(ira, param_type_value, - buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return ira->codegen->invalid_instruction; - } - param_info->type = param_type; - fn_type_id.next_param_index += 1; - return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); - case ReqCompTimeInvalid: - return ira->codegen->invalid_instruction; - case ReqCompTimeNo: - break; - } - if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) { - ir_add_error(ira, param_type_value, - buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return ira->codegen->invalid_instruction; - } - param_info->type = param_type; + if (instruction->param_types[param_index] == nullptr) { + lazy_fn_type->is_generic = true; + return result; } + IrInstruction *param_type_value = instruction->param_types[param_index]->child; + if (type_is_invalid(param_type_value->value.type)) + return ira->codegen->invalid_instruction; + ConstExprValue *param_type_val = ir_resolve_const(ira, param_type_value, LazyOk); + if (param_type_val == nullptr) + return ira->codegen->invalid_instruction; + lazy_fn_type->param_types[param_index] = param_type_val; } if (instruction->align_value != nullptr) { - if (!ir_resolve_align(ira, instruction->align_value->child, &fn_type_id.alignment)) + lazy_fn_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk); + if (lazy_fn_type->align_val == nullptr) return ira->codegen->invalid_instruction; } - IrInstruction *return_type_value = instruction->return_type->child; - fn_type_id.return_type = ir_resolve_type(ira, return_type_value); - if (type_is_invalid(fn_type_id.return_type)) - return ira->codegen->invalid_instruction; - if (fn_type_id.return_type->id == ZigTypeIdOpaque) { - ir_add_error(ira, instruction->return_type, - buf_sprintf("return type cannot be opaque")); - return ira->codegen->invalid_instruction; - } + lazy_fn_type->return_type = ir_resolve_const(ira, instruction->return_type->child, LazyOk); + if (lazy_fn_type->return_type == nullptr) + return ira->codegen->invalid_instruction; - return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id)); + return result; } static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) { @@ -25492,6 +25473,82 @@ bool ir_has_side_effects(IrInstruction *instruction) { zig_unreachable(); } +static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, + LazyValueFnType *lazy_fn_type) +{ + AstNode *proto_node = lazy_fn_type->proto_node; + + FnTypeId fn_type_id = {0}; + init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); + + for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { + AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); + assert(param_node->type == NodeTypeParamDecl); + + bool param_is_var_args = param_node->data.param_decl.is_var_args; + if (param_is_var_args) { + if (fn_type_id.cc == CallingConventionC) { + fn_type_id.param_count = fn_type_id.next_param_index; + continue; + } else if (fn_type_id.cc == CallingConventionUnspecified) { + return get_generic_fn_type(codegen, &fn_type_id); + } else { + zig_unreachable(); + } + } + FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; + param_info->is_noalias = param_node->data.param_decl.is_noalias; + + if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) { + param_info->type = nullptr; + return get_generic_fn_type(codegen, &fn_type_id); + } else { + ZigType *param_type = ir_resolve_const_type(codegen, exec, source_node, + 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)) { + case ReqCompTimeYes: + if (!calling_convention_allows_zig_types(fn_type_id.cc)) { + exec_add_error_node(codegen, exec, source_node, + buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", + buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); + return nullptr; + } + param_info->type = param_type; + fn_type_id.next_param_index += 1; + return get_generic_fn_type(codegen, &fn_type_id); + case ReqCompTimeInvalid: + return nullptr; + case ReqCompTimeNo: + break; + } + if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) { + exec_add_error_node(codegen, exec, source_node, + buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", + buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); + return nullptr; + } + param_info->type = param_type; + } + } + + if (lazy_fn_type->align_val != nullptr) { + if (!ir_resolve_const_align(codegen, exec, source_node, lazy_fn_type->align_val, &fn_type_id.alignment)) + return nullptr; + } + + fn_type_id.return_type = ir_resolve_const_type(codegen, exec, source_node, lazy_fn_type->return_type); + if (type_is_invalid(fn_type_id.return_type)) + return nullptr; + if (fn_type_id.return_type->id == ZigTypeIdOpaque) { + exec_add_error_node(codegen, exec, source_node, buf_create_from_str("return type cannot be opaque")); + return nullptr; + } + + return get_fn_type(codegen, &fn_type_id); +} + static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { Error err; if (val->special != ConstValSpecialLazy) @@ -25551,6 +25608,16 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx val->special = ConstValSpecialStatic; return ErrorNone; } + case LazyValueIdFnType: { + ZigType *fn_type = ir_resolve_lazy_fn_type(codegen, exec, source_node, + reinterpret_cast(val->data.x_lazy)); + if (fn_type == nullptr) + return ErrorSemanticAnalyzeFail; + val->special = ConstValSpecialStatic; + assert(val->type->id == ZigTypeIdMetaType); + val->data.x_type = fn_type; + return ErrorNone; + } } zig_unreachable(); } -- 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') 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 be0a9a72772566667d4c225972c6bc7c17b751ef Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 15:05:15 -0400 Subject: pointer types lazily evaluate their element type --- src/all_types.hpp | 3 +- src/analyze.cpp | 22 +++++++------- src/ir.cpp | 85 +++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 68 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 11bed48e8f..d23020593d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -332,7 +332,8 @@ struct LazyValuePtrType { bool is_volatile; bool is_allowzero; - ZigType *elem_type; + ConstExprValue *elem_type_val; + AstNode *elem_type_src_node; ConstExprValue *align_val; // can be null PtrLen ptr_len; uint32_t bit_offset_in_host; diff --git a/src/analyze.cpp b/src/analyze.cpp index bfdeb5d41a..f140489ab3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -956,7 +956,7 @@ ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, Zig } static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, - bool *is_zero_bits) + ConstExprValue *parent_type_val, bool *is_zero_bits) { Error err; if (type_val->special != ConstValSpecialLazy) { @@ -972,15 +972,17 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi zig_unreachable(); case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_ptr_type->elem_type == parent_type) { + + if (parent_type_val == lazy_ptr_type->elem_type_val) { // Does a struct which contains a pointer field to itself have bits? Yes. *is_zero_bits = false; return ErrorNone; } else { - if ((err = type_resolve(g, lazy_ptr_type->elem_type, ResolveStatusZeroBitsKnown))) - return err; - *is_zero_bits = type_has_bits(lazy_ptr_type->elem_type); - return ErrorNone; + if (parent_type_val == nullptr) { + parent_type_val = type_val; + } + return type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type_val, parent_type, + parent_type_val, is_zero_bits); } } case LazyValueIdSliceType: @@ -1030,9 +1032,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue } case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - if (type_is_invalid(lazy_ptr_type->elem_type)) - return ReqCompTimeInvalid; - return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type); + return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type_val, parent_type); } case LazyValueIdFnType: { LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); @@ -1102,7 +1102,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons case LazyValueIdPtrType: { Error err; bool zero_bits; - if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, &zero_bits))) { + if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, nullptr, &zero_bits))) { return OnePossibleValueInvalid; } if (zero_bits) { @@ -2359,7 +2359,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { } bool field_is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, &field_is_zero_bits))) { + if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, nullptr, &field_is_zero_bits))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } diff --git a/src/ir.cpp b/src/ir.cpp index 5f4cce328a..13ae0715a4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10850,17 +10850,32 @@ static ZigType *ir_resolve_const_type(CodeGen *codegen, IrExecutable *exec, AstN return val->data.x_type; } -static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { +static ConstExprValue *ir_resolve_type_lazy(IrAnalyze *ira, IrInstruction *type_value) { if (type_is_invalid(type_value->value.type)) - return ira->codegen->builtin_types.entry_invalid; + return nullptr; if (type_value->value.type->id != ZigTypeIdMetaType) { ir_add_error(ira, type_value, buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); - return ira->codegen->builtin_types.entry_invalid; + return nullptr; + } + + Error err; + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, type_value->source_node, + &type_value->value, LazyOk))) + { + return nullptr; } - return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, &type_value->value); + return &type_value->value; +} + +static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { + ConstExprValue *val = ir_resolve_type_lazy(ira, type_value); + if (val == nullptr) + return ira->codegen->builtin_types.entry_invalid; + + return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); } static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { @@ -23907,30 +23922,10 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct lazy_ptr_type->base.id = LazyValueIdPtrType; lazy_ptr_type->base.exec = ira->new_irb.exec; - ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); - if (type_is_invalid(child_type)) + lazy_ptr_type->elem_type_val = ir_resolve_type_lazy(ira, instruction->child_type->child); + if (lazy_ptr_type->elem_type_val == nullptr) return ira->codegen->invalid_instruction; - lazy_ptr_type->elem_type = child_type; - - if (child_type->id == ZigTypeIdUnreachable) { - ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); - return ira->codegen->invalid_instruction; - } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { - ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); - return ira->codegen->invalid_instruction; - } else if (instruction->ptr_len == PtrLenC) { - if (!type_allowed_in_extern(ira->codegen, child_type)) { - ir_add_error(ira, &instruction->base, - buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); - return ira->codegen->invalid_instruction; - } else if (child_type->id == ZigTypeIdOpaque) { - ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); - return ira->codegen->invalid_instruction; - } else if (instruction->is_allow_zero) { - ir_add_error(ira, &instruction->base, buf_sprintf("C pointers always allow address zero")); - return ira->codegen->invalid_instruction; - } - } + lazy_ptr_type->elem_type_src_node = instruction->child_type->source_node; if (instruction->align_value != nullptr) { lazy_ptr_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk); @@ -25593,15 +25588,45 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx if (!ir_resolve_const_align(codegen, exec, source_node, lazy_ptr_type->align_val, &align_bytes)) return ErrorSemanticAnalyzeFail; } + ZigType *elem_type = ir_resolve_const_type(codegen, exec, lazy_ptr_type->elem_type_src_node, + lazy_ptr_type->elem_type_val); + if (type_is_invalid(elem_type)) + return ErrorSemanticAnalyzeFail; + + if (elem_type->id == ZigTypeIdUnreachable) { + exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + buf_create_from_str("pointer to noreturn not allowed")); + return ErrorSemanticAnalyzeFail; + } else if (elem_type->id == ZigTypeIdOpaque && lazy_ptr_type->ptr_len == PtrLenUnknown) { + exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + buf_create_from_str("unknown-length pointer to opaque")); + return ErrorSemanticAnalyzeFail; + } else if (lazy_ptr_type->ptr_len == PtrLenC) { + if (!type_allowed_in_extern(codegen, elem_type)) { + exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", + buf_ptr(&elem_type->name))); + return ErrorSemanticAnalyzeFail; + } else if (elem_type->id == ZigTypeIdOpaque) { + exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + buf_sprintf("C pointers cannot point opaque types")); + return ErrorSemanticAnalyzeFail; + } else if (lazy_ptr_type->is_allowzero) { + exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + buf_sprintf("C pointers always allow address zero")); + return ErrorSemanticAnalyzeFail; + } + } + ResolveStatus needed_status = (align_bytes == 0) ? ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; - if ((err = type_resolve(codegen, lazy_ptr_type->elem_type, needed_status))) + if ((err = type_resolve(codegen, elem_type, needed_status))) return err; - if (!type_has_bits(lazy_ptr_type->elem_type)) + if (!type_has_bits(elem_type)) align_bytes = 0; bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra(codegen, lazy_ptr_type->elem_type, + val->data.x_type = get_pointer_to_type_extra(codegen, elem_type, lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, allow_zero); -- 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') 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 f0034495fa74d7a2c36e4a75520f030bb0cdb16a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 15:59:37 -0400 Subject: fix regression with simple pointer to self --- src/analyze.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index f6e8a77770..0b65210eea 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -961,6 +961,13 @@ 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) + { + // Does a struct which contains a pointer field to itself have bits? Yes. + *is_zero_bits = false; + return ErrorNone; + } if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown))) return err; *is_zero_bits = (type_val->data.x_type->abi_size == 0); -- cgit v1.2.3 From 101440c1990de653bbfb19713915d86d7a5bc182 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 17:14:51 -0400 Subject: add lazy value support for optional types this case works now: ```zig const Node = struct { node: ?*Node, }; ``` --- src/all_types.hpp | 8 ++++++ src/analyze.cpp | 11 +++++++ src/ir.cpp | 85 +++++++++++++++++++++++++------------------------------ 3 files changed, 57 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 2a20d3c860..61dde995af 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -302,6 +302,7 @@ enum LazyValueId { LazyValueIdInvalid, LazyValueIdAlignOf, LazyValueIdPtrType, + LazyValueIdOptType, LazyValueIdSliceType, LazyValueIdFnType, }; @@ -340,6 +341,13 @@ struct LazyValuePtrType { uint32_t host_int_bytes; }; +struct LazyValueOptType { + LazyValue base; + + ConstExprValue *payload_type_val; + AstNode *payload_type_src_node; +}; + struct LazyValueFnType { LazyValue base; bool is_generic; diff --git a/src/analyze.cpp b/src/analyze.cpp index 0b65210eea..5159dbb05a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -992,6 +992,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi parent_type_val, is_zero_bits); } } + case LazyValueIdOptType: case LazyValueIdSliceType: *is_zero_bits = false; return ErrorNone; @@ -1017,6 +1018,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool case LazyValueIdSliceType: case LazyValueIdPtrType: case LazyValueIdFnType: + case LazyValueIdOptType: *is_opaque_type = false; return ErrorNone; } @@ -1041,6 +1043,10 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type_val); } + case LazyValueIdOptType: { + LazyValueOptType *lazy_opt_type = reinterpret_cast(type_val->data.x_lazy); + return type_val_resolve_requires_comptime(g, lazy_opt_type->payload_type_val); + } case LazyValueIdFnType: { LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); if (lazy_fn_type->is_generic) @@ -1091,6 +1097,10 @@ static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, si case LazyValueIdFnType: *abi_align = g->builtin_types.entry_usize->abi_align; return ErrorNone; + case LazyValueIdOptType: { + LazyValueOptType *lazy_opt_type = reinterpret_cast(type_val->data.x_lazy); + return type_val_resolve_abi_align(g, lazy_opt_type->payload_type_val, abi_align); + } } zig_unreachable(); } @@ -1104,6 +1114,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons case LazyValueIdAlignOf: zig_unreachable(); case LazyValueIdSliceType: // it has the len field + case LazyValueIdOptType: // it has the optional bit case LazyValueIdFnType: return OnePossibleValueNo; case LazyValueIdPtrType: { diff --git a/src/ir.cpp b/src/ir.cpp index 70dc894f86..2f38b42221 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8212,6 +8212,7 @@ static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, Ast { Error err; assert(ptr_val->type->id == ZigTypeIdPointer); + assert(ptr_val->special == ConstValSpecialStatic); ConstExprValue tmp = {}; tmp.special = ConstValSpecialStatic; tmp.type = ptr_val->type->data.pointer.child_type; @@ -16150,51 +16151,21 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source zig_unreachable(); } -static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { - Error err; - IrInstruction *value = un_op_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; +static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *instruction) { + IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); + result->value.special = ConstValSpecialLazy; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdVector: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry)); + LazyValueOptType *lazy_opt_type = allocate(1); + result->value.data.x_lazy = &lazy_opt_type->base; + lazy_opt_type->base.id = LazyValueIdOptType; + lazy_opt_type->base.exec = ira->new_irb.exec; - case ZigTypeIdUnreachable: - case ZigTypeIdOpaque: - ir_add_error_node(ira, un_op_instruction->base.source_node, - buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - zig_unreachable(); + lazy_opt_type->payload_type_val = ir_resolve_type_lazy(ira, instruction->value->child); + if (lazy_opt_type->payload_type_val == nullptr) + return ira->codegen->invalid_instruction; + lazy_opt_type->payload_type_src_node = instruction->value->source_node; + + return result; } static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type, @@ -19658,11 +19629,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig ZigVar *var = tld->var; - if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - assert(var->const_value->type->id == ZigTypeIdMetaType); - return var->const_value->data.x_type; + + return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, nullptr, var->const_value); } static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val, @@ -25633,6 +25602,28 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx val->special = ConstValSpecialStatic; return ErrorNone; } + case LazyValueIdOptType: { + LazyValueOptType *lazy_opt_type = reinterpret_cast(val->data.x_lazy); + + ZigType *payload_type = ir_resolve_const_type(codegen, exec, lazy_opt_type->payload_type_src_node, + lazy_opt_type->payload_type_val); + if (type_is_invalid(payload_type)) + return ErrorSemanticAnalyzeFail; + + if (payload_type->id == ZigTypeIdOpaque || payload_type->id == ZigTypeIdUnreachable) { + exec_add_error_node(codegen, exec, lazy_opt_type->payload_type_src_node, + buf_sprintf("type '%s' cannot be optional", buf_ptr(&payload_type->name))); + return ErrorSemanticAnalyzeFail; + } + + if ((err = type_resolve(codegen, payload_type, ResolveStatusSizeKnown))) + return err; + + assert(val->type->id == ZigTypeIdMetaType); + val->data.x_type = get_optional_type(codegen, payload_type); + val->special = ConstValSpecialStatic; + return ErrorNone; + } case LazyValueIdFnType: { ZigType *fn_type = ir_resolve_lazy_fn_type(codegen, exec, source_node, reinterpret_cast(val->data.x_lazy)); -- cgit v1.2.3 From e8bad1e12a972ce26aeedd37bf49a6751bab2b76 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 17:39:56 -0400 Subject: fix regression on `@ptrCast` this case regressed and now fixed: ```zig const a: ?*i32 = undefined; const b: ?*f32 = @ptrCast(?*f32, a); ``` --- src/ir.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src') diff --git a/src/ir.cpp b/src/ir.cpp index 2f38b42221..558dbca265 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -23298,12 +23298,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ if (!val) return ira->codegen->invalid_instruction; - if (value_is_comptime(val)) { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_instr->source_node, val, UndefBad))) - { - return ira->codegen->invalid_instruction; - } + if (value_is_comptime(val) && val->special != ConstValSpecialUndef) { bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && val->data.x_ptr.data.hard_coded_addr.addr == 0); -- 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') 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 8f41da221690a8dbbbce41a07513715b9a31e70a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 11:42:19 -0400 Subject: fix behavior test regressions with unions --- src/analyze.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 7c967b4e5c..5e0abea5df 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1950,6 +1950,12 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { } } else if (packed) { field->align = 1; + } else if (field->type_entry != nullptr) { + if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return err; + } + field->align = field->type_entry->abi_align; } else { if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -2040,12 +2046,14 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { AstNode *field_source_node = decl_node->data.container_decl.fields.at(i); TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if ((err = ir_resolve_lazy(g, field_source_node, union_field->type_val))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; + if (union_field->type_entry == nullptr) { + if ((err = ir_resolve_lazy(g, field_source_node, union_field->type_val))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return err; + } + union_field->type_entry = union_field->type_val->data.x_type; } - ZigType *field_type = union_field->type_val->data.x_type; - union_field->type_entry = field_type; + ZigType *field_type = union_field->type_entry; if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -4999,7 +5007,11 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdUnion: if (type_entry->data.unionation.src_field_count > 1) return OnePossibleValueNo; - return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry); + TypeUnionField *only_field = &type_entry->data.unionation.fields[0]; + if (only_field->type_entry != nullptr) { + return type_has_one_possible_value(g, only_field->type_entry); + } + return type_val_resolve_has_one_possible_value(g, only_field->type_val); } zig_unreachable(); } -- cgit v1.2.3 From 64e9b0ee4673bf79d42ea14e354b324308f90b93 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 20:27:56 -0400 Subject: make the zero-bit-ness of pointers lazy this case works now: ```zig const Foo = struct { field: @typeOf(func).ReturnType, }; fn func(self: *Foo) void {} ``` --- src/analyze.cpp | 99 ++++++++++++++++++++++++++++++++++++++------------------- src/ir.cpp | 12 +++---- 2 files changed, 72 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 5e0abea5df..34e9605bdc 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -474,15 +474,21 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons buf_ptr(&child_type->name)); } - if (type_has_bits(child_type)) { - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_align = g->builtin_types.entry_usize->abi_align; + if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { + if (type_has_bits(child_type)) { + entry->abi_size = g->builtin_types.entry_usize->abi_size; + entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; + entry->abi_align = g->builtin_types.entry_usize->abi_align; + } else { + assert(byte_alignment == 0); + entry->abi_size = 0; + entry->size_in_bits = 0; + entry->abi_align = 0; + } } else { - assert(byte_alignment == 0); - entry->abi_size = 0; - entry->size_in_bits = 0; - entry->abi_align = 0; + entry->abi_size = SIZE_MAX; + entry->size_in_bits = SIZE_MAX; + entry->abi_align = UINT32_MAX; } entry->data.pointer.ptr_len = ptr_len; @@ -5585,6 +5591,25 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { return ErrorNone; } +static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { + Error err; + ZigType *elem_type = ty->data.pointer.child_type; + + if ((err = type_resolve(g, elem_type, ResolveStatusZeroBitsKnown))) + return err; + + if (type_has_bits(elem_type)) { + ty->abi_size = g->builtin_types.entry_usize->abi_size; + ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; + ty->abi_align = g->builtin_types.entry_usize->abi_align; + } else { + ty->abi_size = 0; + ty->size_in_bits = 0; + ty->abi_align = 0; + } + return ErrorNone; +} + Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { if (type_is_invalid(ty)) return ErrorSemanticAnalyzeFail; @@ -5594,36 +5619,44 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { case ResolveStatusInvalid: zig_unreachable(); case ResolveStatusZeroBitsKnown: - if (ty->id == ZigTypeIdStruct) { - return resolve_struct_zero_bits(g, ty); - } else if (ty->id == ZigTypeIdEnum) { - return resolve_enum_zero_bits(g, ty); - } else if (ty->id == ZigTypeIdUnion) { - return resolve_union_zero_bits(g, ty); + switch (ty->id) { + case ZigTypeIdStruct: + return resolve_struct_zero_bits(g, ty); + case ZigTypeIdEnum: + return resolve_enum_zero_bits(g, ty); + case ZigTypeIdUnion: + return resolve_union_zero_bits(g, ty); + case ZigTypeIdPointer: + return resolve_pointer_zero_bits(g, ty); + default: + return ErrorNone; } - return ErrorNone; case ResolveStatusAlignmentKnown: - if (ty->id == ZigTypeIdStruct) { - return resolve_struct_alignment(g, ty); - } else if (ty->id == ZigTypeIdEnum) { - return resolve_enum_zero_bits(g, ty); - } else if (ty->id == ZigTypeIdUnion) { - return resolve_union_alignment(g, ty); - } else if (ty->id == ZigTypeIdFnFrame) { - return resolve_async_frame(g, ty); + switch (ty->id) { + case ZigTypeIdStruct: + return resolve_struct_alignment(g, ty); + case ZigTypeIdEnum: + return resolve_enum_zero_bits(g, ty); + case ZigTypeIdUnion: + return resolve_union_alignment(g, ty); + case ZigTypeIdFnFrame: + return resolve_async_frame(g, ty); + default: + return ErrorNone; } - return ErrorNone; case ResolveStatusSizeKnown: - if (ty->id == ZigTypeIdStruct) { - return resolve_struct_type(g, ty); - } else if (ty->id == ZigTypeIdEnum) { - return resolve_enum_zero_bits(g, ty); - } else if (ty->id == ZigTypeIdUnion) { - return resolve_union_type(g, ty); - } else if (ty->id == ZigTypeIdFnFrame) { - return resolve_async_frame(g, ty); + switch (ty->id) { + case ZigTypeIdStruct: + return resolve_struct_type(g, ty); + case ZigTypeIdEnum: + return resolve_enum_zero_bits(g, ty); + case ZigTypeIdUnion: + return resolve_union_type(g, ty); + case ZigTypeIdFnFrame: + return resolve_async_frame(g, ty); + default: + return ErrorNone; } - return ErrorNone; case ResolveStatusLLVMFwdDecl: case ResolveStatusLLVMFull: resolve_llvm_types(g, ty, status); diff --git a/src/ir.cpp b/src/ir.cpp index 558dbca265..3aabb4995f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25582,12 +25582,12 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx } } - ResolveStatus needed_status = (align_bytes == 0) ? - ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; - if ((err = type_resolve(codegen, elem_type, needed_status))) - return err; - if (!type_has_bits(elem_type)) - align_bytes = 0; + if (align_bytes != 0) { + if ((err = type_resolve(codegen, elem_type, ResolveStatusAlignmentKnown))) + return err; + if (!type_has_bits(elem_type)) + align_bytes = 0; + } bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; assert(val->type->id == ZigTypeIdMetaType); val->data.x_type = get_pointer_to_type_extra(codegen, elem_type, -- cgit v1.2.3 From a7f31581850fe2811bc5114459a8d193dd48b42a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 21:16:03 -0400 Subject: behavior tests passing --- src/analyze.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 34e9605bdc..2ee0322db1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2633,7 +2633,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { decl_node->data.container_decl.init_arg_expr != nullptr) { union_field->type_entry = g->builtin_types.entry_void; - field_is_zero_bits = false; + field_is_zero_bits = true; } else { add_node_error(g, field_node, buf_sprintf("union field missing type")); union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -5593,6 +5593,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { Error err; + + if (ty->abi_size != SIZE_MAX) + return ErrorNone; + ZigType *elem_type = ty->data.pointer.child_type; if ((err = type_resolve(g, elem_type, ResolveStatusZeroBitsKnown))) @@ -5641,6 +5645,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { return resolve_union_alignment(g, ty); case ZigTypeIdFnFrame: return resolve_async_frame(g, ty); + case ZigTypeIdPointer: + return resolve_pointer_zero_bits(g, ty); default: return ErrorNone; } @@ -5654,6 +5660,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { return resolve_union_type(g, ty); case ZigTypeIdFnFrame: return resolve_async_frame(g, ty); + case ZigTypeIdPointer: + return resolve_pointer_zero_bits(g, ty); default: return ErrorNone; } @@ -7386,7 +7394,8 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta 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) { + uint32_t gen_field_count = union_type->data.unionation.gen_field_count; + if (gen_field_count == 0) { union_type->llvm_type = get_llvm_type(g, tag_type); union_type->llvm_di_type = get_llvm_di_type(g, tag_type); union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; @@ -7410,7 +7419,6 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; } - uint32_t gen_field_count = union_type->data.unionation.gen_field_count; ZigLLVMDIType **union_inner_di_types = allocate(gen_field_count); uint32_t field_count = union_type->data.unionation.src_field_count; for (uint32_t i = 0; i < field_count; i += 1) { @@ -7541,6 +7549,9 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { if (type->llvm_di_type != nullptr) return; + if (resolve_pointer_zero_bits(g, type) != ErrorNone) + zig_unreachable(); + if (!type_has_bits(type)) { type->llvm_type = g->builtin_types.entry_void->llvm_type; type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; -- cgit v1.2.3 From 720302a6407e954ffccf65f38ad40b47868627ce Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 21:28:16 -0400 Subject: fix resolution detection of pointer types --- src/analyze.cpp | 15 ++++++++++++++- src/ir.cpp | 21 ++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 2ee0322db1..181cab2332 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -289,13 +289,26 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { } case ZigTypeIdOpaque: return status < ResolveStatusSizeKnown; + case ZigTypeIdPointer: + switch (status) { + case ResolveStatusInvalid: + zig_unreachable(); + case ResolveStatusUnstarted: + return true; + case ResolveStatusZeroBitsKnown: + case ResolveStatusAlignmentKnown: + case ResolveStatusSizeKnown: + return type_entry->abi_size != SIZE_MAX; + case ResolveStatusLLVMFwdDecl: + case ResolveStatusLLVMFull: + return type_entry->llvm_type != nullptr; + } case ZigTypeIdMetaType: case ZigTypeIdVoid: case ZigTypeIdBool: case ZigTypeIdUnreachable: case ZigTypeIdInt: case ZigTypeIdFloat: - case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: diff --git a/src/ir.cpp b/src/ir.cpp index 3aabb4995f..d9f7e37e8e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -23338,6 +23338,12 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + + if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + if (type_has_bits(dest_type) && !type_has_bits(src_type)) { ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("'%s' and '%s' do not have the same in-memory representation", @@ -25435,6 +25441,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, LazyValueFnType *lazy_fn_type) { + Error err; AstNode *proto_node = lazy_fn_type->proto_node; FnTypeId fn_type_id = {0}; @@ -25482,11 +25489,15 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As case ReqCompTimeNo: break; } - if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) { - exec_add_error_node(codegen, exec, source_node, - buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return nullptr; + if (!calling_convention_allows_zig_types(fn_type_id.cc)) { + if ((err = type_resolve(codegen, param_type, ResolveStatusZeroBitsKnown))) + return nullptr; + if (!type_has_bits(param_type)) { + exec_add_error_node(codegen, exec, source_node, + buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", + buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); + return nullptr; + } } param_info->type = param_type; } -- cgit v1.2.3 From b13af0750fbe8b38a95b05ec78c8364281fcf477 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 21:45:11 -0400 Subject: fix assertion tripped instead of reporting compile error --- src/ir.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ir.cpp b/src/ir.cpp index d9f7e37e8e..34c6985c6a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9006,7 +9006,8 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad); - assert(const_val != nullptr); + if (const_val == nullptr) + return false; bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); -- cgit v1.2.3 From ede0c22a6796600cfc4555e9ac2f0481c41c290a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 10:03:30 -0400 Subject: make `@alignOf` lazily evaluate the target type this case works now: ```zig const Foo = struct { field: Bar(@alignOf(*Foo)), }; fn Bar(comptime alignment: u29) type { return struct { field: *align(alignment) Foo, }; } ``` --- src/all_types.hpp | 4 ++- src/analyze.cpp | 7 ++-- src/analyze.hpp | 2 +- src/ir.cpp | 103 +++++++++++++++++++++++++++--------------------------- 4 files changed, 60 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 4b8a9c4308..18aa6e6d65 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -314,7 +314,9 @@ struct LazyValue { struct LazyValueAlignOf { LazyValue base; - ZigType *target_type; + + ConstExprValue *target_type_val; + AstNode *target_type_src_node; }; struct LazyValueSliceType { diff --git a/src/analyze.cpp b/src/analyze.cpp index 181cab2332..fc9607e264 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1100,13 +1100,14 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue zig_unreachable(); } -static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) { +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); - if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusAlignmentKnown))) + ZigType *ty = type_val->data.x_type; + if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown))) return err; - *abi_align = type_val->data.x_type->abi_align; + *abi_align = ty->abi_align; return ErrorNone; } switch (type_val->data.x_lazy->id) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 0da9ec09af..79a490ff78 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -247,6 +247,6 @@ ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); bool fn_is_async(ZigFn *fn); -Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type); +Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align); #endif diff --git a/src/ir.cpp b/src/ir.cpp index 34c6985c6a..75f0a5e55a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -22325,63 +22325,24 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { - IrInstruction *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value.type)) - return ira->codegen->invalid_instruction; - ZigType *type_entry = ir_resolve_type(ira, type_value); - - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdVoid: - case ZigTypeIdOpaque: - ir_add_error(ira, instruction->type_value, - buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - - if (type_is_resolved(type_entry, ResolveStatusAlignmentKnown)) { - uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); - return ir_const_unsigned(ira, &instruction->base, align_in_bytes); - } - // Here we create a lazy value in order to avoid resolving the alignment of the type // immediately. This avoids false positive dependency loops such as: // const Node = struct { // field: []align(@alignOf(Node)) Node, // }; - LazyValueAlignOf *lazy_align_of = allocate(1); - lazy_align_of->base.id = LazyValueIdAlignOf; - lazy_align_of->base.exec = ira->new_irb.exec; - lazy_align_of->target_type = type_entry; IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); result->value.special = ConstValSpecialLazy; + + LazyValueAlignOf *lazy_align_of = allocate(1); result->value.data.x_lazy = &lazy_align_of->base; + lazy_align_of->base.id = LazyValueIdAlignOf; + lazy_align_of->base.exec = ira->new_irb.exec; + + lazy_align_of->target_type_val = ir_resolve_type_lazy(ira, instruction->type_value->child); + if (lazy_align_of->target_type_val == nullptr) + return ira->codegen->invalid_instruction; + lazy_align_of->target_type_src_node = instruction->type_value->source_node; + return result; } @@ -25530,9 +25491,49 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx zig_unreachable(); case LazyValueIdAlignOf: { LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); - if ((err = type_resolve(codegen, lazy_align_of->target_type, ResolveStatusAlignmentKnown))) + + if (lazy_align_of->target_type_val->special == ConstValSpecialStatic) { + switch (lazy_align_of->target_type_val->data.x_type->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdMetaType: + case ZigTypeIdUnreachable: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdVoid: + case ZigTypeIdOpaque: + exec_add_error_node(codegen, exec, lazy_align_of->target_type_src_node, + buf_sprintf("no align available for type '%s'", + buf_ptr(&lazy_align_of->target_type_val->data.x_type->name))); + return ErrorSemanticAnalyzeFail; + case ZigTypeIdBool: + case ZigTypeIdInt: + case ZigTypeIdFloat: + case ZigTypeIdPointer: + case ZigTypeIdArray: + case ZigTypeIdStruct: + case ZigTypeIdOptional: + case ZigTypeIdErrorUnion: + case ZigTypeIdErrorSet: + case ZigTypeIdEnum: + case ZigTypeIdUnion: + case ZigTypeIdFn: + case ZigTypeIdVector: + case ZigTypeIdFnFrame: + case ZigTypeIdAnyFrame: + break; + } + } + + uint32_t align_in_bytes; + if ((err = type_val_resolve_abi_align(codegen, lazy_align_of->target_type_val, &align_in_bytes))) return err; - uint64_t align_in_bytes = get_abi_alignment(codegen, lazy_align_of->target_type); + val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdComptimeInt); bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); -- cgit v1.2.3 From e1a4bcbdfd338d85f55aa8da318e203b299a2b91 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 10:43:07 -0400 Subject: fix dependency loop errors with zig build --- src/all_types.hpp | 1 + src/analyze.cpp | 16 +++++++++++++++- src/ir.cpp | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 18aa6e6d65..e860b87857 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1124,6 +1124,7 @@ struct ZigTypePointer { bool is_const; bool is_volatile; bool allow_zero; + bool resolve_loop_flag_zero_bits; }; struct ZigTypeInt { diff --git a/src/analyze.cpp b/src/analyze.cpp index fc9607e264..87e40b3670 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -983,7 +983,9 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi 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)) + type_val->data.x_type->data.unionation.resolve_loop_flag_zero_bits) || + (type_val->data.x_type->id == ZigTypeIdPointer && + type_val->data.x_type->data.pointer.resolve_loop_flag_zero_bits)) { // Does a struct/union which contains a pointer field to itself have bits? Yes. *is_zero_bits = false; @@ -1105,6 +1107,10 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t if (type_val->special != ConstValSpecialLazy) { assert(type_val->special == ConstValSpecialStatic); ZigType *ty = type_val->data.x_type; + if (ty->id == ZigTypeIdPointer) { + *abi_align = g->builtin_types.entry_usize->abi_align; + return ErrorNone; + } if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown))) return err; *abi_align = ty->abi_align; @@ -5611,6 +5617,14 @@ static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { if (ty->abi_size != SIZE_MAX) return ErrorNone; + if (ty->data.pointer.resolve_loop_flag_zero_bits) { + ty->abi_size = g->builtin_types.entry_usize->abi_size; + ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; + ty->abi_align = g->builtin_types.entry_usize->abi_align; + return ErrorNone; + } + ty->data.pointer.resolve_loop_flag_zero_bits = true; + ZigType *elem_type = ty->data.pointer.child_type; if ((err = type_resolve(g, elem_type, ResolveStatusZeroBitsKnown))) diff --git a/src/ir.cpp b/src/ir.cpp index 75f0a5e55a..bd782b4fdc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9367,6 +9367,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.id = ConstCastResultIdInvalid; return result; } + if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { + result.id = ConstCastResultIdInvalid; + return result; + } + if ((err = type_resolve(g, actual_type, ResolveStatusZeroBitsKnown))) { + result.id = ConstCastResultIdInvalid; + return result; + } bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && type_has_bits(wanted_type) == type_has_bits(actual_type) && -- cgit v1.2.3 From 6569bfc85e7de5229dd5b665e84070970d28653d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 11:23:25 -0400 Subject: fix some std lib dependency loops --- src/analyze.cpp | 7 +++---- std/array_list.zig | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 87e40b3670..06212bf48b 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -984,8 +984,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi 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) || - (type_val->data.x_type->id == ZigTypeIdPointer && - type_val->data.x_type->data.pointer.resolve_loop_flag_zero_bits)) + type_val->data.x_type->id == ZigTypeIdPointer) { // Does a struct/union which contains a pointer field to itself have bits? Yes. *is_zero_bits = false; @@ -2162,7 +2161,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, - buf_sprintf("dependency loop: whether enum '%s' has non-zero size", + buf_sprintf("enum '%s' depends on itself", buf_ptr(&enum_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2532,7 +2531,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; g->trace_err = add_node_error(g, decl_node, - buf_sprintf("dependency loop: whether union '%s' has non-zero size", + buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; diff --git a/std/array_list.zig b/std/array_list.zig index ee282145bd..a527d818d6 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -6,20 +6,23 @@ const mem = std.mem; const Allocator = mem.Allocator; pub fn ArrayList(comptime T: type) type { - return AlignedArrayList(T, @alignOf(T)); + return AlignedArrayList(T, null); } -pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { +pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { return struct { const Self = @This(); /// Use toSlice instead of slicing this directly, because if you don't /// specify the end position of the slice, this will potentially give /// you uninitialized memory. - items: []align(A) T, + items: Slice, len: usize, allocator: *Allocator, + pub const Slice = if (alignment) |a| ([]align(a) T) else []T; + pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T; + /// Deinitialize with `deinit` or use `toOwnedSlice`. pub fn init(allocator: *Allocator) Self { return Self{ @@ -33,11 +36,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { self.allocator.free(self.items); } - pub fn toSlice(self: Self) []align(A) T { + pub fn toSlice(self: Self) Slice { return self.items[0..self.len]; } - pub fn toSliceConst(self: Self) []align(A) const T { + pub fn toSliceConst(self: Self) SliceConst { return self.items[0..self.len]; } @@ -69,7 +72,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { /// ArrayList takes ownership of the passed in slice. The slice must have been /// allocated with `allocator`. /// Deinitialize with `deinit` or use `toOwnedSlice`. - pub fn fromOwnedSlice(allocator: *Allocator, slice: []align(A) T) Self { + pub fn fromOwnedSlice(allocator: *Allocator, slice: Slice) Self { return Self{ .items = slice, .len = slice.len, @@ -78,7 +81,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { } /// The caller owns the returned memory. ArrayList becomes empty. - pub fn toOwnedSlice(self: *Self) []align(A) T { + pub fn toOwnedSlice(self: *Self) Slice { const allocator = self.allocator; const result = allocator.shrink(self.items, self.len); self.* = init(allocator); @@ -93,7 +96,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { self.items[n] = item; } - pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void { + pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void { try self.ensureCapacity(self.len + items.len); self.len += items.len; @@ -141,7 +144,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { return self.swapRemove(i); } - pub fn appendSlice(self: *Self, items: []align(A) const T) !void { + pub fn appendSlice(self: *Self, items: SliceConst) !void { try self.ensureCapacity(self.len + items.len); mem.copy(T, self.items[self.len..], items); self.len += items.len; -- cgit v1.2.3 From 73a7747a9cfb180a92fa0d98f9387d5ad1f47fd2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 12:43:36 -0400 Subject: fix some compile error regressions --- src/all_types.hpp | 7 +++++++ src/analyze.cpp | 29 ++++++++++++++++++----------- src/ir.cpp | 13 +++++-------- src/tokenizer.cpp | 2 +- test/compile_errors.zig | 12 ++++++------ 5 files changed, 37 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index e860b87857..61e71c236c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -53,6 +53,13 @@ enum PtrLen { PtrLenC, }; +enum UndefAllowed { + UndefOk, + UndefBad, + LazyOkNoUndef, + LazyOk, +}; + enum X64CABIClass { X64CABIClass_Unknown, X64CABIClass_MEMORY, diff --git a/src/analyze.cpp b/src/analyze.cpp index 06212bf48b..bba26b29ae 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -59,6 +59,7 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) { root_struct->source_code, root_struct->line_offsets, msg); g->errors.append(err); + g->trace_err = err; return err; } @@ -1793,7 +1794,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { 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, + add_node_error(g, decl_node, buf_sprintf("struct '%s' depends on its own size", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; @@ -1947,7 +1948,7 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { 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, + add_node_error(g, decl_node, buf_sprintf("union '%s' depends on its own alignment", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2058,7 +2059,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { 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, + add_node_error(g, decl_node, buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2160,7 +2161,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (enum_type->data.enumeration.resolve_loop_flag) { if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - g->trace_err = add_node_error(g, decl_node, + add_node_error(g, decl_node, buf_sprintf("enum '%s' depends on itself", buf_ptr(&enum_type->name))); } @@ -2337,7 +2338,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { 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, + add_node_error(g, decl_node, buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); } @@ -2462,7 +2463,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { 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, + add_node_error(g, decl_node, buf_sprintf("struct '%s' depends on its own alignment", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; @@ -2530,7 +2531,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { 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, + add_node_error(g, decl_node, buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); } @@ -3423,7 +3424,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { ZigType *explicit_type = nullptr; if (var_decl->type) { if (tld_var->analyzing_type) { - g->trace_err = add_node_error(g, var_decl->type, + add_node_error(g, var_decl->type, buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name))); explicit_type = g->builtin_types.entry_invalid; } else { @@ -4001,6 +4002,13 @@ static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { ZigType *frame_type = get_fn_frame_type(g, fn); Error err; if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { + if (g->trace_err != nullptr && frame_type->data.frame.resolve_loop_src_node != nullptr && + !frame_type->data.frame.reported_loop_err) + { + frame_type->data.frame.reported_loop_err = true; + g->trace_err = add_error_note(g, g->trace_err, frame_type->data.frame.resolve_loop_src_node, + buf_sprintf("when analyzing type '%s' here", buf_ptr(&frame_type->name))); + } fn->anal_state = FnAnalStateInvalid; return; } @@ -5406,8 +5414,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { if (frame_type->data.frame.resolve_loop_type != nullptr) { if (!frame_type->data.frame.reported_loop_err) { - frame_type->data.frame.reported_loop_err = true; - g->trace_err = add_node_error(g, fn->proto_node, + add_node_error(g, fn->proto_node, buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name))); } return ErrorSemanticAnalyzeFail; @@ -5424,7 +5431,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { return ErrorSemanticAnalyzeFail; break; case FnAnalStateProbing: { - g->trace_err = add_node_error(g, fn->proto_node, + add_node_error(g, fn->proto_node, buf_sprintf("cannot resolve '%s': function not fully analyzed yet", buf_ptr(&frame_type->name))); return ErrorSemanticAnalyzeFail; diff --git a/src/ir.cpp b/src/ir.cpp index bd782b4fdc..a6c14885ef 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -152,12 +152,6 @@ struct ConstCastBadAllowsZero { }; -enum UndefAllowed { - UndefOk, - UndefBad, - LazyOk, -}; - static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); @@ -6836,7 +6830,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod const char modifier = *buf_ptr(asm_output->constraint); if (modifier != '=') { add_node_error(irb->codegen, node, - buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." + buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported" " Compiler TODO: see https://github.com/ziglang/zig/issues/215", buf_ptr(asm_output->asm_symbolic_name), modifier)); return irb->codegen->invalid_instruction; @@ -6860,7 +6854,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod uint32_t len = asm_token.end - asm_token.start - 2; add_node_error(irb->codegen, node, - buf_sprintf("could not find '%.*s' in the inputs or outputs.", + buf_sprintf("could not find '%.*s' in the inputs or outputs", len, ptr)); return irb->codegen->invalid_instruction; } @@ -8114,6 +8108,9 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc } IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); if (result == irb->codegen->invalid_instruction) { + if (irb->exec->first_err_trace_msg == nullptr) { + irb->exec->first_err_trace_msg = irb->codegen->trace_err; + } src_assert(irb->exec->first_err_trace_msg != nullptr, node); } return result; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 84f3f2c0ec..9c9effcb10 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -841,7 +841,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawAmpersand: switch (c) { case '&': - tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND."); + tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND"); break; case '=': set_token_id(&t, t.cur_tok, TokenIdBitAndEq); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a6a1d0219b..7ae722366a 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -10,7 +10,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ : [bar] "=r" (-> usize) \\ ); \\} - , "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs."); + , "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs"); tc.target = tests.Target{ .Cross = tests.CrossTarget{ .arch = .x86_64, @@ -53,8 +53,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself", - "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSumIndirect)' here", - "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSum)' here", + "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSum)' here", + "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSumIndirect)' here", ); cases.add( @@ -245,7 +245,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , "tmp.zig:4:1: error: unable to determine async function frame of 'amain'", "tmp.zig:5:10: note: analysis of function 'other' depends on the frame", - "tmp.zig:8:13: note: depends on the frame here", + "tmp.zig:8:13: note: referenced here", ); cases.add( @@ -258,7 +258,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet", - "tmp.zig:5:13: note: depends on its own frame here", + "tmp.zig:5:13: note: referenced here", ); cases.add( @@ -1091,7 +1091,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return 5678; \\} , - "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.", + "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND", ); cases.add( -- cgit v1.2.3 From d316f704501ff7fc809fdfb082226031ef875046 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 14:01:59 -0400 Subject: fix regression on struct field with undefined type --- src/analyze.cpp | 59 +++++++++++++++++++++---------------------------- src/analyze.hpp | 5 ++--- src/ir.cpp | 24 +++++++++----------- src/ir.hpp | 2 +- test/compile_errors.zig | 2 +- 5 files changed, 40 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index bba26b29ae..b9b8cae8aa 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -961,18 +961,14 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind return entry; } -ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name, bool allow_lazy) +ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name, UndefAllowed undef) { size_t backward_branch_count = 0; size_t backward_branch_quota = default_backward_branch_quota; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, &backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr, nullptr, allow_lazy); -} - -ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { - return analyze_const_value_allow_lazy(g, scope, node, type_entry, type_name, false); + nullptr, nullptr, node, type_name, nullptr, nullptr, undef); } static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, @@ -1162,22 +1158,12 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, Cons } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); + ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, + nullptr, UndefBad); if (type_is_invalid(result->type)) return g->builtin_types.entry_invalid; - - assert(result->special != ConstValSpecialRuntime); - // Reject undefined as valid `type` type even though the specification - // allows it to be casted to anything. - // See also ir_resolve_type() - if (result->special == ConstValSpecialUndef) { - add_node_error(g, node, - buf_sprintf("expected type 'type', found '%s'", - buf_ptr(&g->builtin_types.entry_undef->name))); - return g->builtin_types.entry_invalid; - } - - assert(result->data.x_type != nullptr); + src_assert(result->special == ConstValSpecialStatic, node); + src_assert(result->data.x_type != nullptr, node); return result->data.x_type; } @@ -1225,7 +1211,8 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou } static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { - ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); + ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), + nullptr, UndefBad); if (type_is_invalid(align_result->type)) return false; @@ -1247,7 +1234,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, PtrLenUnknown, 0, 0, 0, false); ZigType *str_type = get_slice_type(g, ptr_type); - ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); + ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr, UndefBad); if (type_is_invalid(result_val->type)) return false; @@ -2261,7 +2248,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (tag_value != nullptr) { // A user-specified value is available - ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, + nullptr, UndefBad); if (type_is_invalid(result->type)) { enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; continue; @@ -2377,8 +2365,8 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - ConstExprValue *field_type_val = analyze_const_value_allow_lazy(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, true); + ConstExprValue *field_type_val = analyze_const_value(g, scope, + field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); if (type_is_invalid(field_type_val->type)) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; @@ -2660,8 +2648,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } } else { - ConstExprValue *field_type_val = analyze_const_value_allow_lazy(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, true); + ConstExprValue *field_type_val = analyze_const_value(g, scope, + field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); if (type_is_invalid(field_type_val->type)) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; @@ -2726,7 +2714,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; - ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, + nullptr, UndefBad); if (type_is_invalid(result->type)) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; @@ -2929,7 +2918,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { fake_decl->data.symbol_expr.symbol = tld_fn->base.name; // call this for the side effects of casting to panic_fn_type - analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr); + analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr, UndefBad); } ZigType *get_test_fn_type(CodeGen *g) { @@ -3075,7 +3064,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { assert(tld_comptime->base.source_node->type == NodeTypeCompTime); AstNode *expr_node = tld_comptime->base.source_node->data.comptime_expr.expr; - analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, nullptr); + analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, + nullptr, UndefBad); } static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { @@ -3443,8 +3433,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { if (explicit_type && explicit_type->id == ZigTypeIdInvalid) { implicit_type = explicit_type; } else if (var_decl->expr) { - init_value = analyze_const_value_allow_lazy(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, - var_decl->symbol, allow_lazy); + init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, + var_decl->symbol, allow_lazy ? LazyOk : UndefOk); assert(init_value); implicit_type = init_value->type; @@ -3599,7 +3589,8 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco using_namespace->base.resolution = TldResolutionResolving; assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace); ConstExprValue *result = analyze_const_value(g, &dest_decls_scope->base, - using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr); + using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, + nullptr, UndefBad); using_namespace->using_namespace_value = result; if (type_is_invalid(result->type)) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 79a490ff78..d3c1df4a08 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -240,9 +240,8 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); -ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); -ConstExprValue *analyze_const_value_allow_lazy(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name, bool allow_lazy); +ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name, UndefAllowed undef); void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); bool fn_is_async(ZigFn *fn); diff --git a/src/ir.cpp b/src/ir.cpp index a6c14885ef..c61815b3bb 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -398,7 +398,7 @@ static void ir_ref_var(ZigVar *var) { ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { ConstExprValue *result = ir_eval_const_value(ira->codegen, scope, node, ira->codegen->builtin_types.entry_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, - node, nullptr, ira->new_irb.exec, nullptr, false); + node, nullptr, ira->new_irb.exec, nullptr, UndefBad); if (type_is_invalid(result->type)) return ira->codegen->builtin_types.entry_invalid; @@ -10734,14 +10734,14 @@ static Error ir_resolve_const_val(CodeGen *codegen, IrExecutable *exec, AstNode buf_sprintf("unable to evaluate constant expression")); return ErrorSemanticAnalyzeFail; case ConstValSpecialUndef: - if (undef_allowed == UndefOk) + if (undef_allowed == UndefOk || undef_allowed == LazyOk) return ErrorNone; exec_add_error_node(codegen, exec, source_node, buf_sprintf("use of undefined value here causes undefined behavior")); return ErrorSemanticAnalyzeFail; case ConstValSpecialLazy: - if (undef_allowed == LazyOk) + if (undef_allowed == LazyOk || undef_allowed == LazyOkNoUndef) return ErrorNone; if ((err = ir_resolve_lazy(codegen, source_node, val))) @@ -10765,7 +10765,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec, AstNode *expected_type_source_node, bool allow_lazy) + IrExecutable *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef_allowed) { Error err; @@ -10819,11 +10819,8 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod ConstExprValue *result = ir_exec_const_result(codegen, analyzed_executable); - if (!allow_lazy) { - if ((err = ir_resolve_lazy(codegen, node, result))) { - return &codegen->invalid_instruction->value; - } - } + if ((err = ir_resolve_const_val(codegen, analyzed_executable, node, result, undef_allowed))) + return &codegen->invalid_instruction->value; return result; } @@ -15578,7 +15575,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c AstNode *body_node = fn_entry->body_node; result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, - nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node, false); + nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node, + UndefOk); if (inferred_err_set_type != nullptr) { inferred_err_set_type->data.error_set.infer_fn = nullptr; @@ -15776,7 +15774,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, - nullptr, false); + nullptr, UndefBad); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); copy_const_val(&const_instruction->base.value, align_result, true); @@ -19129,7 +19127,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc Scope *analyze_scope = &get_container_scope(container_type)->base; // memoize it field->init_val = analyze_const_value(ira->codegen, analyze_scope, init_node, - field->type_entry, nullptr); + field->type_entry, nullptr, UndefOk); } if (type_is_invalid(field->init_val->type)) return ira->codegen->invalid_instruction; @@ -20640,7 +20638,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct ZigType *void_type = ira->codegen->builtin_types.entry_void; ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, false); + &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, UndefBad); if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; diff --git a/src/ir.hpp b/src/ir.hpp index 200a92b64f..3923ea28e8 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -16,7 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec, AstNode *expected_type_source_node, bool allow_lazy); + IrExecutable *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef); Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7ae722366a..7e5e3dd601 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -404,7 +404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const foo: Foo = undefined; \\} , - "tmp.zig:2:8: error: expected type 'type', found '(undefined)'", + "tmp.zig:2:8: error: use of undefined value here causes undefined behavior", ); cases.add( -- 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') 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 From ca145a6d5a430cd87d0b242fb7453e8249221cd0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 15:43:39 -0400 Subject: fix regression in ir_get_ref --- src/ir.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/ir.cpp b/src/ir.cpp index db7c2f1b53..832983dbf7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11210,6 +11210,9 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); + if ((err = type_resolve(ira->codegen, ptr_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + IrInstruction *result_loc; if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, -- cgit v1.2.3 From bad4b040cca553ae6845b18f268313f02077f6c1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 18:35:36 -0400 Subject: miscellaneous fixes regarding compile errors --- src/all_types.hpp | 3 +++ src/analyze.cpp | 14 +++++----- src/analyze.hpp | 2 +- src/ir.cpp | 43 +++++++++++++++++++++++------ test/compile_errors.zig | 72 +++++++++++++++++++++++++------------------------ 5 files changed, 84 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 61e71c236c..3145635b45 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -363,8 +363,10 @@ struct LazyValueFnType { AstNode *proto_node; ConstExprValue **param_types; + AstNode **param_type_src_nodes; ConstExprValue *align_val; // can be null ConstExprValue *return_type; + AstNode *return_type_src_node; }; struct ConstExprValue { @@ -1026,6 +1028,7 @@ struct AstNodeEnumLiteral { struct AstNode { enum NodeType type; + bool already_traced_this_node; size_t line; size_t column; ZigType *owner; diff --git a/src/analyze.cpp b/src/analyze.cpp index b9b8cae8aa..366cb59797 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -63,10 +63,11 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) { return err; } -ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) { +ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { Token fake_token; fake_token.start_line = node->line; fake_token.start_column = node->column; + node->already_traced_this_node = true; return add_token_error(g, node->owner, &fake_token, msg); } @@ -1782,7 +1783,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on its own size", buf_ptr(&struct_type->name))); + buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -1936,7 +1937,7 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on its own alignment", buf_ptr(&union_type->name))); + buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -2047,7 +2048,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name))); + buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -2452,7 +2453,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on its own alignment", buf_ptr(&struct_type->name))); + buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -3661,8 +3662,9 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all } } - if (g->trace_err != nullptr && source_node != nullptr) { + if (g->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { g->trace_err = add_error_note(g, g->trace_err, source_node, buf_create_from_str("referenced here")); + source_node->already_traced_this_node = true; } } diff --git a/src/analyze.hpp b/src/analyze.hpp index d3c1df4a08..63ad905798 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -11,7 +11,7 @@ #include "all_types.hpp" void semantic_analyze(CodeGen *g); -ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg); +ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg); ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); ZigType *new_type_table_entry(ZigTypeId id); diff --git a/src/ir.cpp b/src/ir.cpp index 832983dbf7..f9f64d6789 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10818,6 +10818,8 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod } ConstExprValue *result = ir_exec_const_result(codegen, analyzed_executable); + if (type_is_invalid(result->type)) + return &codegen->invalid_instruction->value; if ((err = ir_resolve_const_val(codegen, analyzed_executable, node, result, undef_allowed))) return &codegen->invalid_instruction->value; @@ -14330,6 +14332,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, // since it's a comptime val there are no instructions for it. // we memcpy the init value here IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr, nullptr); + if (type_is_invalid(deref->value.type)) { + var->var_type = ira->codegen->builtin_types.entry_invalid; + return ira->codegen->invalid_instruction; + } // If this assertion trips, something is wrong with the IR instructions, because // we expected the above deref to return a constant value, but it created a runtime // instruction. @@ -21957,6 +21963,11 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction if (slice_ptr == nullptr) return ira->codegen->invalid_instruction; + if (slice_ptr->special == ConstValSpecialUndef) { + ir_add_error(ira, &instruction->base, buf_sprintf("slice of undefined")); + return ira->codegen->invalid_instruction; + } + parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index]; if (parent_ptr->special == ConstValSpecialUndef) { ir_add_error(ira, &instruction->base, buf_sprintf("slice of undefined")); @@ -22836,6 +22847,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct size_t param_count = proto_node->data.fn_proto.params.length; lazy_fn_type->proto_node = proto_node; lazy_fn_type->param_types = allocate(param_count); + lazy_fn_type->param_type_src_nodes = allocate(param_count); for (size_t param_index = 0; param_index < param_count; param_index += 1) { AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); @@ -22865,6 +22877,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct if (param_type_val == nullptr) return ira->codegen->invalid_instruction; lazy_fn_type->param_types[param_index] = param_type_val; + lazy_fn_type->param_type_src_nodes[param_index] = instruction->param_types[param_index]->source_node; } if (instruction->align_value != nullptr) { @@ -22876,6 +22889,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct lazy_fn_type->return_type = ir_resolve_const(ira, instruction->return_type->child, LazyOk); if (lazy_fn_type->return_type == nullptr) return ira->codegen->invalid_instruction; + lazy_fn_type->return_type_src_node = instruction->return_type->source_node; return result; } @@ -25187,7 +25201,10 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ } else { new_exec->first_err_trace_msg = ira->codegen->trace_err; } - if (new_exec->first_err_trace_msg != nullptr) { + if (new_exec->first_err_trace_msg != nullptr && + !old_instruction->source_node->already_traced_this_node) + { + old_instruction->source_node->already_traced_this_node = true; new_exec->first_err_trace_msg = add_error_note(ira->codegen, new_exec->first_err_trace_msg, old_instruction->source_node, buf_create_from_str("referenced here")); } @@ -25204,7 +25221,10 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ if (new_exec->first_err_trace_msg != nullptr) { codegen->trace_err = new_exec->first_err_trace_msg; - if (codegen->trace_err != nullptr) { + if (codegen->trace_err != nullptr && new_exec->source_node != nullptr && + !new_exec->source_node->already_traced_this_node) + { + new_exec->source_node->already_traced_this_node = true; codegen->trace_err = add_error_note(codegen, codegen->trace_err, new_exec->source_node, buf_create_from_str("referenced here")); } @@ -25435,14 +25455,15 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As param_info->type = nullptr; return get_generic_fn_type(codegen, &fn_type_id); } else { - ZigType *param_type = ir_resolve_const_type(codegen, exec, source_node, + AstNode *param_src_node = lazy_fn_type->param_type_src_nodes[fn_type_id.next_param_index]; + ZigType *param_type = ir_resolve_const_type(codegen, exec, param_src_node, 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)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - exec_add_error_node(codegen, exec, source_node, + exec_add_error_node(codegen, exec, param_src_node, buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); return nullptr; @@ -25459,7 +25480,7 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As if ((err = type_resolve(codegen, param_type, ResolveStatusZeroBitsKnown))) return nullptr; if (!type_has_bits(param_type)) { - exec_add_error_node(codegen, exec, source_node, + exec_add_error_node(codegen, exec, param_src_node, buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); return nullptr; @@ -25474,11 +25495,13 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As return nullptr; } - fn_type_id.return_type = ir_resolve_const_type(codegen, exec, source_node, lazy_fn_type->return_type); + fn_type_id.return_type = ir_resolve_const_type(codegen, exec, lazy_fn_type->return_type_src_node, + lazy_fn_type->return_type); if (type_is_invalid(fn_type_id.return_type)) return nullptr; if (fn_type_id.return_type->id == ZigTypeIdOpaque) { - exec_add_error_node(codegen, exec, source_node, buf_create_from_str("return type cannot be opaque")); + exec_add_error_node(codegen, exec, lazy_fn_type->return_type_src_node, + buf_create_from_str("return type cannot be opaque")); return nullptr; } @@ -25653,11 +25676,15 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { Error err; if ((err = ir_resolve_lazy_raw(codegen, source_node, val))) { - if (codegen->trace_err != nullptr) { + if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) { + source_node->already_traced_this_node = true; codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, buf_create_from_str("referenced here")); } return err; } + if (type_is_invalid(val->type)) { + return ErrorSemanticAnalyzeFail; + } return ErrorNone; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7e5e3dd601..49c836f6a3 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -481,7 +481,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches", - "tmp.zig:1:29: note: called from here", + "tmp.zig:1:29: note: referenced here", + "tmp.zig:5:18: note: referenced here", ); cases.add( @@ -645,7 +646,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\const A = struct { a : A, }; \\export fn entry() usize { return @sizeOf(A); } , - "tmp.zig:1:11: error: struct 'A' contains itself", + "tmp.zig:1:11: error: struct 'A' depends on itself", ); cases.add( @@ -655,7 +656,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\const C = struct { a : A, }; \\export fn entry() usize { return @sizeOf(A); } , - "tmp.zig:1:11: error: struct 'A' contains itself", + "tmp.zig:1:11: error: struct 'A' depends on itself", ); cases.add( @@ -670,7 +671,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @sizeOf(@typeOf(foo.x)); \\} , - "tmp.zig:1:13: error: struct 'Foo' contains itself", + "tmp.zig:1:13: error: struct 'Foo' depends on itself", "tmp.zig:8:28: note: referenced here", ); @@ -689,7 +690,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:7:9: error: dependency loop detected", - "tmp.zig:2:19: note: called from here", + "tmp.zig:2:19: note: referenced here", "tmp.zig:10:21: note: referenced here", ); @@ -703,7 +704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var s: Foo = Foo.E; \\} , - "tmp.zig:1:17: error: 'Foo' depends on itself", + "tmp.zig:1:17: error: enum 'Foo' depends on itself", ); cases.add( @@ -866,7 +867,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { break :x tc; }); - cases.addTest( + cases.add( "export generic function", \\export fn foo(num: var) i32 { \\ return 0; @@ -875,17 +876,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'", ); - cases.addTest( + cases.add( "C pointer to c_void", \\export fn a() void { \\ var x: *c_void = undefined; \\ var y: [*c]c_void = x; \\} , - "tmp.zig:3:12: error: C pointers cannot point opaque types", + "tmp.zig:3:16: error: C pointers cannot point opaque types", ); - cases.addTest( + cases.add( "directly embedding opaque type in struct and union", \\const O = @OpaqueType(); \\const Foo = struct { @@ -906,7 +907,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions", ); - cases.addTest( + cases.add( "implicit cast between C pointer and Zig pointer - bad const/align/child", \\export fn a() void { \\ var x: [*c]u8 = undefined; @@ -942,7 +943,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'", ); - cases.addTest( + cases.add( "implicit casting null c pointer to zig pointer", \\comptime { \\ var c_ptr: [*c]u8 = 0; @@ -952,7 +953,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:24: error: null pointer casted to type '*u8'", ); - cases.addTest( + cases.add( "implicit casting undefined c pointer to zig pointer", \\comptime { \\ var c_ptr: [*c]u8 = undefined; @@ -962,7 +963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:24: error: use of undefined value here causes undefined behavior", ); - cases.addTest( + cases.add( "implicit casting C pointers which would mess up null semantics", \\export fn entry() void { \\ var slice: []const u8 = "aoeu"; @@ -987,7 +988,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'", ); - cases.addTest( + cases.add( "implicit casting too big integers to C pointers", \\export fn a() void { \\ var ptr: [*c]u8 = (1 << 64) + 1; @@ -1001,14 +1002,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'", ); - cases.addTest( + cases.add( "C pointer pointing to non C ABI compatible type or has align attr", \\const Foo = struct {}; \\export fn a() void { \\ const T = [*c]Foo; \\} , - "tmp.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", ); cases.addCase(x: { @@ -1029,7 +1030,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { break :x tc; }); - cases.addTest( + cases.add( "assign to invalid dereference", \\export fn entry() void { \\ 'a'.* = 1; @@ -1038,7 +1039,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'", ); - cases.addTest( + cases.add( "take slice of invalid dereference", \\export fn entry() void { \\ const x = 'a'.*[0..]; @@ -1047,7 +1048,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'", ); - cases.addTest( + cases.add( "@truncate undefined value", \\export fn entry() void { \\ var z = @truncate(u8, u16(undefined)); @@ -1935,7 +1936,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "unknown length pointer to opaque", \\export const T = [*]@OpaqueType(); , - "tmp.zig:1:18: error: unknown-length pointer to opaque", + "tmp.zig:1:21: error: unknown-length pointer to opaque", ); cases.add( @@ -2924,7 +2925,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() *noreturn {} \\export fn entry() void { _ = a(); } , - "tmp.zig:1:8: error: pointer to noreturn not allowed", + "tmp.zig:1:9: error: pointer to noreturn not allowed", ); cases.add( @@ -3606,8 +3607,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); } , "tmp.zig:5:25: error: unable to evaluate constant expression", - "tmp.zig:2:12: note: called from here", - "tmp.zig:2:8: note: called from here", + "tmp.zig:2:12: note: referenced here", + "tmp.zig:2:8: note: referenced here", ); cases.add( @@ -3701,7 +3702,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , "tmp.zig:3:14: error: division by zero", - "tmp.zig:1:14: note: called from here", + "tmp.zig:1:14: note: referenced here", ); cases.add( @@ -4133,7 +4134,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); } , "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches", - "tmp.zig:3:21: note: called from here", + "tmp.zig:1:37: note: referenced here", + "tmp.zig:6:50: note: referenced here", ); cases.add( @@ -4174,7 +4176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , "tmp.zig:6:26: error: unable to evaluate constant expression", - "tmp.zig:4:17: note: called from here", + "tmp.zig:4:17: note: referenced here", ); cases.add( @@ -4257,7 +4259,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , "tmp.zig:3:12: error: negation caused overflow", - "tmp.zig:1:14: note: called from here", + "tmp.zig:1:14: note: referenced here", ); cases.add( @@ -4270,7 +4272,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , "tmp.zig:3:14: error: operation caused overflow", - "tmp.zig:1:14: note: called from here", + "tmp.zig:1:14: note: referenced here", ); cases.add( @@ -4283,7 +4285,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , "tmp.zig:3:14: error: operation caused overflow", - "tmp.zig:1:14: note: called from here", + "tmp.zig:1:14: note: referenced here", ); cases.add( @@ -4296,7 +4298,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , "tmp.zig:3:14: error: operation caused overflow", - "tmp.zig:1:14: note: called from here", + "tmp.zig:1:14: note: referenced here", ); cases.add( @@ -4388,7 +4390,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:3:7: error: unable to evaluate constant expression", - "tmp.zig:16:19: note: called from here", + "tmp.zig:16:19: note: referenced here", ); cases.add( @@ -4618,7 +4620,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , "tmp.zig:2:26: error: index 1 outside argument list of size 1", - "tmp.zig:6:15: note: called from here", + "tmp.zig:6:15: note: referenced here", ); cases.add( @@ -4717,7 +4719,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:10:14: error: unable to evaluate constant expression", - "tmp.zig:6:20: note: called from here", + "tmp.zig:6:20: note: referenced here", ); cases.add( @@ -5864,7 +5866,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:4:25: error: aoeu", - "tmp.zig:1:36: note: called from here", + "tmp.zig:1:36: note: referenced here", "tmp.zig:12:20: note: referenced here", ); -- cgit v1.2.3 From db50cf7049b6171a280767e7b1cd0bd215848c92 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 22:38:45 -0400 Subject: fix more compile error regressions --- src/analyze.cpp | 41 +++++++++++++++++++++++++---------------- src/analyze.hpp | 1 + src/ir.cpp | 35 ++++++++++++++++++++++++++--------- test/compile_errors.zig | 10 ++++------ 4 files changed, 56 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 366cb59797..f1df64b17e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1603,14 +1603,17 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc } if (!calling_convention_allows_zig_types(fn_type_id.cc) && - fn_type_id.return_type->id != ZigTypeIdVoid && - !type_allowed_in_extern(g, fn_type_id.return_type)) + fn_type_id.return_type->id != ZigTypeIdVoid) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", - buf_ptr(&fn_type_id.return_type->name), - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; + if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown))) + return g->builtin_types.entry_invalid; + if (!type_allowed_in_extern(g, fn_type_id.return_type)) { + add_node_error(g, fn_proto->return_type, + buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", + buf_ptr(&fn_type_id.return_type->name), + calling_convention_name(fn_type_id.cc))); + return g->builtin_types.entry_invalid; + } } switch (fn_type_id.return_type->id) { @@ -2018,6 +2021,17 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { return ErrorNone; } +ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field) { + Error err; + if (union_field->type_entry == nullptr) { + if ((err = ir_resolve_lazy(g, union_field->decl_node, union_field->type_val))) { + return nullptr; + } + union_field->type_entry = union_field->type_val->data.x_type; + } + return union_field->type_entry; +} + static Error resolve_union_type(CodeGen *g, ZigType *union_type) { assert(union_type->id == ZigTypeIdUnion); @@ -2057,17 +2071,12 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { 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]; - - if (union_field->type_entry == nullptr) { - if ((err = ir_resolve_lazy(g, field_source_node, union_field->type_val))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - union_field->type_entry = union_field->type_val->data.x_type; + ZigType *field_type = resolve_union_field_type(g, union_field); + if (field_type == nullptr) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; } - ZigType *field_type = union_field->type_entry; if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; diff --git a/src/analyze.hpp b/src/analyze.hpp index 63ad905798..ef079a94cd 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -247,5 +247,6 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); bool fn_is_async(ZigFn *fn); Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align); +ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); #endif diff --git a/src/ir.cpp b/src/ir.cpp index f9f64d6789..eb87706c57 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6830,7 +6830,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod const char modifier = *buf_ptr(asm_output->constraint); if (modifier != '=') { add_node_error(irb->codegen, node, - buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported" + buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." " Compiler TODO: see https://github.com/ziglang/zig/issues/215", buf_ptr(asm_output->asm_symbolic_name), modifier)); return irb->codegen->invalid_instruction; @@ -8176,9 +8176,19 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable); } +static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) { + if (!exec || !exec->source_node || limit < 0) return; + add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); + + ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1); +} + static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); invalidate_exec(exec, err_msg); + if (exec->parent_exec) { + ir_add_call_stack_errors(codegen, exec, err_msg, 10); + } return err_msg; } @@ -10783,8 +10793,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod ir_gen(codegen, node, scope, ir_executable); if (ir_executable->first_err_trace_msg != nullptr) { - codegen->trace_err = add_error_note(codegen, ir_executable->first_err_trace_msg, - source_node, buf_create_from_str("called from here")); + codegen->trace_err = ir_executable->first_err_trace_msg; return &codegen->invalid_instruction->value; } @@ -11408,10 +11417,13 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so return ira->codegen->invalid_instruction; TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); assert(union_field != nullptr); - if ((err = type_resolve(ira->codegen, union_field->type_entry, ResolveStatusZeroBitsKnown))) + ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); + if (field_type == nullptr) + return ira->codegen->invalid_instruction; + if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; - switch (type_has_one_possible_value(ira->codegen, union_field->type_entry)) { + switch (type_has_one_possible_value(ira->codegen, field_type)) { case OnePossibleValueInvalid: return ira->codegen->invalid_instruction; case OnePossibleValueNo: { @@ -11420,7 +11432,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", buf_ptr(&wanted_type->name), - buf_ptr(&union_field->type_entry->name), + buf_ptr(&field_type->name), buf_ptr(union_field->name))); add_error_note(ira->codegen, msg, field_node, buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); @@ -11436,7 +11448,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); result->value.data.x_union.payload = create_const_vals(1); result->value.data.x_union.payload->special = ConstValSpecialStatic; - result->value.data.x_union.payload->type = union_field->type_entry; + result->value.data.x_union.payload->type = field_type; return result; } @@ -11453,12 +11465,17 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so buf_ptr(&wanted_type->name))); for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; - if (type_has_bits(union_field->type_entry)) { + ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); + if (field_type == nullptr) + return ira->codegen->invalid_instruction; + if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + if (type_has_bits(field_type)) { AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); add_error_note(ira->codegen, msg, field_node, buf_sprintf("field '%s' has type '%s'", buf_ptr(union_field->name), - buf_ptr(&union_field->type_entry->name))); + buf_ptr(&field_type->name))); } } return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 49c836f6a3..59687a6cc3 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -470,7 +470,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "Generic function where return type is self-referenced", + "generic function where return type is self-referenced", \\fn Foo(comptime T: type) Foo(T) { \\ return struct{ x: T }; \\} @@ -481,7 +481,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches", - "tmp.zig:1:29: note: referenced here", "tmp.zig:5:18: note: referenced here", ); @@ -3597,7 +3596,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "non constant expression in array size outside function", + "non constant expression in array size", \\const Foo = struct { \\ y: [get()]u8, \\}; @@ -3608,7 +3607,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , "tmp.zig:5:25: error: unable to evaluate constant expression", "tmp.zig:2:12: note: referenced here", - "tmp.zig:2:8: note: referenced here", ); cases.add( @@ -4620,7 +4618,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , "tmp.zig:2:26: error: index 1 outside argument list of size 1", - "tmp.zig:6:15: note: referenced here", + "tmp.zig:6:15: note: called from here", ); cases.add( @@ -5941,7 +5939,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: MultipleChoice = undefined; \\} , - "tmp.zig:2:14: error: non-enum union field assignment", + "tmp.zig:2:14: error: untagged union field assignment", "tmp.zig:1:24: note: consider 'union(enum)' here", ); -- cgit v1.2.3 From a2e8ef77e2087e26c1449c56ad16efcea71679db Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 22:49:59 -0400 Subject: fix regression in one of the doc examples --- src/ir.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/ir.cpp b/src/ir.cpp index eb87706c57..d98521de8f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14666,6 +14666,10 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; + if (align != 0) { + if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + } assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); pointee->type = var_type; -- cgit v1.2.3 From ffac0b02e75c9c620df11201ee70965856ba9ebf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Aug 2019 10:14:11 -0400 Subject: implement and test struct field explicit alignment --- src/analyze.cpp | 6 +++--- src/ir.cpp | 7 ++++--- test/stage1/behavior/align.zig | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index f1df64b17e..247788b949 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1896,9 +1896,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { break; } } - size_t next_abi_align = (next_src_field_index == field_count) ? - abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align; - next_offset = next_field_offset(next_offset, abi_align, field_type->abi_size, next_abi_align); + size_t next_align = (next_src_field_index == field_count) ? + abi_align : struct_type->data.structure.fields[next_src_field_index].align; + next_offset = next_field_offset(next_offset, abi_align, field_type->abi_size, next_align); size_in_bits = next_offset * 8; } } diff --git a/src/ir.cpp b/src/ir.cpp index d98521de8f..be0fd1ba64 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17127,6 +17127,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing) { + Error err; switch (type_has_one_possible_value(ira->codegen, field->type_entry)) { case OnePossibleValueInvalid: return ira->codegen->invalid_instruction; @@ -17137,9 +17138,9 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction case OnePossibleValueNo: break; } + if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; assert(struct_ptr->value.type->id == ZigTypeIdPointer); - bool is_packed = (struct_type->data.structure.layout == ContainerLayoutPacked); - uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? @@ -17147,7 +17148,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction bool is_const = struct_ptr->value.type->data.pointer.is_const; bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, - is_const, is_volatile, PtrLenSingle, align_bytes, + is_const, is_volatile, PtrLenSingle, field->align, (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), (uint32_t)host_int_bytes_for_result_type, false); if (instr_is_comptime(struct_ptr)) { diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index f607ac59d2..677ae85b68 100644 --- a/test/stage1/behavior/align.zig +++ b/test/stage1/behavior/align.zig @@ -290,3 +290,18 @@ test "read 128-bit field from default aligned struct in global memory" { expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); expect(12 == default_aligned_global.badguy); } + +test "struct field explicit alignment" { + const S = struct { + const Node = struct { + next: *Node, + massive_byte: u8 align(64), + }; + }; + + var node: S.Node = undefined; + node.massive_byte = 100; + expect(node.massive_byte == 100); + comptime expect(@typeOf(&node.massive_byte) == *align(64) u8); + expect(@ptrToInt(&node.massive_byte) % 64 == 0); +} -- cgit v1.2.3 From 7d34e55a71b1d929c6e847337a3639f3e65a547e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Aug 2019 10:45:15 -0400 Subject: add a TODO compile error for union field alignment syntax See #3125 --- src/analyze.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/analyze.cpp b/src/analyze.cpp index 247788b949..dde6e3defc 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1965,6 +1965,8 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return err; } + add_node_error(g, field->decl_node, + buf_create_from_str("TODO implement field alignment syntax for unions. https://github.com/ziglang/zig/issues/3125")); } else if (packed) { field->align = 1; } else if (field->type_entry != nullptr) { -- cgit v1.2.3 From d9ed55f017bdd23054cd1d7f50ac1da517b5a5e4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Aug 2019 12:54:50 -0400 Subject: fix not properly casting align values and add check for alignment specified on enum fields --- src/all_types.hpp | 43 ++++++------- src/analyze.cpp | 19 +++--- src/ir.cpp | 156 +++++++++++++++++++++++------------------------- test/compile_errors.zig | 27 +++++++++ 4 files changed, 137 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/all_types.hpp b/src/all_types.hpp index 3145635b45..83dcb8ba10 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -315,58 +315,61 @@ enum LazyValueId { }; struct LazyValue { - IrExecutable *exec; LazyValueId id; }; struct LazyValueAlignOf { LazyValue base; - ConstExprValue *target_type_val; - AstNode *target_type_src_node; + IrAnalyze *ira; + IrInstruction *target_type; }; struct LazyValueSliceType { LazyValue base; + + IrAnalyze *ira; + ZigType *elem_type; + IrInstruction *align_inst; // can be null + bool is_const; bool is_volatile; bool is_allowzero; - - ZigType *elem_type; - ConstExprValue *align_val; // can be null }; struct LazyValuePtrType { LazyValue base; - bool is_const; - bool is_volatile; - bool is_allowzero; - ConstExprValue *elem_type_val; - AstNode *elem_type_src_node; - ConstExprValue *align_val; // can be null + IrAnalyze *ira; + IrInstruction *elem_type; + IrInstruction *align_inst; // can be null + PtrLen ptr_len; uint32_t bit_offset_in_host; + uint32_t host_int_bytes; + bool is_const; + bool is_volatile; + bool is_allowzero; }; struct LazyValueOptType { LazyValue base; - ConstExprValue *payload_type_val; - AstNode *payload_type_src_node; + IrAnalyze *ira; + IrInstruction *payload_type; }; struct LazyValueFnType { LazyValue base; - bool is_generic; + IrAnalyze *ira; AstNode *proto_node; - ConstExprValue **param_types; - AstNode **param_type_src_nodes; - ConstExprValue *align_val; // can be null - ConstExprValue *return_type; - AstNode *return_type_src_node; + IrInstruction **param_types; + IrInstruction *align_inst; // can be null + IrInstruction *return_type; + + bool is_generic; }; struct ConstExprValue { diff --git a/src/analyze.cpp b/src/analyze.cpp index dde6e3defc..e0223dd9f7 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1000,7 +1000,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - if (parent_type_val == lazy_ptr_type->elem_type_val) { + if (parent_type_val == &lazy_ptr_type->elem_type->value) { // Does a struct which contains a pointer field to itself have bits? Yes. *is_zero_bits = false; return ErrorNone; @@ -1008,7 +1008,7 @@ static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, Zi if (parent_type_val == nullptr) { parent_type_val = type_val; } - return type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type_val, parent_type, + return type_val_resolve_zero_bits(g, &lazy_ptr_type->elem_type->value, parent_type, parent_type_val, is_zero_bits); } } @@ -1061,17 +1061,17 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue } 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); + return type_val_resolve_requires_comptime(g, &lazy_ptr_type->elem_type->value); } case LazyValueIdOptType: { LazyValueOptType *lazy_opt_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_opt_type->payload_type_val); + return type_val_resolve_requires_comptime(g, &lazy_opt_type->payload_type->value); } 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)) { + switch (type_val_resolve_requires_comptime(g, &lazy_fn_type->return_type->value)) { case ReqCompTimeInvalid: return ReqCompTimeInvalid; case ReqCompTimeYes: @@ -1084,7 +1084,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])) { + switch (type_val_resolve_requires_comptime(g, &lazy_fn_type->param_types[i]->value)) { case ReqCompTimeInvalid: return ReqCompTimeInvalid; case ReqCompTimeYes: @@ -1124,7 +1124,7 @@ Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t return ErrorNone; case LazyValueIdOptType: { LazyValueOptType *lazy_opt_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_abi_align(g, lazy_opt_type->payload_type_val, abi_align); + return type_val_resolve_abi_align(g, &lazy_opt_type->payload_type->value, abi_align); } } zig_unreachable(); @@ -2245,6 +2245,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { buf_sprintf("structs and unions, not enums, support field types")); add_error_note(g, msg, decl_node, buf_sprintf("consider 'union(enum)' here")); + } else if (field_node->data.struct_field.align_expr != nullptr) { + ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.align_expr, + buf_sprintf("structs and unions, not enums, support field alignment")); + add_error_note(g, msg, decl_node, + buf_sprintf("consider 'union(enum)' here")); } auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field); diff --git a/src/ir.cpp b/src/ir.cpp index be0fd1ba64..c1656a1711 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16190,14 +16190,13 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp result->value.special = ConstValSpecialLazy; LazyValueOptType *lazy_opt_type = allocate(1); + lazy_opt_type->ira = ira; result->value.data.x_lazy = &lazy_opt_type->base; lazy_opt_type->base.id = LazyValueIdOptType; - lazy_opt_type->base.exec = ira->new_irb.exec; - lazy_opt_type->payload_type_val = ir_resolve_type_lazy(ira, instruction->value->child); - if (lazy_opt_type->payload_type_val == nullptr) + lazy_opt_type->payload_type = instruction->value->child; + if (ir_resolve_type_lazy(ira, lazy_opt_type->payload_type) == nullptr) return ira->codegen->invalid_instruction; - lazy_opt_type->payload_type_src_node = instruction->value->source_node; return result; } @@ -17936,13 +17935,13 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, result->value.special = ConstValSpecialLazy; LazyValueSliceType *lazy_slice_type = allocate(1); + lazy_slice_type->ira = ira; result->value.data.x_lazy = &lazy_slice_type->base; lazy_slice_type->base.id = LazyValueIdSliceType; - lazy_slice_type->base.exec = ira->new_irb.exec; if (slice_type_instruction->align_value != nullptr) { - lazy_slice_type->align_val = ir_resolve_const(ira, slice_type_instruction->align_value->child, LazyOk); - if (lazy_slice_type->align_val == nullptr) + lazy_slice_type->align_inst = slice_type_instruction->align_value->child; + if (ir_resolve_const(ira, lazy_slice_type->align_inst, LazyOk) == nullptr) return ira->codegen->invalid_instruction; } @@ -22371,14 +22370,13 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct result->value.special = ConstValSpecialLazy; LazyValueAlignOf *lazy_align_of = allocate(1); + lazy_align_of->ira = ira; result->value.data.x_lazy = &lazy_align_of->base; lazy_align_of->base.id = LazyValueIdAlignOf; - lazy_align_of->base.exec = ira->new_irb.exec; - lazy_align_of->target_type_val = ir_resolve_type_lazy(ira, instruction->type_value->child); - if (lazy_align_of->target_type_val == nullptr) + lazy_align_of->target_type = instruction->type_value->child; + if (ir_resolve_type_lazy(ira, lazy_align_of->target_type) == nullptr) return ira->codegen->invalid_instruction; - lazy_align_of->target_type_src_node = instruction->type_value->source_node; return result; } @@ -22856,9 +22854,9 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct result->value.special = ConstValSpecialLazy; LazyValueFnType *lazy_fn_type = allocate(1); + lazy_fn_type->ira = ira; result->value.data.x_lazy = &lazy_fn_type->base; lazy_fn_type->base.id = LazyValueIdFnType; - lazy_fn_type->base.exec = ira->new_irb.exec; if (proto_node->data.fn_proto.auto_err_set) { ir_add_error(ira, &instruction->base, @@ -22868,8 +22866,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct size_t param_count = proto_node->data.fn_proto.params.length; lazy_fn_type->proto_node = proto_node; - lazy_fn_type->param_types = allocate(param_count); - lazy_fn_type->param_type_src_nodes = allocate(param_count); + lazy_fn_type->param_types = allocate(param_count); for (size_t param_index = 0; param_index < param_count; param_index += 1) { AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); @@ -22895,23 +22892,20 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct IrInstruction *param_type_value = instruction->param_types[param_index]->child; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; - ConstExprValue *param_type_val = ir_resolve_const(ira, param_type_value, LazyOk); - if (param_type_val == nullptr) + if (ir_resolve_const(ira, param_type_value, LazyOk) == nullptr) return ira->codegen->invalid_instruction; - lazy_fn_type->param_types[param_index] = param_type_val; - lazy_fn_type->param_type_src_nodes[param_index] = instruction->param_types[param_index]->source_node; + lazy_fn_type->param_types[param_index] = param_type_value; } if (instruction->align_value != nullptr) { - lazy_fn_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk); - if (lazy_fn_type->align_val == nullptr) + lazy_fn_type->align_inst = instruction->align_value->child; + if (ir_resolve_const(ira, lazy_fn_type->align_inst, LazyOk) == nullptr) return ira->codegen->invalid_instruction; } - lazy_fn_type->return_type = ir_resolve_const(ira, instruction->return_type->child, LazyOk); - if (lazy_fn_type->return_type == nullptr) + lazy_fn_type->return_type = instruction->return_type->child; + if (ir_resolve_const(ira, lazy_fn_type->return_type, LazyOk) == nullptr) return ira->codegen->invalid_instruction; - lazy_fn_type->return_type_src_node = instruction->return_type->source_node; return result; } @@ -23890,18 +23884,17 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct result->value.special = ConstValSpecialLazy; LazyValuePtrType *lazy_ptr_type = allocate(1); + lazy_ptr_type->ira = ira; result->value.data.x_lazy = &lazy_ptr_type->base; lazy_ptr_type->base.id = LazyValueIdPtrType; - lazy_ptr_type->base.exec = ira->new_irb.exec; - lazy_ptr_type->elem_type_val = ir_resolve_type_lazy(ira, instruction->child_type->child); - if (lazy_ptr_type->elem_type_val == nullptr) + lazy_ptr_type->elem_type = instruction->child_type->child; + if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) return ira->codegen->invalid_instruction; - lazy_ptr_type->elem_type_src_node = instruction->child_type->source_node; if (instruction->align_value != nullptr) { - lazy_ptr_type->align_val = ir_resolve_const(ira, instruction->align_value->child, LazyOk); - if (lazy_ptr_type->align_val == nullptr) + lazy_ptr_type->align_inst = instruction->align_value->child; + if (ir_resolve_const(ira, lazy_ptr_type->align_inst, LazyOk) == nullptr) return ira->codegen->invalid_instruction; } @@ -25446,9 +25439,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { zig_unreachable(); } -static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, - LazyValueFnType *lazy_fn_type) -{ +static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, LazyValueFnType *lazy_fn_type) { Error err; AstNode *proto_node = lazy_fn_type->proto_node; @@ -25465,7 +25456,7 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As fn_type_id.param_count = fn_type_id.next_param_index; continue; } else if (fn_type_id.cc == CallingConventionUnspecified) { - return get_generic_fn_type(codegen, &fn_type_id); + return get_generic_fn_type(ira->codegen, &fn_type_id); } else { zig_unreachable(); } @@ -25475,34 +25466,33 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) { param_info->type = nullptr; - return get_generic_fn_type(codegen, &fn_type_id); + return get_generic_fn_type(ira->codegen, &fn_type_id); } else { - AstNode *param_src_node = lazy_fn_type->param_type_src_nodes[fn_type_id.next_param_index]; - ZigType *param_type = ir_resolve_const_type(codegen, exec, param_src_node, - lazy_fn_type->param_types[fn_type_id.next_param_index]); + IrInstruction *param_type_inst = lazy_fn_type->param_types[fn_type_id.next_param_index]; + ZigType *param_type = ir_resolve_type(ira, param_type_inst); if (type_is_invalid(param_type)) return nullptr; - switch (type_requires_comptime(codegen, param_type)) { + switch (type_requires_comptime(ira->codegen, param_type)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - exec_add_error_node(codegen, exec, param_src_node, + ir_add_error(ira, param_type_inst, buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); return nullptr; } param_info->type = param_type; fn_type_id.next_param_index += 1; - return get_generic_fn_type(codegen, &fn_type_id); + return get_generic_fn_type(ira->codegen, &fn_type_id); case ReqCompTimeInvalid: return nullptr; case ReqCompTimeNo: break; } if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - if ((err = type_resolve(codegen, param_type, ResolveStatusZeroBitsKnown))) + if ((err = type_resolve(ira->codegen, param_type, ResolveStatusZeroBitsKnown))) return nullptr; if (!type_has_bits(param_type)) { - exec_add_error_node(codegen, exec, param_src_node, + ir_add_error(ira, param_type_inst, buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); return nullptr; @@ -25512,37 +25502,35 @@ static ZigType *ir_resolve_lazy_fn_type(CodeGen *codegen, IrExecutable *exec, As } } - if (lazy_fn_type->align_val != nullptr) { - if (!ir_resolve_const_align(codegen, exec, source_node, lazy_fn_type->align_val, &fn_type_id.alignment)) + if (lazy_fn_type->align_inst != nullptr) { + if (!ir_resolve_align(ira, lazy_fn_type->align_inst, &fn_type_id.alignment)) return nullptr; } - fn_type_id.return_type = ir_resolve_const_type(codegen, exec, lazy_fn_type->return_type_src_node, - lazy_fn_type->return_type); + fn_type_id.return_type = ir_resolve_type(ira, lazy_fn_type->return_type); if (type_is_invalid(fn_type_id.return_type)) return nullptr; if (fn_type_id.return_type->id == ZigTypeIdOpaque) { - exec_add_error_node(codegen, exec, lazy_fn_type->return_type_src_node, - buf_create_from_str("return type cannot be opaque")); + ir_add_error(ira, lazy_fn_type->return_type, buf_create_from_str("return type cannot be opaque")); return nullptr; } - return get_fn_type(codegen, &fn_type_id); + return get_fn_type(ira->codegen, &fn_type_id); } -static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { +static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { Error err; if (val->special != ConstValSpecialLazy) return ErrorNone; - IrExecutable *exec = val->data.x_lazy->exec; switch (val->data.x_lazy->id) { case LazyValueIdInvalid: zig_unreachable(); case LazyValueIdAlignOf: { LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); + IrAnalyze *ira = lazy_align_of->ira; - if (lazy_align_of->target_type_val->special == ConstValSpecialStatic) { - switch (lazy_align_of->target_type_val->data.x_type->id) { + if (lazy_align_of->target_type->value.special == ConstValSpecialStatic) { + switch (lazy_align_of->target_type->value.data.x_type->id) { case ZigTypeIdInvalid: zig_unreachable(); case ZigTypeIdMetaType: @@ -25556,9 +25544,9 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx case ZigTypeIdArgTuple: case ZigTypeIdVoid: case ZigTypeIdOpaque: - exec_add_error_node(codegen, exec, lazy_align_of->target_type_src_node, + ir_add_error(ira, lazy_align_of->target_type, buf_sprintf("no align available for type '%s'", - buf_ptr(&lazy_align_of->target_type_val->data.x_type->name))); + buf_ptr(&lazy_align_of->target_type->value.data.x_type->name))); return ErrorSemanticAnalyzeFail; case ZigTypeIdBool: case ZigTypeIdInt: @@ -25580,8 +25568,11 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx } uint32_t align_in_bytes; - if ((err = type_val_resolve_abi_align(codegen, lazy_align_of->target_type_val, &align_in_bytes))) + if ((err = type_val_resolve_abi_align(ira->codegen, &lazy_align_of->target_type->value, + &align_in_bytes))) + { return err; + } val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdComptimeInt); @@ -25590,69 +25581,72 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx } case LazyValueIdSliceType: { LazyValueSliceType *lazy_slice_type = reinterpret_cast(val->data.x_lazy); + IrAnalyze *ira = lazy_slice_type->ira; + uint32_t align_bytes = 0; - if (lazy_slice_type->align_val != nullptr) { - if (!ir_resolve_const_align(codegen, exec, source_node, lazy_slice_type->align_val, &align_bytes)) + if (lazy_slice_type->align_inst != nullptr) { + if (!ir_resolve_align(ira, lazy_slice_type->align_inst, &align_bytes)) return ErrorSemanticAnalyzeFail; } ResolveStatus needed_status = (align_bytes == 0) ? ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; - if ((err = type_resolve(codegen, lazy_slice_type->elem_type, needed_status))) + if ((err = type_resolve(ira->codegen, lazy_slice_type->elem_type, needed_status))) return err; - ZigType *slice_ptr_type = get_pointer_to_type_extra(codegen, lazy_slice_type->elem_type, + ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, lazy_slice_type->elem_type, lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes, 0, 0, lazy_slice_type->is_allowzero); val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_slice_type(codegen, slice_ptr_type); + val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); return ErrorNone; } case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); + IrAnalyze *ira = lazy_ptr_type->ira; + uint32_t align_bytes = 0; - if (lazy_ptr_type->align_val != nullptr) { - if (!ir_resolve_const_align(codegen, exec, source_node, lazy_ptr_type->align_val, &align_bytes)) + if (lazy_ptr_type->align_inst != nullptr) { + if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, &align_bytes)) return ErrorSemanticAnalyzeFail; } - ZigType *elem_type = ir_resolve_const_type(codegen, exec, lazy_ptr_type->elem_type_src_node, - lazy_ptr_type->elem_type_val); + ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); if (type_is_invalid(elem_type)) return ErrorSemanticAnalyzeFail; if (elem_type->id == ZigTypeIdUnreachable) { - exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + ir_add_error(ira, lazy_ptr_type->elem_type, buf_create_from_str("pointer to noreturn not allowed")); return ErrorSemanticAnalyzeFail; } else if (elem_type->id == ZigTypeIdOpaque && lazy_ptr_type->ptr_len == PtrLenUnknown) { - exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + ir_add_error(ira, lazy_ptr_type->elem_type, buf_create_from_str("unknown-length pointer to opaque")); return ErrorSemanticAnalyzeFail; } else if (lazy_ptr_type->ptr_len == PtrLenC) { - if (!type_allowed_in_extern(codegen, elem_type)) { - exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + if (!type_allowed_in_extern(ira->codegen, elem_type)) { + ir_add_error(ira, lazy_ptr_type->elem_type, buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&elem_type->name))); return ErrorSemanticAnalyzeFail; } else if (elem_type->id == ZigTypeIdOpaque) { - exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + ir_add_error(ira, lazy_ptr_type->elem_type, buf_sprintf("C pointers cannot point opaque types")); return ErrorSemanticAnalyzeFail; } else if (lazy_ptr_type->is_allowzero) { - exec_add_error_node(codegen, exec, lazy_ptr_type->elem_type_src_node, + ir_add_error(ira, lazy_ptr_type->elem_type, buf_sprintf("C pointers always allow address zero")); return ErrorSemanticAnalyzeFail; } } if (align_bytes != 0) { - if ((err = type_resolve(codegen, elem_type, ResolveStatusAlignmentKnown))) + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) return err; if (!type_has_bits(elem_type)) align_bytes = 0; } bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra(codegen, elem_type, + val->data.x_type = get_pointer_to_type_extra(ira->codegen, elem_type, lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, allow_zero); @@ -25661,29 +25655,29 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx } case LazyValueIdOptType: { LazyValueOptType *lazy_opt_type = reinterpret_cast(val->data.x_lazy); + IrAnalyze *ira = lazy_opt_type->ira; - ZigType *payload_type = ir_resolve_const_type(codegen, exec, lazy_opt_type->payload_type_src_node, - lazy_opt_type->payload_type_val); + ZigType *payload_type = ir_resolve_type(ira, lazy_opt_type->payload_type); if (type_is_invalid(payload_type)) return ErrorSemanticAnalyzeFail; if (payload_type->id == ZigTypeIdOpaque || payload_type->id == ZigTypeIdUnreachable) { - exec_add_error_node(codegen, exec, lazy_opt_type->payload_type_src_node, + ir_add_error(ira, lazy_opt_type->payload_type, buf_sprintf("type '%s' cannot be optional", buf_ptr(&payload_type->name))); return ErrorSemanticAnalyzeFail; } - if ((err = type_resolve(codegen, payload_type, ResolveStatusSizeKnown))) + if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) return err; assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_optional_type(codegen, payload_type); + val->data.x_type = get_optional_type(ira->codegen, payload_type); val->special = ConstValSpecialStatic; return ErrorNone; } case LazyValueIdFnType: { - ZigType *fn_type = ir_resolve_lazy_fn_type(codegen, exec, source_node, - reinterpret_cast(val->data.x_lazy)); + LazyValueFnType *lazy_fn_type = reinterpret_cast(val->data.x_lazy); + ZigType *fn_type = ir_resolve_lazy_fn_type(lazy_fn_type->ira, source_node, lazy_fn_type); if (fn_type == nullptr) return ErrorSemanticAnalyzeFail; val->special = ConstValSpecialStatic; @@ -25697,7 +25691,7 @@ static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstEx Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { Error err; - if ((err = ir_resolve_lazy_raw(codegen, source_node, val))) { + if ((err = ir_resolve_lazy_raw(source_node, val))) { if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) { source_node->already_traced_this_node = true; codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 59687a6cc3..bc2d43706f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,33 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "alignment of enum field specified", + \\const Number = enum { + \\ a, + \\ b align(i32), + \\}; + \\export fn entry1() void { + \\ var x: Number = undefined; + \\} + , + "tmp.zig:3:13: error: structs and unions, not enums, support field alignment", + "tmp.zig:1:16: note: consider 'union(enum)' here", + ); + + cases.add( + "bad alignment type", + \\export fn entry1() void { + \\ var x: []align(true) i32 = undefined; + \\} + \\export fn entry2() void { + \\ var x: *align(f64(12.34)) i32 = undefined; + \\} + , + "tmp.zig:2:20: error: expected type 'u29', found 'bool'", + "tmp.zig:5:22: error: fractional component prevents float value 12.340000 from being casted to type 'u29'", + ); + cases.addCase(x: { var tc = cases.create("variable in inline assembly template cannot be found", \\export fn entry() void { -- cgit v1.2.3