ahatanak created this revision.
ahatanak added reviewers: rjmccall, doug.gregor, rsmith.

This patch makes changes that are needed to allow `__weak` fields in C structs 
when ARC is enabled.


Repository:
  rC Clang

https://reviews.llvm.org/D44095

Files:
  include/clang/AST/Decl.h
  include/clang/AST/Type.h
  lib/AST/Decl.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGNonTrivialStruct.cpp
  lib/CodeGen/TargetInfo.cpp
  lib/Sema/SemaDecl.cpp
  test/CodeGenObjC/nontrivial-c-struct-exception.m
  test/CodeGenObjC/weak-in-c-struct.m

Index: test/CodeGenObjC/weak-in-c-struct.m
===================================================================
--- /dev/null
+++ test/CodeGenObjC/weak-in-c-struct.m
@@ -0,0 +1,193 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - %s | FileCheck -check-prefix=ARM64 -check-prefix=COMMON %s
+// RUN: %clang_cc1 -triple thumbv7-apple-ios10 -fobjc-arc -fblocks -fobjc-runtime=ios-10.0 -emit-llvm -o - %s | FileCheck -check-prefix=COMMON %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13 -fobjc-arc -fblocks -fobjc-runtime=macosx-10.13.0 -emit-llvm -o - %s | FileCheck -check-prefix=COMMON %s
+// RUN: %clang_cc1 -triple i386-apple-macosx10.13.0 -fobjc-arc -fblocks -fobjc-runtime=macosx-fragile-10.13.0 -emit-llvm -o - %s | FileCheck -check-prefix=COMMON %s
+
+typedef void (^BlockTy)(void);
+
+// COMMON: %[[STRUCT_WEAK:.*]] = type { i32, i8* }
+
+typedef struct {
+  int f0;
+  __weak id f1;
+} Weak;
+
+Weak getWeak(void);
+void calleeWeak(Weak);
+
+// ARM64: define void @test_constructor_destructor_Weak()
+// ARM64: %[[T:.*]] = alloca %[[STRUCT_WEAK]], align 8
+// ARM64: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[T]] to i8**
+// ARM64: call void @__default_constructor_8_w8(i8** %[[V0]])
+// ARM64: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[T]] to i8**
+// ARM64: call void @__destructor_8_w8(i8** %[[V1]])
+// ARM64: ret void
+
+// ARM64: define linkonce_odr hidden void @__default_constructor_8_w8(i8** %[[DST:.*]])
+// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V1]] = bitcast i8** %[[V0]] to i8*
+// ARM64: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 8
+// ARM64: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
+// ARM64: %[[V4:.*]] = bitcast i8** %[[V3]] to i8*
+// ARM64: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false)
+
+// ARM64: define linkonce_odr hidden void @__destructor_8_w8(i8** %[[DST:.*]])
+// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V1:.*]] = bitcast i8** %[[V0]] to i8*
+// ARM64: %[[V2:.*]] = getelementptr inbounds i8, i8* %[[V1]], i64 8
+// ARM64: %[[V3:.*]] = bitcast i8* %[[V2]] to i8**
+// ARM64: call void @objc_destroyWeak(i8** %[[V3]])
+
+void test_constructor_destructor_Weak(void) {
+  Weak t;
+}
+
+// ARM64: define void @test_copy_constructor_Weak(%[[STRUCT_WEAK]]* %{{.*}})
+// ARM64: call void @__copy_constructor_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}})
+// ARM64: call void @__destructor_8_w8(i8** %{{.*}})
+
+// ARM64: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32*
+// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32*
+// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8
+// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8
+// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8*
+// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8
+// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8*
+// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8
+// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8**
+// ARM64: call void @objc_copyWeak(i8** %[[V7]], i8** %[[V10]])
+
+void test_copy_constructor_Weak(Weak *s) {
+  Weak t = *s;
+}
+
+// ARM64: define void @test_copy_assignment_Weak(%[[STRUCT_WEAK]]* %{{.*}}, %[[STRUCT_WEAK]]* %{{.*}})
+// ARM64: call void @__copy_assignment_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}})
+
+// ARM64: define linkonce_odr hidden void @__copy_assignment_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32*
+// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32*
+// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8
+// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8
+// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8*
+// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8
+// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8*
+// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8
+// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8**
+// ARM64: %[[V11:.*]] = call i8* @objc_loadWeakRetained(i8** %[[V10]])
+// ARM64: %[[V12:.*]] = call i8* @objc_storeWeak(i8** %[[V7]], i8* %[[V11]])
+// ARM64: call void @objc_release(i8* %[[V11]])
+
+void test_copy_assignment_Weak(Weak *d, Weak *s) {
+  *d = *s;
+}
+
+// ARM64: define internal void @__Block_byref_object_copy_(i8*, i8*)
+// ARM64: call void @__move_constructor_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}})
+
+// ARM64: define linkonce_odr hidden void @__move_constructor_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32*
+// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32*
+// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8
+// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8
+// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8*
+// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8
+// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8*
+// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8
+// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8**
+// ARM64: call void @objc_moveWeak(i8** %[[V7]], i8** %[[V10]])
+
+void test_move_constructor_Weak(void) {
+  __block Weak t;
+  BlockTy b = ^{ (void)t; };
+}
+
+// ARM64: define void @test_move_assignment_Weak(%[[STRUCT_WEAK]]* %{{.*}})
+// ARM64: call void @__move_assignment_8_8_t0w4_w8(i8** %{{.*}}, i8** %{{.*}})
+
+// ARM64: define linkonce_odr hidden void @__move_assignment_8_8_t0w4_w8(i8** %[[DST:.*]], i8** %[[SRC:.*]])
+// ARM64: %[[DST_ADDR:.*]] = alloca i8**, align 8
+// ARM64: %[[SRC_ADDR:.*]] = alloca i8**, align 8
+// ARM64: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8
+// ARM64: store i8** %[[SRC]], i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8
+// ARM64: %[[V1:.*]] = load i8**, i8*** %[[SRC_ADDR]], align 8
+// ARM64: %[[V2:.*]] = bitcast i8** %[[V0]] to i32*
+// ARM64: %[[V3:.*]] = bitcast i8** %[[V1]] to i32*
+// ARM64: %[[V4:.*]] = load i32, i32* %[[V3]], align 8
+// ARM64: store i32 %[[V4]], i32* %[[V2]], align 8
+// ARM64: %[[V5:.*]] = bitcast i8** %[[V0]] to i8*
+// ARM64: %[[V6:.*]] = getelementptr inbounds i8, i8* %[[V5]], i64 8
+// ARM64: %[[V7:.*]] = bitcast i8* %[[V6]] to i8**
+// ARM64: %[[V8:.*]] = bitcast i8** %[[V1]] to i8*
+// ARM64: %[[V9:.*]] = getelementptr inbounds i8, i8* %[[V8]], i64 8
+// ARM64: %[[V10:.*]] = bitcast i8* %[[V9]] to i8**
+// ARM64: %[[V11:.*]] = call i8* @objc_loadWeakRetained(i8** %[[V10]])
+// ARM64: %[[V12:.*]] = call i8* @objc_storeWeak(i8** %[[V7]], i8* %[[V11]])
+// ARM64: call void @objc_destroyWeak(i8** %[[V10]])
+// ARM64: call void @objc_release(i8* %[[V11]])
+
+void test_move_assignment_Weak(Weak *p) {
+  *p = getWeak();
+}
+
+// COMMON: define void @test_parameter_Weak(%[[STRUCT_WEAK]]* %[[A:.*]])
+// COMMON: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[A]] to i8**
+// COMMON: call void @__destructor_{{.*}}(i8** %[[V0]])
+
+void test_parameter_Weak(Weak a) {
+}
+
+// COMMON: define void @test_argument_Weak(%[[STRUCT_WEAK]]* %[[A:.*]])
+// COMMON: %[[A_ADDR:.*]] = alloca %[[STRUCT_WEAK]]*
+// COMMON: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]]
+// COMMON: store %[[STRUCT_WEAK]]* %[[A]], %[[STRUCT_WEAK]]** %[[A_ADDR]]
+// COMMON: %[[V0:.*]] = load %[[STRUCT_WEAK]]*, %[[STRUCT_WEAK]]** %[[A_ADDR]]
+// COMMON: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_TMP]] to i8**
+// COMMON: %[[V2:.*]] = bitcast %[[STRUCT_WEAK]]* %[[V0]] to i8**
+// COMMON: call void @__copy_constructor_{{.*}}(i8** %[[V1]], i8** %[[V2]])
+// COMMON: call void @calleeWeak(%[[STRUCT_WEAK]]* %[[AGG_TMP]])
+// COMMON-NEXT: ret
+
+void test_argument_Weak(Weak *a) {
+  calleeWeak(*a);
+}
+
+// COMMON: define void @test_return_Weak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_WEAK]]* %[[A:.*]])
+// COMMON: %[[A_ADDR:.*]] = alloca %[[STRUCT_WEAK]]*
+// COMMON: store %[[STRUCT_WEAK]]* %[[A]], %[[STRUCT_WEAK]]** %[[A_ADDR]]
+// COMMON: %[[V0:.*]] = load %[[STRUCT_WEAK]]*, %[[STRUCT_WEAK]]** %[[A_ADDR]]
+// COMMON: %[[V1:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8**
+// COMMON: %[[V2:.*]] = bitcast %[[STRUCT_WEAK]]* %[[V0]] to i8**
+// COMMON: call void @__copy_constructor_{{.*}}(i8** %[[V1]], i8** %[[V2]])
+// COMMON: ret void
+
+Weak test_return_Weak(Weak *a) {
+  return *a;
+}
Index: test/CodeGenObjC/nontrivial-c-struct-exception.m
===================================================================
--- test/CodeGenObjC/nontrivial-c-struct-exception.m
+++ test/CodeGenObjC/nontrivial-c-struct-exception.m
@@ -1,12 +1,18 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -fobjc-exceptions -fexceptions -fobjc-arc-exceptions -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -fobjc-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
 
 // CHECK: %[[STRUCT_STRONG:.*]] = type { i32, i8* }
+// CHECK: %[[STRUCT_WEAK:.*]] = type { i32, i8* }
 
 typedef struct {
   int i;
   id f1;
 } Strong;
 
+typedef struct {
+  int i;
+  __weak id f1;
+} Weak;
+
 // CHECK: define void @testStrongException()
 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
 // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_STRONG]], align 8
@@ -31,3 +37,26 @@
 void testStrongException(void) {
   calleeStrong(genStrong(), genStrong());
 }
+
+// CHECK: define void @testWeakException()
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]], align 8
+// CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_WEAK]], align 8
+// CHECK: call void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP]])
+// CHECK: invoke void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP1]])
+
+// CHECK: call void @calleeWeak(%[[STRUCT_WEAK]]* %[[AGG_TMP]], %[[STRUCT_WEAK]]* %[[AGG_TMP1]])
+// CHECK: ret void
+
+// CHECK: landingpad { i8*, i32 }
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_TMP]] to i8**
+// CHECK: call void @__destructor_8_w8(i8** %[[V3]])
+// CHECK: br label
+
+// CHECK: resume
+
+Weak genWeak(void);
+void calleeWeak(Weak, Weak);
+
+void testWeakException(void) {
+  calleeWeak(genWeak(), genWeak());
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -15217,7 +15217,6 @@
 
     // 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.
@@ -15358,10 +15357,7 @@
       QualType T = Context.getObjCObjectPointerType(FD->getType());
       FD->setType(T);
     } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
-               Record && !ObjCFieldLifetimeErrReported &&
-               ((!getLangOpts().CPlusPlus &&
-                 QS.getObjCLifetime() == Qualifiers::OCL_Weak) ||
-                Record->isUnion())) {
+               Record && !ObjCFieldLifetimeErrReported && 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.
@@ -15407,6 +15403,8 @@
         Record->setNonTrivialToPrimitiveCopy();
       if (FT.isDestructedType())
         Record->setNonTrivialToPrimitiveDestroy();
+      if (FT.isPassedIndirectly())
+        Record->setPassedIndirectly();
     }
 
     if (Record && FD->getType().isVolatileQualified())
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -1322,6 +1322,9 @@
   if (RetTy->isVoidType())
     return ABIArgInfo::getIgnore();
 
+  if (RetTy.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(RetTy);
+
   const Type *Base = nullptr;
   uint64_t NumElts = 0;
   if ((State.CC == llvm::CallingConv::X86_VectorCall ||
@@ -1576,6 +1579,9 @@
 
   Ty = useFirstFieldIfTransparentUnion(Ty);
 
+  if (Ty.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+
   // Check with the C++ ABI first.
   const RecordType *RT = Ty->getAs<RecordType>();
   if (RT) {
@@ -3213,6 +3219,9 @@
 
 ABIArgInfo X86_64ABIInfo::
 classifyReturnType(QualType RetTy) const {
+  if (RetTy.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(RetTy);
+
   // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
   // classification algorithm.
   X86_64ABIInfo::Class Lo, Hi;
@@ -3582,6 +3591,11 @@
   unsigned ArgNo = 0;
   for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
        it != ie; ++it, ++ArgNo) {
+    if (static_cast<QualType>(it->type).isPassedIndirectly() == QualType::APK_Struct) {
+      it->info = getNaturalAlignIndirect(it->type, /*ByVal=*/false);
+      continue;
+    }
+
     bool IsNamedArg = ArgNo < NumRequiredArgs;
 
     if (IsRegCall && it->type->isStructureOrClassType())
@@ -5031,6 +5045,9 @@
         llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members));
   }
 
+  if (Ty.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+
   // Aggregates <= 16 bytes are passed directly in registers or on the stack.
   if (Size <= 128) {
     // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
@@ -5081,6 +5098,9 @@
     // Homogeneous Floating-point Aggregates (HFAs) are returned directly.
     return ABIArgInfo::getDirect();
 
+  if (RetTy.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(RetTy);
+
   // Aggregates <= 16 bytes are returned directly in registers or on the stack.
   if (Size <= 128) {
     // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
@@ -5750,6 +5770,9 @@
   if (isEmptyRecord(getContext(), Ty, true))
     return ABIArgInfo::getIgnore();
 
+  if (Ty.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+
   if (IsEffectivelyAAPCS_VFP) {
     // Homogeneous Aggregates need to be expanded when we can fit the aggregate
     // into VFP registers.
@@ -5940,6 +5963,9 @@
                                             : ABIArgInfo::getDirect();
   }
 
+  if (RetTy.isPassedIndirectly() == QualType::APK_Struct)
+    return getNaturalAlignIndirect(RetTy);
+
   // Are we following APCS?
   if (getABIKind() == APCS) {
     if (isEmptyRecord(getContext(), RetTy, false))
Index: lib/CodeGen/CGNonTrivialStruct.cpp
===================================================================
--- lib/CodeGen/CGNonTrivialStruct.cpp
+++ lib/CodeGen/CGNonTrivialStruct.cpp
@@ -77,6 +77,8 @@
     switch (PDIK) {
     case QualType::PDIK_ARCStrong:
       return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
+    case QualType::PDIK_ARCWeak:
+      return asDerived().visitARCWeak(FT, std::forward<Ts>(Args)...);
     case QualType::PDIK_Struct:
       return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
     case QualType::PDIK_Trivial:
@@ -108,6 +110,8 @@
     switch (PCK) {
     case QualType::PCK_ARCStrong:
       return asDerived().visitARCStrong(FT, std::forward<Ts>(Args)...);
+    case QualType::PCK_ARCWeak:
+      return asDerived().visitARCWeak(FT, std::forward<Ts>(Args)...);
     case QualType::PCK_Struct:
       return asDerived().visitStruct(FT, std::forward<Ts>(Args)...);
     case QualType::PCK_Trivial:
@@ -141,11 +145,6 @@
 
   template <class... Ts> void visitTrivial(Ts... Args) {}
 
-  template <class... Ts> void visitARCWeak(Ts... Args) {
-    // FIXME: remove this when visitARCWeak is implemented in the subclasses.
-    llvm_unreachable("weak field is not expected");
-  }
-
   template <class... Ts> void visitCXXDestructor(Ts... Args) {
     llvm_unreachable("field of a C++ struct type is not expected");
   }
@@ -245,6 +244,13 @@
     appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
   }
 
+  void visitARCWeak(QualType FT, const FieldDecl *FD,
+                    CharUnits CurStructOffset) {
+    appendStr("_w");
+    CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
+    appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
+  }
+
   void visitStruct(QualType QT, const FieldDecl *FD,
                    CharUnits CurStructOffset) {
     CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
@@ -615,6 +621,12 @@
         *CGF, getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
   }
 
+  void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 1> Addrs) {
+    CGF->destroyARCWeak(
+        *CGF, getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
+  }
+
   void callSpecialFunction(QualType FT, CharUnits Offset,
                            std::array<Address, 1> Addrs) {
     CGF->callCStructDestructor(
@@ -636,6 +648,12 @@
         getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
   }
 
+  void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 1> Addrs) {
+    CGF->EmitNullInitialization(
+        getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD), QT);
+  }
+
   template <class FieldKind, size_t... Is>
   void visitArray(FieldKind FK, QualType QT, const FieldDecl *FD,
                   CharUnits CurStackOffset, std::array<Address, 1> Addrs) {
@@ -678,6 +696,14 @@
     llvm::Value *Val = CGF->EmitARCRetain(QT, SrcVal);
     CGF->EmitStoreOfScalar(Val, CGF->MakeAddrLValue(Addrs[DstIdx], QT), true);
   }
+
+  void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 2> Addrs) {
+    Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
+    Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
+    CGF->EmitARCCopyWeak(Addrs[DstIdx], Addrs[SrcIdx]);
+  }
+
   void callSpecialFunction(QualType FT, CharUnits Offset,
                            std::array<Address, 2> Addrs) {
     CGF->callCStructCopyConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
@@ -700,6 +726,14 @@
     CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT),
                            /* isInitialization */ true);
   }
+
+  void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 2> Addrs) {
+    Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
+    Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
+    CGF->EmitARCMoveWeak(Addrs[DstIdx], Addrs[SrcIdx]);
+  }
+
   void callSpecialFunction(QualType FT, CharUnits Offset,
                            std::array<Address, 2> Addrs) {
     CGF->callCStructMoveConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
@@ -720,6 +754,16 @@
     CGF->EmitARCStoreStrong(CGF->MakeAddrLValue(Addrs[DstIdx], QT), SrcVal,
                             false);
   }
+
+  void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 2> Addrs) {
+    Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
+    Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
+    llvm::Value *Object = CGF->EmitARCLoadWeakRetained(Addrs[SrcIdx]);
+    Object = CGF->EmitObjCConsumeObject(QT, Object);
+    CGF->EmitARCStoreWeak(Addrs[DstIdx], Object, true);
+  }
+
   void callSpecialFunction(QualType FT, CharUnits Offset,
                            std::array<Address, 2> Addrs) {
     CGF->callCStructCopyAssignmentOperator(
@@ -747,6 +791,16 @@
     CGF->EmitARCRelease(DstVal, ARCImpreciseLifetime);
   }
 
+  void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStackOffset,
+                    std::array<Address, 2> Addrs) {
+    Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
+    Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
+    llvm::Value *Object = CGF->EmitARCLoadWeakRetained(Addrs[SrcIdx]);
+    Object = CGF->EmitObjCConsumeObject(QT, Object);
+    CGF->EmitARCStoreWeak(Addrs[DstIdx], Object, false);
+    CGF->EmitARCDestroyWeak(Addrs[SrcIdx]);
+  }
+
   void callSpecialFunction(QualType FT, CharUnits Offset,
                            std::array<Address, 2> Addrs) {
     CGF->callCStructMoveAssignmentOperator(
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -1565,6 +1565,9 @@
   case QualType::PCK_Struct:
     return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct,
                           BlockFieldFlags());
+  case QualType::PCK_ARCWeak:
+    // We need to register __weak direct captures with the runtime.
+    return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags);
   case QualType::PCK_ARCStrong:
     // We need to retain the copied value for __strong direct captures.
     // If it's a block pointer, we have to copy the block and assign that to
@@ -1582,10 +1585,6 @@
     // Special rules for ARC captures:
     Qualifiers QS = T.getQualifiers();
 
-    // We need to register __weak direct captures with the runtime.
-    if (QS.getObjCLifetime() == Qualifiers::OCL_Weak)
-      return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags);
-
     // Non-ARC captures of retainable pointers are strong and
     // therefore require a call to _Block_object_assign.
     if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount)
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2215,11 +2215,14 @@
     if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize())
       return PDIK_Struct;
 
-  Qualifiers::ObjCLifetime Lifetime = getQualifiers().getObjCLifetime();
-  if (Lifetime == Qualifiers::OCL_Strong)
+  switch (getQualifiers().getObjCLifetime()) {
+  case Qualifiers::OCL_Strong:
     return PDIK_ARCStrong;
-
-  return PDIK_Trivial;
+  case Qualifiers::OCL_Weak:
+    return PDIK_ARCWeak;
+  default:
+    return PDIK_Trivial;
+  }
 }
 
 QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const {
@@ -2229,17 +2232,33 @@
       return PCK_Struct;
 
   Qualifiers Qs = getQualifiers();
-  if (Qs.getObjCLifetime() == Qualifiers::OCL_Strong)
+  switch (Qs.getObjCLifetime()) {
+  case Qualifiers::OCL_Strong:
     return PCK_ARCStrong;
-
-  return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial;
+  case Qualifiers::OCL_Weak:
+    return PCK_ARCWeak;
+  default:
+    return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial;
+  }
 }
 
 QualType::PrimitiveCopyKind
 QualType::isNonTrivialToPrimitiveDestructiveMove() const {
   return isNonTrivialToPrimitiveCopy();
 }
 
+QualType::ArgPassingKind QualType::isPassedIndirectly() const {
+  if (const auto *RT =
+          getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    if (RT->getDecl()->isPassedIndirectly())
+      return APK_Struct;
+
+  if (getQualifiers().getObjCLifetime() == Qualifiers::OCL_Weak)
+    return APK_ARCWeak;
+
+  return APK_Direct;
+}
+
 bool Type::isLiteralType(const ASTContext &Ctx) const {
   if (isDependentType())
     return false;
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3931,7 +3931,8 @@
       HasObjectMember(false), HasVolatileMember(false),
       LoadedFieldsFromExternalStorage(false),
       NonTrivialToPrimitiveDefaultInitialize(false),
-      NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false) {
+      NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false),
+      PassedIndirectly(false) {
   assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
 }
 
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1097,6 +1097,10 @@
     /// with the ARC __strong qualifier.
     PDIK_ARCStrong,
 
+    /// The type is an Objective-C retainable pointer type that is qualified
+    /// with the ARC __weak qualifier.
+    PDIK_ARCWeak,
+
     /// The type is a struct containing a field whose type is not PCK_Trivial.
     PDIK_Struct
   };
@@ -1124,6 +1128,10 @@
     /// with the ARC __strong qualifier.
     PCK_ARCStrong,
 
+    /// The type is an Objective-C retainable pointer type that is qualified
+    /// with the ARC __weak qualifier.
+    PCK_ARCWeak,
+
     /// The type is a struct containing a field whose type is neither
     /// PCK_Trivial nor PCK_VolatileTrivial.
     /// Note that a C++ struct type does not necessarily match this; C++ copying
@@ -1146,6 +1154,14 @@
   /// source object is placed in an uninitialized state.
   PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const;
 
+  enum ArgPassingKind {
+    APK_Direct,
+    APK_ARCWeak,
+    APK_Struct
+  };
+
+  ArgPassingKind isPassedIndirectly() const;
+
   enum DestructionKind {
     DK_none,
     DK_cxx_destructor,
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -3537,6 +3537,7 @@
   bool NonTrivialToPrimitiveDefaultInitialize : 1;
   bool NonTrivialToPrimitiveCopy : 1;
   bool NonTrivialToPrimitiveDestroy : 1;
+  bool PassedIndirectly : 1;
 
 protected:
   RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC,
@@ -3621,6 +3622,14 @@
     NonTrivialToPrimitiveDestroy = true;
   }
 
+  bool isPassedIndirectly() const {
+    return PassedIndirectly;
+  }
+
+  void setPassedIndirectly() {
+    PassedIndirectly = true;
+  }
+
   /// \brief Determines whether this declaration represents the
   /// injected class name.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to