diff options
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 26 | ||||
-rw-r--r-- | lib/CodeGen/CGVtable.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.h | 6 | ||||
-rw-r--r-- | test/CodeGenCXX/virtual-functions-incomplete-types.cpp | 30 |
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(); +} |