ahatanak updated this revision to Diff 127591.
ahatanak added a comment.

Address review comments. Changed the mangling of special functions to make it a 
bit easier to read.


https://reviews.llvm.org/D41228

Files:
  docs/LanguageExtensions.rst
  include/clang/AST/Decl.h
  include/clang/AST/Type.h
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ASTContext.cpp
  lib/AST/Decl.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGDeclCXX.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/CMakeLists.txt
  lib/CodeGen/CodeGenFunction.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Sema/JumpDiagnostics.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  test/ARCMT/checking.m
  test/CodeGenObjC/strong-in-c-struct.m
  test/Lexer/has_feature_objc_arc.m
  test/SemaObjC/arc-decls.m
  test/SemaObjC/arc-system-header.m
  test/SemaObjC/strong-in-c-struct.m

Index: test/SemaObjC/strong-in-c-struct.m
===================================================================
--- /dev/null
+++ test/SemaObjC/strong-in-c-struct.m
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks  -fobjc-runtime=ios-11.0 -fsyntax-only -verify %s
+
+typedef struct {
+  id a;
+} Strong;
+
+void callee_variadic(const char *, ...);
+
+void test_variadic(void) {
+  Strong t;
+  callee_variadic("s", t); // expected-error {{cannot pass non-trivial C object of type 'Strong' by value to variadic function}}
+}
+
+void test_jump0(int cond) {
+  switch (cond) {
+  case 0:
+    ;
+    Strong x; // expected-note {{jump bypasses initialization of variable of non-trivial C struct type}}
+    break;
+  case 1: // expected-error {{cannot jump from switch statement to this case label}}
+    x.a = 0;
+    break;
+  }
+}
+
+void test_jump1(void) {
+  static void *ips[] = { &&L0 };
+L0:  // expected-note {{possible target of indirect goto}}
+  ;
+  Strong x; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+  goto *ips; // expected-error {{cannot jump}}
+}
+
+typedef void (^BlockTy)(void);
+void func(BlockTy);
+void func2(Strong);
+
+void test_block_scope0(int cond) {
+  Strong x; // expected-note {{jump enters lifetime of block which captures a C struct that is non-trivial to destroy}}
+  switch (cond) {
+  case 0:
+    func(^{ func2(x); });
+    break;
+  default: // expected-error {{cannot jump from switch statement to this case label}}
+    break;
+  }
+}
+
+void test_block_scope1(void) {
+  static void *ips[] = { &&L0 };
+L0:  // expected-note {{possible target of indirect goto}}
+  ;
+  Strong x; // expected-note {{jump exits scope of variable with non-trivial destructor}} expected-note {{jump exits lifetime of block which captures a C struct that is non-trivial to destroy}}
+  func(^{ func2(x); });
+  goto *ips; // expected-error {{cannot jump}}
+}
Index: test/SemaObjC/arc-system-header.m
===================================================================
--- test/SemaObjC/arc-system-header.m
+++ test/SemaObjC/arc-system-header.m
@@ -23,8 +23,7 @@
 }
 
 void test5(struct Test5 *p) {
-  p->field = 0; // expected-error {{'field' is unavailable in ARC}}
-                // expected-note@arc-system-header.h:25 {{field has non-trivial ownership qualification}}
+  p->field = 0;
 }
 
 id test6() {
@@ -49,8 +48,7 @@
 
 extern void doSomething(Test9 arg);
 void test9() {
-    Test9 foo2 = {0, 0}; // expected-error {{'field' is unavailable in ARC}}
-                         // expected-note@arc-system-header.h:56 {{field has non-trivial ownership qualification}}
+    Test9 foo2 = {0, 0};
     doSomething(foo2);
 }
 #endif
Index: test/SemaObjC/arc-decls.m
===================================================================
--- test/SemaObjC/arc-decls.m
+++ test/SemaObjC/arc-decls.m
@@ -3,7 +3,7 @@
 // rdar://8843524
 
 struct A {
-    id x; // expected-error {{ARC forbids Objective-C objects in struct}}
+    id x;
 };
 
 union u {
@@ -13,7 +13,7 @@
 @interface I {
    struct A a; 
    struct B {
-    id y[10][20]; // expected-error {{ARC forbids Objective-C objects in struct}}
+    id y[10][20];
     id z;
    } b;
 
@@ -23,7 +23,7 @@
 
 // rdar://10260525
 struct r10260525 {
-  id (^block) (); // expected-error {{ARC forbids blocks in struct}}
+  id (^block) ();
 };
 
 struct S { 
Index: test/Lexer/has_feature_objc_arc.m
===================================================================
--- test/Lexer/has_feature_objc_arc.m
+++ test/Lexer/has_feature_objc_arc.m
@@ -13,8 +13,16 @@
 void no_objc_arc_weak_feature();
 #endif
 
+#if __has_feature(objc_arc_fields)
+void has_objc_arc_fields();
+#else
+void no_objc_arc_fields();
+#endif
+
 // CHECK-ARC: void has_objc_arc_feature();
 // CHECK-ARC: void has_objc_arc_weak_feature();
+// CHECK-ARC: void has_objc_arc_fields();
 
 // CHECK-ARCLITE: void has_objc_arc_feature();
 // CHECK-ARCLITE: void no_objc_arc_weak_feature();
+// CHECK-ARCLITE: void has_objc_arc_fields();
Index: test/CodeGenObjC/strong-in-c-struct.m
===================================================================
--- /dev/null
+++ test/CodeGenObjC/strong-in-c-struct.m
@@ -0,0 +1,443 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks  -fobjc-runtime=ios-11.0 -emit-llvm -o - %s | FileCheck %s
+
+typedef void (^BlockTy)(void);
+
+typedef struct {
+  int a[4];
+} Trivial;
+
+typedef struct {
+  Trivial f0;
+  id f1;
+} Strong;
+
+typedef struct {
+  int i;
+  id f1;
+} StrongSmall;
+
+typedef struct {
+  Strong f0;
+  id f1;
+  double d;
+} StrongOuter;
+
+typedef struct {
+  int f0;
+  volatile id f1;
+} StrongVolatile;
+
+typedef struct {
+  BlockTy f0;
+} StrongBlock;
+
+typedef struct {
+  int i;
+  id f0[2][2];
+} IDArray;
+
+typedef struct {
+  double d;
+  Strong f0[2][2];
+} StructArray;
+
+StrongSmall getStrongSmall(void);
+StrongOuter getStrongOuter(void);
+void calleeStrongSmall(StrongSmall);
+void func(Strong *);
+
+// CHECK: define void @test_constructor_destructor_StrongOuter()
+// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER:.*]], align 8
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8**
+// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V0]])
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8**
+// CHECK: call void @__destructor_8_s16_s24(i8** %[[V1]])
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16_s24(i8** %[[DST:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: call void @__default_constructor_8_s16(i8** %[[V0]])
+// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 24
+// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
+// CHECK: %[[V4:.*]] = bitcast i8** %[[V3]] to i8*
+// CHECK: call void @llvm.memset.p0i8.i64(i8* %[[V4]], i8 0, i64 8, i32 8, i1 false)
+// CHECK: %[[V5:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 32
+// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16(i8** %[[DST:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 16
+// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
+// CHECK: %[[V4:.*]] = bitcast i8** %[[V3]] to i8*
+// CHECK: call void @llvm.memset.p0i8.i64(i8* %[[V4]], i8 0, i64 8, i32 8, i1 false)
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__destructor_8_s16_s24(i8** %[[DST:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: call void @__destructor_8_s16(i8** %[[V0]])
+// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 24
+// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
+// CHECK: call void @objc_storeStrong(i8** %[[V3]], i8* null)
+// CHECK: %[[V4:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V5:.*]] = getelementptr inbounds i8, i8* %[[V4]], i64 32
+// CHECK: %[[V6:.*]] = bitcast i8* %[[V5]] to i8**
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__destructor_8_s16(i8** %[[DST:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 16
+// CHECK: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
+// CHECK: call void @objc_storeStrong(i8** %[[V3]], i8* null)
+// CHECK: ret void
+
+void test_constructor_destructor_StrongOuter(void) {
+  StrongOuter t;
+}
+
+// CHECK: define void @test_copy_constructor_StrongOuter(%[[STRUCT_STRONGOUTER:.*]]* %[[S:.*]])
+// CHECK: %[[S_ADDR:.*]] = alloca %[[STRUCT_STRONGOUTER]]*, align 8
+// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER]], align 8
+// CHECK: store %[[STRUCT_STRONGOUTER]]* %[[S]], %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGOUTER]]*, %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[V0]] to i8**
+// CHECK: call void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8**
+// CHECK: call void @__destructor_8_s16_s24(i8** %[[V3]])
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: call void @__copy_constructor_8_8_t0w16_s16(i8** %[[V0]], i8** %[[V1]])
+// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24
+// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8**
+// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24
+// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8
+// CHECK: %[[V9:.*]] = call i8* @objc_retain(i8* %[[V8]])
+// CHECK: store i8* %[[V9]], i8** %[[V4]], align 8
+// CHECK: %[[V10:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V11:.*]] = getelementptr inbounds i8, i8* %[[V10]], i64 32
+// CHECK: %[[V12:.*]] = bitcast i8* %[[V11]] to i8**
+// CHECK: %[[V13:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: %[[V14:.*]] = getelementptr inbounds i8, i8* %[[V13]], i64 32
+// CHECK: %[[V15:.*]] = bitcast i8* %[[V14]] to i8**
+// CHECK: %[[V16:.*]] = bitcast i8** %[[V12]] to double*
+// CHECK: %[[V17:.*]] = bitcast i8** %[[V15]] to double*
+// CHECK: %[[V18:.*]] = load double, double* %[[V17]], align 8
+// CHECK: store double %[[V18]], double* %[[V16]], align 8
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V3:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[V2]], i8* %[[V3]], i64 16, i32 8, i1 false)
+// CHECK: %[[V4:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V5:.*]] = getelementptr inbounds i8, i8* %[[V4]], i64 16
+// CHECK: %[[V6:.*]] = bitcast i8* %[[V5]] to i8**
+// CHECK: %[[V7:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: %[[V8:.*]] = getelementptr inbounds i8, i8* %[[V7]], i64 16
+// CHECK: %[[V9:.*]] = bitcast i8* %[[V8]] to i8**
+// CHECK: %[[V10:.*]] = load i8*, i8** %[[V9]], align 8
+// CHECK: %[[V11:.*]] = call i8* @objc_retain(i8* %[[V10]])
+// CHECK: store i8* %[[V11]], i8** %[[V6]], align 8
+// CHECK: ret void
+
+void test_copy_constructor_StrongOuter(StrongOuter *s) {
+  StrongOuter t = *s;
+}
+
+/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24
+// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8**
+// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24
+// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8
+// CHECK: call void @objc_storeStrong(i8** %[[V4]], i8* %[[V8]])
+
+void test_copy_assignment_StrongOuter(StrongOuter *d, StrongOuter *s) {
+  *d = *s;
+}
+
+// CHECK: define internal void @__Block_byref_object_copy_(i8*, i8*)
+// CHECK: call void @__move_constructor_8_8_t0w16_s16_s24_t32w8(
+
+// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: call void @__move_constructor_8_8_t0w16_s16(i8** %[[V0]], i8** %[[V1]])
+// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24
+// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8**
+// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24
+// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8
+// CHECK: store i8* null, i8** %[[V7]], align 8
+// CHECK: store i8* %[[V8]], i8** %[[V4]], align 8
+
+// CHECK: define internal void @__Block_byref_object_dispose_(i8*)
+// CHECK: call void @__destructor_8_s16_s24(
+
+void test_move_constructor_StrongOuter(void) {
+  __block StrongOuter t;
+  BlockTy b = ^{ (void)t; };
+}
+
+// CHECK: define linkonce_odr hidden void @__move_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: call void @__move_assignment_8_8_t0w16_s16(i8** %[[V0]], i8** %[[V1]])
+// CHECK: %[[V2:.*]] = bitcast i8** %[[V0]] to i8*
+// CHECK: %[[V3:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 24
+// CHECK: %[[V4:.*]] = bitcast i8* %[[V3]] to i8**
+// CHECK: %[[V5:.*]] = bitcast i8** %[[V1]] to i8*
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 24
+// CHECK: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// CHECK: %[[V8:.*]] = load i8*, i8** %[[V7]], align 8
+// CHECK: store i8* null, i8** %[[V7]], align 8
+// CHECK: %[[V9:.*]] = load i8*, i8** %[[V4]], align 8
+// CHECK: store i8* %[[V8]], i8** %[[V4]], align 8
+// CHECK: call void @objc_release(i8* %[[V9]])
+
+void test_move_assignment_StrongOuter(StrongOuter *p) {
+  *p = getStrongOuter();
+}
+
+// CHECK: define void @test_parameter_StrongSmall([2 x i64] %[[A_COERCE:.*]])
+// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG:.*]], align 8
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONG]]* %[[A]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[A_COERCE]], [2 x i64]* %[[V0]], align 8
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONG]]* %[[A]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V1]])
+// CHECK: ret void
+
+void test_parameter_StrongSmall(StrongSmall a) {
+}
+
+// CHECK: define void @test_argument_StrongSmall([2 x i64] %[[A_COERCE:.*]])
+// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONGSMALL:.*]], align 8
+// CHECK: %[[TEMP_LVALUE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[A_COERCE]], [2 x i64]* %[[V0]], align 8
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TEMP_LVALUE]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8**
+// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TEMP_LVALUE]] to [2 x i64]*
+// CHECK: %[[V4:.*]] = load [2 x i64], [2 x i64]* %[[V3]], align 8
+// CHECK: call void @calleeStrongSmall([2 x i64] %[[V4]])
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: ret void
+
+void test_argument_StrongSmall(StrongSmall a) {
+  calleeStrongSmall(a);
+}
+
+// CHECK: define [2 x i64] @test_return_StrongSmall([2 x i64] %[[A_COERCE:.*]])
+// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONGSMALL:.*]], align 8
+// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[A_COERCE]], [2 x i64]* %[[V0]], align 8
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[RETVAL]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8**
+// CHECK: call void @__copy_constructor_8_8_t0w4_s8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[A]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: %[[V4:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[RETVAL]] to [2 x i64]*
+// CHECK: %[[V5:.*]] = load [2 x i64], [2 x i64]* %[[V4]], align 8
+// CHECK: ret [2 x i64] %[[V5]]
+
+StrongSmall test_return_StrongSmall(StrongSmall a) {
+  return a;
+}
+
+// CHECK: define void @test_destructor_ignored_result()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL:.*]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64] @getStrongSmall()
+// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V0]], align 8
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V1]])
+// CHECK: ret void
+
+void test_destructor_ignored_result(void) {
+  getStrongSmall();
+}
+
+// CHECK: define void @test_copy_constructor_StrongBlock(
+// CHECK: call void @__copy_constructor_8_8_sb0(
+// CHECK: call void @__destructor_8_sb0(
+// CHECK: ret void
+
+// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_sb0(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V2:.*]] = load i8*, i8** %[[V1]], align 8
+// CHECK: %[[V3:.*]] = call i8* @objc_retainBlock(i8* %[[V2]])
+// CHECK: store i8* %[[V3]], i8** %[[V0]], align 8
+// CHECK: ret void
+
+void test_copy_constructor_StrongBlock(StrongBlock *s) {
+  StrongBlock t = *s;
+}
+
+// CHECK: define void @test_copy_assignment_StrongBlock(%[[STRUCT_STRONGBLOCK:.*]]* %[[D:.*]], %[[STRUCT_STRONGBLOCK]]* %[[S:.*]])
+// CHECK: call void @__copy_assignment_8_8_sb0(
+
+// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_sb0(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// CHECK: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// CHECK: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// CHECK: %[[V2:.*]] = load i8*, i8** %[[V1]], align 8
+// CHECK: %[[V3:.*]] = call i8* @objc_retainBlock(i8* %[[V2]])
+// CHECK: %[[V4:.*]] = load i8*, i8** %[[V0]], align 8
+// CHECK: store i8* %[[V3]], i8** %[[V0]], align 8
+// CHECK: call void @objc_release(i8* %[[V4]])
+// CHECK: ret void
+
+void test_copy_assignment_StrongBlock(StrongBlock *d, StrongBlock *s) {
+  *d = *s;
+}
+
+// CHECK: define void @test_copy_constructor_StrongVolatile0(
+// CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK: call void @__destructor_8_sv8(
+
+// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
+// CHECK: %[[V9:.*]] = call i8* @objc_retain(i8* %[[V8]])
+// CHECK: store volatile i8* %[[V9]], i8** %{{.*}}, align 8
+
+void test_copy_constructor_StrongVolatile0(StrongVolatile *s) {
+  StrongVolatile t = *s;
+}
+
+// CHECK: define void @test_copy_constructor_StrongVolatile1(
+// CHECK: call void @__copy_constructor_8_8_tv0w16_sv16(
+
+void test_copy_constructor_StrongVolatile1(Strong *s) {
+  volatile Strong t = *s;
+}
+
+// CHECK: define void @test_block_capture_Strong()
+// CHECK: call void @__default_constructor_8_s16(
+// CHECK: call void @__copy_constructor_8_8_t0w16_s16(
+// CHECK: call void @__destructor_8_s16(
+// CHECK: call void @__destructor_8_s16(
+// CHECK: ret void
+
+// CHECK: define internal void @__copy_helper_block_.1(i8*, i8*)
+// CHECK: call void @__copy_constructor_8_8_t0w16_s16(
+// CHECK: ret void
+
+// CHECK: define internal void @__destroy_helper_block_.2(
+// CHECK: call void @__destructor_8_s16(
+// CHECK: ret void
+
+void test_block_capture_Strong(void) {
+  Strong t;
+  BlockTy b = ^(){ (void)t; };
+}
+
+// CHECK: define void @test_variable_length_array(i32 %[[N:.*]])
+// CHECK: %[[N_ADDR:.*]] = alloca i32, align 4
+// CHECK: store i32 %[[N]], i32* %[[N_ADDR]], align 4
+// CHECK: %[[V0:.*]] = load i32, i32* %[[N_ADDR]], align 4
+// CHECK: %[[V1:.*]] = zext i32 %[[V0]] to i64
+// CHECK: %[[VLA:.*]] = alloca %[[STRUCT_STRONG:.*]], i64 %[[V1]], align 8
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONG]]* %[[VLA]] to i8**
+// CHECK: %[[V4:.*]] = mul nuw i64 24, %[[V1]]
+// CHECK: %[[V5:.*]] = bitcast i8** %[[V3]] to i8*
+// CHECK: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 %[[V4]]
+// CHECK: %[[DSTARRAY_END:.*]] = bitcast i8* %[[V6]] to i8**
+// CHECK: br label
+
+// CHECK: %[[DSTADDR_CUR:.*]] = phi i8** [ %[[V3]], {{.*}} ], [ %[[V7:.*]], {{.*}} ]
+// CHECK: %[[DONE:.*]] = icmp eq i8** %[[DSTADDR_CUR]], %[[DSTARRAY_END]]
+// CHECK: br i1 %[[DONE]], label
+
+// CHECK: call void @__default_constructor_8_s16(i8** %[[DSTADDR_CUR]])
+// CHECK: %[[V8:.*]] = bitcast i8** %[[DSTADDR_CUR]] to i8*
+// CHECK: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 24
+// CHECK: %[[V7]] = bitcast i8* %[[V9]] to i8**
+// CHECK: br label
+
+// CHECK: call void @func(%[[STRUCT_STRONG]]* %[[VLA]])
+// CHECK: %[[V10:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[VLA]], i64 %[[V1]]
+// CHECK: %[[ARRAYDESTROY_ISEMPTY:.*]] = icmp eq %[[STRUCT_STRONG]]* %[[VLA]], %[[V10]]
+// CHECK: br i1 %[[ARRAYDESTROY_ISEMPTY]], label
+
+// CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi %[[STRUCT_STRONG]]* [ %[[V10]], {{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], {{.*}} ]
+// CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1
+// CHECK: %[[V11:.*]] = bitcast %[[STRUCT_STRONG]]* %[[ARRAYDESTROY_ELEMENT]] to i8**
+// CHECK: call void @__destructor_8_s16(i8** %[[V11]])
+// CHECK: %[[ARRAYDESTROY_DONE:.*]] = icmp eq %[[STRUCT_STRONG]]* %[[ARRAYDESTROY_ELEMENT]], %[[VLA]]
+// CHECK: br i1 %[[ARRAYDESTROY_DONE]], label
+
+// CHECK: ret void
+
+void test_variable_length_array(int n) {
+  Strong a[n];
+  func(a);
+}
+
+// CHECK: define linkonce_odr hidden void @__default_constructor_8_AB8s8n4_s8_AE(
+void test_constructor_destructor_IDArray(void) {
+  IDArray t;
+}
+
+// CHECK: define linkonce_odr hidden void @__default_constructor_8_AB8s24n4_s24_AE(
+void test_constructor_destructor_StructArray(void) {
+  StructArray t;
+}
Index: test/ARCMT/checking.m
===================================================================
--- test/ARCMT/checking.m
+++ test/ARCMT/checking.m
@@ -116,7 +116,7 @@
 }
 
 struct S {
-  A* a; // expected-error {{ARC forbids Objective-C objects in struct}}
+  A* a;
 };
 
 @interface B
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -776,6 +776,9 @@
     return VAK_Valid;
   }
 
+  if (Ty.nonTrivialToDestroy())
+    return VAK_Invalid;
+
   if (Ty.isCXX98PODType(Context))
     return VAK_Valid;
 
@@ -837,7 +840,10 @@
     break;
 
   case VAK_Invalid:
-    if (Ty->isObjCObjectType())
+    if (Ty.hasNonTrivialToDestroyStruct())
+      Diag(E->getLocStart(),
+           diag::err_cannot_pass_non_trivial_c_struct_to_vararg) << Ty << CT;
+    else if (Ty->isObjCObjectType())
       DiagRuntimeBehavior(
           E->getLocStart(), nullptr,
           PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10941,6 +10941,9 @@
     }
   }
 
+  if (var->getType().hasNonTrivialToDestroyStruct())
+    getCurFunction()->setHasBranchProtectedScope();
+
   // Warn about externally-visible variables being defined without a
   // prior declaration.  We only want to do this for global
   // declarations, but we also specifically need to avoid doing it for
@@ -14823,6 +14826,7 @@
 
     // Get the type for the field.
     const Type *FDTy = FD->getType().getTypePtr();
+    Qualifiers QS = FD->getType().getQualifiers();
 
     if (!FD->isAnonymousStructOrUnion()) {
       // Remember all fields written by the user.
@@ -14964,7 +14968,9 @@
       FD->setType(T);
     } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
                Record && !ObjCFieldLifetimeErrReported &&
-               (!getLangOpts().CPlusPlus || Record->isUnion())) {
+               ((!getLangOpts().CPlusPlus &&
+                 QS.getObjCLifetime() == Qualifiers::OCL_Weak) ||
+                Record->isUnion())) {
       // It's an error in ARC or Weak if a field has lifetime.
       // We don't want to report this in a system header, though,
       // so we just make the field unavailable.
@@ -15000,6 +15006,13 @@
                Record->setHasObjectMember(true);
       }
     }
+
+    if (Record && !getLangOpts().CPlusPlus) {
+      QualType FT = FD->getType();
+      if (FT.hasObjCStrongPointer())
+        Record->setHasStrongObjCPointer(true);
+    }
+
     if (Record && FD->getType().isVolatileQualified())
       Record->setHasVolatileMember(true);
     // Keep track of the number of named members.
Index: lib/Sema/JumpDiagnostics.cpp
===================================================================
--- lib/Sema/JumpDiagnostics.cpp
+++ lib/Sema/JumpDiagnostics.cpp
@@ -154,6 +154,10 @@
         return ScopePair(diag::note_protected_by_objc_weak_init,
                          diag::note_exits_objc_weak);
 
+      case QualType::DK_c_struct_strong_field:
+        return ScopePair(diag::note_protected_by_non_trivial_c_struct_init,
+                         diag::note_exits_dtor);
+
       case QualType::DK_cxx_destructor:
         OutDiag = diag::note_exits_dtor;
         break;
@@ -254,6 +258,10 @@
         Diags = ScopePair(diag::note_enters_block_captures_weak,
                           diag::note_exits_block_captures_weak);
         break;
+      case QualType::DK_c_struct_strong_field:
+        Diags = ScopePair(diag::note_enters_block_captures_non_trivial_c_struct,
+                          diag::note_exits_block_captures_non_trivial_c_struct);
+        break;
       case QualType::DK_none:
         llvm_unreachable("non-lifetime captured variable");
     }
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1146,6 +1146,7 @@
       // Objective-C features
       .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
       .Case("objc_arc", LangOpts.ObjCAutoRefCount)
+      .Case("objc_arc_fields", true)
       .Case("objc_arc_weak", LangOpts.ObjCWeak)
       .Case("objc_default_synthesize_properties", LangOpts.ObjC2)
       .Case("objc_fixed_enum", LangOpts.ObjC2)
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1534,6 +1534,7 @@
     case QualType::DK_objc_weak_lifetime:
       return getLangOpts().Exceptions;
     case QualType::DK_objc_strong_lifetime:
+    case QualType::DK_c_struct_strong_field:
       return getLangOpts().Exceptions &&
              CGM.getCodeGenOpts().ObjCAutoRefCountExceptions;
     }
@@ -3330,6 +3331,22 @@
                                                CXXDtorType Type,
                                                const CXXRecordDecl *RD);
 
+  // These functions emit calls to the special functions of non-trivial C
+  // structs.
+  void defaultInitNonTrivialCStructVar(Address DstPtr, QualType QT,
+                                       bool IsVolatile);
+  void callCStructDefaultConstructor(Address DstPtr, QualType QT,
+                                     bool IsVolatile);
+  void callCStructCopyConstructor(Address DstPtr, Address SrcPtr,
+                                  QualType QT, bool IsVolatile);
+  void callCStructMoveConstructor(Address DstPtr, Address SrcPtr,
+                                  QualType QT, bool IsVolatile);
+  void callCStructCopyAssignmentOperator(Address DstPtr, Address SrcPtr,
+                                         QualType QT, bool IsVolatile);
+  void callCStructMoveAssignmentOperator(Address DstPtr, Address SrcPtr,
+                                         QualType QT, bool IsVolatile);
+  void callCStructDestructor(Address DstPtr, QualType QT, bool IsVolatile);
+
   RValue
   EmitCXXMemberOrOperatorCall(const CXXMethodDecl *Method,
                               const CGCallee &Callee,
@@ -3501,6 +3518,7 @@
   static Destroyer destroyARCStrongPrecise;
   static Destroyer destroyARCWeak;
   static Destroyer emitARCIntrinsicUse;
+  static Destroyer destroyNonTrivialCStruct;
 
   void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
   llvm::Value *EmitObjCAutoreleasePoolPush();
Index: lib/CodeGen/CMakeLists.txt
===================================================================
--- lib/CodeGen/CMakeLists.txt
+++ lib/CodeGen/CMakeLists.txt
@@ -56,6 +56,7 @@
   CGExprScalar.cpp
   CGGPUBuiltin.cpp
   CGLoopInfo.cpp
+  CGNonTrivialStruct.cpp
   CGObjC.cpp
   CGObjCGNU.cpp
   CGObjCMac.cpp
Index: lib/CodeGen/CGNonTrivialStruct.cpp
===================================================================
--- /dev/null
+++ lib/CodeGen/CGNonTrivialStruct.cpp
@@ -0,0 +1,580 @@
+//===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to generate various special functions for C
+// structs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+/// Return an address with the specified offset from the passed address.
+static Address getAddrWithOffset(Address Addr, unsigned Offset,
+                                 CodeGenFunction &CGF) {
+  if (!Addr.isValid() || Offset == 0)
+    return Addr;
+  Addr = CGF.Builder.CreateBitCast(Addr, CGF.CGM.Int8PtrTy);
+  Addr = CGF.Builder.CreateConstInBoundsGEP(Addr, Offset, CharUnits::One());
+  return CGF.Builder.CreateBitCast(Addr, CGF.CGM.Int8PtrPtrTy);
+}
+
+static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM, bool IsBinary,
+                                             FunctionArgList &Args) {
+  ASTContext &Ctx = CGM.getContext();
+  llvm::SmallVector<ImplicitParamDecl *, 2> Params;
+  QualType ParamTy = Ctx.getPointerType(Ctx.VoidPtrTy);
+  Params.push_back(ImplicitParamDecl::Create(Ctx, nullptr, SourceLocation(),
+                                             &Ctx.Idents.get("dst"), ParamTy,
+                                             ImplicitParamDecl::Other));
+
+  if (IsBinary)
+    Params.push_back(ImplicitParamDecl::Create(Ctx, nullptr, SourceLocation(),
+                                               &Ctx.Idents.get("src"), ParamTy,
+                                               ImplicitParamDecl::Other));
+
+  for (auto &P : Params)
+    Args.push_back(P);
+
+  return CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
+}
+
+static std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) {
+  std::string S;
+  if (IsVolatile)
+    S = "v";
+  S += llvm::to_string(Offset.getQuantity());
+  return S;
+}
+
+namespace {
+// This is a helper class that encodes the information about the fields of a
+// non-trivial C struct into the name of its special functions. The string has
+// the following structure:
+//
+// <struct-field-info> ::= <field-info>+
+// <field-info> ::= <struct-or-scalar-field-info> | <array-field-info> |
+// <struct-or-scalar-field-info> ::= <struct-field-info> | <strong-field-info> |
+//                                   <trivial-field-info>
+// <array-field-info> ::= "_AB" <array-offset> "s" <element-size> "n"
+//                        <num-elements> <element-info> "_AE"
+// <element-info> ::= <struct-or-scalar-field-info>
+// <strong-field-info> ::= "_s" ["b"] ["v"] <field-offset>
+// <trivial-field-info> ::= "_t" ["v"] <field-offset> "_" <field-size>
+
+template <class T> class FieldInfoToString {
+public:
+  FieldInfoToString(QualType QT, bool IsVolatile, ASTContext &C) : Ctx(C) {
+    visitStruct(CharUnits::Zero(), QT, IsVolatile);
+  }
+
+  void visitField(CharUnits Offset, QualType QT, bool IsVolatile) {
+    switch (QT.isNonTrivialToCopy(T::isInterestingType, Ctx)) {
+    case QualType::NTFK_Struct:
+      visitStruct(Offset, QT, IsVolatile);
+      break;
+    case QualType::NTFK_Array:
+      visitArray(Offset, QT, IsVolatile);
+      break;
+    case QualType::NTFK_Strong:
+      Str += "_s";
+      if (QT->isBlockPointerType())
+        Str += "b";
+      Str += getVolatileOffsetStr(IsVolatile, Offset);
+      break;
+    case QualType::NTFK_Trivial:
+      // Ignore fields of trivial types if this is a unary special function.
+      if (!T::isBinary())
+        break;
+      Str += "_t" + getVolatileOffsetStr(IsVolatile, Offset) + "w";
+      Str += llvm::to_string(Ctx.getTypeSizeInChars(QT).getQuantity());
+      break;
+    }
+  }
+
+  void visitStruct(CharUnits Offset, QualType QT, bool IsVolatile) {
+    const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
+    const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD);
+
+    // Iterate over the fields of the struct.
+    size_t FieldNo = 0;
+    for (const FieldDecl *FD : RD->fields()) {
+      QualType FT = FD->getType();
+      unsigned FOffsetVal = RL.getFieldOffset(FieldNo++) / Ctx.getCharWidth();
+      CharUnits FOffset = Offset + CharUnits::fromQuantity(FOffsetVal);
+      visitField(FOffset, FT, FT.isVolatileQualified() || IsVolatile);
+    }
+  }
+
+  void visitArray(CharUnits Offset, QualType QT, bool IsVolatile) {
+    const auto *AT = Ctx.getAsConstantArrayType(QT);
+    unsigned NumElts = Ctx.getConstantArrayElementCount(AT);
+    QualType EltTy = Ctx.getBaseElementType(AT);
+    unsigned EltSize = Ctx.getTypeSizeInChars(EltTy).getQuantity();
+    Str += "_AB" + llvm::to_string(Offset.getQuantity()) + "s" +
+           llvm::to_string(EltSize) + "n" + llvm::to_string(NumElts);
+    visitField(Offset, EltTy, IsVolatile);
+    Str += "_AE";
+  }
+
+  operator std::string() const { return Str; }
+
+private:
+  ASTContext &Ctx;
+  std::string Str;
+};
+} // namespace
+
+// This function creates the mangled name of a special function of a non-trivial
+// C struct. Since there is no ODR in C, the function is mangled based on the
+// struct contents and not the name. The mangled name has the following
+// structure:
+//
+// <function-name> ::= <prefix> <alignment-info> "_" <struct-field-info>
+// <prefix> ::= "__destructor_" | "__default_constructor_" |
+//              "__copy_constructor_" | "__move_constructor_" |
+//              "__copy_assignment_" | "__move_assignment_"
+// <alignment-info> ::= <dst-alignment> ["_" <src-alignment>]
+
+template <class T>
+static std::string
+getSpecialFuncName(QualType QT, bool IsVolatile, CharUnits DstAlignment,
+                   CharUnits SrcAlignment, bool IsBinary, CodeGenModule &CGM) {
+  StringRef Prefix = T::getFuncPrefix();
+  std::string S = FieldInfoToString<T>(QT, IsVolatile, CGM.getContext());
+  std::string A = llvm::to_string(DstAlignment.getQuantity());
+  if (IsBinary)
+    A += "_" + llvm::to_string(SrcAlignment.getQuantity());
+  return std::string(Prefix) + A + S;
+}
+
+// Helper function to create a null constant.
+static llvm::Constant *getNullForVariable(Address Addr) {
+  llvm::Type *Ty = Addr.getElementType();
+  return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(Ty));
+}
+
+namespace {
+
+template <class T> class IRGen {
+public:
+  IRGen()
+      : CGF(nullptr), DstStart(Address::invalid()),
+        SrcStart(Address::invalid()) {}
+
+  IRGen(CodeGenFunction &F)
+      : CGF(&F), DstStart(Address::invalid()), SrcStart(Address::invalid()) {}
+
+  void setFunction(CodeGenFunction &F, FunctionArgList &Args,
+                   CharUnits DstAlignment, CharUnits SrcAlignment) {
+    CGF = &F;
+    llvm::Value *D = CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[0]));
+    DstStart = Address(D, DstAlignment);
+    if (isBinary()) {
+      assert(CGF->CurFn->arg_size() == 2 &&
+             "Binary functions expected to have two arguments");
+      llvm::Value *S = CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[1]));
+      SrcStart = Address(S, SrcAlignment);
+    }
+  }
+
+  void visitMostOuterStruct(QualType QT, bool IsVolatile) {
+    visitStruct(DstStart, SrcStart, QT, IsVolatile, false);
+  }
+
+  void visitField(Address DstAddr, Address SrcAddr, QualType QT,
+                  bool IsVolatile) {
+    switch (QT.isNonTrivialToCopy(T::isInterestingType, CGF->getContext())) {
+    case QualType::NTFK_Struct:
+      visitStruct(DstAddr, SrcAddr, QT, IsVolatile);
+      break;
+    case QualType::NTFK_Array:
+      visitArray(DstAddr, SrcAddr, QT, IsVolatile);
+      break;
+    case QualType::NTFK_Strong:
+      if (IsVolatile)
+        QT = QT.withVolatile();
+      T::emitIRStrong(DstAddr, SrcAddr, QT, *CGF);
+      break;
+    case QualType::NTFK_Trivial: {
+      // Ignore fields of trivial types if this is not a copy/move function.
+      if (!T::isBinary())
+        break;
+
+      // Emit load and store if QT is a scalar.
+      if (CGF->getEvaluationKind(QT) == TEK_Scalar) {
+        if (IsVolatile)
+          QT = QT.withVolatile();
+        llvm::Type *PtrTy = CGF->ConvertType(QT)->getPointerTo();
+        DstAddr = CGF->Builder.CreateBitCast(DstAddr, PtrTy);
+        SrcAddr = CGF->Builder.CreateBitCast(SrcAddr, PtrTy);
+        llvm::Value *SrcVal =
+            CGF->EmitLoadOfScalar(SrcAddr, IsVolatile, QT, SourceLocation());
+        CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(DstAddr, QT),
+                               T::isInit());
+        break;
+      }
+
+      // Emit a memcpy if QT is not a scalar.
+      llvm::Value *SizeVal = llvm::ConstantInt::get(
+          CGF->SizeTy, CGF->getContext().getTypeSizeInChars(QT).getQuantity());
+      DstAddr = CGF->Builder.CreateElementBitCast(DstAddr, CGF->Int8Ty);
+      SrcAddr = CGF->Builder.CreateElementBitCast(SrcAddr, CGF->Int8Ty);
+      CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, IsVolatile);
+      break;
+    }
+    }
+  }
+
+  void visitStruct(Address DstAddr, Address SrcAddr, QualType QT,
+                   bool IsVolatile, bool IsField = true) {
+    // Just call the special function if this is a struct field contained in
+    // another struct.
+    if (IsField) {
+      T::callSpecialFunction(DstAddr, SrcAddr, QT, IsVolatile, *CGF);
+      return;
+    }
+
+    const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
+    ASTContext &Ctx = CGF->getContext();
+    const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD);
+
+    // Iterate over the fields of the struct.
+    size_t FieldNo = 0;
+    for (const FieldDecl *FD : RD->fields()) {
+      unsigned FOffset = RL.getFieldOffset(FieldNo++) / Ctx.getCharWidth();
+      Address FieldDstAddr = getAddrWithOffset(DstAddr, FOffset, *CGF);
+      Address FieldSrcAddr = getAddrWithOffset(SrcAddr, FOffset, *CGF);
+      QualType FT = FD->getType();
+      visitField(FieldDstAddr, FieldSrcAddr, FT,
+                 FT.isVolatileQualified() || IsVolatile);
+    }
+  }
+
+  void visitArray(Address DstAddr, Address SrcAddr, QualType QT,
+                  bool IsVolatile) {
+    // Compute the end address.
+    ASTContext &Ctx = CGF->getContext();
+    QualType BaseEltQT;
+    Address TmpAddr = DstAddr;
+    llvm::Value *NumElts =
+        CGF->emitArrayLength(Ctx.getAsArrayType(QT), BaseEltQT, TmpAddr);
+    unsigned BaseEltSize = Ctx.getTypeSizeInChars(BaseEltQT).getQuantity();
+    llvm::Value *BaseEltSizeVal =
+        llvm::ConstantInt::get(NumElts->getType(), BaseEltSize);
+    llvm::Value *SizeInBytes =
+        CGF->Builder.CreateNUWMul(BaseEltSizeVal, NumElts);
+    Address BC = CGF->Builder.CreateBitCast(DstAddr, CGF->CGM.Int8PtrTy);
+    llvm::Value *DstArrayEnd =
+        CGF->Builder.CreateInBoundsGEP(BC.getPointer(), SizeInBytes);
+    DstArrayEnd = CGF->Builder.CreateBitCast(DstArrayEnd, CGF->CGM.Int8PtrPtrTy,
+                                             "dstarray.end");
+    llvm::BasicBlock *PreheaderBB = CGF->Builder.GetInsertBlock();
+
+    // Create the header block and insert the phi instructions.
+    llvm::BasicBlock *HeaderBB = CGF->createBasicBlock("loop.header");
+    CGF->EmitBlock(HeaderBB);
+    llvm::Type *Ty = DstAddr.getPointer()->getType();
+    llvm::PHINode *DstPHI = CGF->Builder.CreatePHI(Ty, 2, "dstaddr.cur");
+    DstPHI->addIncoming(DstAddr.getPointer(), PreheaderBB);
+    llvm::PHINode *SrcPHI = nullptr;
+    if (SrcAddr.isValid()) {
+      SrcPHI = CGF->Builder.CreatePHI(Ty, 2, "srcaddr.cur");
+      SrcPHI->addIncoming(SrcAddr.getPointer(), PreheaderBB);
+    }
+
+    // Create the exit and loop body blocks.
+    llvm::BasicBlock *ExitBB = CGF->createBasicBlock("loop.exit");
+    llvm::BasicBlock *LoopBB = CGF->createBasicBlock("loop.body");
+
+    // Emit the comparison and conditional branch instruction that jumps to
+    // either the exit or the loop body.
+    llvm::Value *Done = CGF->Builder.CreateICmpEQ(DstPHI, DstArrayEnd, "done");
+    CGF->Builder.CreateCondBr(Done, ExitBB, LoopBB);
+
+    // Visit the element of the array in the loop body.
+    CGF->EmitBlock(LoopBB);
+    QualType EltQT = Ctx.getAsArrayType(QT)->getElementType();
+    CharUnits EltSize = Ctx.getTypeSizeInChars(EltQT);
+    Address Dst =
+        Address(DstPHI, DstAddr.getAlignment().alignmentAtOffset(EltSize));
+    Address Src = Address::invalid();
+    if (SrcAddr.isValid())
+      Src = Address(SrcPHI, SrcAddr.getAlignment().alignmentAtOffset(EltSize));
+    visitField(Dst, Src, EltQT, IsVolatile);
+
+    // Instrs to update the destination and source addresses.
+    Address NextDst = getAddrWithOffset(Dst, EltSize.getQuantity(), *CGF);
+    Address NextSrc = getAddrWithOffset(Src, EltSize.getQuantity(), *CGF);
+
+    // Update phi instructions.
+    LoopBB = CGF->Builder.GetInsertBlock();
+    DstPHI->addIncoming(NextDst.getPointer(), LoopBB);
+    if (NextSrc.isValid())
+      SrcPHI->addIncoming(NextSrc.getPointer(), LoopBB);
+
+    // Insert an unconditional branch to the header block.
+    CGF->Builder.CreateBr(HeaderBB);
+    CGF->EmitBlock(ExitBB);
+  }
+
+  static bool isBinary() { return T::isBinary(); }
+
+  static const char *getFuncPrefix() { return T::getFuncPrefix(); }
+
+  static bool isInterestingType(QualType QT) {
+    return T::isInterestingType(QT);
+  }
+
+private:
+  CodeGenFunction *CGF;
+  Address DstStart, SrcStart;
+};
+
+template <bool IsBinary, bool IsInit> struct SpecialFunc {
+  // Emit IR for objc __strong pointers.
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {}
+
+  // This function returns true if the subclass is used to generate special
+  // functions that need two arguments (source and destination arguments for
+  // copy/move constructors/assignment operators).
+  static bool isBinary() { return IsBinary; }
+
+  // This function returns true if the subclass generates a special function for
+  // a constructor.
+  static bool isInit() { return IsInit; }
+};
+
+// Various subclasses of SpecialFunc that are used to customize
+// the IR IRGen generates.
+struct Destructor : SpecialFunc<false, false> {
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {
+    CGF.destroyARCStrongImprecise(CGF, DstAddr, QT);
+  }
+  static const char *getFuncPrefix() { return "__destructor_"; }
+
+  static bool isInterestingType(QualType T) { return T.nonTrivialToDestroy(); }
+  static void callSpecialFunction(Address DstAddr, Address SrcAddr, QualType QT,
+                                  bool IsVolatile, CodeGenFunction &CGF) {
+    CGF.callCStructDestructor(DstAddr, QT, IsVolatile);
+  }
+};
+
+struct DefaultConstructor : SpecialFunc<false, true> {
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {
+    CGF.EmitNullInitialization(DstAddr, QT);
+  }
+  static const char *getFuncPrefix() { return "__default_constructor_"; }
+
+  static bool isInterestingType(QualType T) {
+    return T.nonTrivialToDefaultInitialize();
+  }
+  static void callSpecialFunction(Address DstAddr, Address SrcAddr, QualType QT,
+                                  bool IsVolatile, CodeGenFunction &CGF) {
+    CGF.callCStructDefaultConstructor(DstAddr, QT, IsVolatile);
+  }
+};
+
+struct CopyConstructor : SpecialFunc<true, true> {
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {
+    llvm::Value *SrcVal = CGF.EmitLoadOfScalar(
+        SrcAddr, QT.isVolatileQualified(), QT, SourceLocation());
+    llvm::Value *Val = CGF.EmitARCRetain(QT, SrcVal);
+    CGF.EmitStoreOfScalar(Val, CGF.MakeAddrLValue(DstAddr, QT), true);
+  }
+  static const char *getFuncPrefix() { return "__copy_constructor_"; }
+
+  static bool isInterestingType(QualType T) { return T.nonTrivialToCopy(); }
+  static void callSpecialFunction(Address DstAddr, Address SrcAddr, QualType QT,
+                                  bool IsVolatile, CodeGenFunction &CGF) {
+    CGF.callCStructCopyConstructor(DstAddr, SrcAddr, QT, IsVolatile);
+  }
+};
+
+struct MoveConstructor : SpecialFunc<true, true> {
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {
+    LValue SrcLV = CGF.MakeAddrLValue(SrcAddr, QT);
+    llvm::Value *SrcVal =
+        CGF.EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
+    CGF.EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
+    CGF.EmitStoreOfScalar(SrcVal, CGF.MakeAddrLValue(DstAddr, QT),
+                          /* isInitialization */ true);
+  }
+  static const char *getFuncPrefix() { return "__move_constructor_"; }
+
+  static bool isInterestingType(QualType T) {
+    return T.nonTrivialToDestructiveMove();
+  }
+  static void callSpecialFunction(Address DstAddr, Address SrcAddr, QualType QT,
+                                  bool IsVolatile, CodeGenFunction &CGF) {
+    CGF.callCStructMoveConstructor(DstAddr, SrcAddr, QT, IsVolatile);
+  }
+};
+
+struct CopyAssignment : SpecialFunc<true, false> {
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {
+    llvm::Value *SrcVal = CGF.EmitLoadOfScalar(
+        SrcAddr, QT.isVolatileQualified(), QT, SourceLocation());
+    CGF.EmitARCStoreStrong(CGF.MakeAddrLValue(DstAddr, QT), SrcVal, false);
+  }
+  static const char *getFuncPrefix() { return "__copy_assignment_"; }
+
+  static bool isInterestingType(QualType T) { return T.nonTrivialToCopy(); }
+  static void callSpecialFunction(Address DstAddr, Address SrcAddr, QualType QT,
+                                  bool IsVolatile, CodeGenFunction &CGF) {
+    CGF.callCStructCopyAssignmentOperator(DstAddr, SrcAddr, QT, IsVolatile);
+  }
+};
+
+struct MoveAssignment : SpecialFunc<true, false> {
+  static void emitIRStrong(Address DstAddr, Address SrcAddr, QualType QT,
+                           CodeGenFunction &CGF) {
+    LValue SrcLV = CGF.MakeAddrLValue(SrcAddr, QT);
+    llvm::Value *SrcVal =
+        CGF.EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
+    CGF.EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
+    LValue DstLV = CGF.MakeAddrLValue(DstAddr, QT);
+    llvm::Value *DstVal =
+        CGF.EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();
+    CGF.EmitStoreOfScalar(SrcVal, DstLV);
+    CGF.EmitARCRelease(DstVal, ARCImpreciseLifetime);
+  }
+  static const char *getFuncPrefix() { return "__move_assignment_"; }
+
+  static bool isInterestingType(QualType T) {
+    return T.nonTrivialToDestructiveMove();
+  }
+  static void callSpecialFunction(Address DstAddr, Address SrcAddr, QualType QT,
+                                  bool IsVolatile, CodeGenFunction &CGF) {
+    CGF.callCStructMoveAssignmentOperator(DstAddr, SrcAddr, QT, IsVolatile);
+  }
+};
+} // namespace
+
+void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF,
+                                               Address Addr, QualType Type) {
+  CGF.callCStructDestructor(Addr, Type, Type.isVolatileQualified());
+}
+
+// A template function to create the special function for a non-trivial C
+// struct. Template parameter 'T' is an instantiation of IRGen.
+template <class T>
+static llvm::Function *
+getSpecialFunction(QualType QT, bool IsVolatile, T &Gen, CharUnits DstAlignment,
+                   CharUnits SrcAlignment, CodeGenModule &CGM) {
+  bool IsBinary = T::isBinary();
+  std::string FuncName = getSpecialFuncName<T>(QT, IsVolatile, DstAlignment,
+                                               SrcAlignment, IsBinary, CGM);
+
+  // If the special function already exists in the module, return it here.
+  if (llvm::Function *F = CGM.getModule().getFunction(FuncName))
+    return F;
+
+  // Create the special function.
+  ASTContext &Ctx = CGM.getContext();
+  CodeGenFunction CGF(CGM);
+  FunctionArgList Args;
+  const CGFunctionInfo &FI = getFunctionInfo(CGM, IsBinary, Args);
+  llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);
+  llvm::Function *F =
+      llvm::Function::Create(FuncTy, llvm::GlobalValue::LinkOnceODRLinkage,
+                             FuncName, &CGM.getModule());
+  F->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  CGF.CGM.SetLLVMFunctionAttributes(nullptr, FI, F);
+  CGF.CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F);
+  IdentifierInfo *II = &Ctx.Idents.get(FuncName);
+  FunctionDecl *FD = FunctionDecl::Create(
+      Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
+      Ctx.VoidTy, nullptr, SC_PrivateExtern, false, false);
+  CGF.StartFunction(FD, Ctx.VoidTy, F, FI, Args);
+  Gen.setFunction(CGF, Args, DstAlignment, SrcAlignment);
+  Gen.visitMostOuterStruct(QT, IsVolatile);
+  CGF.FinishFunction();
+  return F;
+}
+
+// Default-initialize a non-trivial struct or an array.
+void CodeGenFunction::defaultInitNonTrivialCStructVar(Address DstPtr,
+                                                      QualType QT,
+                                                      bool IsVolatile) {
+  if (getContext().getAsArrayType(QT)) {
+    IRGen<DefaultConstructor> Gen(*this);
+    DstPtr = Builder.CreateBitCast(DstPtr, CGM.Int8PtrPtrTy);
+    Gen.visitArray(DstPtr, Address::invalid(), QT, IsVolatile);
+  } else {
+    callCStructDefaultConstructor(DstPtr, QT, IsVolatile);
+  }
+}
+
+template <class T>
+static void callUnaryFunction(Address DstPtr, QualType QT, bool IsVolatile,
+                              CodeGenFunction &CGF) {
+  IRGen<T> Gen;
+  llvm::Function *Fn = getSpecialFunction(
+      QT, IsVolatile, Gen, DstPtr.getAlignment(), CharUnits::Zero(), CGF.CGM);
+  DstPtr = CGF.Builder.CreateBitCast(DstPtr, CGF.CGM.Int8PtrPtrTy);
+  CGF.EmitNounwindRuntimeCall(Fn, DstPtr.getPointer());
+}
+
+template <class T>
+static void callBinaryFunction(Address DstPtr, Address SrcPtr, QualType QT,
+                               bool IsVolatile, CodeGenFunction &CGF) {
+  IRGen<T> Gen;
+  llvm::Function *Fn =
+      getSpecialFunction(QT, IsVolatile, Gen, DstPtr.getAlignment(),
+                         SrcPtr.getAlignment(), CGF.CGM);
+  DstPtr = CGF.Builder.CreateBitCast(DstPtr, CGF.CGM.Int8PtrPtrTy);
+  SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, CGF.CGM.Int8PtrPtrTy);
+  CGF.EmitNounwindRuntimeCall(Fn, {DstPtr.getPointer(), SrcPtr.getPointer()});
+}
+
+// Functions to emit calls to the special functions of a non-trivial C struct.
+void CodeGenFunction::callCStructDefaultConstructor(Address DstPtr, QualType QT,
+                                                    bool IsVolatile) {
+  callUnaryFunction<DefaultConstructor>(DstPtr, QT, IsVolatile, *this);
+}
+
+void CodeGenFunction::callCStructDestructor(Address DstPtr, QualType QT,
+                                            bool IsVolatile) {
+  callUnaryFunction<Destructor>(DstPtr, QT, IsVolatile, *this);
+}
+
+void CodeGenFunction::callCStructCopyConstructor(Address DstPtr, Address SrcPtr,
+                                                 QualType QT, bool IsVolatile) {
+  callBinaryFunction<CopyConstructor>(DstPtr, SrcPtr, QT, IsVolatile, *this);
+}
+
+void CodeGenFunction::callCStructCopyAssignmentOperator(Address DstPtr,
+                                                        Address SrcPtr,
+                                                        QualType QT,
+                                                        bool IsVolatile) {
+  callBinaryFunction<CopyAssignment>(DstPtr, SrcPtr, QT, IsVolatile, *this);
+}
+
+void CodeGenFunction::callCStructMoveConstructor(Address DstPtr, Address SrcPtr,
+                                                 QualType QT, bool IsVolatile) {
+  callBinaryFunction<MoveConstructor>(DstPtr, SrcPtr, QT, IsVolatile, *this);
+}
+
+void CodeGenFunction::callCStructMoveAssignmentOperator(Address DstPtr,
+                                                        Address SrcPtr,
+                                                        QualType QT,
+                                                        bool IsVolatile) {
+  callBinaryFunction<MoveAssignment>(DstPtr, SrcPtr, QT, IsVolatile, *this);
+}
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -77,7 +77,9 @@
   void EmitAggLoadOfLValue(const Expr *E);
 
   /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-  void EmitFinalDestCopy(QualType type, const LValue &src);
+  /// SrcIsRValue is true if source comes from an RValue.
+  void EmitFinalDestCopy(QualType type, const LValue &src,
+                         bool SrcIsRValue = false);
   void EmitFinalDestCopy(QualType type, RValue src);
   void EmitCopy(QualType type, const AggValueSlot &dest,
                 const AggValueSlot &src);
@@ -245,6 +247,12 @@
 /// directly into the return value slot.  Otherwise, a final move
 /// will be performed.
 void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue src) {
+  // Push destructor if the result is ignored and the type is a C struct that
+  // is non-trivial to destroy.
+  QualType Ty = E->getType();
+  if (Dest.isIgnored() && Ty.hasNonTrivialToDestroyStruct())
+    CGF.pushDestroy(Ty.isDestructedType(), src.getAggregateAddress(), Ty);
+
   if (shouldUseDestForReturnSlot()) {
     // Logically, Dest.getAddr() should equal Src.getAggregateAddr().
     // The possibility of undef rvalues complicates that a lot,
@@ -261,18 +269,49 @@
 void AggExprEmitter::EmitFinalDestCopy(QualType type, RValue src) {
   assert(src.isAggregate() && "value must be aggregate value!");
   LValue srcLV = CGF.MakeAddrLValue(src.getAggregateAddress(), type);
-  EmitFinalDestCopy(type, srcLV);
+  EmitFinalDestCopy(type, srcLV, true);
 }
 
 /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src) {
+void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src,
+                                       bool SrcIsRValue) {
   // If Dest is ignored, then we're evaluating an aggregate expression
   // in a context that doesn't care about the result.  Note that loads
   // from volatile l-values force the existence of a non-ignored
   // destination.
   if (Dest.isIgnored())
     return;
 
+  // Copy non-trivial C structs here.
+
+  // For simplicity, both the destination and the source are treated as being
+  // volatile if either is volatile.
+  bool IsVolatile = Dest.isVolatile() || src.isVolatile();
+
+  if (SrcIsRValue) {
+    if (type.hasNonTrivialToDestructiveMoveStruct()) {
+      if (Dest.isPotentiallyAliased())
+        CGF.callCStructMoveAssignmentOperator(Dest.getAddress(),
+                                              src.getAddress(), type,
+                                              IsVolatile);
+      else
+        CGF.callCStructMoveConstructor(Dest.getAddress(), src.getAddress(),
+                                       type, IsVolatile);
+      return;
+    }
+  } else {
+    if (type.hasNonTrivialToCopyStruct()) {
+      if (Dest.isPotentiallyAliased())
+        CGF.callCStructCopyAssignmentOperator(Dest.getAddress(),
+                                              src.getAddress(), type,
+                                              IsVolatile);
+      else
+        CGF.callCStructCopyConstructor(Dest.getAddress(), src.getAddress(),
+                                       type, IsVolatile);
+      return;
+    }
+  }
+
   AggValueSlot srcAgg =
     AggValueSlot::forLValue(src, AggValueSlot::IsDestructed,
                             needsGC(type), AggValueSlot::IsAliased);
Index: lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- lib/CodeGen/CGDeclCXX.cpp
+++ lib/CodeGen/CGDeclCXX.cpp
@@ -79,6 +79,7 @@
 
   case QualType::DK_objc_strong_lifetime:
   case QualType::DK_objc_weak_lifetime:
+  case QualType::DK_c_struct_strong_field:
     // We don't care about releasing objects during process teardown.
     assert(!D.getTLSKind() && "should have rejected this");
     return;
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -1232,6 +1232,15 @@
   if (emission.IsByRef)
     emitByrefStructureInit(emission);
 
+  // Initialize the variable here if it doesn't have a initializer and it is a
+  // C struct that is non-trivial to initialize or an array containing such a
+  // struct.
+  if (!Init && type.hasNonTrivialToDefaultInitializeStruct()) {
+    defaultInitNonTrivialCStructVar(emission.getAllocatedAddress(), type,
+                                    type.isVolatileQualified());
+    return;
+  }
+
   if (isTrivialInitializer(Init))
     return;
 
@@ -1406,6 +1415,11 @@
 
   case QualType::DK_objc_weak_lifetime:
     break;
+
+  case QualType::DK_c_struct_strong_field:
+    destroyer = CodeGenFunction::destroyNonTrivialCStruct;
+    cleanupKind = getARCCleanupKind();
+    break;
   }
 
   // If we haven't chosen a more specific destroyer, use the default.
@@ -1467,6 +1481,8 @@
     return destroyARCStrongPrecise;
   case QualType::DK_objc_weak_lifetime:
     return destroyARCWeak;
+  case QualType::DK_c_struct_strong_field:
+    return destroyNonTrivialCStruct;
   }
   llvm_unreachable("Unknown DestructionKind");
 }
@@ -1897,6 +1913,14 @@
 
   setAddrOfLocalVar(&D, DeclPtr);
 
+  // If this arg is a type containing a C struct that is non-trivial to
+  // destruct, the callee is responsible for destructing the argument.
+  if (Ty.hasNonTrivialToDestroyStruct()) {
+    AutoVarEmission Emission(D);
+    Emission.Addr = GetAddrOfLocalVar(&D);
+    emitAutoVarTypeCleanup(Emission, Ty.isDestructedType());
+  }
+
   // Emit debug info for param declaration.
   if (CGDebugInfo *DI = getDebugInfo()) {
     if (CGM.getCodeGenOpts().getDebugInfo() >=
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3532,6 +3532,16 @@
       cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
     LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
     assert(L.isSimple());
+
+    // If type is a C struct that is non-trivial to copy, emit a call to its
+    // copy constructor to build the argument in the temporary slot.
+    if (type.hasNonTrivialToCopyStruct()) {
+      AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
+      EmitAggExpr(E, Slot);
+      args.add(Slot.asRValue(), type);
+      return;
+    }
+
     if (L.getAlignment() >= getContext().getTypeAlignInChars(type)) {
       args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true);
     } else {
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -477,6 +477,12 @@
       info.NeedsCopyDispose = true;
       info.HasCXXObject = true;
 
+    // So do C structs that require non-trivial copy construction or
+    // destruction.
+    } else if (variable->getType().hasNonTrivialToCopyStruct() ||
+               variable->getType().hasNonTrivialToDestroyStruct()) {
+      info.NeedsCopyDispose = true;
+
     // And so do types with destructors.
     } else if (CGM.getLangOpts().CPlusPlus) {
       if (const CXXRecordDecl *record =
@@ -1513,6 +1519,7 @@
   CXXRecord, // Copy or destroy
   ARCWeak,
   ARCStrong,
+  NonTrivialCStruct,
   BlockObject, // Assign or release
   None
 };
@@ -1548,6 +1555,9 @@
       Flags |= BLOCK_FIELD_IS_WEAK;
     return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
   }
+  if (T.hasNonTrivialToCopyStruct())
+    return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct,
+                          BlockFieldFlags());
   if (!T->isObjCRetainableType())
     // For all other types, the memcpy is fine.
     return std::make_pair(BlockCaptureEntityKind::None, Flags);
@@ -1677,6 +1687,13 @@
       EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr());
     } else if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCWeak) {
       EmitARCCopyWeak(dstField, srcField);
+    // If this is a C struct that requires non-trivial copy construction, emit a
+    // call to its copy constructor.
+    } else if (CopiedCapture.Kind ==
+               BlockCaptureEntityKind::NonTrivialCStruct) {
+      QualType varType = CI.getVariable()->getType();
+      callCStructCopyConstructor(dstField, srcField, varType,
+                                 varType.isVolatileQualified());
     } else {
       llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
       if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCStrong) {
@@ -1749,6 +1766,10 @@
     return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags());
   }
 
+  if (T.hasNonTrivialToDestroyStruct())
+    return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct,
+                          BlockFieldFlags());
+
   // Other types don't need to be destroy explicitly.
   if (!T->isObjCRetainableType())
     return std::make_pair(BlockCaptureEntityKind::None, Flags);
@@ -1853,6 +1874,13 @@
     } else if (DestroyedCapture.Kind == BlockCaptureEntityKind::ARCStrong) {
       EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
 
+    // If this is a C struct that requires non-trivial destruction, emit a call
+    // to its destructor.
+    } else if (DestroyedCapture.Kind ==
+               BlockCaptureEntityKind::NonTrivialCStruct) {
+      QualType varType = CI.getVariable()->getType();
+      pushDestroy(varType.isDestructedType(), srcField, varType);
+
     // Otherwise we call _Block_object_dispose.  It wouldn't be too
     // hard to just emit this as a cleanup if we wanted to make sure
     // that things were done in reverse.
@@ -2020,6 +2048,36 @@
     id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
   }
 };
+
+/// Emits the copy/dispose helpers for a __block variable that is a non-trivial
+/// C struct.
+class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers {
+  QualType VarType;
+
+public:
+  NonTrivialCStructByrefHelpers(CharUnits alignment, QualType type)
+    : BlockByrefHelpers(alignment), VarType(type) {}
+
+  void emitCopy(CodeGenFunction &CGF, Address destField,
+                Address srcField) override {
+    CGF.callCStructMoveConstructor(destField, srcField, VarType,
+                                   VarType.isVolatileQualified());
+  }
+
+  bool needsDispose() const override {
+    return VarType.hasNonTrivialToDestroyStruct();
+  }
+
+  void emitDispose(CodeGenFunction &CGF, Address field) override {
+    EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
+    CGF.pushDestroy(VarType.isDestructedType(), field, VarType);
+    CGF.PopCleanupBlocks(cleanupDepth);
+  }
+
+  void profileImpl(llvm::FoldingSetNodeID &id) const override {
+    id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
+  }
+};
 } // end anonymous namespace
 
 static llvm::Constant *
@@ -2205,6 +2263,13 @@
         CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr));
   }
 
+  // If type is a non-trivial C struct type that is non-trivial to
+  // destructly move or destroy, build the copy and dispose helpers.
+  if (type.hasNonTrivialToDestructiveMoveStruct() ||
+      type.hasNonTrivialToDestroyStruct())
+    return ::buildByrefHelpers(
+        CGM, byrefInfo, NonTrivialCStructByrefHelpers(valueAlignment, type));
+
   // Otherwise, if we don't have a retainable type, there's nothing to do.
   // that the runtime does extra copies.
   if (!type->isObjCRetainableType()) return nullptr;
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2207,6 +2207,65 @@
          getObjCLifetime() != Qualifiers::OCL_Weak;
 }
 
+bool QualType::hasNonTrivialToDefaultInitializeStruct() const {
+  if (const auto *RT =
+          getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    return RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize();
+  return false;
+}
+
+bool QualType::hasNonTrivialToCopyStruct() const {
+  if (const auto *RT =
+          getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    return RT->getDecl()->isNonTrivialToPrimitiveCopy();
+  return false;
+}
+
+bool QualType::hasNonTrivialToDestructiveMoveStruct() const {
+  if (const auto *RT =
+          getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    return RT->getDecl()->isNonTrivialToPrimitiveDestructiveMove();
+  return false;
+}
+
+bool QualType::hasNonTrivialToDestroyStruct() const {
+  if (const auto *RT =
+          getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    return RT->getDecl()->isNonTrivialToPrimitiveDestroy();
+  return false;
+}
+
+bool QualType::hasStructWithObjCStrongField() const {
+  if (const auto *RT =
+          getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    return RT->getDecl()->hasStrongObjCPointer();
+  return false;
+}
+
+bool QualType::nonTrivialToDefaultInitialize() const {
+  return hasObjCStrongPointer();
+}
+
+bool QualType::nonTrivialToCopy() const {
+  return hasObjCStrongPointer();
+}
+
+bool QualType::nonTrivialToDestructiveMove() const {
+  return hasObjCStrongPointer();
+}
+
+bool QualType::nonTrivialToDestroy() const {
+  return hasObjCStrongPointer();
+}
+
+bool QualType::hasObjCStrongPointer() const {
+  if (hasStructWithObjCStrongField())
+    return true;
+
+  Qualifiers::ObjCLifetime Lifetime = getQualifiers().getObjCLifetime();
+  return Lifetime == Qualifiers::OCL_Strong;
+}
+
 bool Type::isLiteralType(const ASTContext &Ctx) const {
   if (isDependentType())
     return false;
@@ -3895,6 +3954,11 @@
     return DK_objc_weak_lifetime;
   }
 
+  // See if this is a C struct that is non-trivial to destroy or an array that
+  // contains such a struct.
+  if (type.hasStructWithObjCStrongField())
+    return DK_c_struct_strong_field;
+
   /// Currently, the only destruction kind we recognize is C++ objects
   /// with non-trivial destructors.
   const CXXRecordDecl *record =
@@ -3905,6 +3969,22 @@
   return DK_none;
 }
 
+QualType::NonTrivialCopyKind
+QualType::isNonTrivialToCopy(std::function<bool(QualType)> IsInteresting,
+                             ASTContext &Ctx) const {
+  if (!IsInteresting(*this))
+    return NTFK_Trivial;
+
+  if (getTypePtr()->getAs<RecordType>())
+    return NTFK_Struct;
+  if (Ctx.getAsArrayType(*this))
+    return NTFK_Array;
+  if (getQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong)
+    return NTFK_Strong;
+
+  return NTFK_Trivial;
+}
+
 CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const {
   return getClass()->getAsCXXRecordDecl()->getMostRecentDecl();
 }
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3892,7 +3892,7 @@
     : TagDecl(DK, TK, C, DC, IdLoc, Id, PrevDecl, StartLoc),
       HasFlexibleArrayMember(false), AnonymousStructOrUnion(false),
       HasObjectMember(false), HasVolatileMember(false),
-      LoadedFieldsFromExternalStorage(false) {
+      LoadedFieldsFromExternalStorage(false), HasStrongObjCPointer(false) {
   assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
 }
 
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -5776,6 +5776,12 @@
     return true;
   }
   
+  // The block needs copy/destroy helpers if Ty is a C struct type that is
+  // non-trivial to destructly move or destroy.
+  if (Ty.hasNonTrivialToDestructiveMoveStruct() ||
+      Ty.hasNonTrivialToDestroyStruct())
+    return true;
+
   if (!Ty->isObjCRetainableType()) return false;
   
   Qualifiers qs = Ty.getQualifiers();
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5109,12 +5109,17 @@
   "jump bypasses initialization of __strong variable">;
 def note_protected_by_objc_weak_init : Note<
   "jump bypasses initialization of __weak variable">;
+def note_protected_by_non_trivial_c_struct_init : Note<
+  "jump bypasses initialization of variable of non-trivial C struct type">;
 def note_enters_block_captures_cxx_obj : Note<
   "jump enters lifetime of block which captures a destructible C++ object">;
 def note_enters_block_captures_strong : Note<
   "jump enters lifetime of block which strongly captures a variable">;
 def note_enters_block_captures_weak : Note<
   "jump enters lifetime of block which weakly captures a variable">;
+def note_enters_block_captures_non_trivial_c_struct : Note<
+  "jump enters lifetime of block which captures a C struct that is non-trivial "
+  "to destroy">;
 
 def note_exits_cleanup : Note<
   "jump exits scope of variable with __attribute__((cleanup))">;
@@ -5155,6 +5160,9 @@
   "jump exits lifetime of block which strongly captures a variable">;
 def note_exits_block_captures_weak : Note<
   "jump exits lifetime of block which weakly captures a variable">;
+def note_exits_block_captures_non_trivial_c_struct : Note<
+  "jump exits lifetime of block which captures a C struct that is non-trivial "
+  "to destroy">;
 
 def err_func_returning_qualified_void : ExtWarn<
   "function cannot return qualified void type %0">,
@@ -7173,6 +7181,10 @@
   "cannot pass object with interface type %1 by value to variadic "
   "%select{function|block|method|constructor}2; expected type from format "
   "string was %3">;
+def err_cannot_pass_non_trivial_c_struct_to_vararg : Error<
+  "cannot pass non-trivial C object of type %0 by value to variadic "
+  "%select{function|block|method|constructor}1">;
+
 
 def err_cannot_pass_objc_interface_to_vararg : Error<
   "cannot pass object with interface type %0 by value through variadic "
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1084,11 +1084,55 @@
   // true when Type is objc's weak and weak is enabled but ARC isn't.
   bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
 
+  /// Functions to query basic properties of non-trivial C struct types.
+
+  /// Returns true if this type is a C struct that is non-trivial to
+  /// default-initialize or an array that contains such a struct.
+  bool hasNonTrivialToDefaultInitializeStruct() const;
+
+  /// Returns true if this type is a C struct that is non-trivial to copy or an
+  /// array that contains such a struct.
+  bool hasNonTrivialToCopyStruct() const;
+
+  /// Returns true if this type is a C struct that is non-trivial to
+  /// destructively move or an array that contains such a struct.
+  bool hasNonTrivialToDestructiveMoveStruct() const;
+
+  /// Returns true if this type is a C struct that is non-trivial to destroy or
+  /// an array that contains such a struct.
+  bool hasNonTrivialToDestroyStruct() const;
+
+  /// Returns true if this type is a C struct that has a __strong field or an
+  /// array that contains such a struct.
+  bool hasStructWithObjCStrongField() const;
+
+  /// Returns true if this is a non-trivial type that would cause a struct
+  /// transitively containing this type to be non-trivial to default initialize.
+  bool nonTrivialToDefaultInitialize() const;
+
+  /// Returns true if this is a non-trivial type that would cause a struct
+  /// transitively containing this type to be non-trivial to copy.
+  bool nonTrivialToCopy() const;
+
+  /// Returns true if this is a non-trivial type that would cause a struct
+  /// transitively containing this type to be non-trivial to destructively
+  /// move.
+  bool nonTrivialToDestructiveMove() const;
+
+  /// Returns true if this is a non-trivial type that would cause a struct
+  /// transitively containing this type to be non-trivial to destroy.
+  bool nonTrivialToDestroy() const;
+
+  /// Returns true if this is an objc __strong pointer or a type containing a
+  /// struct that has an objc __strong pointer field.
+  bool hasObjCStrongPointer() const;
+
   enum DestructionKind {
     DK_none,
     DK_cxx_destructor,
     DK_objc_strong_lifetime,
-    DK_objc_weak_lifetime
+    DK_objc_weak_lifetime,
+    DK_c_struct_strong_field
   };
 
   /// Returns a nonzero value if objects of this type require
@@ -1099,6 +1143,19 @@
     return isDestructedTypeImpl(*this);
   }
 
+  // Enum used to distinguish the different kinds of fields of non-trivial C
+  // structs.
+  enum NonTrivialCopyKind {
+    NTFK_Trivial, // a field of a trivial type.
+    NTFK_Strong,  // objc strong pointer.
+    NTFK_Struct,  // non-trivial C struct.
+    NTFK_Array    // array that has non-trivial elements.
+  };
+
+  NonTrivialCopyKind
+  isNonTrivialToCopy(std::function<bool(QualType)> IsInteresting,
+                     ASTContext &Ctx) const;
+
   /// Determine whether expressions of the given type are forbidden
   /// from being lvalues in C.
   ///
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -3506,6 +3506,9 @@
   /// when needed.
   mutable bool LoadedFieldsFromExternalStorage : 1;
 
+  /// Basic properties of non-trivial C structs.
+  bool HasStrongObjCPointer : 1;
+
 protected:
   RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC,
              SourceLocation StartLoc, SourceLocation IdLoc,
@@ -3565,6 +3568,31 @@
     LoadedFieldsFromExternalStorage = val;
   }
 
+  /// Functions to query basic properties of non-trivial C structs.
+  bool isNonTrivialToPrimitiveDefaultInitialize() const {
+    return HasStrongObjCPointer;
+  }
+
+  bool isNonTrivialToPrimitiveCopy() const {
+    return HasStrongObjCPointer;
+  }
+
+  bool isNonTrivialToPrimitiveDestructiveMove() const {
+    return HasStrongObjCPointer;
+  }
+
+  bool isNonTrivialToPrimitiveDestroy() const {
+    return HasStrongObjCPointer;
+  }
+
+  bool hasStrongObjCPointer() const {
+    return HasStrongObjCPointer;
+  }
+
+  void setHasStrongObjCPointer(bool val) {
+    HasStrongObjCPointer = val;
+  }
+
   /// \brief Determines whether this declaration represents the
   /// injected class name.
   ///
Index: docs/LanguageExtensions.rst
===================================================================
--- docs/LanguageExtensions.rst
+++ docs/LanguageExtensions.rst
@@ -1186,12 +1186,14 @@
 
 Clang provides support for :doc:`automated reference counting
 <AutomaticReferenceCounting>` in Objective-C, which eliminates the need
-for manual ``retain``/``release``/``autorelease`` message sends.  There are two
+for manual ``retain``/``release``/``autorelease`` message sends.  There are three
 feature macros associated with automatic reference counting:
 ``__has_feature(objc_arc)`` indicates the availability of automated reference
 counting in general, while ``__has_feature(objc_arc_weak)`` indicates that
 automated reference counting also includes support for ``__weak`` pointers to
-Objective-C objects.
+Objective-C objects. ``__has_feature(objc_arc_fields)`` indicates that C structs
+are allowed to have fields that are pointers to Objective-C objects managed by
+automatic reference counting.
 
 .. _objc-fixed-enum:
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to