mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Use weak_odr linkage when reusing definitions across codegen units
When reuing a definition across codegen units, we obviously cannot use internal linkage, but using external linkage means that we can end up with multiple conflicting definitions of a single symbol across multiple crates. Since the definitions should all be equal semantically, we can use weak_odr linkage to resolve the situation. Fixes #32518
This commit is contained in:
parent
abb3a107e4
commit
22f4587586
@ -2125,6 +2125,9 @@ extern {
|
|||||||
pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef);
|
pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef);
|
||||||
|
|
||||||
pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef);
|
pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef);
|
||||||
|
|
||||||
|
pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char);
|
||||||
|
pub fn LLVMRustUnsetComdat(V: ValueRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVM requires symbols from this library, but apparently they're not printed
|
// LLVM requires symbols from this library, but apparently they're not printed
|
||||||
@ -2149,6 +2152,24 @@ pub fn SetLinkage(global: ValueRef, link: Linkage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Externally visible symbols that might appear in multiple translation units need to appear in
|
||||||
|
// their own comdat section so that the duplicates can be discarded at link time. This can for
|
||||||
|
// example happen for generics when using multiple codegen units. This function simply uses the
|
||||||
|
// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
|
||||||
|
// function.
|
||||||
|
// For more details on COMDAT sections see e.g. http://www.airs.com/blog/archives/52
|
||||||
|
pub fn SetUniqueComdat(llmod: ModuleRef, val: ValueRef) {
|
||||||
|
unsafe {
|
||||||
|
LLVMRustSetComdat(llmod, val, LLVMGetValueName(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn UnsetComdat(val: ValueRef) {
|
||||||
|
unsafe {
|
||||||
|
LLVMRustUnsetComdat(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn SetDLLStorageClass(global: ValueRef, class: DLLStorageClassTypes) {
|
pub fn SetDLLStorageClass(global: ValueRef, class: DLLStorageClassTypes) {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMRustSetDLLStorageClass(global, class);
|
LLVMRustSetDLLStorageClass(global, class);
|
||||||
|
@ -2215,18 +2215,27 @@ pub fn update_linkage(ccx: &CrateContext,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match id {
|
let (is_reachable, is_generic) = if let Some(id) = id {
|
||||||
Some(id) if ccx.reachable().contains(&id) => {
|
(ccx.reachable().contains(&id), false)
|
||||||
|
} else {
|
||||||
|
(false, true)
|
||||||
|
};
|
||||||
|
|
||||||
|
// We need external linkage for items reachable from other translation units, this include
|
||||||
|
// other codegen units in case of parallel compilations.
|
||||||
|
if is_reachable || ccx.sess().opts.cg.codegen_units > 1 {
|
||||||
|
if is_generic {
|
||||||
|
// This only happens with multiple codegen units, in which case we need to use weak_odr
|
||||||
|
// linkage because other crates might expose the same symbol. We cannot use
|
||||||
|
// linkonce_odr here because the symbol might then get dropped before the other codegen
|
||||||
|
// units get to link it.
|
||||||
|
llvm::SetUniqueComdat(ccx.llmod(), llval);
|
||||||
|
llvm::SetLinkage(llval, llvm::WeakODRLinkage);
|
||||||
|
} else {
|
||||||
llvm::SetLinkage(llval, llvm::ExternalLinkage);
|
llvm::SetLinkage(llval, llvm::ExternalLinkage);
|
||||||
},
|
}
|
||||||
_ => {
|
} else {
|
||||||
// `id` does not refer to an item in `ccx.reachable`.
|
llvm::SetLinkage(llval, llvm::InternalLinkage);
|
||||||
if ccx.sess().opts.cg.codegen_units > 1 {
|
|
||||||
llvm::SetLinkage(llval, llvm::ExternalLinkage);
|
|
||||||
} else {
|
|
||||||
llvm::SetLinkage(llval, llvm::InternalLinkage);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2547,8 +2556,10 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
|
|||||||
// then give it internal linkage.
|
// then give it internal linkage.
|
||||||
for ccx in cx.iter() {
|
for ccx in cx.iter() {
|
||||||
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
|
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
|
||||||
|
let linkage = llvm::LLVMGetLinkage(val);
|
||||||
// We only care about external definitions.
|
// We only care about external definitions.
|
||||||
if !(llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint &&
|
if !((linkage == llvm::ExternalLinkage as c_uint ||
|
||||||
|
linkage == llvm::WeakODRLinkage as c_uint) &&
|
||||||
llvm::LLVMIsDeclaration(val) == 0) {
|
llvm::LLVMIsDeclaration(val) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2560,6 +2571,7 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
|
|||||||
!reachable.contains(str::from_utf8(&name).unwrap()) {
|
!reachable.contains(str::from_utf8(&name).unwrap()) {
|
||||||
llvm::SetLinkage(val, llvm::InternalLinkage);
|
llvm::SetLinkage(val, llvm::InternalLinkage);
|
||||||
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
|
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
|
||||||
|
llvm::UnsetComdat(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
ref attrs, node: hir::ImplItemKind::Method(
|
ref attrs, node: hir::ImplItemKind::Method(
|
||||||
hir::MethodSig { ref decl, .. }, ref body), ..
|
hir::MethodSig { ref decl, .. }, ref body), ..
|
||||||
}) => {
|
}) => {
|
||||||
base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
|
|
||||||
attributes::from_fn_attrs(ccx, attrs, lldecl);
|
attributes::from_fn_attrs(ccx, attrs, lldecl);
|
||||||
|
|
||||||
let is_first = !ccx.available_monomorphizations().borrow()
|
let is_first = !ccx.available_monomorphizations().borrow()
|
||||||
@ -133,12 +132,14 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
let trans_everywhere = attr::requests_inline(attrs);
|
let trans_everywhere = attr::requests_inline(attrs);
|
||||||
if trans_everywhere && !is_first {
|
|
||||||
llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if trans_everywhere || is_first {
|
if trans_everywhere || is_first {
|
||||||
|
let origin = if is_first { base::OriginalTranslation } else { base::InlinedCopy };
|
||||||
|
base::update_linkage(ccx, lldecl, None, origin);
|
||||||
trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id);
|
trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id);
|
||||||
|
} else {
|
||||||
|
// We marked the value as using internal linkage earlier, but that is illegal for
|
||||||
|
// declarations, so switch back to external linkage.
|
||||||
|
llvm::SetLinkage(lldecl, llvm::ExternalLinkage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,3 +1189,16 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, LLVMBasicBlockR
|
|||||||
auto point = unwrap(BB)->getFirstInsertionPt();
|
auto point = unwrap(BB)->getFirstInsertionPt();
|
||||||
unwrap(B)->SetInsertPoint(unwrap(BB), point);
|
unwrap(B)->SetInsertPoint(unwrap(BB), point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V, const char *Name) {
|
||||||
|
Triple TargetTriple(unwrap(M)->getTargetTriple());
|
||||||
|
GlobalObject *GV = unwrap<GlobalObject>(V);
|
||||||
|
if (!TargetTriple.isOSBinFormatMachO()) {
|
||||||
|
GV->setComdat(unwrap(M)->getOrInsertComdat(Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) {
|
||||||
|
GlobalObject *GV = unwrap<GlobalObject>(V);
|
||||||
|
GV->setComdat(nullptr);
|
||||||
|
}
|
||||||
|
16
src/test/auxiliary/cgu_test.rs
Normal file
16
src/test/auxiliary/cgu_test.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// compile-flags: --crate-type=lib
|
||||||
|
|
||||||
|
pub fn id<T>(t: T) -> T {
|
||||||
|
t
|
||||||
|
}
|
25
src/test/auxiliary/cgu_test_a.rs
Normal file
25
src/test/auxiliary/cgu_test_a.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// compile-flags: -Ccodegen-units=2 --crate-type=lib
|
||||||
|
|
||||||
|
extern crate cgu_test;
|
||||||
|
|
||||||
|
pub mod a {
|
||||||
|
pub fn a() {
|
||||||
|
::cgu_test::id(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub mod b {
|
||||||
|
pub fn a() {
|
||||||
|
::cgu_test::id(0);
|
||||||
|
}
|
||||||
|
}
|
25
src/test/auxiliary/cgu_test_b.rs
Normal file
25
src/test/auxiliary/cgu_test_b.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// compile-flags: -Ccodegen-units=2 --crate-type=lib
|
||||||
|
|
||||||
|
extern crate cgu_test;
|
||||||
|
|
||||||
|
pub mod a {
|
||||||
|
pub fn a() {
|
||||||
|
::cgu_test::id(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub mod b {
|
||||||
|
pub fn a() {
|
||||||
|
::cgu_test::id(0);
|
||||||
|
}
|
||||||
|
}
|
22
src/test/run-pass/issue-32518.rs
Normal file
22
src/test/run-pass/issue-32518.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// aux-build:cgu_test.rs
|
||||||
|
// aux-build:cgu_test_a.rs
|
||||||
|
// aux-build:cgu_test_b.rs
|
||||||
|
|
||||||
|
extern crate cgu_test_a;
|
||||||
|
extern crate cgu_test_b;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
cgu_test_a::a::a();
|
||||||
|
cgu_test_b::a::a();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user