bkelley created this revision.

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.


https://reviews.llvm.org/D31003

Files:
  lib/AST/DeclCXX.cpp
  lib/Sema/SemaDeclCXX.cpp
  test/CodeGenObjCXX/objc-weak.mm

Index: test/CodeGenObjCXX/objc-weak.mm
===================================================================
--- /dev/null
+++ test/CodeGenObjCXX/objc-weak.mm
@@ -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]])
+
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -4399,11 +4399,13 @@
     }
   }
   
-  if (SemaRef.getLangOpts().ObjCAutoRefCount &&
-      FieldBaseElementType->isObjCRetainableType() &&
-      FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
-      FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
-    // ARC:
+  if (FieldBaseElementType->isObjCRetainableType() &&
+      ((SemaRef.getLangOpts().ObjCAutoRefCount &&
+        FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
+        FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) ||
+       (SemaRef.getLangOpts().ObjCWeak &&
+        FieldBaseElementType.getObjCLifetime() == Qualifiers::OCL_Weak))) {
+    // ARC and Weak:
     //   Default-initialize Objective-C pointers to NULL.
     CXXMemberInit
       = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, 
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -722,7 +722,9 @@
     ASTContext &Context = getASTContext();
     QualType T = Context.getBaseElementType(Field->getType());
     if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
-      if (!Context.getLangOpts().ObjCAutoRefCount) {
+      if (!Context.getLangOpts().ObjCAutoRefCount &&
+          !(Context.getLangOpts().ObjCWeak &&
+            T.getObjCLifetime() == Qualifiers::OCL_Weak)) {
         setHasObjectMember(true);
       } else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
         // Objective-C Automatic Reference Counting:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to