Skip to content

Commit 71e1a56

Browse files
committed
[CodeGen] Emit destructor calls to destruct non-trivial C struct
temporaries created by conditional and assignment operators rdar://problem/64989559 Differential Revision: https://reviews.llvm.org/D83448
1 parent fe9a7d9 commit 71e1a56

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

clang/lib/CodeGen/CGExprAgg.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,11 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
12161216

12171217
// Copy into the destination if the assignment isn't ignored.
12181218
EmitFinalDestCopy(E->getType(), LHS);
1219+
1220+
if (!Dest.isIgnored() && !Dest.isExternallyDestructed() &&
1221+
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
1222+
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
1223+
E->getType());
12191224
}
12201225

12211226
void AggExprEmitter::
@@ -1233,6 +1238,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
12331238

12341239
// Save whether the destination's lifetime is externally managed.
12351240
bool isExternallyDestructed = Dest.isExternallyDestructed();
1241+
bool destructNonTrivialCStruct =
1242+
!isExternallyDestructed &&
1243+
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct;
1244+
isExternallyDestructed |= destructNonTrivialCStruct;
1245+
Dest.setExternallyDestructed(isExternallyDestructed);
12361246

12371247
eval.begin(CGF);
12381248
CGF.EmitBlock(LHSBlock);
@@ -1254,6 +1264,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
12541264
Visit(E->getFalseExpr());
12551265
eval.end(CGF);
12561266

1267+
if (destructNonTrivialCStruct)
1268+
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
1269+
E->getType());
1270+
12571271
CGF.EmitBlock(ContBlock);
12581272
}
12591273

clang/test/CodeGenObjC/strong-in-c-struct.m

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,13 @@ + (StrongSmall)getStrongSmallClass;
9595
@end
9696

9797
id g0;
98+
StrongSmall g1, g2;
9899

100+
// CHECK: %[[STRUCT_STRONGSMALL:.*]] = type { i32, i8* }
99101
// CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
100102
// CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
101103
// CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
102104
// CHECK: %[[STRUCT_BLOCK_BYREF_T:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_T]]*, i32, i32, i8*, i8*, i8*, %[[STRUCT_STRONGOUTER]] }
103-
// CHECK: %[[STRUCT_STRONGSMALL:.*]] = type { i32, i8* }
104105
// CHECK: %[[STRUCT_STRONGBLOCK:.*]] = type { void ()* }
105106
// CHECK: %[[STRUCT_BITFIELD1:.*]] = type { i8, i8, i8*, i32, i8*, [3 x i32], i8*, double, i8, i8 }
106107

@@ -900,4 +901,47 @@ void test_zero_bitfield() {
900901
a = b;
901902
}
902903

904+
// CHECK-LABEL: define i8* @test_conditional0(
905+
// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
906+
907+
// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
908+
// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V1]], i8** bitcast (%[[STRUCT_STRONGSMALL]]* @g2 to i8**))
909+
910+
// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
911+
// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V2]], i8** bitcast (%[[STRUCT_STRONGSMALL]]* @g1 to i8**))
912+
913+
// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
914+
// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
915+
// CHECK: @llvm.objc.autoreleaseReturnValue
916+
917+
id test_conditional0(int c) {
918+
return (c ? g2 : g1).f1;
919+
}
920+
921+
// CHECK-LABEL: define i8* @test_conditional1(
922+
// CHECK-NOT: call void @__destructor
923+
924+
id test_conditional1(int c) {
925+
calleeStrongSmall(c ? g2 : g1);
926+
}
927+
928+
// CHECK-LABEL: define i8* @test_assignment0(
929+
// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
930+
// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** bitcast (%[[STRUCT_STRONGSMALL]]* @g2 to i8**), i8** bitcast (%[[STRUCT_STRONGSMALL]]* @g1 to i8**))
931+
// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
932+
// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V0]], i8** bitcast (%[[STRUCT_STRONGSMALL]]* @g2 to i8**))
933+
// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
934+
// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
935+
936+
id test_assignment0(void) {
937+
return (g2 = g1).f1;
938+
}
939+
940+
// CHECK-LABEL: define i8* @test_assignment1(
941+
// CHECK-NOT: call void @__destructor
942+
943+
id test_assignment1(void) {
944+
calleeStrongSmall(g2 = g1);
945+
}
946+
903947
#endif /* USESTRUCT */

0 commit comments

Comments
 (0)