diff options
| author | Chris Lattner <sabre@nondot.org> | 2011-07-10 00:18:59 +0000 |
|---|---|---|
| committer | Chris Lattner <sabre@nondot.org> | 2011-07-10 00:18:59 +0000 |
| commit | 8806e32f162e3af2c22b600d7d4abdcca5bf7cfd (patch) | |
| tree | 48630569e47697696ae4e86f7028b08adac8b346 | |
| parent | 7161661863c55bc383cb3803958d372ecf0a9980 (diff) | |
| download | bcm5719-llvm-8806e32f162e3af2c22b600d7d4abdcca5bf7cfd.tar.gz bcm5719-llvm-8806e32f162e3af2c22b600d7d4abdcca5bf7cfd.zip | |
Rename CGT::VerifyFuncTypeComplete to isFuncTypeConvertible since
it is a predicate, not an action. Change the return type to be a bool,
not the incomplete member. Enhace it to detect the recursive compilation
case, allowing us to compile Eli's testcase on llvmdev:
struct T {
struct T (*p)(void);
} t;
into:
%struct.T = type { {}* }
@t = common global %struct.T zeroinitializer, align 8
llvm-svn: 134853
| -rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 19 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGVTables.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.cpp | 62 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.h | 7 | ||||
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 2 | ||||
| -rw-r--r-- | clang/test/CodeGen/init.c | 8 |
6 files changed, 73 insertions, 28 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a6f242f2b84..7387fa7096d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/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/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index e439b5fc317..c161b79fd3a 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 93754104773..ed44aec492d 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h index 755f87bdb4d..98786007d79 100644 --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/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/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index e6720c4ed89..1192f322029 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/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/clang/test/CodeGen/init.c b/clang/test/CodeGen/init.c index 0f94729a949..599b4f23dbd 100644 --- a/clang/test/CodeGen/init.c +++ b/clang/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; + |

