aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-11-24 05:08:52 +0000
committerAnders Carlsson <andersca@mac.com>2009-11-24 05:08:52 +0000
commitecf282b0486873309fd58ec4d3ec0dbf983b33d4 (patch)
tree815a9003c3f355ff6ee8907cb54cdb4628bb1073
parentd02174c1f22974a1f0e2334e393f8345c6d11302 (diff)
It is common for vtables to contain pointers to functions that have either incomplete return types or incomplete argument types.
Handle this by returning the llvm::OpaqueType for those cases, which CodeGenModule::GetOrCreateLLVMFunction knows about, and treats as being an "incomplete function". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89736 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGCall.cpp26
-rw-r--r--lib/CodeGen/CGVtable.cpp5
-rw-r--r--lib/CodeGen/CodeGenTypes.h6
-rw-r--r--test/CodeGenCXX/virtual-functions-incomplete-types.cpp30
4 files changed, 63 insertions, 4 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d0c7d03f20..16f4e7b533 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -418,6 +418,32 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
}
+static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) {
+ if (const TagType *TT = T->getResultType()->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ if (const TagType *TT = T->getArgType(i)->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const llvm::Type *
+CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) {
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ if (!HasIncompleteReturnTypeOrArgumentTypes(FPT))
+ return GetFunctionType(getFunctionInfo(MD), FPT->isVariadic());
+
+ return llvm::OpaqueType::get(getLLVMContext());
+}
+
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index f68dbe910f..0c36ef492b 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -367,10 +367,7 @@ public:
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
return wrap(CGM.GetAddrOfFunction(MD, Ty));
}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index f447549f66..d4adebecde 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -173,6 +173,12 @@ public:
const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
bool IsVariadic);
+
+ /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable,
+ /// given a CXXMethodDecl. If the method to has an incomplete return type,
+ /// and/or incomplete argument types, this will return the opaque type.
+ const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD);
+
const CGRecordLayout &getCGRecordLayout(const TagDecl*) const;
/// getLLVMFieldNo - Return llvm::StructType element number
diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
new file mode 100644
index 0000000000..1e1e96286e
--- /dev/null
+++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+struct A;
+
+struct B {
+ virtual void f();
+ virtual A g();
+};
+
+void B::f() { }
+
+// CHECK: declare void @_ZN1B1gEv()
+
+struct C;
+
+struct D {
+ virtual void f();
+ virtual C g();
+};
+
+void D::f() { }
+
+struct C {
+ int a;
+};
+
+// CHECK: define i64 @_ZN1D1gEv(%struct.B* %this)
+C D::g() {
+ return C();
+}