trans: Make sure that closures only get translated once.

This commit is contained in:
Michael Woerister 2016-07-08 20:24:46 -04:00
parent d11936251a
commit b732cf46f8
2 changed files with 69 additions and 35 deletions

View File

@ -169,14 +169,14 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
})); }));
let llfn = declare::declare_fn(ccx, &symbol, function_type); let llfn = declare::declare_fn(ccx, &symbol, function_type);
// set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint);
attributes::set_frame_pointer_elimination(ccx, llfn); attributes::set_frame_pointer_elimination(ccx, llfn);
debug!("get_or_create_declaration_if_closure(): inserting new \ debug!("get_or_create_declaration_if_closure(): inserting new \
closure {:?}: {:?}", closure {:?}: {:?}",
instance, Value(llfn)); instance, Value(llfn));
ccx.instances().borrow_mut().insert(instance, llfn);
// NOTE: We do *not* store llfn in the ccx.instances() map here,
// that is only done, when the closures body is translated.
llfn llfn
} }
@ -197,8 +197,8 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
// (*) Note that in the case of inlined functions, the `closure_def_id` will be the // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
// defid of the closure in its original crate, whereas `id` will be the id of the local // defid of the closure in its original crate, whereas `id` will be the id of the local
// inlined copy. // inlined copy.
debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
let param_substs = closure_substs.func_substs; id, closure_def_id, closure_substs);
let ccx = match dest { let ccx = match dest {
Dest::SaveIn(bcx, _) => bcx.ccx(), Dest::SaveIn(bcx, _) => bcx.ccx(),
@ -207,41 +207,49 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
let tcx = ccx.tcx(); let tcx = ccx.tcx();
let _icx = push_ctxt("closure::trans_closure_expr"); let _icx = push_ctxt("closure::trans_closure_expr");
debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})", let param_substs = closure_substs.func_substs;
id, closure_def_id, closure_substs); let instance = Instance::new(closure_def_id, param_substs);
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); // If we have not done so yet, translate this closure's body
llvm::SetLinkage(llfn, llvm::WeakODRLinkage); if !ccx.instances().borrow().contains_key(&instance) {
llvm::SetUniqueComdat(ccx.llmod(), llfn); let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
llvm::SetUniqueComdat(ccx.llmod(), llfn);
// Get the type of this closure. Use the current `param_substs` as // set an inline hint for all closures
// the closure substitutions. This makes sense because the closure attributes::inline(llfn, attributes::InlineAttr::Hint);
// takes the same set of type arguments as the enclosing fn, and
// this function (`trans_closure`) is invoked at the point
// of the closure expression.
let sig = &tcx.closure_type(closure_def_id, closure_substs).sig; // Get the type of this closure. Use the current `param_substs` as
let sig = tcx.erase_late_bound_regions(sig); // the closure substitutions. This makes sense because the closure
let sig = tcx.normalize_associated_type(&sig); // takes the same set of type arguments as the enclosing fn, and
// this function (`trans_closure`) is invoked at the point
// of the closure expression.
let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id, let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
closure_substs); let sig = tcx.erase_late_bound_regions(sig);
let sig = ty::FnSig { let sig = tcx.normalize_associated_type(&sig);
inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
.into_iter().chain(sig.inputs).collect(),
output: sig.output,
variadic: false
};
trans_closure(ccx, let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
decl, closure_substs);
body, let sig = ty::FnSig {
llfn, inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
Instance::new(closure_def_id, param_substs), .into_iter().chain(sig.inputs).collect(),
id, output: sig.output,
&sig, variadic: false
Abi::RustCall, };
ClosureEnv::Closure(closure_def_id, id));
trans_closure(ccx,
decl,
body,
llfn,
Instance::new(closure_def_id, param_substs),
id,
&sig,
Abi::RustCall,
ClosureEnv::Closure(closure_def_id, id));
ccx.instances().borrow_mut().insert(instance, llfn);
}
// Don't hoist this to the top of the function. It's perfectly legitimate // Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size closure (in which case dest will be `Ignore`) and // to have a zero-size closure (in which case dest will be `Ignore`) and

View File

@ -0,0 +1,26 @@
// Copyright 2016 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.
// compile-flags:-g
// In this test we just want to make sure that the code below does not lead to
// a debuginfo verification assertion during compilation. This was caused by the
// closure in the guard being translated twice due to how match expressions are
// handled.
//
// See https://github.com/rust-lang/rust/issues/34569 for details.
fn main() {
match 0 {
e if (|| { e == 0 })() => {},
1 => {},
_ => {}
}
}