diff options
| author | Michael Goulet <michael@errs.io> | 2024-09-27 14:24:31 -0400 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2024-10-19 18:07:35 +0000 |
| commit | 9453d2cfebfbfb58753c8afef1df3686ae8c6197 (patch) | |
| tree | a0894c04a65905a2be3646aa28b90706c9776916 /compiler/rustc_trait_selection | |
| parent | 38bbcc001e071ab1eaa092b8e387a210713e8d82 (diff) | |
| download | rust-9453d2cfebfbfb58753c8afef1df3686ae8c6197.tar.gz rust-9453d2cfebfbfb58753c8afef1df3686ae8c6197.zip | |
Fix transmute goal
Diffstat (limited to 'compiler/rustc_trait_selection')
4 files changed, 145 insertions, 110 deletions
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 5076152dbff..d8279c6a77a 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 @@ -2247,124 +2247,143 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span: Span, ) -> GetSafeTransmuteErrorAndReason { use rustc_transmute::Answer; + self.probe(|_| { + // We don't assemble a transmutability candidate for types that are generic + // and we should have ambiguity for types that still have non-region infer. + if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { + return GetSafeTransmuteErrorAndReason::Default; + } - // We don't assemble a transmutability candidate for types that are generic - // and we should have ambiguity for types that still have non-region infer. - if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { - return GetSafeTransmuteErrorAndReason::Default; - } + // Erase regions because layout code doesn't particularly care about regions. + let trait_ref = + self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); - // Erase regions because layout code doesn't particularly care about regions. - let trait_ref = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); + let src_and_dst = rustc_transmute::Types { + dst: trait_ref.args.type_at(0), + src: trait_ref.args.type_at(1), + }; - let src_and_dst = rustc_transmute::Types { - dst: trait_ref.args.type_at(0), - src: trait_ref.args.type_at(1), - }; - let Some(assume) = rustc_transmute::Assume::from_const( - self.infcx.tcx, - obligation.param_env, - trait_ref.args.const_at(2), - ) else { - self.dcx().span_delayed_bug( - span, - "Unable to construct rustc_transmute::Assume where it was previously possible", - ); - return GetSafeTransmuteErrorAndReason::Silent; - }; + let ocx = ObligationCtxt::new(self); + let Ok(assume) = ocx.structurally_normalize_const( + &obligation.cause, + obligation.param_env, + trait_ref.args.const_at(2), + ) else { + self.dcx().span_delayed_bug( + span, + "Unable to construct rustc_transmute::Assume where it was previously possible", + ); + return GetSafeTransmuteErrorAndReason::Silent; + }; - let dst = trait_ref.args.type_at(0); - let src = trait_ref.args.type_at(1); + let Some(assume) = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) + else { + self.dcx().span_delayed_bug( + span, + "Unable to construct rustc_transmute::Assume where it was previously possible", + ); + return GetSafeTransmuteErrorAndReason::Silent; + }; - let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); + let dst = trait_ref.args.type_at(0); + let src = trait_ref.args.type_at(1); + let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); - match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( - obligation.cause, - src_and_dst, - assume, - ) { - Answer::No(reason) => { - let safe_transmute_explanation = match reason { - rustc_transmute::Reason::SrcIsNotYetSupported => { - format!("analyzing the transmutability of `{src}` is not yet supported") - } + match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( + obligation.cause, + src_and_dst, + assume, + ) { + Answer::No(reason) => { + let safe_transmute_explanation = match reason { + rustc_transmute::Reason::SrcIsNotYetSupported => { + format!("analyzing the transmutability of `{src}` is not yet supported") + } - rustc_transmute::Reason::DstIsNotYetSupported => { - format!("analyzing the transmutability of `{dst}` is not yet supported") - } + rustc_transmute::Reason::DstIsNotYetSupported => { + format!("analyzing the transmutability of `{dst}` is not yet supported") + } - rustc_transmute::Reason::DstIsBitIncompatible => { - format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`") - } + rustc_transmute::Reason::DstIsBitIncompatible => { + format!( + "at least one value of `{src}` isn't a bit-valid value of `{dst}`" + ) + } - rustc_transmute::Reason::DstUninhabited => { - format!("`{dst}` is uninhabited") - } + rustc_transmute::Reason::DstUninhabited => { + format!("`{dst}` is uninhabited") + } - rustc_transmute::Reason::DstMayHaveSafetyInvariants => { - format!("`{dst}` may carry safety invariants") - } - rustc_transmute::Reason::DstIsTooBig => { - format!("the size of `{src}` is smaller than the size of `{dst}`") - } - rustc_transmute::Reason::DstRefIsTooBig { src, dst } => { - let src_size = src.size; - let dst_size = dst.size; - format!( - "the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)" - ) - } - rustc_transmute::Reason::SrcSizeOverflow => { - format!( - "values of the type `{src}` are too big for the target architecture" - ) - } - rustc_transmute::Reason::DstSizeOverflow => { - format!( - "values of the type `{dst}` are too big for the target architecture" - ) - } - rustc_transmute::Reason::DstHasStricterAlignment { - src_min_align, - dst_min_align, - } => { - format!( - "the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})" - ) - } - rustc_transmute::Reason::DstIsMoreUnique => { - format!("`{src}` is a shared reference, but `{dst}` is a unique reference") - } - // Already reported by rustc - rustc_transmute::Reason::TypeError => { - return GetSafeTransmuteErrorAndReason::Silent; - } - rustc_transmute::Reason::SrcLayoutUnknown => { - format!("`{src}` has an unknown layout") - } - rustc_transmute::Reason::DstLayoutUnknown => { - format!("`{dst}` has an unknown layout") + rustc_transmute::Reason::DstMayHaveSafetyInvariants => { + format!("`{dst}` may carry safety invariants") + } + rustc_transmute::Reason::DstIsTooBig => { + format!("the size of `{src}` is smaller than the size of `{dst}`") + } + rustc_transmute::Reason::DstRefIsTooBig { src, dst } => { + let src_size = src.size; + let dst_size = dst.size; + format!( + "the referent size of `{src}` ({src_size} bytes) \ + is smaller than that of `{dst}` ({dst_size} bytes)" + ) + } + rustc_transmute::Reason::SrcSizeOverflow => { + format!( + "values of the type `{src}` are too big for the target architecture" + ) + } + rustc_transmute::Reason::DstSizeOverflow => { + format!( + "values of the type `{dst}` are too big for the target architecture" + ) + } + rustc_transmute::Reason::DstHasStricterAlignment { + src_min_align, + dst_min_align, + } => { + format!( + "the minimum alignment of `{src}` ({src_min_align}) should \ + be greater than that of `{dst}` ({dst_min_align})" + ) + } + rustc_transmute::Reason::DstIsMoreUnique => { + format!( + "`{src}` is a shared reference, but `{dst}` is a unique reference" + ) + } + // Already reported by rustc + rustc_transmute::Reason::TypeError => { + return GetSafeTransmuteErrorAndReason::Silent; + } + rustc_transmute::Reason::SrcLayoutUnknown => { + format!("`{src}` has an unknown layout") + } + rustc_transmute::Reason::DstLayoutUnknown => { + format!("`{dst}` has an unknown layout") + } + }; + GetSafeTransmuteErrorAndReason::Error { + err_msg, + safe_transmute_explanation: Some(safe_transmute_explanation), } - }; - GetSafeTransmuteErrorAndReason::Error { - err_msg, - safe_transmute_explanation: Some(safe_transmute_explanation), } + // Should never get a Yes at this point! We already ran it before, and did not get a Yes. + Answer::Yes => span_bug!( + span, + "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", + ), + // Reached when a different obligation (namely `Freeze`) causes the + // transmutability analysis to fail. In this case, silence the + // transmutability error message in favor of that more specific + // error. + Answer::If(_) => GetSafeTransmuteErrorAndReason::Error { + err_msg, + safe_transmute_explanation: None, + }, } - // Should never get a Yes at this point! We already ran it before, and did not get a Yes. - Answer::Yes => span_bug!( - span, - "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", - ), - // Reached when a different obligation (namely `Freeze`) causes the - // transmutability analysis to fail. In this case, silence the - // transmutability error message in favor of that more specific - // error. - Answer::If(_) => { - GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None } - } - } + }) } /// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index a45ec8b3c44..5e270b62b00 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -329,4 +329,15 @@ where .at(cause, param_env) .structurally_normalize(value, &mut **self.engine.borrow_mut()) } + + pub fn structurally_normalize_const( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::Const<'tcx>, + ) -> Result<ty::Const<'tcx>, Vec<E>> { + self.infcx + .at(cause, param_env) + .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0ba3b4e6e55..f78cd6c1aa0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -405,11 +405,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = obligation.predicate.skip_binder(); - let Some(assume) = rustc_transmute::Assume::from_const( - self.infcx.tcx, - obligation.param_env, - predicate.trait_ref.args.const_at(2), - ) else { + let mut assume = predicate.trait_ref.args.const_at(2); + // FIXME(min_generic_const_exprs): We should shallowly normalize this. + if self.tcx().features().generic_const_exprs { + assume = assume.normalize_internal(self.tcx(), obligation.param_env); + } + let Some(assume) = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) + else { return Err(Unimplemented); }; diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 3814f8112e9..f8d98eb856e 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -82,6 +82,8 @@ impl<'tcx> At<'_, 'tcx> { } Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) + } else if self.infcx.tcx.features().generic_const_exprs { + Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) } else { Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) } |
