about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-01-26 17:42:52 +0000
committerbors <bors@rust-lang.org>2017-01-26 17:42:52 +0000
commit8430042a49bbd49bbb4fbc54f457feb5fb614f56 (patch)
treea5fb7095092902f3168b86d671f0813d1228eaa4
parent491b978822a56f23acf9ba46f90861958bc1e36c (diff)
parent82a280597d967dc3ec8686f160a0afea4ad45837 (diff)
downloadrust-8430042a49bbd49bbb4fbc54f457feb5fb614f56.tar.gz
rust-8430042a49bbd49bbb4fbc54f457feb5fb614f56.zip
Auto merge of #39066 - arielb1:lifetime-extension-test, r=nikomatsakis
End temporary lifetimes being extended by `let X: &_` hints

cc #39283

r? @nikomatsakis
-rw-r--r--src/librustc/infer/mod.rs5
-rw-r--r--src/librustc/middle/expr_use_visitor.rs1
-rw-r--r--src/librustc/middle/mem_categorization.rs30
-rw-r--r--src/librustc/middle/region.rs62
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/lifetime.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs13
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs3
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs7
-rw-r--r--src/librustc_mir/hair/cx/block.rs3
-rw-r--r--src/librustc_mir/hair/cx/expr.rs121
-rw-r--r--src/librustc_mir/hair/mod.rs3
-rw-r--r--src/librustc_typeck/check/regionck.rs5
-rw-r--r--src/librustc_typeck/check/upvar.rs4
-rw-r--r--src/test/compile-fail/issue-36082.rs27
14 files changed, 205 insertions, 81 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 45a58333f78..ef93a10808b 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<CodeExtent> {
-        self.tcx.region_maps.temporary_scope(rvalue_id)
-    }
-
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
         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 738bd0009ab..2ca0069560c 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 126d43aa690..955bec00433 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 7337c03795b..a19f15a9329 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<NodeMap<CodeExtent>>,
 
+    /// 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<NodeMap<CodeExtent>>,
+
     /// 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<E>(&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<CodeExtent> {
         //! 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<CodeExtent>, 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<CodeExtent>, Option<CodeExtent>)
+    {
+        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<CodeExtent> {
         //! 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: &hir_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 5970d6e4f2f..bbfb7e5874e 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 3464f1fa89a..4a92578fed5 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 6230123a9ca..7caf8a778d4 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 fb12e08affd..0ae4bcc4205 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 4b3d62fd6d6..ba6b9361a83 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 c4c6ec6b8f4..477a1086e81 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 f57d442752d..01dc01c5ecf 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<CodeExtent>,
 
+    /// 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 9a5d402ef0a..7d515a36cfd 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 d511d57c378..c2f64b1bd79 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 00000000000..cec4b2d15dc
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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