]> granicus.if.org Git - clang/commitdiff
Fix the clang bootstrap and Jay's testcase from llvm-dev by being completely
authorChris Lattner <sabre@nondot.org>
Sun, 10 Jul 2011 03:47:27 +0000 (03:47 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 10 Jul 2011 03:47:27 +0000 (03:47 +0000)
conservative when converting a functiontype to IR when in a "pointer within
a struct" context.  This has the unfortunate sideeffect of compiling all
function pointers inside of structs into "{}*" which, though correct, is
ugly.  This has the positive side effect of being correct, and it is pretty
straight-forward to improve on this.

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

lib/CodeGen/CodeGenTypes.cpp
test/CodeGen/struct.c
test/CodeGenCXX/anonymous-union-member-initializer.cpp
test/CodeGenObjC/arc-foreach.m
test/CodeGenObjC/arc.m
test/CodeGenObjCXX/arc-special-member-functions.mm

index f304df917b1438aaa0f69da5b81efe82ee5eeba3..59c632f0d7deaf4e73d63e0ee50055ea590ef317 100644 (file)
@@ -104,6 +104,7 @@ bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty){
   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;
@@ -158,8 +159,14 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
     return;
   }
   
+  // If we completed a RecordDecl that we previously used and converted to an
+  // anonymous type, then go ahead and complete it now.
   const RecordDecl *RD = cast<RecordDecl>(TD);
-  if (!RD->isDependentType())
+  if (RD->isDependentType()) return;
+
+  // Only complete it if we converted it already.  If we haven't converted it
+  // yet, we'll just do it lazily.
+ // if (RecordDeclTypes.count(Context.getTagDeclType(RD).getTypePtr()))
     ConvertRecordDeclType(RD);
 }
 
@@ -333,13 +340,20 @@ 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 (!isFuncTypeConvertible(cast<FunctionType>(Ty))) {
+    if (RecursionState == RS_StructPointer ||
+        !isFuncTypeConvertible(cast<FunctionType>(Ty))) {
       // This function's type depends on an incomplete tag type.
       // Return a placeholder type.
       ResultType = llvm::StructType::get(getLLVMContext());
       break;
     }
 
+    // While we're converting the argument types for a function, we don't want
+    // to recursively convert any pointed-to structs.  Converting directly-used
+    // structs is ok though.
+    RecursionStateTy SavedRecursionState = RecursionState;
+    RecursionState = RS_Struct;
+    
     // The function type can be built; call the appropriate routines to
     // build it.
     const CGFunctionInfo *FI;
@@ -354,8 +368,15 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
                 CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
       isVariadic = true;
     }
-
+    
     ResultType = GetFunctionType(*FI, isVariadic);
+    
+    // Restore our recursion state.
+    RecursionState = SavedRecursionState;
+    
+    if (RecursionState == RS_Normal)
+      while (!DeferredRecords.empty())
+        ConvertRecordDeclType(DeferredRecords.pop_back_val());
     break;
   }
 
@@ -463,10 +484,16 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
   CGRecordLayout *Layout = ComputeRecordLayout(RD, Ty);
   CGRecordLayouts[Key] = Layout;
 
+  // If this struct blocked a FunctionType conversion, then recompute whatever
+  // was derived from that.
+  // FIXME: This is hugely overconservative.
+  TypeCache.clear();
+  
   
   // Restore our recursion state.  If we're done converting the outer-most
   // record, then convert any deferred structs as well.
   RecursionState = SavedRecursionState;
+  
   if (RecursionState == RS_Normal)
     while (!DeferredRecords.empty())
       ConvertRecordDeclType(DeferredRecords.pop_back_val());
index 25477a052e8a8308b3f8bdfa3f3c3c817c6c7c24..e1739314d7fccd86d80a595efffe7299996ac837 100644 (file)
@@ -181,3 +181,16 @@ range f18() {
   rangepair rp;
   return (rp = f18_ext()).range1;
 }
+
+
+
+// Complex forward reference of struct.
+struct f19S;
+extern struct f19T {
+  struct f19S (*p)(void);
+} t;
+struct f19S { int i; };
+void f19(void) {
+  t.p();
+}
+
index 2ddafecf6651e00c9b28ffb4d0f1281b4c03345f..1d514fb09e5cf47244c2556e41f2048f1dcfbce1 100644 (file)
@@ -86,7 +86,7 @@ namespace test3 {
   // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
   // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to 
   // CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0
-  // CHECK-NEXT: store void (i8*)* null, void (i8*)** [[CALLBACK]]
+  // CHECK-NEXT: store {{.*}}* null, {{.*}}** [[CALLBACK]]
   // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0
   // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to 
   // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 1
index 89e05d59e9ce896984bccc407039317cee007328..ccf655b1377c3a2e2fccd11269afa65c335e5cbb 100644 (file)
@@ -33,8 +33,8 @@ void test0(NSArray *array) {
 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]]
 // CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
 // CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
-// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
-// CHECK-LP64-NEXT: call void @use_block(void ()* [[T1]])
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] 
+// CHECK-LP64-NEXT: call void @use_block({{.*}}* [[T1]])
 // CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[T0]]
 // CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
 
@@ -66,7 +66,7 @@ void test1(NSArray *array) {
 // CHECK-LP64:      [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
 // CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]])
 // CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]])
-// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
-// CHECK-LP64-NEXT: call void @use_block(void ()* [[T1]])
+// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
+// CHECK-LP64-NEXT: call void @use_block({{.*}} [[T1]])
 // CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[T0]])
 // CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]])
index ac7dad31d08247ff56fb8491a9c9010cc828d0f4..dbfd9d335cfce9029f5f96f0f707b22ddf87db80 100644 (file)
@@ -1225,8 +1225,8 @@ void test39(void) {
   // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
   // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
   // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
-  // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
-  // CHECK-NEXT: call void @test39_helper(void ()* [[T0]])
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
+  // CHECK-NEXT: call void @test39_helper({{.*}} [[T0]])
   // CHECK-NEXT: ret void
 }
 
@@ -1338,7 +1338,7 @@ void test41(void) {
 // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
 // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST42]]*
 // CHECK-NEXT: store [[TEST42]]* [[T4]], [[TEST42]]** [[T0]]
-// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
 // CHECK-NEXT: call void @test42_helper(
 // CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[T0]]
 // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
index 598dd406107770a7a87f7e742b99bfc291c0eb5d..14e0899cd49310cd5c7d303738b6de51f63fdc38 100644 (file)
@@ -94,9 +94,9 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
 // CHECK:    define linkonce_odr {{%.*}}* @_ZN15ObjCBlockMemberaSERKS_(
 // CHECK:      [[T0:%.*]] = call i8* @objc_retainBlock(
 // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32 (i32)*
-// CHECK-NEXT: [[T2:%.*]] = load i32 (i32)** [[SLOT:%.*]],
-// CHECK-NEXT: store i32 (i32)* [[T1]], i32 (i32)** [[SLOT]]
-// CHECK-NEXT: [[T3:%.*]] = bitcast i32 (i32)* [[T2]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = load {{.*}} [[SLOT:%.*]],
+// CHECK: store
+// CHECK-NEXT: [[T3:%.*]] = bitcast 
 // CHECK-NEXT: call void @objc_release(i8* [[T3]])
 // CHECK-NEXT: ret
 
@@ -112,7 +112,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
 
 // Implicitly-generated default constructor for ObjCBlockMember
 // CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2Ev
-// CHECK: store i32 (i32)* null,
+// CHECK: store {{.*}} null,
 // CHECK-NEXT: ret void
 
 // Implicitly-generated copy constructor for ObjCArrayMember