diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 73e390f1eda3b0..5af8a291e34904 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 278a91f912c62a..9d59f257affcb3 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1598,7 +1598,8 @@ class Parser : public CodeCompletionHandler { //===--------------------------------------------------------------------===// // 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 @@ class Parser : public CodeCompletionHandler { 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 @@ class Parser : public CodeCompletionHandler { /// 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/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 09aabda3805dd5..f908e91e4bf81d 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1632,6 +1632,7 @@ class Declarator { 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 @@ class Declarator { case MemberContext: case BlockContext: case ForContext: + case InitStmtContext: case ConditionContext: return false; @@ -1844,6 +1846,7 @@ class Declarator { case MemberContext: case BlockContext: case ForContext: + case InitStmtContext: case ConditionContext: case PrototypeContext: case LambdaExprParameterContext: @@ -1877,6 +1880,7 @@ class Declarator { case MemberContext: case BlockContext: case ForContext: + case InitStmtContext: case ConditionContext: case PrototypeContext: case LambdaExprParameterContext: @@ -1921,6 +1925,7 @@ class Declarator { case FileContext: case BlockContext: case ForContext: + case InitStmtContext: return true; case ConditionContext: @@ -2120,6 +2125,7 @@ class Declarator { case MemberContext: case BlockContext: case ForContext: + case InitStmtContext: return true; case ConditionContext: diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8b2e6e8b5b8112..8d469a031312c9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3397,12 +3397,14 @@ class Sema { 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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b7a253156f2561..65d7a9b8fd77d7 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 8a6626b9f173b1..b09d7dbc12fc38 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/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/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 5ca9933900833d..fa8eb12044be8c 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/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/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index c79208a00194e3..7703c33b87800f 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 5432a709444885..61ef8f3a81c78f 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -504,9 +504,13 @@ class CommaVisitor : public EvaluatedExprVisitor { } 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/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 84ebb9bc866454..d58de8a3822301 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index fbfc078e988796..c32827fa25c817 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1176,7 +1176,8 @@ class TreeTransform { 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 @@ class TreeTransform { /// 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/clang/test/Parser/cxx1z-init-statement.cpp b/clang/test/Parser/cxx1z-init-statement.cpp new file mode 100644 index 00000000000000..e8621babaa883b --- /dev/null +++ b/clang/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/clang/test/Parser/extra-semi.cpp b/clang/test/Parser/extra-semi.cpp index 1a44dae411e2e6..7287f856d8c973 100644 --- a/clang/test/Parser/extra-semi.cpp +++ b/clang/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 ']'}}