1 use rustc_ast::Attribute;
2 use rustc_hir::def::DefKind;
3 use rustc_hir::def_id::LocalDefId;
4 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
5 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
6 use rustc_span::source_map::Spanned;
7 use rustc_span::symbol::sym;
9 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
11 use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
13 pub fn test_layout(tcx: TyCtxt<'_>) {
14 if tcx.features().rustc_attrs {
15 // if the `rustc_attrs` feature is not enabled, don't bother testing layout
16 for id in tcx.hir().items() {
18 tcx.def_kind(id.owner_id),
19 DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
21 for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) {
22 dump_layout_of(tcx, id.owner_id.def_id, attr);
29 fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
31 let param_env = tcx.param_env(item_def_id);
32 let ty = tcx.type_of(item_def_id);
33 match tcx.layout_of(param_env.and(ty)) {
35 // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
36 // The `..` are the names of fields to dump.
37 let meta_items = attr.meta_item_list().unwrap_or_default();
38 for meta_item in meta_items {
39 match meta_item.name_or_empty() {
41 tcx.sess.emit_err(Abi {
42 span: tcx.def_span(item_def_id.to_def_id()),
43 abi: format!("{:?}", ty_layout.abi),
48 tcx.sess.emit_err(Align {
49 span: tcx.def_span(item_def_id.to_def_id()),
50 align: format!("{:?}", ty_layout.align),
55 tcx.sess.emit_err(Size {
56 span: tcx.def_span(item_def_id.to_def_id()),
57 size: format!("{:?}", ty_layout.size),
61 sym::homogeneous_aggregate => {
62 tcx.sess.emit_err(HomogeneousAggregate {
63 span: tcx.def_span(item_def_id.to_def_id()),
64 homogeneous_aggregate: format!(
66 ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
72 let normalized_ty = format!(
74 tcx.normalize_erasing_regions(
75 param_env.with_reveal_all_normalized(tcx),
79 let ty_layout = format!("{:#?}", *ty_layout);
80 tcx.sess.emit_err(LayoutOf {
81 span: tcx.def_span(item_def_id.to_def_id()),
88 tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
94 Err(layout_error) => {
95 tcx.sess.emit_fatal(Spanned {
97 span: tcx.def_span(item_def_id.to_def_id()),
103 struct UnwrapLayoutCx<'tcx> {
105 param_env: ParamEnv<'tcx>,
108 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
109 type LayoutOfResult = TyAndLayout<'tcx>;
111 fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
114 "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
121 impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
122 fn tcx(&self) -> TyCtxt<'tcx> {
127 impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
128 fn param_env(&self) -> ParamEnv<'tcx> {
133 impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> {
134 fn data_layout(&self) -> &TargetDataLayout {
135 self.tcx.data_layout()