Start generating AddressOf rvalues in MIR

`hir::BorrowKind::Raw` borrows and casting a reference to a raw
pointer no longer do a reborrow followed by a cast. Instead we
dereference and take the address.
This commit is contained in:
Matthew Jasper 2019-04-20 18:06:03 +01:00
parent 3a19fbf95d
commit 35919ace70
11 changed files with 61 additions and 105 deletions

View File

@ -276,6 +276,7 @@ fn expr_as_place(
| ExprKind::Pointer { .. }
| ExprKind::Repeat { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Match { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }

View File

@ -276,6 +276,7 @@ fn expr_as_rvalue(
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Adt { .. }
| ExprKind::Loop { .. }
| ExprKind::LogicalOp { .. }

View File

@ -49,6 +49,7 @@ pub fn of(ek: &ExprKind<'_>) -> Option<Category> {
| ExprKind::Use { .. }
| ExprKind::Adt { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
ExprKind::Array { .. }

View File

@ -3,6 +3,7 @@
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use crate::hair::*;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, CanonicalUserTypeAnnotation};
use rustc_data_structures::fx::FxHashMap;
@ -295,6 +296,23 @@ pub fn into_expr(
this.cfg.push_assign(block, source_info, destination, borrow);
block.unit()
}
ExprKind::AddressOf {
mutability,
arg,
} => {
let address_of = match mutability {
hir::Mutability::Immutable => Rvalue::AddressOf(
Mutability::Not,
unpack!(block = this.as_read_only_place(block, arg)),
),
hir::Mutability::Mutable => Rvalue::AddressOf(
Mutability::Mut,
unpack!(block = this.as_place(block, arg)),
),
};
this.cfg.push_assign(block, source_info, destination, address_of);
block.unit()
}
ExprKind::Adt {
adt_def,
variant_index,

View File

@ -137,8 +137,11 @@ fn apply_adjustment<'a, 'tcx>(
arg: expr.to_ref(),
}
}
Adjust::Borrow(AutoBorrow::RawPtr(mutbl)) => {
raw_ref_shim(cx, expr.to_ref(), adjustment.target, mutbl, span, temp_lifetime)
Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
ExprKind::AddressOf {
mutability,
arg: expr.to_ref(),
}
}
};
@ -262,17 +265,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
}
}
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutbl, ref arg) => {
cx.tcx.sess
.struct_span_err(
expr.span,
"raw borrows are not yet implemented"
)
.note("for more information, see https://github.com/rust-lang/rust/issues/64490")
.emit();
// Lower to an approximation to avoid further errors.
raw_ref_shim(cx, arg.to_ref(), expr_ty, mutbl, expr.span, temp_lifetime)
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
ExprKind::AddressOf {
mutability,
arg: arg.to_ref(),
}
}
hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
@ -1082,67 +1079,6 @@ fn convert_var(
}
/// Fake `&raw [mut|const] expr` using a borrow and a cast until `AddressOf`
/// exists in MIR.
fn raw_ref_shim<'tcx>(
cx: &mut Cx<'_, 'tcx>,
arg: ExprRef<'tcx>,
ty: Ty<'tcx>,
mutbl: hir::Mutability,
span: Span,
temp_lifetime: Option<region::Scope>,
) -> ExprKind<'tcx> {
let arg_tm = if let ty::RawPtr(type_mutbl) = ty.kind {
type_mutbl
} else {
bug!("raw_ref_shim called with non-raw pointer type");
};
// Convert this to a suitable `&foo` and
// then an unsafe coercion.
let borrow_expr = Expr {
temp_lifetime,
ty: cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, arg_tm),
span,
kind: ExprKind::Borrow {
borrow_kind: mutbl.to_borrow_kind(),
arg,
},
};
let cast_expr = Expr {
temp_lifetime,
ty,
span,
kind: ExprKind::Cast { source: borrow_expr.to_ref() }
};
// To ensure that both implicit and explicit coercions are
// handled the same way, we insert an extra layer of indirection here.
// For explicit casts (e.g., 'foo as *const T'), the source of the 'Use'
// will be an ExprKind::Hair with the appropriate cast expression. Here,
// we make our Use source the generated Cast from the original coercion.
//
// In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by
// as_operand, not by as_rvalue - causing the cast result to be stored in a temporary.
// Ordinary, this is identical to using the cast directly as an rvalue. However, if the
// source of the cast was previously borrowed as mutable, storing the cast in a
// temporary gives the source a chance to expire before the cast is used. For
// structs with a self-referential *mut ptr, this allows assignment to work as
// expected.
//
// For example, consider the type 'struct Foo { field: *mut Foo }',
// The method 'fn bar(&mut self) { self.field = self }'
// triggers a coercion from '&mut self' to '*mut self'. In order
// for the assignment to be valid, the implicit borrow
// of 'self' involved in the coercion needs to end before the local
// containing the '*mut T' is assigned to 'self.field' - otherwise,
// we end up trying to assign to 'self.field' while we have another mutable borrow
// active.
//
// We only need to worry about this kind of thing for coercions from refs to ptrs,
// since they get rid of a borrow implicitly.
ExprKind::Use { source: cast_expr.to_ref() }
}
fn bin_op(op: hir::BinOpKind) -> BinOp {
match op {
hir::BinOpKind::Add => BinOp::Add,

View File

@ -212,6 +212,11 @@ pub enum ExprKind<'tcx> {
borrow_kind: BorrowKind,
arg: ExprRef<'tcx>,
},
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
AddressOf {
mutability: hir::Mutability,
arg: ExprRef<'tcx>,
},
Break {
label: region::Scope,
value: Option<ExprRef<'tcx>>,

View File

@ -18,24 +18,23 @@ fn main() {
// START rustc.main.EraseRegions.after.mir
// bb0: {
// ...
// _5 = &mut _2;
// _4 = &mut (*_5);
// _3 = move _4 as *mut usize (Misc);
// _4 = &mut _2;
// _3 = &raw mut (*_4);
// ...
// _7 = _3;
// _6 = const foo(move _7) -> bb1;
// _6 = _3;
// _5 = const foo(move _6) -> bb1;
// }
//
// bb1: {
// ...
// _8 = _2;
// _9 = Len(_1);
// _10 = Lt(_8, _9);
// assert(move _10, "index out of bounds: the len is move _9 but the index is _8") -> bb2;
// _7 = _2;
// _8 = Len(_1);
// _9 = Lt(_7, _8);
// assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2;
// }
//
// bb2: {
// _1[_8] = move _6;
// _1[_7] = move _5;
// ...
// return;
// }

View File

@ -11,25 +11,21 @@ fn main() {
// START rustc.main.ConstProp.before.mir
// bb0: {
// ...
// _3 = _4;
// _2 = move _3 as *const i32 (Misc);
// ...
// _2 = &raw const (*_3);
// _1 = move _2 as usize (Misc);
// ...
// _6 = _1;
// _5 = const read(move _6) -> bb1;
// _5 = _1;
// _4 = const read(move _5) -> bb1;
// }
// END rustc.main.ConstProp.before.mir
// START rustc.main.ConstProp.after.mir
// bb0: {
// ...
// _4 = const main::FOO;
// _3 = _4;
// _2 = move _3 as *const i32 (Misc);
// ...
// _3 = const main::FOO;
// _2 = &raw const (*_3);
// _1 = move _2 as usize (Misc);
// ...
// _6 = _1;
// _5 = const read(move _6) -> bb1;
// _5 = _1;
// _4 = const read(move _5) -> bb1;
// }
// END rustc.main.ConstProp.after.mir

View File

@ -82,18 +82,16 @@ fn main() {
// _10 = move _8;
// Retag(_10);
// ...
// _13 = &mut (*_10);
// Retag(_13);
// _12 = move _13 as *mut i32 (Misc);
// _12 = &raw mut (*_10);
// Retag([raw] _12);
// ...
// _16 = move _17(move _18) -> bb5;
// _15 = move _16(move _17) -> bb5;
// }
//
// bb5: {
// Retag(_16);
// Retag(_15);
// ...
// _20 = const Test::foo_shr(move _21, move _23) -> [return: bb6, unwind: bb7];
// _19 = const Test::foo_shr(move _20, move _22) -> [return: bb6, unwind: bb7];
// }
//
// ...

View File

@ -5,5 +5,5 @@ fn main() {
let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
//~| HELP compare with zero instead
//~| SUGGESTION (1 + 2) != 0
let v = "hello" as bool; //~ ERROR cannot cast as `bool`
let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid
}

View File

@ -10,12 +10,13 @@ error[E0054]: cannot cast as `bool`
LL | let t = (1 + 2) as bool;
| ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
error[E0054]: cannot cast as `bool`
error[E0606]: casting `&'static str` as `bool` is invalid
--> $DIR/cast-as-bool.rs:8:13
|
LL | let v = "hello" as bool;
| ^^^^^^^^^^^^^^^ unsupported cast
| ^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0054`.
Some errors have detailed explanations: E0054, E0606.
For more information about an error, try `rustc --explain E0054`.