Rollup merge of #69901 - RalfJung:rustc_layout, r=eddyb
add #[rustc_layout(debug)] @eddyb recently told me about the `#[rustc_layout]` attribute, and I think it would be very useful if it could be used to print all the layout information Rust has about a type. When working with layouts (e.g. in Miri), it is often not clear how certain surface language features get represented internally. I have some awful hacks locally to be able to dump this debug information; with this attribute I could get it on the playground which is so much better. :)
This commit is contained in:
commit
fd3f9176c3
4 changed files with 356 additions and 8 deletions
|
@ -17,24 +17,30 @@ use rustc_span::symbol::sym;
|
||||||
pub fn test_layout(tcx: TyCtxt<'_>) {
|
pub fn test_layout(tcx: TyCtxt<'_>) {
|
||||||
if tcx.features().rustc_attrs {
|
if tcx.features().rustc_attrs {
|
||||||
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
||||||
tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx });
|
tcx.hir().krate().visit_all_item_likes(&mut LayoutTest { tcx });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VarianceTest<'tcx> {
|
struct LayoutTest<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> {
|
impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
|
||||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||||
let item_def_id = self.tcx.hir().local_def_id(item.hir_id);
|
let item_def_id = self.tcx.hir().local_def_id(item.hir_id);
|
||||||
|
|
||||||
if let ItemKind::TyAlias(..) = item.kind {
|
match item.kind {
|
||||||
for attr in self.tcx.get_attrs(item_def_id).iter() {
|
ItemKind::TyAlias(..)
|
||||||
if attr.check_name(sym::rustc_layout) {
|
| ItemKind::Enum(..)
|
||||||
self.dump_layout_of(item_def_id, item, attr);
|
| ItemKind::Struct(..)
|
||||||
|
| ItemKind::Union(..) => {
|
||||||
|
for attr in self.tcx.get_attrs(item_def_id).iter() {
|
||||||
|
if attr.check_name(sym::rustc_layout) {
|
||||||
|
self.dump_layout_of(item_def_id, item, attr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +48,7 @@ impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> {
|
||||||
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
|
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VarianceTest<'tcx> {
|
impl LayoutTest<'tcx> {
|
||||||
fn dump_layout_of(&self, item_def_id: DefId, item: &hir::Item<'tcx>, attr: &Attribute) {
|
fn dump_layout_of(&self, item_def_id: DefId, item: &hir::Item<'tcx>, attr: &Attribute) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let param_env = self.tcx.param_env(item_def_id);
|
let param_env = self.tcx.param_env(item_def_id);
|
||||||
|
@ -81,6 +87,13 @@ impl VarianceTest<'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sym::debug => {
|
||||||
|
self.tcx.sess.span_err(
|
||||||
|
item.span,
|
||||||
|
&format!("layout debugging: {:#?}", *ty_layout),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
name => {
|
name => {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.span_err(
|
||||||
meta_item.span(),
|
meta_item.span(),
|
||||||
|
|
|
@ -253,6 +253,7 @@ symbols! {
|
||||||
debug_trait,
|
debug_trait,
|
||||||
declare_lint_pass,
|
declare_lint_pass,
|
||||||
decl_macro,
|
decl_macro,
|
||||||
|
debug,
|
||||||
Debug,
|
Debug,
|
||||||
Decodable,
|
Decodable,
|
||||||
Default,
|
Default,
|
||||||
|
|
15
src/test/ui/layout/debug.rs
Normal file
15
src/test/ui/layout/debug.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// normalize-stderr-test "pref: Align \{\n *pow2: [1-3],\n *\}" -> "pref: $$PREF_ALIGN"
|
||||||
|
#![feature(never_type, rustc_attrs)]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
#[rustc_layout(debug)]
|
||||||
|
enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout debugging
|
||||||
|
|
||||||
|
#[rustc_layout(debug)]
|
||||||
|
struct S { f1: i32, f2: (), f3: i32 } //~ ERROR: layout debugging
|
||||||
|
|
||||||
|
#[rustc_layout(debug)]
|
||||||
|
union U { f1: (i32, i32), f3: i32 } //~ ERROR: layout debugging
|
||||||
|
|
||||||
|
#[rustc_layout(debug)]
|
||||||
|
type Test = Result<i32, i32>; //~ ERROR: layout debugging
|
319
src/test/ui/layout/debug.stderr
Normal file
319
src/test/ui/layout/debug.stderr
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
error: layout debugging: LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [
|
||||||
|
Size {
|
||||||
|
raw: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memory_index: [
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
variants: Multiple {
|
||||||
|
discr: Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
valid_range: 0..=0,
|
||||||
|
},
|
||||||
|
discr_kind: Tag,
|
||||||
|
discr_index: 0,
|
||||||
|
variants: [
|
||||||
|
LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [],
|
||||||
|
memory_index: [],
|
||||||
|
},
|
||||||
|
variants: Single {
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
abi: Aggregate {
|
||||||
|
sized: true,
|
||||||
|
},
|
||||||
|
largest_niche: None,
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 0,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [
|
||||||
|
Size {
|
||||||
|
raw: 4,
|
||||||
|
},
|
||||||
|
Size {
|
||||||
|
raw: 4,
|
||||||
|
},
|
||||||
|
Size {
|
||||||
|
raw: 8,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memory_index: [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
variants: Single {
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
abi: Uninhabited,
|
||||||
|
largest_niche: None,
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
abi: Aggregate {
|
||||||
|
sized: true,
|
||||||
|
},
|
||||||
|
largest_niche: Some(
|
||||||
|
Niche {
|
||||||
|
offset: Size {
|
||||||
|
raw: 0,
|
||||||
|
},
|
||||||
|
scalar: Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
valid_range: 0..=0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 12,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
--> $DIR/debug.rs:6:1
|
||||||
|
|
|
||||||
|
LL | enum E { Foo, Bar(!, i32, i32) }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: layout debugging: LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [
|
||||||
|
Size {
|
||||||
|
raw: 0,
|
||||||
|
},
|
||||||
|
Size {
|
||||||
|
raw: 0,
|
||||||
|
},
|
||||||
|
Size {
|
||||||
|
raw: 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memory_index: [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
variants: Single {
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
abi: ScalarPair(
|
||||||
|
Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
valid_range: 0..=4294967295,
|
||||||
|
},
|
||||||
|
Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
valid_range: 0..=4294967295,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
largest_niche: None,
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
--> $DIR/debug.rs:9:1
|
||||||
|
|
|
||||||
|
LL | struct S { f1: i32, f2: (), f3: i32 }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: layout debugging: LayoutDetails {
|
||||||
|
fields: Union(
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
variants: Single {
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
abi: Aggregate {
|
||||||
|
sized: true,
|
||||||
|
},
|
||||||
|
largest_niche: None,
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
--> $DIR/debug.rs:12:1
|
||||||
|
|
|
||||||
|
LL | union U { f1: (i32, i32), f3: i32 }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: layout debugging: LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [
|
||||||
|
Size {
|
||||||
|
raw: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memory_index: [
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
variants: Multiple {
|
||||||
|
discr: Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
valid_range: 0..=1,
|
||||||
|
},
|
||||||
|
discr_kind: Tag,
|
||||||
|
discr_index: 0,
|
||||||
|
variants: [
|
||||||
|
LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [
|
||||||
|
Size {
|
||||||
|
raw: 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memory_index: [
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
variants: Single {
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
abi: Aggregate {
|
||||||
|
sized: true,
|
||||||
|
},
|
||||||
|
largest_niche: None,
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LayoutDetails {
|
||||||
|
fields: Arbitrary {
|
||||||
|
offsets: [
|
||||||
|
Size {
|
||||||
|
raw: 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memory_index: [
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
variants: Single {
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
abi: Aggregate {
|
||||||
|
sized: true,
|
||||||
|
},
|
||||||
|
largest_niche: None,
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
abi: ScalarPair(
|
||||||
|
Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
valid_range: 0..=1,
|
||||||
|
},
|
||||||
|
Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
valid_range: 0..=4294967295,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
largest_niche: Some(
|
||||||
|
Niche {
|
||||||
|
offset: Size {
|
||||||
|
raw: 0,
|
||||||
|
},
|
||||||
|
scalar: Scalar {
|
||||||
|
value: Int(
|
||||||
|
I32,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
valid_range: 0..=1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
align: AbiAndPrefAlign {
|
||||||
|
abi: Align {
|
||||||
|
pow2: 2,
|
||||||
|
},
|
||||||
|
pref: $PREF_ALIGN,
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
raw: 8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
--> $DIR/debug.rs:15:1
|
||||||
|
|
|
||||||
|
LL | type Test = Result<i32, i32>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue