]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_passes/src/layout_test.rs
Rollup merge of #107385 - BoxyUwU:ConstInferUnifier_is_folder, r=compiler-errors
[rust.git] / compiler / rustc_passes / src / layout_test.rs
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;
8 use rustc_span::Span;
9 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
10
11 use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
12
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() {
17             if matches!(
18                 tcx.def_kind(id.owner_id),
19                 DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
20             ) {
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);
23                 }
24             }
25         }
26     }
27 }
28
29 fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
30     let tcx = tcx;
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)) {
34         Ok(ty_layout) => {
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() {
40                     sym::abi => {
41                         tcx.sess.emit_err(Abi {
42                             span: tcx.def_span(item_def_id.to_def_id()),
43                             abi: format!("{:?}", ty_layout.abi),
44                         });
45                     }
46
47                     sym::align => {
48                         tcx.sess.emit_err(Align {
49                             span: tcx.def_span(item_def_id.to_def_id()),
50                             align: format!("{:?}", ty_layout.align),
51                         });
52                     }
53
54                     sym::size => {
55                         tcx.sess.emit_err(Size {
56                             span: tcx.def_span(item_def_id.to_def_id()),
57                             size: format!("{:?}", ty_layout.size),
58                         });
59                     }
60
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!(
65                                 "{:?}",
66                                 ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
67                             ),
68                         });
69                     }
70
71                     sym::debug => {
72                         let normalized_ty = format!(
73                             "{:?}",
74                             tcx.normalize_erasing_regions(
75                                 param_env.with_reveal_all_normalized(tcx),
76                                 ty,
77                             )
78                         );
79                         let ty_layout = format!("{:#?}", *ty_layout);
80                         tcx.sess.emit_err(LayoutOf {
81                             span: tcx.def_span(item_def_id.to_def_id()),
82                             normalized_ty,
83                             ty_layout,
84                         });
85                     }
86
87                     name => {
88                         tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
89                     }
90                 }
91             }
92         }
93
94         Err(layout_error) => {
95             tcx.sess.emit_fatal(Spanned {
96                 node: layout_error,
97                 span: tcx.def_span(item_def_id.to_def_id()),
98             });
99         }
100     }
101 }
102
103 struct UnwrapLayoutCx<'tcx> {
104     tcx: TyCtxt<'tcx>,
105     param_env: ParamEnv<'tcx>,
106 }
107
108 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
109     type LayoutOfResult = TyAndLayout<'tcx>;
110
111     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
112         span_bug!(
113             span,
114             "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
115             ty,
116             err
117         );
118     }
119 }
120
121 impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
122     fn tcx(&self) -> TyCtxt<'tcx> {
123         self.tcx
124     }
125 }
126
127 impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
128     fn param_env(&self) -> ParamEnv<'tcx> {
129         self.param_env
130     }
131 }
132
133 impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> {
134     fn data_layout(&self) -> &TargetDataLayout {
135         self.tcx.data_layout()
136     }
137 }