Skip to content

Commit

Permalink
Rollup merge of #64588 - matthewjasper:mir-address-of, r=oli-obk
Browse files Browse the repository at this point in the history
Add a raw "address of" operator

* Parse and feature gate `&raw [const | mut] expr` (feature gate name is `raw_address_of`)
* Add `mir::Rvalue::AddressOf`
* Use the new `Rvalue` for:
    * the new syntax
    * reference to pointer casts
    * drop shims for slices and arrays
* Stop using `mir::Rvalue::Cast` with a reference as the operand
* Correctly evaluate `mir::Rvalue::{Ref, AddressOf}` in constant propagation

cc @Centril @RalfJung @oli-obk @eddyb
cc #64490
  • Loading branch information
Centril committed Dec 20, 2019
2 parents 6b561b4 + a749116 commit ef01330
Show file tree
Hide file tree
Showing 69 changed files with 1,159 additions and 516 deletions.
18 changes: 18 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2060,6 +2060,11 @@ pub enum Rvalue<'tcx> {
/// &x or &mut x
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),

/// Create a raw pointer to the given place
/// Can be generated by raw address of expressions (`&raw const x`),
/// or when casting a reference to a raw pointer.
AddressOf(Mutability, Place<'tcx>),

/// length of a [X] or [X;n] value
Len(Place<'tcx>),

Expand Down Expand Up @@ -2214,6 +2219,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
write!(fmt, "&{}{}{:?}", region, kind_str, place)
}

AddressOf(mutability, ref place) => {
let kind_str = match mutability {
Mutability::Mut => "mut",
Mutability::Not => "const",
};

write!(fmt, "&raw {} {:?}", kind_str, place)
}

Aggregate(ref kind, ref places) => {
fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
let mut tuple_fmt = fmt.debug_tuple("");
Expand Down Expand Up @@ -3085,6 +3099,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
Ref(region, bk, ref place) => {
Ref(region.fold_with(folder), bk, place.fold_with(folder))
}
AddressOf(mutability, ref place) => {
AddressOf(mutability, place.fold_with(folder))
}
Len(ref place) => Len(place.fold_with(folder)),
Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
BinaryOp(op, ref rhs, ref lhs) => {
Expand Down Expand Up @@ -3125,6 +3142,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
Use(ref op) => op.visit_with(visitor),
Repeat(ref op, _) => op.visit_with(visitor),
Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
AddressOf(_, ref place) => place.visit_with(visitor),
Len(ref place) => place.visit_with(visitor),
Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ impl<'tcx> Rvalue<'tcx> {
}
)
}
Rvalue::AddressOf(mutability, ref place) => {
let place_ty = place.ty(local_decls, tcx).ty;
tcx.mk_ptr(ty::TypeAndMut {
ty: place_ty,
mutbl: mutability.into(),
})
}
Rvalue::Len(..) => tcx.types.usize,
Rvalue::Cast(.., ty) => ty,
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
Expand Down
16 changes: 16 additions & 0 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,18 @@ macro_rules! make_mir_visitor {
self.visit_place(path, ctx, location);
}

Rvalue::AddressOf(m, path) => {
let ctx = match m {
Mutability::Mut => PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
),
Mutability::Not => PlaceContext::NonMutatingUse(
NonMutatingUseContext::AddressOf
),
};
self.visit_place(path, ctx, location);
}

Rvalue::Len(path) => {
self.visit_place(
path,
Expand Down Expand Up @@ -1031,6 +1043,8 @@ pub enum NonMutatingUseContext {
ShallowBorrow,
/// Unique borrow.
UniqueBorrow,
/// AddressOf for *const pointer.
AddressOf,
/// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
/// For example, the projection `x.y` is not marked as a mutation in these cases:
///
Expand All @@ -1054,6 +1068,8 @@ pub enum MutatingUseContext {
Drop,
/// Mutable borrow.
Borrow,
/// AddressOf for *mut pointer.
AddressOf,
/// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
/// For example, the projection `x.y` is marked as a mutation in these cases:
///
Expand Down
3 changes: 0 additions & 3 deletions src/librustc/ty/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ pub enum CastTy<'tcx> {
FnPtr,
/// Raw pointers
Ptr(ty::TypeAndMut<'tcx>),
/// References
RPtr(ty::TypeAndMut<'tcx>),
}

/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
Expand Down Expand Up @@ -63,7 +61,6 @@ impl<'tcx> CastTy<'tcx> {
ty::Adt(d,_) if d.is_enum() && d.is_payloadfree() =>
Some(CastTy::Int(IntTy::CEnum)),
ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
ty::Ref(_, ty, mutbl) => Some(CastTy::RPtr(ty::TypeAndMut { ty, mutbl })),
ty::FnPtr(..) => Some(CastTy::FnPtr),
_ => None,
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_codegen_ssa/mir/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
PlaceContext::MutatingUse(MutatingUseContext::Store) |
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
PlaceContext::MutatingUse(MutatingUseContext::Projection) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
self.not_ssa(local);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_ssa/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let cx = self.cx;
let tcx = self.cx.tcx();

let result = match &place_ref {
let result = match place_ref {
mir::PlaceRef {
base: mir::PlaceBase::Local(index),
projection: [],
Expand Down
58 changes: 38 additions & 20 deletions src/librustc_codegen_ssa/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::MemFlags;
use crate::common::{self, RealPredicate, IntPredicate};
use crate::traits::*;

use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
use rustc::ty::{self, Ty, TyCtxt, adjustment::{PointerCast}, Instance};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
use rustc::mir;
Expand Down Expand Up @@ -349,8 +349,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
(CastTy::Ptr(_), CastTy::Ptr(_)) |
(CastTy::FnPtr, CastTy::Ptr(_)) |
(CastTy::RPtr(_), CastTy::Ptr(_)) =>
(CastTy::FnPtr, CastTy::Ptr(_)) =>
bx.pointercast(llval, ll_t_out),
(CastTy::Ptr(_), CastTy::Int(_)) |
(CastTy::FnPtr, CastTy::Int(_)) =>
Expand All @@ -375,24 +374,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}

mir::Rvalue::Ref(_, bk, ref place) => {
let cg_place = self.codegen_place(&mut bx, &place.as_ref());

let ty = cg_place.layout.ty;
let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ref(
tcx.lifetimes.re_erased,
ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
);
self.codegen_place_to_pointer(bx, place, mk_ref)
}

// Note: places are indirect, so storing the `llval` into the
// destination effectively creates a reference.
let val = if !bx.cx().type_has_metadata(ty) {
OperandValue::Immediate(cg_place.llval)
} else {
OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
};
(bx, OperandRef {
val,
layout: self.cx.layout_of(self.cx.tcx().mk_ref(
self.cx.tcx().lifetimes.re_erased,
ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
)),
})
mir::Rvalue::AddressOf(mutability, ref place) => {
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ptr(
ty::TypeAndMut { ty, mutbl: mutability.into() }
);
self.codegen_place_to_pointer(bx, place, mk_ptr)
}

mir::Rvalue::Len(ref place) => {
Expand Down Expand Up @@ -548,6 +541,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
cg_value.len(bx.cx())
}

/// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref`
fn codegen_place_to_pointer(
&mut self,
mut bx: Bx,
place: &mir::Place<'tcx>,
mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
) -> (Bx, OperandRef<'tcx, Bx::Value>) {
let cg_place = self.codegen_place(&mut bx, &place.as_ref());

let ty = cg_place.layout.ty;

// Note: places are indirect, so storing the `llval` into the
// destination effectively creates a reference.
let val = if !bx.cx().type_has_metadata(ty) {
OperandValue::Immediate(cg_place.llval)
} else {
OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
};
(bx, OperandRef {
val,
layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)),
})
}

pub fn codegen_scalar_binop(
&mut self,
bx: &mut Bx,
Expand Down Expand Up @@ -704,6 +721,7 @@ 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::Ref(..) |
mir::Rvalue::AddressOf(..) |
mir::Rvalue::Len(..) |
mir::Rvalue::Cast(..) | // (*)
mir::Rvalue::BinaryOp(..) |
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_error_codes/error_codes/E0745.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn temp_address() {

To avoid the error, first bind the temporary to a named local variable.

```ignore (not yet implemented)
```
# #![feature(raw_ref_op)]
fn temp_address() {
let val = 2;
Expand Down
18 changes: 17 additions & 1 deletion src/librustc_mir/borrow_check/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
use rustc::mir::{Statement, StatementKind};
use rustc::mir::TerminatorKind;
use rustc::mir::{Operand, BorrowKind};
use rustc::mir::{Operand, BorrowKind, Mutability};
use rustc_data_structures::graph::dominators::Dominators;

use crate::dataflow::indexes::BorrowIndex;
Expand Down Expand Up @@ -337,6 +337,22 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
);
}

Rvalue::AddressOf(mutability, ref place) => {
let access_kind = match mutability {
Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
allow_two_phase_borrow: false,
}))),
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
};

self.access_place(
location,
place,
access_kind,
LocalMutationIsAllowed::No,
);
}

Rvalue::Use(ref operand)
| Rvalue::Repeat(ref operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}


Rvalue::AddressOf(mutability, ref place) => {
let access_kind = match mutability {
Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
allow_two_phase_borrow: false,
}))),
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
};

self.access_place(
location,
(place, span),
access_kind,
LocalMutationIsAllowed::No,
flow_state,
);

self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Borrow,
(place.as_ref(), span),
flow_state,
);
}

Rvalue::Use(ref operand)
| Rvalue::Repeat(ref operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
Expand Down
49 changes: 12 additions & 37 deletions src/librustc_mir/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2273,41 +2273,6 @@ impl<'a, 'tcx> TypeChecker<'a, '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) {
(Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
if let hir::Mutability::Mutable = ptr_tm.mutbl {
if let Err(terr) = self.eq_types(
ref_tm.ty,
ptr_tm.ty,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"equating {:?} with {:?} yields {:?}",
ref_tm.ty,
ptr_tm.ty,
terr
)
}
} else {
if let Err(terr) = self.sub_types(
ref_tm.ty,
ptr_tm.ty,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"relating {:?} with {:?} yields {:?}",
ref_tm.ty,
ptr_tm.ty,
terr
)
}
}
},
(None, _)
| (_, None)
| (_, Some(CastTy::FnPtr))
Expand All @@ -2320,7 +2285,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ty_from,
ty,
),
_ => (),
(Some(CastTy::Int(_)), Some(CastTy::Int(_)))
| (Some(CastTy::Float), Some(CastTy::Int(_)))
| (Some(CastTy::Int(_)), Some(CastTy::Float))
| (Some(CastTy::Float), Some(CastTy::Float))
| (Some(CastTy::Ptr(_)), Some(CastTy::Int(_)))
| (Some(CastTy::FnPtr), Some(CastTy::Int(_)))
| (Some(CastTy::Int(_)), Some(CastTy::Ptr(_)))
| (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_)))
| (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
}
}
}
Expand Down Expand Up @@ -2371,7 +2344,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}

Rvalue::Use(..)
Rvalue::AddressOf(..)
| Rvalue::Use(..)
| Rvalue::Len(..)
| Rvalue::BinaryOp(..)
| Rvalue::CheckedBinaryOp(..)
Expand All @@ -2388,6 +2362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Rvalue::Use(_)
| Rvalue::Repeat(..)
| Rvalue::Ref(..)
| Rvalue::AddressOf(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
| Rvalue::BinaryOp(..)
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Pointer { .. }
| ExprKind::Repeat { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Match { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Adt { .. }
| ExprKind::Loop { .. }
| ExprKind::LogicalOp { .. }
Expand Down
Loading

0 comments on commit ef01330

Please sign in to comment.