Erase regions when confirming transmutability candidate
This commit is contained in:
parent
8a778ca1e3
commit
f6bfb4bf8e
8 changed files with 88 additions and 44 deletions
|
@ -649,7 +649,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
||||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
ty::Binder::dummy(src_and_dst),
|
src_and_dst,
|
||||||
scope,
|
scope,
|
||||||
assume,
|
assume,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -742,7 +742,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
{
|
{
|
||||||
// Recompute the safe transmute reason and use that for the error reporting
|
// Recompute the safe transmute reason and use that for the error reporting
|
||||||
self.get_safe_transmute_error_and_reason(
|
self.get_safe_transmute_error_and_reason(
|
||||||
trait_predicate,
|
|
||||||
obligation.clone(),
|
obligation.clone(),
|
||||||
trait_ref,
|
trait_ref,
|
||||||
span,
|
span,
|
||||||
|
@ -1629,7 +1628,6 @@ trait InferCtxtPrivExt<'tcx> {
|
||||||
|
|
||||||
fn get_safe_transmute_error_and_reason(
|
fn get_safe_transmute_error_and_reason(
|
||||||
&self,
|
&self,
|
||||||
trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
|
||||||
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
|
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
|
||||||
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -2921,18 +2919,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
fn get_safe_transmute_error_and_reason(
|
fn get_safe_transmute_error_and_reason(
|
||||||
&self,
|
&self,
|
||||||
trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
|
||||||
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
|
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
|
||||||
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> (String, Option<String>) {
|
) -> (String, Option<String>) {
|
||||||
let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
|
// Erase regions because layout code doesn't particularly care about regions.
|
||||||
dst: p.trait_ref.substs.type_at(0),
|
let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
|
||||||
src: p.trait_ref.substs.type_at(1),
|
|
||||||
});
|
let src_and_dst = rustc_transmute::Types {
|
||||||
let scope = trait_ref.skip_binder().substs.type_at(2);
|
dst: trait_ref.substs.type_at(0),
|
||||||
|
src: trait_ref.substs.type_at(1),
|
||||||
|
};
|
||||||
|
let scope = trait_ref.substs.type_at(2);
|
||||||
let Some(assume) =
|
let Some(assume) =
|
||||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else {
|
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
|
||||||
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
|
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
|
||||||
};
|
};
|
||||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||||
|
@ -2942,8 +2942,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
assume,
|
assume,
|
||||||
) {
|
) {
|
||||||
rustc_transmute::Answer::No(reason) => {
|
rustc_transmute::Answer::No(reason) => {
|
||||||
let dst = trait_ref.skip_binder().substs.type_at(0);
|
let dst = trait_ref.substs.type_at(0);
|
||||||
let src = trait_ref.skip_binder().substs.type_at(1);
|
let src = trait_ref.substs.type_at(1);
|
||||||
let custom_err_msg = format!(
|
let custom_err_msg = format!(
|
||||||
"`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
|
"`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
|
||||||
);
|
);
|
||||||
|
|
|
@ -275,33 +275,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||||
debug!(?obligation, "confirm_transmutability_candidate");
|
debug!(?obligation, "confirm_transmutability_candidate");
|
||||||
|
|
||||||
let predicate = obligation.predicate;
|
// We erase regions here because transmutability calls layout queries,
|
||||||
|
// which does not handle inference regions and doesn't particularly
|
||||||
|
// care about other regions. Erasing late-bound regions is equivalent
|
||||||
|
// to instantiating the binder with placeholders then erasing those
|
||||||
|
// placeholder regions.
|
||||||
|
let predicate =
|
||||||
|
self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate));
|
||||||
|
|
||||||
let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
|
let Some(assume) = rustc_transmute::Assume::from_const(
|
||||||
let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);
|
self.infcx.tcx,
|
||||||
|
obligation.param_env,
|
||||||
let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
|
predicate.trait_ref.substs.const_at(3)
|
||||||
dst: p.trait_ref.substs.type_at(0),
|
) else {
|
||||||
src: p.trait_ref.substs.type_at(1),
|
return Err(Unimplemented);
|
||||||
});
|
};
|
||||||
|
|
||||||
let scope = type_at(2).skip_binder();
|
|
||||||
|
|
||||||
let Some(assume) =
|
|
||||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)) else {
|
|
||||||
return Err(Unimplemented);
|
|
||||||
};
|
|
||||||
|
|
||||||
let cause = obligation.cause.clone();
|
|
||||||
|
|
||||||
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
|
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
|
||||||
|
let maybe_transmutable = transmute_env.is_transmutable(
|
||||||
let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
|
obligation.cause.clone(),
|
||||||
|
rustc_transmute::Types {
|
||||||
use rustc_transmute::Answer;
|
dst: predicate.trait_ref.substs.type_at(0),
|
||||||
|
src: predicate.trait_ref.substs.type_at(1),
|
||||||
|
},
|
||||||
|
predicate.trait_ref.substs.type_at(2),
|
||||||
|
assume,
|
||||||
|
);
|
||||||
|
|
||||||
match maybe_transmutable {
|
match maybe_transmutable {
|
||||||
Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
|
rustc_transmute::Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
|
||||||
_ => Err(Unimplemented),
|
_ => Err(Unimplemented),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ mod rustc {
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||||
use rustc_middle::traits::ObligationCause;
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::ty::Binder;
|
|
||||||
use rustc_middle::ty::Const;
|
use rustc_middle::ty::Const;
|
||||||
use rustc_middle::ty::ParamEnv;
|
use rustc_middle::ty::ParamEnv;
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
|
@ -92,15 +91,13 @@ mod rustc {
|
||||||
pub fn is_transmutable(
|
pub fn is_transmutable(
|
||||||
&mut self,
|
&mut self,
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
src_and_dst: Binder<'tcx, Types<'tcx>>,
|
types: Types<'tcx>,
|
||||||
scope: Ty<'tcx>,
|
scope: Ty<'tcx>,
|
||||||
assume: crate::Assume,
|
assume: crate::Assume,
|
||||||
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
|
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
|
||||||
let src = src_and_dst.map_bound(|types| types.src).skip_binder();
|
|
||||||
let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
|
|
||||||
crate::maybe_transmutable::MaybeTransmutableQuery::new(
|
crate::maybe_transmutable::MaybeTransmutableQuery::new(
|
||||||
src,
|
types.src,
|
||||||
dst,
|
types.dst,
|
||||||
scope,
|
scope,
|
||||||
assume,
|
assume,
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`
|
error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context`
|
||||||
--> $DIR/references.rs:29:52
|
--> $DIR/references.rs:29:52
|
||||||
|
|
|
|
||||||
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
|
||||||
| ^^^^^^^^^^^^^ `&'static Unit` does not have a well-specified layout
|
| ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout
|
||||||
|
|
|
|
||||||
note: required by a bound in `is_maybe_transmutable`
|
note: required by a bound in `is_maybe_transmutable`
|
||||||
--> $DIR/references.rs:16:14
|
--> $DIR/references.rs:16:14
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`
|
error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context`
|
||||||
--> $DIR/references.rs:29:52
|
--> $DIR/references.rs:29:52
|
||||||
|
|
|
|
||||||
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
|
||||||
| ^^^^^^^^^^^^^ `&'static Unit` does not have a well-specified layout
|
| ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout
|
||||||
|
|
|
|
||||||
note: required by a bound in `is_maybe_transmutable`
|
note: required by a bound in `is_maybe_transmutable`
|
||||||
--> $DIR/references.rs:16:14
|
--> $DIR/references.rs:16:14
|
||||||
|
|
22
tests/ui/transmutability/region-infer.rs
Normal file
22
tests/ui/transmutability/region-infer.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#![feature(transmutability)]
|
||||||
|
|
||||||
|
use std::mem::{Assume, BikeshedIntrinsicFrom};
|
||||||
|
pub struct Context;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct W<'a>(&'a ());
|
||||||
|
|
||||||
|
fn test<'a>()
|
||||||
|
where
|
||||||
|
W<'a>: BikeshedIntrinsicFrom<
|
||||||
|
(),
|
||||||
|
Context,
|
||||||
|
{ Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
|
||||||
|
>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
test();
|
||||||
|
//~^ ERROR `()` cannot be safely transmuted into `W<'_>`
|
||||||
|
}
|
23
tests/ui/transmutability/region-infer.stderr
Normal file
23
tests/ui/transmutability/region-infer.stderr
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0277]: `()` cannot be safely transmuted into `W<'_>` in the defining scope of `Context`
|
||||||
|
--> $DIR/region-infer.rs:20:5
|
||||||
|
|
|
||||||
|
LL | test();
|
||||||
|
| ^^^^ `W<'_>` does not have a well-specified layout
|
||||||
|
|
|
||||||
|
note: required by a bound in `test`
|
||||||
|
--> $DIR/region-infer.rs:11:12
|
||||||
|
|
|
||||||
|
LL | fn test<'a>()
|
||||||
|
| ---- required by a bound in this function
|
||||||
|
LL | where
|
||||||
|
LL | W<'a>: BikeshedIntrinsicFrom<
|
||||||
|
| ____________^
|
||||||
|
LL | | (),
|
||||||
|
LL | | Context,
|
||||||
|
LL | | { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
|
||||||
|
LL | | >,
|
||||||
|
| |_________^ required by this bound in `test`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue