Skip to content

Commit 82a2805

Browse files
committed
end temporary lifetimes being extended by let X: &_ hints
Fixes #36082.
1 parent 249b444 commit 82a2805

File tree

14 files changed

+205
-81
lines changed

14 files changed

+205
-81
lines changed

src/librustc/infer/mod.rs

-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use hir;
2323
use middle::free_region::FreeRegionMap;
2424
use middle::mem_categorization as mc;
2525
use middle::mem_categorization::McResult;
26-
use middle::region::CodeExtent;
2726
use middle::lang_items;
2827
use mir::tcx::LvalueTy;
2928
use ty::subst::{Kind, Subst, Substs};
@@ -1622,10 +1621,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
16221621
self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
16231622
}
16241623

1625-
pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
1626-
self.tcx.region_maps.temporary_scope(rvalue_id)
1627-
}
1628-
16291624
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
16301625
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
16311626
}

src/librustc/middle/expr_use_visitor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
296296
arg.id,
297297
arg.pat.span,
298298
fn_body_scope_r, // Args live only as long as the fn body.
299+
fn_body_scope_r,
299300
arg_ty);
300301

301302
self.walk_irrefutable_pat(arg_cmt, &arg.pat);

src/librustc/middle/mem_categorization.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ use std::rc::Rc;
8888

8989
#[derive(Clone, PartialEq)]
9090
pub enum Categorization<'tcx> {
91-
Rvalue(&'tcx ty::Region), // temporary val, argument is its scope
91+
// temporary val, argument is its scope
92+
Rvalue(&'tcx ty::Region, &'tcx ty::Region),
9293
StaticItem,
9394
Upvar(Upvar), // upvar referenced by closure env
9495
Local(ast::NodeId), // local variable
@@ -760,11 +761,18 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
760761

761762
/// Returns the lifetime of a temporary created by expr with id `id`.
762763
/// This could be `'static` if `id` is part of a constant expression.
763-
pub fn temporary_scope(&self, id: ast::NodeId) -> &'tcx ty::Region {
764-
self.tcx().mk_region(match self.infcx.temporary_scope(id) {
764+
pub fn temporary_scope(&self, id: ast::NodeId) -> (&'tcx ty::Region, &'tcx ty::Region)
765+
{
766+
let (scope, old_scope) =
767+
self.tcx().region_maps.old_and_new_temporary_scope(id);
768+
(self.tcx().mk_region(match scope {
769+
Some(scope) => ty::ReScope(scope),
770+
None => ty::ReStatic
771+
}),
772+
self.tcx().mk_region(match old_scope {
765773
Some(scope) => ty::ReScope(scope),
766774
None => ty::ReStatic
767-
})
775+
}))
768776
}
769777

770778
pub fn cat_rvalue_node(&self,
@@ -785,12 +793,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
785793
// Compute maximum lifetime of this rvalue. This is 'static if
786794
// we can promote to a constant, otherwise equal to enclosing temp
787795
// lifetime.
788-
let re = if promotable {
789-
self.tcx().mk_region(ty::ReStatic)
796+
let (re, old_re) = if promotable {
797+
(self.tcx().mk_region(ty::ReStatic),
798+
self.tcx().mk_region(ty::ReStatic))
790799
} else {
791800
self.temporary_scope(id)
792801
};
793-
let ret = self.cat_rvalue(id, span, re, expr_ty);
802+
let ret = self.cat_rvalue(id, span, re, old_re, expr_ty);
794803
debug!("cat_rvalue_node ret {:?}", ret);
795804
ret
796805
}
@@ -799,11 +808,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
799808
cmt_id: ast::NodeId,
800809
span: Span,
801810
temp_scope: &'tcx ty::Region,
811+
old_temp_scope: &'tcx ty::Region,
802812
expr_ty: Ty<'tcx>) -> cmt<'tcx> {
803813
let ret = Rc::new(cmt_ {
804814
id:cmt_id,
805815
span:span,
806-
cat:Categorization::Rvalue(temp_scope),
816+
cat:Categorization::Rvalue(temp_scope, old_temp_scope),
807817
mutbl:McDeclared,
808818
ty:expr_ty,
809819
note: NoteNone
@@ -1386,7 +1396,9 @@ impl<'tcx> fmt::Debug for Categorization<'tcx> {
13861396
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
13871397
match *self {
13881398
Categorization::StaticItem => write!(f, "static"),
1389-
Categorization::Rvalue(r) => write!(f, "rvalue({:?})", r),
1399+
Categorization::Rvalue(r, or) => {
1400+
write!(f, "rvalue({:?}, {:?})", r, or)
1401+
}
13901402
Categorization::Local(id) => {
13911403
let name = ty::tls::with(|tcx| tcx.local_var_name_str(id));
13921404
write!(f, "local({})", name)

src/librustc/middle/region.rs

+52-10
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ pub struct RegionMaps {
272272
/// block (see `terminating_scopes`).
273273
rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
274274

275+
/// Records the value of rvalue scopes before they were shrunk by
276+
/// #36082, for error reporting.
277+
///
278+
/// FIXME: this should be temporary. Remove this by 1.18.0 or
279+
/// so.
280+
shrunk_rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
281+
275282
/// Encodes the hierarchy of fn bodies. Every fn body (including
276283
/// closures) forms its own distinct region hierarchy, rooted in
277284
/// the block that is the fn body. This map points from the id of
@@ -419,11 +426,7 @@ impl RegionMaps {
419426
e(child, parent)
420427
}
421428
}
422-
pub fn each_rvalue_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) {
423-
for (child, parent) in self.rvalue_scopes.borrow().iter() {
424-
e(child, parent)
425-
}
426-
}
429+
427430
/// Records that `sub_fn` is defined within `sup_fn`. These ids
428431
/// should be the id of the block that is the fn body, which is
429432
/// also the root of the region hierarchy for that fn.
@@ -457,6 +460,12 @@ impl RegionMaps {
457460
self.rvalue_scopes.borrow_mut().insert(var, lifetime);
458461
}
459462

463+
fn record_shrunk_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
464+
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
465+
assert!(var != lifetime.node_id(self));
466+
self.shrunk_rvalue_scopes.borrow_mut().insert(var, lifetime);
467+
}
468+
460469
pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
461470
//! Returns the narrowest scope that encloses `id`, if any.
462471
self.scope_map.borrow()[id.0 as usize].into_option()
@@ -476,6 +485,30 @@ impl RegionMaps {
476485
}
477486
}
478487

488+
pub fn temporary_scope2(&self, expr_id: ast::NodeId) -> (Option<CodeExtent>, bool) {
489+
let temporary_scope = self.temporary_scope(expr_id);
490+
let was_shrunk = match self.shrunk_rvalue_scopes.borrow().get(&expr_id) {
491+
Some(&s) => {
492+
info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})",
493+
expr_id, temporary_scope, s);
494+
temporary_scope != Some(s)
495+
}
496+
_ => false
497+
};
498+
info!("temporary_scope2({:?}) - was_shrunk={:?}", expr_id, was_shrunk);
499+
(temporary_scope, was_shrunk)
500+
}
501+
502+
pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId) ->
503+
(Option<CodeExtent>, Option<CodeExtent>)
504+
{
505+
let temporary_scope = self.temporary_scope(expr_id);
506+
(temporary_scope,
507+
self.shrunk_rvalue_scopes
508+
.borrow().get(&expr_id).cloned()
509+
.or(temporary_scope))
510+
}
511+
479512
pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
480513
//! Returns the scope when temp created by expr_id will be cleaned up
481514
@@ -929,8 +962,10 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
929962
let is_borrow =
930963
if let Some(ref ty) = local.ty { is_borrowed_ty(&ty) } else { false };
931964

932-
if is_binding_pat(&local.pat) || is_borrow {
933-
record_rvalue_scope(visitor, &expr, blk_scope);
965+
if is_binding_pat(&local.pat) {
966+
record_rvalue_scope(visitor, &expr, blk_scope, false);
967+
} else if is_borrow {
968+
record_rvalue_scope(visitor, &expr, blk_scope, true);
934969
}
935970
}
936971

@@ -995,7 +1030,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
9951030
match expr.node {
9961031
hir::ExprAddrOf(_, ref subexpr) => {
9971032
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
998-
record_rvalue_scope(visitor, &subexpr, blk_id);
1033+
record_rvalue_scope(visitor, &subexpr, blk_id, false);
9991034
}
10001035
hir::ExprStruct(_, ref fields, _) => {
10011036
for field in fields {
@@ -1040,15 +1075,21 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
10401075
/// Note: ET is intended to match "rvalues or lvalues based on rvalues".
10411076
fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor,
10421077
expr: &'a hir::Expr,
1043-
blk_scope: CodeExtent) {
1078+
blk_scope: CodeExtent,
1079+
is_shrunk: bool) {
10441080
let mut expr = expr;
10451081
loop {
10461082
// Note: give all the expressions matching `ET` with the
10471083
// extended temporary lifetime, not just the innermost rvalue,
10481084
// because in trans if we must compile e.g. `*rvalue()`
10491085
// into a temporary, we request the temporary scope of the
10501086
// outer expression.
1051-
visitor.region_maps.record_rvalue_scope(expr.id, blk_scope);
1087+
if is_shrunk {
1088+
// this changed because of #36082
1089+
visitor.region_maps.record_shrunk_rvalue_scope(expr.id, blk_scope);
1090+
} else {
1091+
visitor.region_maps.record_rvalue_scope(expr.id, blk_scope);
1092+
}
10521093

10531094
match expr.node {
10541095
hir::ExprAddrOf(_, ref subexpr) |
@@ -1225,6 +1266,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps {
12251266
scope_map: RefCell::new(vec![]),
12261267
var_map: RefCell::new(NodeMap()),
12271268
rvalue_scopes: RefCell::new(NodeMap()),
1269+
shrunk_rvalue_scopes: RefCell::new(NodeMap()),
12281270
fn_tree: RefCell::new(NodeMap()),
12291271
};
12301272
let root_extent = maps.bogus_code_extent(

src/librustc_borrowck/borrowck/gather_loans/lifetime.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
108108
//! rooting etc, and presuming `cmt` is not mutated.
109109
110110
match cmt.cat {
111-
Categorization::Rvalue(temp_scope) => {
111+
Categorization::Rvalue(temp_scope, _) => {
112112
temp_scope
113113
}
114114
Categorization::Upvar(..) => {

src/librustc_borrowck/borrowck/mod.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
967967
err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
968968
err_out_of_scope(super_scope, sub_scope, cause) => {
969969
let (value_kind, value_msg) = match err.cmt.cat {
970-
mc::Categorization::Rvalue(_) =>
970+
mc::Categorization::Rvalue(..) =>
971971
("temporary value", "temporary value created here"),
972972
_ =>
973973
("borrowed value", "borrow occurs here")
@@ -1061,6 +1061,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
10611061
if let Some(_) = statement_scope_span(self.tcx, super_scope) {
10621062
db.note("consider using a `let` binding to increase its lifetime");
10631063
}
1064+
1065+
1066+
1067+
match err.cmt.cat {
1068+
mc::Categorization::Rvalue(r, or) if r != or => {
1069+
db.note("\
1070+
before rustc 1.16, this temporary lived longer - see issue #39283 \
1071+
(https://github.com/rust-lang/rust/issues/39283)");
1072+
}
1073+
_ => {}
1074+
}
10641075
}
10651076

10661077
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {

src/librustc_mir/build/expr/as_constant.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
2626

2727
fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
2828
let this = self;
29-
let Expr { ty, temp_lifetime: _, span, kind } = expr;
29+
let Expr { ty, temp_lifetime: _, temp_lifetime_was_shrunk: _, span, kind }
30+
= expr;
3031
match kind {
3132
ExprKind::Scope { extent: _, value } =>
3233
this.as_constant(value),

src/librustc_mir/build/expr/as_temp.rs

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
3939
let expr_span = expr.span;
4040
let source_info = this.source_info(expr_span);
4141

42+
if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
43+
this.hir.tcx().sess.span_warn(
44+
expr_span,
45+
"this temporary used to live longer - see issue #39283 \
46+
(https://github.com/rust-lang/rust/issues/39283)");
47+
}
48+
4249
if temp_lifetime.is_some() {
4350
this.cfg.push(block, Statement {
4451
source_info: source_info,

src/librustc_mir/hair/cx/block.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
8383
block: &'tcx hir::Block)
8484
-> ExprRef<'tcx> {
8585
let block_ty = cx.tables().node_id_to_type(block.id);
86-
let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id);
86+
let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(block.id);
8787
let expr = Expr {
8888
ty: block_ty,
8989
temp_lifetime: temp_lifetime,
90+
temp_lifetime_was_shrunk: was_shrunk,
9091
span: block.span,
9192
kind: ExprKind::Block { body: block },
9293
};

0 commit comments

Comments
 (0)