Skip to content

Commit fa6e163

Browse files
committed
Fix malformed transmute handling during MIR build
It used to just error on wrong transmutes, without any body tainting. That resulted in ICE during subsequent MIR optimizations. Fixed by tainting the body right before the MIR optimizations
1 parent e7a21fa commit fa6e163

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
@@ -541,11 +541,15 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
541541
body.tainted_by_errors = Some(error_reported);
542542
}
543543

544+
let root = tcx.typeck_root_def_id_local(def);
545+
if let Err(e) = tcx.check_transmutes(root) {
546+
body.tainted_by_errors = Some(e);
547+
}
548+
544549
// Also taint the body if it's within a top-level item that is not well formed.
545550
//
546551
// We do this check here and not during `mir_promoted` because that may result
547552
// in borrowck cycles if WF requires looking into an opaque hidden type.
548-
let root = tcx.typeck_root_def_id_local(def);
549553
match tcx.def_kind(root) {
550554
DefKind::Fn
551555
| 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)