aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-11-24 17:07:59 +0000
committerDouglas Gregor <dgregor@apple.com>2009-11-24 17:07:59 +0000
commitd3d5301c44138b92bf01286183f5bf310cdd37cf (patch)
tree5e426515a870ee432cb704304b79058d3b042a24
parentc102297fb2857ef1af191a8e85e842cc3ac3239e (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.h23
-rw-r--r--lib/CodeGen/CGStmt.cpp5
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp1
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp1
-rw-r--r--lib/Sema/SemaStmt.cpp12
-rw-r--r--lib/Sema/TreeTransform.h13
-rw-r--r--test/CodeGenCXX/condition.cpp24
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;
+}