auto merge of #18546 : bkoropoff/rust/unboxed-closures-cross-crate, r=nick29581
This fixes some metadata/AST encoding problems that lead to ICEs. The way this is currently handled will need revisiting if abstract return types are added, as unboxed closure types from extern crates could show up without being inlined into the local crate. Closes #16790 (I think this was fixed earlier by accident and just needed a test case) Closes #18378 Closes #18543 r? @pcwalton
This commit is contained in:
commit
98958bcaf4
5 changed files with 94 additions and 37 deletions
|
@ -55,6 +55,9 @@ pub enum DefIdSource {
|
||||||
|
|
||||||
// Identifies a region parameter (`fn foo<'X>() { ... }`).
|
// Identifies a region parameter (`fn foo<'X>() { ... }`).
|
||||||
RegionParameter,
|
RegionParameter,
|
||||||
|
|
||||||
|
// Identifies an unboxed closure
|
||||||
|
UnboxedClosureSource
|
||||||
}
|
}
|
||||||
pub type conv_did<'a> =
|
pub type conv_did<'a> =
|
||||||
|source: DefIdSource, ast::DefId|: 'a -> ast::DefId;
|
|source: DefIdSource, ast::DefId|: 'a -> ast::DefId;
|
||||||
|
@ -464,7 +467,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||||
}
|
}
|
||||||
'k' => {
|
'k' => {
|
||||||
assert_eq!(next(st), '[');
|
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 region = parse_region(st, |x,y| conv(x,y));
|
||||||
let substs = parse_substs(st, |x,y| conv(x,y));
|
let substs = parse_substs(st, |x,y| conv(x,y));
|
||||||
assert_eq!(next(st), ']');
|
assert_eq!(next(st), ']');
|
||||||
|
|
|
@ -21,7 +21,7 @@ use metadata::encoder as e;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use metadata::tydecode;
|
use metadata::tydecode;
|
||||||
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
|
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
|
||||||
use metadata::tydecode::{RegionParameter};
|
use metadata::tydecode::{RegionParameter, UnboxedClosureSource};
|
||||||
use metadata::tyencode;
|
use metadata::tyencode;
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
|
@ -1728,12 +1728,14 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||||
"FnMutUnboxedClosureKind",
|
"FnMutUnboxedClosureKind",
|
||||||
"FnOnceUnboxedClosureKind"
|
"FnOnceUnboxedClosureKind"
|
||||||
];
|
];
|
||||||
let kind = self.read_enum_variant(variants, |_, i| {
|
let kind = self.read_enum("UnboxedClosureKind", |this| {
|
||||||
Ok(match i {
|
this.read_enum_variant(variants, |_, i| {
|
||||||
0 => ty::FnUnboxedClosureKind,
|
Ok(match i {
|
||||||
1 => ty::FnMutUnboxedClosureKind,
|
0 => ty::FnUnboxedClosureKind,
|
||||||
2 => ty::FnOnceUnboxedClosureKind,
|
1 => ty::FnMutUnboxedClosureKind,
|
||||||
_ => panic!("bad enum variant for ty::UnboxedClosureKind"),
|
2 => ty::FnOnceUnboxedClosureKind,
|
||||||
|
_ => panic!("bad enum variant for ty::UnboxedClosureKind"),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
ty::UnboxedClosure {
|
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
|
* case. We translate them with `tr_def_id()` which will map
|
||||||
* the crate numbers back to the original source crate.
|
* 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
|
* It'd be really nice to refactor the type repr to not include
|
||||||
* def-ids so that all these distinctions were unnecessary.
|
* def-ids so that all these distinctions were unnecessary.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let r = match source {
|
let r = match source {
|
||||||
NominalType | TypeWithId | RegionParameter => dcx.tr_def_id(did),
|
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);
|
debug!("convert_def_id(source={}, did={})={}", source, did, r);
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -4625,35 +4625,37 @@ pub struct UnboxedClosureUpvar {
|
||||||
// Returns a list of `UnboxedClosureUpvar`s for each upvar.
|
// Returns a list of `UnboxedClosureUpvar`s for each upvar.
|
||||||
pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId, substs: &Substs)
|
pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId, substs: &Substs)
|
||||||
-> Vec<UnboxedClosureUpvar> {
|
-> Vec<UnboxedClosureUpvar> {
|
||||||
if closure_id.krate == ast::LOCAL_CRATE {
|
// Presently an unboxed closure type cannot "escape" out of a
|
||||||
let capture_mode = tcx.capture_modes.borrow().get_copy(&closure_id.node);
|
// function, so we will only encounter ones that originated in the
|
||||||
match tcx.freevars.borrow().find(&closure_id.node) {
|
// local crate or were inlined into it along with some function.
|
||||||
None => vec![],
|
// This may change if abstract return types of some sort are
|
||||||
Some(ref freevars) => {
|
// implemented.
|
||||||
freevars.iter().map(|freevar| {
|
assert!(closure_id.krate == ast::LOCAL_CRATE);
|
||||||
let freevar_def_id = freevar.def.def_id();
|
let capture_mode = tcx.capture_modes.borrow().get_copy(&closure_id.node);
|
||||||
let freevar_ty = node_id_to_type(tcx, freevar_def_id.node);
|
match tcx.freevars.borrow().find(&closure_id.node) {
|
||||||
let mut freevar_ty = freevar_ty.subst(tcx, substs);
|
None => vec![],
|
||||||
if capture_mode == ast::CaptureByRef {
|
Some(ref freevars) => {
|
||||||
let borrow = tcx.upvar_borrow_map.borrow().get_copy(&ty::UpvarId {
|
freevars.iter().map(|freevar| {
|
||||||
var_id: freevar_def_id.node,
|
let freevar_def_id = freevar.def.def_id();
|
||||||
closure_expr_id: closure_id.node
|
let freevar_ty = node_id_to_type(tcx, freevar_def_id.node);
|
||||||
});
|
let mut freevar_ty = freevar_ty.subst(tcx, substs);
|
||||||
freevar_ty = mk_rptr(tcx, borrow.region, ty::mt {
|
if capture_mode == ast::CaptureByRef {
|
||||||
ty: freevar_ty,
|
let borrow = tcx.upvar_borrow_map.borrow().get_copy(&ty::UpvarId {
|
||||||
mutbl: borrow.kind.to_mutbl_lossy()
|
var_id: freevar_def_id.node,
|
||||||
});
|
closure_expr_id: closure_id.node
|
||||||
}
|
});
|
||||||
UnboxedClosureUpvar {
|
freevar_ty = mk_rptr(tcx, borrow.region, ty::mt {
|
||||||
def: freevar.def,
|
ty: freevar_ty,
|
||||||
span: freevar.span,
|
mutbl: borrow.kind.to_mutbl_lossy()
|
||||||
ty: freevar_ty
|
});
|
||||||
}
|
}
|
||||||
}).collect()
|
UnboxedClosureUpvar {
|
||||||
}
|
def: freevar.def,
|
||||||
|
span: freevar.span,
|
||||||
|
ty: freevar_ty
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
tcx.sess.bug("unimplemented cross-crate closure upvars")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/test/auxiliary/unboxed-closures-cross-crate.rs
Normal file
26
src/test/auxiliary/unboxed-closures-cross-crate.rs
Normal file
|
@ -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()
|
||||||
|
}
|
20
src/test/run-pass/unboxed-closures-cross-crate.rs
Normal file
20
src/test/run-pass/unboxed-closures-cross-crate.rs
Normal file
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in a new issue