Skip to content

Commit c7dd5bc

Browse files
authored
Rollup merge of #97582 - tmiasko:pointer-address-cast, r=oli-obk
Add a pointer to address cast kind A pointer to address cast are often special-cased. Introduce a dedicated cast kind to make them easy distinguishable.
2 parents a3d8b07 + dff602f commit c7dd5bc

File tree

15 files changed

+96
-94
lines changed

15 files changed

+96
-94
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -2147,6 +2147,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21472147
}
21482148
}
21492149

2150+
CastKind::PointerAddress => {
2151+
let ty_from = op.ty(body, tcx);
2152+
let cast_ty_from = CastTy::from_ty(ty_from);
2153+
let cast_ty_to = CastTy::from_ty(*ty);
2154+
match (cast_ty_from, cast_ty_to) {
2155+
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (),
2156+
_ => {
2157+
span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty)
2158+
}
2159+
}
2160+
}
2161+
21502162
CastKind::Misc => {
21512163
let ty_from = op.ty(body, tcx);
21522164
let cast_ty_from = CastTy::from_ty(ty_from);
@@ -2155,16 +2167,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21552167
(None, _)
21562168
| (_, None | Some(CastTy::FnPtr))
21572169
| (Some(CastTy::Float), Some(CastTy::Ptr(_)))
2158-
| (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => {
2170+
| (
2171+
Some(CastTy::Ptr(_) | CastTy::FnPtr),
2172+
Some(CastTy::Float | CastTy::Int(_)),
2173+
) => {
21592174
span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,)
21602175
}
21612176
(
21622177
Some(CastTy::Int(_)),
21632178
Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)),
21642179
)
21652180
| (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float))
2166-
| (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_)))
2167-
| (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (),
2181+
| (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
21682182
}
21692183
}
21702184
}

compiler/rustc_codegen_cranelift/src/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ fn codegen_stmt<'tcx>(
607607
let operand = codegen_operand(fx, operand);
608608
lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
609609
}
610-
Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
610+
Rvalue::Cast(CastKind::Misc | CastKind::PointerAddress, ref operand, to_ty) => {
611611
let operand = codegen_operand(fx, operand);
612612
let from_ty = operand.layout().ty;
613613
let to_ty = fx.monomorphize(to_ty);

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
181181
let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
182182

183183
let val = match *kind {
184+
mir::CastKind::PointerAddress => {
185+
assert!(bx.cx().is_backend_immediate(cast));
186+
let llptr = operand.immediate();
187+
let llcast_ty = bx.cx().immediate_backend_type(cast);
188+
let lladdr = bx.ptrtoint(llptr, llcast_ty);
189+
OperandValue::Immediate(lladdr)
190+
}
184191
mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
185192
match *operand.layout.ty.kind() {
186193
ty::FnDef(def_id, substs) => {
@@ -362,9 +369,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
362369
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
363370
bx.pointercast(llval, ll_t_out)
364371
}
365-
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
366-
bx.ptrtoint(llval, ll_t_out)
367-
}
368372
(CastTy::Int(_), CastTy::Ptr(_)) => {
369373
let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
370374
bx.inttoptr(usize_llval, ll_t_out)

compiler/rustc_const_eval/src/interpret/cast.rs

+22-15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::assert_matches::assert_matches;
12
use std::convert::TryFrom;
23

34
use rustc_apfloat::ieee::{Double, Single};
@@ -30,6 +31,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3031
self.unsize_into(src, cast_ty, dest)?;
3132
}
3233

34+
PointerAddress => {
35+
let src = self.read_immediate(src)?;
36+
let res = self.pointer_address_cast(&src, cast_ty)?;
37+
self.write_immediate(res, dest)?;
38+
}
39+
3340
Misc => {
3441
let src = self.read_immediate(src)?;
3542
let res = self.misc_cast(&src, cast_ty)?;
@@ -174,23 +181,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
174181

175182
// # The remaining source values are scalar and "int-like".
176183
let scalar = src.to_scalar()?;
184+
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
185+
}
177186

178-
// If we are casting from a pointer to something
179-
// that is not a pointer, mark the pointer as exposed
180-
if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() {
181-
let ptr = self.scalar_to_ptr(scalar)?;
182-
183-
match ptr.into_pointer_or_addr() {
184-
Ok(ptr) => {
185-
M::expose_ptr(self, ptr)?;
186-
}
187-
Err(_) => {
188-
// do nothing, exposing an invalid pointer
189-
// has no meaning
190-
}
191-
};
192-
}
187+
pub fn pointer_address_cast(
188+
&mut self,
189+
src: &ImmTy<'tcx, M::PointerTag>,
190+
cast_ty: Ty<'tcx>,
191+
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
192+
assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
193+
assert!(cast_ty.is_integral());
193194

195+
let scalar = src.to_scalar()?;
196+
let ptr = self.scalar_to_ptr(scalar)?;
197+
match ptr.into_pointer_or_addr() {
198+
Ok(ptr) => M::expose_ptr(self, ptr)?,
199+
Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
200+
};
194201
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
195202
}
196203

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc_infer::infer::TyCtxtInferExt;
88
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
99
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
1010
use rustc_middle::mir::*;
11-
use rustc_middle::ty::cast::CastTy;
1211
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
1312
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
1413
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
@@ -543,16 +542,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
543542
// in the type of any local, which also excludes casts).
544543
}
545544

546-
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
547-
let operand_ty = operand.ty(self.body, self.tcx);
548-
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
549-
let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
550-
551-
if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
552-
self.check_op(ops::RawPtrToIntCast);
553-
}
545+
Rvalue::Cast(CastKind::PointerAddress, _, _) => {
546+
self.check_op(ops::RawPtrToIntCast);
554547
}
555548

549+
Rvalue::Cast(CastKind::Misc, _, _) => {}
550+
556551
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
557552
Rvalue::ShallowInitBox(_, _) => {}
558553

compiler/rustc_const_eval/src/transform/promote_consts.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use rustc_hir as hir;
1616
use rustc_middle::mir::traversal::ReversePostorderIter;
1717
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
1818
use rustc_middle::mir::*;
19-
use rustc_middle::ty::cast::CastTy;
2019
use rustc_middle::ty::subst::InternalSubsts;
2120
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
2221
use rustc_span::Span;
@@ -502,18 +501,11 @@ impl<'tcx> Validator<'_, 'tcx> {
502501

503502
Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
504503

505-
Rvalue::Cast(kind, operand, cast_ty) => {
506-
if matches!(kind, CastKind::Misc) {
507-
let operand_ty = operand.ty(self.body, self.tcx);
508-
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
509-
let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
510-
if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
511-
// ptr-to-int casts are not possible in consts and thus not promotable
512-
return Err(Unpromotable);
513-
}
514-
// int-to-ptr casts are fine, they just use the integer value at pointer type.
515-
}
504+
// ptr-to-int casts are not possible in consts and thus not promotable
505+
Rvalue::Cast(CastKind::PointerAddress, _, _) => return Err(Unpromotable),
516506

507+
// int-to-ptr casts are fine, they just use the integer value at pointer type.
508+
Rvalue::Cast(_, operand, _) => {
517509
self.validate_operand(operand)?;
518510
}
519511

compiler/rustc_middle/src/mir/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -2604,9 +2604,19 @@ pub enum Rvalue<'tcx> {
26042604
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
26052605
static_assert_size!(Rvalue<'_>, 40);
26062606

2607+
impl<'tcx> Rvalue<'tcx> {
2608+
#[inline]
2609+
pub fn is_pointer_int_cast(&self) -> bool {
2610+
matches!(self, Rvalue::Cast(CastKind::PointerAddress, _, _))
2611+
}
2612+
}
2613+
26072614
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
26082615
pub enum CastKind {
26092616
Misc,
2617+
/// A pointer to address cast. A cast between a pointer and an integer type,
2618+
/// or between a function pointer and an integer type.
2619+
PointerAddress,
26102620
Pointer(PointerCast),
26112621
}
26122622

compiler/rustc_middle/src/mir/tcx.rs

-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
use crate::mir::*;
7-
use crate::ty::cast::CastTy;
87
use crate::ty::subst::Subst;
98
use crate::ty::{self, Ty, TyCtxt};
109
use rustc_hir as hir;
@@ -224,22 +223,6 @@ impl<'tcx> Rvalue<'tcx> {
224223
_ => RvalueInitializationState::Deep,
225224
}
226225
}
227-
228-
pub fn is_pointer_int_cast<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> bool
229-
where
230-
D: HasLocalDecls<'tcx>,
231-
{
232-
if let Rvalue::Cast(CastKind::Misc, src_op, dest_ty) = self {
233-
if let Some(CastTy::Int(_)) = CastTy::from_ty(*dest_ty) {
234-
let src_ty = src_op.ty(local_decls, tcx);
235-
if let Some(CastTy::FnPtr | CastTy::Ptr(_)) = CastTy::from_ty(src_ty) {
236-
return true;
237-
}
238-
}
239-
}
240-
241-
false
242-
}
243226
}
244227

245228
impl<'tcx> Operand<'tcx> {

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_middle::mir::AssertKind;
1111
use rustc_middle::mir::Place;
1212
use rustc_middle::mir::*;
1313
use rustc_middle::thir::*;
14+
use rustc_middle::ty::cast::CastTy;
1415
use rustc_middle::ty::{self, Ty, UpvarSubsts};
1516
use rustc_span::Span;
1617

@@ -188,11 +189,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
188189
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
189190
}
190191
ExprKind::Cast { source } => {
192+
let source = &this.thir[source];
193+
let from_ty = CastTy::from_ty(source.ty);
194+
let cast_ty = CastTy::from_ty(expr.ty);
195+
let cast_kind = match (from_ty, cast_ty) {
196+
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
197+
CastKind::PointerAddress
198+
}
199+
(_, _) => CastKind::Misc,
200+
};
191201
let source = unpack!(
192-
block =
193-
this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
202+
block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
194203
);
195-
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
204+
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
196205
}
197206
ExprKind::Pointer { cast, source } => {
198207
let source = unpack!(

compiler/rustc_mir_dataflow/src/impls/liveness.rs

+8-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
22
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
3-
use rustc_middle::mir::{self, Local, LocalDecls, Location, Place, StatementKind};
4-
use rustc_middle::ty::TyCtxt;
3+
use rustc_middle::mir::{self, Local, Location, Place, StatementKind};
54

65
use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
76

@@ -193,27 +192,21 @@ impl DefUse {
193192
/// This is basically written for dead store elimination and nothing else.
194193
///
195194
/// All of the caveats of `MaybeLiveLocals` apply.
196-
pub struct MaybeTransitiveLiveLocals<'a, 'tcx> {
195+
pub struct MaybeTransitiveLiveLocals<'a> {
197196
always_live: &'a BitSet<Local>,
198-
local_decls: &'a LocalDecls<'tcx>,
199-
tcx: TyCtxt<'tcx>,
200197
}
201198

202-
impl<'a, 'tcx> MaybeTransitiveLiveLocals<'a, 'tcx> {
199+
impl<'a> MaybeTransitiveLiveLocals<'a> {
203200
/// The `always_alive` set is the set of locals to which all stores should unconditionally be
204201
/// considered live.
205202
///
206203
/// This should include at least all locals that are ever borrowed.
207-
pub fn new(
208-
always_live: &'a BitSet<Local>,
209-
local_decls: &'a LocalDecls<'tcx>,
210-
tcx: TyCtxt<'tcx>,
211-
) -> Self {
212-
MaybeTransitiveLiveLocals { always_live, local_decls, tcx }
204+
pub fn new(always_live: &'a BitSet<Local>) -> Self {
205+
MaybeTransitiveLiveLocals { always_live }
213206
}
214207
}
215208

216-
impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
209+
impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
217210
type Domain = ChunkedBitSet<Local>;
218211
type Direction = Backward;
219212

@@ -241,7 +234,7 @@ impl<'a> GenKill<Local> for TransferWrapper<'a> {
241234
}
242235
}
243236

244-
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
237+
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
245238
fn apply_statement_effect(
246239
&self,
247240
trans: &mut Self::Domain,
@@ -251,7 +244,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
251244
// Compute the place that we are storing to, if any
252245
let destination = match &statement.kind {
253246
StatementKind::Assign(assign) => {
254-
if assign.1.is_pointer_int_cast(self.local_decls, self.tcx) {
247+
if assign.1.is_pointer_int_cast() {
255248
// Pointer to int casts may be side-effects due to exposing the provenance.
256249
// While the model is undecided, we should be conservative. See
257250
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>

compiler/rustc_mir_transform/src/dead_store_elimination.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_mir_dataflow::{impls::MaybeTransitiveLiveLocals, Analysis};
2424
/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
2525
/// can be generated via the [`get_borrowed_locals`] function.
2626
pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
27-
let mut live = MaybeTransitiveLiveLocals::new(borrowed, &body.local_decls, tcx)
27+
let mut live = MaybeTransitiveLiveLocals::new(borrowed)
2828
.into_engine(tcx, body)
2929
.iterate_to_fixpoint()
3030
.into_results_cursor(body);
@@ -34,7 +34,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
3434
for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
3535
let loc = Location { block: bb, statement_index };
3636
if let StatementKind::Assign(assign) = &statement.kind {
37-
if assign.1.is_pointer_int_cast(&body.local_decls, tcx) {
37+
if assign.1.is_pointer_int_cast() {
3838
continue;
3939
}
4040
}

src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
2222
// + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
2323
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
24-
_1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
24+
_1 = move _2 as usize (PointerAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
2525
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
2626
StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40
2727
StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12

src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// mir::Constant
1818
// + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
1919
// + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
20-
_2 = move _3 as usize (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
20+
_2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
2121
StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26
2222
_1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
2323
StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41

src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11
2020
StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
2121
_3 = _1; // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
22-
_2 = move _3 as usize (Misc); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
22+
_2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
2323
StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24
2424
StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11
2525
StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
2626
_5 = _1; // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
27-
_4 = move _5 as isize (Misc); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
27+
_4 = move _5 as isize (PointerAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
2828
StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24
2929
_0 = const (); // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2
3030
StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2

0 commit comments

Comments
 (0)