diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6872d038fb7f0..bccb04b4ff302 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -254,9 +254,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { LangItem::TransmuteTrait, ) { // Recompute the safe transmute reason and use that for the error reporting + let (report_obligation, report_pred) = + self.select_transmute_obligation_for_reporting( + &obligation, + main_trait_predicate, + root_obligation, + ); + match self.get_safe_transmute_error_and_reason( - obligation.clone(), - main_trait_predicate, + report_obligation, + report_pred, span, ) { GetSafeTransmuteErrorAndReason::Silent => { @@ -2793,6 +2800,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } + fn select_transmute_obligation_for_reporting( + &self, + obligation: &PredicateObligation<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, + root_obligation: &PredicateObligation<'tcx>, + ) -> (PredicateObligation<'tcx>, ty::PolyTraitPredicate<'tcx>) { + let ocx = ObligationCtxt::new(self); + let normalized_predicate = self.tcx.erase_and_anonymize_regions( + self.tcx.instantiate_bound_regions_with_erased(trait_predicate), + ); + let trait_ref = normalized_predicate.trait_ref; + + let Ok(assume) = ocx.structurally_normalize_const( + &obligation.cause, + obligation.param_env, + trait_ref.args.const_at(2), + ) else { + return (obligation.clone(), trait_predicate); + }; + + let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else { + return (obligation.clone(), trait_predicate); + }; + + let is_normalized_yes = matches!( + rustc_transmute::TransmuteTypeEnv::new(self.tcx).is_transmutable( + trait_ref.args.type_at(1), + trait_ref.args.type_at(0), + assume, + ), + rustc_transmute::Answer::Yes, + ); + + // If the normalized check unexpectedly passes, fall back to root obligation for reporting. + if is_normalized_yes + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(root_pred)) = + root_obligation.predicate.kind().skip_binder() + && root_pred.def_id() == trait_predicate.def_id() + { + return (root_obligation.clone(), root_obligation.predicate.kind().rebind(root_pred)); + } + + (obligation.clone(), trait_predicate) + } + fn get_safe_transmute_error_and_reason( &self, obligation: PredicateObligation<'tcx>, diff --git a/tests/ui/transmutability/type-alias-normalization.rs b/tests/ui/transmutability/type-alias-normalization.rs new file mode 100644 index 0000000000000..8c8734c677e8d --- /dev/null +++ b/tests/ui/transmutability/type-alias-normalization.rs @@ -0,0 +1,31 @@ +//! regression test for https://github.com/rust-lang/rust/issues/151462 +//@compile-flags: -Znext-solver=globally +#![feature(lazy_type_alias, transmutability)] +#![allow(incomplete_features)] +mod assert { + use std::mem::{Assume, TransmuteFrom}; + + pub fn is_maybe_transmutable() + where + Src: TransmuteFrom< + Src, + { + Assume { + alignment: true, + lifetimes: true, + safety: true, + validity: true, + } + }, + >, + { + } +} + +fn test() { + type JustUnit = (); + assert::is_maybe_transmutable::(); + //~^ ERROR `JustUnit` cannot be safely transmuted into `JustUnit` +} + +fn main() {} diff --git a/tests/ui/transmutability/type-alias-normalization.stderr b/tests/ui/transmutability/type-alias-normalization.stderr new file mode 100644 index 0000000000000..d224f755c6119 --- /dev/null +++ b/tests/ui/transmutability/type-alias-normalization.stderr @@ -0,0 +1,29 @@ +error[E0277]: `JustUnit` cannot be safely transmuted into `JustUnit` + --> $DIR/type-alias-normalization.rs:27:37 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^ analyzing the transmutability of `JustUnit` is not yet supported + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/type-alias-normalization.rs:10:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this function +LL | where +LL | Src: TransmuteFrom< + | ______________^ +LL | | Src, +LL | | { +LL | | Assume { +... | +LL | | }, +LL | | >, + | |_________^ required by this bound in `is_maybe_transmutable` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn test() where (): TransmuteFrom<(), Assume { alignment: true, lifetimes: true, safety: true, validity: true }> { + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.