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;
8 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
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() {
15 tcx.def_kind(id.def_id),
16 DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
18 for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
19 dump_layout_of(tcx, id.def_id.def_id, attr);
26 fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
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)) {
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() {
39 tcx.def_span(item_def_id.to_def_id()),
40 &format!("abi: {:?}", ty_layout.abi),
46 tcx.def_span(item_def_id.to_def_id()),
47 &format!("align: {:?}", ty_layout.align),
53 tcx.def_span(item_def_id.to_def_id()),
54 &format!("size: {:?}", ty_layout.size),
58 sym::homogeneous_aggregate => {
60 tcx.def_span(item_def_id.to_def_id()),
62 "homogeneous_aggregate: {:?}",
63 ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
69 let normalized_ty = tcx.normalize_erasing_regions(
70 param_env.with_reveal_all_normalized(tcx),
74 tcx.def_span(item_def_id.to_def_id()),
75 &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
82 &format!("unrecognized field name `{}`", name),
89 Err(layout_error) => {
91 tcx.def_span(item_def_id.to_def_id()),
92 &format!("layout error: {:?}", layout_error),
98 struct UnwrapLayoutCx<'tcx> {
100 param_env: ParamEnv<'tcx>,
103 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
104 type LayoutOfResult = TyAndLayout<'tcx>;
106 fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
109 "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
116 impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
117 fn tcx(&self) -> TyCtxt<'tcx> {
122 impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
123 fn param_env(&self) -> ParamEnv<'tcx> {
128 impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> {
129 fn data_layout(&self) -> &TargetDataLayout {
130 self.tcx.data_layout()