diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 6e7a6dfa094..b9660dbd466 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -55,6 +55,9 @@ pub enum DefIdSource { // Identifies a region parameter (`fn foo<'X>() { ... }`). RegionParameter, + + // Identifies an unboxed closure + UnboxedClosureSource } pub type conv_did<'a> = |source: DefIdSource, ast::DefId|: 'a -> ast::DefId; @@ -464,7 +467,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { } 'k' => { assert_eq!(next(st), '['); - let did = parse_def(st, NominalType, |x,y| conv(x,y)); + let did = parse_def(st, UnboxedClosureSource, |x,y| conv(x,y)); let region = parse_region(st, |x,y| conv(x,y)); let substs = parse_substs(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 0074c15defb..5410417ec3f 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -21,7 +21,7 @@ use metadata::encoder as e; use middle::region; use metadata::tydecode; use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter}; -use metadata::tydecode::{RegionParameter}; +use metadata::tydecode::{RegionParameter, UnboxedClosureSource}; use metadata::tyencode; use middle::mem_categorization::Typer; use middle::subst; @@ -1728,12 +1728,14 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { "FnMutUnboxedClosureKind", "FnOnceUnboxedClosureKind" ]; - let kind = self.read_enum_variant(variants, |_, i| { - Ok(match i { - 0 => ty::FnUnboxedClosureKind, - 1 => ty::FnMutUnboxedClosureKind, - 2 => ty::FnOnceUnboxedClosureKind, - _ => panic!("bad enum variant for ty::UnboxedClosureKind"), + let kind = self.read_enum("UnboxedClosureKind", |this| { + this.read_enum_variant(variants, |_, i| { + Ok(match i { + 0 => ty::FnUnboxedClosureKind, + 1 => ty::FnMutUnboxedClosureKind, + 2 => ty::FnOnceUnboxedClosureKind, + _ => panic!("bad enum variant for ty::UnboxedClosureKind"), + }) }) }).unwrap(); ty::UnboxedClosure { @@ -1771,13 +1773,17 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { * case. We translate them with `tr_def_id()` which will map * the crate numbers back to the original source crate. * + * Unboxed closures are cloned along with the function being + * inlined, and all side tables use interned node IDs, so we + * translate their def IDs accordingly. + * * It'd be really nice to refactor the type repr to not include * def-ids so that all these distinctions were unnecessary. */ let r = match source { NominalType | TypeWithId | RegionParameter => dcx.tr_def_id(did), - TypeParameter => dcx.tr_intern_def_id(did) + TypeParameter | UnboxedClosureSource => dcx.tr_intern_def_id(did) }; debug!("convert_def_id(source={}, did={})={}", source, did, r); return r; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a94b188cb28..bdb9ef8e710 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4625,35 +4625,37 @@ pub struct UnboxedClosureUpvar { // Returns a list of `UnboxedClosureUpvar`s for each upvar. pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId, substs: &Substs) -> Vec { - if closure_id.krate == ast::LOCAL_CRATE { - let capture_mode = tcx.capture_modes.borrow().get_copy(&closure_id.node); - match tcx.freevars.borrow().find(&closure_id.node) { - None => vec![], - Some(ref freevars) => { - freevars.iter().map(|freevar| { - let freevar_def_id = freevar.def.def_id(); - let freevar_ty = node_id_to_type(tcx, freevar_def_id.node); - let mut freevar_ty = freevar_ty.subst(tcx, substs); - if capture_mode == ast::CaptureByRef { - let borrow = tcx.upvar_borrow_map.borrow().get_copy(&ty::UpvarId { - var_id: freevar_def_id.node, - closure_expr_id: closure_id.node - }); - freevar_ty = mk_rptr(tcx, borrow.region, ty::mt { - ty: freevar_ty, - mutbl: borrow.kind.to_mutbl_lossy() - }); - } - UnboxedClosureUpvar { - def: freevar.def, - span: freevar.span, - ty: freevar_ty - } - }).collect() - } + // Presently an unboxed closure type cannot "escape" out of a + // function, so we will only encounter ones that originated in the + // local crate or were inlined into it along with some function. + // This may change if abstract return types of some sort are + // implemented. + assert!(closure_id.krate == ast::LOCAL_CRATE); + let capture_mode = tcx.capture_modes.borrow().get_copy(&closure_id.node); + match tcx.freevars.borrow().find(&closure_id.node) { + None => vec![], + Some(ref freevars) => { + freevars.iter().map(|freevar| { + let freevar_def_id = freevar.def.def_id(); + let freevar_ty = node_id_to_type(tcx, freevar_def_id.node); + let mut freevar_ty = freevar_ty.subst(tcx, substs); + if capture_mode == ast::CaptureByRef { + let borrow = tcx.upvar_borrow_map.borrow().get_copy(&ty::UpvarId { + var_id: freevar_def_id.node, + closure_expr_id: closure_id.node + }); + freevar_ty = mk_rptr(tcx, borrow.region, ty::mt { + ty: freevar_ty, + mutbl: borrow.kind.to_mutbl_lossy() + }); + } + UnboxedClosureUpvar { + def: freevar.def, + span: freevar.span, + ty: freevar_ty + } + }).collect() } - } else { - tcx.sess.bug("unimplemented cross-crate closure upvars") } } diff --git a/src/test/auxiliary/unboxed-closures-cross-crate.rs b/src/test/auxiliary/unboxed-closures-cross-crate.rs new file mode 100644 index 00000000000..d04829bb808 --- /dev/null +++ b/src/test/auxiliary/unboxed-closures-cross-crate.rs @@ -0,0 +1,26 @@ +// 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. + +#![feature(unboxed_closures, overloaded_calls)] + +#[inline] +pub fn has_closures() -> uint { + let x = 1u; + let mut f = move |&mut:| x; + let y = 1u; + let g = |:| y; + f() + g() +} + +pub fn has_generic_closures + Copy>(x: T, y: T) -> T { + let mut f = move |&mut:| x; + let g = |:| y; + f() + g() +} diff --git a/src/test/run-pass/unboxed-closures-cross-crate.rs b/src/test/run-pass/unboxed-closures-cross-crate.rs new file mode 100644 index 00000000000..3babaa2b7e5 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-cross-crate.rs @@ -0,0 +1,20 @@ +// 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 unboxed closures work with cross-crate inlining +// Acts as a regression test for #16790, #18378 and #18543 + +// aux-build:unboxed-closures-cross-crate.rs +extern crate "unboxed-closures-cross-crate" as ubcc; + +fn main() { + assert_eq!(ubcc::has_closures(), 2u); + assert_eq!(ubcc::has_generic_closures(2u, 3u), 5u); +}