Skip to content

Commit

Permalink
Rollup merge of #110038 - compiler-errors:infer-regions-in-transmutab…
Browse files Browse the repository at this point in the history
…ility, r=lcnr

Erase regions when confirming transmutability candidate

Fixes an ICE where we call `layout_of` on a type with infer regions.
  • Loading branch information
matthiaskrgr authored Apr 17, 2023
2 parents 5546cb6 + f6bfb4b commit f5222cd
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 45 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
ObligationCause::dummy(),
ty::Binder::dummy(src_and_dst),
src_and_dst,
scope,
assume,
) {
Expand Down
22 changes: 11 additions & 11 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
// Recompute the safe transmute reason and use that for the error reporting
self.get_safe_transmute_error_and_reason(
trait_predicate,
obligation.clone(),
trait_ref,
span,
Expand Down Expand Up @@ -1629,7 +1628,6 @@ trait InferCtxtPrivExt<'tcx> {

fn get_safe_transmute_error_and_reason(
&self,
trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
span: Span,
Expand Down Expand Up @@ -2921,18 +2919,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {

fn get_safe_transmute_error_and_reason(
&self,
trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
span: Span,
) -> (String, Option<String>) {
let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
dst: p.trait_ref.substs.type_at(0),
src: p.trait_ref.substs.type_at(1),
});
let scope = trait_ref.skip_binder().substs.type_at(2);
// Erase regions because layout code doesn't particularly care about regions.
let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));

let src_and_dst = rustc_transmute::Types {
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) =
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");
};
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
Expand All @@ -2942,8 +2942,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
assume,
) {
rustc_transmute::Answer::No(reason) => {
let dst = trait_ref.skip_binder().substs.type_at(0);
let src = trait_ref.skip_binder().substs.type_at(1);
let dst = trait_ref.substs.type_at(0);
let src = trait_ref.substs.type_at(1);
let custom_err_msg = format!(
"`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
);
Expand Down
48 changes: 25 additions & 23 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,33 +275,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_transmutability_candidate");

let predicate = obligation.predicate;

let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);

let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
dst: p.trait_ref.substs.type_at(0),
src: p.trait_ref.substs.type_at(1),
});

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();
// 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 Some(assume) = rustc_transmute::Assume::from_const(
self.infcx.tcx,
obligation.param_env,
predicate.trait_ref.substs.const_at(3)
) else {
return Err(Unimplemented);
};

let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);

let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);

use rustc_transmute::Answer;
let maybe_transmutable = transmute_env.is_transmutable(
obligation.cause.clone(),
rustc_transmute::Types {
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 {
Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
rustc_transmute::Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
_ => Err(Unimplemented),
}
}
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_transmute/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ mod rustc {
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;
Expand Down Expand Up @@ -92,15 +91,13 @@ mod rustc {
pub fn is_transmutable(
&mut self,
cause: ObligationCause<'tcx>,
src_and_dst: Binder<'tcx, Types<'tcx>>,
types: Types<'tcx>,
scope: Ty<'tcx>,
assume: crate::Assume,
) -> 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(
src,
dst,
types.src,
types.dst,
scope,
assume,
self.infcx.tcx,
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/transmutability/references.current.stderr
Original file line number Diff line number Diff line change
@@ -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
|
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`
--> $DIR/references.rs:16:14
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/transmutability/references.next.stderr
Original file line number Diff line number Diff line change
@@ -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
|
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`
--> $DIR/references.rs:16:14
Expand Down
22 changes: 22 additions & 0 deletions tests/ui/transmutability/region-infer.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions tests/ui/transmutability/region-infer.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit f5222cd

Please sign in to comment.