diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-11-24 17:07:59 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-11-24 17:07:59 +0000 |
commit | d3d5301c44138b92bf01286183f5bf310cdd37cf (patch) | |
tree | 5e426515a870ee432cb704304b79058d3b042a24 | |
parent | c102297fb2857ef1af191a8e85e842cc3ac3239e (diff) |
Explicitly store the condition variable within switch statements, and
make sure that this variable is destroyed when we exit the switch
statement.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89776 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Stmt.h | 23 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 5 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 13 | ||||
-rw-r--r-- | test/CodeGenCXX/condition.cpp | 24 |
7 files changed, 73 insertions, 6 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 609c7cdb1d..103b373017 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -672,6 +672,7 @@ public: class SwitchStmt : public Stmt { enum { COND, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; + VarDecl *Var; // This points to a linked list of case and default statements. SwitchCase *FirstCase; SourceLocation SwitchLoc; @@ -680,14 +681,28 @@ protected: virtual void DoDestroy(ASTContext &Ctx); public: - SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) { - SubExprs[COND] = reinterpret_cast<Stmt*>(cond); - SubExprs[BODY] = NULL; - } + SwitchStmt(VarDecl *Var, Expr *cond) + : Stmt(SwitchStmtClass), Var(Var), FirstCase(0) + { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = NULL; + } /// \brief Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "switch" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// switch (int x = foo()) { + /// case 0: break; + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} const Stmt *getBody() const { return SubExprs[BODY]; } const SwitchCase *getSwitchCaseList() const { return FirstCase; } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 51b7cf8a11..34e364967d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -692,6 +692,11 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) { } void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { + CleanupScope ConditionScope(*this); + + if (S.getConditionVariable()) + EmitLocalBlockVarDecl(*S.getConditionVariable()); + llvm::Value *CondV = EmitScalarExpr(S.getCond()); // Handle nested switch statements. diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index fb95584b2a..1e9f72bd6e 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -188,6 +188,7 @@ unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) { unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2])); S->setBody(StmtStack.back()); S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 8de094a296..064c258edc 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -181,6 +181,7 @@ void PCHStmtWriter::VisitIfStmt(IfStmt *S) { void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); Writer.WriteSubStmt(S->getCond()); Writer.WriteSubStmt(S->getBody()); Writer.AddSourceLocation(S->getSwitchLoc(), Record); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index cecc9b32c1..6ff3d638fe 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -280,7 +280,17 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Action::OwningStmtResult Sema::ActOnStartOfSwitchStmt(ExprArg cond) { - SwitchStmt *SS = new (Context) SwitchStmt(cond.takeAs<Expr>()); + Expr *condExpr = cond.takeAs<Expr>(); + VarDecl *ConditionVar = 0; + if (CXXConditionDeclExpr *Cond = dyn_cast<CXXConditionDeclExpr>(condExpr)) { + ConditionVar = Cond->getVarDecl(); + condExpr = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, + ConditionVar->getLocation(), + ConditionVar->getType().getNonReferenceType()); + // FIXME: Leaks the old condExpr + } + + SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, condExpr); getSwitchStack().push_back(SS); return Owned(SS); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index d226c1eb5c..a7a9cfaca8 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3126,7 +3126,18 @@ template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { // Transform the condition. - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); + OwningExprResult Cond(SemaRef); + VarDecl *ConditionVar = 0; + if (S->getConditionVariable()) { + ConditionVar + = cast_or_null<VarDecl>( + getDerived().TransformDefinition(S->getConditionVariable())); + if (!ConditionVar) + return SemaRef.StmtError(); + + Cond = getSema().CheckConditionVariable(ConditionVar); + } else + Cond = getDerived().TransformExpr(S->getCond()); if (Cond.isInvalid()) return SemaRef.StmtError(); diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp index f8a55d8716..f3c8a9b769 100644 --- a/test/CodeGenCXX/condition.cpp +++ b/test/CodeGenCXX/condition.cpp @@ -45,3 +45,27 @@ void if_destruct(int z) { // CHECK: if.end // CHECK: call void @_ZN1XD1Ev } + +struct ConvertibleToInt { + ConvertibleToInt(); + ~ConvertibleToInt(); + operator int(); +}; + +void switch_destruct(int z) { + // CHECK: call void @_ZN16ConvertibleToIntC1Ev + switch (ConvertibleToInt conv = ConvertibleToInt()) { + case 0: + break; + + default: + // CHECK: sw.default: + // CHECK: store i32 19 + z = 19; + break; + } + // CHECK: sw.epilog: + // CHECK: call void @_ZN16ConvertibleToIntD1Ev + // CHECK: store i32 20 + z = 20; +} |