| author | |
| committer | |
| log | aa3db7cc15520228c0b44328198c78a31e194209 |
| tree | 8df74ef528c3bfdefe00d95f98ad9e0acd9b8afe |
| parent | ea57fb55ea3e433ffb2801f818084fdc9a3c5618 |
Resolves: #232102 files changed, 72 insertions(+), 1 deletions(-)
src/Sema.zig+31-1| ... | ... | @@ -20310,11 +20310,41 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is |
| 20310 | 20310 | const zcu = pt.zcu; |
| 20311 | 20311 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 20312 | 20312 | const src = block.nodeOffset(inst_data.src_node); |
| 20313 | ||
| 20313 | 20314 | // Generic poison means this is an untyped anonymous empty struct/array init |
| 20314 | const ty_operand = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse return .empty_tuple; | |
| 20315 | const ty_operand = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse { | |
| 20316 | if (is_byref) { | |
| 20317 | return sema.uavRef(.empty_tuple); | |
| 20318 | } else { | |
| 20319 | return .empty_tuple; | |
| 20320 | } | |
| 20321 | }; | |
| 20322 | ||
| 20315 | 20323 | const init_ty = if (is_byref) ty: { |
| 20316 | 20324 | const ptr_ty = ty_operand.optEuBaseType(zcu); |
| 20317 | 20325 | assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction |
| 20326 | switch (ptr_ty.ptrSize(zcu)) { | |
| 20327 | // Use a zero-length array for a slice or many-ptr result | |
| 20328 | .slice, .many => break :ty try pt.arrayType(.{ | |
| 20329 | .len = 0, | |
| 20330 | .child = ptr_ty.childType(zcu).toIntern(), | |
| 20331 | .sentinel = if (ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, | |
| 20332 | }), | |
| 20333 | // Just use the child type for a single-pointer or C-pointer result | |
| 20334 | .one, .c => { | |
| 20335 | const child = ptr_ty.childType(zcu); | |
| 20336 | if (child.toIntern() == .anyopaque_type) { | |
| 20337 | // ...unless that child is anyopaque, in which case this is equivalent to an untyped init. | |
| 20338 | // `.{}` is an empty tuple. | |
| 20339 | if (is_byref) { | |
| 20340 | return sema.uavRef(.empty_tuple); | |
| 20341 | } else { | |
| 20342 | return .empty_tuple; | |
| 20343 | } | |
| 20344 | } | |
| 20345 | break :ty child; | |
| 20346 | }, | |
| 20347 | } | |
| 20318 | 20348 | if (!ptr_ty.isSlice(zcu)) { |
| 20319 | 20349 | break :ty ptr_ty.childType(zcu); |
| 20320 | 20350 | } |
test/behavior/array.zig+41| ... | ... | @@ -1094,3 +1094,44 @@ test "@splat zero-length array" { |
| 1094 | 1094 | try S.doTheTest(?*anyopaque, null); |
| 1095 | 1095 | try comptime S.doTheTest(?*anyopaque, null); |
| 1096 | 1096 | } |
| 1097 | ||
| 1098 | test "initialize slice with reference to empty array initializer" { | |
| 1099 | const a: []const u8 = &.{}; | |
| 1100 | comptime assert(a.len == 0); | |
| 1101 | } | |
| 1102 | ||
| 1103 | test "initialize many-pointer with reference to empty array initializer" { | |
| 1104 | const a: [*]const u8 = &.{}; | |
| 1105 | _ = a; // nothing meaningful to test; points to zero bits | |
| 1106 | } | |
| 1107 | ||
| 1108 | test "initialize sentinel-terminated slice with reference to empty array initializer" { | |
| 1109 | const a: [:0]const u8 = &.{}; | |
| 1110 | comptime assert(a.len == 0); | |
| 1111 | comptime assert(a[0] == 0); | |
| 1112 | } | |
| 1113 | ||
| 1114 | test "initialize sentinel-terminated many-pointer with reference to empty array initializer" { | |
| 1115 | const a: [*:0]const u8 = &.{}; | |
| 1116 | comptime assert(a[0] == 0); | |
| 1117 | } | |
| 1118 | ||
| 1119 | test "pass pointer to empty array initializer to anytype parameter" { | |
| 1120 | const S = struct { | |
| 1121 | fn TypeOf(x: anytype) type { | |
| 1122 | return @TypeOf(x); | |
| 1123 | } | |
| 1124 | }; | |
| 1125 | comptime assert(S.TypeOf(&.{}) == @TypeOf(&.{})); | |
| 1126 | } | |
| 1127 | ||
| 1128 | test "initialize pointer to anyopaque with reference to empty array initializer" { | |
| 1129 | const ptr: *const anyopaque = &.{}; | |
| 1130 | // The above acts like an untyped initializer, since the `.{}` has no result type. | |
| 1131 | // So, `ptr` points in memory to an empty tuple (`@TypeOf(.{})`). | |
| 1132 | const casted: *const @TypeOf(.{}) = @alignCast(@ptrCast(ptr)); | |
| 1133 | const loaded = casted.*; | |
| 1134 | // `val` should be a `@TypeOf(.{})`, as expected. | |
| 1135 | // We can't check the value, but it's zero-bit, so the type matching is good enough. | |
| 1136 | comptime assert(@TypeOf(loaded) == @TypeOf(.{})); | |
| 1137 | } |