mirror of
https://github.com/ziglang/zig.git
synced 2025-12-13 01:33:09 +00:00
align(@alignOf(T)) T does not force resolution of T
This commit is contained in:
parent
966670645a
commit
d9fed5cdfd
53
src/ir.cpp
53
src/ir.cpp
@ -12613,10 +12613,27 @@ static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
|
static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, ZigType *elem_type, uint32_t *out) {
|
||||||
if (type_is_invalid(value->value.type))
|
if (type_is_invalid(value->value.type))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Look for this pattern: `*align(@alignOf(T)) T`.
|
||||||
|
// This can be resolved to be `*out = 0` without resolving any alignment.
|
||||||
|
if (elem_type != nullptr && value->value.special == ConstValSpecialLazy &&
|
||||||
|
value->value.data.x_lazy->id == LazyValueIdAlignOf)
|
||||||
|
{
|
||||||
|
LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(value->value.data.x_lazy);
|
||||||
|
|
||||||
|
ZigType *lazy_elem_type = ir_resolve_type(lazy_align_of->ira, lazy_align_of->target_type);
|
||||||
|
if (type_is_invalid(lazy_elem_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (elem_type == lazy_elem_type) {
|
||||||
|
*out = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
|
IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
|
||||||
if (type_is_invalid(casted_value->value.type))
|
if (type_is_invalid(casted_value->value.type))
|
||||||
return false;
|
return false;
|
||||||
@ -14424,7 +14441,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
|
|||||||
}
|
}
|
||||||
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
|
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
|
||||||
} else {
|
} else {
|
||||||
if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) {
|
if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, nullptr, &var->align_bytes)) {
|
||||||
var->var_type = ira->codegen->builtin_types.entry_invalid;
|
var->var_type = ira->codegen->builtin_types.entry_invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14879,7 +14896,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
|||||||
|
|
||||||
if (alloca_src->base.child == nullptr || is_comptime) {
|
if (alloca_src->base.child == nullptr || is_comptime) {
|
||||||
uint32_t align = 0;
|
uint32_t align = 0;
|
||||||
if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) {
|
if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, nullptr, &align)) {
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
}
|
}
|
||||||
IrInstruction *alloca_gen;
|
IrInstruction *alloca_gen;
|
||||||
@ -15896,7 +15913,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
|||||||
copy_const_val(&const_instruction->base.value, align_result, true);
|
copy_const_val(&const_instruction->base.value, align_result, true);
|
||||||
|
|
||||||
uint32_t align_bytes = 0;
|
uint32_t align_bytes = 0;
|
||||||
ir_resolve_align(ira, &const_instruction->base, &align_bytes);
|
ir_resolve_align(ira, &const_instruction->base, nullptr, &align_bytes);
|
||||||
impl_fn->align_bytes = align_bytes;
|
impl_fn->align_bytes = align_bytes;
|
||||||
inst_fn_type_id.alignment = align_bytes;
|
inst_fn_type_id.alignment = align_bytes;
|
||||||
}
|
}
|
||||||
@ -23948,7 +23965,7 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
|
|||||||
static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
|
static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
|
||||||
uint32_t align_bytes;
|
uint32_t align_bytes;
|
||||||
IrInstruction *align_bytes_inst = instruction->align_bytes->child;
|
IrInstruction *align_bytes_inst = instruction->align_bytes->child;
|
||||||
if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes))
|
if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes))
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
IrInstruction *target = instruction->target->child;
|
IrInstruction *target = instruction->target->child;
|
||||||
@ -23974,7 +23991,7 @@ static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstr
|
|||||||
static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) {
|
static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) {
|
||||||
uint32_t align_bytes;
|
uint32_t align_bytes;
|
||||||
IrInstruction *align_bytes_inst = instruction->align_bytes->child;
|
IrInstruction *align_bytes_inst = instruction->align_bytes->child;
|
||||||
if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes))
|
if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes))
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
if (align_bytes > 256) {
|
if (align_bytes > 256) {
|
||||||
@ -25555,7 +25572,7 @@ static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, La
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lazy_fn_type->align_inst != nullptr) {
|
if (lazy_fn_type->align_inst != nullptr) {
|
||||||
if (!ir_resolve_align(ira, lazy_fn_type->align_inst, &fn_type_id.alignment))
|
if (!ir_resolve_align(ira, lazy_fn_type->align_inst, nullptr, &fn_type_id.alignment))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25690,15 +25707,16 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
|
|||||||
LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
|
LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy);
|
||||||
IrAnalyze *ira = lazy_slice_type->ira;
|
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;
|
|
||||||
}
|
|
||||||
ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type);
|
ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type);
|
||||||
if (type_is_invalid(elem_type))
|
if (type_is_invalid(elem_type))
|
||||||
return ErrorSemanticAnalyzeFail;
|
return ErrorSemanticAnalyzeFail;
|
||||||
|
|
||||||
|
uint32_t align_bytes = 0;
|
||||||
|
if (lazy_slice_type->align_inst != nullptr) {
|
||||||
|
if (!ir_resolve_align(ira, lazy_slice_type->align_inst, elem_type, &align_bytes))
|
||||||
|
return ErrorSemanticAnalyzeFail;
|
||||||
|
}
|
||||||
|
|
||||||
switch (elem_type->id) {
|
switch (elem_type->id) {
|
||||||
case ZigTypeIdInvalid: // handled above
|
case ZigTypeIdInvalid: // handled above
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
@ -25750,15 +25768,16 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
|
|||||||
LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(val->data.x_lazy);
|
LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(val->data.x_lazy);
|
||||||
IrAnalyze *ira = lazy_ptr_type->ira;
|
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);
|
ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type);
|
||||||
if (type_is_invalid(elem_type))
|
if (type_is_invalid(elem_type))
|
||||||
return ErrorSemanticAnalyzeFail;
|
return ErrorSemanticAnalyzeFail;
|
||||||
|
|
||||||
|
uint32_t align_bytes = 0;
|
||||||
|
if (lazy_ptr_type->align_inst != nullptr) {
|
||||||
|
if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, elem_type, &align_bytes))
|
||||||
|
return ErrorSemanticAnalyzeFail;
|
||||||
|
}
|
||||||
|
|
||||||
if (elem_type->id == ZigTypeIdUnreachable) {
|
if (elem_type->id == ZigTypeIdUnreachable) {
|
||||||
ir_add_error(ira, lazy_ptr_type->elem_type,
|
ir_add_error(ira, lazy_ptr_type->elem_type,
|
||||||
buf_create_from_str("pointer to noreturn not allowed"));
|
buf_create_from_str("pointer to noreturn not allowed"));
|
||||||
|
|||||||
@ -10,6 +10,11 @@ pub fn ArrayList(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
|
pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
|
||||||
|
if (alignment) |a| {
|
||||||
|
if (a == @alignOf(T)) {
|
||||||
|
return AlignedArrayList(T, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
|||||||
18
std/mem.zig
18
std/mem.zig
@ -94,24 +94,30 @@ pub const Allocator = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
|
pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
|
||||||
return self.alignedAlloc(T, @alignOf(T), n);
|
return self.alignedAlloc(T, null, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alignedAlloc(
|
pub fn alignedAlloc(
|
||||||
self: *Allocator,
|
self: *Allocator,
|
||||||
comptime T: type,
|
comptime T: type,
|
||||||
comptime alignment: u29,
|
/// null means naturally aligned
|
||||||
|
comptime alignment: ?u29,
|
||||||
n: usize,
|
n: usize,
|
||||||
) Error![]align(alignment) T {
|
) Error![]align(alignment orelse @alignOf(T)) T {
|
||||||
|
const a = if (alignment) |a| blk: {
|
||||||
|
if (a == @alignOf(T)) return alignedAlloc(self, T, null, n);
|
||||||
|
break :blk a;
|
||||||
|
} else @alignOf(T);
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return ([*]align(alignment) T)(undefined)[0..0];
|
return ([*]align(a) T)(undefined)[0..0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
|
const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
|
||||||
const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, alignment);
|
const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a);
|
||||||
assert(byte_slice.len == byte_count);
|
assert(byte_slice.len == byte_count);
|
||||||
@memset(byte_slice.ptr, undefined, byte_slice.len);
|
@memset(byte_slice.ptr, undefined, byte_slice.len);
|
||||||
return @bytesToSlice(T, @alignCast(alignment, byte_slice));
|
return @bytesToSlice(T, @alignCast(a, byte_slice));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function requests a new byte size for an existing allocation,
|
/// This function requests a new byte size for an existing allocation,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
const expect = @import("std").testing.expect;
|
const std = @import("std");
|
||||||
|
const expect = std.testing.expect;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
var foo: u8 align(4) = 100;
|
var foo: u8 align(4) = 100;
|
||||||
@ -305,3 +306,25 @@ test "struct field explicit alignment" {
|
|||||||
comptime expect(@typeOf(&node.massive_byte) == *align(64) u8);
|
comptime expect(@typeOf(&node.massive_byte) == *align(64) u8);
|
||||||
expect(@ptrToInt(&node.massive_byte) % 64 == 0);
|
expect(@ptrToInt(&node.massive_byte) % 64 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "align(@alignOf(T)) T does not force resolution of T" {
|
||||||
|
const S = struct {
|
||||||
|
const A = struct {
|
||||||
|
a: *align(@alignOf(A)) A,
|
||||||
|
};
|
||||||
|
fn doTheTest() void {
|
||||||
|
suspend {
|
||||||
|
resume @frame();
|
||||||
|
}
|
||||||
|
_ = bar(@Frame(doTheTest));
|
||||||
|
}
|
||||||
|
fn bar(comptime T: type) *align(@alignOf(T)) T {
|
||||||
|
ok = true;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok = false;
|
||||||
|
};
|
||||||
|
_ = async S.doTheTest();
|
||||||
|
expect(S.ok);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user