Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -869,12 +869,13 @@ Stmt* SubExprs[END_EXPR]; SourceLocation IfLoc; + SourceLocation LParenLoc, RParenLoc; SourceLocation ElseLoc; public: IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, - Stmt *then, SourceLocation EL = SourceLocation(), - Stmt *elsev = nullptr); + SourceLocation LP, SourceLocation RP, Stmt *then, + SourceLocation EL = SourceLocation(), Stmt *elsev = nullptr); /// \brief Build an empty if/then/else statement explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } @@ -911,6 +912,10 @@ void setIfLoc(SourceLocation L) { IfLoc = L; } SourceLocation getElseLoc() const { return ElseLoc; } void setElseLoc(SourceLocation L) { ElseLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; } SourceLocation getLocEnd() const LLVM_READONLY { @@ -939,6 +944,7 @@ // This points to a linked list of case and default statements. SwitchCase *FirstCase; SourceLocation SwitchLoc; + SourceLocation LParenLoc, RParenLoc; /// If the SwitchStmt is a switch on an enum value, this records whether /// all the enum values were covered by CaseStmts. This value is meant to @@ -946,7 +952,8 @@ unsigned AllEnumCasesCovered : 1; public: - SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond); + SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond, SourceLocation LP, + SourceLocation RP); /// \brief Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } @@ -984,6 +991,10 @@ SourceLocation getSwitchLoc() const { return SwitchLoc; } void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } void setBody(Stmt *S, SourceLocation SL) { SubExprs[BODY] = S; @@ -1030,9 +1041,10 @@ enum { VAR, COND, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; SourceLocation WhileLoc; + SourceLocation LParenLoc, RParenLoc; public: WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, - SourceLocation WL); + SourceLocation WL, SourceLocation LP, SourceLocation RP); /// \brief Build an empty while statement. explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } @@ -1063,6 +1075,10 @@ SourceLocation getWhileLoc() const { return WhileLoc; } void setWhileLoc(SourceLocation L) { WhileLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getLocStart() const LLVM_READONLY { return WhileLoc; } SourceLocation getLocEnd() const LLVM_READONLY { Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1587,10 +1587,9 @@ unsigned ScopeFlags); void ParseCompoundStatementLeadingPragmas(); StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); - bool ParseParenExprOrCondition(ExprResult &ExprResult, - Decl *&DeclResult, - SourceLocation Loc, - bool ConvertToBoolean); + bool ParseParenExprOrCondition(BalancedDelimiterTracker &Tracker, + ExprResult &ExprResult, Decl *&DeclResult, + SourceLocation Loc, bool ConvertToBoolean); StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc); StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc); StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3056,18 +3056,18 @@ ArrayRef Attrs, Stmt *SubStmt); - StmtResult ActOnIfStmt(SourceLocation IfLoc, + StmtResult ActOnIfStmt(SourceLocation IfLoc, SourceLocation CondLParen, FullExprArg CondVal, Decl *CondVar, - Stmt *ThenVal, + SourceLocation CondRParen, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, - Expr *Cond, - Decl *CondVar); + SourceLocation CondLParen, Expr *Cond, + Decl *CondVar, SourceLocation CondRParen); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); - StmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, - Decl *CondVar, Stmt *Body); + StmtResult ActOnWhileStmt(SourceLocation WhileLoc, SourceLocation CondLParen, + FullExprArg Cond, Decl *CondVar, + SourceLocation CondRParen, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, Index: lib/AST/Stmt.cpp =================================================================== --- lib/AST/Stmt.cpp +++ lib/AST/Stmt.cpp @@ -854,9 +854,9 @@ } IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, - Stmt *then, SourceLocation EL, Stmt *elsev) - : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) -{ + SourceLocation LP, SourceLocation RP, Stmt *then, + SourceLocation EL, Stmt *elsev) + : Stmt(IfStmtClass), IfLoc(IL), LParenLoc(LP), RParenLoc(RP), ElseLoc(EL) { setConditionVariable(C, var); SubExprs[COND] = cond; SubExprs[THEN] = then; @@ -913,9 +913,10 @@ VarRange.getEnd()); } -SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond) - : Stmt(SwitchStmtClass), FirstCase(nullptr), AllEnumCasesCovered(0) -{ +SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond, + SourceLocation LP, SourceLocation RP) + : Stmt(SwitchStmtClass), FirstCase(nullptr), LParenLoc(LP), RParenLoc(RP), + AllEnumCasesCovered(0) { setConditionVariable(C, Var); SubExprs[COND] = cond; SubExprs[BODY] = nullptr; @@ -947,12 +948,11 @@ } WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, - SourceLocation WL) - : Stmt(WhileStmtClass) { + SourceLocation WL, SourceLocation LP, SourceLocation RP) + : Stmt(WhileStmtClass), WhileLoc(WL), LParenLoc(LP), RParenLoc(RP) { setConditionVariable(C, Var); SubExprs[COND] = cond; SubExprs[BODY] = body; - WhileLoc = WL; } VarDecl *WhileStmt::getConditionVariable() const { Index: lib/Analysis/BodyFarm.cpp =================================================================== --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -242,7 +242,8 @@ SourceLocation()); // (5) Create the 'if' statement. - IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS); + IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, + SourceLocation(), SourceLocation(), CS); return If; } @@ -346,8 +347,8 @@ /// Construct the If. Stmt *If = - new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body, - SourceLocation(), Else); + new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, SourceLocation(), + SourceLocation(), Body, SourceLocation(), Else); return If; } Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -1004,12 +1004,11 @@ /// 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(ExprResult &ExprResult, - Decl *&DeclResult, - SourceLocation Loc, +bool Parser::ParseParenExprOrCondition(BalancedDelimiterTracker &Tracker, + ExprResult &ExprResult, + Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean) { - BalancedDelimiterTracker T(*this, tok::l_paren); - T.consumeOpen(); + Tracker.consumeOpen(); if (getLangOpts().CPlusPlus) ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean); @@ -1035,7 +1034,7 @@ } // Otherwise the condition is valid or the rparen is present. - T.consumeClose(); + Tracker.consumeClose(); // Check for extraneous ')'s to catch things like "if (foo())) {". We know // that all callers are looking for a statement after the condition, so ")" @@ -1086,7 +1085,8 @@ // Parse the condition. ExprResult CondExp; Decl *CondVar = nullptr; - if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (ParseParenExprOrCondition(T, CondExp, CondVar, IfLoc, true)) return StmtError(); FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get(), IfLoc)); @@ -1173,8 +1173,9 @@ if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, ThenStmt.get(), - ElseLoc, ElseStmt.get()); + return Actions.ActOnIfStmt(IfLoc, T.getOpenLocation(), FullCondExp, CondVar, + T.getCloseLocation(), ThenStmt.get(), ElseLoc, + ElseStmt.get()); } /// ParseSwitchStatement @@ -1213,11 +1214,13 @@ // Parse the condition. ExprResult Cond; Decl *CondVar = nullptr; - if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (ParseParenExprOrCondition(T, Cond, CondVar, SwitchLoc, false)) return StmtError(); - StmtResult Switch - = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar); + StmtResult Switch = + Actions.ActOnStartOfSwitchStmt(SwitchLoc, T.getOpenLocation(), Cond.get(), + CondVar, T.getCloseLocation()); if (Switch.isInvalid()) { // Skip the switch body. @@ -1301,7 +1304,8 @@ // Parse the condition. ExprResult Cond; Decl *CondVar = nullptr; - if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) + BalancedDelimiterTracker T(*this, tok::l_paren); + if (ParseParenExprOrCondition(T, Cond, CondVar, WhileLoc, true)) return StmtError(); FullExprArg FullCond(Actions.MakeFullExpr(Cond.get(), WhileLoc)); @@ -1329,7 +1333,8 @@ if ((Cond.isInvalid() && !CondVar) || Body.isInvalid()) return StmtError(); - return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, Body.get()); + return Actions.ActOnWhileStmt(WhileLoc, T.getOpenLocation(), FullCond, + CondVar, T.getCloseLocation(), Body.get()); } /// ParseDoStatement Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -449,10 +449,10 @@ return LS; } -StmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, - Stmt *thenStmt, SourceLocation ElseLoc, - Stmt *elseStmt) { +StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, SourceLocation CondLParen, + FullExprArg CondVal, Decl *CondVar, + SourceLocation CondRParen, Stmt *thenStmt, + SourceLocation ElseLoc, Stmt *elseStmt) { // If the condition was invalid, discard the if statement. We could recover // better by replacing it with a valid expr, but don't do that yet. if (!CondVal.get() && !CondVar) { @@ -482,8 +482,9 @@ DiagnoseUnusedExprResult(elseStmt); - return new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, - thenStmt, ElseLoc, elseStmt); + return new (Context) + IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, CondLParen, + CondRParen, thenStmt, ElseLoc, elseStmt); } namespace { @@ -545,9 +546,10 @@ return expr->getType(); } -StmtResult -Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, - Decl *CondVar) { +StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + SourceLocation CondLParen, Expr *Cond, + Decl *CondVar, + SourceLocation CondRParen) { ExprResult CondResult; VarDecl *ConditionVar = nullptr; @@ -629,7 +631,8 @@ getCurFunction()->setHasBranchIntoScope(); - SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond); + SwitchStmt *SS = new (Context) + SwitchStmt(Context, ConditionVar, Cond, CondLParen, CondRParen); getCurFunction()->SwitchStack.push_back(SS); return SS; } @@ -1195,9 +1198,10 @@ } } -StmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, - Decl *CondVar, Stmt *Body) { +StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, + SourceLocation CondLParen, FullExprArg Cond, + Decl *CondVar, SourceLocation CondRParen, + Stmt *Body) { ExprResult CondResult(Cond.release()); VarDecl *ConditionVar = nullptr; @@ -1217,8 +1221,8 @@ if (isa(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); - return new (Context) - WhileStmt(Context, ConditionVar, ConditionExpr, Body, WhileLoc); + return new (Context) WhileStmt(Context, ConditionVar, ConditionExpr, Body, + WhileLoc, CondLParen, CondRParen); } StmtResult Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1112,10 +1112,12 @@ /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, - VarDecl *CondVar, Stmt *Then, + StmtResult RebuildIfStmt(SourceLocation IfLoc, SourceLocation LParenLoc, + Sema::FullExprArg Cond, VarDecl *CondVar, + SourceLocation RParenLoc, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { - return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else); + return getSema().ActOnIfStmt(IfLoc, LParenLoc, Cond, CondVar, RParenLoc, + Then, ElseLoc, Else); } /// \brief Start building a new switch statement. @@ -1123,9 +1125,11 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, - Expr *Cond, VarDecl *CondVar) { - return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond, - CondVar); + SourceLocation LParenLoc, Expr *Cond, + VarDecl *CondVar, + SourceLocation RParenLoc) { + return getSema().ActOnStartOfSwitchStmt(SwitchLoc, LParenLoc, Cond, CondVar, + RParenLoc); } /// \brief Attach the body to the switch statement. @@ -1141,9 +1145,11 @@ /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::FullExprArg Cond, - VarDecl *CondVar, Stmt *Body) { - return getSema().ActOnWhileStmt(WhileLoc, Cond, CondVar, Body); + StmtResult RebuildWhileStmt(SourceLocation WhileLoc, SourceLocation LParenLoc, + Sema::FullExprArg Cond, VarDecl *CondVar, + SourceLocation RParenLoc, Stmt *Body) { + return getSema().ActOnWhileStmt(WhileLoc, LParenLoc, Cond, CondVar, + RParenLoc, Body); } /// \brief Build a new do-while statement. @@ -5602,8 +5608,8 @@ Else.get() == S->getElse()) return S; - return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar, - Then.get(), + return getDerived().RebuildIfStmt(S->getIfLoc(), S->getLParenLoc(), FullCond, + ConditionVar, S->getRParenLoc(), Then.get(), S->getElseLoc(), Else.get()); } @@ -5629,9 +5635,9 @@ } // Rebuild the switch statement. - StmtResult Switch - = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond.get(), - ConditionVar); + StmtResult Switch = getDerived().RebuildSwitchStmtStart( + S->getSwitchLoc(), S->getLParenLoc(), Cond.get(), ConditionVar, + S->getRParenLoc()); if (Switch.isInvalid()) return StmtError(); @@ -5691,8 +5697,9 @@ Body.get() == S->getBody()) return Owned(S); - return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, - ConditionVar, Body.get()); + return getDerived().RebuildWhileStmt(S->getWhileLoc(), S->getLParenLoc(), + FullCond, ConditionVar, + S->getRParenLoc(), Body.get()); } template Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -189,6 +189,8 @@ S->setThen(Reader.ReadSubStmt()); S->setElse(Reader.ReadSubStmt()); S->setIfLoc(ReadSourceLocation(Record, Idx)); + S->setLParenLoc(ReadSourceLocation(Record, Idx)); + S->setRParenLoc(ReadSourceLocation(Record, Idx)); S->setElseLoc(ReadSourceLocation(Record, Idx)); } @@ -199,6 +201,8 @@ S->setCond(Reader.ReadSubExpr()); S->setBody(Reader.ReadSubStmt()); S->setSwitchLoc(ReadSourceLocation(Record, Idx)); + S->setLParenLoc(ReadSourceLocation(Record, Idx)); + S->setRParenLoc(ReadSourceLocation(Record, Idx)); if (Record[Idx++]) S->setAllEnumCasesCovered(); @@ -222,6 +226,8 @@ S->setCond(Reader.ReadSubExpr()); S->setBody(Reader.ReadSubStmt()); S->setWhileLoc(ReadSourceLocation(Record, Idx)); + S->setLParenLoc(ReadSourceLocation(Record, Idx)); + S->setRParenLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitDoStmt(DoStmt *S) { Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -124,6 +124,8 @@ Writer.AddStmt(S->getThen()); Writer.AddStmt(S->getElse()); Writer.AddSourceLocation(S->getIfLoc(), Record); + Writer.AddSourceLocation(S->getLParenLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); Writer.AddSourceLocation(S->getElseLoc(), Record); Code = serialization::STMT_IF; } @@ -134,6 +136,8 @@ Writer.AddStmt(S->getCond()); Writer.AddStmt(S->getBody()); Writer.AddSourceLocation(S->getSwitchLoc(), Record); + Writer.AddSourceLocation(S->getLParenLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); Record.push_back(S->isAllEnumCasesCovered()); for (SwitchCase *SC = S->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) @@ -147,6 +151,8 @@ Writer.AddStmt(S->getCond()); Writer.AddStmt(S->getBody()); Writer.AddSourceLocation(S->getWhileLoc(), Record); + Writer.AddSourceLocation(S->getLParenLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); Code = serialization::STMT_WHILE; }