diff --git a/src/all_types.hpp b/src/all_types.hpp index 2394bcb73bdc..83dcb8ba10d1 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -47,6 +47,19 @@ struct ResultLocPeer; struct ResultLocPeerParent; struct ResultLocBitCast; +enum PtrLen { + PtrLenUnknown, + PtrLenSingle, + PtrLenC, +}; + +enum UndefAllowed { + UndefOk, + UndefBad, + LazyOkNoUndef, + LazyOk, +}; + enum X64CABIClass { X64CABIClass_Unknown, X64CABIClass_MEMORY, @@ -69,9 +82,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; @@ -255,6 +268,7 @@ enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, ConstValSpecialUndef, + ConstValSpecialLazy, }; enum RuntimeHintErrorUnion { @@ -291,6 +305,73 @@ struct ConstGlobalRefs { uint32_t align; }; +enum LazyValueId { + LazyValueIdInvalid, + LazyValueIdAlignOf, + LazyValueIdPtrType, + LazyValueIdOptType, + LazyValueIdSliceType, + LazyValueIdFnType, +}; + +struct LazyValue { + LazyValueId id; +}; + +struct LazyValueAlignOf { + LazyValue base; + + 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; +}; + +struct LazyValuePtrType { + LazyValue base; + + 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; + + IrAnalyze *ira; + IrInstruction *payload_type; +}; + +struct LazyValueFnType { + LazyValue base; + + IrAnalyze *ira; + AstNode *proto_node; + IrInstruction **param_types; + IrInstruction *align_inst; // can be null + IrInstruction *return_type; + + bool is_generic; +}; + struct ConstExprValue { ZigType *type; ConstValSpecial special; @@ -318,6 +399,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; @@ -364,6 +446,7 @@ enum TldResolution { TldResolutionUnresolved, TldResolutionResolving, TldResolutionInvalid, + TldResolutionOkLazy, TldResolutionOk, }; @@ -420,10 +503,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 { @@ -946,6 +1031,7 @@ struct AstNodeEnumLiteral { struct AstNode { enum NodeType type; + bool already_traced_this_node; size_t line; size_t column; ZigType *owner; @@ -1041,12 +1127,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; @@ -1057,6 +1137,7 @@ struct ZigTypePointer { bool is_const; bool is_volatile; bool allow_zero; + bool resolve_loop_flag_zero_bits; }; struct ZigTypeInt { @@ -1075,7 +1156,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 @@ -1131,11 +1213,11 @@ 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_zero_bits; + bool resolve_loop_flag_other; }; struct ZigTypeOptional { @@ -1157,26 +1239,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); @@ -1189,7 +1265,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; @@ -1201,11 +1277,11 @@ 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_zero_bits; + bool resolve_loop_flag_other; }; struct FnGenParamInfo { @@ -1717,6 +1793,7 @@ struct CodeGen { //////////////////////////// Runtime State LLVMModuleRef module; ZigList errors; + ErrorMsg *trace_err; LLVMBuilderRef builder; ZigLLVMDIBuilder *dbuilder; ZigLLVMDICompileUnit *compile_unit; @@ -1769,7 +1846,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; @@ -1854,7 +1930,6 @@ struct CodeGen { ZigFn *main_fn; ZigFn *panic_fn; TldFn *panic_tld_fn; - AstNode *root_export_decl; WantPIC want_pic; WantStackCheck want_stack_check; @@ -1942,7 +2017,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; @@ -3659,13 +3734,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 35c598ab97af..e0223dd9f7c4 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); @@ -59,13 +59,15 @@ 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; } -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); } @@ -271,6 +273,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,32 +289,28 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ResolveStatusLLVMFull: return type_entry->llvm_type != nullptr; } - case ZigTypeIdEnum: + case ZigTypeIdOpaque: + return status < ResolveStatusSizeKnown; + case ZigTypeIdPointer: switch (status) { - case ResolveStatusUnstarted: - return true; case ResolveStatusInvalid: zig_unreachable(); + case ResolveStatusUnstarted: + return true; 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; + return type_entry->abi_size != SIZE_MAX; case ResolveStatusLLVMFwdDecl: case ResolveStatusLLVMFull: - return type_entry->llvm_di_type != nullptr; + return type_entry->llvm_type != nullptr; } - zig_unreachable(); - case ZigTypeIdOpaque: - return status < ResolveStatusSizeKnown; case ZigTypeIdMetaType: case ZigTypeIdVoid: case ZigTypeIdBool: case ZigTypeIdUnreachable: case ZigTypeIdInt: case ZigTypeIdFloat: - case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -460,8 +460,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); @@ -491,17 +489,21 @@ 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; - 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; @@ -865,7 +867,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 { @@ -960,31 +962,209 @@ 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(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); + nullptr, nullptr, node, type_name, nullptr, nullptr, undef); } -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)) - return g->builtin_types.entry_invalid; +static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, + ConstExprValue *parent_type_val, bool *is_zero_bits) +{ + 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) || + (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) + { + // Does a struct/union 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); + 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); - 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; + 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; + } else { + if (parent_type_val == nullptr) { + parent_type_val = type_val; + } + return type_val_resolve_zero_bits(g, &lazy_ptr_type->elem_type->value, parent_type, + parent_type_val, is_zero_bits); + } + } + case LazyValueIdOptType: + 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(); +} + +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: + case LazyValueIdFnType: + case LazyValueIdOptType: + *is_opaque_type = false; + return ErrorNone; } + zig_unreachable(); +} - assert(result->data.x_type != nullptr); +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); + } + 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); + if (type_is_invalid(lazy_slice_type->elem_type)) + return ReqCompTimeInvalid; + 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->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->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->value)) { + 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]->value)) { + case ReqCompTimeInvalid: + return ReqCompTimeInvalid; + case ReqCompTimeYes: + return ReqCompTimeYes; + case ReqCompTimeNo: + break; + } + } + return ReqCompTimeNo; + } + } + zig_unreachable(); +} + +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); + 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; + return ErrorNone; + } + switch (type_val->data.x_lazy->id) { + case LazyValueIdInvalid: + case LazyValueIdAlignOf: + zig_unreachable(); + case LazyValueIdSliceType: + case LazyValueIdPtrType: + 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->value, abi_align); + } + } + 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: // it has the len field + case LazyValueIdOptType: // it has the optional bit + case LazyValueIdFnType: + return OnePossibleValueNo; + case LazyValueIdPtrType: { + Error err; + bool zero_bits; + if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, 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, UndefBad); + if (type_is_invalid(result->type)) + return g->builtin_types.entry_invalid; + src_assert(result->special == ConstValSpecialStatic, node); + src_assert(result->data.x_type != nullptr, node); return result->data.x_type; } @@ -1032,7 +1212,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; @@ -1054,7 +1235,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; @@ -1404,7 +1585,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); @@ -1423,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) { @@ -1490,7 +1673,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; } @@ -1599,12 +1782,11 @@ 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; - 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); + add_node_error(g, decl_node, + buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; } @@ -1615,18 +1797,42 @@ 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; - // 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; @@ -1690,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; } } @@ -1708,7 +1914,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; @@ -1728,22 +1934,21 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) return ErrorNone; - 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; + AstNode *decl_node = union_type->data.structure.decl_node; + + if (union_type->data.unionation.resolve_loop_flag_other) { + 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); + add_node_error(g, decl_node, + buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; } // 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; @@ -1752,34 +1957,40 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { if (field->gen_index == UINT32_MAX) continue; - 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 { + 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; + } + 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) { if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; + 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; + 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; @@ -1793,18 +2004,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; } @@ -1812,6 +2023,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); @@ -1831,30 +2053,32 @@ 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.reported_infinite_err) { - union_type->data.unionation.reported_infinite_err = true; + if (union_type->data.unionation.resolve_loop_flag_other) { + 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); + add_node_error(g, decl_node, + buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); } return ErrorSemanticAnalyzeFail; } // 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) { TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - ZigType *field_type = union_field->type_entry; + ZigType *field_type = resolve_union_field_type(g, union_field); + if (field_type == nullptr) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -1874,11 +2098,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; @@ -1897,7 +2121,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; @@ -1925,24 +2149,25 @@ static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) { static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { assert(enum_type->id == ZigTypeIdEnum); - if (enum_type->data.enumeration.is_invalid) + if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - - if (enum_type->data.enumeration.zero_bits_known) + if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown) return ErrorNone; - if (enum_type->data.enumeration.zero_bits_loop_flag) { - ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node, - buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name))); - emit_error_notes_for_ref_stack(g, msg); - enum_type->data.enumeration.is_invalid = true; + AstNode *decl_node = enum_type->data.enumeration.decl_node; + assert(decl_node->type == NodeTypeContainerDecl); + + if (enum_type->data.enumeration.resolve_loop_flag) { + if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + add_node_error(g, decl_node, + buf_sprintf("enum '%s' depends on itself", + buf_ptr(&enum_type->name))); + } return ErrorSemanticAnalyzeFail; } - enum_type->data.enumeration.zero_bits_loop_flag = true; - - AstNode *decl_node = enum_type->data.enumeration.decl_node; - assert(decl_node->type == NodeTypeContainerDecl); + enum_type->data.enumeration.resolve_loop_flag = true; assert(!enum_type->data.enumeration.fields); uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; @@ -1951,9 +2176,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 +2205,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))); @@ -2022,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); @@ -2029,7 +2257,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; } @@ -2037,9 +2265,10 @@ 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.is_invalid = true; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; continue; } @@ -2060,7 +2289,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 +2304,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 +2318,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; } @@ -2112,16 +2340,17 @@ 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) { - // 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_loop_flag_zero_bits) { + 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 itself", + buf_ptr(&struct_type->name))); + } + 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; @@ -2153,58 +2382,60 @@ 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(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; } + assert(field_type_val->special != ConstValSpecialRuntime); + type_struct_field->type_val = field_type_val; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.layout == ContainerLayoutExtern && - !type_allowed_in_extern(g, field_type)) - { - add_node_error(g, field_node, - buf_sprintf("extern structs cannot contain fields of type '%s'", - buf_ptr(&field_type->name))); + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; - } else if (struct_type->data.structure.layout == ContainerLayoutPacked) { - if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_node))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } } - - type_struct_field->src_index = i; - type_struct_field->gen_index = SIZE_MAX; - - if (field_type->id == ZigTypeIdOpaque) { + if (field_is_opaque_type) { add_node_error(g, field_node->data.struct_field.type, buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - switch (type_requires_comptime(g, field_type)) { + + type_struct_field->src_index = i; + type_struct_field->gen_index = SIZE_MAX; + + switch (type_val_resolve_requires_comptime(g, field_type_val)) { case ReqCompTimeYes: 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: 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, nullptr, &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; 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; @@ -2234,17 +2465,16 @@ 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; - 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); + add_node_error(g, decl_node, + buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); } 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; @@ -2255,47 +2485,31 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { if (field->gen_index == SIZE_MAX) continue; - uint32_t this_field_align; - - // TODO: Sets the field alignment in the type, but doesn't do anything - // to actually make that happen yet. AstNode *align_expr = field->decl_node->data.struct_field.align_expr; if (align_expr != nullptr) { - if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, &this_field_align)) { - field->type_entry = g->builtin_types.entry_invalid; - } else { - field->align = this_field_align; + if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, + &field->align)) + { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return err; } } else if (packed) { - // TODO: https://github.com/ziglang/zig/issues/1512 - // TODO: Validate requested alignment is possible, given packed, - // and given other field alignments. - 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; + 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))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; + return err; } - this_field_align = field->type_entry->abi_align; + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; } - // TODO: https://github.com/ziglang/zig/issues/1512 - if (this_field_align > struct_type->abi_align) { - struct_type->abi_align = this_field_align; + if (field->align > struct_type->abi_align) { + struct_type->abi_align = field->align; } } - 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; @@ -2316,23 +2530,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) return ErrorNone; - 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; - } - - union_type->data.unionation.resolve_loop_flag = true; - AstNode *decl_node = union_type->data.unionation.decl_node; assert(decl_node->type == NodeTypeContainerDecl); + 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; + add_node_error(g, decl_node, + buf_sprintf("union '%s' depends on itself", + buf_ptr(&union_type->name))); + } + return ErrorSemanticAnalyzeFail; + } + + 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; if (field_count == 0) { @@ -2392,14 +2604,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)) { @@ -2441,49 +2652,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 = true; } 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(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; } + assert(field_type_val->special != ConstValSpecialRuntime); + union_field->type_val = field_type_val; if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - } - union_field->type_entry = field_type; - if (field_type->id == ZigTypeIdOpaque) { - add_node_error(g, field_node->data.struct_field.type, - buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + if (field_is_opaque_type) { + add_node_error(g, field_node->data.struct_field.type, + buf_create_from_str( + "opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } - switch (type_requires_comptime(g, field_type)) { - case ReqCompTimeInvalid: + switch (type_val_resolve_requires_comptime(g, field_type_val)) { + case ReqCompTimeInvalid: + if (g->trace_err != nullptr) { + g->trace_err = add_error_note(g, g->trace_err, field_node, + buf_create_from_str("while checking this field")); + } + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + case ReqCompTimeYes: + union_type->data.unionation.requires_comptime = true; + break; + case ReqCompTimeNo: + break; + } + + if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; + } } if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, - buf_sprintf("non-enum union field assignment")); - add_error_note(g, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); + buf_create_from_str("untagged union field assignment")); + add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); } if (create_enum_type) { @@ -2501,7 +2731,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; @@ -2542,7 +2773,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; @@ -2619,7 +2850,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); @@ -2676,6 +2907,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; } @@ -2702,7 +2935,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) { @@ -2848,7 +3081,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) { @@ -2943,7 +3177,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; @@ -3185,7 +3419,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; @@ -3197,9 +3431,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, + 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; @@ -3217,7 +3450,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(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; @@ -3372,7 +3606,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)) { @@ -3392,51 +3627,61 @@ 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; - g->tld_ref_source_node_stack.append(source_node); 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; - g->tld_ref_source_node_stack.pop(); + 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; + } } Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) { @@ -3562,7 +3807,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) { @@ -3631,43 +3876,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; @@ -3803,6 +4011,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; } @@ -3918,7 +4133,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; @@ -4002,7 +4217,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; } @@ -4140,12 +4355,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); + resolve_top_level_decl(g, tld, source_node, false); } 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); } } @@ -4157,6 +4374,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, @@ -4802,7 +5020,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_has_one_possible_value(g, field->type_entry)) { + 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: @@ -4828,18 +5049,19 @@ 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(); } -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { Error err; - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return ReqCompTimeInvalid; - switch (type_entry->id) { + switch (ty->id) { case ZigTypeIdInvalid: - case ZigTypeIdOpaque: zig_unreachable(); case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -4851,23 +5073,36 @@ 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); case ZigTypeIdStruct: - return type_entry->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; + 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; case ZigTypeIdUnion: - return type_entry->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; + 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; case ZigTypeIdOptional: - return type_requires_comptime(g, type_entry->data.maybe.child_type); + return type_requires_comptime(g, ty->data.maybe.child_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); 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); } case ZigTypeIdFn: - return type_entry->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; + return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; + case ZigTypeIdOpaque: case ZigTypeIdEnum: case ZigTypeIdErrorSet: case ZigTypeIdBool: @@ -5155,34 +5390,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); @@ -5192,10 +5399,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; @@ -5209,27 +5412,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; @@ -5241,14 +5423,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, + 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; } @@ -5264,11 +5440,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, + 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; } } @@ -5339,10 +5513,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; } @@ -5454,6 +5626,37 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { return ErrorNone; } +static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { + Error err; + + 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))) + 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; @@ -5463,36 +5666,48 @@ 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); + case ZigTypeIdPointer: + return resolve_pointer_zero_bits(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); + case ZigTypeIdPointer: + return resolve_pointer_zero_bits(g, ty); + default: + return ErrorNone; } - return ErrorNone; case ResolveStatusLLVMFwdDecl: case ResolveStatusLLVMFull: resolve_llvm_types(g, ty, status); @@ -5867,6 +6082,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; @@ -6241,6 +6459,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; @@ -6504,7 +6756,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; @@ -6719,19 +6971,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; @@ -7134,10 +7373,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); @@ -7158,6 +7396,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; } @@ -7190,14 +7429,16 @@ 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) { 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) { + 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; @@ -7221,7 +7462,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) { @@ -7248,17 +7488,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; @@ -7269,7 +7509,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, ""); @@ -7280,14 +7520,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); @@ -7303,7 +7543,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, @@ -7314,8 +7554,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); @@ -7352,6 +7592,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; @@ -7921,7 +8164,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 5752c747512b..ef079a94cd3c 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -11,10 +11,9 @@ #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); -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); @@ -59,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); @@ -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); @@ -244,9 +240,13 @@ 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(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); +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/codegen.cpp b/src/codegen.cpp index 6c87d3e0c340..e8724f0d2280 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: @@ -3525,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); @@ -6041,6 +6045,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 +6305,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: @@ -6563,7 +6570,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) { @@ -8891,7 +8898,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 5251e6fb7850..c1656a171118 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -152,11 +152,6 @@ struct ConstCastBadAllowsZero { }; -enum UndefAllowed { - UndefOk, - UndefBad, -}; - 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); @@ -234,6 +229,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; } @@ -402,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); + node, nullptr, ira->new_irb.exec, nullptr, UndefBad); if (type_is_invalid(result->type)) return ira->codegen->builtin_types.entry_invalid; @@ -6858,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; } @@ -8111,7 +8107,12 @@ 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) { + 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; } @@ -8119,21 +8120,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 +8151,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)); @@ -8181,15 +8183,9 @@ static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, Error 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); + invalidate_exec(exec, err_msg); if (exec->parent_exec) { ir_add_call_stack_errors(codegen, exec, err_msg, 10); } @@ -8223,6 +8219,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; @@ -9016,7 +9013,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); @@ -9376,6 +9374,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) && @@ -10634,7 +10640,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; } @@ -10722,32 +10728,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 || 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 || undef_allowed == LazyOkNoUndef) + 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, UndefAllowed undef_allowed) { + Error err; + if (expected_type != nullptr && type_is_invalid(expected_type)) return &codegen->invalid_instruction->value; @@ -10761,8 +10792,10 @@ 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 = ir_executable->first_err_trace_msg; return &codegen->invalid_instruction->value; + } if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); @@ -10783,8 +10816,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"); @@ -10792,7 +10826,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 (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; + + return result; } static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_value) { @@ -10813,22 +10854,43 @@ static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_valu return const_val->data.x_err_set; } -static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { +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 ConstExprValue *ir_resolve_type_lazy(IrAnalyze *ira, IrInstruction *type_value) { if (type_is_invalid(type_value->value.type)) - return ira->codegen->builtin_types.entry_invalid; + return nullptr; if (type_value->value.type->id != ZigTypeIdMetaType) { ir_add_error(ira, type_value, buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); - return ira->codegen->builtin_types.entry_invalid; + return nullptr; } - ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad); - if (!const_val) + 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; - 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, val); } static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { @@ -11026,14 +11088,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; } @@ -11152,6 +11221,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, @@ -11322,7 +11394,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; } @@ -11345,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: { @@ -11357,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))); @@ -11373,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; } @@ -11390,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; @@ -11461,7 +11541,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) { @@ -12508,26 +12588,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_u32(&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; } @@ -12535,6 +12611,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; @@ -12719,7 +12807,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); @@ -13576,21 +13666,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; @@ -13602,7 +13705,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; @@ -14171,9 +14274,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) { @@ -14231,7 +14338,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; @@ -14242,6 +14349,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. @@ -14250,7 +14361,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); @@ -14555,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; @@ -15174,23 +15289,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 (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)) { - // 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) { @@ -15198,6 +15315,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) { @@ -15208,8 +15326,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(); @@ -15217,15 +15338,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. @@ -15489,7 +15605,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); + 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; @@ -15513,8 +15630,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); @@ -15685,7 +15803,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, 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); @@ -16066,51 +16185,20 @@ 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); + lazy_opt_type->ira = ira; + result->value.data.x_lazy = &lazy_opt_type->base; + lazy_opt_type->base.id = LazyValueIdOptType; - case ZigTypeIdUnreachable: - case ZigTypeIdOpaque: - ir_add_error_node(ira, un_op_instruction->base.source_node, - buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - zig_unreachable(); + lazy_opt_type->payload_type = instruction->value->child; + if (ir_resolve_type_lazy(ira, lazy_opt_type->payload_type) == nullptr) + return ira->codegen->invalid_instruction; + + return result; } static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type, @@ -16727,7 +16815,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); @@ -17005,7 +17093,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; @@ -17038,6 +17126,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; @@ -17048,9 +17137,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) ? @@ -17058,7 +17147,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)) { @@ -17113,7 +17202,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,23 +17332,22 @@ 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) + resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node, true); + if (tld->resolution == TldResolutionInvalid) { return ira->codegen->invalid_instruction; + } switch (tld->id) { case TldIdContainer: case TldIdCompTime: case TldIdUsingNamespace: zig_unreachable(); - case TldIdVar: - { + case TldIdVar: { TldVar *tld_var = (TldVar *)tld; ZigVar *var = tld_var->var; if (var == nullptr) { @@ -17271,8 +17359,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); @@ -17396,7 +17483,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 +17512,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) { @@ -17844,22 +17931,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); + lazy_slice_type->ira = ira; + result->value.data.x_lazy = &lazy_slice_type->base; + lazy_slice_type->base.id = LazyValueIdSliceType; + if (slice_type_instruction->align_value != nullptr) { - if (!ir_resolve_align(ira, slice_type_instruction->align_value->child, &align_bytes)) + 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; } - 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: @@ -17868,7 +17962,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: @@ -17891,18 +17985,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) { @@ -18008,7 +18093,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 +18109,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 +18614,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) { @@ -19070,7 +19155,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; @@ -19276,8 +19361,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; } @@ -19319,7 +19403,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); @@ -19391,7 +19478,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 +19557,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,11 +19661,9 @@ 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))) - 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, @@ -19594,15 +19679,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. @@ -19613,7 +19698,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; } @@ -19673,7 +19758,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 +19884,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 +19940,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 +19952,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); @@ -20581,7 +20666,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, UndefBad); if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; @@ -21482,64 +21567,75 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio return ira->codegen->invalid_instruction; // TODO test this at comptime with u8 and non-u8 types - if (casted_dest_ptr->value.special == ConstValSpecialStatic && - casted_byte->value.special == ConstValSpecialStatic && - casted_count->value.special == ConstValSpecialStatic && - casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + if (instr_is_comptime(casted_dest_ptr) && + instr_is_comptime(casted_byte) && + instr_is_comptime(casted_count)) { - ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; + ConstExprValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); + if (dest_ptr_val == nullptr) + return ira->codegen->invalid_instruction; - ConstExprValue *dest_elements; - size_t start; - size_t bound_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - start = 0; - bound_end = 1; - break; - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - bound_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memset on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memset on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memset on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memset on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memset on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memset on null ptr"); - } + ConstExprValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); + if (byte_val == nullptr) + return ira->codegen->invalid_instruction; - size_t count = bigint_as_usize(&casted_count->value.data.x_bigint); - size_t end = start + count; - if (end > bound_end) { - ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); + ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); + if (count_val == nullptr) return ira->codegen->invalid_instruction; - } - ConstExprValue *byte_val = &casted_byte->value; - for (size_t i = start; i < end; i += 1) { - copy_const_val(&dest_elements[i], byte_val, true); - } + if (casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && + casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + { + ConstExprValue *dest_elements; + size_t start; + size_t bound_end; + switch (dest_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; + start = 0; + bound_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(ira->codegen, array_val); + dest_elements = array_val->data.x_array.data.s_none.elements; + start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; + bound_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memset on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memset on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memset on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memset on const inner optional payload"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + case ConstPtrSpecialFunction: + zig_panic("TODO memset on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memset on null ptr"); + } - return ir_const_void(ira, &instruction->base); + size_t count = bigint_as_usize(&count_val->data.x_bigint); + size_t end = start + count; + if (end > bound_end) { + ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } + + for (size_t i = start; i < end; i += 1) { + copy_const_val(&dest_elements[i], byte_val, true); + } + + return ir_const_void(ira, &instruction->base); + } } IrInstruction *result = ir_build_memset(&ira->new_irb, instruction->base.scope, instruction->base.source_node, @@ -21607,107 +21703,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_usize(&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_usize(&count_val->data.x_bigint); - switch (src_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; - src_start = 0; - src_end = 1; - break; - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - src_elements = array_val->data.x_array.data.s_none.elements; - src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; - src_end = array_val->type->data.array.len; + ConstExprValue *dest_elements; + size_t dest_start; + size_t dest_end; + switch (dest_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; + dest_start = 0; + dest_end = 1; break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(ira->codegen, array_val); + dest_elements = array_val->data.x_array.data.s_none.elements; + dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; + dest_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + case ConstPtrSpecialFunction: + zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); + } - if (src_start + count > src_end) { - ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_instruction; - } + if (dest_start + count > dest_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } - // TODO check for noalias violations - this should be generalized to work for any function + ConstExprValue *src_elements; + size_t src_start; + size_t src_end; - for (size_t i = 0; i < count; i += 1) { - copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); - } + switch (src_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; + src_start = 0; + src_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(ira->codegen, array_val); + src_elements = array_val->data.x_array.data.s_none.elements; + src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; + src_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + case ConstPtrSpecialFunction: + zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); + } - return ir_const_void(ira, &instruction->base); + if (src_start + count > src_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); + return ira->codegen->invalid_instruction; + } + + // TODO check for noalias violations - this should be generalized to work for any function + + for (size_t i = 0; i < count; i += 1) { + copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); + } + + return ir_const_void(ira, &instruction->base); + } } IrInstruction *result = ir_build_memcpy(&ira->new_irb, instruction->base.scope, instruction->base.source_node, @@ -21877,6 +21984,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")); @@ -22021,7 +22133,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 +22169,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 +22212,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; @@ -22249,53 +22361,24 @@ 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); + // 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); + lazy_align_of->ira = ira; + result->value.data.x_lazy = &lazy_align_of->base; + lazy_align_of->base.id = LazyValueIdAlignOf; - if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) + 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; - 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: - { - uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); - return ir_const_unsigned(ira, &instruction->base, align_in_bytes); - } - } - zig_unreachable(); + return result; } static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) { @@ -22359,13 +22442,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; @@ -22754,84 +22850,64 @@ 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); + lazy_fn_type->ira = ira; + result->value.data.x_lazy = &lazy_fn_type->base; + lazy_fn_type->base.id = LazyValueIdFnType; + 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; - 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)) { - 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; + if (ir_resolve_const(ira, param_type_value, LazyOk) == nullptr) + return ira->codegen->invalid_instruction; + lazy_fn_type->param_types[param_index] = param_type_value; } if (instruction->align_value != nullptr) { - if (!ir_resolve_align(ira, instruction->align_value->child, &fn_type_id.alignment)) + 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; } - 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 = instruction->return_type->child; + if (ir_resolve_const(ira, lazy_fn_type->return_type, LazyOk) == 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) { @@ -23218,7 +23294,7 @@ 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) && 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); @@ -23258,6 +23334,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", @@ -23309,8 +23391,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 +23830,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; @@ -23795,53 +23880,32 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { - Error err; - ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); - if (type_is_invalid(child_type)) - return ira->codegen->invalid_instruction; + IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); + result->value.special = ConstValSpecialLazy; - 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")); + 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->elem_type = instruction->child_type->child; + if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) 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; - } - } - uint32_t align_bytes; if (instruction->align_value != nullptr) { - if (!ir_resolve_align(ira, instruction->align_value->child, &align_bytes)) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) + 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; - 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) { @@ -23954,7 +24018,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 +25164,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 +25211,18 @@ 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 && + !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")); + } return ira->codegen->builtin_types.entry_invalid; } @@ -25158,7 +25234,15 @@ 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 && 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")); + } return ira->codegen->builtin_types.entry_invalid; } else if (ira->src_implicit_return_type_list.length == 0) { return codegen->builtin_types.entry_unreachable; @@ -25354,3 +25438,269 @@ bool ir_has_side_effects(IrInstruction *instruction) { } zig_unreachable(); } + +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; + + 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(ira->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(ira->codegen, &fn_type_id); + } else { + 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(ira->codegen, param_type)) { + case ReqCompTimeYes: + if (!calling_convention_allows_zig_types(fn_type_id.cc)) { + 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(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(ira->codegen, param_type, ResolveStatusZeroBitsKnown))) + return nullptr; + if (!type_has_bits(param_type)) { + 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; + } + } + param_info->type = param_type; + } + } + + 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_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) { + ir_add_error(ira, lazy_fn_type->return_type, buf_create_from_str("return type cannot be opaque")); + return nullptr; + } + + return get_fn_type(ira->codegen, &fn_type_id); +} + +static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { + Error err; + if (val->special != ConstValSpecialLazy) + return ErrorNone; + 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->value.special == ConstValSpecialStatic) { + switch (lazy_align_of->target_type->value.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: + ir_add_error(ira, lazy_align_of->target_type, + buf_sprintf("no align available for type '%s'", + buf_ptr(&lazy_align_of->target_type->value.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(ira->codegen, &lazy_align_of->target_type->value, + &align_in_bytes))) + { + return err; + } + + 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); + IrAnalyze *ira = lazy_slice_type->ira; + + uint32_t align_bytes = 0; + 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(ira->codegen, lazy_slice_type->elem_type, needed_status))) + return err; + 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(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_inst != nullptr) { + if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, &align_bytes)) + return ErrorSemanticAnalyzeFail; + } + 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) { + 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) { + 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(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) { + 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) { + 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(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(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); + val->special = ConstValSpecialStatic; + return ErrorNone; + } + case LazyValueIdOptType: { + LazyValueOptType *lazy_opt_type = reinterpret_cast(val->data.x_lazy); + IrAnalyze *ira = lazy_opt_type->ira; + + 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) { + 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(ira->codegen, payload_type, ResolveStatusSizeKnown))) + return err; + + assert(val->type->id == ZigTypeIdMetaType); + val->data.x_type = get_optional_type(ira->codegen, payload_type); + val->special = ConstValSpecialStatic; + return ErrorNone; + } + case LazyValueIdFnType: { + 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; + assert(val->type->id == ZigTypeIdMetaType); + val->data.x_type = fn_type; + return ErrorNone; + } + } + zig_unreachable(); +} + +Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { + Error err; + 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, + buf_create_from_str("referenced here")); + } + return err; + } + if (type_is_invalid(val->type)) { + return ErrorSemanticAnalyzeFail; + } + return ErrorNone; +} diff --git a/src/ir.hpp b/src/ir.hpp index 3761c5a97d71..3923ea28e8e2 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, UndefAllowed undef); + +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); @@ -28,6 +30,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 diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 84f3f2c0ec63..9c9effcb1076 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/std/array_list.zig b/std/array_list.zig index ee282145bd95..a527d818d66e 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; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a6a1d0219b24..bc2d43706f30 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 { @@ -10,7 +37,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 +80,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 +272,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 +285,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( @@ -404,7 +431,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( @@ -470,7 +497,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 +508,7 @@ 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:5:18: note: referenced here", ); cases.add( @@ -645,7 +672,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 +682,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 +697,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 +716,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 +730,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 +893,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 +902,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 +933,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 +969,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 +979,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 +989,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 +1014,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 +1028,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 +1056,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 +1065,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 +1074,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)); @@ -1091,7 +1118,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( @@ -1935,7 +1962,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 +2951,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( @@ -3596,7 +3623,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, \\}; @@ -3606,8 +3633,7 @@ 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", ); cases.add( @@ -3701,7 +3727,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 +4159,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 +4201,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 +4284,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 +4297,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 +4310,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 +4323,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 +4415,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( @@ -4717,7 +4744,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 +5891,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", ); @@ -5939,7 +5966,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", ); diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index f607ac59d228..677ae85b68a6 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); +} diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index ab58f2ed08a0..c122b18e0a45 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); +}