| author | |
| committer | |
| log | 0e3feebb042a538405153e4bc75a3bb73ee2e63c |
| tree | d597c19b71254dacb25c7744b03eb5c37d9ee516 |
| parent | 52e5c6602550788cab96957d1a177bc7952d7a09 |
Normally when we want a pointer to the end of a struct we just add 1 to
the struct pointer. However, when it is a zero-bit struct, the pointer
type being used during lowering is often a dummy pointer type that
actually points to a non-zero-bit type, so we actually want to add 0
instead, since a zero-bit struct begins and ends at the same address.3 files changed, 30 insertions(+), 9 deletions(-)
src/codegen/c.zig+3-1| ... | ... | @@ -5131,7 +5131,9 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 5131 | 5131 | .begin, .end => { |
| 5132 | 5132 | try writer.writeByte('('); |
| 5133 | 5133 | try f.writeCValue(writer, struct_ptr, .Other); |
| 5134 | try writer.print(")[{}]", .{@boolToInt(field_loc == .end)}); | |
| 5134 | try writer.print(")[{}]", .{ | |
| 5135 | @boolToInt(field_loc == .end and struct_ty.hasRuntimeBitsIgnoreComptime()), | |
| 5136 | }); | |
| 5135 | 5137 | }, |
| 5136 | 5138 | .field => |field| if (extra_name != .none) { |
| 5137 | 5139 | try f.writeCValueDerefMember(writer, struct_ptr, extra_name); |
src/codegen/llvm.zig+4-5| ... | ... | @@ -4046,9 +4046,8 @@ pub const DeclGen = struct { |
| 4046 | 4046 | break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4047 | 4047 | } else { |
| 4048 | 4048 | bitcast_needed = !parent_ty.eql(ptr_child_ty, dg.module); |
| 4049 | const indices: [1]*llvm.Value = .{ | |
| 4050 | llvm_u32.constInt(1, .False), | |
| 4051 | }; | |
| 4049 | const llvm_index = llvm_u32.constInt(@boolToInt(parent_ty.hasRuntimeBitsIgnoreComptime()), .False); | |
| 4050 | const indices: [1]*llvm.Value = .{llvm_index}; | |
| 4052 | 4051 | break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4053 | 4052 | } |
| 4054 | 4053 | }, |
| ... | ... | @@ -9774,8 +9773,8 @@ pub const FuncGen = struct { |
| 9774 | 9773 | // end of the struct. Treat our struct pointer as an array of two and get |
| 9775 | 9774 | // the index to the element at index `1` to get a pointer to the end of |
| 9776 | 9775 | // the struct. |
| 9777 | const llvm_usize = try self.dg.lowerType(Type.usize); | |
| 9778 | const llvm_index = llvm_usize.constInt(1, .False); | |
| 9776 | const llvm_u32 = self.dg.context.intType(32); | |
| 9777 | const llvm_index = llvm_u32.constInt(@boolToInt(struct_ty.hasRuntimeBitsIgnoreComptime()), .False); | |
| 9779 | 9778 | const indices: [1]*llvm.Value = .{llvm_index}; |
| 9780 | 9779 | return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, ""); |
| 9781 | 9780 | } |
test/behavior/struct.zig+23-3| ... | ... | @@ -1365,7 +1365,7 @@ test "fieldParentPtr of a zero-bit field" { |
| 1365 | 1365 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1366 | 1366 | |
| 1367 | 1367 | const S = struct { |
| 1368 | fn testOneType(comptime A: type) !void { | |
| 1368 | fn testStruct(comptime A: type) !void { | |
| 1369 | 1369 | { |
| 1370 | 1370 | const a = A{ .u = 0 }; |
| 1371 | 1371 | const b_ptr = &a.b; |
| ... | ... | @@ -1379,9 +1379,29 @@ test "fieldParentPtr of a zero-bit field" { |
| 1379 | 1379 | try std.testing.expectEqual(&a, a_ptr); |
| 1380 | 1380 | } |
| 1381 | 1381 | } |
| 1382 | fn testNestedStruct(comptime A: type) !void { | |
| 1383 | { | |
| 1384 | const a = A{ .u = 0 }; | |
| 1385 | const c_ptr = &a.b.c; | |
| 1386 | const b_ptr = @fieldParentPtr(@TypeOf(a.b), "c", c_ptr); | |
| 1387 | try std.testing.expectEqual(&a.b, b_ptr); | |
| 1388 | const a_ptr = @fieldParentPtr(A, "b", b_ptr); | |
| 1389 | try std.testing.expectEqual(&a, a_ptr); | |
| 1390 | } | |
| 1391 | { | |
| 1392 | var a = A{ .u = 0 }; | |
| 1393 | const c_ptr = &a.b.c; | |
| 1394 | const b_ptr = @fieldParentPtr(@TypeOf(a.b), "c", c_ptr); | |
| 1395 | try std.testing.expectEqual(&a.b, b_ptr); | |
| 1396 | const a_ptr = @fieldParentPtr(A, "b", b_ptr); | |
| 1397 | try std.testing.expectEqual(&a, a_ptr); | |
| 1398 | } | |
| 1399 | } | |
| 1382 | 1400 | fn doTheTest() !void { |
| 1383 | try testOneType(struct { b: void = {}, u: u8 }); | |
| 1384 | try testOneType(struct { u: u8, b: void = {} }); | |
| 1401 | try testStruct(struct { b: void = {}, u: u8 }); | |
| 1402 | try testStruct(struct { u: u8, b: void = {} }); | |
| 1403 | try testNestedStruct(struct { b: struct { c: void = {} } = .{}, u: u8 }); | |
| 1404 | try testNestedStruct(struct { u: u8, b: struct { c: void = {} } = .{} }); | |
| 1385 | 1405 | } |
| 1386 | 1406 | }; |
| 1387 | 1407 | try S.doTheTest(); |