Skip to content

Commit a823904

Browse files
authored
Rollup merge of rust-lang#67215 - nnethercote:fix-Zprint-type-size-zero-sized-fields, r=pnkfelix
Fix `-Z print-type-sizes`'s handling of zero-sized fields. Currently, the type `struct S { x: u32, y: u32, tag: () }` is incorrectly described like this: ``` print-type-size type: `S`: 8 bytes, alignment: 4 bytes print-type-size field `.x`: 4 bytes print-type-size field `.tag`: 0 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size padding: 4 bytes print-type-size field `.y`: 4 bytes, alignment: 4 bytes ``` Specifically: - The `padding` line is wrong. (There is no padding.) - The `offset` and `alignment` on the `.tag` line shouldn't be printed. The problem is that multiple fields can end up with the same offset, and the printing code doesn't handle this correctly. This commit fixes it by adjusting the field sorting so that zero-sized fields are dealt with before non-zero-sized fields. With that in place, the printing code works correctly. The commit also corrects the "something is very wrong" comment. The new output looks like this: ``` print-type-size type: `S`: 8 bytes, alignment: 4 bytes print-type-size field `.tag`: 0 bytes print-type-size field `.x`: 4 bytes print-type-size field `.y`: 4 bytes ``` r? @pnkfelix
2 parents f642dc4 + c681841 commit a823904

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

src/librustc_session/code_stats.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,12 @@ impl CodeStats {
132132

133133
let mut min_offset = discr_size;
134134

135-
// We want to print fields by increasing offset.
135+
// We want to print fields by increasing offset. We also want
136+
// zero-sized fields before non-zero-sized fields, otherwise
137+
// the loop below goes wrong; hence the `f.size` in the sort
138+
// key.
136139
let mut fields = fields.clone();
137-
fields.sort_by_key(|f| f.offset);
140+
fields.sort_by_key(|f| (f.offset, f.size));
138141

139142
for field in fields.iter() {
140143
let FieldInfo { ref name, offset, size, align } = *field;
@@ -146,7 +149,7 @@ impl CodeStats {
146149
}
147150

148151
if offset < min_offset {
149-
// if this happens something is very wrong
152+
// If this happens it's probably a union.
150153
println!("print-type-size {}field `.{}`: {} bytes, \
151154
offset: {} bytes, \
152155
alignment: {} bytes",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// compile-flags: -Z print-type-sizes
2+
// build-pass (FIXME(62277): could be check-pass?)
3+
4+
// At one point, zero-sized fields such as those in this file were causing
5+
// incorrect output from `-Z print-type-sizes`.
6+
7+
#![feature(start)]
8+
9+
struct S1 {
10+
x: u32,
11+
y: u32,
12+
tag: (),
13+
}
14+
15+
struct Void();
16+
struct Empty {}
17+
18+
struct S5<TagW, TagZ> {
19+
tagw: TagW,
20+
w: u32,
21+
unit: (),
22+
x: u32,
23+
void: Void,
24+
y: u32,
25+
empty: Empty,
26+
z: u32,
27+
tagz: TagZ,
28+
}
29+
30+
#[start]
31+
fn start(_: isize, _: *const *const u8) -> isize {
32+
let _s1: S1 = S1 { x: 0, y: 0, tag: () };
33+
34+
let _s5: S5<(), Empty> = S5 {
35+
tagw: (),
36+
w: 1,
37+
unit: (),
38+
x: 2,
39+
void: Void(),
40+
y: 3,
41+
empty: Empty {},
42+
z: 4,
43+
tagz: Empty {},
44+
};
45+
0
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
print-type-size type: `S5<(), Empty>`: 16 bytes, alignment: 4 bytes
2+
print-type-size field `.tagw`: 0 bytes
3+
print-type-size field `.unit`: 0 bytes
4+
print-type-size field `.void`: 0 bytes
5+
print-type-size field `.empty`: 0 bytes
6+
print-type-size field `.tagz`: 0 bytes
7+
print-type-size field `.w`: 4 bytes
8+
print-type-size field `.x`: 4 bytes
9+
print-type-size field `.y`: 4 bytes
10+
print-type-size field `.z`: 4 bytes
11+
print-type-size type: `S1`: 8 bytes, alignment: 4 bytes
12+
print-type-size field `.tag`: 0 bytes
13+
print-type-size field `.x`: 4 bytes
14+
print-type-size field `.y`: 4 bytes
15+
print-type-size type: `Empty`: 0 bytes, alignment: 1 bytes
16+
print-type-size type: `Void`: 0 bytes, alignment: 1 bytes

0 commit comments

Comments
 (0)