diff options
| author | Jack Wrenn <jack@wrenn.fyi> | 2025-06-04 15:58:01 +0000 |
|---|---|---|
| committer | Jack Wrenn <jack@wrenn.fyi> | 2025-06-09 14:08:12 +0000 |
| commit | e9eae28eee0a99c64e81f4fdf87d3c76241e56bd (patch) | |
| tree | 51caaa23c92cceeff5c65e86248adf94f63a4762 /compiler/rustc_trait_selection/src/traits/select/confirmation.rs | |
| parent | 7c10378e1fee5ddc6573b916aeb884ab10e0de17 (diff) | |
| download | rust-e9eae28eee0a99c64e81f4fdf87d3c76241e56bd.tar.gz rust-e9eae28eee0a99c64e81f4fdf87d3c76241e56bd.zip | |
transmutability: shift abstraction boundary
Previously, `rustc_transmute`'s layout representations were genericized over `R`, a reference. Now, it's instead genericized over representations of type and region. This allows us to move reference transmutability logic from `rustc_trait_selection` to `rustc_transmutability` (and thus unit test it independently of the compiler), and — in a follow-up PR — will make it possible to support analyzing function pointer transmutability with minimal surgery.
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/select/confirmation.rs')
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/confirmation.rs | 143 |
1 files changed, 46 insertions, 97 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7acf0f990d1..786afd7cf48 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -9,13 +9,12 @@ use std::ops::ControlFlow; -use rustc_ast::Mutability; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast, elaborate}; +use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, Upcast, elaborate}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use thin_vec::thin_vec; @@ -286,99 +285,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { use rustc_transmute::{Answer, Assume, Condition}; - /// Generate sub-obligations for reference-to-reference transmutations. - fn reference_obligations<'tcx>( - tcx: TyCtxt<'tcx>, - obligation: &PolyTraitObligation<'tcx>, - (src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability), - (dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability), - assume: Assume, - ) -> PredicateObligations<'tcx> { - let make_transmute_obl = |src, dst| { - let transmute_trait = obligation.predicate.def_id(); - let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2); - let trait_ref = ty::TraitRef::new( - tcx, - transmute_trait, - [ - ty::GenericArg::from(dst), - ty::GenericArg::from(src), - ty::GenericArg::from(assume), - ], - ); - Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - trait_ref, - ) - }; - - let make_freeze_obl = |ty| { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), - [ty::GenericArg::from(ty)], - ); - Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - trait_ref, - ) - }; - - let make_outlives_obl = |target, region| { - let outlives = ty::OutlivesPredicate(target, region); - Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - outlives, - ) - }; - - // Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`, - // it is always the case that `Src` must be transmutable into `Dst`, - // and that that `'src` must outlive `'dst`. - let mut obls = PredicateObligations::with_capacity(1); - obls.push(make_transmute_obl(src_ty, dst_ty)); - if !assume.lifetimes { - obls.push(make_outlives_obl(src_lifetime, dst_lifetime)); - } - - // Given a transmutation from `&Src`, both `Src` and `Dst` must be - // `Freeze`, otherwise, using the transmuted value could lead to - // data races. - if src_mut == Mutability::Not { - obls.extend([make_freeze_obl(src_ty), make_freeze_obl(dst_ty)]) - } - - // Given a transmutation into `&'dst mut Dst`, it also must be the - // case that `Dst` is transmutable into `Src`. For example, - // transmuting bool -> u8 is OK as long as you can't update that u8 - // to be > 1, because you could later transmute the u8 back to a - // bool and get undefined behavior. It also must be the case that - // `'dst` lives exactly as long as `'src`. - if dst_mut == Mutability::Mut { - obls.push(make_transmute_obl(dst_ty, src_ty)); - if !assume.lifetimes { - obls.push(make_outlives_obl(dst_lifetime, src_lifetime)); - } - } - - obls - } - /// Flatten the `Condition` tree into a conjunction of obligations. #[instrument(level = "debug", skip(tcx, obligation))] fn flatten_answer_tree<'tcx>( tcx: TyCtxt<'tcx>, obligation: &PolyTraitObligation<'tcx>, - cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>, + cond: Condition<Region<'tcx>, Ty<'tcx>>, assume: Assume, ) -> PredicateObligations<'tcx> { match cond { @@ -388,13 +300,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .into_iter() .flat_map(|cond| flatten_answer_tree(tcx, obligation, cond, assume)) .collect(), - Condition::IfTransmutable { src, dst } => reference_obligations( - tcx, - obligation, - (src.lifetime, src.ty, src.mutability), - (dst.lifetime, dst.ty, dst.mutability), - assume, - ), + Condition::Immutable { ty } => { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), + [ty::GenericArg::from(ty)], + ); + thin_vec![Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref, + )] + } + Condition::Outlives { long, short } => { + let outlives = ty::OutlivesPredicate(long, short); + thin_vec![Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + outlives, + )] + } + Condition::Transmutable { src, dst } => { + let transmute_trait = obligation.predicate.def_id(); + let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2); + let trait_ref = ty::TraitRef::new( + tcx, + transmute_trait, + [ + ty::GenericArg::from(dst), + ty::GenericArg::from(src), + ty::GenericArg::from(assume), + ], + ); + thin_vec![Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref, + )] + } } } |
