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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits