]> granicus.if.org Git - clang/commitdiff
Revert r183721. It caused cleanups to be delayed too long in some cases.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 11 Jun 2013 19:14:25 +0000 (19:14 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 11 Jun 2013 19:14:25 +0000 (19:14 +0000)
Testcase to follow.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183776 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCleanup.cpp
lib/CodeGen/CGCleanup.h
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaInit.cpp
test/CodeGenCXX/cxx11-thread-local.cpp
test/CodeGenCXX/temporaries.cpp

index 65de4d498d1a36bbdfd6feb773e599a720e9e57c..9f693ca8b7b3957dc3efc93c818bff11999c61d2 100644 (file)
@@ -387,33 +387,6 @@ void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) {
   }
 }
 
-/// Pops cleanup blocks until the given savepoint is reached, then add the
-/// cleanups from the given savepoint in the lifetime-extended cleanups stack.
-void
-CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,
-                                  size_t OldLifetimeExtendedSize) {
-  PopCleanupBlocks(Old);
-
-  // Move our deferred cleanups onto the EH stack.
-  for (size_t I = OldLifetimeExtendedSize,
-              E = LifetimeExtendedCleanupStack.size(); I != E; /**/) {
-    // Alignment should be guaranteed by the vptrs in the individual cleanups.
-    assert((I % llvm::alignOf<LifetimeExtendedCleanupHeader>() == 0) &&
-           "misaligned cleanup stack entry");
-
-    LifetimeExtendedCleanupHeader &Header =
-        reinterpret_cast<LifetimeExtendedCleanupHeader&>(
-            LifetimeExtendedCleanupStack[I]);
-    I += sizeof(Header);
-
-    EHStack.pushCopyOfCleanup(Header.getKind(),
-                              &LifetimeExtendedCleanupStack[I],
-                              Header.getSize());
-    I += Header.getSize();
-  }
-  LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize);
-}
-
 static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,
                                            EHCleanupScope &Scope) {
   assert(Scope.isNormalCleanup());
index 61d9f02a08f064a7eaee372ecd77b6e42b7b32c3..40a7502973e1b6014a614b289aa465e64dabaf21 100644 (file)
@@ -374,11 +374,6 @@ public:
     return new (Buffer) T(N, a0, a1, a2);
   }
 
-  void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {
-    void *Buffer = pushCleanup(Kind, Size);
-    std::memcpy(Buffer, Cleanup, Size);
-  }
-
   /// Pops a cleanup scope off the stack.  This is private to CGCleanup.cpp.
   void popCleanup();
 
index 7fc79e08f0f30393ca4a03de7087c312e5b6d1be..4b19b54df587038e724f565e4a6ce56464f79811 100644 (file)
@@ -1340,26 +1340,6 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
                                      destroyer, useEHCleanupForArray);
 }
 
-void CodeGenFunction::pushLifetimeExtendedDestroy(
-    CleanupKind cleanupKind, llvm::Value *addr, QualType type,
-    Destroyer *destroyer, bool useEHCleanupForArray) {
-  assert(!isInConditionalBranch() &&
-         "performing lifetime extension from within conditional");
-
-  // Push an EH-only cleanup for the object now.
-  // FIXME: When popping normal cleanups, we need to keep this EH cleanup
-  // around in case a temporary's destructor throws an exception.
-  if (cleanupKind & EHCleanup)
-    EHStack.pushCleanup<DestroyObject>(
-        static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
-        destroyer, useEHCleanupForArray);
-
-  // Remember that we need to push a full cleanup for the object at the
-  // end of the full-expression.
-  pushCleanupAfterFullExpr<DestroyObject>(
-      cleanupKind, addr, type, destroyer, useEHCleanupForArray);
-}
-
 /// emitDestroy - Immediately perform the destruction of the given
 /// object.
 ///
index d534ff440cf077319e1c921415698537decae0d7..501d7ecfa3734bb50941f1c8d2ad8d40da81c719 100644 (file)
@@ -171,164 +171,66 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
   llvm_unreachable("bad evaluation kind");
 }
 
-static void
-pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
-                     const Expr *E, llvm::Value *ReferenceTemporary) {
-  // Objective-C++ ARC:
-  //   If we are binding a reference to a temporary that has ownership, we
-  //   need to perform retain/release operations on the temporary.
-  //
-  // FIXME: This should be looking at E, not M.
-  if (CGF.getLangOpts().ObjCAutoRefCount &&
-      M->getType()->isObjCLifetimeType()) {
-    QualType ObjCARCReferenceLifetimeType = M->getType();
-    switch (Qualifiers::ObjCLifetime Lifetime =
-                ObjCARCReferenceLifetimeType.getObjCLifetime()) {
-    case Qualifiers::OCL_None:
-    case Qualifiers::OCL_ExplicitNone:
-      // Carry on to normal cleanup handling.
-      break;
-
-    case Qualifiers::OCL_Autoreleasing:
-      // Nothing to do; cleaned up by an autorelease pool.
-      return;
-
-    case Qualifiers::OCL_Strong:
-    case Qualifiers::OCL_Weak:
-      switch (StorageDuration Duration = M->getStorageDuration()) {
-      case SD_Static:
-        // Note: we intentionally do not register a cleanup to release
-        // the object on program termination.
-        return;
-
-      case SD_Thread:
-        // FIXME: We should probably register a cleanup in this case.
-        return;
-
-      case SD_Automatic:
-      case SD_FullExpression:
-        assert(!ObjCARCReferenceLifetimeType->isArrayType());
-        CodeGenFunction::Destroyer *Destroy;
-        CleanupKind CleanupKind;
-        if (Lifetime == Qualifiers::OCL_Strong) {
-          const ValueDecl *VD = M->getExtendingDecl();
-          bool Precise =
-              VD && isa<VarDecl>(VD) && VD->hasAttr<ObjCPreciseLifetimeAttr>();
-          CleanupKind = CGF.getARCCleanupKind();
-          Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise
-                            : &CodeGenFunction::destroyARCStrongImprecise;
-        } else {
-          // __weak objects always get EH cleanups; otherwise, exceptions
-          // could cause really nasty crashes instead of mere leaks.
-          CleanupKind = NormalAndEHCleanup;
-          Destroy = &CodeGenFunction::destroyARCWeak;
-        }
-        if (Duration == SD_FullExpression)
-          CGF.pushDestroy(CleanupKind, ReferenceTemporary,
-                          ObjCARCReferenceLifetimeType, *Destroy,
-                          CleanupKind & EHCleanup);
-        else
-          CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,
-                                          ObjCARCReferenceLifetimeType,
-                                          *Destroy, CleanupKind & EHCleanup);
-        return;
-
-      case SD_Dynamic:
-        llvm_unreachable("temporary cannot have dynamic storage duration");
-      }
-      llvm_unreachable("unknown storage duration");
-    }
-  }
-
-  if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
-    if (ILE->initializesStdInitializerList()) {
-      // FIXME: This is wrong if the temporary has static or thread storage
-      // duration.
-      CGF.EmitStdInitializerListCleanup(ReferenceTemporary, ILE);
-      return;
-    }
-  }
-
-  CXXDestructorDecl *ReferenceTemporaryDtor = 0;
-  if (const RecordType *RT =
-          E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
-    // Get the destructor for the reference temporary.
-    CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
-    if (!ClassDecl->hasTrivialDestructor())
-      ReferenceTemporaryDtor = ClassDecl->getDestructor();
-  }
-
-  if (!ReferenceTemporaryDtor)
-    return;
-
-  // Call the destructor for the temporary.
-  switch (M->getStorageDuration()) {
-  case SD_Static:
-  case SD_Thread: {
-    llvm::Constant *CleanupFn;
-    llvm::Constant *CleanupArg;
-    if (E->getType()->isArrayType()) {
-      CleanupFn = CodeGenFunction(CGF.CGM).generateDestroyHelper(
-          cast<llvm::Constant>(ReferenceTemporary), E->getType(),
-          CodeGenFunction::destroyCXXObject, CGF.getLangOpts().Exceptions);
-      CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);
-    } else {
-      CleanupFn =
-        CGF.CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
-      CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
+static llvm::Value *
+CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
+                         const NamedDecl *InitializedDecl) {
+  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
+    if (VD->hasGlobalStorage()) {
+      SmallString<256> Name;
+      llvm::raw_svector_ostream Out(Name);
+      CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
+      Out.flush();
+
+      llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);
+  
+      // Create the reference temporary.
+      llvm::GlobalVariable *RefTemp =
+        new llvm::GlobalVariable(CGF.CGM.getModule(), 
+                                 RefTempTy, /*isConstant=*/false,
+                                 llvm::GlobalValue::InternalLinkage,
+                                 llvm::Constant::getNullValue(RefTempTy),
+                                 Name.str());
+      // If we're binding to a thread_local variable, the temporary is also
+      // thread local.
+      if (VD->getTLSKind())
+        CGF.CGM.setTLSMode(RefTemp, *VD);
+      return RefTemp;
     }
-    CGF.CGM.getCXXABI().registerGlobalDtor(
-        CGF, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);
-    break;
-  }
-
-  case SD_FullExpression:
-    CGF.pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
-                    CodeGenFunction::destroyCXXObject,
-                    CGF.getLangOpts().Exceptions);
-    break;
-
-  case SD_Automatic:
-    CGF.pushLifetimeExtendedDestroy(NormalAndEHCleanup,
-                                    ReferenceTemporary, E->getType(),
-                                    CodeGenFunction::destroyCXXObject,
-                                    CGF.getLangOpts().Exceptions);
-    break;
-
-  case SD_Dynamic:
-    llvm_unreachable("temporary cannot have dynamic storage duration");
   }
-}
-
-static llvm::Value *
-createReferenceTemporary(CodeGenFunction &CGF,
-                         const MaterializeTemporaryExpr *M, const Expr *Inner) {
-  switch (M->getStorageDuration()) {
-  case SD_FullExpression:
-  case SD_Automatic:
-    return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
 
-  case SD_Thread:
-  case SD_Static:
-    return CGF.CGM.GetAddrOfGlobalTemporary(M, Inner);
-
-  case SD_Dynamic:
-    llvm_unreachable("temporary can't have dynamic storage duration");
-  }
-  llvm_unreachable("unknown storage duration");
+  return CGF.CreateMemTemp(Type, "ref.tmp");
 }
 
 static llvm::Value *
-emitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
+EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
+                            llvm::Value *&ReferenceTemporary,
+                            const CXXDestructorDecl *&ReferenceTemporaryDtor,
+                            const InitListExpr *&ReferenceInitializerList,
+                            QualType &ObjCARCReferenceLifetimeType,
                             const NamedDecl *InitializedDecl) {
+  const MaterializeTemporaryExpr *M = NULL;
+  E = E->findMaterializedTemporary(M);
+  // Objective-C++ ARC:
+  //   If we are binding a reference to a temporary that has ownership, we
+  //   need to perform retain/release operations on the temporary.
+  if (M && CGF.getLangOpts().ObjCAutoRefCount &&
+      M->getType()->isObjCLifetimeType() &&
+      (M->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
+       M->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
+       M->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
+    ObjCARCReferenceLifetimeType = M->getType();
+
   if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
     CGF.enterFullExpression(EWC);
     CodeGenFunction::RunCleanupsScope Scope(CGF);
-    return emitExprForReferenceBinding(CGF, EWC->getSubExpr(), InitializedDecl);
-  }
 
-  const MaterializeTemporaryExpr *M = 0;
-  E = E->findMaterializedTemporary(M);
+    return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(), 
+                                       ReferenceTemporary, 
+                                       ReferenceTemporaryDtor,
+                                       ReferenceInitializerList,
+                                       ObjCARCReferenceLifetimeType,
+                                       InitializedDecl);
+  }
 
   if (E->isGLValue()) {
     // Emit the expression as an lvalue.
@@ -336,22 +238,61 @@ emitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
     assert(LV.isSimple());
     return LV.getAddress();
   }
-
-  assert(M && "prvalue reference initializer but not a materialized temporary");
-
-  if (CGF.getLangOpts().ObjCAutoRefCount &&
-      M->getType()->isObjCLifetimeType() &&
-      M->getType().getObjCLifetime() != Qualifiers::OCL_None &&
-      M->getType().getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
-    // FIXME: Fold this into the general case below.
-    llvm::Value *Object = createReferenceTemporary(CGF, M, E);
-    LValue RefTempDst = CGF.MakeAddrLValue(Object, M->getType());
+  
+  if (!ObjCARCReferenceLifetimeType.isNull()) {
+    ReferenceTemporary = CreateReferenceTemporary(CGF, 
+                                                ObjCARCReferenceLifetimeType, 
+                                                  InitializedDecl);
+    
+    
+    LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary, 
+                                           ObjCARCReferenceLifetimeType);
 
     CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl),
                        RefTempDst, false);
-
-    pushTemporaryCleanup(CGF, M, E, Object);
-    return Object;
+    
+    bool ExtendsLifeOfTemporary = false;
+    if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
+      if (Var->extendsLifetimeOfTemporary())
+        ExtendsLifeOfTemporary = true;
+    } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) {
+      ExtendsLifeOfTemporary = true;
+    }
+    
+    if (!ExtendsLifeOfTemporary) {
+      // Since the lifetime of this temporary isn't going to be extended,
+      // we need to clean it up ourselves at the end of the full expression.
+      switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+      case Qualifiers::OCL_None:
+      case Qualifiers::OCL_ExplicitNone:
+      case Qualifiers::OCL_Autoreleasing:
+        break;
+          
+      case Qualifiers::OCL_Strong: {
+        assert(!ObjCARCReferenceLifetimeType->isArrayType());
+        CleanupKind cleanupKind = CGF.getARCCleanupKind();
+        CGF.pushDestroy(cleanupKind, 
+                        ReferenceTemporary,
+                        ObjCARCReferenceLifetimeType,
+                        CodeGenFunction::destroyARCStrongImprecise,
+                        cleanupKind & EHCleanup);
+        break;
+      }
+        
+      case Qualifiers::OCL_Weak:
+        assert(!ObjCARCReferenceLifetimeType->isArrayType());
+        CGF.pushDestroy(NormalAndEHCleanup, 
+                        ReferenceTemporary,
+                        ObjCARCReferenceLifetimeType,
+                        CodeGenFunction::destroyARCWeak,
+                        /*useEHCleanupForArray*/ true);
+        break;
+      }
+      
+      ObjCARCReferenceLifetimeType = QualType();
+    }
+    
+    return ReferenceTemporary;
   }
 
   SmallVector<const Expr *, 2> CommaLHSs;
@@ -361,59 +302,112 @@ emitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
   for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
     CGF.EmitIgnoredExpr(CommaLHSs[I]);
 
-  if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) {
-    if (opaque->getType()->isRecordType()) {
-      assert(Adjustments.empty());
+  if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
+    if (opaque->getType()->isRecordType())
       return CGF.EmitOpaqueValueLValue(opaque).getAddress();
+
+  // Create a reference temporary if necessary.
+  AggValueSlot AggSlot = AggValueSlot::ignored();
+  if (CGF.hasAggregateEvaluationKind(E->getType())) {
+    ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), 
+                                                  InitializedDecl);
+    CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
+    AggValueSlot::IsDestructed_t isDestructed
+      = AggValueSlot::IsDestructed_t(InitializedDecl != 0);
+    AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment,
+                                    Qualifiers(), isDestructed,
+                                    AggValueSlot::DoesNotNeedGCBarriers,
+                                    AggValueSlot::IsNotAliased);
+  }
+  
+  if (InitializedDecl) {
+    if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+      if (ILE->initializesStdInitializerList()) {
+        ReferenceInitializerList = ILE;
+      }
+    }
+    else if (const RecordType *RT =
+               E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()){
+      // Get the destructor for the reference temporary.
+      CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+      if (!ClassDecl->hasTrivialDestructor())
+        ReferenceTemporaryDtor = ClassDecl->getDestructor();
     }
   }
 
-  // Create and initialize the reference temporary.
-  llvm::Value *Object = createReferenceTemporary(CGF, M, E);
-  CGF.EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
-  pushTemporaryCleanup(CGF, M, E, Object);
-
-  // Perform derived-to-base casts and/or field accesses, to get from the
-  // temporary object we created (and, potentially, for which we extended
-  // the lifetime) to the subobject we're binding the reference to.
-  for (unsigned I = Adjustments.size(); I != 0; --I) {
-    SubobjectAdjustment &Adjustment = Adjustments[I-1];
-    switch (Adjustment.Kind) {
-    case SubobjectAdjustment::DerivedToBaseAdjustment:
-      Object =
-          CGF.GetAddressOfBaseClass(Object,
-                                    Adjustment.DerivedToBase.DerivedClass,
-                          Adjustment.DerivedToBase.BasePath->path_begin(),
-                          Adjustment.DerivedToBase.BasePath->path_end(),
-                                    /*NullCheckValue=*/false);
-      break;
+  RValue RV = CGF.EmitAnyExpr(E, AggSlot);
+
+  // FIXME: This is wrong. We need to register the destructor for the temporary
+  // now, *before* we perform the adjustments, because in the case of a
+  // pointer-to-member adjustment, the adjustment might throw.
+
+  // Check if need to perform derived-to-base casts and/or field accesses, to
+  // get from the temporary object we created (and, potentially, for which we
+  // extended the lifetime) to the subobject we're binding the reference to.
+  if (!Adjustments.empty()) {
+    llvm::Value *Object = RV.getAggregateAddr();
+    for (unsigned I = Adjustments.size(); I != 0; --I) {
+      SubobjectAdjustment &Adjustment = Adjustments[I-1];
+      switch (Adjustment.Kind) {
+      case SubobjectAdjustment::DerivedToBaseAdjustment:
+        Object = 
+            CGF.GetAddressOfBaseClass(Object, 
+                                      Adjustment.DerivedToBase.DerivedClass, 
+                            Adjustment.DerivedToBase.BasePath->path_begin(),
+                            Adjustment.DerivedToBase.BasePath->path_end(),
+                                      /*NullCheckValue=*/false);
+        break;
+          
+      case SubobjectAdjustment::FieldAdjustment: {
+        LValue LV = CGF.MakeAddrLValue(Object, E->getType());
+        LV = CGF.EmitLValueForField(LV, Adjustment.Field);
+        assert(LV.isSimple() &&
+               "materialized temporary field is not a simple lvalue");
+        Object = LV.getAddress();
+        break;
+      }
 
-    case SubobjectAdjustment::FieldAdjustment: {
-      LValue LV = CGF.MakeAddrLValue(Object, E->getType());
-      LV = CGF.EmitLValueForField(LV, Adjustment.Field);
-      assert(LV.isSimple() &&
-             "materialized temporary field is not a simple lvalue");
-      Object = LV.getAddress();
-      break;
+      case SubobjectAdjustment::MemberPointerAdjustment: {
+        llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
+        Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
+                      CGF, Object, Ptr, Adjustment.Ptr.MPT);
+        break;
+      }
+      }
     }
 
-    case SubobjectAdjustment::MemberPointerAdjustment: {
-      llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
-      Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
-                    CGF, Object, Ptr, Adjustment.Ptr.MPT);
-      break;
-    }
-    }
+    return Object;
   }
 
-  return Object;
+  if (RV.isAggregate())
+    return RV.getAggregateAddr();
+
+  // Create a temporary variable that we can bind the reference to.
+  ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), 
+                                                InitializedDecl);
+
+
+  LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,
+                                                 E->getType());
+  if (RV.isScalar())
+    CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);
+  else
+    CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);
+  return ReferenceTemporary;
 }
 
 RValue
 CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
                                             const NamedDecl *InitializedDecl) {
-  llvm::Value *Value = emitExprForReferenceBinding(*this, E, InitializedDecl);
-
+  llvm::Value *ReferenceTemporary = 0;
+  const CXXDestructorDecl *ReferenceTemporaryDtor = 0;
+  const InitListExpr *ReferenceInitializerList = 0;
+  QualType ObjCARCReferenceLifetimeType;
+  llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,
+                                                   ReferenceTemporaryDtor,
+                                                   ReferenceInitializerList,
+                                                   ObjCARCReferenceLifetimeType,
+                                                   InitializedDecl);
   if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) {
     // C++11 [dcl.ref]p5 (as amended by core issue 453):
     //   If a glvalue to which a reference is directly bound designates neither
@@ -423,7 +417,80 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
     QualType Ty = E->getType();
     EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
   }
+  if (!ReferenceTemporaryDtor && !ReferenceInitializerList &&
+      ObjCARCReferenceLifetimeType.isNull())
+    return RValue::get(Value);
+  
+  // Make sure to call the destructor for the reference temporary.
+  const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
+  if (VD && VD->hasGlobalStorage()) {
+    if (ReferenceTemporaryDtor) {
+      llvm::Constant *CleanupFn;
+      llvm::Constant *CleanupArg;
+      if (E->getType()->isArrayType()) {
+        CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(
+            cast<llvm::Constant>(ReferenceTemporary), E->getType(),
+            destroyCXXObject, getLangOpts().Exceptions);
+        CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);
+      } else {
+        CleanupFn =
+          CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+        CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
+      }
+      CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg);
+    } else if (ReferenceInitializerList) {
+      // FIXME: This is wrong. We need to register a global destructor to clean
+      // up the initializer_list object, rather than adding it as a local
+      // cleanup.
+      EmitStdInitializerListCleanup(ReferenceTemporary,
+                                    ReferenceInitializerList);
+    } else {
+      assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind());
+      // Note: We intentionally do not register a global "destructor" to
+      // release the object.
+    }
+    
+    return RValue::get(Value);
+  }
 
+  if (ReferenceTemporaryDtor) {
+    if (E->getType()->isArrayType())
+      pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
+                  destroyCXXObject, getLangOpts().Exceptions);
+    else
+      PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
+  } else if (ReferenceInitializerList) {
+    EmitStdInitializerListCleanup(ReferenceTemporary,
+                                  ReferenceInitializerList);
+  } else {
+    switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+    case Qualifiers::OCL_None:
+      llvm_unreachable(
+                      "Not a reference temporary that needs to be deallocated");
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      // Nothing to do.
+      break;        
+        
+    case Qualifiers::OCL_Strong: {
+      bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
+      CleanupKind cleanupKind = getARCCleanupKind();
+      pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,
+                  precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,
+                  cleanupKind & EHCleanup);
+      break;
+    }
+        
+    case Qualifiers::OCL_Weak: {
+      // __weak objects always get EH cleanups; otherwise, exceptions
+      // could cause really nasty crashes instead of mere leaks.
+      pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
+                  ObjCARCReferenceLifetimeType, destroyARCWeak, true);
+      break;        
+    }
+    }
+  }
+  
   return RValue::get(Value);
 }
 
index f87f203d8fd6e5892f44c9269abf1dc46898d6eb..81b5d05cf6591982904ea7f8d8cda684cfb12208 100644 (file)
@@ -241,18 +241,6 @@ public:
   llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
 
   EHScopeStack EHStack;
-  llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
-
-  /// Header for data within LifetimeExtendedCleanupStack.
-  struct LifetimeExtendedCleanupHeader {
-    /// The size of the following cleanup object.
-    size_t Size : 29;
-    /// The kind of cleanup to push: a value from the CleanupKind enumeration.
-    unsigned Kind : 3;
-
-    size_t getSize() const { return Size; }
-    CleanupKind getKind() const { return static_cast<CleanupKind>(Kind); }
-  };
 
   /// i32s containing the indexes of the cleanup destinations.
   llvm::AllocaInst *NormalCleanupDest;
@@ -388,23 +376,6 @@ public:
     initFullExprCleanup();
   }
 
-  /// \brief Queue a cleanup to be pushed after finishing the current
-  /// full-expression.
-  template <class T, class A0, class A1, class A2, class A3>
-  void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
-    assert(!isInConditionalBranch() && "can't defer conditional cleanup");
-
-    LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind };
-
-    size_t OldSize = LifetimeExtendedCleanupStack.size();
-    LifetimeExtendedCleanupStack.resize(
-        LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size);
-
-    char *Buffer = &LifetimeExtendedCleanupStack[OldSize];
-    new (Buffer) LifetimeExtendedCleanupHeader(Header);
-    new (Buffer + sizeof(Header)) T(a0, a1, a2, a3);
-  }
-
   /// Set up the last cleaup that was pushed as a conditional
   /// full-expression cleanup.
   void initFullExprCleanup();
@@ -450,7 +421,6 @@ public:
   /// will be executed once the scope is exited.
   class RunCleanupsScope {
     EHScopeStack::stable_iterator CleanupStackDepth;
-    size_t LifetimeExtendedCleanupStackSize;
     bool OldDidCallStackSave;
   protected:
     bool PerformCleanup;
@@ -468,8 +438,6 @@ public:
       : PerformCleanup(true), CGF(CGF)
     {
       CleanupStackDepth = CGF.EHStack.stable_begin();
-      LifetimeExtendedCleanupStackSize =
-          CGF.LifetimeExtendedCleanupStack.size();
       OldDidCallStackSave = CGF.DidCallStackSave;
       CGF.DidCallStackSave = false;
     }
@@ -479,8 +447,7 @@ public:
     ~RunCleanupsScope() {
       if (PerformCleanup) {
         CGF.DidCallStackSave = OldDidCallStackSave;
-        CGF.PopCleanupBlocks(CleanupStackDepth,
-                             LifetimeExtendedCleanupStackSize);
+        CGF.PopCleanupBlocks(CleanupStackDepth);
       }
     }
 
@@ -494,8 +461,7 @@ public:
     void ForceCleanup() {
       assert(PerformCleanup && "Already forced cleanup");
       CGF.DidCallStackSave = OldDidCallStackSave;
-      CGF.PopCleanupBlocks(CleanupStackDepth,
-                           LifetimeExtendedCleanupStackSize);
+      CGF.PopCleanupBlocks(CleanupStackDepth);
       PerformCleanup = false;
     }
   };
@@ -547,16 +513,10 @@ public:
   };
 
 
-  /// \brief Takes the old cleanup stack size and emits the cleanup blocks
-  /// that have been added.
+  /// PopCleanupBlocks - Takes the old cleanup stack size and emits
+  /// the cleanup blocks that have been added.
   void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize);
 
-  /// \brief Takes the old cleanup stack size and emits the cleanup blocks
-  /// that have been added, then adds all lifetime-extended cleanups from
-  /// the given position to the stack.
-  void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
-                        size_t OldLifetimeExtendedStackSize);
-
   void ResolveBranchFixups(llvm::BasicBlock *Target);
 
   /// The given basic block lies in the current EH scope, but may be a
@@ -1028,9 +988,6 @@ public:
                      llvm::Value *addr, QualType type);
   void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
                    Destroyer *destroyer, bool useEHCleanupForArray);
-  void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
-                                   QualType type, Destroyer *destroyer,
-                                   bool useEHCleanupForArray);
   void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
                    bool useEHCleanupForArray);
   llvm::Function *generateDestroyHelper(llvm::Constant *addr,
index 847b935505a0ce0815fe36490f6cccc62531825f..7d73e0890ec9bdd668c3f7982148f405d3bf23e7 100644 (file)
@@ -5214,9 +5214,6 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
   Init = const_cast<Expr *>(
       Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
 
-  if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
-    Init = BTE->getSubExpr();
-
   if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
     if (ILE->initializesStdInitializerList() || ILE->getType()->isArrayType()) {
       // FIXME: If this is an InitListExpr which creates a std::initializer_list
index 04ca0890d5e3922b935aec70b2148935156bdd73..298770336212deb9e14ff071858a6e546a00b6af 100644 (file)
@@ -35,7 +35,7 @@ int e = V<int>::m;
 
 // CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global
 // CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0
-// CHECK: @_ZGRZ8tls_dtorvE1u = private thread_local global
+// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global
 
 // CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0
 
index f8f7f9fba1ea2fb7ef84a51d80dc1d83230a31a1..61b517abeb26baa858c0bbfa2a3abe36ee675110 100644 (file)
@@ -584,9 +584,11 @@ namespace BindToSubobject {
   // CHECK: call void @_ZN15BindToSubobject1fEv()
   // CHECK: call void @_ZN15BindToSubobject1gEv()
   // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE)
-  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)
+  // FIXME: This is wrong. We should emit the call to __cxa_atexit prior to
+  // calling h(), in case h() throws.
   // CHECK: call {{.*}} @_ZN15BindToSubobject1hE
   // CHECK: getelementptr
+  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)
   // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8
   int &&c = (f(), (g(), A().*h()));
 
@@ -596,9 +598,9 @@ namespace BindToSubobject {
   };
 
   // CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE)
-  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)
   // CHECK: call {{.*}} @_ZN15BindToSubobject1hE
   // CHECK: getelementptr {{.*}} getelementptr
+  // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)
   // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8
   int &&d = (B().a).*h();
 }
@@ -609,7 +611,7 @@ namespace Bitfield {
   // Do not lifetime extend the S() temporary here.
   // CHECK: alloca
   // CHECK: call {{.*}}memset
-  // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE
+  // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE, align 4
   // CHECK: call void @_ZN8Bitfield1SD1
   // CHECK: store i32* @_ZGRN8Bitfield1rE, i32** @_ZN8Bitfield1rE, align 8
   int &&r = S().a;
@@ -624,91 +626,15 @@ namespace Vector {
   };
   // CHECK: alloca
   // CHECK: extractelement
-  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE
+  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE,
   // CHECK: store i32* @_ZGRN6Vector1rE, i32** @_ZN6Vector1rE,
   int &&r = S().v[1];
 
   // CHECK: alloca
   // CHECK: extractelement
-  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE
+  // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE,
   // CHECK: store i32* @_ZGRN6Vector1sE, i32** @_ZN6Vector1sE,
   int &&s = S().w[1];
   // FIXME PR16204: The following code leads to an assertion in Sema.
   //int &&s = S().w.y;
 }
-
-namespace MultipleExtension {
-  struct A { A(); ~A(); };
-  struct B { B(); ~B(); };
-  struct C { C(); ~C(); };
-  struct D { D(); ~D(); int n; C c; };
-  struct E { const A &a; B b; const C &c; ~E(); };
-
-  E &&e1 = { A(), B(), D().c };
-
-  // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e1E.*]])
-  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]
-  // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], i32 0, i32 0)
-
-  // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1))
-
-  // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]])
-  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]
-  // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 2)
-  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[TEMPE]]
-  // CHECK: store {{.*}} @[[TEMPE]], %"struct.MultipleExtension::E"** @_ZN17MultipleExtension2e1E, align 8
-
-  E e2 = { A(), B(), D().c };
-
-  // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e2E.*]])
-  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]]
-  // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[E:_ZN17MultipleExtension2e2E]], i32 0, i32 0)
-
-  // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1))
-
-  // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]])
-  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]]
-  // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 2)
-  // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[E]]
-
-
-  void g();
-  // CHECK: define void @[[NS:_ZN17MultipleExtension]]1fEv(
-  void f() {
-    E &&e1 = { A(), B(), D().c };
-    // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0
-    // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]])
-    // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]]
-    // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1
-    // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]])
-    // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2
-    // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]])
-    // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1
-    // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]]
-    // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]]
-
-    g();
-    // CHECK: call void @[[NS]]1gEv()
-
-    E e2 = { A(), B(), D().c };
-    // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0
-    // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]])
-    // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]]
-    // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1
-    // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]])
-    // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2
-    // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]])
-    // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1
-    // CHECK: store {{.*}} %[[TEMPD2_C]], {{.*}}* %[[TEMPE2_C]]
-
-    g();
-    // CHECK: call void @[[NS]]1gEv()
-
-    // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[E2]])
-    // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD2]])
-    // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA2]])
-    // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[TEMPE1]])
-    // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD1]])
-    // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA1]])
-  }
-}