diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b44e1563ee7ed..ccb46d3a16273 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -23,7 +23,6 @@ use hir; use middle::free_region::FreeRegionMap; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; -use middle::region::CodeExtent; use middle::lang_items; use mir::tcx::LvalueTy; use ty::subst::{Kind, Subst, Substs}; @@ -1622,10 +1621,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id)) } - pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { - self.tcx.region_maps.temporary_scope(rvalue_id) - } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0eacbba3fdd44..2130752b4d052 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -296,6 +296,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { arg.id, arg.pat.span, fn_body_scope_r, // Args live only as long as the fn body. + fn_body_scope_r, arg_ty); self.walk_irrefutable_pat(arg_cmt, &arg.pat); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 92e69d7d72957..a74c976cc3296 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -88,7 +88,8 @@ use std::rc::Rc; #[derive(Clone, PartialEq)] pub enum Categorization<'tcx> { - Rvalue(&'tcx ty::Region), // temporary val, argument is its scope + // temporary val, argument is its scope + Rvalue(&'tcx ty::Region, &'tcx ty::Region), StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable @@ -760,11 +761,18 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { /// Returns the lifetime of a temporary created by expr with id `id`. /// This could be `'static` if `id` is part of a constant expression. - pub fn temporary_scope(&self, id: ast::NodeId) -> &'tcx ty::Region { - self.tcx().mk_region(match self.infcx.temporary_scope(id) { + pub fn temporary_scope(&self, id: ast::NodeId) -> (&'tcx ty::Region, &'tcx ty::Region) + { + let (scope, old_scope) = + self.tcx().region_maps.old_and_new_temporary_scope(id); + (self.tcx().mk_region(match scope { + Some(scope) => ty::ReScope(scope), + None => ty::ReStatic + }), + self.tcx().mk_region(match old_scope { Some(scope) => ty::ReScope(scope), None => ty::ReStatic - }) + })) } pub fn cat_rvalue_node(&self, @@ -785,12 +793,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Compute maximum lifetime of this rvalue. This is 'static if // we can promote to a constant, otherwise equal to enclosing temp // lifetime. - let re = if promotable { - self.tcx().mk_region(ty::ReStatic) + let (re, old_re) = if promotable { + (self.tcx().mk_region(ty::ReStatic), + self.tcx().mk_region(ty::ReStatic)) } else { self.temporary_scope(id) }; - let ret = self.cat_rvalue(id, span, re, expr_ty); + let ret = self.cat_rvalue(id, span, re, old_re, expr_ty); debug!("cat_rvalue_node ret {:?}", ret); ret } @@ -799,11 +808,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { cmt_id: ast::NodeId, span: Span, temp_scope: &'tcx ty::Region, + old_temp_scope: &'tcx ty::Region, expr_ty: Ty<'tcx>) -> cmt<'tcx> { let ret = Rc::new(cmt_ { id:cmt_id, span:span, - cat:Categorization::Rvalue(temp_scope), + cat:Categorization::Rvalue(temp_scope, old_temp_scope), mutbl:McDeclared, ty:expr_ty, note: NoteNone @@ -1386,7 +1396,9 @@ impl<'tcx> fmt::Debug for Categorization<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Categorization::StaticItem => write!(f, "static"), - Categorization::Rvalue(r) => write!(f, "rvalue({:?})", r), + Categorization::Rvalue(r, or) => { + write!(f, "rvalue({:?}, {:?})", r, or) + } Categorization::Local(id) => { let name = ty::tls::with(|tcx| tcx.local_var_name_str(id)); write!(f, "local({})", name) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index faf4a448b7a84..ebc5b4cfa9b08 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -272,6 +272,13 @@ pub struct RegionMaps { /// block (see `terminating_scopes`). rvalue_scopes: RefCell>, + /// Records the value of rvalue scopes before they were shrunk by + /// #36082, for error reporting. + /// + /// FIXME: this should be temporary. Remove this by 1.18.0 or + /// so. + shrunk_rvalue_scopes: RefCell>, + /// Encodes the hierarchy of fn bodies. Every fn body (including /// closures) forms its own distinct region hierarchy, rooted in /// the block that is the fn body. This map points from the id of @@ -419,11 +426,7 @@ impl RegionMaps { e(child, parent) } } - pub fn each_rvalue_scope(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) { - for (child, parent) in self.rvalue_scopes.borrow().iter() { - e(child, parent) - } - } + /// Records that `sub_fn` is defined within `sup_fn`. These ids /// should be the id of the block that is the fn body, which is /// also the root of the region hierarchy for that fn. @@ -457,6 +460,12 @@ impl RegionMaps { self.rvalue_scopes.borrow_mut().insert(var, lifetime); } + fn record_shrunk_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { + debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); + assert!(var != lifetime.node_id(self)); + self.shrunk_rvalue_scopes.borrow_mut().insert(var, lifetime); + } + pub fn opt_encl_scope(&self, id: CodeExtent) -> Option { //! Returns the narrowest scope that encloses `id`, if any. self.scope_map.borrow()[id.0 as usize].into_option() @@ -476,6 +485,30 @@ impl RegionMaps { } } + pub fn temporary_scope2(&self, expr_id: ast::NodeId) -> (Option, bool) { + let temporary_scope = self.temporary_scope(expr_id); + let was_shrunk = match self.shrunk_rvalue_scopes.borrow().get(&expr_id) { + Some(&s) => { + info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})", + expr_id, temporary_scope, s); + temporary_scope != Some(s) + } + _ => false + }; + info!("temporary_scope2({:?}) - was_shrunk={:?}", expr_id, was_shrunk); + (temporary_scope, was_shrunk) + } + + pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId) -> + (Option, Option) + { + let temporary_scope = self.temporary_scope(expr_id); + (temporary_scope, + self.shrunk_rvalue_scopes + .borrow().get(&expr_id).cloned() + .or(temporary_scope)) + } + pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option { //! Returns the scope when temp created by expr_id will be cleaned up @@ -929,8 +962,10 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, let is_borrow = if let Some(ref ty) = local.ty { is_borrowed_ty(&ty) } else { false }; - if is_binding_pat(&local.pat) || is_borrow { - record_rvalue_scope(visitor, &expr, blk_scope); + if is_binding_pat(&local.pat) { + record_rvalue_scope(visitor, &expr, blk_scope, false); + } else if is_borrow { + record_rvalue_scope(visitor, &expr, blk_scope, true); } } @@ -995,7 +1030,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, match expr.node { hir::ExprAddrOf(_, ref subexpr) => { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id); - record_rvalue_scope(visitor, &subexpr, blk_id); + record_rvalue_scope(visitor, &subexpr, blk_id, false); } hir::ExprStruct(_, ref fields, _) => { for field in fields { @@ -1040,7 +1075,8 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, /// Note: ET is intended to match "rvalues or lvalues based on rvalues". fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor, expr: &'a hir::Expr, - blk_scope: CodeExtent) { + blk_scope: CodeExtent, + is_shrunk: bool) { let mut expr = expr; loop { // Note: give all the expressions matching `ET` with the @@ -1048,7 +1084,12 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, // because in trans if we must compile e.g. `*rvalue()` // into a temporary, we request the temporary scope of the // outer expression. - visitor.region_maps.record_rvalue_scope(expr.id, blk_scope); + if is_shrunk { + // this changed because of #36082 + visitor.region_maps.record_shrunk_rvalue_scope(expr.id, blk_scope); + } else { + visitor.region_maps.record_rvalue_scope(expr.id, blk_scope); + } match expr.node { hir::ExprAddrOf(_, ref subexpr) | @@ -1225,6 +1266,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps { scope_map: RefCell::new(vec![]), var_map: RefCell::new(NodeMap()), rvalue_scopes: RefCell::new(NodeMap()), + shrunk_rvalue_scopes: RefCell::new(NodeMap()), fn_tree: RefCell::new(NodeMap()), }; let root_extent = maps.bogus_code_extent( diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 5970d6e4f2f65..bbfb7e5874ea0 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { //! rooting etc, and presuming `cmt` is not mutated. match cmt.cat { - Categorization::Rvalue(temp_scope) => { + Categorization::Rvalue(temp_scope, _) => { temp_scope } Categorization::Upvar(..) => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index c0e038d183dad..738647ab981d6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -967,7 +967,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), err_out_of_scope(super_scope, sub_scope, cause) => { let (value_kind, value_msg) = match err.cmt.cat { - mc::Categorization::Rvalue(_) => + mc::Categorization::Rvalue(..) => ("temporary value", "temporary value created here"), _ => ("borrowed value", "borrow occurs here") @@ -1061,6 +1061,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some(_) = statement_scope_span(self.tcx, super_scope) { db.note("consider using a `let` binding to increase its lifetime"); } + + + + match err.cmt.cat { + mc::Categorization::Rvalue(r, or) if r != or => { + db.note("\ +before rustc 1.16, this temporary lived longer - see issue #39283 \ +(https://github.com/rust-lang/rust/issues/39283)"); + } + _ => {} + } } err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 6230123a9ca17..7caf8a778d409 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -26,7 +26,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> { let this = self; - let Expr { ty, temp_lifetime: _, span, kind } = expr; + let Expr { ty, temp_lifetime: _, temp_lifetime_was_shrunk: _, span, kind } + = expr; match kind { ExprKind::Scope { extent: _, value } => this.as_constant(value), diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index fb12e08affd2d..0ae4bcc4205d4 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -39,6 +39,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let expr_span = expr.span; let source_info = this.source_info(expr_span); + if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) { + this.hir.tcx().sess.span_warn( + expr_span, + "this temporary used to live longer - see issue #39283 \ +(https://github.com/rust-lang/rust/issues/39283)"); + } + if temp_lifetime.is_some() { this.cfg.push(block, Statement { source_info: source_info, diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 4b3d62fd6d6ef..ba6b9361a83f4 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -83,10 +83,11 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> { let block_ty = cx.tables().node_id_to_type(block.id); - let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(block.id); let expr = Expr { ty: block_ty, temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, span: block.span, kind: ExprKind::Block { body: block }, }; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index cdf7cae3020c8..0b40b6c0ad364 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -27,7 +27,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { - let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(self.id); let expr_extent = cx.tcx.region_maps.node_extent(self.id); debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); @@ -45,6 +45,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, @@ -53,6 +54,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, @@ -61,6 +63,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::NeverToAny { source: expr.to_ref() }, @@ -69,6 +72,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::Cast { source: expr.to_ref() }, @@ -98,6 +102,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, @@ -123,6 +128,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { }; expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: kind, @@ -135,6 +141,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ty::adjustment::AutoBorrow::Ref(r, m) => { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::Borrow { @@ -152,6 +159,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { let region = cx.tcx.mk_region(region); expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, @@ -166,6 +174,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { }; expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::Cast { source: expr.to_ref() }, @@ -177,6 +186,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { if unsize { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: adjusted_ty, span: self.span, kind: ExprKind::Unsize { source: expr.to_ref() }, @@ -188,6 +198,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { // Next, wrap this up in the expr's scope. expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: expr.ty, span: self.span, kind: ExprKind::Scope { @@ -200,6 +211,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { if let Some(extent) = cx.tcx.region_maps.opt_destruction_extent(self.id) { expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: expr.ty, span: self.span, kind: ExprKind::Scope { @@ -218,7 +230,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { let expr_ty = cx.tables().expr_ty(expr); - let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id); let kind = match expr.node { // Here comes the interesting stuff: @@ -260,6 +272,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let tupled_args = Expr { ty: sig.inputs()[1], temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, span: expr.span, kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() }, }; @@ -670,6 +683,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: expr_ty, span: expr.span, kind: kind, @@ -681,9 +695,10 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, method_call: ty::MethodCall) -> Expr<'tcx> { let callee = cx.tables().method_map[&method_call]; - let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id); Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: callee.ty, span: expr.span, kind: ExprKind::Literal { @@ -761,7 +776,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) -> ExprKind<'tcx> { - let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id); match def { Def::Local(def_id) => { @@ -813,15 +828,17 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Expr { ty: closure_ty, temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, span: expr.span, kind: ExprKind::Deref { arg: Expr { - ty: ref_closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - } - .to_ref(), + ty: ref_closure_ty, + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + span: expr.span, + kind: ExprKind::SelfRef, + } + .to_ref(), }, } } @@ -834,15 +851,16 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Expr { ty: closure_ty, temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, span: expr.span, kind: ExprKind::Deref { arg: Expr { - ty: ref_closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - } - .to_ref(), + ty: ref_closure_ty, + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + span: expr.span, + kind: ExprKind::SelfRef, + }.to_ref(), }, } } @@ -850,6 +868,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Expr { ty: closure_ty, temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, span: expr.span, kind: ExprKind::SelfRef, } @@ -879,16 +898,16 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::UpvarCapture::ByRef(borrow) => { ExprKind::Deref { arg: Expr { - temp_lifetime: temp_lifetime, - ty: cx.tcx.mk_ref(borrow.region, - ty::TypeAndMut { - ty: var_ty, - mutbl: borrow.kind.to_mutbl_lossy(), - }), - span: expr.span, - kind: field_kind, - } - .to_ref(), + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: cx.tcx.mk_ref(borrow.region, + ty::TypeAndMut { + ty: var_ty, + mutbl: borrow.kind.to_mutbl_lossy(), + }), + span: expr.span, + kind: field_kind, + }.to_ref(), } } } @@ -944,7 +963,8 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, PassArgs::ByRef => { let region = cx.tcx.node_scope_region(expr.id); - let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); + let (temp_lifetime, was_shrunk) = + cx.tcx.region_maps.temporary_scope2(expr.id); argrefs.extend(args.iter() .map(|arg| { let arg_ty = cx.tables().expr_ty_adjusted(arg); @@ -954,16 +974,17 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, mutbl: hir::MutImmutable, }); Expr { - temp_lifetime: temp_lifetime, - ty: adjusted_ty, - span: expr.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: BorrowKind::Shared, - arg: arg.to_ref(), - }, - } - .to_ref() + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: adjusted_ty, + span: expr.span, + kind: ExprKind::Borrow { + region: region, + borrow_kind: BorrowKind::Shared, + arg: arg.to_ref(), + }, + } + .to_ref() })) } } @@ -995,10 +1016,11 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type - let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id); let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args); let ref_expr = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: ref_ty, span: expr.span, kind: ref_kind, @@ -1019,10 +1041,11 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_expr_id: closure_expr.id, }; let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap(); - let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id); + let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(closure_expr.id); let var_ty = cx.tables().node_id_to_type(id_var); let captured_var = Expr { temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, ty: var_ty, span: closure_expr.span, kind: convert_var(cx, closure_expr, freevar.def), @@ -1036,16 +1059,16 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::BorrowKind::MutBorrow => BorrowKind::Mut, }; Expr { - temp_lifetime: temp_lifetime, - ty: freevar_ty, - span: closure_expr.span, - kind: ExprKind::Borrow { - region: upvar_borrow.region, - borrow_kind: borrow_kind, - arg: captured_var.to_ref(), - }, - } - .to_ref() + temp_lifetime: temp_lifetime, + temp_lifetime_was_shrunk: was_shrunk, + ty: freevar_ty, + span: closure_expr.span, + kind: ExprKind::Borrow { + region: upvar_borrow.region, + borrow_kind: borrow_kind, + arg: captured_var.to_ref(), + }, + }.to_ref() } } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index f57d442752d99..01dc01c5ecfd4 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -97,6 +97,9 @@ pub struct Expr<'tcx> { /// temporary; should be None only if in a constant context pub temp_lifetime: Option, + /// whether this temp lifetime was shrunk by #36082. + pub temp_lifetime_was_shrunk: bool, + /// span of the expression in the source pub span: Span, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bd63eb6ad25ef..c26278bfc243d 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -996,7 +996,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { cmt: mc::cmt<'tcx>, span: Span) { match cmt.cat { - Categorization::Rvalue(region) => { + Categorization::Rvalue(region, _) => { match *region { ty::ReScope(rvalue_scope) => { let typ = self.resolve_type(cmt.ty); @@ -1113,7 +1113,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { for arg in args { let arg_ty = self.node_ty(arg.id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); - let arg_cmt = mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty); + let arg_cmt = mc.cat_rvalue( + arg.id, arg.pat.span, re_scope, re_scope, arg_ty); debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, arg_cmt, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 95da5a97f6750..ce3689e4b715f 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -339,7 +339,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { Categorization::Deref(.., mc::UnsafePtr(..)) | Categorization::StaticItem | - Categorization::Rvalue(_) | + Categorization::Rvalue(..) | Categorization::Local(_) | Categorization::Upvar(..) => { return; @@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { Categorization::Deref(.., mc::UnsafePtr(..)) | Categorization::StaticItem | - Categorization::Rvalue(_) | + Categorization::Rvalue(..) | Categorization::Local(_) | Categorization::Upvar(..) => { } diff --git a/src/test/compile-fail/issue-36082.rs b/src/test/compile-fail/issue-36082.rs new file mode 100644 index 0000000000000..cec4b2d15dcd3 --- /dev/null +++ b/src/test/compile-fail/issue-36082.rs @@ -0,0 +1,27 @@ +// Copyright 2016 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. + +use std::cell::RefCell; + +fn main() { + let mut r = 0; + let s = 0; + let x = RefCell::new((&mut r,s)); + + let val: &_ = x.borrow().0; + //~^ WARNING this temporary used to live longer - see issue #39283 + //~^^ ERROR borrowed value does not live long enough + //~| temporary value dropped here while still borrowed + //~| temporary value created here + //~| consider using a `let` binding to increase its lifetime + //~| before rustc 1.16, this temporary lived longer - see issue #39283 + println!("{}", val); +} +//~^ temporary value needs to live until here