Skip to content

Commit d9fed5c

Browse files
committed
align(@Alignof(T)) T does not force resolution of T
1 parent 9666706 commit d9fed5c

File tree

4 files changed

+75
-22
lines changed

4 files changed

+75
-22
lines changed

src/ir.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12613,10 +12613,27 @@ static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode
1261312613
return true;
1261412614
}
1261512615

12616-
static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
12616+
static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, ZigType *elem_type, uint32_t *out) {
1261712617
if (type_is_invalid(value->value.type))
1261812618
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+
1262012637
IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
1262112638
if (type_is_invalid(casted_value->value.type))
1262212639
return false;
@@ -14424,7 +14441,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
1442414441
}
1442514442
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
1442614443
} 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)) {
1442814445
var->var_type = ira->codegen->builtin_types.entry_invalid;
1442914446
}
1443014447
}
@@ -14879,7 +14896,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1487914896

1488014897
if (alloca_src->base.child == nullptr || is_comptime) {
1488114898
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)) {
1488314900
return ira->codegen->invalid_instruction;
1488414901
}
1488514902
IrInstruction *alloca_gen;
@@ -15896,7 +15913,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1589615913
copy_const_val(&const_instruction->base.value, align_result, true);
1589715914

1589815915
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);
1590015917
impl_fn->align_bytes = align_bytes;
1590115918
inst_fn_type_id.alignment = align_bytes;
1590215919
}
@@ -23948,7 +23965,7 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
2394823965
static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
2394923966
uint32_t align_bytes;
2395023967
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))
2395223969
return ira->codegen->invalid_instruction;
2395323970

2395423971
IrInstruction *target = instruction->target->child;
@@ -23974,7 +23991,7 @@ static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstr
2397423991
static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) {
2397523992
uint32_t align_bytes;
2397623993
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))
2397823995
return ira->codegen->invalid_instruction;
2397923996

2398023997
if (align_bytes > 256) {
@@ -25555,7 +25572,7 @@ static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, La
2555525572
}
2555625573

2555725574
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))
2555925576
return nullptr;
2556025577
}
2556125578

@@ -25690,14 +25707,15 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
2569025707
LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
2569125708
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+
2569325714
uint32_t align_bytes = 0;
2569425715
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))
2569625717
return ErrorSemanticAnalyzeFail;
2569725718
}
25698-
ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type);
25699-
if (type_is_invalid(elem_type))
25700-
return ErrorSemanticAnalyzeFail;
2570125719

2570225720
switch (elem_type->id) {
2570325721
case ZigTypeIdInvalid: // handled above
@@ -25750,14 +25768,15 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
2575025768
LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(val->data.x_lazy);
2575125769
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+
2575325775
uint32_t align_bytes = 0;
2575425776
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))
2575625778
return ErrorSemanticAnalyzeFail;
2575725779
}
25758-
ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type);
25759-
if (type_is_invalid(elem_type))
25760-
return ErrorSemanticAnalyzeFail;
2576125780

2576225781
if (elem_type->id == ZigTypeIdUnreachable) {
2576325782
ir_add_error(ira, lazy_ptr_type->elem_type,

std/array_list.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ pub fn ArrayList(comptime T: type) type {
1010
}
1111

1212
pub 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+
}
1318
return struct {
1419
const Self = @This();
1520

std/mem.zig

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,24 +94,30 @@ pub const Allocator = struct {
9494
}
9595

9696
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);
9898
}
9999

100100
pub fn alignedAlloc(
101101
self: *Allocator,
102102
comptime T: type,
103-
comptime alignment: u29,
103+
/// null means naturally aligned
104+
comptime alignment: ?u29,
104105
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+
106112
if (n == 0) {
107-
return ([*]align(alignment) T)(undefined)[0..0];
113+
return ([*]align(a) T)(undefined)[0..0];
108114
}
109115

110116
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);
112118
assert(byte_slice.len == byte_count);
113119
@memset(byte_slice.ptr, undefined, byte_slice.len);
114-
return @bytesToSlice(T, @alignCast(alignment, byte_slice));
120+
return @bytesToSlice(T, @alignCast(a, byte_slice));
115121
}
116122

117123
/// This function requests a new byte size for an existing allocation,

test/stage1/behavior/align.zig

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const expect = @import("std").testing.expect;
1+
const std = @import("std");
2+
const expect = std.testing.expect;
23
const builtin = @import("builtin");
34

45
var foo: u8 align(4) = 100;
@@ -305,3 +306,25 @@ test "struct field explicit alignment" {
305306
comptime expect(@typeOf(&node.massive_byte) == *align(64) u8);
306307
expect(@ptrToInt(&node.massive_byte) % 64 == 0);
307308
}
309+
310+
test "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+
}

0 commit comments

Comments
 (0)