Skip to content

Commit 927f6d9

Browse files
Fix transmute goal
1 parent 6878066 commit 927f6d9

File tree

9 files changed

+235
-117
lines changed

9 files changed

+235
-117
lines changed

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,36 @@ where
290290
Ok(ty)
291291
}
292292
}
293+
294+
/// Normalize a type for when it is structurally matched on.
295+
///
296+
/// This function is necessary in nearly all cases before matching on a type.
297+
/// Not doing so is likely to be incomplete and therefore unsound during
298+
/// coherence.
299+
#[instrument(level = "trace", skip(self, param_env), ret)]
300+
fn structurally_normalize_const(
301+
&mut self,
302+
param_env: I::ParamEnv,
303+
ct: I::Const,
304+
) -> Result<I::Const, NoSolution> {
305+
if let ty::ConstKind::Unevaluated(..) = ct.kind() {
306+
let normalized_ct = self.next_const_infer();
307+
let alias_relate_goal = Goal::new(
308+
self.cx(),
309+
param_env,
310+
ty::PredicateKind::AliasRelate(
311+
ct.into(),
312+
normalized_ct.into(),
313+
ty::AliasRelationDirection::Equate,
314+
),
315+
);
316+
self.add_goal(GoalSource::Misc, alias_relate_goal);
317+
self.try_evaluate_added_goals()?;
318+
Ok(self.resolve_vars_if_possible(normalized_ct))
319+
} else {
320+
Ok(ct)
321+
}
322+
}
293323
}
294324

295325
fn response_no_constraints_raw<I: Interner>(

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,11 +634,16 @@ where
634634
// FIXME: This actually should destructure the `Result` we get from transmutability and
635635
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
636636
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
637+
let assume = ecx.structurally_normalize_const(
638+
goal.param_env,
639+
goal.predicate.trait_ref.args.const_at(2),
640+
)?;
641+
637642
let certainty = ecx.is_transmutable(
638643
goal.param_env,
639644
goal.predicate.trait_ref.args.type_at(0),
640645
goal.predicate.trait_ref.args.type_at(1),
641-
goal.predicate.trait_ref.args.const_at(2),
646+
assume,
642647
)?;
643648
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
644649
})

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

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

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

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

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

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

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

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

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

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

2302-
rustc_transmute::Reason::DstUninhabited => {
2303-
format!("`{dst}` is uninhabited")
2304-
}
2315+
rustc_transmute::Reason::DstUninhabited => {
2316+
format!("`{dst}` is uninhabited")
2317+
}
23052318

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

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

compiler/rustc_trait_selection/src/traits/engine.rs

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

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
402402

403403
let predicate = obligation.predicate.skip_binder();
404404

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

compiler/rustc_trait_selection/src/traits/structural_normalize.rs

Lines changed: 2 additions & 0 deletions
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
}

compiler/rustc_transmute/src/lib.rs

Lines changed: 1 addition & 6 deletions
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()?;
Lines changed: 19 additions & 0 deletions
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)