diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cdf34c7f4d2f3..2445087c24c96 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 2aec4393de942..80ee2cce4ce70 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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>, 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 diff --git a/src/test/run-pass/regions-link-fn-args.rs b/src/test/run-pass/regions-link-fn-args.rs new file mode 100644 index 0000000000000..2823622bdf6d9 --- /dev/null +++ b/src/test/run-pass/regions-link-fn-args.rs @@ -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 or the MIT license +// , 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| -> &'a Vec) { } + +fn foo() { + with(|&ref ints| ints); +} + +fn main() { }