From 28f70d34400959cd2e0095d019b53dba244b900b Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Sun, 2 Nov 2014 00:16:38 -0700 Subject: [PATCH 1/3] Fix decoding of unboxed closure kinds Closes #18378. Note that cross-crate unboxed closures are still unimplemented and will fail to work currently. --- src/librustc/middle/astencode.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3d2bd763a14..692a815c63c 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1756,12 +1756,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 { From 9b322a6a90420759724471ca018b90603e8b1497 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Sun, 2 Nov 2014 11:34:18 -0800 Subject: [PATCH 2/3] Treat cross-crate unboxed closure def IDs consistently Always translate the ID into the local crate ID space since presently the only way to encounter an unboxed closure type from another crate is to inline once of its functions. This may need to change if abstract return types are added. Closes #18543 --- src/librustc/metadata/tydecode.rs | 5 ++- src/librustc/middle/astencode.rs | 8 +++-- src/librustc/middle/ty.rs | 58 ++++++++++++++++--------------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index a52d02ccca7..d475f6ddcba 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -56,6 +56,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; @@ -465,7 +468,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 692a815c63c..a127566b67e 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; @@ -1801,13 +1801,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 b9af31665a1..faeca0b1886 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4632,35 +4632,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") } } From bfa5320527b838e1b735a2999acbe1f55b034205 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Sun, 2 Nov 2014 11:44:15 -0800 Subject: [PATCH 3/3] Add regression test for #16790, #18378 and #18543 --- .../auxiliary/unboxed-closures-cross-crate.rs | 26 +++++++++++++++++++ .../run-pass/unboxed-closures-cross-crate.rs | 20 ++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/test/auxiliary/unboxed-closures-cross-crate.rs create mode 100644 src/test/run-pass/unboxed-closures-cross-crate.rs 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); +}