Skip to content

Add a raw "address of" operator #64588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 20, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -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>),

@@ -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("");
@@ -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) => {
@@ -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) => {
7 changes: 7 additions & 0 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
@@ -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) => {
16 changes: 16 additions & 0 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
@@ -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,
@@ -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:
///
@@ -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:
///
3 changes: 0 additions & 3 deletions src/librustc/ty/cast.rs
Original file line number Diff line number Diff line change
@@ -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)
@@ -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,
}
2 changes: 2 additions & 0 deletions src/librustc_codegen_ssa/mir/analyze.rs
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 1 addition & 1 deletion src/librustc_codegen_ssa/mir/place.rs
Original file line number Diff line number Diff line change
@@ -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: [],
58 changes: 38 additions & 20 deletions src/librustc_codegen_ssa/mir/rvalue.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -342,8 +342,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(_)) =>
@@ -370,24 +369,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) => {
@@ -543,6 +536,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,
@@ -699,6 +716,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(..) |
2 changes: 1 addition & 1 deletion src/librustc_error_codes/error_codes/E0745.md
Original file line number Diff line number Diff line change
@@ -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;
18 changes: 17 additions & 1 deletion src/librustc_mir/borrow_check/invalidation.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -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)
25 changes: 25 additions & 0 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
@@ -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)
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
@@ -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))
@@ -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(_))) => (),
}
}
}
@@ -2371,7 +2344,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}

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