Hi doug.gregor, rjmccall,

* Handle C/C++ statements associated with cleanups, which is parallel
      to ExprWithCleanups.
    
 * Currently, this is only used for AsmStmt's. Previously, an AsmStmt
    with cleanups is wrapped by a CompoundStmt, a StmtExpr, and then
    an ExprWithCleanups. This statement cleanups its AST representation.
    Another potential user is for statements with copy captures.

http://llvm-reviews.chandlerc.com/D672

Files:
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTDumper.cpp
  lib/AST/Stmt.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CGStmt.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/asm.cpp
  test/Misc/ast-dump-stmt.m
  tools/libclang/CXCursor.cpp
  tools/libclang/RecursiveASTVisitor.h
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1911,7 +1911,7 @@
 DEF_TRAVERSE_STMT(ReturnStmt, { })
 DEF_TRAVERSE_STMT(SwitchStmt, { })
 DEF_TRAVERSE_STMT(WhileStmt, { })
-
+DEF_TRAVERSE_STMT(StmtWithCleanups, { })
 
 DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
     TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -31,6 +31,7 @@
 namespace clang {
   class ASTContext;
   class Attr;
+  class BlockDecl;
   class Decl;
   class Expr;
   class IdentifierInfo;
@@ -134,6 +135,13 @@
     unsigned NumStmts : 32 - NumStmtBits;
   };
 
+  class StmtWithCleanupsBitfields {
+    friend class StmtWithCleanups;
+    unsigned : NumStmtBits;
+
+    unsigned NumObjects : 32 - NumStmtBits;
+  };
+
   class ExprBitfields {
     friend class Expr;
     friend class DeclRefExpr; // computeDependence
@@ -292,6 +300,7 @@
 
     StmtBitfields StmtBits;
     CompoundStmtBitfields CompoundStmtBits;
+    StmtWithCleanupsBitfields StmtWithCleanupsBits;
     ExprBitfields ExprBits;
     CharacterLiteralBitfields CharacterLiteralBits;
     FloatingLiteralBitfields FloatingLiteralBits;
@@ -1882,6 +1891,67 @@
   }
 };
 
+/// \brief Represents a statement which introduces cleanups to be run
+/// at the end of the statement.
+class StmtWithCleanups : public Stmt {
+public:
+  /// \brief The type of objects that are kept in the cleanup.
+  typedef BlockDecl *CleanupObject;
+
+private:
+  /// \brief The statement with cleanups associated.
+  Stmt *SubStmt;
+
+  StmtWithCleanups(EmptyShell, unsigned NumObjects);
+
+  StmtWithCleanups(Stmt *SubStmt, ArrayRef<CleanupObject> Objects);
+
+  CleanupObject *getObjectsBuffer() {
+    return reinterpret_cast<CleanupObject*>(this + 1);
+  }
+
+  const CleanupObject *getObjectsBuffer() const {
+    return reinterpret_cast<const CleanupObject*>(this + 1);
+  }
+
+  friend class ASTStmtReader;
+
+public:
+  static StmtWithCleanups *Create(ASTContext &C, Stmt *SubStmt,
+                                  ArrayRef<CleanupObject> Objects);
+
+  static StmtWithCleanups *CreateDeserialized(ASTContext &C, EmptyShell Empty,
+                                              unsigned NumObjects);
+
+  ArrayRef<CleanupObject> getObjects() const {
+    return ArrayRef<CleanupObject>(getObjectsBuffer(), getNumObjects());
+  }
+
+  unsigned getNumObjects() const { return StmtWithCleanupsBits.NumObjects; }
+
+  CleanupObject getObject(unsigned i) const {
+    assert(i < getNumObjects() && "Index out of range");
+    return getObjects()[i];
+  }
+
+  Stmt *getSubStmt() { return SubStmt; }
+  const Stmt *getSubStmt() const { return SubStmt; }
+  void setSubStmt(Stmt *S) { SubStmt = S; }
+
+  SourceLocation getLocStart() const LLVM_READONLY {
+    return SubStmt->getLocStart();
+  }
+  SourceLocation getLocEnd() const LLVM_READONLY {
+    return SubStmt->getLocEnd();
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == StmtWithCleanupsClass;
+  }
+
+  child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
+};
+
 }  // end namespace clang
 
 #endif
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -27,6 +27,7 @@
 def SwitchCase : Stmt<1>;
 def CaseStmt : DStmt<SwitchCase>;
 def DefaultStmt : DStmt<SwitchCase>;
+def StmtWithCleanups : Stmt;
 
 // Asm statements
 def AsmStmt : Stmt<1>;
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1105,6 +1105,8 @@
       STMT_GCCASM,
       /// \brief A MS-style AsmStmt record.
       STMT_MSASM,
+      /// \brief A StmtWithCleanups record.
+      STMT_STMT_WITH_CLEANUPS,
       /// \brief A PredefinedExpr record.
       EXPR_PREDEFINED,
       /// \brief A DeclRefExpr record.
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -244,6 +244,7 @@
     void VisitAttributedStmt(const AttributedStmt *Node);
     void VisitLabelStmt(const LabelStmt *Node);
     void VisitGotoStmt(const GotoStmt *Node);
+    void VisitStmtWithCleanups(const StmtWithCleanups *Node);
 
     // Exprs
     void VisitExpr(const Expr *Node);
@@ -1385,6 +1386,12 @@
   dumpPointer(Node->getLabel());
 }
 
+void ASTDumper::VisitStmtWithCleanups(const StmtWithCleanups *Node) {
+  VisitStmt(Node);
+  for (unsigned I = 0, E = Node->getNumObjects(); I != E; ++I)
+    dumpDeclRef(Node->getObject(I), "cleanup");
+}
+
 //===----------------------------------------------------------------------===//
 //  Expr dumping methods.
 //===----------------------------------------------------------------------===//
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -1023,3 +1023,32 @@
                                        Stmt *Block) {
   return new(C)SEHFinallyStmt(Loc,Block);
 }
+
+StmtWithCleanups::StmtWithCleanups(Stmt *SubStmt,
+                                   ArrayRef<CleanupObject> Objects)
+  : Stmt(StmtWithCleanupsClass), SubStmt(SubStmt) {
+  StmtWithCleanupsBits.NumObjects = Objects.size();
+  for (unsigned I = 0, E = Objects.size(); I != E; ++I)
+    getObjectsBuffer()[I] = Objects[I];
+}
+
+StmtWithCleanups::StmtWithCleanups(EmptyShell Empty, unsigned NumObjects)
+  : Stmt(StmtWithCleanupsClass, Empty), SubStmt(0) {
+  StmtWithCleanupsBits.NumObjects = NumObjects;
+}
+
+StmtWithCleanups *StmtWithCleanups::Create(ASTContext &C, Stmt *SubStmt,
+                                           ArrayRef<CleanupObject> Objects) {
+  size_t Size = sizeof(StmtWithCleanups) +
+                Objects.size() * sizeof(CleanupObject);
+  void *Buffer = C.Allocate(Size, llvm::alignOf<StmtWithCleanups>());
+  return new (Buffer) StmtWithCleanups(SubStmt, Objects);
+}
+
+StmtWithCleanups *StmtWithCleanups::CreateDeserialized(ASTContext &C,
+                                                       EmptyShell Empty,
+                                                       unsigned NumObjects) {
+  size_t Size = sizeof(StmtWithCleanups) + NumObjects * sizeof(CleanupObject);
+  void *Buffer = C.Allocate(Size, llvm::alignOf<StmtWithCleanups>());
+  return new (Buffer) StmtWithCleanups(Empty, NumObjects);
+}
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -575,6 +575,10 @@
   OS << "\n";
 }
 
+void StmtPrinter::VisitStmtWithCleanups(StmtWithCleanups *Node) {
+  PrintStmt(Node->getSubStmt());
+}
+
 //===----------------------------------------------------------------------===//
 //  Expr printing methods.
 //===----------------------------------------------------------------------===//
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -248,6 +248,10 @@
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitStmtWithCleanups(const StmtWithCleanups *S) {
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitExpr(const Expr *S) {
   VisitStmt(S);
 }
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -643,6 +643,15 @@
   }
 }
 
+void CodeGenFunction::enterNonTrivialFullStatement(const StmtWithCleanups *S) {
+  assert(S->getNumObjects() != 0);
+  ArrayRef<StmtWithCleanups::CleanupObject> Cleanups = S->getObjects();
+  for (ArrayRef<StmtWithCleanups::CleanupObject>::iterator
+         I = Cleanups.begin(), E = Cleanups.end(); I != E; ++I) {
+    enterBlockScope(*this, *I);
+  }
+}
+
 /// Find the layout for the given block in a linked list and remove it.
 static CGBlockInfo *findAndRemoveBlockInfo(CGBlockInfo **head,
                                            const BlockDecl *block) {
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -134,7 +134,9 @@
   case Stmt::SwitchStmtClass:   EmitSwitchStmt(cast<SwitchStmt>(*S));     break;
   case Stmt::GCCAsmStmtClass:   // Intentional fall-through.
   case Stmt::MSAsmStmtClass:    EmitAsmStmt(cast<AsmStmt>(*S));           break;
-
+  case Stmt::StmtWithCleanupsClass:
+    EmitStmtWithCleanups(cast<StmtWithCleanups>(*S));
+    break;
   case Stmt::ObjCAtTryStmtClass:
     EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
     break;
@@ -1735,3 +1737,9 @@
     EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
   }
 }
+
+void CodeGenFunction::EmitStmtWithCleanups(const StmtWithCleanups &S) {
+  enterFullStatement(&S);
+  RunCleanupsScope Scope(*this);
+  EmitStmt(S.getSubStmt());
+}
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -2133,6 +2133,7 @@
   void EmitCaseStmt(const CaseStmt &S);
   void EmitCaseStmtRange(const CaseStmt &S);
   void EmitAsmStmt(const AsmStmt &S);
+  void EmitStmtWithCleanups(const StmtWithCleanups &S);
 
   void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
   void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
@@ -2648,8 +2649,16 @@
     if (E->getNumObjects() == 0) return;
     enterNonTrivialFullExpression(E);
   }
+
+  void enterFullStatement(const StmtWithCleanups *S) {
+    if (S->getNumObjects() == 0) return;
+    enterNonTrivialFullStatement(S);
+  }
+
   void enterNonTrivialFullExpression(const ExprWithCleanups *E);
 
+  void enterNonTrivialFullStatement(const StmtWithCleanups *S);
+
   void EmitCXXThrowExpr(const CXXThrowExpr *E);
 
   void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest);
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -4866,19 +4866,20 @@
 
   CleanupVarDeclMarking();
 
+  unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects;
+  assert(ExprCleanupObjects.size() >= FirstCleanup);
+  assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup);
   if (!ExprNeedsCleanups)
     return SubStmt;
 
-  // FIXME: In order to attach the temporaries, wrap the statement into
-  // a StmtExpr; currently this is only used for asm statements.
-  // This is hacky, either create a new CXXStmtWithTemporaries statement or
-  // a new AsmStmtWithTemporaries.
-  CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, SubStmt,
-                                                      SourceLocation(),
-                                                      SourceLocation());
-  Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
-                                   SourceLocation());
-  return MaybeCreateExprWithCleanups(E);
+  ArrayRef<StmtWithCleanups::CleanupObject> Cleanups
+    = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
+                         ExprCleanupObjects.size() - FirstCleanup);
+
+  Stmt *S = StmtWithCleanups::Create(Context, SubStmt, Cleanups);
+  DiscardCleanupsInEvaluationContext();
+
+  return S;
 }
 
 /// Process the expression contained within a decltype. For such expressions,
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -5637,6 +5637,14 @@
 
 template<typename Derived>
 StmtResult
+TreeTransform<Derived>::TransformStmtWithCleanups(StmtWithCleanups *S) {
+  // Since StmtWithCleanups nodes are implicitly generated, just return
+  // the transformed sub-statement.
+  return getDerived().TransformStmt(S->getSubStmt());
+}
+
+template<typename Derived>
+StmtResult
 TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
   // Transform the body of the @try.
   StmtResult TryBody = getDerived().TransformStmt(S->getTryBody());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -324,6 +324,17 @@
   VisitStmt(S);
 }
 
+void ASTStmtReader::VisitStmtWithCleanups(StmtWithCleanups *S) {
+  VisitStmt(S);
+
+  unsigned NumObjects = Record[Idx++];
+  assert(NumObjects == S->getNumObjects());
+  for (unsigned I = 0; I != NumObjects; ++I)
+    S->getObjectsBuffer()[I] = ReadDeclAs<BlockDecl>(Record, Idx);
+
+  S->setSubStmt(Reader.ReadSubStmt());
+}
+
 void ASTStmtReader::VisitExpr(Expr *E) {
   VisitStmt(E);
   E->setType(Reader.readType(F, Record, Idx));
@@ -1715,6 +1726,11 @@
       S = new (Context) MSAsmStmt(Empty);
       break;
 
+    case STMT_STMT_WITH_CLEANUPS:
+      S = StmtWithCleanups::CreateDeserialized(Context, Empty,
+                                          Record[ASTStmtReader::NumStmtFields]);
+      break;
+
     case EXPR_PREDEFINED:
       S = new (Context) PredefinedExpr(Empty);
       break;
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -255,6 +255,16 @@
   Code = serialization::STMT_MSASM;
 }
 
+void ASTStmtWriter::VisitStmtWithCleanups(StmtWithCleanups *S) {
+  VisitStmt(S);
+  Record.push_back(S->getNumObjects());
+  for (unsigned I = 0, E = S->getNumObjects(); I != E; ++I)
+    Writer.AddDeclRef(S->getObject(I), Record);
+
+  Writer.AddStmt(S->getSubStmt());
+  Code = serialization::STMT_STMT_WITH_CLEANUPS;
+}
+
 void ASTStmtWriter::VisitExpr(Expr *E) {
   VisitStmt(E);
   Writer.AddTypeRef(E->getType(), Record);
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -653,6 +653,7 @@
     case Stmt::NullStmtClass:
     case Stmt::SwitchStmtClass:
     case Stmt::WhileStmtClass:
+    case Stmt::StmtWithCleanupsClass:
     case Expr::MSDependentExistsStmtClass:
       llvm_unreachable("Stmt should not be in analyzer evaluation loop");
 
Index: test/CodeGenCXX/asm.cpp
===================================================================
--- test/CodeGenCXX/asm.cpp
+++ test/CodeGenCXX/asm.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -std=c++11 -fexceptions %s -o - | FileCheck %s
 
 struct A
 {
@@ -8,7 +8,41 @@
 
 void bar(A &a)
 {
+    // CHECK: define void @_Z3barR1A
+    // CHECK: invoke i32 @_Z3foo1A
+    //
+    // Normal branch:
     // CHECK: call void asm
+    // CHECK-NEXT: call void @_ZN1AD1Ev
+    // CHECK-NEXT: ret
+    //
+    // Exception branch:
+    // CHECK: call void @_ZN1AD1Ev
     asm("" : : "r"(foo(a)) ); // rdar://8540491
+}
+
+void bar2(A &a)
+{
+    // CHECK: define void @_Z4bar2R1A
+    // CHECK: invoke i32 @_Z3foo1A
+    //
+    // Normal branch:
+    // CHECK: call void asm
+    // CHECK-NEXT: call void @_ZN1AD1Ev
+    // CHECK: invoke i32 @_Z3foo1A
+    //
+    // CHECK: call void asm
+    // CHECK-NEXT: call void @_ZN1AD1Ev
+    // CHECK-NEXT: ret
+    //
+    // Exception branch:
+    // destructor calls should be in two different landingpad blocks.
+    //
+    // CHECK: landingpad
+    // CHECK: call void @_ZN1AD1Ev
+    //
+    // CHECK: landingpad
     // CHECK: call void @_ZN1AD1Ev
+    asm("" : : "r"(foo(a)) );
+    asm("" : : "r"(foo(a)) );
 }
Index: test/Misc/ast-dump-stmt.m
===================================================================
--- test/Misc/ast-dump-stmt.m
+++ test/Misc/ast-dump-stmt.m
@@ -15,6 +15,15 @@
 // CHECK-NEXT:   cleanup Block
 // CHECK-NEXT:   BlockExpr
 
+void TestStmtWithCleanups(int x) {
+  asm("" : : "r"(^{ return x; }()));
+}
+
+// CHECK:      FunctionDecl{{.*}}TestStmtWithCleanups
+// CHECK:      StmtWithCleanups
+// CHECK-NEXT:   cleanup Block
+// CHECK-NEXT:   GCCAsmStmt
+
 @interface A
 @end
 
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -482,6 +482,7 @@
   }
       
   case Stmt::MSDependentExistsStmtClass:
+  case Stmt::StmtWithCleanupsClass:
     K = CXCursor_UnexposedStmt;
     break;
   }
Index: tools/libclang/RecursiveASTVisitor.h
===================================================================
--- tools/libclang/RecursiveASTVisitor.h
+++ tools/libclang/RecursiveASTVisitor.h
@@ -1835,7 +1835,7 @@
 DEF_TRAVERSE_STMT(ReturnStmt, { })
 DEF_TRAVERSE_STMT(SwitchStmt, { })
 DEF_TRAVERSE_STMT(WhileStmt, { })
-
+DEF_TRAVERSE_STMT(StmtWithCleanups, { })
 
 DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
     TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to