Skip to content

Commit 9453d2c

Browse files
Fix transmute goal
1 parent 38bbcc0 commit 9453d2c

File tree

9 files changed

+236
-117
lines changed

9 files changed

+236
-117
lines changed

Diff for: compiler/rustc_next_trait_solver/src/solve/mod.rs

+31
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,37 @@ where
295295
Ok(ty)
296296
}
297297
}
298+
299+
/// Normalize a const for when it is structurally matched on, or more likely
300+
/// when it needs `.try_to_*` called on it (e.g. to turn it into a usize).
301+
///
302+
/// This function is necessary in nearly all cases before matching on a const.
303+
/// Not doing so is likely to be incomplete and therefore unsound during
304+
/// coherence.
305+
#[instrument(level = "trace", skip(self, param_env), ret)]
306+
fn structurally_normalize_const(
307+
&mut self,
308+
param_env: I::ParamEnv,
309+
ct: I::Const,
310+
) -> Result<I::Const, NoSolution> {
311+
if let ty::ConstKind::Unevaluated(..) = ct.kind() {
312+
let normalized_ct = self.next_const_infer();
313+
let alias_relate_goal = Goal::new(
314+
self.cx(),
315+
param_env,
316+
ty::PredicateKind::AliasRelate(
317+
ct.into(),
318+
normalized_ct.into(),
319+
ty::AliasRelationDirection::Equate,
320+
),
321+
);
322+
self.add_goal(GoalSource::Misc, alias_relate_goal);
323+
self.try_evaluate_added_goals()?;
324+
Ok(self.resolve_vars_if_possible(normalized_ct))
325+
} else {
326+
Ok(ct)
327+
}
328+
}
298329
}
299330

300331
fn response_no_constraints_raw<I: Interner>(

Diff for: compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -627,11 +627,16 @@ where
627627
}
628628

629629
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
630+
let assume = ecx.structurally_normalize_const(
631+
goal.param_env,
632+
goal.predicate.trait_ref.args.const_at(2),
633+
)?;
634+
630635
let certainty = ecx.is_transmutable(
631636
goal.param_env,
632637
goal.predicate.trait_ref.args.type_at(0),
633638
goal.predicate.trait_ref.args.type_at(1),
634-
goal.predicate.trait_ref.args.const_at(2),
639+
assume,
635640
)?;
636641
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
637642
})

Diff for: compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+124-105
Original file line numberDiff line numberDiff line change
@@ -2247,124 +2247,143 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
22472247
span: Span,
22482248
) -> GetSafeTransmuteErrorAndReason {
22492249
use rustc_transmute::Answer;
2250+
self.probe(|_| {
2251+
// We don't assemble a transmutability candidate for types that are generic
2252+
// and we should have ambiguity for types that still have non-region infer.
2253+
if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() {
2254+
return GetSafeTransmuteErrorAndReason::Default;
2255+
}
22502256

2251-
// We don't assemble a transmutability candidate for types that are generic
2252-
// and we should have ambiguity for types that still have non-region infer.
2253-
if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() {
2254-
return GetSafeTransmuteErrorAndReason::Default;
2255-
}
2257+
// Erase regions because layout code doesn't particularly care about regions.
2258+
let trait_ref =
2259+
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
22562260

2257-
// Erase regions because layout code doesn't particularly care about regions.
2258-
let trait_ref =
2259-
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
2261+
let src_and_dst = rustc_transmute::Types {
2262+
dst: trait_ref.args.type_at(0),
2263+
src: trait_ref.args.type_at(1),
2264+
};
22602265

2261-
let src_and_dst = rustc_transmute::Types {
2262-
dst: trait_ref.args.type_at(0),
2263-
src: trait_ref.args.type_at(1),
2264-
};
2265-
let Some(assume) = rustc_transmute::Assume::from_const(
2266-
self.infcx.tcx,
2267-
obligation.param_env,
2268-
trait_ref.args.const_at(2),
2269-
) else {
2270-
self.dcx().span_delayed_bug(
2271-
span,
2272-
"Unable to construct rustc_transmute::Assume where it was previously possible",
2273-
);
2274-
return GetSafeTransmuteErrorAndReason::Silent;
2275-
};
2266+
let ocx = ObligationCtxt::new(self);
2267+
let Ok(assume) = ocx.structurally_normalize_const(
2268+
&obligation.cause,
2269+
obligation.param_env,
2270+
trait_ref.args.const_at(2),
2271+
) else {
2272+
self.dcx().span_delayed_bug(
2273+
span,
2274+
"Unable to construct rustc_transmute::Assume where it was previously possible",
2275+
);
2276+
return GetSafeTransmuteErrorAndReason::Silent;
2277+
};
22762278

2277-
let dst = trait_ref.args.type_at(0);
2278-
let src = trait_ref.args.type_at(1);
2279+
let Some(assume) =
2280+
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
2281+
else {
2282+
self.dcx().span_delayed_bug(
2283+
span,
2284+
"Unable to construct rustc_transmute::Assume where it was previously possible",
2285+
);
2286+
return GetSafeTransmuteErrorAndReason::Silent;
2287+
};
22792288

2280-
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
2289+
let dst = trait_ref.args.type_at(0);
2290+
let src = trait_ref.args.type_at(1);
2291+
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
22812292

2282-
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
2283-
obligation.cause,
2284-
src_and_dst,
2285-
assume,
2286-
) {
2287-
Answer::No(reason) => {
2288-
let safe_transmute_explanation = match reason {
2289-
rustc_transmute::Reason::SrcIsNotYetSupported => {
2290-
format!("analyzing the transmutability of `{src}` is not yet supported")
2291-
}
2293+
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
2294+
obligation.cause,
2295+
src_and_dst,
2296+
assume,
2297+
) {
2298+
Answer::No(reason) => {
2299+
let safe_transmute_explanation = match reason {
2300+
rustc_transmute::Reason::SrcIsNotYetSupported => {
2301+
format!("analyzing the transmutability of `{src}` is not yet supported")
2302+
}
22922303

2293-
rustc_transmute::Reason::DstIsNotYetSupported => {
2294-
format!("analyzing the transmutability of `{dst}` is not yet supported")
2295-
}
2304+
rustc_transmute::Reason::DstIsNotYetSupported => {
2305+
format!("analyzing the transmutability of `{dst}` is not yet supported")
2306+
}
22962307

2297-
rustc_transmute::Reason::DstIsBitIncompatible => {
2298-
format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
2299-
}
2308+
rustc_transmute::Reason::DstIsBitIncompatible => {
2309+
format!(
2310+
"at least one value of `{src}` isn't a bit-valid value of `{dst}`"
2311+
)
2312+
}
23002313

2301-
rustc_transmute::Reason::DstUninhabited => {
2302-
format!("`{dst}` is uninhabited")
2303-
}
2314+
rustc_transmute::Reason::DstUninhabited => {
2315+
format!("`{dst}` is uninhabited")
2316+
}
23042317

2305-
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
2306-
format!("`{dst}` may carry safety invariants")
2307-
}
2308-
rustc_transmute::Reason::DstIsTooBig => {
2309-
format!("the size of `{src}` is smaller than the size of `{dst}`")
2310-
}
2311-
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
2312-
let src_size = src.size;
2313-
let dst_size = dst.size;
2314-
format!(
2315-
"the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
2316-
)
2317-
}
2318-
rustc_transmute::Reason::SrcSizeOverflow => {
2319-
format!(
2320-
"values of the type `{src}` are too big for the target architecture"
2321-
)
2322-
}
2323-
rustc_transmute::Reason::DstSizeOverflow => {
2324-
format!(
2325-
"values of the type `{dst}` are too big for the target architecture"
2326-
)
2327-
}
2328-
rustc_transmute::Reason::DstHasStricterAlignment {
2329-
src_min_align,
2330-
dst_min_align,
2331-
} => {
2332-
format!(
2333-
"the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
2334-
)
2335-
}
2336-
rustc_transmute::Reason::DstIsMoreUnique => {
2337-
format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
2338-
}
2339-
// Already reported by rustc
2340-
rustc_transmute::Reason::TypeError => {
2341-
return GetSafeTransmuteErrorAndReason::Silent;
2342-
}
2343-
rustc_transmute::Reason::SrcLayoutUnknown => {
2344-
format!("`{src}` has an unknown layout")
2345-
}
2346-
rustc_transmute::Reason::DstLayoutUnknown => {
2347-
format!("`{dst}` has an unknown layout")
2318+
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
2319+
format!("`{dst}` may carry safety invariants")
2320+
}
2321+
rustc_transmute::Reason::DstIsTooBig => {
2322+
format!("the size of `{src}` is smaller than the size of `{dst}`")
2323+
}
2324+
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
2325+
let src_size = src.size;
2326+
let dst_size = dst.size;
2327+
format!(
2328+
"the referent size of `{src}` ({src_size} bytes) \
2329+
is smaller than that of `{dst}` ({dst_size} bytes)"
2330+
)
2331+
}
2332+
rustc_transmute::Reason::SrcSizeOverflow => {
2333+
format!(
2334+
"values of the type `{src}` are too big for the target architecture"
2335+
)
2336+
}
2337+
rustc_transmute::Reason::DstSizeOverflow => {
2338+
format!(
2339+
"values of the type `{dst}` are too big for the target architecture"
2340+
)
2341+
}
2342+
rustc_transmute::Reason::DstHasStricterAlignment {
2343+
src_min_align,
2344+
dst_min_align,
2345+
} => {
2346+
format!(
2347+
"the minimum alignment of `{src}` ({src_min_align}) should \
2348+
be greater than that of `{dst}` ({dst_min_align})"
2349+
)
2350+
}
2351+
rustc_transmute::Reason::DstIsMoreUnique => {
2352+
format!(
2353+
"`{src}` is a shared reference, but `{dst}` is a unique reference"
2354+
)
2355+
}
2356+
// Already reported by rustc
2357+
rustc_transmute::Reason::TypeError => {
2358+
return GetSafeTransmuteErrorAndReason::Silent;
2359+
}
2360+
rustc_transmute::Reason::SrcLayoutUnknown => {
2361+
format!("`{src}` has an unknown layout")
2362+
}
2363+
rustc_transmute::Reason::DstLayoutUnknown => {
2364+
format!("`{dst}` has an unknown layout")
2365+
}
2366+
};
2367+
GetSafeTransmuteErrorAndReason::Error {
2368+
err_msg,
2369+
safe_transmute_explanation: Some(safe_transmute_explanation),
23482370
}
2349-
};
2350-
GetSafeTransmuteErrorAndReason::Error {
2351-
err_msg,
2352-
safe_transmute_explanation: Some(safe_transmute_explanation),
23532371
}
2372+
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
2373+
Answer::Yes => span_bug!(
2374+
span,
2375+
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
2376+
),
2377+
// Reached when a different obligation (namely `Freeze`) causes the
2378+
// transmutability analysis to fail. In this case, silence the
2379+
// transmutability error message in favor of that more specific
2380+
// error.
2381+
Answer::If(_) => GetSafeTransmuteErrorAndReason::Error {
2382+
err_msg,
2383+
safe_transmute_explanation: None,
2384+
},
23542385
}
2355-
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
2356-
Answer::Yes => span_bug!(
2357-
span,
2358-
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
2359-
),
2360-
// Reached when a different obligation (namely `Freeze`) causes the
2361-
// transmutability analysis to fail. In this case, silence the
2362-
// transmutability error message in favor of that more specific
2363-
// error.
2364-
Answer::If(_) => {
2365-
GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None }
2366-
}
2367-
}
2386+
})
23682387
}
23692388

23702389
/// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the

Diff for: compiler/rustc_trait_selection/src/traits/engine.rs

+11
Original file line numberDiff line numberDiff line change
@@ -329,4 +329,15 @@ where
329329
.at(cause, param_env)
330330
.structurally_normalize(value, &mut **self.engine.borrow_mut())
331331
}
332+
333+
pub fn structurally_normalize_const(
334+
&self,
335+
cause: &ObligationCause<'tcx>,
336+
param_env: ty::ParamEnv<'tcx>,
337+
value: ty::Const<'tcx>,
338+
) -> Result<ty::Const<'tcx>, Vec<E>> {
339+
self.infcx
340+
.at(cause, param_env)
341+
.structurally_normalize_const(value, &mut **self.engine.borrow_mut())
342+
}
332343
}

Diff for: compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
405405

406406
let predicate = obligation.predicate.skip_binder();
407407

408-
let Some(assume) = rustc_transmute::Assume::from_const(
409-
self.infcx.tcx,
410-
obligation.param_env,
411-
predicate.trait_ref.args.const_at(2),
412-
) else {
408+
let mut assume = predicate.trait_ref.args.const_at(2);
409+
// FIXME(min_generic_const_exprs): We should shallowly normalize this.
410+
if self.tcx().features().generic_const_exprs {
411+
assume = assume.normalize_internal(self.tcx(), obligation.param_env);
412+
}
413+
let Some(assume) =
414+
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
415+
else {
413416
return Err(Unimplemented);
414417
};
415418

Diff for: compiler/rustc_trait_selection/src/traits/structural_normalize.rs

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ impl<'tcx> At<'_, 'tcx> {
8282
}
8383

8484
Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
85+
} else if self.infcx.tcx.features().generic_const_exprs {
86+
Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
8587
} else {
8688
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
8789
}

Diff for: compiler/rustc_transmute/src/lib.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,7 @@ mod rustc {
134134
use rustc_span::symbol::sym;
135135

136136
let Some((cv, ty)) = c.try_to_valtree() else {
137-
return Some(Self {
138-
alignment: true,
139-
lifetimes: true,
140-
safety: true,
141-
validity: true,
142-
});
137+
return None;
143138
};
144139

145140
let adt_def = ty.ty_adt_def()?;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(transmutability)]
2+
#![feature(generic_const_exprs)]
3+
//~^ WARN the feature `generic_const_exprs` is incomplete
4+
5+
use std::mem::{Assume, TransmuteFrom};
6+
7+
pub fn is_transmutable<const ASSUME_ALIGNMENT: bool>()
8+
where
9+
(): TransmuteFrom<(), { Assume::SAFETY }>,
10+
{
11+
}
12+
13+
fn foo<const N: usize>() {
14+
is_transmutable::<{}>();
15+
//~^ ERROR the trait bound `(): TransmuteFrom<(), { Assume::SAFETY }>` is not satisfied
16+
//~| ERROR mismatched types
17+
}
18+
19+
fn main() {}

0 commit comments

Comments
 (0)