Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

‎compiler/rustc_next_trait_solver/src/solve/mod.rs‎

Lines changed: 31 additions & 0 deletions
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>(

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs‎

Lines changed: 6 additions & 1 deletion
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
})

‎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
@@ -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

‎compiler/rustc_trait_selection/src/traits/engine.rs‎

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

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

Lines changed: 8 additions & 5 deletions
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

‎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)

AltStyle によって変換されたページ (->オリジナル) /