diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index a3680214432..5178963179d 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -27,8 +27,8 @@ pub fn as_local_operand(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>> { - let topmost_scope = self.topmost_scope(); // FIXME(#6393) - self.as_operand(block, Some(topmost_scope), expr) + let local_scope = self.local_scope(); + self.as_operand(block, local_scope, expr) } /// Compile `expr` into a value that can be used as an operand. diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 7b29cd970d7..e1832e0a0af 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -33,8 +33,8 @@ pub fn as_local_rvalue(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>> { - let topmost_scope = self.topmost_scope(); // FIXME(#6393) - self.as_rvalue(block, Some(topmost_scope), expr) + let local_scope = self.local_scope(); + self.as_rvalue(block, local_scope, expr) } /// Compile `expr`, yielding an rvalue. @@ -51,7 +51,7 @@ fn expr_as_rvalue(&mut self, scope: Option, expr: Expr<'tcx>) -> BlockAnd> { - debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr); + debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr); let this = self; let expr_span = expr.span; diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index a334923546f..ab27a1a9c24 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -35,7 +35,8 @@ fn expr_as_temp(&mut self, temp_lifetime: Option, expr: Expr<'tcx>) -> BlockAnd> { - debug!("expr_as_temp(block={:?}, expr={:?})", block, expr); + debug!("expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?})", + block, temp_lifetime, expr); let this = self; if let ExprKind::Scope { extent, value } = expr.kind { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index fb173e2487b..9b1db2193e6 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -392,9 +392,9 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, mir } -pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, - body_id: hir::BodyId) - -> Mir<'tcx> { +fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, + body_id: hir::BodyId) + -> Mir<'tcx> { let tcx = hir.tcx(); let ast_expr = &tcx.hir.body(body_id).value; let ty = hir.tables().expr_ty_adjusted(ast_expr); @@ -415,7 +415,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, builder.finish(vec![], ty) } -pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, +fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, body_id: hir::BodyId) -> Mir<'tcx> { let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id)); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index ae47f4c4244..0b1d411d96e 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -93,6 +93,7 @@ use rustc::ty::subst::{Kind, Subst}; use rustc::ty::{Ty, TyCtxt}; use rustc::mir::*; +use rustc::mir::transform::MirSource; use syntax_pos::Span; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::fx::FxHashMap; @@ -428,6 +429,33 @@ pub fn topmost_scope(&self) -> CodeExtent { self.scopes.last().expect("topmost_scope: no scopes present").extent } + /// Returns the scope that we should use as the lifetime of an + /// operand. Basically, an operand must live until it is consumed. + /// This is similar to, but not quite the same as, the temporary + /// scope (which can be larger or smaller). + /// + /// Consider: + /// + /// let x = foo(bar(X, Y)); + /// + /// We wish to pop the storage for X and Y after `bar()` is + /// called, not after the whole `let` is completed. + /// + /// When building statics/constants, returns `None` since + /// intermediate values do not have to be dropped in that case. + pub fn local_scope(&self) -> Option { + match self.hir.src { + MirSource::Const(_) | + MirSource::Static(..) => + // No need to free storage in this context. + None, + MirSource::Fn(_) => + Some(self.topmost_scope()), + MirSource::Promoted(..) => + bug!(), + } + } + // Scheduling drops // ================ /// Indicates that `lvalue` should be dropped on exit from diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 9ffce18fe15..11b511ca47b 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -36,8 +36,14 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, pub region_maps: Rc, + + /// This is `Constness::Const` if we are compiling a `static`, + /// `const`, or the body of a `const fn`. constness: hir::Constness, + /// What are we compiling? + pub src: MirSource, + /// True if this constant/function needs overflow checks. check_overflow: bool, } @@ -74,7 +80,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx, // Constants and const fn's always need overflow checks. check_overflow |= constness == hir::Constness::Const; - Cx { tcx, infcx, region_maps, constness, check_overflow } + Cx { tcx, infcx, region_maps, constness, src, check_overflow } } } diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs new file mode 100644 index 00000000000..9fb725a980e --- /dev/null +++ b/src/test/mir-opt/storage_live_dead_in_statics.rs @@ -0,0 +1,100 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that when we compile the static `XXX` into MIR, we do not +// generate `StorageStart` or `StorageEnd` statements. + +// ignore-tidy-linelength + +static XXX: &'static Foo = &Foo { + tup: "hi", + data: &[ + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + (0, 1), (0, 2), (0, 3), + ] +}; + +#[derive(Debug)] +struct Foo { + tup: &'static str, + data: &'static [(u32, u32)] +} + +fn main() { + println!("{:?}", XXX); +} + +// END RUST SOURCE +// START rustc.node4.mir_map.0.mir +// bb0: { +// _7 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:29:9: 29:15 +// _8 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:29:17: 29:23 +// _9 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:29:25: 29:31 +// _10 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:30:9: 30:15 +// _11 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:30:17: 30:23 +// _12 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:30:25: 30:31 +// _13 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:31:9: 31:15 +// _14 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:31:17: 31:23 +// _15 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:31:25: 31:31 +// _16 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:32:9: 32:15 +// _17 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:32:17: 32:23 +// _18 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:32:25: 32:31 +// _19 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:33:9: 33:15 +// _20 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:33:17: 33:23 +// _21 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:33:25: 33:31 +// _22 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:34:9: 34:15 +// _23 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:34:17: 34:23 +// _24 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:34:25: 34:31 +// _25 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:35:9: 35:15 +// _26 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:35:17: 35:23 +// _27 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:35:25: 35:31 +// _28 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:36:9: 36:15 +// _29 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:36:17: 36:23 +// _30 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:36:25: 36:31 +// _31 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:37:9: 37:15 +// _32 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:37:17: 37:23 +// _33 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:37:25: 37:31 +// _34 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:38:9: 38:15 +// _35 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:38:17: 38:23 +// _36 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:38:25: 38:31 +// _37 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:39:9: 39:15 +// _38 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:39:17: 39:23 +// _39 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:39:25: 39:31 +// _40 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:40:9: 40:15 +// _41 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:40:17: 40:23 +// _42 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:40:25: 40:31 +// _43 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:41:9: 41:15 +// _44 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:41:17: 41:23 +// _45 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:41:25: 41:31 +// _46 = (const 0u32, const 1u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:42:9: 42:15 +// _47 = (const 0u32, const 2u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:42:17: 42:23 +// _48 = (const 0u32, const 3u32); // scope 0 at src/test/mir-opt/basic_assignment.rs:42:25: 42:31 +// _6 = [_7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48]; // scope 0 at src/test/mir-opt/basic_assignment.rs:28:12: 43:6 +// _5 = &_6; // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6 +// _4 = &(*_5); // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6 +// _3 = _4 as &'static [(u32, u32)] (Unsize); // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6 +// _2 = Foo { tup: const "hi", data: _3 }; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:29: 44:2 +// _1 = &_2; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:28: 44:2 +// _0 = &(*_1); // scope 0 at src/test/mir-opt/basic_assignment.rs:26:28: 44:2 +// return; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:1: 44:3 +// } +// END rustc.node4.mir_map.0.mir