diff options
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 19 | ||||
-rw-r--r-- | lib/CodeGen/CGVTables.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 62 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.h | 7 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 2 | ||||
-rw-r--r-- | test/CodeGen/init.c | 8 |
6 files changed, 73 insertions, 28 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index a6f242f2b8..7387fa7096 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -704,16 +704,15 @@ const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - if (!VerifyFuncTypeComplete(FPT)) { - const CGFunctionInfo *Info; - if (isa<CXXDestructorDecl>(MD)) - Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType()); - else - Info = &getFunctionInfo(MD); - return GetFunctionType(*Info, FPT->isVariadic()); - } - - return llvm::StructType::get(getLLVMContext()); + if (!isFuncTypeConvertible(FPT)) + return llvm::StructType::get(getLLVMContext()); + + const CGFunctionInfo *Info; + if (isa<CXXDestructorDecl>(MD)) + Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType()); + else + Info = &getFunctionInfo(MD); + return GetFunctionType(*Info, FPT->isVariadic()); } void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index e439b5fc31..c161b79fd3 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -2937,7 +2937,8 @@ void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD, // 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())) + if (!CGM.getTypes().isFuncTypeConvertible( + cast<FunctionType>(MD->getType().getTypePtr()))) return; EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 9375410477..ed44aec492 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -93,19 +93,55 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T){ } -// Code to verify a given function type is complete, i.e. the return type -// and all of the argument types are complete. -const TagType *CodeGenTypes::VerifyFuncTypeComplete(const Type* T) { - const FunctionType *FT = cast<FunctionType>(T); - if (const TagType* TT = FT->getResultType()->getAs<TagType>()) - if (!TT->getDecl()->isDefinition()) - return TT; - if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(T)) +/// isFuncTypeArgumentConvertible - Return true if the specified type in a +/// function argument or result position can be converted to an IR type at this +/// point. This boils down to being whether it is complete, as well as whether +/// we've temporarily deferred expanding the type because we're in a recursive +/// context. +bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty){ + // If this isn't a tagged type, we can convert it! + const TagType *TT = Ty->getAs<TagType>(); + if (TT == 0) return true; + + // If it's a tagged type, but is a forward decl, we can't convert it. + if (!TT->getDecl()->isDefinition()) + return false; + + // If we're not under a pointer under a struct, then we can convert it if + // needed. + if (RecursionState != RS_StructPointer) + return true; + + // If this is an enum, then it is safe to convert. + const RecordType *RT = dyn_cast<RecordType>(TT); + if (RT == 0) return true; + + // Otherwise, we have to be careful. If it is a struct that we're in the + // process of expanding, then we can't convert the function type. That's ok + // though because we must be in a pointer context under the struct, so we can + // just convert it to a dummy type. + // + // We decide this by checking whether ConvertRecordDeclType returns us an + // opaque type for a struct that we know is defined. + return !ConvertRecordDeclType(RT->getDecl())->isOpaque(); +} + + +/// Code to verify a given function type is complete, i.e. the return type +/// and all of the argument types are complete. Also check to see if we are in +/// a RS_StructPointer context, and if so whether any struct types have been +/// pended. If so, we don't want to ask the ABI lowering code to handle a type +/// that cannot be converted to an IR type. +bool CodeGenTypes::isFuncTypeConvertible(const FunctionType *FT) { + if (!isFuncTypeArgumentConvertible(FT->getResultType())) + return false; + + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) for (unsigned i = 0, e = FPT->getNumArgs(); i != e; i++) - if (const TagType *TT = FPT->getArgType(i)->getAs<TagType>()) - if (!TT->getDecl()->isDefinition()) - return TT; - return 0; + if (!isFuncTypeArgumentConvertible(FPT->getArgType(i))) + return false; + + return true; } /// UpdateCompletedType - When we find the full definition for a TagDecl, @@ -296,7 +332,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { // First, check whether we can build the full function type. If the // function type depends on an incomplete type (e.g. a struct or enum), we // cannot lower the function type. - if (VerifyFuncTypeComplete(Ty)) { + if (!isFuncTypeConvertible(cast<FunctionType>(Ty))) { // This function's type depends on an incomplete tag type. // Return a placeholder type. ResultType = llvm::StructType::get(getLLVMContext()); diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 755f87bdb4..98786007d7 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -137,11 +137,12 @@ public: llvm::FunctionType *GetFunctionType(GlobalDecl GD); - /// VerifyFuncTypeComplete - Utility to check whether a function type can + /// isFuncTypeConvertible - Utility to check whether a function type can /// be converted to an LLVM type (i.e. doesn't depend on an incomplete tag /// type). - static const TagType *VerifyFuncTypeComplete(const Type* T); - + bool isFuncTypeConvertible(const FunctionType *FT); + bool isFuncTypeArgumentConvertible(QualType Ty); + /// 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. diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index e6720c4ed8..1192f32202 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -537,7 +537,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); const llvm::Type *Ty; // Check whether the function has a computable LLVM signature. - if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { + if (Types.isFuncTypeConvertible(FPT)) { // The function has a computable LLVM signature; use the correct type. Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c index 0f94729a94..599b4f23db 100644 --- a/test/CodeGen/init.c +++ b/test/CodeGen/init.c @@ -115,3 +115,11 @@ void test11(struct test11S *P) { // CHECK: store i32 4 // CHECK: ret void } + + +// Verify that we can convert a recursive struct with a memory that returns +// an instance of the struct we're converting. +struct test12 { + struct test12 (*p)(void); +} test12g; + |