diff options
Diffstat (limited to 'compiler/rustc_transmute/src/maybe_transmutable/query_context.rs')
-rw-r--r-- | compiler/rustc_transmute/src/maybe_transmutable/query_context.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs new file mode 100644 index 000000000..9c2cf4c9a --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -0,0 +1,93 @@ +use crate::layout; + +/// Context necessary to answer the question "Are these types transmutable?". +pub(crate) trait QueryContext { + type Def: layout::Def; + type Ref: layout::Ref; + type Scope: Copy; + + /// Is `def` accessible from the defining module of `scope`? + fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool; + + fn min_align(&self, reference: Self::Ref) -> usize; +} + +#[cfg(test)] +pub(crate) mod test { + use super::QueryContext; + + pub(crate) struct UltraMinimal; + + #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] + pub(crate) enum Def { + Visible, + Invisible, + } + + impl crate::layout::Def for Def {} + + impl QueryContext for UltraMinimal { + type Def = Def; + type Ref = !; + type Scope = (); + + fn is_accessible_from(&self, def: Def, scope: ()) -> bool { + matches!(Def::Visible, def) + } + + fn min_align(&self, reference: !) -> usize { + unimplemented!() + } + } +} + +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use rustc_middle::ty::{Ty, TyCtxt}; + + impl<'tcx> super::QueryContext for TyCtxt<'tcx> { + type Def = layout::rustc::Def<'tcx>; + type Ref = layout::rustc::Ref<'tcx>; + + type Scope = Ty<'tcx>; + + #[instrument(level = "debug", skip(self))] + fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { + use layout::rustc::Def; + use rustc_middle::ty; + + let parent = if let ty::Adt(adt_def, ..) = scope.kind() { + use rustc_middle::ty::DefIdTree; + let parent = self.parent(adt_def.did()); + parent + } else { + // Is this always how we want to handle a non-ADT scope? + return false; + }; + + let def_id = match def { + Def::Adt(adt_def) => adt_def.did(), + Def::Variant(variant_def) => variant_def.def_id, + Def::Field(field_def) => field_def.did, + Def::Primitive => { + // primitives do not have a def_id, but they're always accessible + return true; + } + }; + + let ret = if self.visibility(def_id).is_accessible_from(parent, *self) { + true + } else { + false + }; + + tracing::trace!(?ret, "ret"); + ret + } + + fn min_align(&self, reference: Self::Ref) -> usize { + unimplemented!() + } + } +} |