Skip to content

Commit 53509ca

Browse files
committed
Auto merge of #154144 - Human9000-bit:const-prop-transmute-async-fix, r=cjgillot
Fix malformed transmute handling during mir build Running dataflow const prop optimization on `std::mem::transmute` of mismatched sizes failed the assertion in interpreter and caused ICE. So it's better to not let those transmutations into the interpreter at all Fixes #149920
2 parents d595fce + fa6e163 commit 53509ca

11 files changed

Lines changed: 67 additions & 37 deletions

File tree

compiler/rustc_hir_typeck/src/intrinsicck.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_index::Idx;
88
use rustc_middle::bug;
99
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
1010
use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized};
11+
use rustc_span::ErrorGuaranteed;
1112
use rustc_span::def_id::LocalDefId;
1213
use tracing::trace;
1314

@@ -72,7 +73,7 @@ fn check_transmute<'tcx>(
7273
from: Ty<'tcx>,
7374
to: Ty<'tcx>,
7475
hir_id: HirId,
75-
) {
76+
) -> Result<(), ErrorGuaranteed> {
7677
let span = tcx.hir_span(hir_id);
7778
let normalize = |ty| {
7879
if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) {
@@ -92,7 +93,7 @@ fn check_transmute<'tcx>(
9293

9394
// Transmutes that are only changing lifetimes are always ok.
9495
if from == to {
95-
return;
96+
return Ok(());
9697
}
9798

9899
let sk_from = SizeSkeleton::compute(from, tcx, typing_env, span);
@@ -104,7 +105,7 @@ fn check_transmute<'tcx>(
104105
&& let Ok(sk_to) = sk_to
105106
{
106107
if sk_from.same_size(sk_to) {
107-
return;
108+
return Ok(());
108109
}
109110

110111
// Special-case transmuting from `typeof(function)` and
@@ -119,7 +120,7 @@ fn check_transmute<'tcx>(
119120
.with_note(format!("target type: {to}"))
120121
.with_help("cast with `as` to a pointer instead")
121122
.emit();
122-
return;
123+
return Ok(());
123124
}
124125
}
125126

@@ -131,21 +132,25 @@ fn check_transmute<'tcx>(
131132
);
132133
if from == to {
133134
err.note(format!("`{from}` does not have a fixed size"));
134-
err.emit();
135+
Err(err.emit())
135136
} else {
136137
err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)));
137138
err.note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
138-
err.emit();
139+
Err(err.emit())
139140
}
140141
}
141142

142-
pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) {
143+
pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), ErrorGuaranteed> {
143144
assert!(!tcx.is_typeck_child(owner.to_def_id()));
144145
let typeck_results = tcx.typeck(owner);
145-
let None = typeck_results.tainted_by_errors else { return };
146+
if let Some(e) = typeck_results.tainted_by_errors {
147+
return Err(e);
148+
};
146149

147150
let typing_env = ty::TypingEnv::post_analysis(tcx, owner);
151+
let mut result = Ok(());
148152
for &(from, to, hir_id) in &typeck_results.transmutes_to_check {
149-
check_transmute(tcx, typing_env, from, to, hir_id);
153+
result = result.and(check_transmute(tcx, typing_env, from, to, hir_id));
150154
}
155+
result
151156
}

compiler/rustc_middle/src/queries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ rustc_queries! {
11181118
}
11191119

11201120
/// Unsafety-check this `LocalDefId`.
1121-
query check_transmutes(key: LocalDefId) {
1121+
query check_transmutes(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
11221122
desc { "check transmute calls inside `{}`", tcx.def_path_str(key) }
11231123
}
11241124

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,11 +544,15 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
544544
body.tainted_by_errors = Some(error_reported);
545545
}
546546

547+
let root = tcx.typeck_root_def_id_local(def);
548+
if let Err(e) = tcx.check_transmutes(root) {
549+
body.tainted_by_errors = Some(e);
550+
}
551+
547552
// Also taint the body if it's within a top-level item that is not well formed.
548553
//
549554
// We do this check here and not during `mir_promoted` because that may result
550555
// in borrowck cycles if WF requires looking into an opaque hidden type.
551-
let root = tcx.typeck_root_def_id_local(def);
552556
match tcx.def_kind(root) {
553557
DefKind::Fn
554558
| DefKind::AssocFn
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
//@ only-64bit
22

33
pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
4-
//~^ ERROR transmuting from 8-byte type to 16-byte type
4+
//~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types [E0512]
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]`
1+
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
22
--> $DIR/issue-79494.rs:3:33
33
|
44
LL | pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: source type: `usize` (64 bits)
8+
= note: target type: `&[u8]` (128 bits)
69

710
error: aborting due to 1 previous error
811

9-
For more information about this error, try `rustc --explain E0080`.
12+
For more information about this error, try `rustc --explain E0512`.

tests/ui/consts/transmute-size-mismatch-before-typeck.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,4 @@ fn main() {
1414
}
1515

1616
const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
17-
//~^ ERROR transmuting from
18-
//~| ERROR cannot transmute between types of different sizes
17+
//~^ ERROR cannot transmute between types of different sizes
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error[E0080]: transmuting from word size type to 2 * word size type: `usize` -> `&[u8]`
2-
--> $DIR/transmute-size-mismatch-before-typeck.rs:16:29
3-
|
4-
LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here
6-
71
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
82
--> $DIR/transmute-size-mismatch-before-typeck.rs:16:29
93
|
@@ -13,7 +7,6 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
137
= note: source type: `usize` (word size)
148
= note: target type: `&[u8]` (2 * word size)
159

16-
error: aborting due to 2 previous errors
10+
error: aborting due to 1 previous error
1711

18-
Some errors have detailed explanations: E0080, E0512.
19-
For more information about an error, try `rustc --explain E0080`.
12+
For more information about this error, try `rustc --explain E0512`.

tests/ui/layout/base-layout-is-sized-ice-123078.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ struct S {
88
}
99

1010
const C: S = unsafe { std::mem::transmute(()) };
11-
//~^ ERROR the type `S` has an unknown layout
12-
//~| ERROR cannot transmute between types of different sizes, or dependently-sized types
11+
//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
1312

1413
const _: [(); {
1514
C;

tests/ui/layout/base-layout-is-sized-ice-123078.stderr

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,6 @@ help: the `Box` type always has a statically known size and allocates its conten
1616
LL | a: Box<[u8]>,
1717
| ++++ +
1818

19-
error[E0080]: the type `S` has an unknown layout
20-
--> $DIR/base-layout-is-sized-ice-123078.rs:10:1
21-
|
22-
LL | const C: S = unsafe { std::mem::transmute(()) };
23-
| ^^^^^^^^^^ evaluation of `C` failed here
24-
2519
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
2620
--> $DIR/base-layout-is-sized-ice-123078.rs:10:23
2721
|
@@ -31,7 +25,7 @@ LL | const C: S = unsafe { std::mem::transmute(()) };
3125
= note: source type: `()` (0 bits)
3226
= note: target type: `S` (the type `S` has an unknown layout)
3327

34-
error: aborting due to 3 previous errors
28+
error: aborting due to 2 previous errors
3529

36-
Some errors have detailed explanations: E0080, E0277, E0512.
37-
For more information about an error, try `rustc --explain E0080`.
30+
Some errors have detailed explanations: E0277, E0512.
31+
For more information about an error, try `rustc --explain E0277`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@compile-flags: -Zmir-enable-passes=+DataflowConstProp --crate-type lib
2+
//@ edition:2021
3+
pub async fn a() -> u32 {
4+
unsafe { std::mem::transmute(1u64) }
5+
//~^error: cannot transmute between types of different sizes, or dependently-sized types
6+
}
7+
8+
pub async fn b() -> u32 {
9+
let closure = || unsafe { std::mem::transmute(1u64) };
10+
//~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types [E0512]
11+
closure()
12+
}

0 commit comments

Comments
 (0)