Skip to content

Commit

Permalink
Add CastKind::Transmute to MIR
Browse files Browse the repository at this point in the history
Nothing actually produces it in this commit.
  • Loading branch information
scottmcm committed Feb 25, 2023
1 parent c5c7d2b commit 0905bad
Show file tree
Hide file tree
Showing 26 changed files with 184 additions and 55 deletions.
7 changes: 7 additions & 0 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2242,6 +2242,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
CastKind::Transmute => {
span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute, should only appear after lowering_intrinsics",
);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,10 @@ fn codegen_stmt<'tcx>(
let operand = codegen_operand(fx, operand);
operand.coerce_dyn_star(fx, lval);
}
Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
let operand = codegen_operand(fx, operand);
lval.write_cvalue_transmute(fx, operand);
}
Rvalue::Discriminant(place) => {
let place = codegen_place(fx, place);
let value = place.to_cvalue(fx);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1789,7 +1789,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}

fn codegen_transmute_into(
pub(crate) fn codegen_transmute_into(
&mut self,
bx: &mut Bx,
src: &mir::Operand<'tcx>,
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
dest.codegen_set_discr(bx, variant_index);
}

mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
self.codegen_transmute_into(bx, operand, dest);
}

_ => {
assert!(self.rvalue_creates_operand(rvalue, DUMMY_SP));
let temp = self.codegen_rvalue_operand(bx, rvalue);
Expand Down Expand Up @@ -344,6 +348,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};
OperandValue::Immediate(newval)
}
mir::CastKind::Transmute => {
bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand);
}
};
OperandRef { val, layout: cast }
}
Expand Down Expand Up @@ -684,6 +691,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
match *rvalue {
mir::Rvalue::Cast(mir::CastKind::Transmute, ..) =>
// sometimes this could, but for aggregates it can't
false,
mir::Rvalue::Ref(..) |
mir::Rvalue::CopyForDeref(..) |
mir::Rvalue::AddressOf(..) |
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
bug!()
}
}

Transmute => {
self.copy_op(src, dest, /*allow_transmute*/ true)?;
}
}
Ok(())
}
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
CastKind::Transmute => {
let src_layout = self.tcx.layout_of(self.param_env.and(op_ty));
let dst_layout = self.tcx.layout_of(self.param_env.and(*target_type));
if let Err(e) = src_layout {
self.fail(
location,
format!("Unable to compute layout for source type {op_ty:?}: {e}"),
);
}
if let Err(e) = dst_layout {
self.fail(location, format!("Unable to compute layout for destination type {target_type:?}: {e}"));
}

if let (Ok(src_layout), Ok(dst_layout)) = (src_layout, dst_layout) {
if src_layout.layout.size() != dst_layout.layout.size() {
self.fail(location, format!("Source and destination layouts have different sizes: {src_layout:?} vs {dst_layout:?}"));
}
}
}
}
}
Rvalue::Repeat(_, _)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1963,7 +1963,8 @@ impl<'tcx> Rvalue<'tcx> {
| CastKind::PtrToPtr
| CastKind::Pointer(_)
| CastKind::PointerFromExposedAddress
| CastKind::DynStar,
| CastKind::DynStar
| CastKind::Transmute,
_,
_,
)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,8 @@ pub enum CastKind {
IntToFloat,
PtrToPtr,
FnPtrToPtr,
/// Reinterpret the bits of the input as a different type.
Transmute,
}

#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_mir_transform/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
self.register_violations(violations, used_unsafe_blocks.iter().copied());
}
},
Rvalue::Cast(CastKind::Transmute, ..) => {
self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::CallToUnsafeFunction,
);
}
_ => {}
}
self.super_rvalue(rvalue, location);
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_mir_transform/src/lower_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::MirPass;
use rustc_middle::mir::*;
use rustc_middle::ty::inhabitedness::inhabited_predicate::InhabitedPredicate;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
Expand Down Expand Up @@ -162,6 +163,30 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
terminator.kind = TerminatorKind::Goto { target };
}
}
sym::transmute => {
let dst_ty = destination.ty(local_decls, tcx).ty;
if let Some(target) = *target {
let mut args = args.drain(..);
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::Cast(CastKind::Transmute, args.next().unwrap(), dst_ty),
))),
});
assert_eq!(args.next(), None, "Extra argument for transmute intrinsic");
drop(args);
terminator.kind = TerminatorKind::Goto { target };
} else {
debug_assert!(!matches!(
dst_ty.inhabited_predicate(tcx),
InhabitedPredicate::True
));
// `transmute::<_, !>(x)` is UB for anything inhabited,
// and must be unreachable if `x` is uninhabited.
terminator.kind = TerminatorKind::Unreachable;
}
}
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
validate_simd_shuffle(tcx, args, terminator.source_info.span);
}
Expand Down
3 changes: 3 additions & 0 deletions src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ fn check_rvalue<'tcx>(
// FIXME(dyn-star)
unimplemented!()
},
Rvalue::Cast(CastKind::Transmute, _, _) => {
Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into()))
},
// binops are fine on integers
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
check_operand(tcx, lhs, span, body)?;
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/fail/never_transmute_humans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ struct Human;

fn main() {
let _x: ! = unsafe {
std::mem::transmute::<Human, !>(Human) //~ ERROR: transmuting to uninhabited
std::mem::transmute::<Human, !>(Human) //~ ERROR: entering unreachable code
};
}
4 changes: 2 additions & 2 deletions src/tools/miri/tests/fail/never_transmute_humans.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: Undefined Behavior: transmuting to uninhabited type
error: Undefined Behavior: entering unreachable code
--> $DIR/never_transmute_humans.rs:LL:CC
|
LL | std::mem::transmute::<Human, !>(Human)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Expand Down
48 changes: 18 additions & 30 deletions tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
Original file line number Diff line number Diff line change
Expand Up @@ -24,61 +24,49 @@
StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15
StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
_3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
_2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
// mir::Constant
// + span: $DIR/issue_75439.rs:8:37: 8:46
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
_2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}

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

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

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

bb4: {
StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38
StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
_6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
_5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
// mir::Constant
// + span: $DIR/issue_75439.rs:11:23: 11:32
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
_5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
_0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}

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

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

bb7: {
StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
_0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}

bb8: {
bb6: {
_0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}

bb9: {
bb7: {
StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2
return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2
}
Expand Down
2 changes: 1 addition & 1 deletion tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
- _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
- // + span: $DIR/lower_intrinsics.rs:84:9: 84:32
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
+ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
Expand Down
14 changes: 7 additions & 7 deletions tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
_3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
- _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
- // + span: $DIR/lower_intrinsics.rs:61:5: 61:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
Expand All @@ -46,13 +46,13 @@
StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:50:42: 50:44
// + span: $DIR/lower_intrinsics.rs:62:42: 62:44
// + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
- // + span: $DIR/lower_intrinsics.rs:62:5: 62:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
Expand All @@ -67,13 +67,13 @@
StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:51:42: 51:45
// + span: $DIR/lower_intrinsics.rs:63:42: 63:45
// + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
- // + span: $DIR/lower_intrinsics.rs:63:5: 63:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
Expand All @@ -88,13 +88,13 @@
StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:52:42: 52:47
// + span: $DIR/lower_intrinsics.rs:64:42: 64:47
// + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
- // + span: $DIR/lower_intrinsics.rs:64:5: 64:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
Expand Down
Loading

0 comments on commit 0905bad

Please sign in to comment.