mirror of https://github.com/microsoft/clang.git
[Objective-C] C++ Classes with __weak Members non-POD Types when using -fobjc-weak
Summary: When adding an Objective-C retainable type member to a C++ class, also check the LangOpts.ObjCWeak flag and the lifetime qualifier so __weak qualified Objective-C pointer members cause the class to be a non-POD type with non-trivial special members, so the compiler always emits the necessary runtime calls for copying, moving, and destroying the weak member. Otherwise, Objective-C++ classes with weak Objective-C pointer members compiled with -fobjc-weak exhibit undefined behavior if the C++ class is classified as a POD type. Reviewers: rsmith, benlangmuir, doug.gregor, rjmccall Reviewed By: rjmccall Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D31003 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@299008 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1895a41ddd
commit
b18f3efe98
|
@ -722,9 +722,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
ASTContext &Context = getASTContext();
|
||||
QualType T = Context.getBaseElementType(Field->getType());
|
||||
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
|
||||
if (!Context.getLangOpts().ObjCAutoRefCount) {
|
||||
setHasObjectMember(true);
|
||||
} else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
|
||||
if (T.hasNonTrivialObjCLifetime()) {
|
||||
// Objective-C Automatic Reference Counting:
|
||||
// If a class has a non-static data member of Objective-C pointer
|
||||
// type (or array thereof), it is a non-POD type and its
|
||||
|
@ -736,6 +734,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
Data.PlainOldData = false;
|
||||
Data.HasTrivialSpecialMembers = 0;
|
||||
Data.HasIrrelevantDestructor = false;
|
||||
} else if (!Context.getLangOpts().ObjCAutoRefCount) {
|
||||
setHasObjectMember(true);
|
||||
}
|
||||
} else if (!T.isCXX98PODType(Context))
|
||||
data().PlainOldData = false;
|
||||
|
|
|
@ -4399,11 +4399,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
|
|||
}
|
||||
}
|
||||
|
||||
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
|
||||
FieldBaseElementType->isObjCRetainableType() &&
|
||||
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
|
||||
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
|
||||
// ARC:
|
||||
if (FieldBaseElementType.hasNonTrivialObjCLifetime()) {
|
||||
// ARC and Weak:
|
||||
// Default-initialize Objective-C pointers to NULL.
|
||||
CXXMemberInit
|
||||
= new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-weak -fobjc-runtime-has-weak -std=c++11 -o - %s | FileCheck %s
|
||||
|
||||
struct A { __weak id x; };
|
||||
|
||||
id test0() {
|
||||
A a;
|
||||
A b = a;
|
||||
A c(static_cast<A&&>(b));
|
||||
a = c;
|
||||
c = static_cast<A&&>(a);
|
||||
return c.x;
|
||||
}
|
||||
|
||||
// Copy Assignment Operator
|
||||
// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.A* @_ZN1AaSERKS_(
|
||||
// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
|
||||
// CHECK: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]])
|
||||
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
|
||||
|
||||
// Move Assignment Operator
|
||||
// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.A* @_ZN1AaSEOS_(
|
||||
// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
|
||||
// CHECK: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[T0]])
|
||||
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[T2]], i8* [[T1]])
|
||||
|
||||
// Default Constructor
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZN1AC2Ev(
|
||||
// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8* null, i8** [[T0]]
|
||||
|
||||
// Copy Constructor
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZN1AC2ERKS_(
|
||||
// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
|
||||
// CHECK-NEXT: call void @objc_copyWeak(i8** [[T0]], i8** [[T1]])
|
||||
|
||||
// Move Constructor
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZN1AC2EOS_(
|
||||
// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[OBJECTADDR:%.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
|
||||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[OBJECT:%.*]] = load [[A]]*, [[A]]** [[OBJECTADDR]]
|
||||
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[OBJECT]], i32 0, i32 0
|
||||
// CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
|
||||
|
||||
// Destructor
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZN1AD2Ev(
|
||||
// CHECK: [[THISADDR:%this.*]] = alloca [[A:.*]]*
|
||||
// CHECK: [[THIS:%this.*]] = load [[A]]*, [[A]]** [[THISADDR]]
|
||||
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
|
||||
|
Loading…
Reference in New Issue