Skip to content

Commit 98ddc0f

Browse files
committed
Safe Transmute: Fix ICE (Inconsistent is_transmutable result)
This patch updates the code that constructs the `Assume` type to return an error instead of silently falling back to a default `Assume`. This fixes an ICE where error reporting would get a different `is_transmutable` result that is inconsistent with the original one computed during trait confirmation. Fixes #110969
1 parent 39f42ad commit 98ddc0f

File tree

12 files changed

+147
-45
lines changed

12 files changed

+147
-45
lines changed

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -599,10 +599,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
599599
// which will ICE for region vars.
600600
let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args);
601601

602-
let Some(assume) =
603-
rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(3))
604-
else {
605-
return Err(NoSolution);
602+
let maybe_assume =
603+
rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(3));
604+
let assume = match maybe_assume {
605+
Some(Ok(assume)) => assume,
606+
Some(Err(_guar)) => return Err(NoSolution),
607+
None => return Err(NoSolution),
606608
};
607609

608610
let certainty = ecx.is_transmutable(

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

+17-10
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ pub struct ImplCandidate<'tcx> {
6969
}
7070

7171
enum GetSafeTransmuteErrorAndReason {
72-
Silent,
72+
ErrorGuaranteed(ErrorGuaranteed),
73+
// Unable to compute Safe Transmute result because of ambiguity
74+
Ambiguous,
7375
Error { err_msg: String, safe_transmute_explanation: String },
7476
}
7577

@@ -756,7 +758,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
756758
trait_ref,
757759
span,
758760
) {
759-
GetSafeTransmuteErrorAndReason::Silent => return,
761+
GetSafeTransmuteErrorAndReason::ErrorGuaranteed(_guar) => return,
762+
// Unable to compute whether Safe Transmute is possible (for example, due to an unevaluated const).
763+
// The same thing occurred during trait selection/confirmation, so there is no error to report here.
764+
GetSafeTransmuteErrorAndReason::Ambiguous => return,
760765
GetSafeTransmuteErrorAndReason::Error {
761766
err_msg,
762767
safe_transmute_explanation,
@@ -2884,15 +2889,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
28842889
src: trait_ref.args.type_at(1),
28852890
};
28862891
let scope = trait_ref.args.type_at(2);
2887-
let Some(assume) = rustc_transmute::Assume::from_const(
2892+
2893+
let maybe_assume = rustc_transmute::Assume::from_const(
28882894
self.infcx.tcx,
28892895
obligation.param_env,
28902896
trait_ref.args.const_at(3),
2891-
) else {
2892-
span_bug!(
2893-
span,
2894-
"Unable to construct rustc_transmute::Assume where it was previously possible"
2895-
);
2897+
);
2898+
2899+
let assume = match maybe_assume {
2900+
Some(Ok(assume)) => assume,
2901+
Some(Err(guar)) => return GetSafeTransmuteErrorAndReason::ErrorGuaranteed(guar),
2902+
None => return GetSafeTransmuteErrorAndReason::Ambiguous,
28962903
};
28972904

28982905
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2938,8 +2945,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
29382945
format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
29392946
}
29402947
// Already reported by rustc
2941-
rustc_transmute::Reason::TypeError => {
2942-
return GetSafeTransmuteErrorAndReason::Silent;
2948+
rustc_transmute::Reason::TypeError(guar) => {
2949+
return GetSafeTransmuteErrorAndReason::ErrorGuaranteed(guar);
29432950
}
29442951
rustc_transmute::Reason::SrcLayoutUnknown => {
29452952
format!("`{src}` has an unknown layout")

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
340340
let predicate =
341341
self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate));
342342

343-
let Some(assume) = rustc_transmute::Assume::from_const(
343+
let Some(Ok(assume)) = rustc_transmute::Assume::from_const(
344344
self.infcx.tcx,
345345
obligation.param_env,
346346
predicate.trait_ref.args.const_at(3),

compiler/rustc_transmute/src/layout/tree.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ pub(crate) mod rustc {
261261
use rustc_middle::ty::UintTy::*;
262262
use rustc_target::abi::HasDataLayout;
263263

264-
if let Err(e) = ty.error_reported() {
265-
return Err(Err::TypeError(e));
264+
if let Err(guar) = ty.error_reported() {
265+
return Err(Err::TypeError(guar));
266266
}
267267

268268
let target = tcx.data_layout();

compiler/rustc_transmute/src/lib.rs

+8-19
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub enum Reason {
5959
/// Can't go from shared pointer to unique pointer
6060
DstIsMoreUnique,
6161
/// Encountered a type error
62-
TypeError,
62+
TypeError(ErrorGuaranteed),
6363
/// The layout of src is unknown
6464
SrcLayoutUnknown,
6565
/// The layout of dst is unknown
@@ -79,6 +79,7 @@ mod rustc {
7979
use rustc_middle::ty::Ty;
8080
use rustc_middle::ty::TyCtxt;
8181
use rustc_middle::ty::ValTree;
82+
use rustc_span::ErrorGuaranteed;
8283

8384
/// The source and destination types of a transmutation.
8485
#[derive(TypeVisitable, Debug, Clone, Copy)]
@@ -123,20 +124,14 @@ mod rustc {
123124
tcx: TyCtxt<'tcx>,
124125
param_env: ParamEnv<'tcx>,
125126
c: Const<'tcx>,
126-
) -> Option<Self> {
127+
) -> Option<Result<Self, ErrorGuaranteed>> {
127128
use rustc_middle::ty::ScalarInt;
128129
use rustc_middle::ty::TypeVisitableExt;
129130
use rustc_span::symbol::sym;
130131

131132
let c = c.eval(tcx, param_env);
132-
133133
if let Err(err) = c.error_reported() {
134-
return Some(Self {
135-
alignment: true,
136-
lifetimes: true,
137-
safety: true,
138-
validity: true,
139-
});
134+
return Some(Err(err));
140135
}
141136

142137
let adt_def = c.ty().ty_adt_def()?;
@@ -151,14 +146,7 @@ mod rustc {
151146
let variant = adt_def.non_enum_variant();
152147
let fields = match c.try_to_valtree() {
153148
Some(ValTree::Branch(branch)) => branch,
154-
_ => {
155-
return Some(Self {
156-
alignment: true,
157-
lifetimes: true,
158-
safety: true,
159-
validity: true,
160-
});
161-
}
149+
_ => return None,
162150
};
163151

164152
let get_field = |name| {
@@ -171,15 +159,16 @@ mod rustc {
171159
fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
172160
};
173161

174-
Some(Self {
162+
Some(Ok(Self {
175163
alignment: get_field(sym::alignment),
176164
lifetimes: get_field(sym::lifetimes),
177165
safety: get_field(sym::safety),
178166
validity: get_field(sym::validity),
179-
})
167+
}))
180168
}
181169
}
182170
}
183171

184172
#[cfg(feature = "rustc")]
185173
pub use rustc::*;
174+
use rustc_span::ErrorGuaranteed;

compiler/rustc_transmute/src/maybe_transmutable/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ mod rustc {
7878
let dst = Tree::from_ty(dst, context);
7979

8080
match (src, dst) {
81-
(Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => {
82-
Answer::No(Reason::TypeError)
81+
(Err(Err::TypeError(guar)), _) | (_, Err(Err::TypeError(guar))) => {
82+
Answer::No(Reason::TypeError(guar))
8383
}
8484
(Err(Err::UnknownLayout), _) => Answer::No(Reason::SrcLayoutUnknown),
8585
(_, Err(Err::UnknownLayout)) => Answer::No(Reason::DstLayoutUnknown),

tests/ui/transmutability/issue-110892.stderr renamed to tests/ui/transmutability/issue-110892.current.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
error: expected parameter name, found `,`
2-
--> $DIR/issue-110892.rs:27:9
2+
--> $DIR/issue-110892.rs:29:9
33
|
44
LL | ,
55
| ^ expected parameter name
66

77
error: expected parameter name, found `,`
8-
--> $DIR/issue-110892.rs:28:9
8+
--> $DIR/issue-110892.rs:30:9
99
|
1010
LL | ,
1111
| ^ expected parameter name
1212

1313
error: expected parameter name, found `,`
14-
--> $DIR/issue-110892.rs:29:9
14+
--> $DIR/issue-110892.rs:31:9
1515
|
1616
LL | ,
1717
| ^ expected parameter name
1818

1919
error: expected parameter name, found `,`
20-
--> $DIR/issue-110892.rs:30:9
20+
--> $DIR/issue-110892.rs:32:9
2121
|
2222
LL | ,
2323
| ^ expected parameter name
2424

2525
error[E0308]: mismatched types
26-
--> $DIR/issue-110892.rs:31:10
26+
--> $DIR/issue-110892.rs:33:10
2727
|
2828
LL | const fn from_options(
2929
| ------------ implicitly returns `()` as its body has no tail or `return` expression
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
error: expected parameter name, found `,`
2+
--> $DIR/issue-110892.rs:29:9
3+
|
4+
LL | ,
5+
| ^ expected parameter name
6+
7+
error: expected parameter name, found `,`
8+
--> $DIR/issue-110892.rs:30:9
9+
|
10+
LL | ,
11+
| ^ expected parameter name
12+
13+
error: expected parameter name, found `,`
14+
--> $DIR/issue-110892.rs:31:9
15+
|
16+
LL | ,
17+
| ^ expected parameter name
18+
19+
error: expected parameter name, found `,`
20+
--> $DIR/issue-110892.rs:32:9
21+
|
22+
LL | ,
23+
| ^ expected parameter name
24+
25+
error[E0284]: type annotations needed: cannot satisfy `the constant `{ from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }` can be evaluated`
26+
--> $DIR/issue-110892.rs:23:13
27+
|
28+
LL | { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }` can be evaluated`
30+
|
31+
note: required by a bound in `is_transmutable`
32+
--> $DIR/issue-110892.rs:23:13
33+
|
34+
LL | pub fn is_transmutable<
35+
| --------------- required by a bound in this function
36+
...
37+
LL | { from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
39+
40+
error: aborting due to 5 previous errors
41+
42+
For more information about this error, try `rustc --explain E0284`.

tests/ui/transmutability/issue-110892.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// check-fail
2+
// revisions: current next
3+
//[next] compile-flags: -Ztrait-solver=next
24
#![feature(generic_const_exprs, transmutability)]
35
#![allow(incomplete_features)]
46

@@ -18,7 +20,7 @@ mod assert {
1820
Dst: BikeshedIntrinsicFrom<
1921
Src,
2022
Context,
21-
{ from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) }
23+
{ from_options(ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_SAFETY, ASSUME_VALIDITY) } //[next]~ ERROR type annotations needed
2224
>,
2325
{}
2426

@@ -28,7 +30,7 @@ mod assert {
2830
, //~ ERROR expected parameter name, found `,`
2931
, //~ ERROR expected parameter name, found `,`
3032
, //~ ERROR expected parameter name, found `,`
31-
) -> Assume {} //~ ERROR mismatched types
33+
) -> Assume {} //[current]~ ERROR mismatched types
3234
}
3335

3436
fn main() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-110969.rs:26:74
3+
|
4+
LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>();
5+
| ^^ expected `Assume`, found `()`
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/issue-110969.rs:26:29
9+
|
10+
LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>();
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-110969.rs:26:74
3+
|
4+
LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>();
5+
| ^^ expected `Assume`, found `()`
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/issue-110969.rs:26:29
9+
|
10+
LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>();
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0308`.
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// check-fail
2+
// revisions: current next
3+
//[next] compile-flags: -Ztrait-solver=next
4+
#![feature(adt_const_params, generic_const_exprs, transmutability)]
5+
#![allow(incomplete_features)]
6+
7+
mod assert {
8+
use std::mem::BikeshedIntrinsicFrom;
9+
10+
pub fn is_transmutable<Src, Dst, Context, const ASSUME: std::mem::Assume>()
11+
where
12+
Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME>,
13+
{
14+
}
15+
}
16+
17+
fn main() {
18+
struct Context;
19+
#[repr(C)]
20+
struct Src;
21+
#[repr(C)]
22+
struct Dst;
23+
24+
trait Trait {
25+
// The `{}` should not cause an ICE
26+
const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>();
27+
//~^ ERROR mismatched types
28+
//~^^ ERROR mismatched types
29+
}
30+
}

0 commit comments

Comments
 (0)