mirror of
https://github.com/ziglang/zig.git
synced 2026-01-30 11:13:38 +00:00
Merge pull request #3115 from ziglang/fix-field-alignment-kludge
fix field alignment kludge by implementing lazy values
This commit is contained in:
commit
35a374efe0
@ -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;
|
||||
|
||||
1173
src/analyze.cpp
1173
src/analyze.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
1396
src/ir.cpp
1396
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -6,20 +6,23 @@ const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub fn ArrayList(comptime T: type) type {
|
||||
return AlignedArrayList(T, @alignOf(T));
|
||||
return AlignedArrayList(T, null);
|
||||
}
|
||||
|
||||
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
/// Use toSlice instead of slicing this directly, because if you don't
|
||||
/// specify the end position of the slice, this will potentially give
|
||||
/// you uninitialized memory.
|
||||
items: []align(A) T,
|
||||
items: Slice,
|
||||
len: usize,
|
||||
allocator: *Allocator,
|
||||
|
||||
pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
|
||||
pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T;
|
||||
|
||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||
pub fn init(allocator: *Allocator) Self {
|
||||
return Self{
|
||||
@ -33,11 +36,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
self.allocator.free(self.items);
|
||||
}
|
||||
|
||||
pub fn toSlice(self: Self) []align(A) T {
|
||||
pub fn toSlice(self: Self) Slice {
|
||||
return self.items[0..self.len];
|
||||
}
|
||||
|
||||
pub fn toSliceConst(self: Self) []align(A) const T {
|
||||
pub fn toSliceConst(self: Self) SliceConst {
|
||||
return self.items[0..self.len];
|
||||
}
|
||||
|
||||
@ -69,7 +72,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
/// ArrayList takes ownership of the passed in slice. The slice must have been
|
||||
/// allocated with `allocator`.
|
||||
/// Deinitialize with `deinit` or use `toOwnedSlice`.
|
||||
pub fn fromOwnedSlice(allocator: *Allocator, slice: []align(A) T) Self {
|
||||
pub fn fromOwnedSlice(allocator: *Allocator, slice: Slice) Self {
|
||||
return Self{
|
||||
.items = slice,
|
||||
.len = slice.len,
|
||||
@ -78,7 +81,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
}
|
||||
|
||||
/// The caller owns the returned memory. ArrayList becomes empty.
|
||||
pub fn toOwnedSlice(self: *Self) []align(A) T {
|
||||
pub fn toOwnedSlice(self: *Self) Slice {
|
||||
const allocator = self.allocator;
|
||||
const result = allocator.shrink(self.items, self.len);
|
||||
self.* = init(allocator);
|
||||
@ -93,7 +96,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
self.items[n] = item;
|
||||
}
|
||||
|
||||
pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
|
||||
pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void {
|
||||
try self.ensureCapacity(self.len + items.len);
|
||||
self.len += items.len;
|
||||
|
||||
@ -141,7 +144,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
return self.swapRemove(i);
|
||||
}
|
||||
|
||||
pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
|
||||
pub fn appendSlice(self: *Self, items: SliceConst) !void {
|
||||
try self.ensureCapacity(self.len + items.len);
|
||||
mem.copy(T, self.items[self.len..], items);
|
||||
self.len += items.len;
|
||||
|
||||
@ -2,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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user