Debugging rustc type layouts
This post is a “public service announcement” for people working on the guts of rustc. I wish I had known about this a year ago, so I hope this post can make this feature more widely known.
When working with MIR in rustc, one key data structure that comes up a lot is Layout
(formerly LayoutDetails
), usually paired up with a type in a TyAndLayout
(formerly TyLayout
).
This data structure describes everything that there is to know about how a type “looks like” in memory: size and alignment of the entire type, at which offset we can find which field, how enum variants are represented, which “niche” can be used in this type to optimize enums.
Layout
is quite versatile and can be hard to interpret, and when debugging Miri I regularly have to know what exactly the Layout
of a certain type looks like or what exactly some aspect of Layout
actually means in practice.
While debugging MIR is easy via rustc --emit mir
or the “MIR” button on the playground, debugging Layout
was much more tedious.
But not any more. :)
All you have to do is enter the following code in the playground:
#![feature(rustc_attrs)]
#[rustc_layout(debug)]
type T = (u8, u16);
The (permanently) unstable rustc_layout
attribute can now be used to dump some information about the type it is attached to (also works with struct
/enum
/union
definitions).
In this case, it prints:
error: layout_of((u8, u16)) = Layout {
fields: Arbitrary {
offsets: [
Size {
raw: 0,
},
Size {
raw: 2,
},
],
memory_index: [
0,
1,
],
},
variants: Single {
index: 0,
},
abi: ScalarPair(
Scalar {
value: Int(
I8,
false,
),
valid_range: 0..=255,
},
Scalar {
value: Int(
I16,
false,
),
valid_range: 0..=65535,
},
),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align {
pow2: 1,
},
pref: Align {
pow2: 3,
},
},
size: Size {
raw: 4,
},
}
That is quite a lot, but it contains all the key information about this type:
the fields are at offsets 0 and 2, the type has alignment 2 (but preferred alignment 8) and size 4.
We can also see that it uses the ScalarPair
abi which is relevant for Miri and when passing data as arguments to another function.
To learn more about what all this information means, see the Layout
type docs.
Update: After a suggestions by @jschievink, this can now also be used to print the underlying type and layout of named opaque types, which is particularly useful for generators. /Update
So the next time you work with Layout
and wonder how exactly the niche gets represented, or whether an enum
can have ScalarPair
abi (hint: yes it can), you can easily look at a few examples to see how rustc thinks about this type internally.
This is basically the type-level equivalent of --emit mir
.
I have wanted this since forever, so much that some time ago I wrote an awful hack for this based on rustc debug tracing.
Only very recently did I learn about the rustc_layout
attribute and then I had to immediately extend it to support dumping all the information.
Now Layout
can be debugged in the browser on the playground, which is so much more convenient. :D
Posted on Ralf's Ramblings on Apr 4, 2020.
Comments? Drop me a mail or leave a note in the forum!