]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_passes/src/layout_test.rs
Rollup merge of #102127 - TaKO8Ki:use-appropriate-variable-names, r=lcnr
[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::symbol::sym;
7 use rustc_span::Span;
8 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
9
10 pub fn test_layout(tcx: TyCtxt<'_>) {
11     if tcx.features().rustc_attrs {
12         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
13         for id in tcx.hir().items() {
14             if matches!(
15                 tcx.def_kind(id.def_id),
16                 DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
17             ) {
18                 for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
19                     dump_layout_of(tcx, id.def_id, attr);
20                 }
21             }
22         }
23     }
24 }
25
26 fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
27     let tcx = tcx;
28     let param_env = tcx.param_env(item_def_id);
29     let ty = tcx.type_of(item_def_id);
30     match tcx.layout_of(param_env.and(ty)) {
31         Ok(ty_layout) => {
32             // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
33             // The `..` are the names of fields to dump.
34             let meta_items = attr.meta_item_list().unwrap_or_default();
35             for meta_item in meta_items {
36                 match meta_item.name_or_empty() {
37                     sym::abi => {
38                         tcx.sess.span_err(
39                             tcx.def_span(item_def_id.to_def_id()),
40                             &format!("abi: {:?}", ty_layout.abi),
41                         );
42                     }
43
44                     sym::align => {
45                         tcx.sess.span_err(
46                             tcx.def_span(item_def_id.to_def_id()),
47                             &format!("align: {:?}", ty_layout.align),
48                         );
49                     }
50
51                     sym::size => {
52                         tcx.sess.span_err(
53                             tcx.def_span(item_def_id.to_def_id()),
54                             &format!("size: {:?}", ty_layout.size),
55                         );
56                     }
57
58                     sym::homogeneous_aggregate => {
59                         tcx.sess.span_err(
60                             tcx.def_span(item_def_id.to_def_id()),
61                             &format!(
62                                 "homogeneous_aggregate: {:?}",
63                                 ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
64                             ),
65                         );
66                     }
67
68                     sym::debug => {
69                         let normalized_ty = tcx.normalize_erasing_regions(
70                             param_env.with_reveal_all_normalized(tcx),
71                             ty,
72                         );
73                         tcx.sess.span_err(
74                             tcx.def_span(item_def_id.to_def_id()),
75                             &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
76                         );
77                     }
78
79                     name => {
80                         tcx.sess.span_err(
81                             meta_item.span(),
82                             &format!("unrecognized field name `{}`", name),
83                         );
84                     }
85                 }
86             }
87         }
88
89         Err(layout_error) => {
90             tcx.sess.span_err(
91                 tcx.def_span(item_def_id.to_def_id()),
92                 &format!("layout error: {:?}", layout_error),
93             );
94         }
95     }
96 }
97
98 struct UnwrapLayoutCx<'tcx> {
99     tcx: TyCtxt<'tcx>,
100     param_env: ParamEnv<'tcx>,
101 }
102
103 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
104     type LayoutOfResult = TyAndLayout<'tcx>;
105
106     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
107         span_bug!(
108             span,
109             "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
110             ty,
111             err
112         );
113     }
114 }
115
116 impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
117     fn tcx(&self) -> TyCtxt<'tcx> {
118         self.tcx
119     }
120 }
121
122 impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
123     fn param_env(&self) -> ParamEnv<'tcx> {
124         self.param_env
125     }
126 }
127
128 impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> {
129     fn data_layout(&self) -> &TargetDataLayout {
130         self.tcx.data_layout()
131     }
132 }