Use aliases for more constructors and destructors.

With this patch we produce alias for cases like

template<typename T>
struct foobar {
  foobar() {
  }
};
template struct foobar<void>;

It is safe to use aliases to weak symbols, as long and the alias itself is also
weak.

llvm-svn: 192300
This commit is contained in:
Rafael Espindola 2013-10-09 16:13:15 +00:00
parent ee863cedc2
commit a25c79e704
2 changed files with 34 additions and 24 deletions

View File

@ -108,32 +108,17 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
// support aliases with that linkage, fail.
llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
switch (Linkage) {
// We can definitely emit aliases to definitions with external linkage.
case llvm::GlobalValue::ExternalLinkage:
case llvm::GlobalValue::ExternalWeakLinkage:
break;
// Same with local linkage.
case llvm::GlobalValue::InternalLinkage:
case llvm::GlobalValue::PrivateLinkage:
case llvm::GlobalValue::LinkerPrivateLinkage:
break;
// We should try to support linkonce linkages.
case llvm::GlobalValue::LinkOnceAnyLinkage:
case llvm::GlobalValue::LinkOnceODRLinkage:
// We can't use an alias if the linkage is not valid for one.
if (!llvm::GlobalAlias::isValidLinkage(Linkage))
return true;
// Other linkages will probably never be supported.
default:
return true;
}
llvm::GlobalValue::LinkageTypes TargetLinkage
= getFunctionLinkage(TargetDecl);
if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
// Don't create an strong alias to a linker weak symbol. If the linker
// decides to drop the symbol, the alias would become undefined.
if (llvm::GlobalValue::isWeakForLinker(TargetLinkage) &&
!llvm::GlobalValue::isWeakForLinker(Linkage))
return true;
// Derive the type for the alias.

View File

@ -6,10 +6,16 @@
// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
// CHECK: @_ZN6test106foobarIvEC1Ev = alias weak_odr void (%"struct.test10::foobar"*)* @_ZN6test106foobarIvEC2Ev
// CHECK: @_ZN6test116foobarIvEC1Ev = alias linkonce_odr void (%"struct.test11::foobar"*)* @_ZN6test116foobarIvEC2Ev
// CHECK: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
// CHECK: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
// CHECK: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
// CHECK: @_ZN6PR752617allocator_derivedD1Ev = alias linkonce_odr void (%"struct.PR7526::allocator_derived"*)* @_ZN6PR752617allocator_derivedD2Ev
struct A {
int a;
@ -44,9 +50,6 @@ namespace PR7526 {
// CHECK: call void @__cxa_call_unexpected
allocator::~allocator() throw() { foo(); }
// CHECK-LABEL: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr
// CHECK-NOT: call void @__cxa_call_unexpected
// CHECK: }
void foo() {
allocator_derived ad;
}
@ -419,3 +422,25 @@ namespace test9 {
// CHECK: ret void
// CHECK: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}}
namespace test10 {
template<typename T>
struct foobar {
foobar() {
}
};
template struct foobar<void>;
}
namespace test11 {
void g();
template<typename T>
struct foobar {
foobar() {
g();
}
};
foobar<void> x;
}