about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/metadata/tydecode.rs5
-rw-r--r--src/librustc/middle/astencode.rs22
-rw-r--r--src/librustc/middle/ty.rs58
-rw-r--r--src/test/auxiliary/unboxed-closures-cross-crate.rs26
-rw-r--r--src/test/run-pass/unboxed-closures-cross-crate.rs20
5 files changed, 94 insertions, 37 deletions
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<UnboxedClosureUpvar> {
-    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 <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.
+
+#![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<T: Add<T,T> + 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 <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 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);
+}