r275350 - P0305R0: Semantic analysis and code generation for C++17 init-statement for 'if' and 'switch':

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 13 17:11:03 PDT 2016


Author: rsmith
Date: Wed Jul 13 19:11:03 2016
New Revision: 275350

URL: http://llvm.org/viewvc/llvm-project?rev=275350&view=rev
Log:
P0305R0: Semantic analysis and code generation for C++17 init-statement for 'if' and 'switch':

  if (stmt; condition) { ... }

Patch by Anton Bikineev! Some minor formatting and comment tweets by me.

Added:
    cfe/trunk/test/CodeGenCXX/cxx1z-init-statement.cpp
    cfe/trunk/test/PCH/cxx1z-init-statement.cpp
    cfe/trunk/test/PCH/cxx1z-init-statement.h
    cfe/trunk/test/SemaCXX/cxx1z-init-statement-warn-unused.cpp
    cfe/trunk/test/SemaCXX/cxx1z-init-statement.cpp
Modified:
    cfe/trunk/include/clang/AST/Stmt.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/Analysis/BodyFarm.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/Sema/JumpDiagnostics.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/test/Misc/ast-dump-invalid.cpp
    cfe/trunk/test/Parser/cxx1z-init-statement.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Wed Jul 13 19:11:03 2016
@@ -879,7 +879,7 @@ public:
 /// 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 @@ class IfStmt : public Stmt {
 
 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);
 
@@ -911,6 +911,9 @@ public:
     return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
   }
 
+  Stmt *getInit() { return SubExprs[INIT]; }
+  const Stmt *getInit() const { return SubExprs[INIT]; }
+  void setInit(Stmt *S) { SubExprs[INIT] = S; }
   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]; }
@@ -953,7 +956,7 @@ public:
 ///
 class SwitchStmt : public Stmt {
   SourceLocation SwitchLoc;
-  enum { VAR, COND, BODY, END_EXPR };
+  enum { INIT, VAR, COND, BODY, END_EXPR };
   Stmt* SubExprs[END_EXPR];
   // This points to a linked list of case and default statements and, if the
   // SwitchStmt is a switch on an enum value, records whether all the enum
@@ -962,7 +965,7 @@ class SwitchStmt : public Stmt {
   llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase;
 
 public:
-  SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
+  SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond);
 
   /// \brief Build a empty switch statement.
   explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
@@ -985,6 +988,9 @@ public:
     return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
   }
 
+  Stmt *getInit() { return SubExprs[INIT]; }
+  const Stmt *getInit() const { return SubExprs[INIT]; }
+  void setInit(Stmt *S) { SubExprs[INIT] = S; }
   const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
   const Stmt *getBody() const { return SubExprs[BODY]; }
   const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jul 13 19:11:03 2016
@@ -7503,9 +7503,6 @@ def warn_empty_switch_body : Warning<
 def note_empty_body_on_separate_line : Note<
   "put the semicolon on a separate line to silence this warning">;
 
-def err_init_stmt_not_supported : Error<
-  "C++1z init-statement not yet supported">;
-
 def err_va_start_used_in_non_variadic_function : Error<
   "'va_start' used in function with fixed args">;
 def err_va_start_used_in_wrong_abi_function : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jul 13 19:11:03 2016
@@ -3401,6 +3401,7 @@ public:
                          ConditionResult Cond, Stmt *ThenVal,
                          SourceLocation ElseLoc, Stmt *ElseVal);
   StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+                         Stmt *InitStmt,
                          ConditionResult Cond, Stmt *ThenVal,
                          SourceLocation ElseLoc, Stmt *ElseVal);
   StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed Jul 13 19:11:03 2016
@@ -4961,6 +4961,9 @@ Stmt *ASTNodeImporter::VisitAttributedSt
 
 Stmt *ASTNodeImporter::VisitIfStmt(IfStmt *S) {
   SourceLocation ToIfLoc = Importer.Import(S->getIfLoc());
+  Stmt *ToInit = Importer.Import(S->getInit());
+  if (!ToInit && S->getInit())
+    return nullptr;
   VarDecl *ToConditionVariable = nullptr;
   if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
     ToConditionVariable =
@@ -4980,12 +4983,16 @@ Stmt *ASTNodeImporter::VisitIfStmt(IfStm
     return nullptr;
   return new (Importer.getToContext()) IfStmt(Importer.getToContext(),
                                               ToIfLoc, S->isConstexpr(),
+                                              ToInit,
                                               ToConditionVariable,
                                               ToCondition, ToThenStmt,
                                               ToElseLoc, ToElseStmt);
 }
 
 Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) {
+  Stmt *ToInit = Importer.Import(S->getInit());
+  if (!ToInit && S->getInit())
+    return nullptr;
   VarDecl *ToConditionVariable = nullptr;
   if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
     ToConditionVariable =
@@ -4997,8 +5004,8 @@ Stmt *ASTNodeImporter::VisitSwitchStmt(S
   if (!ToCondition && S->getCond())
     return nullptr;
   SwitchStmt *ToStmt = new (Importer.getToContext()) SwitchStmt(
-                         Importer.getToContext(), ToConditionVariable,
-                         ToCondition);
+                         Importer.getToContext(), ToInit,
+                         ToConditionVariable, ToCondition);
   Stmt *ToBody = Importer.Import(S->getBody());
   if (!ToBody && S->getBody())
     return nullptr;

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Jul 13 19:11:03 2016
@@ -3485,6 +3485,11 @@ static EvalStmtResult EvaluateSwitch(Stm
   APSInt Value;
   {
     FullExpressionRAII Scope(Info);
+    if (const Stmt *Init = SS->getInit()) {
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
+      if (ESR != ESR_Succeeded)
+        return ESR;
+    }
     if (SS->getConditionVariable() &&
         !EvaluateDecl(Info, SS->getConditionVariable()))
       return ESR_Failed;
@@ -3667,6 +3672,11 @@ static EvalStmtResult EvaluateStmt(StmtR
 
     // Evaluate the condition, as either a var decl or as an expression.
     BlockScopeRAII Scope(Info);
+    if (const Stmt *Init = IS->getInit()) {
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
+      if (ESR != ESR_Succeeded)
+        return ESR;
+    }
     bool Cond;
     if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
       return ESR_Failed;

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Wed Jul 13 19:11:03 2016
@@ -764,11 +764,12 @@ void MSAsmStmt::initialize(const ASTCont
 }
 
 IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr,
-               VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
-               Stmt *elsev)
+               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;
@@ -824,9 +825,11 @@ void ForStmt::setConditionVariable(const
                                        VarRange.getEnd());
 }
 
-SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
+SwitchStmt::SwitchStmt(const ASTContext &C, Stmt *init, VarDecl *Var,
+                       Expr *cond)
     : Stmt(SwitchStmtClass), FirstCase(nullptr, false) {
   setConditionVariable(C, Var);
+  SubExprs[INIT] = init;
   SubExprs[COND] = cond;
   SubExprs[BODY] = nullptr;
 }

Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/BodyFarm.cpp (original)
+++ cfe/trunk/lib/Analysis/BodyFarm.cpp Wed Jul 13 19:11:03 2016
@@ -239,7 +239,8 @@ static Stmt *create_dispatch_once(ASTCon
                                            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;
 }
 
@@ -342,9 +343,8 @@ static Stmt *create_OSAtomicCompareAndSw
   Stmt *Else = M.makeReturn(RetVal);
   
   /// Construct the If.
-  Stmt *If =
-    new (C) IfStmt(C, SourceLocation(), false, nullptr, Comparison, Body,
-                   SourceLocation(), Else);
+  Stmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr,
+                            Comparison, Body, SourceLocation(), Else);
 
   return If;  
 }

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Wed Jul 13 19:11:03 2016
@@ -1,4 +1,4 @@
-  //===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
+//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -1945,7 +1945,8 @@ CFGBlock *CFGBuilder::VisitCompoundStmt(
     addLocalScopeForStmt(C);
   }
   if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
-    // If the body ends with a ReturnStmt, the dtors will be added in VisitReturnStmt
+    // If the body ends with a ReturnStmt, the dtors will be added in
+    // VisitReturnStmt.
     addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
   }
 
@@ -2168,6 +2169,13 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt
   // won't be restored when traversing AST.
   SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
 
+  // Create local scope for C++17 if init-stmt if one exists.
+  if (Stmt *Init = I->getInit()) {
+    LocalScope::const_iterator BeginScopePos = ScopePos;
+    addLocalScopeForStmt(Init);
+    addAutomaticObjDtors(ScopePos, BeginScopePos, I);
+  }
+
   // Create local scope for possible condition variable.
   // Store scope position. Add implicit destructor.
   if (VarDecl *VD = I->getConditionVariable()) {
@@ -2268,13 +2276,19 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt
   // blocks will be pointed to be "Block".
   CFGBlock *LastBlock = addStmt(I->getCond());
 
-  // Finally, if the IfStmt contains a condition variable, add it and its
+  // If the IfStmt contains a condition variable, add it and its
   // initializer to the CFG.
   if (const DeclStmt* DS = I->getConditionVariableDeclStmt()) {
     autoCreateBlock();
     LastBlock = addStmt(const_cast<DeclStmt *>(DS));
   }
 
+  // Finally, if the IfStmt contains a C++17 init-stmt, add it to the CFG.
+  if (Stmt *Init = I->getInit()) {
+    autoCreateBlock();
+    LastBlock = addStmt(Init);
+  }
+
   return LastBlock;
 }
 
@@ -3059,6 +3073,13 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(Sw
   // won't be restored when traversing AST.
   SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
 
+  // Create local scope for C++17 switch init-stmt if one exists.
+  if (Stmt *Init = Terminator->getInit()) {
+    LocalScope::const_iterator BeginScopePos = ScopePos;
+    addLocalScopeForStmt(Init);
+    addAutomaticObjDtors(ScopePos, BeginScopePos, Terminator);
+  }
+
   // Create local scope for possible condition variable.
   // Store scope position. Add implicit destructor.
   if (VarDecl *VD = Terminator->getConditionVariable()) {
@@ -3138,7 +3159,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(Sw
   Block = SwitchTerminatedBlock;
   CFGBlock *LastBlock = addStmt(Terminator->getCond());
 
-  // Finally, if the SwitchStmt contains a condition variable, add both the
+  // If the SwitchStmt contains a condition variable, add both the
   // SwitchStmt and the condition variable initialization to the CFG.
   if (VarDecl *VD = Terminator->getConditionVariable()) {
     if (Expr *Init = VD->getInit()) {
@@ -3148,6 +3169,12 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(Sw
     }
   }
 
+  // Finally, if the SwitchStmt contains a C++17 init-stmt, add it to the CFG.
+  if (Stmt *Init = Terminator->getInit()) {
+    autoCreateBlock();
+    LastBlock = addStmt(Init);
+  }
+
   return LastBlock;
 }
   

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Wed Jul 13 19:11:03 2016
@@ -568,6 +568,9 @@ void CodeGenFunction::EmitIfStmt(const I
   // 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());
 
@@ -1484,6 +1487,9 @@ void CodeGenFunction::EmitSwitchStmt(con
         incrementProfileCounter(Case);
       RunCleanupsScope ExecutedScope(*this);
 
+      if (S.getInit())
+        EmitStmt(S.getInit());
+
       // Emit the condition variable if needed inside the entire cleanup scope
       // used by this special case for constant folded switches.
       if (S.getConditionVariable())
@@ -1511,6 +1517,10 @@ void CodeGenFunction::EmitSwitchStmt(con
   JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
 
   RunCleanupsScope ConditionScope(*this);
+
+  if (S.getInit())
+    EmitStmt(S.getInit());
+
   if (S.getConditionVariable())
     EmitAutoVarDecl(*S.getConditionVariable());
   llvm::Value *CondV = EmitScalarExpr(S.getCond());

Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
+++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Wed Jul 13 19:11:03 2016
@@ -279,7 +279,7 @@ void JumpScopeChecker::BuildScopeInforma
   unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
                             ? origParentScope : independentParentScope);
 
-  bool SkipFirstSubStmt = false;
+  unsigned StmtsToSkip = 0u;
 
   // If we found a label, remember that it is in ParentScope scope.
   switch (S->getStmtClass()) {
@@ -304,11 +304,15 @@ void JumpScopeChecker::BuildScopeInforma
     break;
 
   case Stmt::SwitchStmtClass:
-    // Evaluate the condition variable before entering the scope of the switch
-    // statement.
+    // Evaluate the C++17 init stmt and condition variable
+    // before entering the scope of the switch statement.
+    if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
+      BuildScopeInformation(Init, ParentScope);
+      ++StmtsToSkip;
+    }
     if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
       BuildScopeInformation(Var, ParentScope);
-      SkipFirstSubStmt = true;
+      ++StmtsToSkip;
     }
     // Fall through
 
@@ -537,13 +541,13 @@ void JumpScopeChecker::BuildScopeInforma
   }
 
   for (Stmt *SubStmt : S->children()) {
-    if (SkipFirstSubStmt) {
-      SkipFirstSubStmt = false;
+    if (!SubStmt)
+        continue;
+    if (StmtsToSkip) {
+      --StmtsToSkip;
       continue;
     }
 
-    if (!SubStmt) continue;
-
     // Cases, labels, and defaults aren't "scope parents".  It's also
     // important to handle these iteratively instead of recursively in
     // order to avoid blowing out the stack.

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Jul 13 19:11:03 2016
@@ -508,9 +508,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc,
                   ConditionResult Cond,
                   Stmt *thenStmt, SourceLocation ElseLoc,
                   Stmt *elseStmt) {
-  if (InitStmt)
-    Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
-
   if (Cond.isInvalid())
     Cond = ConditionResult(
         *this, nullptr,
@@ -528,12 +525,14 @@ Sema::ActOnIfStmt(SourceLocation IfLoc,
     DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
                           diag::warn_empty_if_body);
 
-  return BuildIfStmt(IfLoc, IsConstexpr, Cond, thenStmt, ElseLoc, elseStmt);
+  return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc,
+                     elseStmt);
 }
 
 StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
-                             ConditionResult Cond, Stmt *thenStmt,
-                             SourceLocation ElseLoc, Stmt *elseStmt) {
+                             Stmt *InitStmt, ConditionResult Cond,
+                             Stmt *thenStmt, SourceLocation ElseLoc,
+                             Stmt *elseStmt) {
   if (Cond.isInvalid())
     return StmtError();
 
@@ -543,8 +542,9 @@ StmtResult Sema::BuildIfStmt(SourceLocat
   DiagnoseUnusedExprResult(thenStmt);
   DiagnoseUnusedExprResult(elseStmt);
 
-  return new (Context) IfStmt(Context, IfLoc, IsConstexpr, Cond.get().first,
-                              Cond.get().second, thenStmt, ElseLoc, elseStmt);
+  return new (Context)
+      IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
+             Cond.get().second, thenStmt, ElseLoc, elseStmt);
 }
 
 namespace {
@@ -668,13 +668,10 @@ StmtResult Sema::ActOnStartOfSwitchStmt(
   if (Cond.isInvalid())
     return StmtError();
 
-  if (InitStmt)
-    Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
-
   getCurFunction()->setHasBranchIntoScope();
 
-  SwitchStmt *SS =
-      new (Context) SwitchStmt(Context, Cond.get().first, Cond.get().second);
+  SwitchStmt *SS = new (Context)
+      SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second);
   getCurFunction()->SwitchStack.push_back(SS);
   return SS;
 }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Jul 13 19:11:03 2016
@@ -1174,9 +1174,9 @@ public:
   /// 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, nullptr, Cond, Then,
+    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then,
                                  ElseLoc, Else);
   }
 
@@ -1184,9 +1184,9 @@ public:
   ///
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
-  StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
+  StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, Stmt *Init,
                                     Sema::ConditionResult Cond) {
-    return getSema().ActOnStartOfSwitchStmt(SwitchLoc, nullptr, Cond);
+    return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond);
   }
 
   /// \brief Attach the body to the switch statement.
@@ -6266,6 +6266,11 @@ StmtResult TreeTransform<Derived>::Trans
 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(),
@@ -6298,18 +6303,25 @@ TreeTransform<Derived>::TransformIfStmt(
   }
 
   if (!getDerived().AlwaysRebuild() &&
+      Init.get() == S->getInit() &&
       Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
       Then.get() == S->getThen() &&
       Else.get() == S->getElse())
     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>
 StmtResult
 TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *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->getSwitchLoc(), S->getConditionVariable(), S->getCond(),
@@ -6319,7 +6331,8 @@ TreeTransform<Derived>::TransformSwitchS
 
   // Rebuild the switch statement.
   StmtResult Switch
-    = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond);
+    = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(),
+                                          S->getInit(), Cond);
   if (Switch.isInvalid())
     return StmtError();
 

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Jul 13 19:11:03 2016
@@ -185,6 +185,7 @@ void ASTStmtReader::VisitAttributedStmt(
 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());
@@ -196,6 +197,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *
 
 void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
   VisitStmt(S);
+  S->setInit(Reader.ReadSubStmt());
   S->setConditionVariable(Reader.getContext(),
                           ReadDeclAs<VarDecl>(Record, Idx));
   S->setCond(Reader.ReadSubExpr());

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Jul 13 19:11:03 2016
@@ -129,6 +129,7 @@ void ASTStmtWriter::VisitAttributedStmt(
 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());
@@ -140,6 +141,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *
 
 void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
   VisitStmt(S);
+  Record.AddStmt(S->getInit());
   Record.AddDeclRef(S->getConditionVariable());
   Record.AddStmt(S->getCond());
   Record.AddStmt(S->getBody());

Added: cfe/trunk/test/CodeGenCXX/cxx1z-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-init-statement.cpp?rev=275350&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1z-init-statement.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx1z-init-statement.cpp Wed Jul 13 19:11:03 2016
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
+
+typedef int T;
+void f() {
+  // CHECK:      %[[A:.*]] = alloca i32, align 4
+  // CHECK-NEXT: store i32 5, i32* %[[A]], align 4
+  // CHECK-NEXT: %[[B:.*]] = load i32, i32* %[[A]], align 4
+  // CHECK-NEXT  %[[C:.*]] = icmp slt i32 %[[B]], 8
+  if (int a = 5; a < 8)
+    ;
+}
+
+void f1() {
+  // CHECK:      %[[A:.*]] = alloca i32, align 4
+  // CHECK-NEXT: %[[B:.*]] = alloca i32, align 4
+  // CHECK-NEXT: %[[C:.*]] = alloca i32, align 4
+  // CHECK-NEXT: store i32 5, i32* %[[B]], align 4
+  // CHECK-NEXT: store i32 7, i32* %[[C]], align 4
+  if (int a, b = 5; int c = 7)
+    ;
+}
+
+int f2() {
+  // CHECK:      %[[A:.*]] = alloca i32, align 4
+  // CHECK-NEXT: %[[B:.*]] = call i32 @_Z2f2v()
+  // CHECK-NEXT: store i32 7, i32* %[[A]], align 4
+  // CHECK-NEXT: %[[C:.*]] = load i32, i32* %[[A]], align 4
+  // CHECK-NEXT: %[[D:.*]] = icmp ne i32 %[[C]], 0
+  if (T{f2()}; int c = 7)
+    ;
+  return 2;
+}
+
+void g() {
+  // CHECK:      %[[A:.*]] = alloca i32, align 4
+  // CHECK-NEXT: store i32 5, i32* %[[A]], align 4
+  // CHECK-NEXT: %[[B:.*]] = load i32, i32* %[[A]], align 4
+  // CHECK-NEXT: switch i32 %[[B]], label %[[C:.*]] [
+  switch (int a = 5; a) {
+    case 0:
+      break;
+  }
+}
+
+void g1() {
+  // CHECK:      %[[A:.*]] = alloca i32, align 4
+  // CHECK-NEXT: %[[B:.*]] = alloca i32, align 4
+  // CHECK-NEXT: %[[C:.*]] = alloca i32, align 4
+  // CHECK-NEXT: store i32 5, i32* %[[B]], align 4
+  // CHECK-NEXT: store i32 7, i32* %[[C]], align 4
+  // CHECK-NEXT: %[[D:.*]] = load i32, i32* %[[C]], align 4
+  // CHECK-NEXT: switch i32 %[[D]], label %[[E:.*]] [
+  switch (int a, b = 5; int c = 7) {
+    case 0:
+      break;
+  }
+}
+
+int g2() {
+  // CHECK:      %[[A:.*]] = alloca i32, align 4
+  // CHECK-NEXT: %[[B:.*]] = call i32 @_Z2f2v()
+  // CHECK-NEXT: store i32 7, i32* %[[A]], align 4
+  // CHECK-NEXT: %[[C:.*]] = load i32, i32* %[[A]], align 4
+  // CHECK-NEXT: switch i32 %[[C]], label %[[E:.*]] [
+  switch (T{f2()}; int c = 7) {
+    case 0:
+      break;
+  }
+  return 2;
+}

Modified: cfe/trunk/test/Misc/ast-dump-invalid.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ast-dump-invalid.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/test/Misc/ast-dump-invalid.cpp (original)
+++ cfe/trunk/test/Misc/ast-dump-invalid.cpp Wed Jul 13 19:11:03 2016
@@ -34,6 +34,7 @@ int g(int i) {
 // CHECK-NEXT:   `-CompoundStmt
 // CHECK-NEXT:     `-IfStmt {{.*}} <line:25:3, line:28:12>
 // CHECK-NEXT:       |-<<<NULL>>>
+// CHECK-NEXT:       |-<<<NULL>>>
 // CHECK-NEXT:       |-OpaqueValueExpr {{.*}} <<invalid sloc>> '_Bool'
 // CHECK-NEXT:       |-ReturnStmt {{.*}} <line:26:5, col:12>
 // CHECK-NEXT:       | `-IntegerLiteral {{.*}} <col:12> 'int' 4
@@ -41,7 +42,6 @@ int g(int i) {
 // CHECK-NEXT:         `-ImplicitCastExpr {{.*}} <col:12> 'int' <LValueToRValue>
 // CHECK-NEXT:           `-DeclRefExpr {{.*}} <col:12> 'int' lvalue ParmVar {{.*}} 'i' 'int'
 
-
 namespace TestInvalidFunctionDecl {
 struct Str {
    double foo1(double, invalid_type);

Added: cfe/trunk/test/PCH/cxx1z-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1z-init-statement.cpp?rev=275350&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx1z-init-statement.cpp (added)
+++ cfe/trunk/test/PCH/cxx1z-init-statement.cpp Wed Jul 13 19:11:03 2016
@@ -0,0 +1,17 @@
+// Test this without pch.
+// RUN: %clang_cc1 -std=c++1z -include %S/cxx1z-init-statement.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x c++ -std=c++1z -emit-pch -o %t %S/cxx1z-init-statement.h
+// RUN: %clang_cc1 -std=c++1z -include-pch %t -fsyntax-only -emit-llvm -o - %s 
+
+void g0(void) {
+  static_assert(test_if(-1) == -1, "");
+  static_assert(test_if(0) == 0, "");
+}
+
+void g1(void) {
+  static_assert(test_switch(-1) == -1, "");
+  static_assert(test_switch(0) == 0, "");
+  static_assert(test_switch(1) == 1, "");
+}

Added: cfe/trunk/test/PCH/cxx1z-init-statement.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1z-init-statement.h?rev=275350&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx1z-init-statement.h (added)
+++ cfe/trunk/test/PCH/cxx1z-init-statement.h Wed Jul 13 19:11:03 2016
@@ -0,0 +1,22 @@
+// Header for PCH test cxx1z-init-statement.cpp
+
+constexpr int test_if(int x) { 
+  if (int a = ++x; a == 0) {
+    return -1;
+  } else if (++a; a == 2) {
+    return 0;
+  }
+  return 2;
+}
+
+constexpr int test_switch(int x) {
+  switch (int a = ++x; a) {
+    case 0:
+      return -1;
+    case 1:
+      return 0;
+    case 2:
+      return 1;
+  }
+  return 2;
+}

Modified: cfe/trunk/test/Parser/cxx1z-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-init-statement.cpp?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-init-statement.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-init-statement.cpp Wed Jul 13 19:11:03 2016
@@ -4,18 +4,18 @@ int g, h;
 typedef int T;
 int f() {
   // init-statement declarations
-  if (T n = 0; n != 0) {} // expected-error {{not yet supported}}
-  if (T f(); f()) {} // expected-error {{not yet supported}}
-  if (T(f()); f()) {} // expected-error {{not yet supported}}
-  if (T(f()), g, h; f()) {} // expected-error {{not yet supported}}
-  if (T f(); f()) {} // expected-error {{not yet supported}}
-  if (T f(), g, h; f()) {} // expected-error {{not yet supported}}
-  if (T(n) = 0; n) {} // expected-error {{not yet supported}}
+  if (T n = 0; n != 0) {}
+  if (T f(); f()) {}
+  if (T(f()); f()) {}
+  if (T(f()), g, h; f()) {}
+  if (T f(); f()) {}
+  if (T f(), g, h; f()) {}
+  if (T(n) = 0; n) {}
 
   // init-statement expressions
-  if (T{f()}; f()) {} // expected-error {{not yet supported}}
-  if (T{f()}, g, h; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}}
-  if (T(f()), g, h + 1; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}}
+  if (T{f()}; f()) {}
+  if (T{f()}, g, h; f()) {} // expected-warning 2{{unused}}
+  if (T(f()), g, h + 1; f()) {} // expected-warning 2{{unused}}
 
   // condition declarations
   if (T(n){g}) {}
@@ -34,10 +34,10 @@ int f() {
   if (T(n)(int())) {} // expected-error {{undeclared identifier 'n'}}
 
   // Likewise for 'switch'
-  switch (int n; n) {} // expected-error {{not yet supported}}
-  switch (g; int g = 5) {} // expected-error {{not yet supported}}
+  switch (int n; n) {}
+  switch (g; int g = 5) {}
 
-  if (int a, b; int c = a) { // expected-error {{not yet supported}} expected-note 6{{previous}}
+  if (int a, b; int c = a) { // expected-note 6{{previous}}
     int a; // expected-error {{redefinition}}
     int b; // expected-error {{redefinition}}
     int c; // expected-error {{redefinition}}
@@ -46,4 +46,6 @@ int f() {
     int b; // expected-error {{redefinition}}
     int c; // expected-error {{redefinition}}
   }
+
+  return 0;
 }

Added: cfe/trunk/test/SemaCXX/cxx1z-init-statement-warn-unused.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-init-statement-warn-unused.cpp?rev=275350&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-init-statement-warn-unused.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1z-init-statement-warn-unused.cpp Wed Jul 13 19:11:03 2016
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s
+
+void testIf() {
+  if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}}
+    ;
+  if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}}
+    ;
+  int a;
+  if (a = 0; a) {} // OK
+}
+
+void testSwitch() {
+  switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}}
+    case 0:
+      break;
+  }
+  switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}}
+    case 0:
+      break;
+  }
+  int c;
+  switch (c = 0; c) { // OK
+    case 0:
+      break;
+  }
+}

Added: cfe/trunk/test/SemaCXX/cxx1z-init-statement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-init-statement.cpp?rev=275350&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-init-statement.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1z-init-statement.cpp Wed Jul 13 19:11:03 2016
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+void testIf() {
+  int x = 0;
+  if (x; x) ++x;
+  if (int t = 0; t) ++t; else --t;
+
+  if (int x, y = 0; y) // expected-note 2 {{previous definition is here}}
+    int x = 0; // expected-error {{redefinition of 'x'}}
+  else
+    int x = 0; // expected-error {{redefinition of 'x'}}
+
+  if (x; int a = 0) ++a;
+  if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}}
+    int a = 0; // expected-error {{redefinition of 'a'}}
+  else
+    int a = 0; // expected-error {{redefinition of 'a'}}
+
+  if (int b = 0; b)
+    ;
+  b = 2; // expected-error {{use of undeclared identifier}}
+}
+
+void testSwitch() {
+  int x = 0;
+  switch (x; x) {
+    case 1:
+      ++x;
+  }
+
+  switch (int x, y = 0; y) {
+    case 1:
+      ++x;
+    default:
+      ++y;
+  }
+
+  switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}}
+    case 0:
+      int x = 0; // expected-error {{redefinition of 'x'}}
+    case 1:
+      int y = 0; // expected-error {{redefinition of 'y'}}
+  };
+
+  switch (x; int a = 0) {
+    case 0:
+      ++a;
+  }
+
+  switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}}
+    case 0:
+      int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}}
+    case 1:
+      int a = 0; // expected-error {{redefinition of 'a'}}
+  }
+
+  switch (int b = 0; b) {
+    case 0:
+      break;
+  }
+  b = 2; // expected-error {{use of undeclared identifier}}
+}
+
+constexpr bool constexpr_if_init(int n) {
+  if (int a = n; ++a > 0)
+    return true;
+  else
+    return false;
+}
+
+constexpr int constexpr_switch_init(int n) {
+  switch (int p = n + 2; p) {
+    case 0:
+      return 0;
+    case 1:
+      return 1;
+    default:
+      return -1;
+  }
+}
+
+void test_constexpr_init_stmt() {
+  constexpr bool a = constexpr_if_init(-2);
+  static_assert(!a, "");
+  static_assert(constexpr_if_init(1), "");
+
+  constexpr int b = constexpr_switch_init(-1);
+  static_assert(b == 1, "");
+  static_assert(constexpr_switch_init(-2) == 0, "");
+  static_assert(constexpr_switch_init(-5) == -1, "");
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=275350&r1=275349&r2=275350&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Jul 13 19:11:03 2016
@@ -725,7 +725,7 @@ as the draft C++1z standard evolves.</p>
     <tr>
       <td>Separate variable and condition for <tt>if</tt> and <tt>switch</tt></td>
       <td><a href="http://wg21.link/p0305r1">P0305R1</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
 </table>
 




More information about the cfe-commits mailing list