]> granicus.if.org Git - clang/commitdiff
P0305R1: Parsing support for init-statements in 'if' and 'switch' statements.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 29 Jun 2016 21:17:59 +0000 (21:17 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 29 Jun 2016 21:17:59 +0000 (21:17 +0000)
No semantic analysis yet.

This is a pain to disambiguate correctly, because the parsing rules for the
declaration form of a condition and of an init-statement are quite different --
for a token sequence that looks like a declaration, we frequently need to
disambiguate all the way to the ')' or ';'.

We could do better here in some cases by stopping disambiguation once we've
decided whether we've got an expression or not (rather than keeping going until
we know whether it's an init-statement declaration or a condition declaration),
by unifying our parsing code for the two types of declaration and moving the
syntactic checks into Sema; if this has a measurable impact on parsing
performance, I'll look into that.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@274169 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/DeclSpec.h
include/clang/Sema/Sema.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
test/Parser/cxx1z-init-statement.cpp [new file with mode: 0644]
test/Parser/extra-semi.cpp

index 73e390f1eda3b088c7a88cc49859619474491161..5af8a291e3490426cfdea31ec80a149f68161d9e 100644 (file)
@@ -7499,6 +7499,9 @@ 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<
index 278a91f912c62a5a699f84d0947487c9f2030a09..9d59f257affcb31bb005cfcbc246a9c87a5783f0 100644 (file)
@@ -1598,7 +1598,8 @@ private:
 
   //===--------------------------------------------------------------------===//
   // C++ if/switch/while condition expression.
-  Sema::ConditionResult ParseCXXCondition(SourceLocation Loc,
+  Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt,
+                                          SourceLocation Loc,
                                           Sema::ConditionKind CK);
 
   //===--------------------------------------------------------------------===//
@@ -1690,7 +1691,8 @@ private:
                                     unsigned ScopeFlags);
   void ParseCompoundStatementLeadingPragmas();
   StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
-  bool ParseParenExprOrCondition(Sema::ConditionResult &CondResult,
+  bool ParseParenExprOrCondition(StmtResult *InitStmt,
+                                 Sema::ConditionResult &CondResult,
                                  SourceLocation Loc,
                                  Sema::ConditionKind CK);
   StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
@@ -1984,11 +1986,18 @@ private:
   /// the function returns true to let the declaration parsing code handle it.
   bool isCXXFunctionDeclarator(bool *IsAmbiguous = nullptr);
 
-  /// isCXXConditionDeclaration - Disambiguates between a declaration or an
-  /// expression for a condition of a if/switch/while/for statement.
-  /// If during the disambiguation process a parsing error is encountered,
-  /// the function returns true to let the declaration parsing code handle it.
-  bool isCXXConditionDeclaration();
+  struct ConditionDeclarationOrInitStatementState;
+  enum class ConditionOrInitStatement {
+    Expression,    ///< Disambiguated as an expression (either kind).
+    ConditionDecl, ///< Disambiguated as the declaration form of condition.
+    InitStmtDecl,  ///< Disambiguated as a simple-declaration init-statement.
+    Error          ///< Can't be any of the above!
+  };
+  /// \brief Disambiguates between the different kinds of things that can happen
+  /// after 'if (' or 'switch ('. This could be one of two different kinds of
+  /// declaration (depending on whether there is a ';' later) or an expression.
+  ConditionOrInitStatement
+  isCXXConditionDeclarationOrInitStatement(bool CanBeInitStmt);
 
   bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous);
   bool isCXXTypeId(TentativeCXXTypeIdContext Context) {
index 09aabda3805dd58079ee72a16bf608a3e1df215f..f908e91e4bf81de83a7b0decd96e4da2bb1bbd5f 100644 (file)
@@ -1632,6 +1632,7 @@ public:
     MemberContext,       // Struct/Union field.
     BlockContext,        // Declaration within a block in a function.
     ForContext,          // Declaration within first part of a for loop.
+    InitStmtContext,     // Declaration within optional init stmt of if/switch.
     ConditionContext,    // Condition declaration in a C++ if/switch/while/for.
     TemplateParamContext,// Within a template parameter list.
     CXXNewContext,       // C++ new-expression.
@@ -1810,6 +1811,7 @@ public:
     case MemberContext:
     case BlockContext:
     case ForContext:
+    case InitStmtContext:
     case ConditionContext:
       return false;
 
@@ -1844,6 +1846,7 @@ public:
     case MemberContext:
     case BlockContext:
     case ForContext:
+    case InitStmtContext:
     case ConditionContext:
     case PrototypeContext:
     case LambdaExprParameterContext:
@@ -1877,6 +1880,7 @@ public:
     case MemberContext:
     case BlockContext:
     case ForContext:
+    case InitStmtContext:
     case ConditionContext:
     case PrototypeContext:
     case LambdaExprParameterContext:
@@ -1921,6 +1925,7 @@ public:
     case FileContext:
     case BlockContext:
     case ForContext:
+    case InitStmtContext:
       return true;
 
     case ConditionContext:
@@ -2120,6 +2125,7 @@ public:
     case MemberContext:
     case BlockContext:
     case ForContext:
+    case InitStmtContext:
       return true;
 
     case ConditionContext:
index 8b2e6e8b5b811293ed3f8d991a8e3601738ad44d..8d469a031312c9e8366955b8349cc474c22bba2e 100644 (file)
@@ -3397,12 +3397,14 @@ public:
 
   class ConditionResult;
   StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+                         Stmt *InitStmt,
                          ConditionResult Cond, Stmt *ThenVal,
                          SourceLocation ElseLoc, Stmt *ElseVal);
   StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                          ConditionResult Cond, Stmt *ThenVal,
                          SourceLocation ElseLoc, Stmt *ElseVal);
   StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+                                    Stmt *InitStmt,
                                     ConditionResult Cond);
   StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
                                            Stmt *Switch, Stmt *Body);
index b7a253156f25610c09dbd0ab5e70d5135c0ec62c..65d7a9b8fd77d7d00feb4fd8208f28535616bd4c 100644 (file)
@@ -2075,7 +2075,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
       if (Init.isInvalid()) {
         SmallVector<tok::TokenKind, 2> StopTokens;
         StopTokens.push_back(tok::comma);
-        if (D.getContext() == Declarator::ForContext)
+        if (D.getContext() == Declarator::ForContext ||
+            D.getContext() == Declarator::InitStmtContext)
           StopTokens.push_back(tok::r_paren);
         SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch);
         Actions.ActOnInitializerError(ThisDecl);
index 8a6626b9f173b109fc054da9c374c95637540c73..b09d7dbc12fc38fb710143f0cefc605f15ccfd5e 100644 (file)
@@ -1726,11 +1726,18 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
 /// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
 ///             '=' assignment-expression
 ///
+/// In C++1z, a condition may in some contexts be preceded by an
+/// optional init-statement. This function will parse that too.
+///
+/// \param InitStmt If non-null, an init-statement is permitted, and if present
+/// will be parsed and stored here.
+///
 /// \param Loc The location of the start of the statement that requires this
 /// condition, e.g., the "for" in a for loop.
 ///
 /// \returns The parsed condition.
-Sema::ConditionResult Parser::ParseCXXCondition(SourceLocation Loc,
+Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
+                                                SourceLocation Loc,
                                                 Sema::ConditionKind CK) {
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
@@ -1741,7 +1748,9 @@ Sema::ConditionResult Parser::ParseCXXCondition(SourceLocation Loc,
   ParsedAttributesWithRange attrs(AttrFactory);
   MaybeParseCXX11Attributes(attrs);
 
-  if (!isCXXConditionDeclaration()) {
+  // Determine what kind of thing we have.
+  switch (isCXXConditionDeclarationOrInitStatement(InitStmt)) {
+  case ConditionOrInitStatement::Expression: {
     ProhibitAttributes(attrs);
 
     // Parse the expression.
@@ -1749,9 +1758,28 @@ Sema::ConditionResult Parser::ParseCXXCondition(SourceLocation Loc,
     if (Expr.isInvalid())
       return Sema::ConditionError();
 
+    if (InitStmt && Tok.is(tok::semi)) {
+      *InitStmt = Actions.ActOnExprStmt(Expr.get());
+      ConsumeToken();
+      return ParseCXXCondition(nullptr, Loc, CK);
+    }
+
     return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK);
   }
 
+  case ConditionOrInitStatement::InitStmtDecl: {
+    SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+    DeclGroupPtrTy DG = ParseSimpleDeclaration(
+        Declarator::InitStmtContext, DeclEnd, attrs, /*RequireSemi=*/true);
+    *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
+    return ParseCXXCondition(nullptr, Loc, CK);
+  }
+
+  case ConditionOrInitStatement::ConditionDecl:
+  case ConditionOrInitStatement::Error:
+    break;
+  }
+
   // type-specifier-seq
   DeclSpec DS(AttrFactory);
   DS.takeAttributesFrom(attrs);
@@ -1814,9 +1842,6 @@ Sema::ConditionResult Parser::ParseCXXCondition(SourceLocation Loc,
   else
     Actions.ActOnInitializerError(DeclOut);
 
-  // FIXME: Build a reference to this declaration? Convert it to bool?
-  // (This is currently handled by Sema).
-
   Actions.FinalizeDeclaration(DeclOut);
   return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
 }
index 5ca9933900833dcb4ada7c9c858069efaa46ba4a..fa8eb12044be8c385f12aa03a9ce55497081a2a6 100644 (file)
@@ -1043,7 +1043,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
 
 /// ParseParenExprOrCondition:
 /// [C  ]     '(' expression ')'
-/// [C++]     '(' condition ')'       [not allowed if OnlyAllowCondition=true]
+/// [C++]     '(' condition ')'
+/// [C++1z]   '(' init-statement[opt] condition ')'
 ///
 /// This function parses and performs error recovery on the specified condition
 /// or expression (depending on whether we're in C++ or C mode).  This function
@@ -1052,14 +1053,15 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
 /// should try to recover harder.  It returns false if the condition is
 /// successfully parsed.  Note that a successful parse can still have semantic
 /// errors in the condition.
-bool Parser::ParseParenExprOrCondition(Sema::ConditionResult &Cond,
+bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
+                                       Sema::ConditionResult &Cond,
                                        SourceLocation Loc,
                                        Sema::ConditionKind CK) {
   BalancedDelimiterTracker T(*this, tok::l_paren);
   T.consumeOpen();
 
   if (getLangOpts().CPlusPlus)
-    Cond = ParseCXXCondition(Loc, CK);
+    Cond = ParseCXXCondition(InitStmt, Loc, CK);
   else {
     ExprResult CondExpr = ParseExpression();
 
@@ -1139,8 +1141,9 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
   ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
 
   // Parse the condition.
+  StmtResult InitStmt;
   Sema::ConditionResult Cond;
-  if (ParseParenExprOrCondition(Cond, IfLoc,
+  if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
                                 IsConstexpr ? Sema::ConditionKind::ConstexprIf
                                             : Sema::ConditionKind::Boolean))
     return StmtError();
@@ -1241,8 +1244,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
   if (ElseStmt.isInvalid())
     ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
 
-  return Actions.ActOnIfStmt(IfLoc, IsConstexpr, Cond, ThenStmt.get(), ElseLoc,
-                             ElseStmt.get());
+  return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond,
+                             ThenStmt.get(), ElseLoc, ElseStmt.get());
 }
 
 /// ParseSwitchStatement
@@ -1279,11 +1282,14 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
   ParseScope SwitchScope(this, ScopeFlags);
 
   // Parse the condition.
+  StmtResult InitStmt;
   Sema::ConditionResult Cond;
-  if (ParseParenExprOrCondition(Cond, SwitchLoc, Sema::ConditionKind::Switch))
+  if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
+                                Sema::ConditionKind::Switch))
     return StmtError();
 
-  StmtResult Switch = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond);
+  StmtResult Switch =
+      Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond);
 
   if (Switch.isInvalid()) {
     // Skip the switch body.
@@ -1366,7 +1372,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
 
   // Parse the condition.
   Sema::ConditionResult Cond;
-  if (ParseParenExprOrCondition(Cond, WhileLoc, Sema::ConditionKind::Boolean))
+  if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
+                                Sema::ConditionKind::Boolean))
     return StmtError();
 
   // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
@@ -1681,7 +1688,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
       // missing both semicolons.
     } else {
       if (getLangOpts().CPlusPlus)
-        SecondPart = ParseCXXCondition(ForLoc, Sema::ConditionKind::Boolean);
+        SecondPart =
+            ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean);
       else {
         ExprResult SecondExpr = ParseExpression();
         if (SecondExpr.isInvalid())
index c79208a00194e31914cb2042d8dc50e861b6a91f..7703c33b87800f98002426ae04a58b38163d7f6c 100644 (file)
@@ -330,10 +330,70 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
   return TPResult::Ambiguous;
 }
 
-/// isCXXConditionDeclaration - Disambiguates between a declaration or an
-/// expression for a condition of a if/switch/while/for statement.
-/// If during the disambiguation process a parsing error is encountered,
-/// the function returns true to let the declaration parsing code handle it.
+struct Parser::ConditionDeclarationOrInitStatementState {
+  Parser &P;
+  bool CanBeExpression = true;
+  bool CanBeCondition = true;
+  bool CanBeInitStatement;
+
+  ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement)
+      : P(P), CanBeInitStatement(CanBeInitStatement) {}
+
+  void markNotExpression() {
+    CanBeExpression = false;
+
+    if (CanBeCondition && CanBeInitStatement) {
+      // FIXME: Unify the parsing codepaths for condition variables and
+      // simple-declarations so that we don't need to eagerly figure out which
+      // kind we have here. (Just parse init-declarators until we reach a
+      // semicolon or right paren.)
+      RevertingTentativeParsingAction PA(P);
+      P.SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
+      if (P.Tok.isNot(tok::r_paren))
+        CanBeCondition = false;
+      if (P.Tok.isNot(tok::semi))
+        CanBeInitStatement = false;
+    }
+  }
+
+  bool markNotCondition() {
+    CanBeCondition = false;
+    return !CanBeInitStatement || !CanBeExpression;
+  }
+
+  bool update(TPResult IsDecl) {
+    switch (IsDecl) {
+    case TPResult::True:
+      markNotExpression();
+      return true;
+    case TPResult::False:
+      CanBeCondition = CanBeInitStatement = false;
+      return true;
+    case TPResult::Ambiguous:
+      return false;
+    case TPResult::Error:
+      CanBeExpression = CanBeCondition = CanBeInitStatement = false;
+      return true;
+    }
+    llvm_unreachable("unknown tentative parse result");
+  }
+
+  ConditionOrInitStatement result() const {
+    assert(CanBeExpression + CanBeCondition + CanBeInitStatement < 2 &&
+           "result called but not yet resolved");
+    if (CanBeExpression)
+      return ConditionOrInitStatement::Expression;
+    if (CanBeCondition)
+      return ConditionOrInitStatement::ConditionDecl;
+    if (CanBeInitStatement)
+      return ConditionOrInitStatement::InitStmtDecl;
+    return ConditionOrInitStatement::Error;
+  }
+};
+
+/// \brief Disambiguates between a declaration in a condition, a
+/// simple-declaration in an init-statement, and an expression for
+/// a condition of a if/switch statement.
 ///
 ///       condition:
 ///         expression
@@ -342,45 +402,64 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
 /// [C++11] type-specifier-seq declarator braced-init-list
 /// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
 ///             '=' assignment-expression
+///       simple-declaration:
+///         decl-specifier-seq init-declarator-list[opt] ';'
 ///
-bool Parser::isCXXConditionDeclaration() {
-  TPResult TPR = isCXXDeclarationSpecifier();
-  if (TPR != TPResult::Ambiguous)
-    return TPR != TPResult::False; // Returns true for TPResult::True or
-                                   // TPResult::Error.
+/// Note that, unlike isCXXSimpleDeclaration, we must disambiguate all the way
+/// to the ';' to disambiguate cases like 'int(x))' (an expression) from
+/// 'int(x);' (a simple-declaration in an init-statement).
+Parser::ConditionOrInitStatement
+Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) {
+  ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement);
 
-  // FIXME: Add statistics about the number of ambiguous statements encountered
-  // and how they were resolved (number of declarations+number of expressions).
-
-  // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
-  // We need tentative parsing...
+  if (State.update(isCXXDeclarationSpecifier()))
+    return State.result();
 
+  // It might be a declaration; we need tentative parsing.
   RevertingTentativeParsingAction PA(*this);
 
-  // type-specifier-seq
-  TryConsumeDeclarationSpecifier();
+  // FIXME: A tag definition unambiguously tells us this is an init-statement.
+  if (State.update(TryConsumeDeclarationSpecifier()))
+    return State.result();
   assert(Tok.is(tok::l_paren) && "Expected '('");
 
-  // declarator
-  TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+  while (true) {
+    // Consume a declarator.
+    if (State.update(TryParseDeclarator(false/*mayBeAbstract*/)))
+      return State.result();
+
+    // Attributes, asm label, or an initializer imply this is not an expression.
+    // FIXME: Disambiguate properly after an = instead of assuming that it's a
+    // valid declaration.
+    if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute) ||
+        (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))) {
+      State.markNotExpression();
+      return State.result();
+    }
 
-  // In case of an error, let the declaration parsing code handle it.
-  if (TPR == TPResult::Error)
-    TPR = TPResult::True;
+    // At this point, it can't be a condition any more, because a condition
+    // must have a brace-or-equal-initializer.
+    if (State.markNotCondition())
+      return State.result();
 
-  if (TPR == TPResult::Ambiguous) {
-    // '='
-    // [GNU] simple-asm-expr[opt] attributes[opt]
-    if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute))
-      TPR = TPResult::True;
-    else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))
-      TPR = TPResult::True;
-    else
-      TPR = TPResult::False;
+    // A parenthesized initializer could be part of an expression or a
+    // simple-declaration.
+    if (Tok.is(tok::l_paren)) {
+      ConsumeParen();
+      SkipUntil(tok::r_paren, StopAtSemi);
+    }
+
+    if (!TryConsumeToken(tok::comma))
+      break;
   }
 
-  assert(TPR == TPResult::True || TPR == TPResult::False);
-  return TPR == TPResult::True;
+  // We reached the end. If it can now be some kind of decl, then it is.
+  if (State.CanBeCondition && Tok.is(tok::r_paren))
+    return ConditionOrInitStatement::ConditionDecl;
+  else if (State.CanBeInitStatement && Tok.is(tok::semi))
+    return ConditionOrInitStatement::InitStmtDecl;
+  else
+    return ConditionOrInitStatement::Expression;
 }
 
   /// \brief Determine whether the next set of tokens contains a type-id.
@@ -1329,6 +1408,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
             *HasMissingTypename = true;
             return TPResult::Ambiguous;
           }
+
+          // FIXME: Fails to either revert or commit the tentative parse!
         } else {
           // Try to resolve the name. If it doesn't exist, assume it was
           // intended to name a type and keep disambiguating.
index 5432a7094448857ba9be112d4fccb31c2f8ce792..61ef8f3a81c78fdeea4225ccd5461149391a5615 100644 (file)
@@ -504,9 +504,13 @@ public:
 }
 
 StmtResult
-Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, ConditionResult Cond,
+Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
+                  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,
@@ -659,11 +663,14 @@ ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) {
   return UsualUnaryConversions(CondResult.get());
 }
 
-StmtResult
-Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ConditionResult Cond) {
+StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+                                        Stmt *InitStmt, ConditionResult Cond) {
   if (Cond.isInvalid())
     return StmtError();
 
+  if (InitStmt)
+    Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
+
   getCurFunction()->setHasBranchIntoScope();
 
   SwitchStmt *SS =
index 84ebb9bc8664549bc90533458850ab591d663847..d58de8a38223019cbb4ba5be0dcffc764b4285eb 100644 (file)
@@ -2883,6 +2883,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     case Declarator::FileContext:
     case Declarator::BlockContext:
     case Declarator::ForContext:
+    case Declarator::InitStmtContext:
     case Declarator::ConditionContext:
       break;
     case Declarator::CXXNewContext:
@@ -2968,6 +2969,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     case Declarator::MemberContext:
     case Declarator::BlockContext:
     case Declarator::ForContext:
+    case Declarator::InitStmtContext:
     case Declarator::BlockLiteralContext:
     case Declarator::LambdaExprContext:
       // C++11 [dcl.type]p3:
@@ -3711,6 +3713,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
     case Declarator::CXXCatchContext:
     case Declarator::CXXNewContext:
     case Declarator::ForContext:
+    case Declarator::InitStmtContext:
     case Declarator::LambdaExprContext:
     case Declarator::LambdaExprParameterContext:
     case Declarator::ObjCCatchContext:
@@ -4523,6 +4526,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
     case Declarator::MemberContext:
     case Declarator::BlockContext:
     case Declarator::ForContext:
+    case Declarator::InitStmtContext:
     case Declarator::ConditionContext:
     case Declarator::CXXCatchContext:
     case Declarator::ObjCCatchContext:
index fbfc078e988796bab8f40b36f4b2d9f8409f49b6..c32827fa25c8176472d6b923db0f1338e5b33704 100644 (file)
@@ -1176,7 +1176,8 @@ public:
   StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
                            Sema::ConditionResult Cond, Stmt *Then,
                            SourceLocation ElseLoc, Stmt *Else) {
-    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Cond, Then, ElseLoc, Else);
+    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, nullptr, Cond, Then,
+                                 ElseLoc, Else);
   }
 
   /// \brief Start building a new switch statement.
@@ -1185,7 +1186,7 @@ public:
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
                                     Sema::ConditionResult Cond) {
-    return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond);
+    return getSema().ActOnStartOfSwitchStmt(SwitchLoc, nullptr, Cond);
   }
 
   /// \brief Attach the body to the switch statement.
diff --git a/test/Parser/cxx1z-init-statement.cpp b/test/Parser/cxx1z-init-statement.cpp
new file mode 100644 (file)
index 0000000..e8621ba
--- /dev/null
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s -Wno-vexing-parse
+
+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}}
+
+  // 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}}
+
+  // condition declarations
+  if (T(n){g}) {}
+  if (T f()) {} // expected-error {{function type}}
+  if (T f(), g, h) {} // expected-error {{function type}}
+
+  // condition expressions
+  if (T(f())) {}
+  if (T{f()}) {}
+  if (T(f()), g, h) {} // expected-warning 2{{unused}}
+  if (T{f()}, g, h) {} // expected-warning 2{{unused}}
+
+  // none of the above
+  // FIXME: This causes a typo-correction crash, as does "void f() { +T(n)(g); }"
+  //if (T(n)(g)) {} // expected-err-FIXME {{not a function}}
+
+  // Likewise for 'switch'
+  switch (int n; n) {} // expected-error {{not yet supported}}
+  switch (g; int g = 5) {} // expected-error {{not yet supported}}
+
+  if (int a, b; int c = a) { // expected-error {{not yet supported}} expected-note 6{{previous}}
+    int a; // expected-error {{redefinition}}
+    int b; // expected-error {{redefinition}}
+    int c; // expected-error {{redefinition}}
+  } else {
+    int a; // expected-error {{redefinition}}
+    int b; // expected-error {{redefinition}}
+    int c; // expected-error {{redefinition}}
+  }
+}
index 1a44dae411e2e608458fbaa2ed5168ec811fb740..7287f856d8c97361ff1145405a8c1d2d8128f0b8 100644 (file)
@@ -5,7 +5,6 @@
 
 void test1(int a;) { // expected-error{{unexpected ';' before ')'}}
   while (a > 5;) {} // expected-error{{unexpected ';' before ')'}}
-  if (int b = 10;) {} // expected-error{{unexpected ';' before ')'}}
   for (int c  = 0; c < 21; ++c;) {} // expected-error{{unexpected ';' before ')'}}
   int d = int(3 + 4;); // expected-error{{unexpected ';' before ')'}}
   int e[5;]; // expected-error{{unexpected ';' before ']'}}