From fafccdced349d655db83e0ec30e91b85dcf65cf7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jun 2022 09:05:37 -0400 Subject: [PATCH 1/2] add cast kind of from_exposed_addr (int-to-ptr casts) --- compiler/rustc_borrowck/src/type_check/mod.rs | 50 ++++++++++++++----- compiler/rustc_codegen_cranelift/src/base.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 3 +- .../rustc_const_eval/src/interpret/cast.rs | 34 +++++++++---- .../src/transform/check_consts/check.rs | 18 +++---- .../src/transform/promote_consts.rs | 3 +- compiler/rustc_middle/src/mir/mod.rs | 8 ++- .../src/build/expr/as_rvalue.rs | 3 ++ .../reify_fn_ptr.main.ConstProp.diff | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 7 ++- 10 files changed, 93 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index abf77acb8c7ad..e5aed1b60ddc1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2154,31 +2154,55 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match (cast_ty_from, cast_ty_to) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (), _ => { - span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty) + span_mirbug!( + self, + rvalue, + "Invalid PointerExposeAddress cast {:?} -> {:?}", + ty_from, + ty + ) } } } - CastKind::Misc => { + CastKind::PointerFromExposedAddress => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { - (None, _) - | (_, None | Some(CastTy::FnPtr)) - | (Some(CastTy::Float), Some(CastTy::Ptr(_))) - | ( - Some(CastTy::Ptr(_) | CastTy::FnPtr), - Some(CastTy::Float | CastTy::Int(_)), - ) => { - span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,) + (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid PointerFromExposedAddress cast {:?} -> {:?}", + ty_from, + ty + ) } + } + } + + CastKind::Misc => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + // Misc casts are either between floats and ints, or one ptr type to another. + match (cast_ty_from, cast_ty_to) { ( - Some(CastTy::Int(_)), - Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)), + Some(CastTy::Int(_) | CastTy::Float), + Some(CastTy::Int(_) | CastTy::Float), ) - | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float)) | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid Misc cast {:?} -> {:?}", + ty_from, + ty, + ) + } } } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 58bec183c94aa..07136e1b76a9f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -608,7 +608,9 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } Rvalue::Cast( - CastKind::Misc | CastKind::PointerExposeAddress, + CastKind::Misc + | CastKind::PointerExposeAddress + | CastKind::PointerFromExposedAddress, ref operand, to_ty, ) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6ff8d4aa44216..90afb7adcb2b5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -269,7 +269,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::CastKind::Pointer( PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, ) - | mir::CastKind::Misc => { + | mir::CastKind::Misc + | mir::CastKind::PointerFromExposedAddress => { assert!(bx.cx().is_backend_immediate(cast)); let ll_t_out = bx.cx().immediate_backend_type(cast); if operand.layout.abi.is_uninhabited() { diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 520ae409e6b9f..73cc59ad1e674 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -37,6 +37,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(res, dest)?; } + PointerFromExposedAddress => { + let src = self.read_immediate(src)?; + let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + Misc => { let src = self.read_immediate(src)?; let res = self.misc_cast(&src, cast_ty)?; @@ -201,6 +207,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } + pub fn pointer_from_exposed_address_cast( + &mut self, + src: &ImmTy<'tcx, M::PointerTag>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate> { + assert!(src.layout.ty.is_integral()); + assert_matches!(cast_ty.kind(), ty::RawPtr(_)); + + // First cast to usize. + let scalar = src.to_scalar()?; + let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?; + let addr = addr.to_machine_usize(self)?; + + // Then turn address into pointer. + let ptr = M::ptr_from_addr_cast(&self, addr); + Ok(Scalar::from_maybe_pointer(ptr, self).into()) + } + pub fn cast_from_int_like( &self, scalar: Scalar, // input value (there is no ScalarTy so we separate data+layout) @@ -225,16 +249,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::from_uint(v, size) } - RawPtr(_) => { - assert!(src_layout.ty.is_integral()); - - let size = self.pointer_size(); - let addr = u64::try_from(size.truncate(v)).unwrap(); - - let ptr = M::ptr_from_addr_cast(&self, addr); - Scalar::from_maybe_pointer(ptr, self) - } - Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value), Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value), Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value), diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index c07680515f4e7..4b98e19376dda 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -519,32 +519,30 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Cast( - CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), - _, - _, - ) => {} - Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer + PointerCast::MutToConstPointer + | PointerCast::ArrayToPointer + | PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, ), _, _, ) => { - // Nothing to do here. Function pointer casts are allowed now. + // These are all okay; they only change the type, not the data. } Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => { - // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur - // in the type of any local, which also excludes casts). + // Unsizing is implemented for CTFE. } Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { self.check_op(ops::RawPtrToIntCast); } + Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => { + // Since no pointer can ever get exposed (rejected above), this is easy to support. + } Rvalue::Cast(CastKind::Misc, _, _) => {} diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index cf5d7b6c70a30..4879e8de10000 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -504,7 +504,8 @@ impl<'tcx> Validator<'_, 'tcx> { // ptr-to-int casts are not possible in consts and thus not promotable Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable), - // int-to-ptr casts are fine, they just use the integer value at pointer type. + // all ohter casts including int-to-ptr casts are fine, they just use the integer value + // at pointer type. Rvalue::Cast(_, operand, _) => { self.validate_operand(operand)?; } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d9cdca8bcb5d7..f3db359ec3348 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2613,12 +2613,18 @@ impl<'tcx> Rvalue<'tcx> { #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum CastKind { - Misc, /// An exposing pointer to address cast. A cast between a pointer and an integer type, or /// between a function pointer and an integer type. /// See the docs on `expose_addr` for more details. PointerExposeAddress, + /// An address-to-pointer cast that picks up an exposed provenance. + /// See the docs on `from_exposed_addr` for more details. + PointerFromExposedAddress, + /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are + /// translated into `&raw mut/const *r`, i.e., they are not actually casts. Pointer(PointerCast), + /// Remaining unclassified casts. + Misc, } #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 7d08b20631e47..8e87ecd27d285 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -196,6 +196,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress } + (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => { + CastKind::PointerFromExposedAddress + } (_, _) => CastKind::Misc, }; let source = unpack!( diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 04724b13ca64c..037febdf3a579 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -19,7 +19,7 @@ // + literal: Const { ty: fn() {main}, val: Value(Scalar()) } _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26 - _1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 + _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41 StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:4:41: 4:42 nop; // scope 0 at $DIR/reify_fn_ptr.rs:3:11: 5:2 diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index b1c82ac76e8eb..58abef38ea8be 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -131,7 +131,12 @@ fn check_rvalue<'tcx>( Rvalue::Cast(CastKind::Misc, operand, _) => { check_operand(tcx, operand, span, body) }, - Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => { + Rvalue::Cast( + CastKind::PointerFromExposedAddress + | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + operand, + _ + ) => { check_operand(tcx, operand, span, body) }, Rvalue::Cast( From d5a590f53744add6e37eee19f4591f2be6d990f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jun 2022 11:10:34 -0400 Subject: [PATCH 2/2] comment Co-authored-by: Oli Scherer --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 3 +++ compiler/rustc_const_eval/src/transform/promote_consts.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 90afb7adcb2b5..81c1897694ce6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -270,6 +270,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, ) | mir::CastKind::Misc + // Since int2ptr can have arbitrary integer types as input (so we have to do + // sign extension and all that), it is currently best handled in the same code + // path as the other integer-to-X casts. | mir::CastKind::PointerFromExposedAddress => { assert!(bx.cx().is_backend_immediate(cast)); let ll_t_out = bx.cx().immediate_backend_type(cast); diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 4879e8de10000..d1e776854b231 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -504,7 +504,7 @@ impl<'tcx> Validator<'_, 'tcx> { // ptr-to-int casts are not possible in consts and thus not promotable Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable), - // all ohter casts including int-to-ptr casts are fine, they just use the integer value + // all other casts including int-to-ptr casts are fine, they just use the integer value // at pointer type. Rvalue::Cast(_, operand, _) => { self.validate_operand(operand)?;