Skip to content

Commit 0905bad

Browse files
committed
Add CastKind::Transmute to MIR
Nothing actually produces it in this commit.
1 parent c5c7d2b commit 0905bad

26 files changed

+184
-55
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2242,6 +2242,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
22422242
}
22432243
}
22442244
}
2245+
CastKind::Transmute => {
2246+
span_mirbug!(
2247+
self,
2248+
rvalue,
2249+
"Unexpected CastKind::Transmute, should only appear after lowering_intrinsics",
2250+
);
2251+
}
22452252
}
22462253
}
22472254

compiler/rustc_codegen_cranelift/src/base.rs

+4
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,10 @@ fn codegen_stmt<'tcx>(
720720
let operand = codegen_operand(fx, operand);
721721
operand.coerce_dyn_star(fx, lval);
722722
}
723+
Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
724+
let operand = codegen_operand(fx, operand);
725+
lval.write_cvalue_transmute(fx, operand);
726+
}
723727
Rvalue::Discriminant(place) => {
724728
let place = codegen_place(fx, place);
725729
let value = place.to_cvalue(fx);

compiler/rustc_codegen_ssa/src/mir/block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
17891789
}
17901790
}
17911791

1792-
fn codegen_transmute_into(
1792+
pub(crate) fn codegen_transmute_into(
17931793
&mut self,
17941794
bx: &mut Bx,
17951795
src: &mir::Operand<'tcx>,

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+10
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
135135
dest.codegen_set_discr(bx, variant_index);
136136
}
137137

138+
mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
139+
self.codegen_transmute_into(bx, operand, dest);
140+
}
141+
138142
_ => {
139143
assert!(self.rvalue_creates_operand(rvalue, DUMMY_SP));
140144
let temp = self.codegen_rvalue_operand(bx, rvalue);
@@ -344,6 +348,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
344348
};
345349
OperandValue::Immediate(newval)
346350
}
351+
mir::CastKind::Transmute => {
352+
bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand);
353+
}
347354
};
348355
OperandRef { val, layout: cast }
349356
}
@@ -684,6 +691,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
684691
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
685692
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
686693
match *rvalue {
694+
mir::Rvalue::Cast(mir::CastKind::Transmute, ..) =>
695+
// sometimes this could, but for aggregates it can't
696+
false,
687697
mir::Rvalue::Ref(..) |
688698
mir::Rvalue::CopyForDeref(..) |
689699
mir::Rvalue::AddressOf(..) |

compiler/rustc_const_eval/src/interpret/cast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
133133
bug!()
134134
}
135135
}
136+
137+
Transmute => {
138+
self.copy_op(src, dest, /*allow_transmute*/ true)?;
139+
}
136140
}
137141
Ok(())
138142
}

compiler/rustc_const_eval/src/transform/validate.rs

+19
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
619619
);
620620
}
621621
}
622+
CastKind::Transmute => {
623+
let src_layout = self.tcx.layout_of(self.param_env.and(op_ty));
624+
let dst_layout = self.tcx.layout_of(self.param_env.and(*target_type));
625+
if let Err(e) = src_layout {
626+
self.fail(
627+
location,
628+
format!("Unable to compute layout for source type {op_ty:?}: {e}"),
629+
);
630+
}
631+
if let Err(e) = dst_layout {
632+
self.fail(location, format!("Unable to compute layout for destination type {target_type:?}: {e}"));
633+
}
634+
635+
if let (Ok(src_layout), Ok(dst_layout)) = (src_layout, dst_layout) {
636+
if src_layout.layout.size() != dst_layout.layout.size() {
637+
self.fail(location, format!("Source and destination layouts have different sizes: {src_layout:?} vs {dst_layout:?}"));
638+
}
639+
}
640+
}
622641
}
623642
}
624643
Rvalue::Repeat(_, _)

compiler/rustc_middle/src/mir/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1963,7 +1963,8 @@ impl<'tcx> Rvalue<'tcx> {
19631963
| CastKind::PtrToPtr
19641964
| CastKind::Pointer(_)
19651965
| CastKind::PointerFromExposedAddress
1966-
| CastKind::DynStar,
1966+
| CastKind::DynStar
1967+
| CastKind::Transmute,
19671968
_,
19681969
_,
19691970
)

compiler/rustc_middle/src/mir/syntax.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,8 @@ pub enum CastKind {
11891189
IntToFloat,
11901190
PtrToPtr,
11911191
FnPtrToPtr,
1192+
/// Reinterpret the bits of the input as a different type.
1193+
Transmute,
11921194
}
11931195

11941196
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]

compiler/rustc_mir_transform/src/check_unsafety.rs

+6
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
132132
self.register_violations(violations, used_unsafe_blocks.iter().copied());
133133
}
134134
},
135+
Rvalue::Cast(CastKind::Transmute, ..) => {
136+
self.require_unsafe(
137+
UnsafetyViolationKind::General,
138+
UnsafetyViolationDetails::CallToUnsafeFunction,
139+
);
140+
}
135141
_ => {}
136142
}
137143
self.super_rvalue(rvalue, location);

compiler/rustc_mir_transform/src/lower_intrinsics.rs

+25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::MirPass;
44
use rustc_middle::mir::*;
5+
use rustc_middle::ty::inhabitedness::inhabited_predicate::InhabitedPredicate;
56
use rustc_middle::ty::subst::SubstsRef;
67
use rustc_middle::ty::{self, Ty, TyCtxt};
78
use rustc_span::symbol::{sym, Symbol};
@@ -162,6 +163,30 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
162163
terminator.kind = TerminatorKind::Goto { target };
163164
}
164165
}
166+
sym::transmute => {
167+
let dst_ty = destination.ty(local_decls, tcx).ty;
168+
if let Some(target) = *target {
169+
let mut args = args.drain(..);
170+
block.statements.push(Statement {
171+
source_info: terminator.source_info,
172+
kind: StatementKind::Assign(Box::new((
173+
*destination,
174+
Rvalue::Cast(CastKind::Transmute, args.next().unwrap(), dst_ty),
175+
))),
176+
});
177+
assert_eq!(args.next(), None, "Extra argument for transmute intrinsic");
178+
drop(args);
179+
terminator.kind = TerminatorKind::Goto { target };
180+
} else {
181+
debug_assert!(!matches!(
182+
dst_ty.inhabited_predicate(tcx),
183+
InhabitedPredicate::True
184+
));
185+
// `transmute::<_, !>(x)` is UB for anything inhabited,
186+
// and must be unreachable if `x` is uninhabited.
187+
terminator.kind = TerminatorKind::Unreachable;
188+
}
189+
}
165190
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
166191
validate_simd_shuffle(tcx, args, terminator.source_info.span);
167192
}

src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs

+3
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ fn check_rvalue<'tcx>(
176176
// FIXME(dyn-star)
177177
unimplemented!()
178178
},
179+
Rvalue::Cast(CastKind::Transmute, _, _) => {
180+
Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into()))
181+
},
179182
// binops are fine on integers
180183
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
181184
check_operand(tcx, lhs, span, body)?;

src/tools/miri/tests/fail/never_transmute_humans.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ struct Human;
77

88
fn main() {
99
let _x: ! = unsafe {
10-
std::mem::transmute::<Human, !>(Human) //~ ERROR: transmuting to uninhabited
10+
std::mem::transmute::<Human, !>(Human) //~ ERROR: entering unreachable code
1111
};
1212
}

src/tools/miri/tests/fail/never_transmute_humans.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: transmuting to uninhabited type
1+
error: Undefined Behavior: entering unreachable code
22
--> $DIR/never_transmute_humans.rs:LL:CC
33
|
44
LL | std::mem::transmute::<Human, !>(Human)
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff

+18-30
Original file line numberDiff line numberDiff line change
@@ -24,61 +24,49 @@
2424
StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15
2525
StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
2626
_3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
27-
_2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
28-
// mir::Constant
29-
// + span: $DIR/issue_75439.rs:8:37: 8:46
30-
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
27+
_2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
28+
StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
29+
switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
3130
}
3231

3332
bb1: {
34-
StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
35-
switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
33+
switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
3634
}
3735

3836
bb2: {
39-
switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
37+
switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
4038
}
4139

4240
bb3: {
43-
switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
44-
}
45-
46-
bb4: {
4741
StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38
4842
StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
4943
_6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
50-
_5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
51-
// mir::Constant
52-
// + span: $DIR/issue_75439.rs:11:23: 11:32
53-
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
44+
_5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
45+
StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
46+
_0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
47+
StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
48+
StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
49+
goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
5450
}
5551

56-
bb5: {
52+
bb4: {
5753
StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
5854
_4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
59-
goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
55+
goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
6056
}
6157

62-
bb6: {
58+
bb5: {
6359
StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
6460
_4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
65-
goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
61+
goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
6662
}
6763

68-
bb7: {
69-
StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
70-
_0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
71-
StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
72-
StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
73-
goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
74-
}
75-
76-
bb8: {
64+
bb6: {
7765
_0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
78-
goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
66+
goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
7967
}
8068

81-
bb9: {
69+
bb7: {
8270
StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2
8371
return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2
8472
}

tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
1212
- _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
1313
- // mir::Constant
14-
- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
14+
- // + span: $DIR/lower_intrinsics.rs:84:9: 84:32
1515
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
1616
+ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
1717
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38

tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff

+7-7
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
_3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
3232
- _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
3333
- // mir::Constant
34-
- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
34+
- // + span: $DIR/lower_intrinsics.rs:61:5: 61:41
3535
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
3636
+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
3737
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
@@ -46,13 +46,13 @@
4646
StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
4747
_19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
4848
// mir::Constant
49-
// + span: $DIR/lower_intrinsics.rs:50:42: 50:44
49+
// + span: $DIR/lower_intrinsics.rs:62:42: 62:44
5050
// + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
5151
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
5252
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
5353
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
5454
- // mir::Constant
55-
- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
55+
- // + span: $DIR/lower_intrinsics.rs:62:5: 62:41
5656
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
5757
+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
5858
+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
@@ -67,13 +67,13 @@
6767
StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
6868
_18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
6969
// mir::Constant
70-
// + span: $DIR/lower_intrinsics.rs:51:42: 51:45
70+
// + span: $DIR/lower_intrinsics.rs:63:42: 63:45
7171
// + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
7272
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
7373
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
7474
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
7575
- // mir::Constant
76-
- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
76+
- // + span: $DIR/lower_intrinsics.rs:63:5: 63:41
7777
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
7878
+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
7979
+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
@@ -88,13 +88,13 @@
8888
StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
8989
_17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
9090
// mir::Constant
91-
// + span: $DIR/lower_intrinsics.rs:52:42: 52:47
91+
// + span: $DIR/lower_intrinsics.rs:64:42: 64:47
9292
// + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
9393
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
9494
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
9595
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
9696
- // mir::Constant
97-
- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
97+
- // + span: $DIR/lower_intrinsics.rs:64:5: 64:41
9898
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
9999
+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
100100
+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48

0 commit comments

Comments
 (0)