auto merge of #19456 : nikomatsakis/rust/reborrow-closure-arg, r=pnkfelix
Otherwise region inference can fail when closure arguments include `ref` bindings. Test case included in the PR.
This commit is contained in:
commit
eacbd296fa
@ -406,7 +406,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
decl, id, body, &inh);
|
||||
|
||||
vtable::select_all_fcx_obligations_or_error(&fcx);
|
||||
regionck::regionck_fn(&fcx, id, body);
|
||||
regionck::regionck_fn(&fcx, id, decl, body);
|
||||
fcx.default_diverging_type_variables_to_nil();
|
||||
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
|
||||
}
|
||||
|
@ -158,11 +158,11 @@ pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
|
||||
pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast::Block) {
|
||||
let mut rcx = Rcx::new(fcx, blk.id);
|
||||
if fcx.err_count_since_creation() == 0 {
|
||||
// regionck assumes typeck succeeded
|
||||
rcx.visit_fn_body(id, blk);
|
||||
rcx.visit_fn_body(id, decl, blk);
|
||||
}
|
||||
|
||||
// Region checking a fn can introduce new trait obligations,
|
||||
@ -328,6 +328,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
||||
|
||||
fn visit_fn_body(&mut self,
|
||||
id: ast::NodeId,
|
||||
fn_decl: &ast::FnDecl,
|
||||
body: &ast::Block)
|
||||
{
|
||||
// When we enter a function, we can derive
|
||||
@ -343,6 +344,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
||||
|
||||
let len = self.region_param_pairs.len();
|
||||
self.relate_free_regions(fn_sig.as_slice(), body.id);
|
||||
link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs.as_slice());
|
||||
self.visit_block(body);
|
||||
self.visit_region_obligations(body.id);
|
||||
self.region_param_pairs.truncate(len);
|
||||
@ -480,9 +482,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Rcx<'a, 'tcx> {
|
||||
// hierarchy, and in particular the relationships between free
|
||||
// regions, until regionck, as described in #3238.
|
||||
|
||||
fn visit_fn(&mut self, _fk: visit::FnKind<'v>, _fd: &'v ast::FnDecl,
|
||||
fn visit_fn(&mut self, _fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
|
||||
b: &'v ast::Block, _s: Span, id: ast::NodeId) {
|
||||
self.visit_fn_body(id, b)
|
||||
self.visit_fn_body(id, fd, b)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &ast::Item) { visit_item(self, i); }
|
||||
@ -1288,7 +1290,6 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
|
||||
/// then ensures that the lifetime of the resulting pointer is
|
||||
/// linked to the lifetime of its guarantor (if any).
|
||||
fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
|
||||
|
||||
debug!("regionck::for_match()");
|
||||
let mc = mc::MemCategorizationContext::new(rcx);
|
||||
let discr_cmt = ignore_err!(mc.cat_expr(discr));
|
||||
@ -1300,12 +1301,32 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the guarantors for any ref bindings in a match and
|
||||
/// then ensures that the lifetime of the resulting pointer is
|
||||
/// linked to the lifetime of its guarantor (if any).
|
||||
fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) {
|
||||
debug!("regionck::link_fn_args(body_scope={})", body_scope);
|
||||
let mc = mc::MemCategorizationContext::new(rcx);
|
||||
for arg in args.iter() {
|
||||
let arg_ty = rcx.fcx.node_ty(arg.id);
|
||||
let re_scope = ty::ReScope(body_scope);
|
||||
let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
|
||||
debug!("arg_ty={} arg_cmt={}",
|
||||
arg_ty.repr(rcx.tcx()),
|
||||
arg_cmt.repr(rcx.tcx()));
|
||||
link_pattern(rcx, mc, arg_cmt, &*arg.pat);
|
||||
}
|
||||
}
|
||||
|
||||
/// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if
|
||||
/// needed.
|
||||
fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||
mc: mc::MemCategorizationContext<Rcx<'a, 'tcx>>,
|
||||
discr_cmt: mc::cmt<'tcx>,
|
||||
root_pat: &ast::Pat) {
|
||||
debug!("link_pattern(discr_cmt={}, root_pat={})",
|
||||
discr_cmt.repr(rcx.tcx()),
|
||||
root_pat.repr(rcx.tcx()));
|
||||
let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
|
||||
match sub_pat.node {
|
||||
// `ref x` pattern
|
||||
|
22
src/test/run-pass/regions-link-fn-args.rs
Normal file
22
src/test/run-pass/regions-link-fn-args.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2014 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 that region inference correctly links up the regions when a
|
||||
// `ref` borrow occurs inside a fn argument.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn with<'a>(_: |&'a Vec<int>| -> &'a Vec<int>) { }
|
||||
|
||||
fn foo() {
|
||||
with(|&ref ints| ints);
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
Reference in New Issue
Block a user