From 35919ace7084e10fce15cb9bb42a9404b63b849d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 20 Apr 2019 18:06:03 +0100 Subject: [PATCH] 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. --- src/librustc_mir/build/expr/as_place.rs | 1 + src/librustc_mir/build/expr/as_rvalue.rs | 1 + src/librustc_mir/build/expr/category.rs | 1 + src/librustc_mir/build/expr/into.rs | 18 ++++ src/librustc_mir/hair/cx/expr.rs | 84 +++---------------- src/librustc_mir/hair/mod.rs | 5 ++ src/test/mir-opt/array-index-is-temporary.rs | 19 ++--- .../const_prop/const_prop_fails_gracefully.rs | 18 ++-- src/test/mir-opt/retag.rs | 10 +-- src/test/ui/cast/cast-as-bool.rs | 2 +- src/test/ui/cast/cast-as-bool.stderr | 7 +- 11 files changed, 61 insertions(+), 105 deletions(-) diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index ddacda72e1e6..15c7c92d7db5 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -276,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } + | ExprKind::AddressOf { .. } | ExprKind::Match { .. } | ExprKind::Loop { .. } | ExprKind::Block { .. } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 37eb0cc9d961..24282a6617ac 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -276,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::NeverToAny { .. } | ExprKind::Use { .. } | ExprKind::Borrow { .. } + | ExprKind::AddressOf { .. } | ExprKind::Adt { .. } | ExprKind::Loop { .. } | ExprKind::LogicalOp { .. } diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 270a1a644743..4d0039b2e8ce 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -49,6 +49,7 @@ impl Category { | ExprKind::Use { .. } | ExprKind::Adt { .. } | ExprKind::Borrow { .. } + | ExprKind::AddressOf { .. } | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)), ExprKind::Array { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 07a44b190b20..6b33e8433f67 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8c852854be1f..6cbc25aa7356 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -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, -) -> 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, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 47644d9ba837..46e0d2a17b32 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -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>, diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs index 00a6b26d0cf2..096f98bade25 100644 --- a/src/test/mir-opt/array-index-is-temporary.rs +++ b/src/test/mir-opt/array-index-is-temporary.rs @@ -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; // } diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs index 3f82b81a47de..3c8c0ff44934 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs @@ -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 diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 32995448a21e..ccecaeac96b8 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -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]; // } // // ... diff --git a/src/test/ui/cast/cast-as-bool.rs b/src/test/ui/cast/cast-as-bool.rs index 8130f4dedc9a..1aed218aeb47 100644 --- a/src/test/ui/cast/cast-as-bool.rs +++ b/src/test/ui/cast/cast-as-bool.rs @@ -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 } diff --git a/src/test/ui/cast/cast-as-bool.stderr b/src/test/ui/cast/cast-as-bool.stderr index 30f8459c2e1e..15d94ab69d88 100644 --- a/src/test/ui/cast/cast-as-bool.stderr +++ b/src/test/ui/cast/cast-as-bool.stderr @@ -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`.