Explicitly track the condition variable within an "if" statement,
rather than burying it in a CXXConditionDeclExpr (that occassionally
hides behind implicit conversions). Similar changes for
switch, while, and do-while will follow, then the removal of
CXXConditionDeclExpr. This commit is the canary.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89717 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 411f215..609c7cd 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -604,22 +604,36 @@
 class IfStmt : public Stmt {
   enum { COND, THEN, ELSE, END_EXPR };
   Stmt* SubExprs[END_EXPR];
+
+  /// \brief If non-NULL, the declaration in the "if" statement.
+  VarDecl *Var;
+  
   SourceLocation IfLoc;
   SourceLocation ElseLoc;
+  
 public:
-  IfStmt(SourceLocation IL, Expr *cond, Stmt *then,
+  IfStmt(SourceLocation IL, VarDecl *Var, Expr *cond, Stmt *then,
          SourceLocation EL = SourceLocation(), Stmt *elsev = 0)
-    : Stmt(IfStmtClass)  {
+    : Stmt(IfStmtClass), Var(Var), IfLoc(IL), ElseLoc(EL)  {
     SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
     SubExprs[THEN] = then;
     SubExprs[ELSE] = elsev;
-    IfLoc = IL;
-    ElseLoc = EL;
   }
 
   /// \brief Build an empty if/then/else statement
   explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
 
+  /// \brief Retrieve the variable declared in this "if" statement, if any.
+  ///
+  /// In the following example, "x" is the condition variable.
+  /// \code
+  /// if (int x = foo()) {
+  ///   printf("x is %d", x);
+  /// }
+  /// \endcode
+  VarDecl *getConditionVariable() const { return Var; }
+  void setConditionVariable(VarDecl *V) { Var = V; }
+  
   const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
   void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
   const Stmt *getThen() const { return SubExprs[THEN]; }
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index b6d7b39..1c3f357 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -294,6 +294,8 @@
 void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
   // C99 6.8.4.1: The first substatement is executed if the expression compares
   // unequal to 0.  The condition must be a scalar type.
+  if (S.getConditionVariable())
+    EmitDecl(*S.getConditionVariable());
 
   // If the condition constant folds and can be elided, try to avoid emitting
   // the condition and the dead arm of the if/else.
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 01af67d..fb95584 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -177,6 +177,7 @@
 
 unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
   VisitStmt(S);
+  S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
   S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
   S->setThen(StmtStack[StmtStack.size() - 2]);
   S->setElse(StmtStack[StmtStack.size() - 1]);
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 78a56db..8de094a 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -170,6 +170,7 @@
 
 void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
   VisitStmt(S);
+  Writer.AddDeclRef(S->getConditionVariable(), Record);
   Writer.WriteSubStmt(S->getCond());
   Writer.WriteSubStmt(S->getThen());
   Writer.WriteSubStmt(S->getElse());
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 9e20771..1df1ec6 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1879,7 +1879,8 @@
                                                       Declarator &D,
                                                       SourceLocation EqualLoc,
                                                       ExprArg AssignExprVal);
-
+  OwningExprResult CheckConditionVariable(VarDecl *ConditionVar);
+                                          
   /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
   /// pseudo-functions.
   virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 21ab093..f2b82aa 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1002,6 +1002,27 @@
   return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD));
 }
 
+/// \brief Check the use of the given variable as a C++ condition in an if,
+/// while, do-while, or switch statement.
+Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) {
+  QualType T = ConditionVar->getType();
+  
+  // C++ [stmt.select]p2:
+  //   The declarator shall not specify a function or an array.
+  if (T->isFunctionType())
+    return ExprError(Diag(ConditionVar->getLocation(), 
+                          diag::err_invalid_use_of_function_type)
+                       << ConditionVar->getSourceRange());
+  else if (T->isArrayType())
+    return ExprError(Diag(ConditionVar->getLocation(), 
+                          diag::err_invalid_use_of_array_type)
+                     << ConditionVar->getSourceRange());
+  
+  return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+                                   ConditionVar->getLocation(), 
+                                ConditionVar->getType().getNonReferenceType()));
+}
+
 /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
 bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
   // C++ 6.4p4:
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index ad3376b..cecc9b3 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -242,8 +242,17 @@
   OwningExprResult CondResult(CondVal.release());
 
   Expr *condExpr = CondResult.takeAs<Expr>();
-
   assert(condExpr && "ActOnIfStmt(): missing expression");
+  
+  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
+  }
+  
   if (CheckBooleanCondition(condExpr, IfLoc)) {
     CondResult = condExpr;
     return StmtError();
@@ -265,7 +274,7 @@
   DiagnoseUnusedExprResult(elseStmt);
 
   CondResult.release();
-  return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt,
+  return Owned(new (Context) IfStmt(IfLoc, ConditionVar, condExpr, thenStmt,
                                     ElseLoc, elseStmt));
 }
 
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ecac31a..d226c1e 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -3084,10 +3084,22 @@
 Sema::OwningStmtResult
 TreeTransform<Derived>::TransformIfStmt(IfStmt *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();
-
+  
   Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
 
   // Transform the "then" branch.