mirror of
https://github.com/ziglang/zig.git
synced 2026-02-09 11:03:30 +00:00
Sema: implement pointer to tuple to pointer to array coercion
This involved an LLVM backend fix for the aggregate_init instruction.
This commit is contained in:
parent
017d3864de
commit
f736cde397
62
src/Sema.zig
62
src/Sema.zig
@ -16005,9 +16005,17 @@ fn coerce(
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
|
||||
// coercion to C pointer
|
||||
if (dest_info.size == .C) {
|
||||
switch (inst_ty.zigTypeTag()) {
|
||||
// cast from *T and [*]T to *anyopaque
|
||||
// but don't do it if the source type is a double pointer
|
||||
if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
|
||||
inst_ty.childType().zigTypeTag() != .Pointer)
|
||||
{
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
|
||||
switch (dest_info.size) {
|
||||
// coercion to C pointer
|
||||
.C => switch (inst_ty.zigTypeTag()) {
|
||||
.Null => {
|
||||
return sema.addConstant(dest_ty, Value.@"null");
|
||||
},
|
||||
@ -16041,22 +16049,10 @@ fn coerce(
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// cast from *T and [*]T to *anyopaque
|
||||
// but don't do it if the source type is a double pointer
|
||||
if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
|
||||
inst_ty.childType().zigTypeTag() != .Pointer)
|
||||
{
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
|
||||
switch (dest_info.size) {
|
||||
.C, .Many => {},
|
||||
},
|
||||
.One => switch (dest_info.pointee_type.zigTypeTag()) {
|
||||
.Union => {
|
||||
// cast from pointer to anonymous struct to pointer to union
|
||||
// pointer to anonymous struct to pointer to union
|
||||
if (inst_ty.isSinglePointer() and
|
||||
inst_ty.childType().isAnonStruct() and
|
||||
!dest_info.mutable)
|
||||
@ -16065,7 +16061,7 @@ fn coerce(
|
||||
}
|
||||
},
|
||||
.Struct => {
|
||||
// cast from pointer to anonymous struct to pointer to struct
|
||||
// pointer to anonymous struct to pointer to struct
|
||||
if (inst_ty.isSinglePointer() and
|
||||
inst_ty.childType().isAnonStruct() and
|
||||
!dest_info.mutable)
|
||||
@ -16073,6 +16069,15 @@ fn coerce(
|
||||
return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Array => {
|
||||
// pointer to tuple to pointer to array
|
||||
if (inst_ty.isSinglePointer() and
|
||||
inst_ty.childType().isTuple() and
|
||||
!dest_info.mutable)
|
||||
{
|
||||
return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Slice => {
|
||||
@ -16084,6 +16089,7 @@ fn coerce(
|
||||
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Many => {},
|
||||
}
|
||||
|
||||
// This will give an extra hint on top of what the bottom of this func would provide.
|
||||
@ -17554,6 +17560,26 @@ fn coerceTupleToSlicePtrs(
|
||||
return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
|
||||
}
|
||||
|
||||
/// If the lengths match, coerces element-wise.
|
||||
fn coerceTupleToArrayPtrs(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
ptr_array_ty: Type,
|
||||
array_ty_src: LazySrcLoc,
|
||||
ptr_tuple: Air.Inst.Ref,
|
||||
tuple_src: LazySrcLoc,
|
||||
) !Air.Inst.Ref {
|
||||
const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
|
||||
const ptr_info = ptr_array_ty.ptrInfo().data;
|
||||
const array_ty = ptr_info.pointee_type;
|
||||
const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src);
|
||||
if (ptr_info.@"align" != 0) {
|
||||
return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{});
|
||||
}
|
||||
const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst);
|
||||
return ptr_array;
|
||||
}
|
||||
|
||||
/// Handles both tuples and anon struct literals. Coerces field-wise. Reports
|
||||
/// errors for both extra fields and missing fields.
|
||||
fn coerceTupleToStruct(
|
||||
|
||||
@ -5838,8 +5838,15 @@ pub const FuncGen = struct {
|
||||
const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?;
|
||||
indices[1] = llvm_u32.constInt(llvm_i, .False);
|
||||
const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
|
||||
const store_inst = self.builder.buildStore(llvm_elem, field_ptr);
|
||||
store_inst.setAlignment(result_ty.structFieldAlign(i, target));
|
||||
var field_ptr_payload: Type.Payload.Pointer = .{
|
||||
.data = .{
|
||||
.pointee_type = self.air.typeOf(elem),
|
||||
.@"align" = result_ty.structFieldAlign(i, target),
|
||||
.@"addrspace" = .generic,
|
||||
},
|
||||
};
|
||||
const field_ptr_ty = Type.initPayload(&field_ptr_payload.base);
|
||||
self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);
|
||||
}
|
||||
|
||||
return alloca_inst;
|
||||
@ -5871,8 +5878,14 @@ pub const FuncGen = struct {
|
||||
};
|
||||
const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
|
||||
const llvm_elem = try self.resolveInst(elem);
|
||||
const store_inst = self.builder.buildStore(llvm_elem, elem_ptr);
|
||||
store_inst.setAlignment(elem_ty.abiAlignment(target));
|
||||
var elem_ptr_payload: Type.Payload.Pointer = .{
|
||||
.data = .{
|
||||
.pointee_type = elem_ty,
|
||||
.@"addrspace" = .generic,
|
||||
},
|
||||
};
|
||||
const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);
|
||||
self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
|
||||
}
|
||||
|
||||
return alloca_inst;
|
||||
|
||||
@ -193,11 +193,9 @@ test "function alignment" {
|
||||
}
|
||||
|
||||
test "implicitly decreasing fn alignment" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
@ -321,7 +319,6 @@ const DefaultAligned = struct {
|
||||
|
||||
test "read 128-bit field from default aligned struct in stack memory" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
@ -353,10 +350,10 @@ test "read 128-bit field from default aligned struct in global memory" {
|
||||
|
||||
test "struct field explicit alignment" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
const Node = struct {
|
||||
@ -402,8 +399,9 @@ test "align(@alignOf(T)) T does not force resolution of T" {
|
||||
}
|
||||
|
||||
test "align(N) on functions" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
@ -553,12 +553,11 @@ test "type coercion of anon struct literal to array" {
|
||||
}
|
||||
|
||||
test "type coercion of pointer to anon struct literal to pointer to array" {
|
||||
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
const U = union {
|
||||
|
||||
@ -760,7 +760,8 @@ test "pointer to thread local array" {
|
||||
threadlocal var buffer: [11]u8 = undefined;
|
||||
|
||||
test "auto created variables have correct alignment" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn foo(str: [*]const u8) u32 {
|
||||
|
||||
@ -518,7 +518,11 @@ test "slice syntax resulting in pointer-to-array" {
|
||||
}
|
||||
|
||||
test "type coercion of pointer to anon struct literal to pointer to slice" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
const U = union {
|
||||
@ -546,7 +550,7 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
|
||||
try expect(mem.eql(u8, slice2[2], "world!"));
|
||||
}
|
||||
};
|
||||
// try S.doTheTest();
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
@ -578,8 +582,6 @@ test "slice bounds in comptime concatenation" {
|
||||
}
|
||||
|
||||
test "slice sentinel access at comptime" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
{
|
||||
const str0 = &[_:0]u8{ '1', '2', '3' };
|
||||
const slice0: [:0]const u8 = str0;
|
||||
|
||||
@ -426,7 +426,7 @@ test "packed struct 24bits" {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.stage2_arch == .wasm32) return error.SkipZigTest; // TODO
|
||||
if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
|
||||
|
||||
comptime {
|
||||
try expect(@sizeOf(Foo24Bits) == 4);
|
||||
|
||||
@ -289,9 +289,8 @@ test "while bool 2 break statements and an else" {
|
||||
}
|
||||
|
||||
test "while optional 2 break statements and an else" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn entry(opt_t: ?bool, f: bool) !void {
|
||||
@ -308,7 +307,8 @@ test "while optional 2 break statements and an else" {
|
||||
}
|
||||
|
||||
test "while error 2 break statements and an else" {
|
||||
if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn entry(opt_t: anyerror!bool, f: bool) !void {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user