]> granicus.if.org Git - clang/commitdiff
Explicitly store the condition variable within switch statements, and
authorDouglas Gregor <dgregor@apple.com>
Tue, 24 Nov 2009 17:07:59 +0000 (17:07 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 24 Nov 2009 17:07:59 +0000 (17:07 +0000)
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

include/clang/AST/Stmt.h
lib/CodeGen/CGStmt.cpp
lib/Frontend/PCHReaderStmt.cpp
lib/Frontend/PCHWriterStmt.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
test/CodeGenCXX/condition.cpp

index 609c7cdb1dd82d15f10c5d88f74f161cd2951c26..103b373017002ec29639c484a2ac41cb487c25c0 100644 (file)
@@ -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; }
index 51b7cf8a112d3f329cc331f715177a71c724d733..34e364967d6e722df8dc9c27fade909f26635ca1 100644 (file)
@@ -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.
index fb95584b2a8a7bf1c783e0ebb56bf86edf737b13..1e9f72bd6ed49661bd3f77148909f785a6c7f887 100644 (file)
@@ -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++]));
index 8de094a29673361b12bd51b716a1bb8bda8386b9..064c258edc8ddae825c2611833d42bc25429d3bc 100644 (file)
@@ -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);
index cecc9b32c10dd7e90aae0276d1e760c93f066dcf..6ff3d638fe9d94a7f4ef711e71a95dcd529c9d93 100644 (file)
@@ -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);
 }
index d226c1eb5c251162317f2b3f1127536c8a5fa57f..a7a9cfaca8491fac9ed3e621236c7012856365a1 100644 (file)
@@ -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();
 
index f8a55d8716ae3de45984b7f80bd364f4c32d559d..f3c8a9b7695b58061df35e4d1adf36cf27eeffd2 100644 (file)
@@ -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;
+}