setThunkVisibility(CGM, MD, Thunk, Fn);
}
-void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
+void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
+ bool UseAvailableExternallyLinkage)
{
llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
OldThunkFn->eraseFromParent();
}
- // Actually generate the thunk body.
llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
+
+ if (!ThunkFn->isDeclaration()) {
+ if (UseAvailableExternallyLinkage) {
+ // There is already a thunk emitted for this function, do nothing.
+ return;
+ }
+
+ // We should never be able to get a function with a definition here.
+ assert(false && "Shouldn't have an already existing definition");
+ }
+
+ // Actually generate the thunk body.
CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk);
+
+ if (UseAvailableExternallyLinkage)
+ ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+}
+
+void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ // We only want to do this when building with optimizations.
+ if (!CGM.getCodeGenOpts().OptimizationLevel)
+ return;
+
+ // We can't emit thunks for member functions with incomplete types.
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ if (CGM.getTypes().VerifyFuncTypeComplete(MD->getType().getTypePtr()))
+ return;
+
+ EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
}
void CodeGenVTables::EmitThunks(GlobalDecl GD)
const ThunkInfoVectorTy &ThunkInfoVector = I->second;
for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I)
- EmitThunk(GD, ThunkInfoVector[I]);
+ EmitThunk(GD, ThunkInfoVector[I], /*UseAvailableExternallyLinkage=*/false);
}
void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD,
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
Init = CGM.GetAddrOfThunk(GD, Thunk);
-
+ MaybeEmitThunkAvailableExternally(GD, Thunk);
+
NextVTableThunkIndex++;
} else {
const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD);
void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
/// EmitThunk - Emit a single thunk.
- void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk);
-
+ void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
+ bool UseAvailableExternallyLinkage);
+
+ /// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with
+ /// available_externally linkage to allow for inlining of thunks.
+ /// This will be done iff optimizations are enabled and the member function
+ /// doesn't contain any incomplete types.
+ void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
+
/// ComputeVTableRelatedInformation - Compute and store all vtable related
/// information (vtable layout, vbase offset offsets, thunks etc) for the
/// given record decl.
--- /dev/null
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s
+
+// Check that we don't assert on this case.
+namespace Test1 {
+
+struct Incomplete;
+
+struct A {
+ virtual void f();
+ virtual void g(Incomplete);
+ virtual void h();
+ virtual void i();
+ int a;
+};
+
+struct B {
+ virtual void f();
+ virtual void g(Incomplete);
+ virtual void h();
+ virtual void i();
+ int b;
+};
+
+struct C : A, B {
+ C();
+
+ virtual void f();
+ virtual void g(Incomplete);
+ virtual void h();
+ virtual void i();
+};
+
+void C::h() { }
+
+C::C() { }
+
+void C::i() { }
+
+}
+
+namespace Test2 {
+
+struct A {
+ virtual void f();
+ int a;
+};
+
+struct B {
+ virtual void f();
+ int b;
+};
+
+struct C : A, B {
+ virtual void f();
+};
+
+static void f(B* b) {
+ b->f();
+}
+
+// CHECK: define void @_ZN5Test21fEv()
+// CHECK: call void @_ZN5Test21C1fEv
+// CHECK: ret void
+// CHECK: define available_externally void @_ZThn16_N5Test21C1fEv
+void f() {
+ C c;
+ f(&c);
+}
+
+}