From efdbede7abf91d5fe2836d95987a83e95e9fcf8e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 21 Aug 2019 19:20:18 -0400 Subject: [PATCH 01/32] 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 | 345 ++++++++++++++++------------------------------ src/analyze.hpp | 6 +- src/ir.cpp | 133 ++++++++++-------- src/ir.hpp | 2 - 5 files changed, 202 insertions(+), 313 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 559ebe8cda53a8fb89f4b69404681ba0f3731764..c5a30b75cc266ff4429dbae0d8807a6d607d5968 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 a06bba3f2ad15eb30318d8a339e636365dc69b5a..8fd80d0a080b66f99a017db5bf2c9661ec040f2b 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,25 +1904,26 @@ 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; - 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); + 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.resolve_loop_flag = true; + assert(!enum_type->data.enumeration.fields); uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; if (field_count == 0) { @@ -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 5752c747512be7cde6b124bfda215b2d88444822..5613c182318a430342edfdc28831591489330c15 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 cdddce1b187e2bdcf39a5b5f50bfa5e02cb86b88..aa5b69649d9264d07a59192be6807347974a1f18 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 3761c5a97d710c2acc84cd7b6f7311eaea44311e..597624e2e67448c1d42fe34154d97def52c54e96 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 -- 2.54.0 From 8460d5617cc12d614abf39f55ab85c783c4b35a8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 12:07:56 -0400 Subject: [PATCH 02/32] 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 diff --git a/BRANCH_TODO b/BRANCH_TODO new file mode 100644 index 0000000000000000000000000000000000000000..9df8ba2ca75a2b3751aa13f0e5418b123d1d18dd --- /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 c5a30b75cc266ff4429dbae0d8807a6d607d5968..de82159d27b08434239ded41b2a3b3c4b1e002df 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 8fd80d0a080b66f99a017db5bf2c9661ec040f2b..0a5de5fd3679ba8915d3c4ce7931ceef51737669 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 5613c182318a430342edfdc28831591489330c15..d62d176cc544ec258c5ffe87f35ecaa0b4f7f9f1 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 622ade712a348c19665953c277e7c45f8cf0377a..2be4ebbbc9a1d8d97dbed448458784b090e96826 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 aa5b69649d9264d07a59192be6807347974a1f18..9c9a28ee56e293521309c4fe39c95fdb62c28ce0 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)) + 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; - 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))) - 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 597624e2e67448c1d42fe34154d97def52c54e96..200a92b64f4274f90735083709022ed77d60795f 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); -- 2.54.0 From 0d6a6c76eabcd020c5f58dc4667766b0e2756dfa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 12:55:09 -0400 Subject: [PATCH 03/32] add missing "referenced here" notes for lazy values --- src/analyze.cpp | 6 +++--- src/ir.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 0a5de5fd3679ba8915d3c4ce7931ceef51737669..ee67f259f03f6e68468fb435e7b8cfc596e3432b 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 9c9a28ee56e293521309c4fe39c95fdb62c28ce0..e64098be0149270eb0dcb7fa9327b58c42e7a4c9 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; -- 2.54.0 From 26b79ac90ee8cf17f28b0584c773be759e0e49bd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 14:46:26 -0400 Subject: [PATCH 04/32] simple self-referential struct is working now --- src/analyze.cpp | 216 +++++++++++++++++++++++++++++++++++++++--------- src/ir.cpp | 18 ++-- 2 files changed, 190 insertions(+), 44 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index ee67f259f03f6e68468fb435e7b8cfc596e3432b..a4ee17d56cb45a2e85fa415cdcf5a06f29ba512c 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; + } + 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; - } 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) { - 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)) { + 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); - - 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))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - this_field_align = field->type_entry->abi_align; - } - // TODO: https://github.com/ziglang/zig/issues/1512 + size_t this_field_align; + if (packed) { + this_field_align = 1; + } else { + if ((err = type_val_resolve_abi_align(g, field->type_val, &this_field_align))) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return err; + } + } + 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 e64098be0149270eb0dcb7fa9327b58c42e7a4c9..92b85984420928715234410f64abb0d9baae8496 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; +} -- 2.54.0 From 79a4b7a2365dc50d01eb6bc29bbb77244a1620cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Aug 2019 18:24:15 -0400 Subject: [PATCH 05/32] fix regressions --- src/analyze.cpp | 19 ++- src/ir.cpp | 409 ++++++++++++++++++++++++++++-------------------- 2 files changed, 254 insertions(+), 174 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index a4ee17d56cb45a2e85fa415cdcf5a06f29ba512c..414ce09b2caafda0f78d070f9d5d7a4a9ea31e70 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 92b85984420928715234410f64abb0d9baae8496..c545109d2428011689bf601e07020cea56803911 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; + ConstExprValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); + if (byte_val == nullptr) + return ira->codegen->invalid_instruction; + + ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); + if (count_val == nullptr) + return ira->codegen->invalid_instruction; + + 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 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"); - } + 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"); + } - 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")); - return ira->codegen->invalid_instruction; - } + 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; + } - ConstExprValue *byte_val = &casted_byte->value; - for (size_t i = start; i < end; i += 1) { - copy_const_val(&dest_elements[i], byte_val, true); - } + 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); + 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"); + } + + if (src_start + count > src_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } - return ir_const_void(ira, &instruction->base); + // 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); -- 2.54.0 From 20049caaba0354754811ae0d36a773c31cf4578a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 13:28:26 -0400 Subject: [PATCH 06/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 3e811311b0eab3de622808457cef4b4a310068bc..595df7460f209bec1890f432d25fac511810952c 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 84299a5c8b5f7c0c2fcdaeb7e6fdf5502888429f..c08f954e18be601d4656a9dee0b6d457ee68fcaa 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 d62d176cc544ec258c5ffe87f35ecaa0b4f7f9f1..740b47ac1d1445e3300249f05ee66f94bedd7b7e 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 789126cf67b6034ae6c216d7954f102ec0f971c7..2970f536b9e93d25f94020ab3f8db5812facd43f 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(); } -- 2.54.0 From 1dd658d1d02f8dfc432bcda88fdb542189c31725 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 14:07:34 -0400 Subject: [PATCH 07/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 595df7460f209bec1890f432d25fac511810952c..11bed48e8fac7221d8ba2ce7674795854271fc92 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 c08f954e18be601d4656a9dee0b6d457ee68fcaa..bfdeb5d41a2f93ddddc39638d0ba20c85dfd97e0 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 740b47ac1d1445e3300249f05ee66f94bedd7b7e..cd855522f354e21725d2466aea60eadfeae7e730 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 cfeb0187eb6e3cea59170d167c984c9fb6def938..29c3a301589836cefd9f6d94d505673f070b5cc1 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 2970f536b9e93d25f94020ab3f8db5812facd43f..5f4cce328a24d677826a59fbf2d1f7bebf7a14dd 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; } -- 2.54.0 From be0a9a72772566667d4c225972c6bc7c17b751ef Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 15:05:15 -0400 Subject: [PATCH 08/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 11bed48e8fac7221d8ba2ce7674795854271fc92..d23020593db3341a38c9e1fc72e403b8c5c2993e 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 bfdeb5d41a2f93ddddc39638d0ba20c85dfd97e0..f140489ab3c4f3caa282c5f293268d82e4613d0b 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 5f4cce328a24d677826a59fbf2d1f7bebf7a14dd..13ae0715a441f219568b1ca46370caa4ccfa2b07 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 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 &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, &type_value->value); + 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); -- 2.54.0 From ac4dd9d665ba195a6b21b3b033f27c865015ccac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 15:54:51 -0400 Subject: [PATCH 09/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index d23020593db3341a38c9e1fc72e403b8c5c2993e..2a20d3c860b2b0322e5c132cb55291c1dcef0fcf 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 f140489ab3c4f3caa282c5f293268d82e4613d0b..f6e8a77770db32332710b05826ef218d6ddbba67 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 cd855522f354e21725d2466aea60eadfeae7e730..0da9ec09afae17c361b33ba160d709ad8cf9e2fb 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 29c3a301589836cefd9f6d94d505673f070b5cc1..930818ab4233fd61bdd330fbb010ef94f12f2fb4 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 13ae0715a441f219568b1ca46370caa4ccfa2b07..70dc894f8685362f7ce65025b9af9f80cbbdc3f4 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, -- 2.54.0 From f0034495fa74d7a2c36e4a75520f030bb0cdb16a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 15:59:37 -0400 Subject: [PATCH 10/32] fix regression with simple pointer to self --- src/analyze.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index f6e8a77770db32332710b05826ef218d6ddbba67..0b65210eea8a4fb6f600e8299618b94413b6e605 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); -- 2.54.0 From 101440c1990de653bbfb19713915d86d7a5bc182 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 17:14:51 -0400 Subject: [PATCH 11/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 2a20d3c860b2b0322e5c132cb55291c1dcef0fcf..61dde995afb7d4ccf92b3b8c0699bf500733e5a1 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 0b65210eea8a4fb6f600e8299618b94413b6e605..5159dbb05a4b766cc73fdd2ec4926e012f4da6dd 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 70dc894f8685362f7ce65025b9af9f80cbbdc3f4..2f38b422210b9d631c79f983c1bd50c41acbdef1 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; + + 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; - 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(); + 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)); -- 2.54.0 From e8bad1e12a972ce26aeedd37bf49a6751bab2b76 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 17:39:56 -0400 Subject: [PATCH 12/32] 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(-) diff --git a/src/ir.cpp b/src/ir.cpp index 2f38b422210b9d631c79f983c1bd50c41acbdef1..558dbca265430d2fd864fc7f7d9bb7faaaa7af49 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); -- 2.54.0 From d277a1196b85cf51a22f7c6b41ad0df7804c71bd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 23 Aug 2019 17:54:01 -0400 Subject: [PATCH 13/32] tracking these issues on github now --- BRANCH_TODO | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 BRANCH_TODO diff --git a/BRANCH_TODO b/BRANCH_TODO deleted file mode 100644 index 9df8ba2ca75a2b3751aa13f0e5418b123d1d18dd..0000000000000000000000000000000000000000 --- a/BRANCH_TODO +++ /dev/null @@ -1,3 +0,0 @@ -* slice type and ptr type instructions need to implicit cast alignment -* fix regressions of error notes with "called from here" -* fix tests -- 2.54.0 From fa6c20a02d2ee7648f69d9ba3b19fa600e8dd0e9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 11:34:07 -0400 Subject: [PATCH 14/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 61dde995afb7d4ccf92b3b8c0699bf500733e5a1..4b8a9c430877c1bf6e59ac02c3d30292cc85d9f5 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 5159dbb05a4b766cc73fdd2ec4926e012f4da6dd..7c967b4e5c6ea38129d73bb01110d8b021c61cb6 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_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; + } - switch (type_requires_comptime(g, field_type)) { - case ReqCompTimeInvalid: + 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 930818ab4233fd61bdd330fbb010ef94f12f2fb4..ed6ef6367dac6fc3985ab5fbe23ec684882adc29 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) { -- 2.54.0 From 8f41da221690a8dbbbce41a07513715b9a31e70a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 11:42:19 -0400 Subject: [PATCH 15/32] fix behavior test regressions with unions --- src/analyze.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 7c967b4e5c6ea38129d73bb01110d8b021c61cb6..5e0abea5df886a8713b4853f1f1de635e249709e 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(); } -- 2.54.0 From 64e9b0ee4673bf79d42ea14e354b324308f90b93 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 20:27:56 -0400 Subject: [PATCH 16/32] 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(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 5e0abea5df886a8713b4853f1f1de635e249709e..34e9605bdc911fef954cae133cca5f6afa8af6ed 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 558dbca265430d2fd864fc7f7d9bb7faaaa7af49..3aabb4995fd441c1238ad2cb2e2f812c41ab4933 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, -- 2.54.0 From a7f31581850fe2811bc5114459a8d193dd48b42a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 21:16:03 -0400 Subject: [PATCH 17/32] behavior tests passing --- src/analyze.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 34e9605bdc911fef954cae133cca5f6afa8af6ed..2ee0322db11edbee032cc147ecdd1ad62ec71ec8 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; -- 2.54.0 From 720302a6407e954ffccf65f38ad40b47868627ce Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 21:28:16 -0400 Subject: [PATCH 18/32] fix resolution detection of pointer types --- src/analyze.cpp | 15 ++++++++++++++- src/ir.cpp | 21 ++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 2ee0322db11edbee032cc147ecdd1ad62ec71ec8..181cab2332828e96f39a5b8b8a230e796c415689 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 3aabb4995fd441c1238ad2cb2e2f812c41ab4933..d9f7e37e8e992bf3826a271c5c73f1721bdc4d18 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; } -- 2.54.0 From b13af0750fbe8b38a95b05ec78c8364281fcf477 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 25 Aug 2019 21:45:11 -0400 Subject: [PATCH 19/32] fix assertion tripped instead of reporting compile error --- src/ir.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index d9f7e37e8e992bf3826a271c5c73f1721bdc4d18..34c6985c6acdb3fadcd33e3bddd9263a4db68cfa 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); -- 2.54.0 From ede0c22a6796600cfc4555e9ac2f0481c41c290a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 10:03:30 -0400 Subject: [PATCH 20/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 4b8a9c430877c1bf6e59ac02c3d30292cc85d9f5..18aa6e6d65e601d628211605c61c52caf830ffd5 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 181cab2332828e96f39a5b8b8a230e796c415689..fc9607e2642238f713a8f31a6c778601c787e51e 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 0da9ec09afae17c361b33ba160d709ad8cf9e2fb..79a490ff786d35fd01f766a19bf27b3e8c93753e 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 34c6985c6acdb3fadcd33e3bddd9263a4db68cfa..75f0a5e55ae4c0bdce6a2da415ebdb2570e788fc 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, // }; + 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 = 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; + + 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); -- 2.54.0 From e1a4bcbdfd338d85f55aa8da318e203b299a2b91 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 10:43:07 -0400 Subject: [PATCH 21/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 18aa6e6d65e601d628211605c61c52caf830ffd5..e860b878575d474f8e4d1ecbc6a8b79fd97ba801 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 fc9607e2642238f713a8f31a6c778601c787e51e..87e40b36706f5f186d09d4ed27ba840e8f473b02 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 75f0a5e55ae4c0bdce6a2da415ebdb2570e788fc..bd782b4fdc7d38c9a4674258db076115f63e220c 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) && -- 2.54.0 From 6569bfc85e7de5229dd5b665e84070970d28653d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 11:23:25 -0400 Subject: [PATCH 22/32] fix some std lib dependency loops --- src/analyze.cpp | 7 +++---- std/array_list.zig | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 87e40b36706f5f186d09d4ed27ba840e8f473b02..06212bf48b2167d299ae36ea7d312a069c8273c1 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 ee282145bd95a2721be3e96f4f2ca28b2908189c..a527d818d66e686dac151538ee108638cdc9f936 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; -- 2.54.0 From 73a7747a9cfb180a92fa0d98f9387d5ad1f47fd2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 12:43:36 -0400 Subject: [PATCH 23/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index e860b878575d474f8e4d1ecbc6a8b79fd97ba801..61e71c236c7744789808594d50aeb8afea2a9472 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 06212bf48b2167d299ae36ea7d312a069c8273c1..bba26b29aef60e28f8134e4e32bf8c7c9455e532 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 bd782b4fdc7d38c9a4674258db076115f63e220c..a6c14885efb7ff77801647eb5fe2e6de56d88cf2 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 84f3f2c0ec63a5e1ee680c515522a84d2d746d0c..9c9effcb1076ac60df0d5547f60665b6f5b1436c 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 a6a1d0219b24109479a387c3b9828af392a860a2..7ae722366ac77f9e0bb3f8978ad98e6a7228fb8d 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( -- 2.54.0 From d316f704501ff7fc809fdfb082226031ef875046 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 14:01:59 -0400 Subject: [PATCH 24/32] 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(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index bba26b29aef60e28f8134e4e32bf8c7c9455e532..b9b8cae8aa3fa645ddb77c9a5e0c2dcf9e156287 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 79a490ff786d35fd01f766a19bf27b3e8c93753e..d3c1df4a08982a709074bb65be7cd0bf5b299ca1 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 a6c14885efb7ff77801647eb5fe2e6de56d88cf2..c61815b3bb3b63bbcb05c8d16f81d0159a5189d3 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 200a92b64f4274f90735083709022ed77d60795f..3923ea28e8e241c1902134493746ac6748efe70f 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 7ae722366ac77f9e0bb3f8978ad98e6a7228fb8d..7e5e3dd601875b1799c73925a8ae4a52f9877e8e 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( -- 2.54.0 From ae65c236c55a1e22e63bb9f03c1ff925268646f1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 15:24:24 -0400 Subject: [PATCH 25/32] 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(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index ed6ef6367dac6fc3985ab5fbe23ec684882adc29..e8724f0d22801cfa5eda2f7c9a41d5aae01b79f6 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 c61815b3bb3b63bbcb05c8d16f81d0159a5189d3..db7c2f1b537ca17415eef648e1485d9db50d269e 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 ab58f2ed08a06805e805e7eb895e19514001f9c2..c122b18e0a450e53c8e7651b9e725d39e076806a 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); +} -- 2.54.0 From ca145a6d5a430cd87d0b242fb7453e8249221cd0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 15:43:39 -0400 Subject: [PATCH 26/32] fix regression in ir_get_ref --- src/ir.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index db7c2f1b537ca17415eef648e1485d9db50d269e..832983dbf7bfa204d6bb075761cdc75dc1053865 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, -- 2.54.0 From bad4b040cca553ae6845b18f268313f02077f6c1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 18:35:36 -0400 Subject: [PATCH 27/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 61e71c236c7744789808594d50aeb8afea2a9472..3145635b45876fa2e50697db550ca958d56f6262 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 b9b8cae8aa3fa645ddb77c9a5e0c2dcf9e156287..366cb597978583516c254415bd079528f6f54b2b 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 d3c1df4a08982a709074bb65be7cd0bf5b299ca1..63ad905798f156f728ce27957f58833585032a94 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 832983dbf7bfa204d6bb075761cdc75dc1053865..f9f64d67899fc0ef2d929f6cabe596a7a28aa689 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 7e5e3dd601875b1799c73925a8ae4a52f9877e8e..49c836f6a32b563e5e4007994728d75dbb446196 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", ); -- 2.54.0 From db50cf7049b6171a280767e7b1cd0bd215848c92 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 22:38:45 -0400 Subject: [PATCH 28/32] 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(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 366cb597978583516c254415bd079528f6f54b2b..f1df64b17ef32e561fd422b6184e868379e65989 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 63ad905798f156f728ce27957f58833585032a94..ef079a94cd3cd1206f41b4c1b64afdf9d71a2f2e 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 f9f64d67899fc0ef2d929f6cabe596a7a28aa689..eb87706c578c5123c1711714d5618a488916caf7 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 49c836f6a32b563e5e4007994728d75dbb446196..59687a6cc336640fb70b508e21a3d91d5691f05d 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", ); -- 2.54.0 From a2e8ef77e2087e26c1449c56ad16efcea71679db Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Aug 2019 22:49:59 -0400 Subject: [PATCH 29/32] fix regression in one of the doc examples --- src/ir.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index eb87706c578c5123c1711714d5618a488916caf7..d98521de8f7b71cc136593481e8794f74785294f 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; -- 2.54.0 From ffac0b02e75c9c620df11201ee70965856ba9ebf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Aug 2019 10:14:11 -0400 Subject: [PATCH 30/32] 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(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index f1df64b17ef32e561fd422b6184e868379e65989..247788b94924a82938829891ac55efd136fa5c03 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 d98521de8f7b71cc136593481e8794f74785294f..be0fd1ba64e848ccb23bbc8ad30cc9e22dc75d33 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 f607ac59d228a678cb944f5de8d91402d3afe33a..677ae85b68a6d43858305080686e9c8a78e0202d 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); +} -- 2.54.0 From 7d34e55a71b1d929c6e847337a3639f3e65a547e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Aug 2019 10:45:15 -0400 Subject: [PATCH 31/32] add a TODO compile error for union field alignment syntax See #3125 --- src/analyze.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 247788b94924a82938829891ac55efd136fa5c03..dde6e3defce473d7198762464d618726e34d3586 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) { -- 2.54.0 From d9ed55f017bdd23054cd1d7f50ac1da517b5a5e4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Aug 2019 12:54:50 -0400 Subject: [PATCH 32/32] 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(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 3145635b45876fa2e50697db550ca958d56f6262..83dcb8ba10d19a5801288f8f6b541218e40ae378 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 dde6e3defce473d7198762464d618726e34d3586..e0223dd9f7c4457c80dc35616f0f17fc0a76492b 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 be0fd1ba64e848ccb23bbc8ad30cc9e22dc75d33..c1656a1711186958b274e2c86abd5b6c557a3ade 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 59687a6cc336640fb70b508e21a3d91d5691f05d..bc2d43706f30084f03fccb90fa3147832f9aa232 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 { -- 2.54.0