diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1895,6 +1895,8 @@ // Present if and only if hasElseStorage(). enum { InitOffset = 0, ThenOffsetFromCond = 1, ElseOffsetFromCond = 2 }; enum { NumMandatoryStmtPtr = 2 }; + SourceLocation LParenLoc; + SourceLocation RParenLoc; unsigned numTrailingObjects(OverloadToken) const { return NumMandatoryStmtPtr + hasElseStorage() + hasVarStorage() + @@ -1915,7 +1917,8 @@ /// Build an if/then/else statement. IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, - VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else); + VarDecl *Var, Expr *Cond, SourceLocation LParenLoc, + SourceLocation RParenLoc, Stmt *Then, SourceLocation EL, Stmt *Else); /// Build an empty if/then/else statement. explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit); @@ -1924,7 +1927,8 @@ /// Create an IfStmt. static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, - Stmt *Then, SourceLocation EL = SourceLocation(), + SourceLocation LPL, SourceLocation RPL, Stmt *Then, + SourceLocation EL = SourceLocation(), Stmt *Else = nullptr); /// Create an empty IfStmt optionally with storage for an else statement, @@ -2054,6 +2058,10 @@ return getElse()->getEndLoc(); return getThen()->getEndLoc(); } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } // Iterators over subexpressions. The iterators will include iterating // over the initialization expression referenced by the condition variable. @@ -2101,6 +2109,8 @@ // Always present. enum { InitOffset = 0, BodyOffsetFromCond = 1 }; enum { NumMandatoryStmtPtr = 2 }; + SourceLocation LParenLoc; + SourceLocation RParenLoc; unsigned numTrailingObjects(OverloadToken) const { return NumMandatoryStmtPtr + hasInitStorage() + hasVarStorage(); @@ -2114,7 +2124,8 @@ unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; } /// Build a switch statement. - SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, Expr *Cond); + SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, Expr *Cond, + SourceLocation LParenLoc, SourceLocation RParenLoc); /// Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar); @@ -2122,7 +2133,8 @@ public: /// Create a switch statement. static SwitchStmt *Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, - Expr *Cond); + Expr *Cond, SourceLocation LParenLoc, + SourceLocation RParenLoc); /// Create an empty switch statement optionally with storage for /// an init expression and a condition variable. @@ -2210,6 +2222,10 @@ SourceLocation getSwitchLoc() const { return SwitchStmtBits.SwitchLoc; } void setSwitchLoc(SourceLocation L) { SwitchStmtBits.SwitchLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } void setBody(Stmt *S, SourceLocation SL) { setBody(S); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4380,16 +4380,17 @@ class ConditionResult; StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Stmt *InitStmt, - ConditionResult Cond, Stmt *ThenVal, - SourceLocation ElseLoc, Stmt *ElseVal); + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, SourceLocation RParenLoc, + Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Stmt *InitStmt, - ConditionResult Cond, Stmt *ThenVal, - SourceLocation ElseLoc, Stmt *ElseVal); + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, SourceLocation RParenLoc, + Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, - Stmt *InitStmt, - ConditionResult Cond); + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, + SourceLocation RParenLoc); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, SourceLocation LParenLoc, diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6067,6 +6067,8 @@ auto ToInit = importChecked(Err, S->getInit()); auto ToConditionVariable = importChecked(Err, S->getConditionVariable()); auto ToCond = importChecked(Err, S->getCond()); + auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); + auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); auto ToThen = importChecked(Err, S->getThen()); auto ToElseLoc = importChecked(Err, S->getElseLoc()); auto ToElse = importChecked(Err, S->getElse()); @@ -6074,8 +6076,8 @@ return std::move(Err); return IfStmt::Create(Importer.getToContext(), ToIfLoc, S->isConstexpr(), - ToInit, ToConditionVariable, ToCond, ToThen, ToElseLoc, - ToElse); + ToInit, ToConditionVariable, ToCond, ToLParenLoc, + ToRParenLoc, ToThen, ToElseLoc, ToElse); } ExpectedStmt ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) { @@ -6084,13 +6086,16 @@ auto ToInit = importChecked(Err, S->getInit()); auto ToConditionVariable = importChecked(Err, S->getConditionVariable()); auto ToCond = importChecked(Err, S->getCond()); + auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); + auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); auto ToBody = importChecked(Err, S->getBody()); auto ToSwitchLoc = importChecked(Err, S->getSwitchLoc()); if (Err) return std::move(Err); - auto *ToStmt = SwitchStmt::Create(Importer.getToContext(), ToInit, - ToConditionVariable, ToCond); + auto *ToStmt = + SwitchStmt::Create(Importer.getToContext(), ToInit, ToConditionVariable, + ToCond, ToLParenLoc, ToRParenLoc); ToStmt->setBody(ToBody); ToStmt->setSwitchLoc(ToSwitchLoc); diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -827,9 +827,9 @@ } IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, - Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then, - SourceLocation EL, Stmt *Else) - : Stmt(IfStmtClass) { + Stmt *Init, VarDecl *Var, Expr *Cond, SourceLocation LPL, + SourceLocation RPL, Stmt *Then, SourceLocation EL, Stmt *Else) + : Stmt(IfStmtClass), LParenLoc(LPL), RParenLoc(RPL) { bool HasElse = Else != nullptr; bool HasVar = Var != nullptr; bool HasInit = Init != nullptr; @@ -862,7 +862,8 @@ IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, - Stmt *Then, SourceLocation EL, Stmt *Else) { + SourceLocation LPL, SourceLocation RPL, Stmt *Then, + SourceLocation EL, Stmt *Else) { bool HasElse = Else != nullptr; bool HasVar = Var != nullptr; bool HasInit = Init != nullptr; @@ -871,7 +872,7 @@ NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse), alignof(IfStmt)); return new (Mem) - IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, Then, EL, Else); + IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, LPL, RPL, Then, EL, Else); } IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar, @@ -947,8 +948,10 @@ } SwitchStmt::SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, - Expr *Cond) - : Stmt(SwitchStmtClass), FirstCase(nullptr) { + Expr *Cond, SourceLocation LParenLoc, + SourceLocation RParenLoc) + : Stmt(SwitchStmtClass), FirstCase(nullptr), LParenLoc(LParenLoc), + RParenLoc(RParenLoc) { bool HasInit = Init != nullptr; bool HasVar = Var != nullptr; SwitchStmtBits.HasInit = HasInit; @@ -973,13 +976,14 @@ } SwitchStmt *SwitchStmt::Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, - Expr *Cond) { + Expr *Cond, SourceLocation LParenLoc, + SourceLocation RParenLoc) { bool HasInit = Init != nullptr; bool HasVar = Var != nullptr; void *Mem = Ctx.Allocate( totalSizeToAlloc(NumMandatoryStmtPtr + HasInit + HasVar), alignof(SwitchStmt)); - return new (Mem) SwitchStmt(Ctx, Init, Var, Cond); + return new (Mem) SwitchStmt(Ctx, Init, Var, Cond, LParenLoc, RParenLoc); } SwitchStmt *SwitchStmt::CreateEmpty(const ASTContext &Ctx, bool HasInit, diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -468,6 +468,8 @@ /* Init=*/nullptr, /* Var=*/nullptr, /* Cond=*/FlagCheck, + /* LPL=*/SourceLocation(), + /* RPL=*/SourceLocation(), /* Then=*/M.makeCompound({CallbackCall, FlagAssignment})); return Out; @@ -552,6 +554,8 @@ /* Init=*/nullptr, /* Var=*/nullptr, /* Cond=*/GuardCondition, + /* LPL=*/SourceLocation(), + /* RPL=*/SourceLocation(), /* Then=*/CS); return If; } @@ -655,11 +659,13 @@ Stmt *Else = M.makeReturn(RetVal); /// Construct the If. - auto *If = IfStmt::Create(C, SourceLocation(), - /* IsConstexpr=*/false, - /* Init=*/nullptr, - /* Var=*/nullptr, Comparison, Body, - SourceLocation(), Else); + auto *If = + IfStmt::Create(C, SourceLocation(), + /* IsConstexpr=*/false, + /* Init=*/nullptr, + /* Var=*/nullptr, Comparison, + /* LPL=*/SourceLocation(), + /* RPL=*/SourceLocation(), Body, SourceLocation(), Else); return If; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1350,9 +1350,12 @@ // Parse the condition. StmtResult InitStmt; Sema::ConditionResult Cond; + SourceLocation LParen; + SourceLocation RParen; if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, IsConstexpr ? Sema::ConditionKind::ConstexprIf - : Sema::ConditionKind::Boolean)) + : Sema::ConditionKind::Boolean, + &LParen, &RParen)) return StmtError(); llvm::Optional ConstexprCondition; @@ -1465,8 +1468,8 @@ if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond, - ThenStmt.get(), ElseLoc, ElseStmt.get()); + return Actions.ActOnIfStmt(IfLoc, IsConstexpr, LParen, InitStmt.get(), Cond, + RParen, ThenStmt.get(), ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement @@ -1505,12 +1508,14 @@ // Parse the condition. StmtResult InitStmt; Sema::ConditionResult Cond; + SourceLocation LParen; + SourceLocation RParen; if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc, - Sema::ConditionKind::Switch)) + Sema::ConditionKind::Switch, &LParen, &RParen)) return StmtError(); - StmtResult Switch = - Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond); + StmtResult Switch = Actions.ActOnStartOfSwitchStmt( + SwitchLoc, LParen, InitStmt.get(), Cond, RParen); if (Switch.isInvalid()) { // Skip the switch body. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -8022,10 +8022,10 @@ if (ReturnFalse.isInvalid()) return StmtError(); - return S.ActOnIfStmt(Loc, false, nullptr, + return S.ActOnIfStmt(Loc, false, Loc, nullptr, S.ActOnCondition(nullptr, Loc, NotCond.get(), Sema::ConditionKind::Boolean), - ReturnFalse.get(), SourceLocation(), nullptr); + Loc, ReturnFalse.get(), SourceLocation(), nullptr); } StmtResult visitSubobjectArray(QualType Type, llvm::APInt Size, @@ -8177,9 +8177,9 @@ return StmtError(); // if (...) - return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, InitStmt, Cond, - ReturnStmt.get(), /*ElseLoc=*/SourceLocation(), - /*Else=*/nullptr); + return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, Loc, InitStmt, Cond, Loc, + ReturnStmt.get(), + /*ElseLoc=*/SourceLocation(), /*Else=*/nullptr); } case DefaultedComparisonKind::NotEqual: diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -574,11 +574,11 @@ }; } -StmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, - ConditionResult Cond, - Stmt *thenStmt, SourceLocation ElseLoc, - Stmt *elseStmt) { +StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, SourceLocation RParenLoc, + Stmt *thenStmt, SourceLocation ElseLoc, + Stmt *elseStmt) { if (Cond.isInvalid()) Cond = ConditionResult( *this, nullptr, @@ -597,12 +597,13 @@ DiagnoseEmptyStmtBody(CondExpr->getEndLoc(), thenStmt, diag::warn_empty_if_body); - return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc, - elseStmt); + return BuildIfStmt(IfLoc, IsConstexpr, LParenLoc, InitStmt, Cond, RParenLoc, + thenStmt, ElseLoc, elseStmt); } StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Stmt *InitStmt, ConditionResult Cond, + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, SourceLocation RParenLoc, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { if (Cond.isInvalid()) @@ -612,7 +613,8 @@ setFunctionHasBranchProtectedScope(); return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first, - Cond.get().second, thenStmt, ElseLoc, elseStmt); + Cond.get().second, LParenLoc, RParenLoc, thenStmt, + ElseLoc, elseStmt); } namespace { @@ -739,7 +741,9 @@ } StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, - Stmt *InitStmt, ConditionResult Cond) { + SourceLocation LParenLoc, + Stmt *InitStmt, ConditionResult Cond, + SourceLocation RParenLoc) { Expr *CondExpr = Cond.get().second; assert((Cond.isInvalid() || CondExpr) && "switch with no condition"); @@ -761,7 +765,8 @@ setFunctionHasBranchIntoScope(); - auto *SS = SwitchStmt::Create(Context, InitStmt, Cond.get().first, CondExpr); + auto *SS = SwitchStmt::Create(Context, InitStmt, Cond.get().first, CondExpr, + LParenLoc, RParenLoc); getCurFunction()->SwitchStack.push_back( FunctionScopeInfo::SwitchInfo(SS, false)); return SS; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1319,19 +1319,23 @@ /// 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 *Init, Stmt *Then, + SourceLocation LParenLoc, Sema::ConditionResult Cond, + SourceLocation RParenLoc, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { - return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then, - ElseLoc, Else); + return getSema().ActOnIfStmt(IfLoc, IsConstexpr, LParenLoc, Init, Cond, + RParenLoc, Then, ElseLoc, Else); } /// Start building a new switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, Stmt *Init, - Sema::ConditionResult Cond) { - return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond); + StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, + SourceLocation LParenLoc, Stmt *Init, + Sema::ConditionResult Cond, + SourceLocation RParenLoc) { + return getSema().ActOnStartOfSwitchStmt(SwitchLoc, LParenLoc, Init, Cond, + RParenLoc); } /// Attach the body to the switch statement. @@ -7289,9 +7293,9 @@ Else.get() == S->getElse()) return S; - return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond, - Init.get(), Then.get(), S->getElseLoc(), - Else.get()); + return getDerived().RebuildIfStmt( + S->getIfLoc(), S->isConstexpr(), S->getLParenLoc(), Cond, + S->getRParenLoc(), Init.get(), Then.get(), S->getElseLoc(), Else.get()); } template @@ -7310,8 +7314,9 @@ return StmtError(); // Rebuild the switch statement. - StmtResult Switch - = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Init.get(), Cond); + StmtResult Switch = + getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), S->getLParenLoc(), + Init.get(), Cond, S->getRParenLoc()); if (Switch.isInvalid()) return StmtError(); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -226,6 +226,8 @@ S->setInit(Record.readSubStmt()); S->setIfLoc(readSourceLocation()); + S->setLParenLoc(readSourceLocation()); + S->setRParenLoc(readSourceLocation()); if (HasElse) S->setElseLoc(readSourceLocation()); } @@ -247,6 +249,8 @@ S->setConditionVariable(Record.getContext(), readDeclAs()); S->setSwitchLoc(readSourceLocation()); + S->setLParenLoc(readSourceLocation()); + S->setRParenLoc(readSourceLocation()); SwitchCase *PrevSC = nullptr; for (auto E = Record.size(); Record.getIdx() != E; ) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -152,6 +152,8 @@ Record.AddStmt(S->getInit()); Record.AddSourceLocation(S->getIfLoc()); + Record.AddSourceLocation(S->getLParenLoc()); + Record.AddSourceLocation(S->getRParenLoc()); if (HasElse) Record.AddSourceLocation(S->getElseLoc()); @@ -175,6 +177,8 @@ Record.AddDeclRef(S->getConditionVariable()); Record.AddSourceLocation(S->getSwitchLoc()); + Record.AddSourceLocation(S->getLParenLoc()); + Record.AddSourceLocation(S->getRParenLoc()); for (SwitchCase *SC = S->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase())