Merge pull request #3115 from ziglang/fix-field-alignment-kludge

fix field alignment kludge by implementing lazy values
This commit is contained in:
Andrew Kelley 2019-08-27 13:02:31 -04:00 committed by GitHub
commit 35a374efe0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1821 additions and 1086 deletions

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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",
);

View File

@ -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);
}

View File

@ -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);
}