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