Skip to content

Commit eacbd29

Browse files
committed
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.
2 parents 84a7615 + 9c65a5b commit eacbd29

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
406406
decl, id, body, &inh);
407407

408408
vtable::select_all_fcx_obligations_or_error(&fcx);
409-
regionck::regionck_fn(&fcx, id, body);
409+
regionck::regionck_fn(&fcx, id, decl, body);
410410
fcx.default_diverging_type_variables_to_nil();
411411
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
412412
}

src/librustc_typeck/check/regionck.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
158158
fcx.infcx().resolve_regions_and_report_errors();
159159
}
160160

161-
pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
161+
pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, decl: &ast::FnDecl, blk: &ast::Block) {
162162
let mut rcx = Rcx::new(fcx, blk.id);
163163
if fcx.err_count_since_creation() == 0 {
164164
// regionck assumes typeck succeeded
165-
rcx.visit_fn_body(id, blk);
165+
rcx.visit_fn_body(id, decl, blk);
166166
}
167167

168168
// Region checking a fn can introduce new trait obligations,
@@ -328,6 +328,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
328328

329329
fn visit_fn_body(&mut self,
330330
id: ast::NodeId,
331+
fn_decl: &ast::FnDecl,
331332
body: &ast::Block)
332333
{
333334
// When we enter a function, we can derive
@@ -343,6 +344,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
343344

344345
let len = self.region_param_pairs.len();
345346
self.relate_free_regions(fn_sig.as_slice(), body.id);
347+
link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs.as_slice());
346348
self.visit_block(body);
347349
self.visit_region_obligations(body.id);
348350
self.region_param_pairs.truncate(len);
@@ -480,9 +482,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Rcx<'a, 'tcx> {
480482
// hierarchy, and in particular the relationships between free
481483
// regions, until regionck, as described in #3238.
482484

483-
fn visit_fn(&mut self, _fk: visit::FnKind<'v>, _fd: &'v ast::FnDecl,
485+
fn visit_fn(&mut self, _fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
484486
b: &'v ast::Block, _s: Span, id: ast::NodeId) {
485-
self.visit_fn_body(id, b)
487+
self.visit_fn_body(id, fd, b)
486488
}
487489

488490
fn visit_item(&mut self, i: &ast::Item) { visit_item(self, i); }
@@ -1288,7 +1290,6 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
12881290
/// then ensures that the lifetime of the resulting pointer is
12891291
/// linked to the lifetime of its guarantor (if any).
12901292
fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
1291-
12921293
debug!("regionck::for_match()");
12931294
let mc = mc::MemCategorizationContext::new(rcx);
12941295
let discr_cmt = ignore_err!(mc.cat_expr(discr));
@@ -1300,12 +1301,32 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
13001301
}
13011302
}
13021303

1304+
/// Computes the guarantors for any ref bindings in a match and
1305+
/// then ensures that the lifetime of the resulting pointer is
1306+
/// linked to the lifetime of its guarantor (if any).
1307+
fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) {
1308+
debug!("regionck::link_fn_args(body_scope={})", body_scope);
1309+
let mc = mc::MemCategorizationContext::new(rcx);
1310+
for arg in args.iter() {
1311+
let arg_ty = rcx.fcx.node_ty(arg.id);
1312+
let re_scope = ty::ReScope(body_scope);
1313+
let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
1314+
debug!("arg_ty={} arg_cmt={}",
1315+
arg_ty.repr(rcx.tcx()),
1316+
arg_cmt.repr(rcx.tcx()));
1317+
link_pattern(rcx, mc, arg_cmt, &*arg.pat);
1318+
}
1319+
}
1320+
13031321
/// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if
13041322
/// needed.
13051323
fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
13061324
mc: mc::MemCategorizationContext<Rcx<'a, 'tcx>>,
13071325
discr_cmt: mc::cmt<'tcx>,
13081326
root_pat: &ast::Pat) {
1327+
debug!("link_pattern(discr_cmt={}, root_pat={})",
1328+
discr_cmt.repr(rcx.tcx()),
1329+
root_pat.repr(rcx.tcx()));
13091330
let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
13101331
match sub_pat.node {
13111332
// `ref x` pattern
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that region inference correctly links up the regions when a
12+
// `ref` borrow occurs inside a fn argument.
13+
14+
#![allow(dead_code)]
15+
16+
fn with<'a>(_: |&'a Vec<int>| -> &'a Vec<int>) { }
17+
18+
fn foo() {
19+
with(|&ref ints| ints);
20+
}
21+
22+
fn main() { }

0 commit comments

Comments
 (0)