From: Ralf Jung Date: Sat, 4 Apr 2020 17:14:31 +0000 (+0200) Subject: add rustc_layout(debug) post X-Git-Url: https://git.ralfj.de/web.git/commitdiff_plain/14fe6fd0bdbd3f006cc037da23d11bf734756c05?ds=inline;hp=2b2e99e56e940470cf2fcd4d4f2336520805fd6c add rustc_layout(debug) post --- diff --git a/personal/_posts/2020-04-04-layout-debugging.md b/personal/_posts/2020-04-04-layout-debugging.md new file mode 100644 index 0000000..627a45f --- /dev/null +++ b/personal/_posts/2020-04-04-layout-debugging.md @@ -0,0 +1,89 @@ +--- +title: "Debugging rustc type layouts" +categories: rust +--- + +This post is a "public service announcement" for people working on the guts of rustc. +I wish I had know 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`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/abi/struct.Layout.html) (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](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=7abc008aed2669466d4ebe79ee7767fe): + +{% highlight rust %} +#![feature(rustc_attrs)] + +#[rustc_layout(debug)] +type T = (u8, u16); +{% endhighlight %} + +The (permanently) unstable `rustc_layout` attribute [can now be used](https://github.com/rust-lang/rust/pull/69901) 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 debugging: 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](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/abi/struct.Layout.html). + +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