Link lifetimes in let patterns just as we do for match patterns

This commit is contained in:
Niko Matsakis 2014-01-17 08:03:43 -05:00
parent 0c916c58e8
commit 56f4d1831a
5 changed files with 72 additions and 3 deletions

View File

@ -67,6 +67,9 @@ impl<'a> GuaranteeLifetimeContext<'a> {
fn check(&self, cmt: mc::cmt, discr_scope: Option<ast::NodeId>) -> R {
//! Main routine. Walks down `cmt` until we find the "guarantor".
debug!("guarantee_lifetime.check(cmt={}, loan_region={})",
cmt.repr(self.bccx.tcx),
self.loan_region.repr(self.bccx.tcx));
match cmt.cat {
mc::cat_rvalue(..) |

View File

@ -213,6 +213,7 @@ fn visit_arm(rcx: &mut Rcx, arm: &ast::Arm) {
fn visit_local(rcx: &mut Rcx, l: &ast::Local) {
// see above
constrain_bindings_in_pat(l.pat, rcx);
guarantor::for_local(rcx, l);
visit::walk_local(rcx, l, ());
}
@ -828,6 +829,30 @@ pub mod guarantor {
}
}
pub fn for_local(rcx: &mut Rcx, local: &ast::Local) {
/*!
* Link the lifetimes of any ref bindings in a let
* pattern to the lifetimes in the initializer.
*
* For example, given something like this:
*
* let &Foo(ref x) = ...;
*
* this would ensure that the lifetime 'a of the
* region pointer being matched must be >= the lifetime
* of the ref binding.
*/
debug!("regionck::for_match()");
let init_expr = match local.init {
None => { return; }
Some(e) => e
};
let init_guarantor = guarantor(rcx, init_expr);
debug!("init_guarantor={}", init_guarantor.repr(rcx.tcx()));
link_ref_bindings_in_pat(rcx, local.pat, init_guarantor);
}
pub fn for_autoref(rcx: &mut Rcx,
expr: &ast::Expr,
autoderefs: uint,

View File

@ -0,0 +1,22 @@
// Copyright 2012 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.
// Test lifetimes are linked properly when we take reference
// to interior.
struct Foo(int);
fn foo() -> &int {
let &Foo(ref x) = &Foo(3); //~ ERROR borrowed value does not live long enough
x
}
pub fn main() {
}

View File

@ -196,13 +196,13 @@ fn main() {
let Unit(ii) = Unit(51);
// univariant enum with ref binding
let Unit(ref jj) = Unit(52);
let &Unit(ref jj) = &Unit(52);
// tuple struct
let TupleStruct(kk, ll) = TupleStruct(53.0, 54);
let &TupleStruct(kk, ll) = &TupleStruct(53.0, 54);
// tuple struct with ref binding
let TupleStruct(mm, ref nn) = TupleStruct(55.0, 56);
let &TupleStruct(mm, ref nn) = &TupleStruct(55.0, 56);
zzz();
}

View File

@ -0,0 +1,19 @@
// Copyright 2012 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.
// Test lifetimes are linked properly when we take reference
// to interior.
struct Foo(int);
pub fn main() {
// Here the lifetime of the `&` should be at least the
// block, since a ref binding is created to the interior.
let &Foo(ref _x) = &Foo(3);
}