From: Chris Lattner Date: Sun, 10 Jul 2011 03:47:27 +0000 (+0000) Subject: Fix the clang bootstrap and Jay's testcase from llvm-dev by being completely X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f0a8679b6e6635117533b89894646f1450cea25b;p=clang Fix the clang bootstrap and Jay's testcase from llvm-dev by being completely 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 --- diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index f304df917b..59c632f0d7 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -104,6 +104,7 @@ bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty){ const TagType *TT = Ty->getAs(); 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(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(Ty))) { + if (RecursionState == RS_StructPointer || + !isFuncTypeConvertible(cast(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::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()); diff --git a/test/CodeGen/struct.c b/test/CodeGen/struct.c index 25477a052e..e1739314d7 100644 --- a/test/CodeGen/struct.c +++ b/test/CodeGen/struct.c @@ -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(); +} + diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp index 2ddafecf66..1d514fb09e 100644 --- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp +++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -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 diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index 89e05d59e9..ccf655b137 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -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]]) diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index ac7dad31d0..dbfd9d335c 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -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* diff --git a/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm index 598dd40610..14e0899cd4 100644 --- a/test/CodeGenObjCXX/arc-special-member-functions.mm +++ b/test/CodeGenObjCXX/arc-special-member-functions.mm @@ -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