[cfe-commits] r89776 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Tue Nov 24 09:08:00 PST 2009


Author: dgregor
Date: Tue Nov 24 11:07:59 2009
New Revision: 89776

URL: http://llvm.org/viewvc/llvm-project?rev=89776&view=rev
Log:
Explicitly store the condition variable within switch statements, and
make sure that this variable is destroyed when we exit the switch
statement.

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

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Tue Nov 24 11:07:59 2009
@@ -672,6 +672,7 @@
 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 @@
   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; }

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Tue Nov 24 11:07:59 2009
@@ -692,6 +692,11 @@
 }
 
 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.

Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Tue Nov 24 11:07:59 2009
@@ -188,6 +188,7 @@
 
 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++]));

Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Tue Nov 24 11:07:59 2009
@@ -181,6 +181,7 @@
 
 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);

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Nov 24 11:07:59 2009
@@ -280,7 +280,17 @@
 
 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);
 }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Nov 24 11:07:59 2009
@@ -3126,7 +3126,18 @@
 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();
 

Modified: cfe/trunk/test/CodeGenCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/condition.cpp?rev=89776&r1=89775&r2=89776&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/condition.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/condition.cpp Tue Nov 24 11:07:59 2009
@@ -45,3 +45,27 @@
   // 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;
+}





More information about the cfe-commits mailing list