Skip to content

Commit 63c147f

Browse files
Fix transmute goal
1 parent c053591 commit 63c147f

File tree

8 files changed

+204
-137
lines changed

8 files changed

+204
-137
lines changed

compiler/rustc_next_trait_solver/src/solve/mod.rs

+30
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

+6-1
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

+120-101
Original file line numberDiff line numberDiff line change
@@ -2220,117 +2220,136 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
22202220
span: Span,
22212221
) -> GetSafeTransmuteErrorAndReason {
22222222
use rustc_transmute::Answer;
2223+
self.probe(|_| {
2224+
let trait_ref =
2225+
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
22232226

2224-
// Erase regions because layout code doesn't particularly care about regions.
2225-
let trait_ref =
2226-
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
2227+
let src_and_dst = rustc_transmute::Types {
2228+
dst: trait_ref.args.type_at(0),
2229+
src: trait_ref.args.type_at(1),
2230+
};
22272231

2228-
let src_and_dst = rustc_transmute::Types {
2229-
dst: trait_ref.args.type_at(0),
2230-
src: trait_ref.args.type_at(1),
2231-
};
2232-
let Some(assume) = rustc_transmute::Assume::from_const(
2233-
self.infcx.tcx,
2234-
obligation.param_env,
2235-
trait_ref.args.const_at(2),
2236-
) else {
2237-
self.dcx().span_delayed_bug(
2238-
span,
2239-
"Unable to construct rustc_transmute::Assume where it was previously possible",
2240-
);
2241-
return GetSafeTransmuteErrorAndReason::Silent;
2242-
};
2232+
let ocx = ObligationCtxt::new(self);
2233+
let Ok(assume) = ocx.structurally_normalize_const(
2234+
&obligation.cause,
2235+
obligation.param_env,
2236+
trait_ref.args.const_at(2),
2237+
) else {
2238+
self.dcx().span_delayed_bug(
2239+
span,
2240+
"Unable to construct rustc_transmute::Assume where it was previously possible",
2241+
);
2242+
return GetSafeTransmuteErrorAndReason::Silent;
2243+
};
22432244

2244-
let dst = trait_ref.args.type_at(0);
2245-
let src = trait_ref.args.type_at(1);
2246-
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
2247-
2248-
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
2249-
obligation.cause,
2250-
src_and_dst,
2251-
assume,
2252-
) {
2253-
Answer::No(reason) => {
2254-
let safe_transmute_explanation = match reason {
2255-
rustc_transmute::Reason::SrcIsNotYetSupported => {
2256-
format!("analyzing the transmutability of `{src}` is not yet supported")
2257-
}
2245+
let Some(assume) =
2246+
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
2247+
else {
2248+
self.dcx().span_delayed_bug(
2249+
span,
2250+
"Unable to construct rustc_transmute::Assume where it was previously possible",
2251+
);
2252+
return GetSafeTransmuteErrorAndReason::Silent;
2253+
};
22582254

2259-
rustc_transmute::Reason::DstIsNotYetSupported => {
2260-
format!("analyzing the transmutability of `{dst}` is not yet supported")
2261-
}
2255+
let dst = trait_ref.args.type_at(0);
2256+
let src = trait_ref.args.type_at(1);
2257+
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
22622258

2263-
rustc_transmute::Reason::DstIsBitIncompatible => {
2264-
format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
2265-
}
2259+
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
2260+
obligation.cause,
2261+
src_and_dst,
2262+
assume,
2263+
) {
2264+
Answer::No(reason) => {
2265+
let safe_transmute_explanation = match reason {
2266+
rustc_transmute::Reason::SrcIsNotYetSupported => {
2267+
format!("analyzing the transmutability of `{src}` is not yet supported")
2268+
}
22662269

2267-
rustc_transmute::Reason::DstUninhabited => {
2268-
format!("`{dst}` is uninhabited")
2269-
}
2270+
rustc_transmute::Reason::DstIsNotYetSupported => {
2271+
format!("analyzing the transmutability of `{dst}` is not yet supported")
2272+
}
22702273

2271-
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
2272-
format!("`{dst}` may carry safety invariants")
2273-
}
2274-
rustc_transmute::Reason::DstIsTooBig => {
2275-
format!("the size of `{src}` is smaller than the size of `{dst}`")
2276-
}
2277-
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
2278-
let src_size = src.size;
2279-
let dst_size = dst.size;
2280-
format!(
2281-
"the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
2282-
)
2283-
}
2284-
rustc_transmute::Reason::SrcSizeOverflow => {
2285-
format!(
2286-
"values of the type `{src}` are too big for the target architecture"
2287-
)
2288-
}
2289-
rustc_transmute::Reason::DstSizeOverflow => {
2290-
format!(
2291-
"values of the type `{dst}` are too big for the target architecture"
2292-
)
2293-
}
2294-
rustc_transmute::Reason::DstHasStricterAlignment {
2295-
src_min_align,
2296-
dst_min_align,
2297-
} => {
2298-
format!(
2299-
"the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
2300-
)
2301-
}
2302-
rustc_transmute::Reason::DstIsMoreUnique => {
2303-
format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
2304-
}
2305-
// Already reported by rustc
2306-
rustc_transmute::Reason::TypeError => {
2307-
return GetSafeTransmuteErrorAndReason::Silent;
2308-
}
2309-
rustc_transmute::Reason::SrcLayoutUnknown => {
2310-
format!("`{src}` has an unknown layout")
2311-
}
2312-
rustc_transmute::Reason::DstLayoutUnknown => {
2313-
format!("`{dst}` has an unknown layout")
2274+
rustc_transmute::Reason::DstIsBitIncompatible => {
2275+
format!(
2276+
"at least one value of `{src}` isn't a bit-valid value of `{dst}`"
2277+
)
2278+
}
2279+
2280+
rustc_transmute::Reason::DstUninhabited => {
2281+
format!("`{dst}` is uninhabited")
2282+
}
2283+
2284+
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
2285+
format!("`{dst}` may carry safety invariants")
2286+
}
2287+
rustc_transmute::Reason::DstIsTooBig => {
2288+
format!("the size of `{src}` is smaller than the size of `{dst}`")
2289+
}
2290+
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
2291+
let src_size = src.size;
2292+
let dst_size = dst.size;
2293+
format!(
2294+
"the referent size of `{src}` ({src_size} bytes) \
2295+
is smaller than that of `{dst}` ({dst_size} bytes)"
2296+
)
2297+
}
2298+
rustc_transmute::Reason::SrcSizeOverflow => {
2299+
format!(
2300+
"values of the type `{src}` are too big for the target architecture"
2301+
)
2302+
}
2303+
rustc_transmute::Reason::DstSizeOverflow => {
2304+
format!(
2305+
"values of the type `{dst}` are too big for the target architecture"
2306+
)
2307+
}
2308+
rustc_transmute::Reason::DstHasStricterAlignment {
2309+
src_min_align,
2310+
dst_min_align,
2311+
} => {
2312+
format!(
2313+
"the minimum alignment of `{src}` ({src_min_align}) should \
2314+
be greater than that of `{dst}` ({dst_min_align})"
2315+
)
2316+
}
2317+
rustc_transmute::Reason::DstIsMoreUnique => {
2318+
format!(
2319+
"`{src}` is a shared reference, but `{dst}` is a unique reference"
2320+
)
2321+
}
2322+
// Already reported by rustc
2323+
rustc_transmute::Reason::TypeError => {
2324+
return GetSafeTransmuteErrorAndReason::Silent;
2325+
}
2326+
rustc_transmute::Reason::SrcLayoutUnknown => {
2327+
format!("`{src}` has an unknown layout")
2328+
}
2329+
rustc_transmute::Reason::DstLayoutUnknown => {
2330+
format!("`{dst}` has an unknown layout")
2331+
}
2332+
};
2333+
GetSafeTransmuteErrorAndReason::Error {
2334+
err_msg,
2335+
safe_transmute_explanation: Some(safe_transmute_explanation),
23142336
}
2315-
};
2316-
GetSafeTransmuteErrorAndReason::Error {
2317-
err_msg,
2318-
safe_transmute_explanation: Some(safe_transmute_explanation),
23192337
}
2338+
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
2339+
Answer::Yes => span_bug!(
2340+
span,
2341+
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
2342+
),
2343+
// Reached when a different obligation (namely `Freeze`) causes the
2344+
// transmutability analysis to fail. In this case, silence the
2345+
// transmutability error message in favor of that more specific
2346+
// error.
2347+
Answer::If(_) => GetSafeTransmuteErrorAndReason::Error {
2348+
err_msg,
2349+
safe_transmute_explanation: None,
2350+
},
23202351
}
2321-
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
2322-
Answer::Yes => span_bug!(
2323-
span,
2324-
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
2325-
),
2326-
// Reached when a different obligation (namely `Freeze`) causes the
2327-
// transmutability analysis to fail. In this case, silence the
2328-
// transmutability error message in favor of that more specific
2329-
// error.
2330-
Answer::If(_) => {
2331-
GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None }
2332-
}
2333-
}
2352+
})
23342353
}
23352354

23362355
fn add_tuple_trait_message(

compiler/rustc_trait_selection/src/traits/engine.rs

+11
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,15 @@ where
315315
.at(cause, param_env)
316316
.structurally_normalize(value, &mut **self.engine.borrow_mut())
317317
}
318+
319+
pub fn structurally_normalize_const(
320+
&self,
321+
cause: &ObligationCause<'tcx>,
322+
param_env: ty::ParamEnv<'tcx>,
323+
value: ty::Const<'tcx>,
324+
) -> Result<ty::Const<'tcx>, Vec<E>> {
325+
self.infcx
326+
.at(cause, param_env)
327+
.structurally_normalize_const(value, &mut **self.engine.borrow_mut())
328+
}
318329
}

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()?;

tests/crashes/126377.rs

-29
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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 mismatched types
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/dont-assume-err-is-yes-issue-126377.rs:2:12
3+
|
4+
LL | #![feature(generic_const_exprs)]
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/dont-assume-err-is-yes-issue-126377.rs:14:23
12+
|
13+
LL | is_transmutable::<{}>();
14+
| ^^ expected `bool`, found `()`
15+
16+
error: aborting due to 1 previous error; 1 warning emitted
17+
18+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)