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 | |
| 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')
| -rw-r--r-- | compiler/rustc_hir/src/lang_items.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/confirmation.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_transmute/Cargo.toml | 2 | ||||
| -rw-r--r-- | compiler/rustc_transmute/src/lib.rs | 59 | ||||
| -rw-r--r-- | compiler/rustc_transmute/src/maybe_transmutable/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_transmute/src/maybe_transmutable/tests.rs | 4 |
7 files changed, 74 insertions, 21 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c337be12ae4..ccbc225b9ec 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -192,7 +192,8 @@ language_item_table! { DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); // language items relating to transmutability - TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6); + TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0); + TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3); Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 156f53ac486..130cc9a854a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -334,6 +334,7 @@ symbols! { alias, align, align_offset, + alignment, alignstack, all, alloc, @@ -859,6 +860,7 @@ symbols! { lib, libc, lifetime, + lifetimes, likely, line, line_macro, @@ -1284,6 +1286,7 @@ symbols! { rustfmt, rvalue_static_promotion, s, + safety, sanitize, sanitizer_runtime, saturating_add, @@ -1466,6 +1469,7 @@ symbols! { trait_alias, trait_upcasting, transmute, + transmute_opts, transmute_trait, transparent, transparent_enums, @@ -1560,6 +1564,7 @@ symbols! { va_list, va_start, val, + validity, values, var, variant_count, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2a1099fc82a..e44f6665795 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -279,29 +279,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = obligation.predicate; let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); - let bool_at = |i| { - predicate - .skip_binder() - .trait_ref - .substs - .const_at(i) - .try_eval_bool(self.tcx(), obligation.param_env) - .unwrap_or(true) - }; + let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i); let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { - src: p.trait_ref.substs.type_at(1), dst: p.trait_ref.substs.type_at(0), + src: p.trait_ref.substs.type_at(1), }); let scope = type_at(2).skip_binder(); - let assume = rustc_transmute::Assume { - alignment: bool_at(3), - lifetimes: bool_at(4), - validity: bool_at(5), - visibility: bool_at(6), - }; + let assume = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)); let cause = obligation.cause.clone(); diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 9dc96e08a8e..fa3f45fa235 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] tracing = "0.1" rustc_data_structures = { path = "../rustc_data_structures", optional = true} +rustc_hir = { path = "../rustc_hir", optional = true} rustc_infer = { path = "../rustc_infer", optional = true} rustc_macros = { path = "../rustc_macros", optional = true} rustc_middle = { path = "../rustc_middle", optional = true} @@ -18,6 +19,7 @@ rustc_target = { path = "../rustc_target", optional = true} rustc = [ "rustc_middle", "rustc_data_structures", + "rustc_hir", "rustc_infer", "rustc_macros", "rustc_span", 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")] diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 076d922d1b7..b6b6de38f66 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -105,7 +105,7 @@ where #[inline(always)] #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> { - let assume_visibility = self.assume.visibility; + let assume_visibility = self.assume.safety; let query_or_answer = self.map_layouts(|src, dst, scope, context| { // Remove all `Def` nodes from `src`, without checking their visibility. let src = src.prune(&|def| true); diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index d9d125687f6..4d5772a4f2e 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -13,7 +13,7 @@ mod bool { layout::Tree::<Def, !>::bool(), layout::Tree::<Def, !>::bool(), (), - crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, UltraMinimal, ) .answer(); @@ -26,7 +26,7 @@ mod bool { layout::Dfa::<!>::bool(), layout::Dfa::<!>::bool(), (), - crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false }, UltraMinimal, ) .answer(); |
