Skip to content

Commit 7323ac4

Browse files
authored
Auto merge of #34728 - michaelwoerister:issue34569, r=luqmana
trans: Make sure that closures only get translated once. Fixes #34569.
2 parents 459b1a4 + b732cf4 commit 7323ac4

File tree

2 files changed

+74
-40
lines changed

2 files changed

+74
-40
lines changed

src/librustc_trans/closure.rs

+48-40
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,14 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
169169
}));
170170
let llfn = declare::declare_fn(ccx, &symbol, function_type);
171171

172-
// set an inline hint for all closures
173-
attributes::inline(llfn, attributes::InlineAttr::Hint);
174172
attributes::set_frame_pointer_elimination(ccx, llfn);
175173

176174
debug!("get_or_create_declaration_if_closure(): inserting new \
177175
closure {:?}: {:?}",
178176
instance, Value(llfn));
179-
ccx.instances().borrow_mut().insert(instance, llfn);
177+
178+
// NOTE: We do *not* store llfn in the ccx.instances() map here,
179+
// that is only done, when the closures body is translated.
180180

181181
llfn
182182
}
@@ -197,8 +197,8 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
197197
// (*) Note that in the case of inlined functions, the `closure_def_id` will be the
198198
// defid of the closure in its original crate, whereas `id` will be the id of the local
199199
// inlined copy.
200-
201-
let param_substs = closure_substs.func_substs;
200+
debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
201+
id, closure_def_id, closure_substs);
202202

203203
let ccx = match dest {
204204
Dest::SaveIn(bcx, _) => bcx.ccx(),
@@ -207,41 +207,49 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
207207
let tcx = ccx.tcx();
208208
let _icx = push_ctxt("closure::trans_closure_expr");
209209

210-
debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
211-
id, closure_def_id, closure_substs);
212-
213-
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
214-
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
215-
llvm::SetUniqueComdat(ccx.llmod(), llfn);
216-
217-
// Get the type of this closure. Use the current `param_substs` as
218-
// the closure substitutions. This makes sense because the closure
219-
// takes the same set of type arguments as the enclosing fn, and
220-
// this function (`trans_closure`) is invoked at the point
221-
// of the closure expression.
222-
223-
let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
224-
let sig = tcx.erase_late_bound_regions(sig);
225-
let sig = tcx.normalize_associated_type(&sig);
226-
227-
let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
228-
closure_substs);
229-
let sig = ty::FnSig {
230-
inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
231-
.into_iter().chain(sig.inputs).collect(),
232-
output: sig.output,
233-
variadic: false
234-
};
235-
236-
trans_closure(ccx,
237-
decl,
238-
body,
239-
llfn,
240-
Instance::new(closure_def_id, param_substs),
241-
id,
242-
&sig,
243-
Abi::RustCall,
244-
ClosureEnv::Closure(closure_def_id, id));
210+
let param_substs = closure_substs.func_substs;
211+
let instance = Instance::new(closure_def_id, param_substs);
212+
213+
// If we have not done so yet, translate this closure's body
214+
if !ccx.instances().borrow().contains_key(&instance) {
215+
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
216+
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
217+
llvm::SetUniqueComdat(ccx.llmod(), llfn);
218+
219+
// set an inline hint for all closures
220+
attributes::inline(llfn, attributes::InlineAttr::Hint);
221+
222+
// Get the type of this closure. Use the current `param_substs` as
223+
// the closure substitutions. This makes sense because the closure
224+
// takes the same set of type arguments as the enclosing fn, and
225+
// this function (`trans_closure`) is invoked at the point
226+
// of the closure expression.
227+
228+
let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
229+
let sig = tcx.erase_late_bound_regions(sig);
230+
let sig = tcx.normalize_associated_type(&sig);
231+
232+
let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
233+
closure_substs);
234+
let sig = ty::FnSig {
235+
inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
236+
.into_iter().chain(sig.inputs).collect(),
237+
output: sig.output,
238+
variadic: false
239+
};
240+
241+
trans_closure(ccx,
242+
decl,
243+
body,
244+
llfn,
245+
Instance::new(closure_def_id, param_substs),
246+
id,
247+
&sig,
248+
Abi::RustCall,
249+
ClosureEnv::Closure(closure_def_id, id));
250+
251+
ccx.instances().borrow_mut().insert(instance, llfn);
252+
}
245253

246254
// Don't hoist this to the top of the function. It's perfectly legitimate
247255
// to have a zero-size closure (in which case dest will be `Ignore`) and

src/test/run-pass/issue34569.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-g
12+
13+
// In this test we just want to make sure that the code below does not lead to
14+
// a debuginfo verification assertion during compilation. This was caused by the
15+
// closure in the guard being translated twice due to how match expressions are
16+
// handled.
17+
//
18+
// See https://github.com/rust-lang/rust/issues/34569 for details.
19+
20+
fn main() {
21+
match 0 {
22+
e if (|| { e == 0 })() => {},
23+
1 => {},
24+
_ => {}
25+
}
26+
}

0 commit comments

Comments
 (0)