mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-05-04 00:32:40 +03:00
Merge pull request #3115 from ziglang/fix-field-alignment-kludge
fix field alignment kludge by implementing lazy values
This commit is contained in:
+106
-31
@@ -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 *> 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<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> 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<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> 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<ErrorMsg*> errors;
|
||||
ErrorMsg *trace_err;
|
||||
LLVMBuilderRef builder;
|
||||
ZigLLVMDIBuilder *dbuilder;
|
||||
ZigLLVMDICompileUnit *compile_unit;
|
||||
@@ -1769,7 +1846,6 @@ struct CodeGen {
|
||||
ZigList<Tld *> resolve_queue;
|
||||
size_t resolve_queue_index;
|
||||
ZigList<TimeEvent> timing_events;
|
||||
ZigList<AstNode *> tld_ref_source_node_stack;
|
||||
ZigList<ZigFn *> inline_fns;
|
||||
ZigList<ZigFn *> test_fns;
|
||||
ZigList<ErrorTableEntry *> 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;
|
||||
|
||||
+708
-465
@@ -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:
|
||||
switch (status) {
|
||||
case ResolveStatusUnstarted:
|
||||
return true;
|
||||
case ResolveStatusInvalid:
|
||||
zig_unreachable();
|
||||
case ResolveStatusZeroBitsKnown:
|
||||
return type_entry->data.enumeration.zero_bits_known;
|
||||
case ResolveStatusAlignmentKnown:
|
||||
return type_entry->data.enumeration.zero_bits_known;
|
||||
case ResolveStatusSizeKnown:
|
||||
return type_entry->data.enumeration.complete;
|
||||
case ResolveStatusLLVMFwdDecl:
|
||||
case ResolveStatusLLVMFull:
|
||||
return type_entry->llvm_di_type != nullptr;
|
||||
}
|
||||
zig_unreachable();
|
||||
case ZigTypeIdOpaque:
|
||||
return status < ResolveStatusSizeKnown;
|
||||
case ZigTypeIdPointer:
|
||||
switch (status) {
|
||||
case ResolveStatusInvalid:
|
||||
zig_unreachable();
|
||||
case ResolveStatusUnstarted:
|
||||
return true;
|
||||
case ResolveStatusZeroBitsKnown:
|
||||
case ResolveStatusAlignmentKnown:
|
||||
case ResolveStatusSizeKnown:
|
||||
return type_entry->abi_size != SIZE_MAX;
|
||||
case ResolveStatusLLVMFwdDecl:
|
||||
case ResolveStatusLLVMFull:
|
||||
return type_entry->llvm_type != nullptr;
|
||||
}
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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<LazyValuePtrType *>(type_val->data.x_lazy);
|
||||
|
||||
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<LazyValueFnType *>(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();
|
||||
}
|
||||
|
||||
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<LazyValueSliceType *>(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<LazyValuePtrType *>(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<LazyValueOptType *>(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<LazyValueFnType *>(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<LazyValueOptType *>(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);
|
||||
ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type,
|
||||
nullptr, UndefBad);
|
||||
if (type_is_invalid(result->type))
|
||||
return g->builtin_types.entry_invalid;
|
||||
|
||||
assert(result->special != ConstValSpecialRuntime);
|
||||
// Reject undefined as valid `type` type even though the specification
|
||||
// allows it to be casted to anything.
|
||||
// See also ir_resolve_type()
|
||||
if (result->special == ConstValSpecialUndef) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("expected type 'type', found '%s'",
|
||||
buf_ptr(&g->builtin_types.entry_undef->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
assert(result->data.x_type != nullptr);
|
||||
src_assert(result->special == ConstValSpecialStatic, node);
|
||||
src_assert(result->data.x_type != nullptr, node);
|
||||
return result->data.x_type;
|
||||
}
|
||||
|
||||
@@ -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<uint32_t>(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 ErrorSemanticAnalyzeFail;
|
||||
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,25 +2149,26 @@ static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) {
|
||||
static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
|
||||
assert(enum_type->id == ZigTypeIdEnum);
|
||||
|
||||
if (enum_type->data.enumeration.is_invalid)
|
||||
if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
||||
if (enum_type->data.enumeration.zero_bits_known)
|
||||
if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown)
|
||||
return ErrorNone;
|
||||
|
||||
if (enum_type->data.enumeration.zero_bits_loop_flag) {
|
||||
ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node,
|
||||
buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
|
||||
emit_error_notes_for_ref_stack(g, msg);
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
enum_type->data.enumeration.zero_bits_loop_flag = true;
|
||||
|
||||
AstNode *decl_node = enum_type->data.enumeration.decl_node;
|
||||
assert(decl_node->type == NodeTypeContainerDecl);
|
||||
|
||||
if (enum_type->data.enumeration.resolve_loop_flag) {
|
||||
if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) {
|
||||
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
|
||||
add_node_error(g, decl_node,
|
||||
buf_sprintf("enum '%s' depends on itself",
|
||||
buf_ptr(&enum_type->name)));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
enum_type->data.enumeration.resolve_loop_flag = true;
|
||||
|
||||
assert(!enum_type->data.enumeration.fields);
|
||||
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
|
||||
if (field_count == 0) {
|
||||
@@ -1951,9 +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<TypeEnumField>(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;
|
||||
}
|
||||
|
||||
switch (type_requires_comptime(g, field_type)) {
|
||||
case ReqCompTimeInvalid:
|
||||
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;
|
||||
case ReqCompTimeYes:
|
||||
union_type->data.unionation.requires_comptime = true;
|
||||
break;
|
||||
case ReqCompTimeNo:
|
||||
break;
|
||||
}
|
||||
if (field_is_opaque_type) {
|
||||
add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_create_from_str(
|
||||
"opaque types have unknown size and therefore cannot be directly embedded in unions"));
|
||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
switch (type_val_resolve_requires_comptime(g, field_type_val)) {
|
||||
case ReqCompTimeInvalid:
|
||||
if (g->trace_err != nullptr) {
|
||||
g->trace_err = add_error_note(g, g->trace_err, field_node,
|
||||
buf_create_from_str("while checking this field"));
|
||||
}
|
||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
case ReqCompTimeYes:
|
||||
union_type->data.unionation.requires_comptime = true;
|
||||
break;
|
||||
case ReqCompTimeNo:
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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<ConstGlobalRefs>(count);
|
||||
ConstExprValue *vals = allocate<ConstExprValue>(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<ZigLLVMDIType*>(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:
|
||||
|
||||
+8
-8
@@ -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<const char *> &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
|
||||
|
||||
+9
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+873
-523
@@ -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 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) {
|
||||
Error err;
|
||||
if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node,
|
||||
&value->value, undef_allowed)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
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,6 +12588,29 @@ 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_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) {
|
||||
exec_add_error_node(codegen, exec, source_node, buf_sprintf("alignment must be >= 1"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_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;
|
||||
}
|
||||
|
||||
*out = align_bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
|
||||
if (type_is_invalid(value->value.type))
|
||||
return false;
|
||||
@@ -12516,23 +12619,8 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out
|
||||
if (type_is_invalid(casted_value->value.type))
|
||||
return false;
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
|
||||
if (!const_val)
|
||||
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"));
|
||||
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));
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = align_bytes;
|
||||
return true;
|
||||
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) {
|
||||
@@ -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<IrInstructionConst>(&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)))
|
||||
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;
|
||||
|
||||
LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1);
|
||||
lazy_opt_type->ira = ira;
|
||||
result->value.data.x_lazy = &lazy_opt_type->base;
|
||||
lazy_opt_type->base.id = LazyValueIdOptType;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdOpaque:
|
||||
ir_add_error_node(ira, un_op_instruction->base.source_node,
|
||||
buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
zig_unreachable();
|
||||
return result;
|
||||
}
|
||||
|
||||
static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type,
|
||||
@@ -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<LazyValueSliceType>(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_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");
|
||||
}
|
||||
|
||||
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 *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad);
|
||||
if (dest_ptr_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);
|
||||
}
|
||||
ConstExprValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk);
|
||||
if (byte_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
return ir_const_void(ira, &instruction->base);
|
||||
ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad);
|
||||
if (count_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
|
||||
casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
|
||||
{
|
||||
ConstExprValue *dest_elements;
|
||||
size_t start;
|
||||
size_t bound_end;
|
||||
switch (dest_ptr_val->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
case ConstPtrSpecialDiscard:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialRef:
|
||||
dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee;
|
||||
start = 0;
|
||||
bound_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
expand_undef_array(ira->codegen, array_val);
|
||||
dest_elements = array_val->data.x_array.data.s_none.elements;
|
||||
start = dest_ptr_val->data.x_ptr.data.base_array.elem_index;
|
||||
bound_end = array_val->type->data.array.len;
|
||||
break;
|
||||
}
|
||||
case ConstPtrSpecialBaseStruct:
|
||||
zig_panic("TODO memset on const inner struct");
|
||||
case ConstPtrSpecialBaseErrorUnionCode:
|
||||
zig_panic("TODO memset on const inner error union code");
|
||||
case ConstPtrSpecialBaseErrorUnionPayload:
|
||||
zig_panic("TODO memset on const inner error union payload");
|
||||
case ConstPtrSpecialBaseOptionalPayload:
|
||||
zig_panic("TODO memset on const inner optional payload");
|
||||
case ConstPtrSpecialHardCodedAddr:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialFunction:
|
||||
zig_panic("TODO memset on ptr cast from function");
|
||||
case ConstPtrSpecialNull:
|
||||
zig_panic("TODO memset on null ptr");
|
||||
}
|
||||
|
||||
size_t count = bigint_as_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 = &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");
|
||||
}
|
||||
|
||||
if (dest_start + count > dest_end) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access"));
|
||||
ConstExprValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad);
|
||||
if (dest_ptr_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;
|
||||
|
||||
switch (src_ptr_val->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
case ConstPtrSpecialDiscard:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialRef:
|
||||
src_elements = src_ptr_val->data.x_ptr.data.ref.pointee;
|
||||
src_start = 0;
|
||||
src_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
expand_undef_array(ira->codegen, array_val);
|
||||
src_elements = array_val->data.x_array.data.s_none.elements;
|
||||
src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index;
|
||||
src_end = array_val->type->data.array.len;
|
||||
break;
|
||||
}
|
||||
case ConstPtrSpecialBaseStruct:
|
||||
zig_panic("TODO memcpy on const inner struct");
|
||||
case ConstPtrSpecialBaseErrorUnionCode:
|
||||
zig_panic("TODO memcpy on const inner error union code");
|
||||
case ConstPtrSpecialBaseErrorUnionPayload:
|
||||
zig_panic("TODO memcpy on const inner error union payload");
|
||||
case ConstPtrSpecialBaseOptionalPayload:
|
||||
zig_panic("TODO memcpy on const inner optional payload");
|
||||
case ConstPtrSpecialHardCodedAddr:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialFunction:
|
||||
zig_panic("TODO memcpy on ptr cast from function");
|
||||
case ConstPtrSpecialNull:
|
||||
zig_panic("TODO memcpy on null ptr");
|
||||
}
|
||||
|
||||
if (src_start + count > src_end) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access"));
|
||||
ConstExprValue *src_ptr_val = ir_resolve_const(ira, casted_src_ptr, UndefBad);
|
||||
if (src_ptr_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad);
|
||||
if (count_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (dest_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
|
||||
size_t count = bigint_as_usize(&count_val->data.x_bigint);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
if (dest_start + count > dest_end) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ConstExprValue *src_elements;
|
||||
size_t src_start;
|
||||
size_t src_end;
|
||||
|
||||
switch (src_ptr_val->data.x_ptr.special) {
|
||||
case ConstPtrSpecialInvalid:
|
||||
case ConstPtrSpecialDiscard:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialRef:
|
||||
src_elements = src_ptr_val->data.x_ptr.data.ref.pointee;
|
||||
src_start = 0;
|
||||
src_end = 1;
|
||||
break;
|
||||
case ConstPtrSpecialBaseArray:
|
||||
{
|
||||
ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val;
|
||||
expand_undef_array(ira->codegen, array_val);
|
||||
src_elements = array_val->data.x_array.data.s_none.elements;
|
||||
src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index;
|
||||
src_end = array_val->type->data.array.len;
|
||||
break;
|
||||
}
|
||||
case ConstPtrSpecialBaseStruct:
|
||||
zig_panic("TODO memcpy on const inner struct");
|
||||
case ConstPtrSpecialBaseErrorUnionCode:
|
||||
zig_panic("TODO memcpy on const inner error union code");
|
||||
case ConstPtrSpecialBaseErrorUnionPayload:
|
||||
zig_panic("TODO memcpy on const inner error union payload");
|
||||
case ConstPtrSpecialBaseOptionalPayload:
|
||||
zig_panic("TODO memcpy on const inner optional payload");
|
||||
case ConstPtrSpecialHardCodedAddr:
|
||||
zig_unreachable();
|
||||
case ConstPtrSpecialFunction:
|
||||
zig_panic("TODO memcpy on ptr cast from function");
|
||||
case ConstPtrSpecialNull:
|
||||
zig_panic("TODO memcpy on null ptr");
|
||||
}
|
||||
|
||||
if (src_start + count > src_end) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown)))
|
||||
LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);
|
||||
lazy_align_of->ira = ira;
|
||||
result->value.data.x_lazy = &lazy_align_of->base;
|
||||
lazy_align_of->base.id = LazyValueIdAlignOf;
|
||||
|
||||
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<LazyValueFnType>(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<IrInstruction *>(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))
|
||||
IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
|
||||
result->value.special = ConstValSpecialLazy;
|
||||
|
||||
LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(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;
|
||||
|
||||
if (child_type->id == ZigTypeIdUnreachable) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (instruction->ptr_len == PtrLenC) {
|
||||
if (!type_allowed_in_extern(ira->codegen, child_type)) {
|
||||
ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (child_type->id == ZigTypeIdOpaque) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (instruction->is_allow_zero) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("C pointers always allow address zero"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t align_bytes;
|
||||
if (instruction->align_value != nullptr) {
|
||||
if (!ir_resolve_align(ira, instruction->align_value->child, &align_bytes))
|
||||
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 ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (!type_has_bits(child_type)) {
|
||||
align_bytes = 0;
|
||||
}
|
||||
} else {
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
align_bytes = 0;
|
||||
}
|
||||
|
||||
bool allow_zero = instruction->is_allow_zero || instruction->ptr_len == PtrLenC;
|
||||
lazy_ptr_type->ptr_len = instruction->ptr_len;
|
||||
lazy_ptr_type->is_const = instruction->is_const;
|
||||
lazy_ptr_type->is_volatile = instruction->is_volatile;
|
||||
lazy_ptr_type->is_allowzero = instruction->is_allow_zero;
|
||||
lazy_ptr_type->bit_offset_in_host = instruction->bit_offset_start;
|
||||
lazy_ptr_type->host_int_bytes = instruction->host_int_bytes;
|
||||
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
instruction->is_const, instruction->is_volatile,
|
||||
instruction->ptr_len, align_bytes,
|
||||
instruction->bit_offset_start, instruction->host_int_bytes, allow_zero);
|
||||
return ir_const_type(ira, &instruction->base, result_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
|
||||
@@ -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<IrAnalyze>(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<LazyValueAlignOf *>(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<LazyValueSliceType *>(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<LazyValuePtrType *>(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<LazyValueOptType *>(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<LazyValueFnType *>(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;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+12
-9
@@ -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;
|
||||
|
||||
+71
-44
@@ -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",
|
||||
);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user