diff options
| author | Jack Wrenn <jack@wrenn.fyi> | 2022-08-18 19:39:14 +0000 |
|---|---|---|
| committer | Jack Wrenn <jack@wrenn.fyi> | 2022-08-22 18:37:54 +0000 |
| commit | f46fffc276c19b2c81c9b5e84f4f8678fc4d6d0a (patch) | |
| tree | 5a5d0e994f5cf930365f2d03343e64d54e12f308 /compiler/rustc_transmute/src/lib.rs | |
| parent | e0dc8d78019ca924203fe153ff0af7f64f68cb5d (diff) | |
| download | rust-f46fffc276c19b2c81c9b5e84f4f8678fc4d6d0a.tar.gz rust-f46fffc276c19b2c81c9b5e84f4f8678fc4d6d0a.zip | |
safe transmute: use `Assume` struct to provide analysis options
This was left as a TODO in #92268, and brings the trait more in line with what was defined in MCP411. `Assume::visibility` has been renamed to `Assume::safety`, as library safety is what's actually being assumed; visibility is just the mechanism by which it is currently checked (this may change). ref: https://github.com/rust-lang/compiler-team/issues/411 ref: https://github.com/rust-lang/rust/issues/99571
Diffstat (limited to 'compiler/rustc_transmute/src/lib.rs')
| -rw-r--r-- | compiler/rustc_transmute/src/lib.rs | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 32e6cb9c64f..d7c2119a1c4 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -26,8 +26,8 @@ pub(crate) mod maybe_transmutable; pub struct Assume { pub alignment: bool, pub lifetimes: bool, + pub safety: bool, pub validity: bool, - pub visibility: bool, } /// The type encodes answers to the question: "Are these types transmutable?" @@ -69,11 +69,17 @@ pub enum Reason { #[cfg(feature = "rustc")] mod rustc { + use super::*; + + use rustc_hir::lang_items::LangItem; use rustc_infer::infer::InferCtxt; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::Binder; + use rustc_middle::ty::Const; + use rustc_middle::ty::ParamEnv; use rustc_middle::ty::Ty; + use rustc_middle::ty::TyCtxt; /// The source and destination types of a transmutation. #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)] @@ -113,6 +119,57 @@ mod rustc { .answer() } } + + impl Assume { + /// Constructs an `Assume` from a given const-`Assume`. + pub fn from_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + c: Const<'tcx>, + ) -> Self { + use rustc_middle::ty::DestructuredConst; + use rustc_middle::ty::TypeVisitable; + use rustc_span::symbol::sym; + + let c = c.eval(tcx, param_env); + + if let Some(err) = c.error_reported() { + return Self { alignment: true, lifetimes: true, safety: true, validity: true }; + } + + let adt_def = c.ty().ty_adt_def().expect("The given `Const` must be an ADT."); + + assert_eq!( + tcx.require_lang_item(LangItem::TransmuteOpts, None), + adt_def.did(), + "The given `Const` was not marked with the `{}` lang item.", + LangItem::TransmuteOpts.name(), + ); + + let DestructuredConst { variant, fields } = tcx.destructure_const(c); + let variant_idx = variant.expect("The given `Const` must be an ADT."); + let variant = adt_def.variant(variant_idx); + + let get_field = |name| { + let (field_idx, _) = variant + .fields + .iter() + .enumerate() + .find(|(_, field_def)| name == field_def.name) + .expect(&format!("There were no fields named `{name}`.")); + fields[field_idx].try_eval_bool(tcx, param_env).expect(&format!( + "The field named `{name}` lang item could not be evaluated to a bool." + )) + }; + + Self { + alignment: get_field(sym::alignment), + lifetimes: get_field(sym::lifetimes), + safety: get_field(sym::safety), + validity: get_field(sym::validity), + } + } + } } #[cfg(feature = "rustc")] |
