[CodeGen] Emit destructor calls to destruct compound literals

Fix a bug in IRGen where it wasn't destructing compound literals in C
that are ObjC pointer arrays or non-trivial structs. Also diagnose jumps
that enter or exit the lifetime of the compound literals.

rdar://problem/51867864

Differential Revision: https://reviews.llvm.org/D64464
diff --git a/clang/test/AST/ast-dump-objc-arc-json.m b/clang/test/AST/ast-dump-objc-arc-json.m
new file mode 100644
index 0000000..bb9268b
--- /dev/null
+++ b/clang/test/AST/ast-dump-objc-arc-json.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -ast-dump=json -ast-dump-filter Test %s | FileCheck %s
+
+typedef struct {
+  id f;
+} S;
+
+id TestCompoundLiteral(id a) {
+  return ((S){ .f = a }).f;
+}
+
+// CHECK:  "kind": "ExprWithCleanups",
+// CHECK-NEXT:  "range": {
+// CHECK-NEXT:   "begin": {
+// CHECK-NEXT:    "offset": 202,
+// CHECK-NEXT:    "col": 10,
+// CHECK-NEXT:    "tokLen": 1
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "end": {
+// CHECK-NEXT:    "offset": 218,
+// CHECK-NEXT:    "col": 26,
+// CHECK-NEXT:    "tokLen": 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:  },
+// CHECK-NEXT:  "type": {
+// CHECK-NEXT:   "desugaredQualType": "id",
+// CHECK-NEXT:   "qualType": "id",
+// CHECK-NEXT:   "typeAliasDeclId": "0x{{.*}}"
+// CHECK-NEXT:  },
+// CHECK-NEXT:  "valueCategory": "rvalue",
+// CHECK-NEXT:  "cleanupsHaveSideEffects": true,
+// CHECK-NEXT:  "cleanups": [
+// CHECK-NEXT:   {
+// CHECK-NEXT:    "id": "0x{{.*}}",
+// CHECK-NEXT:    "kind": "CompoundLiteralExpr"
+// CHECK-NEXT:   }
+// CHECK-NEXT:  ],
diff --git a/clang/test/AST/ast-dump-stmt.m b/clang/test/AST/ast-dump-stmt.m
index 8c0ca89..9744e7a 100644
--- a/clang/test/AST/ast-dump-stmt.m
+++ b/clang/test/AST/ast-dump-stmt.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -Wno-unused -fobjc-arc -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
 
 void TestBlockExpr(int x) {
   ^{ x; };
@@ -34,3 +34,16 @@
 // CHECK-NEXT:   ObjCAtCatchStmt{{.*}} catch all
 // CHECK-NEXT:     CompoundStmt
 // CHECK-NEXT:   ObjCAtFinallyStmt
+
+typedef struct {
+  id f;
+} S;
+
+id TestCompoundLiteral(id a) {
+  return ((S){ .f = a }).f;
+}
+
+// CHECK:     FunctionDecl{{.*}}TestCompoundLiteral
+// CHECK:       ExprWithCleanups
+// CHECK-NEXT:    cleanup CompoundLiteralExpr
+// CHECK:           CompoundLiteralExpr{{.*}}'S':'S' lvalue
diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m b/clang/test/CodeGenObjC/arc-ternary-op.m
index 4883143..28567fc 100644
--- a/clang/test/CodeGenObjC/arc-ternary-op.m
+++ b/clang/test/CodeGenObjC/arc-ternary-op.m
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
 
+id g0, g1;
+
 void test0(_Bool cond) {
   id test0_helper(void) __attribute__((ns_returns_retained));
 
@@ -147,4 +149,58 @@
   // CHECK:      call void @llvm.objc.release(i8* [[RESULT]])
 }
 
+void test3(int cond) {
+  __strong id *p = cond ? (__strong id[]){g0, g1} : (__strong id[]){g1, g0};
+  test2(cond);
+
+  // CHECK: define void @test3(
+  // CHECK: %[[P:.*]] = alloca i8**, align 8
+  // CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca [2 x i8*], align 8
+  // CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1
+  // CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca [2 x i8*], align 8
+  // CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1
+
+  // CHECK: %[[ARRAYINIT_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i64 0, i64 0
+  // CHECK: %[[V2:.*]] = load i8*, i8** @g0, align 8
+  // CHECK: %[[V3:.*]] = call i8* @llvm.objc.retain(i8* %[[V2]])
+  // CHECK: store i8* %[[V3]], i8** %[[ARRAYINIT_BEGIN]], align 8
+  // CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN]], i64 1
+  // CHECK: %[[V4:.*]] = load i8*, i8** @g1, align 8
+  // CHECK: %[[V5:.*]] = call i8* @llvm.objc.retain(i8* %[[V4]])
+  // CHECK: store i8* %[[V5]], i8** %[[ARRAYINIT_ELEMENT]], align 8
+  // CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1
+  // CHECK: %[[ARRAYDECAY:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i64 0, i64 0
+
+  // CHECK: %[[ARRAYINIT_BEGIN2:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i64 0, i64 0
+  // CHECK: %[[V6:.*]] = load i8*, i8** @g1, align 8
+  // CHECK: %[[V7:.*]] = call i8* @llvm.objc.retain(i8* %[[V6]])
+  // CHECK: store i8* %[[V7]], i8** %[[ARRAYINIT_BEGIN2]], align 8
+  // CHECK: %[[ARRAYINIT_ELEMENT3:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN2]], i64 1
+  // CHECK: %[[V8:.*]] = load i8*, i8** @g0, align 8
+  // CHECK: %[[V9:.*]] = call i8* @llvm.objc.retain(i8* %[[V8]])
+  // CHECK: store i8* %[[V9]], i8** %[[ARRAYINIT_ELEMENT3]], align 8
+  // CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1
+  // CHECK: %[[ARRAYDECAY5:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i64 0, i64 0
+
+  // CHECK: %[[COND6:.*]] = phi i8** [ %[[ARRAYDECAY]], %{{.*}} ], [ %[[ARRAYDECAY5]], %{{.*}} ]
+  // CHECK: store i8** %[[COND6]], i8*** %[[P]], align 8
+  // CHECK: call void @test2(
+
+  // CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0
+  // CHECK: %[[V11:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN]], i64 2
+
+  // CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi i8** [ %[[V11]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], %{{.*}} ]
+  // CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1
+  // CHECK: %[[V12:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT]], align 8
+  // CHECK: call void @llvm.objc.release(i8* %[[V12]])
+
+  // CHECK: %[[ARRAY_BEGIN10:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i32 0, i32 0
+  // CHECK: %[[V13:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN10]], i64 2
+
+  // CHECK: %[[ARRAYDESTROY_ELEMENTPAST12:.*]] = phi i8** [ %[[V13]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT13:.*]], %{{.*}} ]
+  // CHECK: %[[ARRAYDESTROY_ELEMENT13]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST12]], i64 -1
+  // CHECK: %[[V14:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT13]], align 8
+  // CHECK: call void @llvm.objc.release(i8* %[[V14]])
+}
+
 // CHECK: attributes [[NUW]] = { nounwind }
diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m
index 31ecb53..560a084 100644
--- a/clang/test/CodeGenObjC/arc.m
+++ b/clang/test/CodeGenObjC/arc.m
@@ -1557,6 +1557,43 @@
   getAggDtor();
 }
 
+// Check that no extra release calls are emitted to detruct the compond literal.
+
+// CHECK: define void @test72(i8* %[[A:.*]], i8* %[[B:.*]])
+// CHECK: %[[A_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[T:.*]] = alloca [2 x i8*], align 16
+// CHECK: %[[V0:.*]] = call i8* @llvm.objc.retain(i8* %[[A]])
+// CHECK: %[[V1:.*]] = call i8* @llvm.objc.retain(i8* %[[B]]) #2
+// CHECK: %[[ARRAYINIT_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[T]], i64 0, i64 0
+// CHECK: %[[V3:.*]] = load i8*, i8** %[[A_ADDR]], align 8, !tbaa !7
+// CHECK: %[[V4:.*]] = call i8* @llvm.objc.retain(i8* %[[V3]]) #2
+// CHECK: store i8* %[[V4]], i8** %[[ARRAYINIT_BEGIN]], align 8, !tbaa !7
+// CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN]], i64 1
+// CHECK: %[[V5:.*]] = load i8*, i8** %[[B_ADDR]], align 8, !tbaa !7
+// CHECK: %[[V6:.*]] = call i8* @llvm.objc.retain(i8* %[[V5]]) #2
+// CHECK: store i8* %[[V6]], i8** %[[ARRAYINIT_ELEMENT]], align 8, !tbaa !7
+// CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[T]], i32 0, i32 0
+// CHECK: %[[V7:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN]], i64 2
+
+// CHECK-NOT: call void @llvm.objc.release
+
+// CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi i8** [ %[[V7]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], %{{.*}} ]
+// CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1
+// CHECK: %[[V8:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT]], align 8
+// CHECK: call void @llvm.objc.release(i8* %[[V8]]) #2, !clang.imprecise_release !10
+
+// CHECK-NOT: call void @llvm.objc.release
+
+// CHECK: %[[V10:.*]] = load i8*, i8** %[[B_ADDR]], align 8
+// CHECK: call void @llvm.objc.release(i8* %[[V10]]) #2, !clang.imprecise_release !10
+// CHECK: %[[V11:.*]] = load i8*, i8** %[[A_ADDR]], align 8
+// CHECK: call void @llvm.objc.release(i8* %[[V11]]) #2, !clang.imprecise_release !10
+
+void test72(id a, id b) {
+  __strong id t[] = (__strong id[]){a, b};
+}
+
 // ARC-ALIEN: attributes [[NLB]] = { nonlazybind }
 // ARC-NATIVE: attributes [[NLB]] = { nonlazybind }
 // CHECK: attributes [[NUW]] = { nounwind }
diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m
index eae5013..34bf032 100644
--- a/clang/test/CodeGenObjC/strong-in-c-struct.m
+++ b/clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -709,4 +709,103 @@
   VolatileArray t = *a;
 }
 
+// CHECK: define void @test_compound_literal0(
+// CHECK: %[[P:.*]] = alloca %[[STRUCT_STRONGSMALL]]*, align 8
+// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1
+// CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1
+
+// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 0
+// CHECK: store i32 1, i32* %[[I]], align 8
+// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 1
+// CHECK: store i8* null, i8** %[[F1]], align 8
+// CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1
+
+// CHECK: %[[I2:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0
+// CHECK: store i32 2, i32* %[[I2]], align 8
+// CHECK: %[[F13:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 1
+// CHECK: store i8* null, i8** %[[F13]], align 8
+// CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1
+
+// CHECK: %[[COND:.*]] = phi %[[STRUCT_STRONGSMALL]]* [ %[[_COMPOUNDLITERAL]], %{{.*}} ], [ %[[_COMPOUNDLITERAL1]], %{{.*}} ]
+// CHECK: store %[[STRUCT_STRONGSMALL]]* %[[COND]], %[[STRUCT_STRONGSMALL]]** %[[P]], align 8
+// CHECK: call void @func(
+
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V1]])
+
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V2]])
+
+void test_compound_literal0(int c) {
+  StrongSmall *p = c ? &(StrongSmall){ 1, 0 } : &(StrongSmall){ 2, 0 };
+  func(0);
+}
+
+// Check that there is only one destructor call, which destructs 't'.
+
+// CHECK: define void @test_compound_literal1(
+// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+
+// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 0
+// CHECK: store i32 1, i32* %[[I]], align 8
+// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 1
+// CHECK: store i8* null, i8** %[[F1]], align 8
+
+// CHECK: %[[I1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 0
+// CHECK: store i32 2, i32* %[[I1]], align 8
+// CHECK: %[[F12:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 1
+// CHECK: store i8* null, i8** %[[F12]], align 8
+
+// CHECK: call void @func(
+// CHECK-NOT: call void
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[T]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V1]])
+// CHECK-NOT: call void
+
+void test_compound_literal1(int c) {
+  StrongSmall t = c ? (StrongSmall){ 1, 0 } : (StrongSmall){ 2, 0 };
+  func(0);
+}
+
+// CHECK: define void @test_compound_literal2(
+// CHECK: %[[P_ADDR:.*]] = alloca %[[STRUCT_STRONGSMALL]]*, align 8
+// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1
+// CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1
+// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGSMALL]]*, %[[STRUCT_STRONGSMALL]]** %[[P_ADDR]], align 8
+
+// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 0
+// CHECK: store i32 1, i32* %[[I]], align 8
+// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 1
+// CHECK: store i8* null, i8** %[[F1]], align 8
+// CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[V0]] to i8**
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8**
+// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** %[[V2]], i8** %[[V3]])
+
+// CHECK: %[[I2:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0
+// CHECK: store i32 2, i32* %[[I2]], align 8
+// CHECK: %[[F13:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 1
+// CHECK: store i8* null, i8** %[[F13]], align 8
+// CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1
+// CHECK: %[[V4:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[V0]] to i8**
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8**
+// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** %[[V4]], i8** %[[V5]])
+
+// CHECK: call void @func(
+
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+// CHECK: %[[V7:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V7]])
+
+void test_compound_literal2(int c, StrongSmall *p) {
+  *p = c ? (StrongSmall){ 1, 0 } : (StrongSmall){ 2, 0 };
+  func(0);
+}
+
 #endif /* USESTRUCT */
diff --git a/clang/test/Import/objc-arc/Inputs/cleanup-objects.m b/clang/test/Import/objc-arc/Inputs/cleanup-objects.m
new file mode 100644
index 0000000..9c18399
--- /dev/null
+++ b/clang/test/Import/objc-arc/Inputs/cleanup-objects.m
@@ -0,0 +1,10 @@
+typedef struct {
+  id x;
+} S;
+
+id getObj(int c, id a) {
+  // Commenting out the following line because AST importer crashes when trying
+  // to import a BlockExpr.
+  // return c ? ^{ return a; }() : ((S){ .x = a }).x;
+  return ((S){ .x = a }).x;
+}
diff --git a/clang/test/Import/objc-arc/test-cleanup-object.m b/clang/test/Import/objc-arc/test-cleanup-object.m
new file mode 100644
index 0000000..aab1cd3
--- /dev/null
+++ b/clang/test/Import/objc-arc/test-cleanup-object.m
@@ -0,0 +1,10 @@
+// RUN: clang-import-test -x objective-c -objc-arc -import %S/Inputs/cleanup-objects.m -dump-ast -expression %s | FileCheck %s
+
+// CHECK: FunctionDecl {{.*}} getObj '
+// CHECK: ExprWithCleanups
+// CHECK-NEXT: cleanup CompoundLiteralExpr
+
+void test(int c, id a) {
+  (void)getObj(c, a);
+}
+
diff --git a/clang/test/PCH/non-trivial-c-compound-literal.m b/clang/test/PCH/non-trivial-c-compound-literal.m
new file mode 100644
index 0000000..d4e3c1f
--- /dev/null
+++ b/clang/test/PCH/non-trivial-c-compound-literal.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -include-pch %t -emit-llvm -o - %s | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef struct {
+  id f;
+} S;
+
+static inline id getObj(id a) {
+  S *p = &(S){ .f = a };
+  return p->f;
+}
+
+#else
+
+// CHECK: %[[STRUCT_S:.*]] = type { i8* }
+
+// CHECK: define internal i8* @getObj(
+// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_S]],
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_S]]* %[[_COMPOUNDLITERAL]] to i8**
+// CHECK: call void @__destructor_8_s0(i8** %[[V5]])
+
+id test(id a) {
+  return getObj(a);
+}
+
+#endif
diff --git a/clang/test/SemaObjC/strong-in-c-struct.m b/clang/test/SemaObjC/strong-in-c-struct.m
index 5dd5f94..5d2f4e4 100644
--- a/clang/test/SemaObjC/strong-in-c-struct.m
+++ b/clang/test/SemaObjC/strong-in-c-struct.m
@@ -54,3 +54,21 @@
   func(^{ func2(x); });
   goto *ips; // expected-error {{cannot jump}}
 }
+
+void test_compound_literal0(int cond, id x) {
+  switch (cond) {
+  case 0:
+    (void)(Strong){ .a = x }; // expected-note {{jump enters lifetime of a compound literal that is non-trivial to destruct}}
+    break;
+  default: // expected-error {{cannot jump from switch statement to this case label}}
+    break;
+  }
+}
+
+void test_compound_literal1(id x) {
+  static void *ips[] = { &&L0 };
+L0:  // expected-note {{possible target of indirect goto}}
+  ;
+  (void)(Strong){ .a = x }; // expected-note {{jump exits lifetime of a compound literal that is non-trivial to destruct}}
+  goto *ips; // expected-error {{cannot jump}}
+}