Skip to content

Commit 59cfe90

Browse files
trans: Avoid weak linkage for closures when linking with MinGW.
1 parent 535cea0 commit 59cfe90

File tree

6 files changed

+97
-41
lines changed

6 files changed

+97
-41
lines changed

Diff for: src/librustc/session/config.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,11 @@ impl Options {
330330
self.debugging_opts.dump_dep_graph ||
331331
self.debugging_opts.query_dep_graph
332332
}
333+
334+
pub fn single_codegen_unit(&self) -> bool {
335+
self.incremental.is_none() ||
336+
self.cg.codegen_units == 1
337+
}
333338
}
334339

335340
// The type of entry function, so
@@ -655,7 +660,6 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
655660
"panic strategy to compile crate with"),
656661
}
657662

658-
659663
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
660664
build_debugging_options, "Z", "debugging",
661665
DB_OPTIONS, db_type_desc, dbsetters,

Diff for: src/librustc_back/target/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,13 @@ pub struct TargetOptions {
292292
pub is_like_android: bool,
293293
/// Whether the linker support GNU-like arguments such as -O. Defaults to false.
294294
pub linker_is_gnu: bool,
295+
/// The MinGW toolchain has a known issue that prevents it from correctly
296+
/// handling COFF object files with more than 2^15 sections. Since each weak
297+
/// symbol needs its own COMDAT section, weak linkage implies a large
298+
/// number sections that easily exceeds the given limit for larger
299+
/// codebases. Consequently we want a way to disallow weak linkage on some
300+
/// platforms.
301+
pub allows_weak_linkage: bool,
295302
/// Whether the linker support rpaths or not. Defaults to false.
296303
pub has_rpath: bool,
297304
/// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
@@ -367,6 +374,7 @@ impl Default for TargetOptions {
367374
is_like_android: false,
368375
is_like_msvc: false,
369376
linker_is_gnu: false,
377+
allows_weak_linkage: true,
370378
has_rpath: false,
371379
no_compiler_rt: false,
372380
no_default_libraries: true,
@@ -509,6 +517,7 @@ impl Target {
509517
key!(is_like_msvc, bool);
510518
key!(is_like_android, bool);
511519
key!(linker_is_gnu, bool);
520+
key!(allows_weak_linkage, bool);
512521
key!(has_rpath, bool);
513522
key!(no_compiler_rt, bool);
514523
key!(no_default_libraries, bool);
@@ -651,6 +660,7 @@ impl ToJson for Target {
651660
target_option_val!(is_like_msvc);
652661
target_option_val!(is_like_android);
653662
target_option_val!(linker_is_gnu);
663+
target_option_val!(allows_weak_linkage);
654664
target_option_val!(has_rpath);
655665
target_option_val!(no_compiler_rt);
656666
target_option_val!(no_default_libraries);

Diff for: src/librustc_back/target/windows_base.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub fn opts() -> TargetOptions {
2525
staticlib_suffix: ".lib".to_string(),
2626
no_default_libraries: true,
2727
is_like_windows: true,
28+
allows_weak_linkage: false,
2829
pre_link_args: vec!(
2930
// And here, we see obscure linker flags #45. On windows, it has been
3031
// found to be necessary to have this flag to compile liblibc.

Diff for: src/librustc_trans/closure.rs

+75-2
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,41 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
181181
llfn
182182
}
183183

184+
fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext,
185+
closure_def_id: DefId)
186+
-> bool {
187+
let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
188+
let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
189+
let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert);
190+
191+
!use_mir
192+
}
193+
194+
pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
195+
closure_def_id: DefId,
196+
closure_substs: ty::ClosureSubsts<'tcx>) {
197+
use syntax::ast::DUMMY_NODE_ID;
198+
use syntax_pos::DUMMY_SP;
199+
use syntax::ptr::P;
200+
201+
trans_closure_expr(Dest::Ignore(ccx),
202+
&hir::FnDecl {
203+
inputs: P::new(),
204+
output: hir::NoReturn(DUMMY_SP),
205+
variadic: false
206+
},
207+
&hir::Block {
208+
stmts: P::new(),
209+
expr: None,
210+
id: DUMMY_NODE_ID,
211+
rules: hir::DefaultBlock,
212+
span: DUMMY_SP
213+
},
214+
DUMMY_NODE_ID,
215+
closure_def_id,
216+
closure_substs);
217+
}
218+
184219
pub enum Dest<'a, 'tcx: 'a> {
185220
SaveIn(Block<'a, 'tcx>, ValueRef),
186221
Ignore(&'a CrateContext<'a, 'tcx>)
@@ -213,8 +248,13 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
213248
// If we have not done so yet, translate this closure's body
214249
if !ccx.instances().borrow().contains_key(&instance) {
215250
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);
251+
252+
if ccx.sess().target.target.options.allows_weak_linkage {
253+
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
254+
llvm::SetUniqueComdat(ccx.llmod(), llfn);
255+
} else {
256+
llvm::SetLinkage(llfn, llvm::InternalLinkage);
257+
}
218258

219259
// set an inline hint for all closures
220260
attributes::inline(llfn, attributes::InlineAttr::Hint);
@@ -296,6 +336,39 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
296336
// If this is a closure, redirect to it.
297337
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
298338

339+
// If weak linkage is not allowed, we have to make sure that a local,
340+
// private copy of the closure is available in this codegen unit
341+
if !ccx.sess().target.target.options.allows_weak_linkage &&
342+
!ccx.sess().opts.single_codegen_unit() {
343+
344+
if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) {
345+
// If the closure is defined in the local crate, we can always just
346+
// translate it.
347+
let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node {
348+
hir::ExprClosure(_, ref decl, ref body, _) => (decl, body),
349+
_ => { unreachable!() }
350+
};
351+
352+
trans_closure_expr(Dest::Ignore(ccx),
353+
decl,
354+
body,
355+
node_id,
356+
closure_def_id,
357+
substs);
358+
} else {
359+
// If the closure is defined in an upstream crate, we can only
360+
// translate it if MIR-trans is active.
361+
362+
if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) {
363+
ccx.sess().fatal("You have run into a known limitation of the \
364+
MingW toolchain. Either compile with -Zorbit or \
365+
with -Ccodegen-units=1 to work around it.");
366+
}
367+
368+
trans_closure_body_via_mir(ccx, closure_def_id, substs);
369+
}
370+
}
371+
299372
// If the closure is a Fn closure, but a FnOnce is needed (etc),
300373
// then adapt the self type
301374
let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);

Diff for: src/librustc_trans/mir/constant.rs

+3-19
Original file line numberDiff line numberDiff line change
@@ -530,26 +530,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
530530

531531
// FIXME Shouldn't need to manually trigger closure instantiations.
532532
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
533-
use rustc::hir;
534-
use syntax::ast::DUMMY_NODE_ID;
535-
use syntax::ptr::P;
536533
use closure;
537-
538-
closure::trans_closure_expr(closure::Dest::Ignore(self.ccx),
539-
&hir::FnDecl {
540-
inputs: P::new(),
541-
output: hir::NoReturn(DUMMY_SP),
542-
variadic: false
543-
},
544-
&hir::Block {
545-
stmts: P::new(),
546-
expr: None,
547-
id: DUMMY_NODE_ID,
548-
rules: hir::DefaultBlock,
549-
span: DUMMY_SP
550-
},
551-
DUMMY_NODE_ID, def_id,
552-
self.monomorphize(&substs));
534+
closure::trans_closure_body_via_mir(self.ccx,
535+
def_id,
536+
self.monomorphize(&substs));
553537
}
554538

555539
let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {

Diff for: src/librustc_trans/mir/rvalue.rs

+3-19
Original file line numberDiff line numberDiff line change
@@ -131,27 +131,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
131131
_ => {
132132
// FIXME Shouldn't need to manually trigger closure instantiations.
133133
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
134-
use rustc::hir;
135-
use syntax::ast::DUMMY_NODE_ID;
136-
use syntax::ptr::P;
137-
use syntax_pos::DUMMY_SP;
138134
use closure;
139135

140-
closure::trans_closure_expr(closure::Dest::Ignore(bcx.ccx()),
141-
&hir::FnDecl {
142-
inputs: P::new(),
143-
output: hir::NoReturn(DUMMY_SP),
144-
variadic: false
145-
},
146-
&hir::Block {
147-
stmts: P::new(),
148-
expr: None,
149-
id: DUMMY_NODE_ID,
150-
rules: hir::DefaultBlock,
151-
span: DUMMY_SP
152-
},
153-
DUMMY_NODE_ID, def_id,
154-
bcx.monomorphize(&substs));
136+
closure::trans_closure_body_via_mir(bcx.ccx(),
137+
def_id,
138+
bcx.monomorphize(&substs));
155139
}
156140

157141
for (i, operand) in operands.iter().enumerate() {

0 commit comments

Comments
 (0)