summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_passes/src/layout_test.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_passes/src/layout_test.rs')
-rw-r--r--compiler/rustc_passes/src/layout_test.rs132
1 files changed, 132 insertions, 0 deletions
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
new file mode 100644
index 000000000..fd03f6571
--- /dev/null
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -0,0 +1,132 @@
+use rustc_ast::Attribute;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+use rustc_target::abi::{HasDataLayout, TargetDataLayout};
+
+pub fn test_layout(tcx: TyCtxt<'_>) {
+ if tcx.features().rustc_attrs {
+ // if the `rustc_attrs` feature is not enabled, don't bother testing layout
+ for id in tcx.hir().items() {
+ if matches!(
+ tcx.def_kind(id.def_id),
+ DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
+ ) {
+ for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
+ dump_layout_of(tcx, id.def_id, attr);
+ }
+ }
+ }
+ }
+}
+
+fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
+ let tcx = tcx;
+ let param_env = tcx.param_env(item_def_id);
+ let ty = tcx.type_of(item_def_id);
+ match tcx.layout_of(param_env.and(ty)) {
+ Ok(ty_layout) => {
+ // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
+ // The `..` are the names of fields to dump.
+ let meta_items = attr.meta_item_list().unwrap_or_default();
+ for meta_item in meta_items {
+ match meta_item.name_or_empty() {
+ sym::abi => {
+ tcx.sess.span_err(
+ tcx.def_span(item_def_id.to_def_id()),
+ &format!("abi: {:?}", ty_layout.abi),
+ );
+ }
+
+ sym::align => {
+ tcx.sess.span_err(
+ tcx.def_span(item_def_id.to_def_id()),
+ &format!("align: {:?}", ty_layout.align),
+ );
+ }
+
+ sym::size => {
+ tcx.sess.span_err(
+ tcx.def_span(item_def_id.to_def_id()),
+ &format!("size: {:?}", ty_layout.size),
+ );
+ }
+
+ sym::homogeneous_aggregate => {
+ tcx.sess.span_err(
+ tcx.def_span(item_def_id.to_def_id()),
+ &format!(
+ "homogeneous_aggregate: {:?}",
+ ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
+ ),
+ );
+ }
+
+ sym::debug => {
+ let normalized_ty = tcx.normalize_erasing_regions(
+ param_env.with_reveal_all_normalized(tcx),
+ ty,
+ );
+ tcx.sess.span_err(
+ tcx.def_span(item_def_id.to_def_id()),
+ &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
+ );
+ }
+
+ name => {
+ tcx.sess.span_err(
+ meta_item.span(),
+ &format!("unrecognized field name `{}`", name),
+ );
+ }
+ }
+ }
+ }
+
+ Err(layout_error) => {
+ tcx.sess.span_err(
+ tcx.def_span(item_def_id.to_def_id()),
+ &format!("layout error: {:?}", layout_error),
+ );
+ }
+ }
+}
+
+struct UnwrapLayoutCx<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
+ type LayoutOfResult = TyAndLayout<'tcx>;
+
+ fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+ span_bug!(
+ span,
+ "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
+ ty,
+ err
+ );
+ }
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
+
+impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
+ fn param_env(&self) -> ParamEnv<'tcx> {
+ self.param_env
+ }
+}
+
+impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ self.tcx.data_layout()
+ }
+}