AntonBikineev added a subscriber: cfe-commits.
AntonBikineev updated this revision to Diff 62254.

http://reviews.llvm.org/D21834

Files:
  include/clang/AST/Stmt.h
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/AST/ASTImporter.cpp
  lib/AST/Stmt.cpp
  lib/Analysis/BodyFarm.cpp
  lib/CodeGen/CGStmt.cpp
  lib/Parse/ParseStmt.cpp
  lib/Parse/ParseTentative.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaStmt.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp

Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -129,6 +129,7 @@
 void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
   VisitStmt(S);
   Record.push_back(S->isConstexpr());
+  Record.AddStmt(S->getInit());
   Record.AddDeclRef(S->getConditionVariable());
   Record.AddStmt(S->getCond());
   Record.AddStmt(S->getThen());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -185,6 +185,7 @@
 void ASTStmtReader::VisitIfStmt(IfStmt *S) {
   VisitStmt(S);
   S->setConstexpr(Record[Idx++]);
+  S->setInit(Reader.ReadSubStmt());
   S->setConditionVariable(Reader.getContext(),
                           ReadDeclAs<VarDecl>(Record, Idx));
   S->setCond(Reader.ReadSubExpr());
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1174,9 +1174,9 @@
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                           Sema::ConditionResult Cond, Stmt *Then,
+                           Sema::ConditionResult Cond, Stmt *Init, Stmt *Then,
                            SourceLocation ElseLoc, Stmt *Else) {
-    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Cond, Then, ElseLoc, Else);
+    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Cond, Init, Then, ElseLoc, Else);
   }
 
   /// \brief Start building a new switch statement.
@@ -6225,6 +6225,11 @@
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
+  // Transform the initialization statement
+  StmtResult Init = getDerived().TransformStmt(S->getInit());
+  if (Init.isInvalid())
+    return StmtError();
+
   // Transform the condition
   Sema::ConditionResult Cond = getDerived().TransformCondition(
       S->getIfLoc(), S->getConditionVariable(), S->getCond(),
@@ -6257,6 +6262,7 @@
   }
 
   if (!getDerived().AlwaysRebuild() &&
+      Init.get() == S->getInit() &&
       Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
       Then.get() == S->getThen() &&
       Else.get() == S->getElse())
@@ -6263,7 +6269,7 @@
     return S;
 
   return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond,
-                                    Then.get(), S->getElseLoc(), Else.get());
+                                    Init.get(), Then.get(), S->getElseLoc(), Else.get());
 }
 
 template<typename Derived>
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -505,7 +505,7 @@
 
 StmtResult
 Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, ConditionResult Cond,
-                  Stmt *thenStmt, SourceLocation ElseLoc,
+                  Stmt *initStmt, Stmt *thenStmt, SourceLocation ElseLoc,
                   Stmt *elseStmt) {
   if (Cond.isInvalid())
     Cond = ConditionResult(
@@ -524,11 +524,11 @@
     DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
                           diag::warn_empty_if_body);
 
-  return BuildIfStmt(IfLoc, IsConstexpr, Cond, thenStmt, ElseLoc, elseStmt);
+  return BuildIfStmt(IfLoc, IsConstexpr, Cond, initStmt, thenStmt, ElseLoc, elseStmt);
 }
 
 StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                             ConditionResult Cond, Stmt *thenStmt,
+                             ConditionResult Cond, Stmt *initStmt, Stmt *thenStmt,
                              SourceLocation ElseLoc, Stmt *elseStmt) {
   if (Cond.isInvalid())
     return StmtError();
@@ -539,7 +539,7 @@
   DiagnoseUnusedExprResult(thenStmt);
   DiagnoseUnusedExprResult(elseStmt);
 
-  return new (Context) IfStmt(Context, IfLoc, IsConstexpr, Cond.get().first,
+  return new (Context) IfStmt(Context, IfLoc, IsConstexpr, initStmt, Cond.get().first,
                               Cond.get().second, thenStmt, ElseLoc, elseStmt);
 }
 
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -3095,6 +3095,7 @@
 
   switch (CK) {
   case ConditionKind::Boolean:
+  case ConditionKind::IfWithInit:
     return CheckBooleanCondition(StmtLoc, Condition.get());
 
   case ConditionKind::ConstexprIf:
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -14385,6 +14385,7 @@
   ExprResult Cond;
   switch (CK) {
   case ConditionKind::Boolean:
+  case ConditionKind::IfWithInit:
     Cond = CheckBooleanCondition(Loc, SubExpr);
     break;
 
Index: lib/Parse/ParseTentative.cpp
===================================================================
--- lib/Parse/ParseTentative.cpp
+++ lib/Parse/ParseTentative.cpp
@@ -14,6 +14,7 @@
 
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
 #include "clang/Sema/ParsedTemplate.h"
 using namespace clang;
 
@@ -66,6 +67,20 @@
   }
 }
 
+/// isForInitDeclarationWithSemi - is the same as isForInitDeclaration
+/// but makes sure that there is a semicolon at the of the declaration
+/// (needed for C++1z 'if statement with init')
+bool Parser::isForInitDeclarationWithSemi() {
+  if (!isForInitDeclaration())
+    return false;
+
+  TentativeParsingAction PA(*this);
+  bool NotFound = SkipUntil(tok::r_paren, StopAtSemi);
+  PA.Revert();
+
+  return !NotFound;
+}
+
 /// isCXXSimpleDeclaration - C++-specialized function that disambiguates
 /// between a simple-declaration or an expression-statement.
 /// If during the disambiguation process a parsing error is encountered,
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -1054,10 +1054,26 @@
 /// errors in the condition.
 bool Parser::ParseParenExprOrCondition(Sema::ConditionResult &Cond,
                                        SourceLocation Loc,
-                                       Sema::ConditionKind CK) {
+                                       Sema::ConditionKind CK,
+                                       Stmt** Init) {
   BalancedDelimiterTracker T(*this, tok::l_paren);
   T.consumeOpen();
 
+  if (CK == Sema::ConditionKind::IfWithInit &&
+      isForInitDeclarationWithSemi()) {  // if (int X = 4;
+    // Parse declaration, which eats the ';'.
+    ParsedAttributesWithRange attrs(AttrFactory);
+    MaybeParseCXX11Attributes(attrs);
+
+    SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+    DeclGroupPtrTy DG = ParseSimpleDeclaration(
+      Declarator::ForContext, DeclEnd, attrs, false, nullptr);
+    StmtResult InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
+    if (Init) *Init = InitStmt.get();
+
+    ConsumeToken(); // Consume semi
+  }
+
   if (getLangOpts().CPlusPlus)
     Cond = ParseCXXCondition(Loc, CK);
   else {
@@ -1140,9 +1156,14 @@
 
   // Parse the condition.
   Sema::ConditionResult Cond;
+  Stmt* Init = nullptr;
   if (ParseParenExprOrCondition(Cond, IfLoc,
                                 IsConstexpr ? Sema::ConditionKind::ConstexprIf
-                                            : Sema::ConditionKind::Boolean))
+                                            : getLangOpts().CPlusPlus1z
+                                                   ? Sema::ConditionKind::IfWithInit
+                                                   : Sema::ConditionKind::Boolean,
+                                &Init))
+
     return StmtError();
 
   llvm::Optional<bool> ConstexprCondition;
@@ -1241,8 +1262,8 @@
   if (ElseStmt.isInvalid())
     ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
 
-  return Actions.ActOnIfStmt(IfLoc, IsConstexpr, Cond, ThenStmt.get(), ElseLoc,
-                             ElseStmt.get());
+  return Actions.ActOnIfStmt(IfLoc, IsConstexpr, Cond, Init,
+                             ThenStmt.get(), ElseLoc, ElseStmt.get());
 }
 
 /// ParseSwitchStatement
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -557,6 +557,9 @@
   // unequal to 0.  The condition must be a scalar type.
   LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
 
+  if (S.getInit())
+    EmitStmt(S.getInit());
+
   if (S.getConditionVariable())
     EmitAutoVarDecl(*S.getConditionVariable());
 
Index: lib/Analysis/BodyFarm.cpp
===================================================================
--- lib/Analysis/BodyFarm.cpp
+++ lib/Analysis/BodyFarm.cpp
@@ -239,7 +239,7 @@
                                            SourceLocation());
   
   // (5) Create the 'if' statement.
-  IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, UO, CS);
+  IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr, UO, CS);
   return If;
 }
 
@@ -343,7 +343,7 @@
   
   /// Construct the If.
   Stmt *If =
-    new (C) IfStmt(C, SourceLocation(), false, nullptr, Comparison, Body,
+    new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr, Comparison, Body,
                    SourceLocation(), Else);
 
   return If;  
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -764,11 +764,12 @@
 }
 
 IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr,
-               VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
+               Stmt *init, VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
                Stmt *elsev)
     : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) {
   setConstexpr(IsConstexpr);
   setConditionVariable(C, var);
+  SubExprs[INIT] = init;
   SubExprs[COND] = cond;
   SubExprs[THEN] = then;
   SubExprs[ELSE] = elsev;
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -4964,6 +4964,9 @@
 Stmt *ASTNodeImporter::VisitIfStmt(IfStmt *S) {
   SourceLocation ToIfLoc = Importer.Import(S->getIfLoc());
   VarDecl *ToConditionVariable = nullptr;
+  Stmt *ToInit = Importer.Import(S->getInit());
+  if (!ToInit && S->getInit())
+    return nullptr;
   if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
     ToConditionVariable =
       dyn_cast_or_null<VarDecl>(Importer.Import(FromConditionVariable));
@@ -4982,6 +4985,7 @@
     return nullptr;
   return new (Importer.getToContext()) IfStmt(Importer.getToContext(),
                                               ToIfLoc, S->isConstexpr(),
+                                              ToInit,
                                               ToConditionVariable,
                                               ToCondition, ToThenStmt,
                                               ToElseLoc, ToElseStmt);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3397,10 +3397,10 @@
 
   class ConditionResult;
   StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                         ConditionResult Cond, Stmt *ThenVal,
+                         ConditionResult Cond, Stmt *InitVal, Stmt *ThenVal,
                          SourceLocation ElseLoc, Stmt *ElseVal);
   StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                         ConditionResult Cond, Stmt *ThenVal,
+                         ConditionResult Cond, Stmt *InitVal, Stmt *ThenVal,
                          SourceLocation ElseLoc, Stmt *ElseVal);
   StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
                                     ConditionResult Cond);
@@ -8958,7 +8958,8 @@
   enum class ConditionKind {
     Boolean,     ///< A boolean condition, from 'if', 'while', 'for', or 'do'.
     ConstexprIf, ///< A constant boolean condition from 'if constexpr'.
-    Switch       ///< An integral condition for a 'switch' statement.
+    Switch,      ///< An integral condition for a 'switch' statement.
+    IfWithInit   ///< A for-init-statement from C++17's 'if statement with initializer'
   };
 
   ConditionResult ActOnCondition(Scope *S, SourceLocation Loc,
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1682,7 +1682,8 @@
   StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
   bool ParseParenExprOrCondition(Sema::ConditionResult &CondResult,
                                  SourceLocation Loc,
-                                 Sema::ConditionKind CK);
+                                 Sema::ConditionKind CK,
+                                 Stmt** Init = nullptr);
   StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
   StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
   StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
@@ -1908,6 +1909,11 @@
     return isDeclarationSpecifier(true);
   }
 
+  /// isForInitDeclarationWithSemi - is the same as isForInitDeclaration
+  /// but makes sure that there is a semicolon at the of the declaration
+  /// (needed for C++1z 'if statement with init')
+  bool isForInitDeclarationWithSemi();
+
   /// \brief Determine whether this is a C++1z for-range-identifier.
   bool isForRangeIdentifier();
 
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -879,7 +879,7 @@
 /// IfStmt - This represents an if/then/else.
 ///
 class IfStmt : public Stmt {
-  enum { VAR, COND, THEN, ELSE, END_EXPR };
+  enum { INIT, VAR, COND, THEN, ELSE, END_EXPR };
   Stmt* SubExprs[END_EXPR];
 
   SourceLocation IfLoc;
@@ -887,7 +887,7 @@
 
 public:
   IfStmt(const ASTContext &C, SourceLocation IL,
-         bool IsConstexpr, VarDecl *var, Expr *cond,
+         bool IsConstexpr, Stmt *init, VarDecl *var, Expr *cond,
          Stmt *then, SourceLocation EL = SourceLocation(),
          Stmt *elsev = nullptr);
 
@@ -905,6 +905,10 @@
   VarDecl *getConditionVariable() const;
   void setConditionVariable(const ASTContext &C, VarDecl *V);
 
+  Stmt *getInit() { return SubExprs[INIT]; }
+  const Stmt *getInit() const { return SubExprs[INIT]; }
+  void setInit(Stmt *S) { SubExprs[INIT] = S; }
+
   /// If this IfStmt has a condition variable, return the faux DeclStmt
   /// associated with the creation of that condition variable.
   const DeclStmt *getConditionVariableDeclStmt() const {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to