]> granicus.if.org Git - clang/commitdiff
Rename CGT::VerifyFuncTypeComplete to isFuncTypeConvertible since
authorChris Lattner <sabre@nondot.org>
Sun, 10 Jul 2011 00:18:59 +0000 (00:18 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 10 Jul 2011 00:18:59 +0000 (00:18 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134853 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCall.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenTypes.cpp
lib/CodeGen/CodeGenTypes.h
lib/CodeGen/ItaniumCXXABI.cpp
test/CodeGen/init.c

index a6f242f2b847bdc9fb5990901afa20308547e180..7387fa7096d5f0724a03d8f1686cb5425e55b0c3 100644 (file)
@@ -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,
index e439b5fc317a80310005961ebfdfa0f7a35d0dd8..c161b79fd3a0809acbf565388ec217535a2609cb 100644 (file)
@@ -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);
index 93754104773d64410d112e0a60075033841ae782..ed44aec492ddd61fa646bed6100a17953d660ca0 100644 (file)
@@ -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());
index 755f87bdb4dc31d92f34846eabb197d443464281..98786007d795afc2900a147e1ab1ca2efb64513b 100644 (file)
@@ -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.
index e6720c4ed899b9f2174c8e4a10465ab083cbf1a4..1192f322029d901609fe392c561b30d81c4a6adc 100644 (file)
@@ -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());
index 0f94729a949eca245b2cd0911d94248da4361741..599b4f23dbdc155a79383f1517c3241511c783e8 100644 (file)
@@ -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;
+