From: Richard Smith Date: Wed, 29 Jun 2016 21:17:59 +0000 (+0000) Subject: P0305R1: Parsing support for init-statements in 'if' and 'switch' statements. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=24d543be3689fba09cd4afd3fc7f05b930c563a8;p=clang P0305R1: Parsing support for init-statements in 'if' and 'switch' statements. 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 73e390f1ed..5af8a291e3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 278a91f912..9d59f257af 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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) { diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 09aabda380..f908e91e4b 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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: diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8b2e6e8b5b..8d469a0313 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b7a253156f..65d7a9b8fd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2075,7 +2075,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( if (Init.isInvalid()) { SmallVector 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); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 8a6626b9f1..b09d7dbc12 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 5ca9933900..fa8eb12044 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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()) diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index c79208a001..7703c33b87 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -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. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 5432a70944..61ef8f3a81 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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 = diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 84ebb9bc86..d58de8a382 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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: diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fbfc078e98..c32827fa25 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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 index 0000000000..e8621babaa --- /dev/null +++ b/test/Parser/cxx1z-init-statement.cpp @@ -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}} + } +} diff --git a/test/Parser/extra-semi.cpp b/test/Parser/extra-semi.cpp index 1a44dae411..7287f856d8 100644 --- a/test/Parser/extra-semi.cpp +++ b/test/Parser/extra-semi.cpp @@ -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 ']'}}