ahatanak created this revision.
ahatanak added reviewers: rjmccall, rsmith.
Herald added a subscriber: kristof.beyls.

This patch fixes a bug where a struct with an ObjC `__weak` field gets 
destructed after it has already been destructed. This bug was introduced in 
r328731, which made changes to the ABI that caused structs with ObjC pointer 
fields to be destructed in the callee in some cases.

This happens in two cases:

1. C++11 inheriting constructors.
2. When EmitConstructorBody does complete->base constructor delegation 
optimization.

I fixed the first case by making changes to canEmitDelegateCallArgs so that it 
returns false when the constructor has a parameter that is destructed in the 
callee.

For the second case, I made changes so that EmitParmDecl doesn't push the 
destructor cleanup for the struct parameter if the function is a constructor 
that is going to delegate to the base constructor. Alternatively, I think it's 
possible to just disable the optimization in EmitConstructorBody if 
canEmitDelegateCallArgs returns false.

rdar://problem/39194693


Repository:
  rC Clang

https://reviews.llvm.org/D45382

Files:
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenObjCXX/arc-special-member-functions.mm

Index: test/CodeGenObjCXX/arc-special-member-functions.mm
===================================================================
--- test/CodeGenObjCXX/arc-special-member-functions.mm
+++ test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
 
 struct ObjCMember {
   id member;
@@ -12,6 +12,54 @@
   int (^bp)(int);
 };
 
+// CHECK: %[[STRUCT_CONTAINSWEAK:.*]] = type { %[[STRUCT_WEAK:.*]] }
+// CHECK: %[[STRUCT_WEAK]] = type { i8* }
+
+// The Weak object that is passed is destructed in this constructor.
+
+// CHECK: define void @_ZN12ContainsWeakC2E4Weak(
+// CHECK: call void @_ZN4WeakC1ERKS_(
+// CHECK: call void @_ZN4WeakD1Ev(
+
+// Check that Weak's destructor is not called after the delegate constructor is
+// called.
+
+// CHECK: define void @_ZN12ContainsWeakC1E4Weak(
+// CHECK: call void @_ZN12ContainsWeakC2E4Weak(
+// CHECK-NEXT: ret void
+
+struct Weak {
+  Weak(id);
+  __weak id x;
+};
+
+struct ContainsWeak {
+  ContainsWeak(Weak);
+  Weak w;
+};
+
+ContainsWeak::ContainsWeak(Weak a) : w(a) {}
+
+// Check that the call to the inheriting constructor is inlined.
+
+// CHECK: define internal void @__cxx_global_var_init{{.*}}()
+// CHECK: call void @_ZN4WeakC1EP11objc_object(
+// CHECK-NOT: call
+// CHECK: call void @_ZN4BaseC2E4Weak(
+// CHECK-NEXT: ret void
+
+struct Base {
+  Base(Weak);
+};
+
+Base::Base(Weak a) {}
+
+struct Derived : Base {
+  using Base::Base;
+};
+
+Derived d(Weak(0));
+
 // CHECK-LABEL: define void @_Z42test_ObjCMember_default_construct_destructv(
 void test_ObjCMember_default_construct_destruct() {
   // CHECK: call void @_ZN10ObjCMemberC1Ev
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -380,6 +380,10 @@
   /// should emit cleanups.
   bool CurFuncIsThunk;
 
+  /// In C++, whether we are code generating a constructor that is calling a
+  /// delegating constructor.
+  bool DelegateCXXConstructorCall;
+
   /// In ARC, whether we should autorelease the return value.
   bool AutoreleaseResult;
 
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -67,7 +67,8 @@
               CGBuilderInserterTy(this)),
       CurFn(nullptr), ReturnValue(Address::invalid()),
       CapturedStmtInfo(nullptr), SanOpts(CGM.getLangOpts().Sanitize),
-      IsSanitizerScope(false), CurFuncIsThunk(false), AutoreleaseResult(false),
+      IsSanitizerScope(false), CurFuncIsThunk(false),
+      DelegateCXXConstructorCall(false), AutoreleaseResult(false),
       SawAsmBlock(false), IsOutlinedSEHHelper(false), BlockInfo(nullptr),
       BlockPointer(nullptr), LambdaThisCaptureField(nullptr),
       NormalCleanupDest(Address::invalid()), NextCleanupDestIndex(1),
@@ -1307,6 +1308,13 @@
   if (Body && ShouldEmitLifetimeMarkers)
     Bypasses.Init(Body);
 
+  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(CurGD.getDecl())) {
+    if (CurGD.getCtorType() == Ctor_Complete &&
+        IsConstructorDelegationValid(Ctor) &&
+        CGM.getTarget().getCXXABI().hasConstructorVariants())
+      DelegateCXXConstructorCall = true;
+  }
+
   // Emit the standard function prologue.
   StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
 
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -1949,7 +1949,7 @@
     // Push a destructor cleanup for this parameter if the ABI requires it.
     // Don't push a cleanup in a thunk for a method that will also emit a
     // cleanup.
-    if (!IsScalar && !CurFuncIsThunk &&
+    if (!IsScalar && !CurFuncIsThunk && !DelegateCXXConstructorCall &&
         getContext().isParamDestroyedInCallee(Ty)) {
       if (QualType::DestructionKind DtorKind = Ty.isDestructedType()) {
         assert((DtorKind == QualType::DK_cxx_destructor ||
Index: lib/CodeGen/CGClass.cpp
===================================================================
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -819,8 +819,7 @@
 
   // Before we go any further, try the complete->base constructor
   // delegation optimization.
-  if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
-      CGM.getTarget().getCXXABI().hasConstructorVariants()) {
+  if (DelegateCXXConstructorCall) {
     EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getLocEnd());
     return;
   }
@@ -2033,12 +2032,13 @@
   if (Ctor->isVariadic())
     return false;
 
-  if (CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
-    // If the parameters are callee-cleanup, it's not safe to forward.
-    for (auto *P : Ctor->parameters())
-      if (P->getType().isDestructedType())
-        return false;
+  // If the parameters are callee-cleanup, it's not safe to forward.
+  for (auto *P : Ctor->parameters())
+    if (CGF.getContext().isParamDestroyedInCallee(P->getType()) &&
+        P->getType().isDestructedType())
+      return false;
 
+  if (CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
     // Likewise if they're inalloca.
     const CGFunctionInfo &Info =
         CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0, 0);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to