| author | |
| committer | |
| log | 6c690a966ad21bfa7fabf1b1f9a25bb2d3f826cb |
| tree | f78550fda9996663be07419edb7f1d5dff9d8a49 |
| parent | f9549504851c9445ea474e78cedc5d52a5b21f36 |
| signature |
Resolves: #232102 files changed, 72 insertions(+), 1 deletions(-)
src/Sema.zig+31-1| ... | ... | @@ -20290,11 +20290,41 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is |
| 20290 | 20290 | const zcu = pt.zcu; |
| 20291 | 20291 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 20292 | 20292 | const src = block.nodeOffset(inst_data.src_node); |
| 20293 | ||
| 20293 | 20294 | // Generic poison means this is an untyped anonymous empty struct/array init |
| 20294 | const ty_operand = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse return .empty_tuple; | |
| 20295 | const ty_operand = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse { | |
| 20296 | if (is_byref) { | |
| 20297 | return sema.uavRef(.empty_tuple); | |
| 20298 | } else { | |
| 20299 | return .empty_tuple; | |
| 20300 | } | |
| 20301 | }; | |
| 20302 | ||
| 20295 | 20303 | const init_ty = if (is_byref) ty: { |
| 20296 | 20304 | const ptr_ty = ty_operand.optEuBaseType(zcu); |
| 20297 | 20305 | assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction |
| 20306 | switch (ptr_ty.ptrSize(zcu)) { | |
| 20307 | // Use a zero-length array for a slice or many-ptr result | |
| 20308 | .slice, .many => break :ty try pt.arrayType(.{ | |
| 20309 | .len = 0, | |
| 20310 | .child = ptr_ty.childType(zcu).toIntern(), | |
| 20311 | .sentinel = if (ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, | |
| 20312 | }), | |
| 20313 | // Just use the child type for a single-pointer or C-pointer result | |
| 20314 | .one, .c => { | |
| 20315 | const child = ptr_ty.childType(zcu); | |
| 20316 | if (child.toIntern() == .anyopaque_type) { | |
| 20317 | // ...unless that child is anyopaque, in which case this is equivalent to an untyped init. | |
| 20318 | // `.{}` is an empty tuple. | |
| 20319 | if (is_byref) { | |
| 20320 | return sema.uavRef(.empty_tuple); | |
| 20321 | } else { | |
| 20322 | return .empty_tuple; | |
| 20323 | } | |
| 20324 | } | |
| 20325 | break :ty child; | |
| 20326 | }, | |
| 20327 | } | |
| 20298 | 20328 | if (!ptr_ty.isSlice(zcu)) { |
| 20299 | 20329 | break :ty ptr_ty.childType(zcu); |
| 20300 | 20330 | } |
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 | } |