authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-30 14:53:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-30 14:53:44-04:00
logd9fed5cdfdfa6ac944856cd360d3385296f136e8
tree6c57968453032c3e3cb8605bf925533bddd94705
parent966670645a382e6c660b4a002e5eb1264a00cbe5
signaturelock-open Commit is signed but in an unrecognized format.

align(@alignOf(T)) T does not force resolution of T


4 files changed, 75 insertions(+), 22 deletions(-)

src/ir.cpp+34-15
...@@ -12613,10 +12613,27 @@ static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode...@@ -12613,10 +12613,27 @@ static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode
12613 return true;12613 return true;
12614}12614}
1261512615
12616static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {12616static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, ZigType *elem_type, uint32_t *out) {
12617 if (type_is_invalid(value->value.type))12617 if (type_is_invalid(value->value.type))
12618 return false;12618 return false;
1261912619
12620 // Look for this pattern: `*align(@alignOf(T)) T`.
12621 // This can be resolved to be `*out = 0` without resolving any alignment.
12622 if (elem_type != nullptr && value->value.special == ConstValSpecialLazy &&
12623 value->value.data.x_lazy->id == LazyValueIdAlignOf)
12624 {
12625 LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(value->value.data.x_lazy);
12626
12627 ZigType *lazy_elem_type = ir_resolve_type(lazy_align_of->ira, lazy_align_of->target_type);
12628 if (type_is_invalid(lazy_elem_type))
12629 return false;
12630
12631 if (elem_type == lazy_elem_type) {
12632 *out = 0;
12633 return true;
12634 }
12635 }
12636
12620 IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));12637 IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
12621 if (type_is_invalid(casted_value->value.type))12638 if (type_is_invalid(casted_value->value.type))
12622 return false;12639 return false;
...@@ -14424,7 +14441,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,...@@ -14424,7 +14441,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
14424 }14441 }
14425 var->align_bytes = get_abi_alignment(ira->codegen, result_type);14442 var->align_bytes = get_abi_alignment(ira->codegen, result_type);
14426 } else {14443 } else {
14427 if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) {14444 if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, nullptr, &var->align_bytes)) {
14428 var->var_type = ira->codegen->builtin_types.entry_invalid;14445 var->var_type = ira->codegen->builtin_types.entry_invalid;
14429 }14446 }
14430 }14447 }
...@@ -14879,7 +14896,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe...@@ -14879,7 +14896,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1487914896
14880 if (alloca_src->base.child == nullptr || is_comptime) {14897 if (alloca_src->base.child == nullptr || is_comptime) {
14881 uint32_t align = 0;14898 uint32_t align = 0;
14882 if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) {14899 if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, nullptr, &align)) {
14883 return ira->codegen->invalid_instruction;14900 return ira->codegen->invalid_instruction;
14884 }14901 }
14885 IrInstruction *alloca_gen;14902 IrInstruction *alloca_gen;
...@@ -15896,7 +15913,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15896,7 +15913,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
15896 copy_const_val(&const_instruction->base.value, align_result, true);15913 copy_const_val(&const_instruction->base.value, align_result, true);
1589715914
15898 uint32_t align_bytes = 0;15915 uint32_t align_bytes = 0;
15899 ir_resolve_align(ira, &const_instruction->base, &align_bytes);15916 ir_resolve_align(ira, &const_instruction->base, nullptr, &align_bytes);
15900 impl_fn->align_bytes = align_bytes;15917 impl_fn->align_bytes = align_bytes;
15901 inst_fn_type_id.alignment = align_bytes;15918 inst_fn_type_id.alignment = align_bytes;
15902 }15919 }
...@@ -23948,7 +23965,7 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct...@@ -23948,7 +23965,7 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
23948static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {23965static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
23949 uint32_t align_bytes;23966 uint32_t align_bytes;
23950 IrInstruction *align_bytes_inst = instruction->align_bytes->child;23967 IrInstruction *align_bytes_inst = instruction->align_bytes->child;
23951 if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes))23968 if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes))
23952 return ira->codegen->invalid_instruction;23969 return ira->codegen->invalid_instruction;
2395323970
23954 IrInstruction *target = instruction->target->child;23971 IrInstruction *target = instruction->target->child;
...@@ -23974,7 +23991,7 @@ static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstr...@@ -23974,7 +23991,7 @@ static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstr
23974static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) {23991static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) {
23975 uint32_t align_bytes;23992 uint32_t align_bytes;
23976 IrInstruction *align_bytes_inst = instruction->align_bytes->child;23993 IrInstruction *align_bytes_inst = instruction->align_bytes->child;
23977 if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes))23994 if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes))
23978 return ira->codegen->invalid_instruction;23995 return ira->codegen->invalid_instruction;
2397923996
23980 if (align_bytes > 256) {23997 if (align_bytes > 256) {
...@@ -25555,7 +25572,7 @@ static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, La...@@ -25555,7 +25572,7 @@ static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, La
25555 }25572 }
2555625573
25557 if (lazy_fn_type->align_inst != nullptr) {25574 if (lazy_fn_type->align_inst != nullptr) {
25558 if (!ir_resolve_align(ira, lazy_fn_type->align_inst, &fn_type_id.alignment))25575 if (!ir_resolve_align(ira, lazy_fn_type->align_inst, nullptr, &fn_type_id.alignment))
25559 return nullptr;25576 return nullptr;
25560 }25577 }
2556125578
...@@ -25690,14 +25707,15 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -25690,14 +25707,15 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
25690 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);25707 LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
25691 IrAnalyze *ira = lazy_slice_type->ira;25708 IrAnalyze *ira = lazy_slice_type->ira;
2569225709
25710 ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type);
25711 if (type_is_invalid(elem_type))
25712 return ErrorSemanticAnalyzeFail;
25713
25693 uint32_t align_bytes = 0;25714 uint32_t align_bytes = 0;
25694 if (lazy_slice_type->align_inst != nullptr) {25715 if (lazy_slice_type->align_inst != nullptr) {
25695 if (!ir_resolve_align(ira, lazy_slice_type->align_inst, &align_bytes))25716 if (!ir_resolve_align(ira, lazy_slice_type->align_inst, elem_type, &align_bytes))
25696 return ErrorSemanticAnalyzeFail;25717 return ErrorSemanticAnalyzeFail;
25697 }25718 }
25698 ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type);
25699 if (type_is_invalid(elem_type))
25700 return ErrorSemanticAnalyzeFail;
2570125719
25702 switch (elem_type->id) {25720 switch (elem_type->id) {
25703 case ZigTypeIdInvalid: // handled above25721 case ZigTypeIdInvalid: // handled above
...@@ -25750,14 +25768,15 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -25750,14 +25768,15 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
25750 LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(val->data.x_lazy);25768 LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(val->data.x_lazy);
25751 IrAnalyze *ira = lazy_ptr_type->ira;25769 IrAnalyze *ira = lazy_ptr_type->ira;
2575225770
25771 ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type);
25772 if (type_is_invalid(elem_type))
25773 return ErrorSemanticAnalyzeFail;
25774
25753 uint32_t align_bytes = 0;25775 uint32_t align_bytes = 0;
25754 if (lazy_ptr_type->align_inst != nullptr) {25776 if (lazy_ptr_type->align_inst != nullptr) {
25755 if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, &align_bytes))25777 if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, elem_type, &align_bytes))
25756 return ErrorSemanticAnalyzeFail;25778 return ErrorSemanticAnalyzeFail;
25757 }25779 }
25758 ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type);
25759 if (type_is_invalid(elem_type))
25760 return ErrorSemanticAnalyzeFail;
2576125780
25762 if (elem_type->id == ZigTypeIdUnreachable) {25781 if (elem_type->id == ZigTypeIdUnreachable) {
25763 ir_add_error(ira, lazy_ptr_type->elem_type,25782 ir_add_error(ira, lazy_ptr_type->elem_type,
std/array_list.zig+5
...@@ -10,6 +10,11 @@ pub fn ArrayList(comptime T: type) type {...@@ -10,6 +10,11 @@ pub fn ArrayList(comptime T: type) type {
10}10}
1111
12pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {12pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
13 if (alignment) |a| {
14 if (a == @alignOf(T)) {
15 return AlignedArrayList(T, null);
16 }
17 }
13 return struct {18 return struct {
14 const Self = @This();19 const Self = @This();
1520
std/mem.zig+12-6
...@@ -94,24 +94,30 @@ pub const Allocator = struct {...@@ -94,24 +94,30 @@ pub const Allocator = struct {
94 }94 }
9595
96 pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {96 pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
97 return self.alignedAlloc(T, @alignOf(T), n);97 return self.alignedAlloc(T, null, n);
98 }98 }
9999
100 pub fn alignedAlloc(100 pub fn alignedAlloc(
101 self: *Allocator,101 self: *Allocator,
102 comptime T: type,102 comptime T: type,
103 comptime alignment: u29,103 /// null means naturally aligned
104 comptime alignment: ?u29,
104 n: usize,105 n: usize,
105 ) Error![]align(alignment) T {106 ) Error![]align(alignment orelse @alignOf(T)) T {
107 const a = if (alignment) |a| blk: {
108 if (a == @alignOf(T)) return alignedAlloc(self, T, null, n);
109 break :blk a;
110 } else @alignOf(T);
111
106 if (n == 0) {112 if (n == 0) {
107 return ([*]align(alignment) T)(undefined)[0..0];113 return ([*]align(a) T)(undefined)[0..0];
108 }114 }
109115
110 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;116 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
111 const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, alignment);117 const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a);
112 assert(byte_slice.len == byte_count);118 assert(byte_slice.len == byte_count);
113 @memset(byte_slice.ptr, undefined, byte_slice.len);119 @memset(byte_slice.ptr, undefined, byte_slice.len);
114 return @bytesToSlice(T, @alignCast(alignment, byte_slice));120 return @bytesToSlice(T, @alignCast(a, byte_slice));
115 }121 }
116122
117 /// This function requests a new byte size for an existing allocation,123 /// This function requests a new byte size for an existing allocation,
test/stage1/behavior/align.zig+24-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const expect = std.testing.expect;
2const builtin = @import("builtin");3const builtin = @import("builtin");
34
4var foo: u8 align(4) = 100;5var foo: u8 align(4) = 100;
...@@ -305,3 +306,25 @@ test "struct field explicit alignment" {...@@ -305,3 +306,25 @@ test "struct field explicit alignment" {
305 comptime expect(@typeOf(&node.massive_byte) == *align(64) u8);306 comptime expect(@typeOf(&node.massive_byte) == *align(64) u8);
306 expect(@ptrToInt(&node.massive_byte) % 64 == 0);307 expect(@ptrToInt(&node.massive_byte) % 64 == 0);
307}308}
309
310test "align(@alignOf(T)) T does not force resolution of T" {
311 const S = struct {
312 const A = struct {
313 a: *align(@alignOf(A)) A,
314 };
315 fn doTheTest() void {
316 suspend {
317 resume @frame();
318 }
319 _ = bar(@Frame(doTheTest));
320 }
321 fn bar(comptime T: type) *align(@alignOf(T)) T {
322 ok = true;
323 return undefined;
324 }
325
326 var ok = false;
327 };
328 _ = async S.doTheTest();
329 expect(S.ok);
330}