Commit f32a77b30d
Changed files (5)
test
behavior
src/Sema.zig
@@ -16052,13 +16052,38 @@ fn coerce(
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
}
- // cast from pointer to anonymous struct to pointer to union
- if (dest_info.pointee_type.zigTypeTag() == .Union and
- inst_ty.zigTypeTag() == .Pointer and
- inst_ty.childType().tag() == .anon_struct and
- !dest_info.mutable)
- {
- return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, 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
+ if (inst_ty.isSinglePointer() and
+ inst_ty.childType().isAnonStruct() and
+ !dest_info.mutable)
+ {
+ return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
+ }
+ },
+ .Struct => {
+ // cast from pointer to anonymous struct to pointer to struct
+ if (inst_ty.isSinglePointer() and
+ inst_ty.childType().isAnonStruct() and
+ !dest_info.mutable)
+ {
+ return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
+ }
+ },
+ else => {},
+ },
+ .Slice => {
+ // pointer to tuple to slice
+ if (inst_ty.isSinglePointer() and
+ inst_ty.childType().isTuple() and
+ !dest_info.mutable and dest_info.size == .Slice)
+ {
+ return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
+ }
+ },
}
// This will give an extra hint on top of what the bottom of this func would provide.
@@ -17365,6 +17390,20 @@ fn coerceAnonStructToUnionPtrs(
return sema.analyzeRef(block, union_ty_src, union_inst);
}
+fn coerceAnonStructToStructPtrs(
+ sema: *Sema,
+ block: *Block,
+ ptr_struct_ty: Type,
+ struct_ty_src: LazySrcLoc,
+ ptr_anon_struct: Air.Inst.Ref,
+ anon_struct_src: LazySrcLoc,
+) !Air.Inst.Ref {
+ const struct_ty = ptr_struct_ty.childType();
+ const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
+ const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, struct_ty_src, anon_struct, anon_struct_src);
+ return sema.analyzeRef(block, struct_ty_src, struct_inst);
+}
+
/// If the lengths match, coerces element-wise.
fn coerceArrayLike(
sema: *Sema,
@@ -17494,6 +17533,27 @@ fn coerceTupleToArray(
);
}
+/// If the lengths match, coerces element-wise.
+fn coerceTupleToSlicePtrs(
+ sema: *Sema,
+ block: *Block,
+ slice_ty: Type,
+ slice_ty_src: LazySrcLoc,
+ ptr_tuple: Air.Inst.Ref,
+ tuple_src: LazySrcLoc,
+) !Air.Inst.Ref {
+ const tuple_ty = sema.typeOf(ptr_tuple).childType();
+ const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
+ const slice_info = slice_ty.ptrInfo().data;
+ const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type);
+ const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src);
+ if (slice_info.@"align" != 0) {
+ return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{});
+ }
+ const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst);
+ return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
+}
+
/// Handles both tuples and anon struct literals. Coerces field-wise. Reports
/// errors for both extra fields and missing fields.
fn coerceTupleToStruct(
@@ -17504,11 +17564,13 @@ fn coerceTupleToStruct(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
- if (dest_ty.isTupleOrAnonStruct()) {
+ const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty);
+
+ if (struct_ty.isTupleOrAnonStruct()) {
return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{});
}
- const fields = dest_ty.structFields();
+ const fields = struct_ty.structFields();
const field_vals = try sema.arena.alloc(Value, fields.count());
const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
mem.set(Air.Inst.Ref, field_refs, .none);
@@ -17523,7 +17585,7 @@ fn coerceTupleToStruct(
payload.data.names[i]
else
try std.fmt.allocPrint(sema.arena, "{d}", .{i});
- const field_index = try sema.structFieldIndex(block, dest_ty, field_name, field_src);
+ const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
const field = fields.values()[field_index];
if (field.is_comptime) {
return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{});
@@ -17567,17 +17629,17 @@ fn coerceTupleToStruct(
}
if (root_msg) |msg| {
- try sema.addDeclaredHereNote(msg, dest_ty);
+ try sema.addDeclaredHereNote(msg, struct_ty);
return sema.failWithOwnedErrorMsg(block, msg);
}
if (runtime_src) |rs| {
try sema.requireRuntimeBlock(block, rs);
- return block.addAggregateInit(dest_ty, field_refs);
+ return block.addAggregateInit(struct_ty, field_refs);
}
return sema.addConstant(
- dest_ty,
+ struct_ty,
try Value.Tag.@"struct".create(sema.arena, field_vals),
);
}
src/type.zig
@@ -3502,6 +3502,7 @@ pub const Type = extern union {
.tuple => ty.castTag(.tuple).?.data.types.len,
.anon_struct => ty.castTag(.anon_struct).?.data.types.len,
.@"struct" => ty.castTag(.@"struct").?.data.fields.count(),
+ .empty_struct, .empty_struct_literal => 0,
else => unreachable,
};
@@ -5070,7 +5071,7 @@ pub const Type = extern union {
pub fn isAnonStruct(ty: Type) bool {
return switch (ty.tag()) {
- .anon_struct => true,
+ .anon_struct, .empty_struct_literal => true,
else => false,
};
}
test/behavior/align.zig
@@ -6,17 +6,15 @@ const native_arch = builtin.target.cpu.arch;
var foo: u8 align(4) = 100;
test "global variable alignment" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
comptime try expect(@TypeOf(&foo) == *align(4) u8);
{
- const slice = @as(*[1]u8, &foo)[0..];
+ const slice = @as(*align(4) [1]u8, &foo)[0..];
comptime try expect(@TypeOf(slice) == *align(4) [1]u8);
}
{
var runtime_zero: usize = 0;
- const slice = @as(*[1]u8, &foo)[runtime_zero..];
+ const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];
comptime try expect(@TypeOf(slice) == []align(4) u8);
}
}
@@ -86,8 +84,6 @@ test "size of extern struct with 128-bit field" {
}
test "@ptrCast preserves alignment of bigger source" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
var x: u32 align(16) = 1234;
const ptr = @ptrCast(*u8, &x);
try expect(@TypeOf(ptr) == *align(16) u8);
test/behavior/struct.zig
@@ -1072,7 +1072,11 @@ test "type coercion of anon struct literal to struct" {
}
test "type coercion of pointer to anon struct literal to pointer to struct" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ 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_aarch64) return error.SkipZigTest; // TODO
const S = struct {
const S2 = struct {
test/behavior/tuple.zig
@@ -159,8 +159,8 @@ test "array-like initializer for tuple types" {
const S = struct {
fn doTheTest() !void {
var obj: T = .{ -1234, 128 };
- try testing.expectEqual(@as(i32, -1234), obj[0]);
- try testing.expectEqual(@as(u8, 128), obj[1]);
+ try expect(@as(i32, -1234) == obj[0]);
+ try expect(@as(u8, 128) == obj[1]);
}
};