trans: Avoid weak linkage for closures when linking with MinGW.
This commit is contained in:
parent
535cea0eec
commit
59cfe904dc
@ -330,6 +330,11 @@ impl Options {
|
||||
self.debugging_opts.dump_dep_graph ||
|
||||
self.debugging_opts.query_dep_graph
|
||||
}
|
||||
|
||||
pub fn single_codegen_unit(&self) -> bool {
|
||||
self.incremental.is_none() ||
|
||||
self.cg.codegen_units == 1
|
||||
}
|
||||
}
|
||||
|
||||
// The type of entry function, so
|
||||
@ -655,7 +660,6 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
||||
"panic strategy to compile crate with"),
|
||||
}
|
||||
|
||||
|
||||
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
build_debugging_options, "Z", "debugging",
|
||||
DB_OPTIONS, db_type_desc, dbsetters,
|
||||
|
@ -292,6 +292,13 @@ pub struct TargetOptions {
|
||||
pub is_like_android: bool,
|
||||
/// Whether the linker support GNU-like arguments such as -O. Defaults to false.
|
||||
pub linker_is_gnu: bool,
|
||||
/// The MinGW toolchain has a known issue that prevents it from correctly
|
||||
/// handling COFF object files with more than 2^15 sections. Since each weak
|
||||
/// symbol needs its own COMDAT section, weak linkage implies a large
|
||||
/// number sections that easily exceeds the given limit for larger
|
||||
/// codebases. Consequently we want a way to disallow weak linkage on some
|
||||
/// platforms.
|
||||
pub allows_weak_linkage: bool,
|
||||
/// Whether the linker support rpaths or not. Defaults to false.
|
||||
pub has_rpath: bool,
|
||||
/// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
|
||||
@ -367,6 +374,7 @@ impl Default for TargetOptions {
|
||||
is_like_android: false,
|
||||
is_like_msvc: false,
|
||||
linker_is_gnu: false,
|
||||
allows_weak_linkage: true,
|
||||
has_rpath: false,
|
||||
no_compiler_rt: false,
|
||||
no_default_libraries: true,
|
||||
@ -509,6 +517,7 @@ impl Target {
|
||||
key!(is_like_msvc, bool);
|
||||
key!(is_like_android, bool);
|
||||
key!(linker_is_gnu, bool);
|
||||
key!(allows_weak_linkage, bool);
|
||||
key!(has_rpath, bool);
|
||||
key!(no_compiler_rt, bool);
|
||||
key!(no_default_libraries, bool);
|
||||
@ -651,6 +660,7 @@ impl ToJson for Target {
|
||||
target_option_val!(is_like_msvc);
|
||||
target_option_val!(is_like_android);
|
||||
target_option_val!(linker_is_gnu);
|
||||
target_option_val!(allows_weak_linkage);
|
||||
target_option_val!(has_rpath);
|
||||
target_option_val!(no_compiler_rt);
|
||||
target_option_val!(no_default_libraries);
|
||||
|
@ -25,6 +25,7 @@ pub fn opts() -> TargetOptions {
|
||||
staticlib_suffix: ".lib".to_string(),
|
||||
no_default_libraries: true,
|
||||
is_like_windows: true,
|
||||
allows_weak_linkage: false,
|
||||
pre_link_args: vec!(
|
||||
// And here, we see obscure linker flags #45. On windows, it has been
|
||||
// found to be necessary to have this flag to compile liblibc.
|
||||
|
@ -181,6 +181,41 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
llfn
|
||||
}
|
||||
|
||||
fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext,
|
||||
closure_def_id: DefId)
|
||||
-> bool {
|
||||
let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
|
||||
let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
|
||||
let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert);
|
||||
|
||||
!use_mir
|
||||
}
|
||||
|
||||
pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
closure_def_id: DefId,
|
||||
closure_substs: ty::ClosureSubsts<'tcx>) {
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use syntax::ptr::P;
|
||||
|
||||
trans_closure_expr(Dest::Ignore(ccx),
|
||||
&hir::FnDecl {
|
||||
inputs: P::new(),
|
||||
output: hir::NoReturn(DUMMY_SP),
|
||||
variadic: false
|
||||
},
|
||||
&hir::Block {
|
||||
stmts: P::new(),
|
||||
expr: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: hir::DefaultBlock,
|
||||
span: DUMMY_SP
|
||||
},
|
||||
DUMMY_NODE_ID,
|
||||
closure_def_id,
|
||||
closure_substs);
|
||||
}
|
||||
|
||||
pub enum Dest<'a, 'tcx: 'a> {
|
||||
SaveIn(Block<'a, 'tcx>, ValueRef),
|
||||
Ignore(&'a CrateContext<'a, 'tcx>)
|
||||
@ -213,8 +248,13 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||
// If we have not done so yet, translate this closure's body
|
||||
if !ccx.instances().borrow().contains_key(&instance) {
|
||||
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
|
||||
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
|
||||
llvm::SetUniqueComdat(ccx.llmod(), llfn);
|
||||
|
||||
if ccx.sess().target.target.options.allows_weak_linkage {
|
||||
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
|
||||
llvm::SetUniqueComdat(ccx.llmod(), llfn);
|
||||
} else {
|
||||
llvm::SetLinkage(llfn, llvm::InternalLinkage);
|
||||
}
|
||||
|
||||
// set an inline hint for all closures
|
||||
attributes::inline(llfn, attributes::InlineAttr::Hint);
|
||||
@ -296,6 +336,39 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
// If this is a closure, redirect to it.
|
||||
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
|
||||
|
||||
// If weak linkage is not allowed, we have to make sure that a local,
|
||||
// private copy of the closure is available in this codegen unit
|
||||
if !ccx.sess().target.target.options.allows_weak_linkage &&
|
||||
!ccx.sess().opts.single_codegen_unit() {
|
||||
|
||||
if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) {
|
||||
// If the closure is defined in the local crate, we can always just
|
||||
// translate it.
|
||||
let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node {
|
||||
hir::ExprClosure(_, ref decl, ref body, _) => (decl, body),
|
||||
_ => { unreachable!() }
|
||||
};
|
||||
|
||||
trans_closure_expr(Dest::Ignore(ccx),
|
||||
decl,
|
||||
body,
|
||||
node_id,
|
||||
closure_def_id,
|
||||
substs);
|
||||
} else {
|
||||
// If the closure is defined in an upstream crate, we can only
|
||||
// translate it if MIR-trans is active.
|
||||
|
||||
if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) {
|
||||
ccx.sess().fatal("You have run into a known limitation of the \
|
||||
MingW toolchain. Either compile with -Zorbit or \
|
||||
with -Ccodegen-units=1 to work around it.");
|
||||
}
|
||||
|
||||
trans_closure_body_via_mir(ccx, closure_def_id, substs);
|
||||
}
|
||||
}
|
||||
|
||||
// If the closure is a Fn closure, but a FnOnce is needed (etc),
|
||||
// then adapt the self type
|
||||
let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
|
||||
|
@ -530,26 +530,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
|
||||
// FIXME Shouldn't need to manually trigger closure instantiations.
|
||||
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
|
||||
use rustc::hir;
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax::ptr::P;
|
||||
use closure;
|
||||
|
||||
closure::trans_closure_expr(closure::Dest::Ignore(self.ccx),
|
||||
&hir::FnDecl {
|
||||
inputs: P::new(),
|
||||
output: hir::NoReturn(DUMMY_SP),
|
||||
variadic: false
|
||||
},
|
||||
&hir::Block {
|
||||
stmts: P::new(),
|
||||
expr: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: hir::DefaultBlock,
|
||||
span: DUMMY_SP
|
||||
},
|
||||
DUMMY_NODE_ID, def_id,
|
||||
self.monomorphize(&substs));
|
||||
closure::trans_closure_body_via_mir(self.ccx,
|
||||
def_id,
|
||||
self.monomorphize(&substs));
|
||||
}
|
||||
|
||||
let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
|
||||
|
@ -131,27 +131,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
_ => {
|
||||
// FIXME Shouldn't need to manually trigger closure instantiations.
|
||||
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
|
||||
use rustc::hir;
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use closure;
|
||||
|
||||
closure::trans_closure_expr(closure::Dest::Ignore(bcx.ccx()),
|
||||
&hir::FnDecl {
|
||||
inputs: P::new(),
|
||||
output: hir::NoReturn(DUMMY_SP),
|
||||
variadic: false
|
||||
},
|
||||
&hir::Block {
|
||||
stmts: P::new(),
|
||||
expr: None,
|
||||
id: DUMMY_NODE_ID,
|
||||
rules: hir::DefaultBlock,
|
||||
span: DUMMY_SP
|
||||
},
|
||||
DUMMY_NODE_ID, def_id,
|
||||
bcx.monomorphize(&substs));
|
||||
closure::trans_closure_body_via_mir(bcx.ccx(),
|
||||
def_id,
|
||||
bcx.monomorphize(&substs));
|
||||
}
|
||||
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user