]> granicus.if.org Git - clang/commitdiff
There's no good reason to track temporaries in ExprWithCleanups,
authorJohn McCall <rjmccall@apple.com>
Thu, 10 Nov 2011 05:35:25 +0000 (05:35 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 10 Nov 2011 05:35:25 +0000 (05:35 +0000)
but it is sometimes useful to track blocks.  Do so.  Also
optimize the storage of these expressions.

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

14 files changed:
include/clang/AST/Decl.h
include/clang/AST/ExprCXX.h
include/clang/AST/Stmt.h
include/clang/Sema/Sema.h
lib/AST/Decl.cpp
lib/AST/ExprCXX.cpp
lib/AST/StmtDumper.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp

index 058e304149e7e13765236d2b516613406b45b2a6..2941982a2874dd1b45ca93130099724f1c3e4d16 100644 (file)
@@ -1285,12 +1285,6 @@ public:
     Init = reinterpret_cast<Stmt *>(defarg);
   }
 
-  unsigned getNumDefaultArgTemporaries() const;
-  CXXTemporary *getDefaultArgTemporary(unsigned i);
-  const CXXTemporary *getDefaultArgTemporary(unsigned i) const {
-    return const_cast<ParmVarDecl *>(this)->getDefaultArgTemporary(i);
-  }
-
   /// \brief Retrieve the source range that covers the entire default
   /// argument.
   SourceRange getDefaultArgRange() const;
index 3998ae8a4b99b33b287ad1a0cc7324e4a3aab217..4ea1ef4aa96a160a72642a226faad396d5c2a768 100644 (file)
@@ -2179,43 +2179,58 @@ public:
 /// Represents an expression --- generally a full-expression --- which
 /// introduces cleanups to be run at the end of the sub-expression's
 /// evaluation.  The most common source of expression-introduced
-/// cleanups is temporary objects in C++, but several other C++
-/// expressions can create cleanups.
+/// cleanups is temporary objects in C++, but several other kinds of
+/// expressions can create cleanups, including basically every
+/// call in ARC that returns an Objective-C pointer.
+///
+/// This expression also tracks whether the sub-expression contains a
+/// potentially-evaluated block literal.  The lifetime of a block
+/// literal is the extent of the enclosing scope.
 class ExprWithCleanups : public Expr {
+public:
+  /// The type of objects that are kept in the cleanup.
+  /// It's useful to remember the set of blocks;  we could also
+  /// remember the set of temporaries, but there's currently
+  /// no need.
+  typedef BlockDecl *CleanupObject;
+
+private:
   Stmt *SubExpr;
 
-  CXXTemporary **Temps;
-  unsigned NumTemps;
+  ExprWithCleanups(EmptyShell, unsigned NumObjects);
+  ExprWithCleanups(Expr *SubExpr, ArrayRef<CleanupObject> Objects);
 
-  ExprWithCleanups(ASTContext &C, Expr *SubExpr,
-                   CXXTemporary **Temps, unsigned NumTemps);
+  CleanupObject *getObjectsBuffer() {
+    return reinterpret_cast<CleanupObject*>(this + 1);
+  }
+  const CleanupObject *getObjectsBuffer() const {
+    return reinterpret_cast<const CleanupObject*>(this + 1);
+  }
+  friend class ASTStmtReader;
 
 public:
-  ExprWithCleanups(EmptyShell Empty)
-    : Expr(ExprWithCleanupsClass, Empty),
-      SubExpr(0), Temps(0), NumTemps(0) {}
-
-  static ExprWithCleanups *Create(ASTContext &C, Expr *SubExpr,
-                                        CXXTemporary **Temps,
-                                        unsigned NumTemps);
+  static ExprWithCleanups *Create(ASTContext &C, EmptyShell empty,
+                                  unsigned numObjects);
 
-  unsigned getNumTemporaries() const { return NumTemps; }
-  void setNumTemporaries(ASTContext &C, unsigned N);
+  static ExprWithCleanups *Create(ASTContext &C, Expr *subexpr,
+                                  ArrayRef<CleanupObject> objects);
 
-  CXXTemporary *getTemporary(unsigned i) {
-    assert(i < NumTemps && "Index out of range");
-    return Temps[i];
-  }
-  const CXXTemporary *getTemporary(unsigned i) const {
-    return const_cast<ExprWithCleanups*>(this)->getTemporary(i);
+  ArrayRef<CleanupObject> getObjects() const {
+    return ArrayRef<CleanupObject>(getObjectsBuffer(), getNumObjects());
   }
-  void setTemporary(unsigned i, CXXTemporary *T) {
-    assert(i < NumTemps && "Index out of range");
-    Temps[i] = T;
+
+  unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; }
+
+  CleanupObject getObject(unsigned i) const {
+    assert(i < getNumObjects() && "Index out of range");
+    return getObjects()[i];
   }
 
   Expr *getSubExpr() { return cast<Expr>(SubExpr); }
   const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+
+  /// setSubExpr - As with any mutator of the AST, be very careful
+  /// when modifying an existing AST to preserve its invariants.
   void setSubExpr(Expr *E) { SubExpr = E; }
 
   SourceRange getSourceRange() const {
index 3dc8a41714ffad35b31e214c14117aee2c28639c..1a1dc6755068c988078839f3a8477e02a30c4d2b 100644 (file)
@@ -185,6 +185,15 @@ protected:
     unsigned NumPreArgs : 1;
   };
 
+  class ExprWithCleanupsBitfields {
+    friend class ExprWithCleanups;
+    friend class ASTStmtReader; // deserialization
+
+    unsigned : NumExprBits;
+
+    unsigned NumObjects : 32 - NumExprBits;
+  };
+
   class PseudoObjectExprBitfields {
     friend class PseudoObjectExpr;
     friend class ASTStmtReader; // deserialization
@@ -214,6 +223,7 @@ protected:
     DeclRefExprBitfields DeclRefExprBits;
     CastExprBitfields CastExprBits;
     CallExprBitfields CallExprBits;
+    ExprWithCleanupsBitfields ExprWithCleanupsBits;
     PseudoObjectExprBitfields PseudoObjectExprBits;
     ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
   };
index 4c87dd6d3c776ff555ce3a1ffd136d89fb152c33..27730f08f7b506f7091140a57503d623ded4cb80 100644 (file)
@@ -223,6 +223,11 @@ public:
   /// requires cleanups to be run at its conclusion.
   bool ExprNeedsCleanups;
 
+  /// ExprCleanupObjects - This is the stack of objects requiring
+  /// cleanup that are created by the current full expression.  The
+  /// element type here is ExprWithCleanups::Object.
+  SmallVector<BlockDecl*, 8> ExprCleanupObjects;
+
   /// \brief Stack containing information about each of the nested
   /// function, block, and method scopes that are currently active.
   ///
@@ -231,10 +236,6 @@ public:
   /// that's used to parse every top-level function.
   SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
 
-  /// ExprTemporaries - This is the stack of temporaries that are created by
-  /// the current full expression.
-  SmallVector<CXXTemporary*, 8> ExprTemporaries;
-
   typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
                      &ExternalSemaSource::ReadExtVectorDecls, 2, 2>
     ExtVectorDeclsType;
@@ -547,9 +548,9 @@ public:
     /// \brief Whether the enclosing context needed a cleanup.
     bool ParentNeedsCleanups;
 
-    /// \brief The number of temporaries that were active when we
-    /// entered this expression evaluation context.
-    unsigned NumTemporaries;
+    /// \brief The number of active cleanup objects when we entered
+    /// this expression evaluation context.
+    unsigned NumCleanupObjects;
 
     /// \brief The set of declarations referenced within a
     /// potentially potentially-evaluated context.
@@ -565,10 +566,10 @@ public:
     PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
 
     ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
-                                      unsigned NumTemporaries,
+                                      unsigned NumCleanupObjects,
                                       bool ParentNeedsCleanups)
       : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
-        NumTemporaries(NumTemporaries),
+        NumCleanupObjects(NumCleanupObjects),
         PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
 
     void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
index c766577ab0e3494e44edd205c64403384c7fbbfd..095491aafe8297ae3fc8849161ff06daf7bfed04 100644 (file)
@@ -1412,21 +1412,6 @@ Expr *ParmVarDecl::getDefaultArg() {
   return Arg;
 }
 
-unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
-  if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(getInit()))
-    return E->getNumTemporaries();
-
-  return 0;
-}
-
-CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
-  assert(getNumDefaultArgTemporaries() && 
-         "Default arguments does not have any temporaries!");
-
-  ExprWithCleanups *E = cast<ExprWithCleanups>(getInit());
-  return E->getTemporary(i);
-}
-
 SourceRange ParmVarDecl::getDefaultArgRange() const {
   if (const Expr *E = getInit())
     return E->getSourceRange();
index ad5ec8b8331a68ea0ad31d6582aa49c579815d78..99e9002a48293fa4d40457d6fbe3ef891937b27d 100644 (file)
@@ -695,35 +695,37 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
   }
 }
 
-ExprWithCleanups::ExprWithCleanups(ASTContext &C,
-                                   Expr *subexpr,
-                                   CXXTemporary **temps,
-                                   unsigned numtemps)
+ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
+                                   ArrayRef<CleanupObject> objects)
   : Expr(ExprWithCleanupsClass, subexpr->getType(),
          subexpr->getValueKind(), subexpr->getObjectKind(),
          subexpr->isTypeDependent(), subexpr->isValueDependent(),
          subexpr->isInstantiationDependent(),
          subexpr->containsUnexpandedParameterPack()),
-    SubExpr(subexpr), Temps(0), NumTemps(0) {
-  if (numtemps) {
-    setNumTemporaries(C, numtemps);
-    for (unsigned i = 0; i != numtemps; ++i)
-      Temps[i] = temps[i];
-  }
+    SubExpr(subexpr) {
+  ExprWithCleanupsBits.NumObjects = objects.size();
+  for (unsigned i = 0, e = objects.size(); i != e; ++i)
+    getObjectsBuffer()[i] = objects[i];
 }
 
-void ExprWithCleanups::setNumTemporaries(ASTContext &C, unsigned N) {
-  assert(Temps == 0 && "Cannot resize with this");
-  NumTemps = N;
-  Temps = new (C) CXXTemporary*[NumTemps];
+ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr,
+                                           ArrayRef<CleanupObject> objects) {
+  size_t size = sizeof(ExprWithCleanups)
+              + objects.size() * sizeof(CleanupObject);
+  void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
+  return new (buffer) ExprWithCleanups(subexpr, objects);
 }
 
+ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
+  : Expr(ExprWithCleanupsClass, empty) {
+  ExprWithCleanupsBits.NumObjects = numObjects;
+}
 
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C,
-                                           Expr *SubExpr,
-                                           CXXTemporary **Temps,
-                                           unsigned NumTemps) {
-  return new (C) ExprWithCleanups(C, SubExpr, Temps, NumTemps);
+ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
+                                           unsigned numObjects) {
+  size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject);
+  void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
+  return new (buffer) ExprWithCleanups(empty, numObjects);
 }
 
 CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
index 224834319984b7658de72fb82025f3741bedbd7b..bfbacf4f3062688f7f768a8b80b6eda8ee6c8d8f 100644 (file)
@@ -590,10 +590,12 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
 void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
   DumpExpr(Node);
   ++IndentLevel;
-  for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) {
+  for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
     OS << "\n";
     Indent();
-    DumpCXXTemporary(Node->getTemporary(i));
+    OS << "(cleanup ";
+    DumpDeclRef(Node->getObject(i));
+    OS << ")";
   }
   --IndentLevel;
 }
index 7d28026402a677484788915419de7cdc477447d4..d36b67aed85989d4567da734b578966bfee43554 100644 (file)
@@ -97,7 +97,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
     CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
     CurContext(0), OriginalLexicalContext(0),
     PackContext(0), MSStructPragmaOn(false), VisContext(0),
-    ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
+    ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
     GlobalNewDeleteDeclared(false), 
     ObjCShouldCallSuperDealloc(false),
index 6fbdb5163cf82a63eeeb0158b87cbfc9df6a128f..ad290fa5687ced707cefb955bd8a56561db34b79 100644 (file)
@@ -2676,6 +2676,9 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
   case Stmt::AddrLabelExprClass:
     return E; // address of label.
 
+  case Stmt::ExprWithCleanupsClass:
+    return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+
   // For casts, we need to handle conversions from arrays to
   // pointer values, and pointer-to-pointer conversions.
   case Stmt::ImplicitCastExprClass:
@@ -2752,6 +2755,9 @@ do {
     return NULL;
   }
 
+  case Stmt::ExprWithCleanupsClass:
+    return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+
   case Stmt::DeclRefExprClass: {
     // When we hit a DeclRefExpr we are looking at code that refers to a
     // variable's name. If it's not a reference variable we check if it has
index 8419cbebc4bc890e6d980662bf77d5f7acedc013..f59fa5bb47df27f29542f5a73669ae7a8c0d22e4 100644 (file)
@@ -7190,8 +7190,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
     // deletion in some later function.
     if (PP.getDiagnostics().hasErrorOccurred() ||
         PP.getDiagnostics().getSuppressAllDiagnostics()) {
-      ExprTemporaries.clear();
-      ExprNeedsCleanups = false;
+      DiscardCleanupsInEvaluationContext();
     } else if (!isa<FunctionTemplateDecl>(dcl)) {
       // Since the body is valid, issue any analysis-based warnings that are
       // enabled.
@@ -7202,7 +7201,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
         !CheckConstexprFunctionBody(FD, Body))
       FD->setInvalidDecl();
 
-    assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+    assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");
     assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
   }
   
@@ -7215,8 +7214,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   // been leftover. This ensures that these temporaries won't be picked up for
   // deletion in some later function.
   if (getDiagnostics().hasErrorOccurred()) {
-    ExprTemporaries.clear();
-    ExprNeedsCleanups = false;
+    DiscardCleanupsInEvaluationContext();
   }
 
   return dcl;
index 4ba294cb8a1d800bf9b361ba29143250bde8fae3..bc422db8b912139258abfb1bacbef97b556429b1 100644 (file)
@@ -3291,12 +3291,18 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
   // be properly destroyed.
   // FIXME: We should really be rebuilding the default argument with new
   // bound temporaries; see the comment in PR5810.
-  for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) {
-    CXXTemporary *Temporary = Param->getDefaultArgTemporary(i);
-    MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(), 
-                    const_cast<CXXDestructorDecl*>(Temporary->getDestructor()));
-    ExprTemporaries.push_back(Temporary);
+  // We don't need to do that with block decls, though, because
+  // blocks in default argument expression can never capture anything.
+  if (isa<ExprWithCleanups>(Param->getInit())) {
+    // Set the "needs cleanups" bit regardless of whether there are
+    // any explicit objects.
     ExprNeedsCleanups = true;
+
+    // Append all the objects to the cleanup list.  Right now, this
+    // should always be a no-op, because blocks in default argument
+    // expressions should never be able to capture anything.
+    assert(!cast<ExprWithCleanups>(Param->getInit())->getNumObjects() &&
+           "default argument expression has capturing blocks?");
   }
 
   // We already type-checked the argument, so we know it works. 
@@ -8828,6 +8834,13 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
   const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
   PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
 
+  // If the block isn't obviously global, i.e. it captures anything at
+  // all, mark this full-expression as needing a cleanup.
+  if (Result->getBlockDecl()->hasCaptures()) {
+    ExprCleanupObjects.push_back(Result->getBlockDecl());
+    ExprNeedsCleanups = true;
+  }
+
   return Owned(Result);
 }
 
@@ -9158,7 +9171,7 @@ void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
   ExprEvalContexts.push_back(
              ExpressionEvaluationContextRecord(NewContext,
-                                               ExprTemporaries.size(),
+                                               ExprCleanupObjects.size(),
                                                ExprNeedsCleanups));
   ExprNeedsCleanups = false;
 }
@@ -9195,8 +9208,8 @@ void Sema::PopExpressionEvaluationContext() {
   // the expression in that context: they aren't relevant because they
   // will never be constructed.
   if (Rec.Context == Unevaluated) {
-    ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
-                          ExprTemporaries.end());
+    ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
+                             ExprCleanupObjects.end());
     ExprNeedsCleanups = Rec.ParentNeedsCleanups;
 
   // Otherwise, merge the contexts together.
@@ -9209,9 +9222,9 @@ void Sema::PopExpressionEvaluationContext() {
 }
 
 void Sema::DiscardCleanupsInEvaluationContext() {
-  ExprTemporaries.erase(
-              ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
-              ExprTemporaries.end());
+  ExprCleanupObjects.erase(
+         ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects,
+         ExprCleanupObjects.end());
   ExprNeedsCleanups = false;
 }
 
@@ -9454,6 +9467,12 @@ namespace {
       Inherited::VisitMemberExpr(E);
     }
     
+    void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+      S.MarkDeclarationReferenced(E->getLocStart(),
+            const_cast<CXXDestructorDecl*>(E->getTemporary()->getDestructor()));
+      Visit(E->getSubExpr());
+    }
+    
     void VisitCXXNewExpr(CXXNewExpr *E) {
       if (E->getConstructor())
         S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
index 72494009658ac3cc01307ad81da3d887d3eca467..6c533c4ed4925eb385f2b315dace577997298e68 100644 (file)
@@ -4122,37 +4122,37 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
                           PDiag(diag::err_access_dtor_temp)
                             << E->getType());
 
-    ExprTemporaries.push_back(Temp);
+    // We need a cleanup, but we don't need to remember the temporary.
     ExprNeedsCleanups = true;
   }
   return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
 }
 
+ExprResult
+Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
+  if (SubExpr.isInvalid())
+    return ExprError();
+
+  return Owned(MaybeCreateExprWithCleanups(SubExpr.take()));
+}
+
 Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
   assert(SubExpr && "sub expression can't be null!");
 
-  unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
-  assert(ExprTemporaries.size() >= FirstTemporary);
-  assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary);
+  unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects;
+  assert(ExprCleanupObjects.size() >= FirstCleanup);
+  assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup);
   if (!ExprNeedsCleanups)
     return SubExpr;
 
-  Expr *E = ExprWithCleanups::Create(Context, SubExpr,
-                                     ExprTemporaries.begin() + FirstTemporary,
-                                     ExprTemporaries.size() - FirstTemporary);
-  ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
-                        ExprTemporaries.end());
-  ExprNeedsCleanups = false;
+  ArrayRef<ExprWithCleanups::CleanupObject> Cleanups
+    = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
+                         ExprCleanupObjects.size() - FirstCleanup);
 
-  return E;
-}
-
-ExprResult
-Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
-  if (SubExpr.isInvalid())
-    return ExprError();
+  Expr *E = ExprWithCleanups::Create(Context, SubExpr, Cleanups);
+  DiscardCleanupsInEvaluationContext();
 
-  return Owned(MaybeCreateExprWithCleanups(SubExpr.take()));
+  return E;
 }
 
 Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
index ff306b06c9ea49d456d269ced10572711dfe3ecf..cd51b06a5afe3e04a013362dc3306174fee74148 100644 (file)
@@ -1195,13 +1195,13 @@ void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
 
 void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
   VisitExpr(E);
-  unsigned NumTemps = Record[Idx++];
-  if (NumTemps) {
-    E->setNumTemporaries(Reader.getContext(), NumTemps);
-    for (unsigned i = 0; i != NumTemps; ++i)
-      E->setTemporary(i, Reader.ReadCXXTemporary(F, Record, Idx));
-  }
-  E->setSubExpr(Reader.ReadSubExpr());
+
+  unsigned NumObjects = Record[Idx++];
+  assert(NumObjects == E->getNumObjects());
+  for (unsigned i = 0; i != NumObjects; ++i)
+    E->getObjectsBuffer()[i] = ReadDeclAs<BlockDecl>(Record, Idx);
+
+  E->SubExpr = Reader.ReadSubExpr();
 }
 
 void
@@ -1974,7 +1974,8 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
       break;
         
     case EXPR_EXPR_WITH_CLEANUPS:
-      S = new (Context) ExprWithCleanups(Empty);
+      S = ExprWithCleanups::Create(Context, Empty,
+                                   Record[ASTStmtReader::NumExprFields]);
       break;
       
     case EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
index a8c76b51143f91fc04c1254494903f7e2c910bdc..e25a20b3532386c7884320576b22d6f933b4133f 100644 (file)
@@ -1180,9 +1180,9 @@ void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
 
 void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) {
   VisitExpr(E);
-  Record.push_back(E->getNumTemporaries());
-  for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i)
-    Writer.AddCXXTemporary(E->getTemporary(i), Record);
+  Record.push_back(E->getNumObjects());
+  for (unsigned i = 0, e = E->getNumObjects(); i != e; ++i)
+    Writer.AddDeclRef(E->getObject(i), Record);
   
   Writer.AddStmt(E->getSubExpr());
   Code = serialization::EXPR_EXPR_WITH_CLEANUPS;