Index: clang/include/clang/AST/Stmt.h =================================================================== --- clang/include/clang/AST/Stmt.h +++ clang/include/clang/AST/Stmt.h @@ -2357,11 +2357,12 @@ Stmt *SubExprs[END_EXPR]; SourceLocation WhileLoc; SourceLocation RParenLoc; // Location of final ')' in do stmt condition. + SourceLocation EndLoc; // Location of final ';' in do stmt condition. public: DoStmt(Stmt *Body, Expr *Cond, SourceLocation DL, SourceLocation WL, - SourceLocation RP) - : Stmt(DoStmtClass), WhileLoc(WL), RParenLoc(RP) { + SourceLocation RP, SourceLocation EL) + : Stmt(DoStmtClass), WhileLoc(WL), RParenLoc(RP), EndLoc(EL) { setCond(Cond); setBody(Body); setDoLoc(DL); @@ -2389,7 +2390,7 @@ void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const { return getDoLoc(); } - SourceLocation getEndLoc() const { return getRParenLoc(); } + SourceLocation getEndLoc() const { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == DoStmtClass; @@ -2482,10 +2483,11 @@ class GotoStmt : public Stmt { LabelDecl *Label; SourceLocation LabelLoc; + SourceLocation EndLoc; // Location of final ';' public: - GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL) - : Stmt(GotoStmtClass), Label(label), LabelLoc(LL) { + GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL, SourceLocation EL) + : Stmt(GotoStmtClass), Label(label), LabelLoc(LL), EndLoc(EL) { setGotoLoc(GL); } @@ -2501,7 +2503,7 @@ void setLabelLoc(SourceLocation L) { LabelLoc = L; } SourceLocation getBeginLoc() const { return getGotoLoc(); } - SourceLocation getEndLoc() const { return getLabelLoc(); } + SourceLocation getEndLoc() const { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GotoStmtClass; @@ -2568,8 +2570,9 @@ /// ContinueStmt - This represents a continue. class ContinueStmt : public Stmt { + SourceLocation EndLoc; // Location of final ';' public: - ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass) { + ContinueStmt(SourceLocation CL, SourceLocation EL) : Stmt(ContinueStmtClass), EndLoc(EL) { setContinueLoc(CL); } @@ -2580,7 +2583,7 @@ void setContinueLoc(SourceLocation L) { ContinueStmtBits.ContinueLoc = L; } SourceLocation getBeginLoc() const { return getContinueLoc(); } - SourceLocation getEndLoc() const { return getContinueLoc(); } + SourceLocation getEndLoc() const { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ContinueStmtClass; @@ -2598,8 +2601,9 @@ /// BreakStmt - This represents a break. class BreakStmt : public Stmt { + SourceLocation EndLoc; // Location of final ';' public: - BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass) { + BreakStmt(SourceLocation BL, SourceLocation EL) : Stmt(BreakStmtClass), EndLoc(EL) { setBreakLoc(BL); } @@ -2610,7 +2614,7 @@ void setBreakLoc(SourceLocation L) { BreakStmtBits.BreakLoc = L; } SourceLocation getBeginLoc() const { return getBreakLoc(); } - SourceLocation getEndLoc() const { return getBreakLoc(); } + SourceLocation getEndLoc() const { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == BreakStmtClass; @@ -2653,14 +2657,16 @@ } /// Build a return statement. - ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate); + ReturnStmt(SourceLocation RL, SourceLocation EL, Expr *E, + const VarDecl *NRVOCandidate); /// Build an empty return statement. explicit ReturnStmt(EmptyShell Empty, bool HasNRVOCandidate); + SourceLocation EndLoc; // Location of final ';' public: /// Create a return statement. - static ReturnStmt *Create(const ASTContext &Ctx, SourceLocation RL, Expr *E, + static ReturnStmt *Create(const ASTContext &Ctx, SourceLocation RL, SourceLocation EL, Expr *E, const VarDecl *NRVOCandidate); /// Create an empty return statement, optionally with @@ -2694,9 +2700,7 @@ void setReturnLoc(SourceLocation L) { ReturnStmtBits.RetLoc = L; } SourceLocation getBeginLoc() const { return getReturnLoc(); } - SourceLocation getEndLoc() const LLVM_READONLY { - return RetExpr ? RetExpr->getEndLoc() : getReturnLoc(); - } + SourceLocation getEndLoc() const LLVM_READONLY { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ReturnStmtClass; @@ -3337,10 +3341,11 @@ /// Represents a __leave statement. class SEHLeaveStmt : public Stmt { SourceLocation LeaveLoc; + SourceLocation EndLoc; // Location of final ';' public: - explicit SEHLeaveStmt(SourceLocation LL) - : Stmt(SEHLeaveStmtClass), LeaveLoc(LL) {} + explicit SEHLeaveStmt(SourceLocation LL, SourceLocation EL) + : Stmt(SEHLeaveStmtClass), LeaveLoc(LL), EndLoc(EL) {} /// Build an empty __leave statement. explicit SEHLeaveStmt(EmptyShell Empty) : Stmt(SEHLeaveStmtClass, Empty) {} @@ -3349,7 +3354,7 @@ void setLeaveLoc(SourceLocation L) { LeaveLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return LeaveLoc; } - SourceLocation getEndLoc() const LLVM_READONLY { return LeaveLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == SEHLeaveStmtClass; Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -1996,6 +1996,8 @@ /// A SmallVector of types. typedef SmallVector TypeVector; + SourceLocation consumeStatementEndingSemicolon(const char *SemiError); + StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr, ParsedStmtContext StmtCtx = ParsedStmtContext::SubStmt); Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4215,7 +4215,8 @@ Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, - Expr *Cond, SourceLocation CondRParen); + Expr *Cond, SourceLocation CondRParen, + SourceLocation EndLoc); StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -4260,14 +4261,15 @@ BuildForRangeKind Kind); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); - StmtResult ActOnGotoStmt(SourceLocation GotoLoc, - SourceLocation LabelLoc, - LabelDecl *TheDecl); + StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, + SourceLocation EndLoc, LabelDecl *TheDecl); StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, - Expr *DestExp); - StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); - StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); + SourceLocation EndLoc, Expr *DestExp); + StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, + SourceLocation EndLoc, Scope *CurScope); + StmtResult ActOnBreakStmt(SourceLocation BreakLoc, SourceLocation EndLoc, + Scope *CurScope); void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, unsigned NumParams); @@ -4298,10 +4300,12 @@ bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, CopyElisionSemanticsKind CESK); - StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, - Scope *CurScope); - StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); - StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); + StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, SourceLocation EndLoc, + Expr *RetValExp, Scope *CurScope); + StmtResult BuildReturnStmt(SourceLocation ReturnLoc, SourceLocation EndLoc, + Expr *RetValExp); + StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, + SourceLocation EndLoc, Expr *RetValExp); StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, @@ -4380,7 +4384,8 @@ void ActOnStartSEHFinallyBlock(); void ActOnAbortSEHFinallyBlock(); StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); - StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); + StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, SourceLocation EndLoc, + Scope *CurScope); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); @@ -9566,7 +9571,8 @@ StringRef Keyword); ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); - StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); + StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, + SourceLocation EndLoc, Expr *E); ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -6054,11 +6054,12 @@ auto ToDoLoc = importChecked(Err, S->getDoLoc()); auto ToWhileLoc = importChecked(Err, S->getWhileLoc()); auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); + auto ToEndLoc = importChecked(Err, S->getEndLoc()); if (Err) return std::move(Err); - return new (Importer.getToContext()) DoStmt( - ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc); + return new (Importer.getToContext()) + DoStmt(ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc, ToEndLoc); } ExpectedStmt ASTNodeImporter::VisitForStmt(ForStmt *S) { @@ -6087,11 +6088,12 @@ auto ToLabel = importChecked(Err, S->getLabel()); auto ToGotoLoc = importChecked(Err, S->getGotoLoc()); auto ToLabelLoc = importChecked(Err, S->getLabelLoc()); + auto ToEndLoc = importChecked(Err, S->getEndLoc()); if (Err) return std::move(Err); - return new (Importer.getToContext()) GotoStmt( - ToLabel, ToGotoLoc, ToLabelLoc); + return new (Importer.getToContext()) + GotoStmt(ToLabel, ToGotoLoc, ToLabelLoc, ToEndLoc); } ExpectedStmt ASTNodeImporter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { @@ -6108,17 +6110,22 @@ } ExpectedStmt ASTNodeImporter::VisitContinueStmt(ContinueStmt *S) { - ExpectedSLoc ToContinueLocOrErr = import(S->getContinueLoc()); - if (!ToContinueLocOrErr) - return ToContinueLocOrErr.takeError(); - return new (Importer.getToContext()) ContinueStmt(*ToContinueLocOrErr); + Error Err = Error::success(); + auto ToContinueLoc = importChecked(Err, S->getContinueLoc()); + auto ToEndLoc = importChecked(Err, S->getEndLoc()); + if (Err) + return std::move(Err); + return new (Importer.getToContext()) ContinueStmt(ToContinueLoc, ToEndLoc); } ExpectedStmt ASTNodeImporter::VisitBreakStmt(BreakStmt *S) { - auto ToBreakLocOrErr = import(S->getBreakLoc()); - if (!ToBreakLocOrErr) - return ToBreakLocOrErr.takeError(); - return new (Importer.getToContext()) BreakStmt(*ToBreakLocOrErr); + Error Err = Error::success(); + auto ToBreakLoc = importChecked(Err, S->getBreakLoc()); + auto ToEndLoc = importChecked(Err, S->getEndLoc()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) BreakStmt(ToBreakLoc, ToEndLoc); } ExpectedStmt ASTNodeImporter::VisitReturnStmt(ReturnStmt *S) { @@ -6127,11 +6134,12 @@ auto ToReturnLoc = importChecked(Err, S->getReturnLoc()); auto ToRetValue = importChecked(Err, S->getRetValue()); auto ToNRVOCandidate = importChecked(Err, S->getNRVOCandidate()); + auto ToEndLoc = importChecked(Err, S->getEndLoc()); if (Err) return std::move(Err); - return ReturnStmt::Create(Importer.getToContext(), ToReturnLoc, ToRetValue, - ToNRVOCandidate); + return ReturnStmt::Create(Importer.getToContext(), ToReturnLoc, ToEndLoc, + ToRetValue, ToNRVOCandidate); } ExpectedStmt ASTNodeImporter::VisitCXXCatchStmt(CXXCatchStmt *S) { Index: clang/lib/AST/Stmt.cpp =================================================================== --- clang/lib/AST/Stmt.cpp +++ clang/lib/AST/Stmt.cpp @@ -1076,8 +1076,9 @@ } // ReturnStmt -ReturnStmt::ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) - : Stmt(ReturnStmtClass), RetExpr(E) { +ReturnStmt::ReturnStmt(SourceLocation RL, SourceLocation EL, Expr *E, + const VarDecl *NRVOCandidate) + : Stmt(ReturnStmtClass), RetExpr(E), EndLoc(EL) { bool HasNRVOCandidate = NRVOCandidate != nullptr; ReturnStmtBits.HasNRVOCandidate = HasNRVOCandidate; if (HasNRVOCandidate) @@ -1091,11 +1092,12 @@ } ReturnStmt *ReturnStmt::Create(const ASTContext &Ctx, SourceLocation RL, - Expr *E, const VarDecl *NRVOCandidate) { + SourceLocation EL, Expr *E, + const VarDecl *NRVOCandidate) { bool HasNRVOCandidate = NRVOCandidate != nullptr; void *Mem = Ctx.Allocate(totalSizeToAlloc(HasNRVOCandidate), alignof(ReturnStmt)); - return new (Mem) ReturnStmt(RL, E, NRVOCandidate); + return new (Mem) ReturnStmt(RL, EL, E, NRVOCandidate); } ReturnStmt *ReturnStmt::CreateEmpty(const ASTContext &Ctx, Index: clang/lib/Analysis/BodyFarm.cpp =================================================================== --- clang/lib/Analysis/BodyFarm.cpp +++ clang/lib/Analysis/BodyFarm.cpp @@ -201,7 +201,8 @@ } ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { - return ReturnStmt::Create(C, SourceLocation(), const_cast(RetVal), + return ReturnStmt::Create(C, SourceLocation(), SourceLocation(), + const_cast(RetVal), /* NRVOCandidate=*/nullptr); } Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -1043,9 +1043,10 @@ // If there's a non-trivial 'get' expression, we just have to emit that. if (!hasTrivialGetExpr(propImpl)) { if (!AtomicHelperFn) { - auto *ret = ReturnStmt::Create(getContext(), SourceLocation(), - propImpl->getGetterCXXConstructor(), - /* NRVOCandidate=*/nullptr); + auto *ret = + ReturnStmt::Create(getContext(), SourceLocation(), SourceLocation(), + propImpl->getGetterCXXConstructor(), + /* NRVOCandidate=*/nullptr); EmitReturnStmt(*ret); } else { Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -148,19 +148,31 @@ }; } +SourceLocation Parser::consumeStatementEndingSemicolon(const char *SemiError) { + SourceLocation Loc; + // If we reached this code, the statement must end in a semicolon. + if (!TryConsumeToken(tok::semi, Loc)) { + // If the result was valid, then we do want to diagnose this. Use + // ExpectAndConsume to emit the diagnostic, even though we know it won't + // succeed. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError); + // Skip until we see a } or ;, but don't eat it. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + } + return Loc; +} + StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { - const char *SemiError = nullptr; - StmtResult Res; + StmtResult Res; //< deprecated SourceLocation GNUAttributeLoc; - // Cases in this switch statement should fall through if the parser expects - // the token to end in a semicolon (in which case SemiError should be set), - // or they directly 'return;' if not. Retry: tok::TokenKind Kind = Tok.getKind(); SourceLocation AtLoc; + + // Each case should return directly. switch (Kind) { case tok::at: // May be a @try or @throw statement { @@ -259,32 +271,26 @@ case tok::kw_while: // C99 6.8.5.1: while-statement return ParseWhileStatement(TrailingElseLoc); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(); - SemiError = "do/while"; - break; + return ParseDoStatement(); case tok::kw_for: // C99 6.8.5.3: for-statement return ParseForStatement(TrailingElseLoc); case tok::kw_goto: // C99 6.8.6.1: goto-statement Res = ParseGotoStatement(); - SemiError = "goto"; - break; + return Res; case tok::kw_continue: // C99 6.8.6.2: continue-statement Res = ParseContinueStatement(); - SemiError = "continue"; - break; + return Res; case tok::kw_break: // C99 6.8.6.3: break-statement Res = ParseBreakStatement(); - SemiError = "break"; - break; + return Res; case tok::kw_return: // C99 6.8.6.4: return-statement Res = ParseReturnStatement(); - SemiError = "return"; - break; + return Res; case tok::kw_co_return: // C++ Coroutines: co_return statement Res = ParseReturnStatement(); - SemiError = "co_return"; - break; + consumeStatementEndingSemicolon("co_return"); + return Res; case tok::kw_asm: { ProhibitAttributes(Attrs); @@ -292,8 +298,8 @@ Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); if (msAsm) return Res; - SemiError = "asm"; - break; + consumeStatementEndingSemicolon("asm"); + return Res; } case tok::kw___if_exists: @@ -313,8 +319,8 @@ case tok::kw___leave: Res = ParseSEHLeaveStatement(); - SemiError = "__leave"; - break; + consumeStatementEndingSemicolon("__leave"); + return Res; case tok::annot_pragma_vis: ProhibitAttributes(Attrs); @@ -409,16 +415,6 @@ return StmtEmpty(); } - // If we reached this code, the statement must end in a semicolon. - if (!TryConsumeToken(tok::semi) && !Res.isInvalid()) { - // If the result was valid, then we do want to diagnose this. Use - // ExpectAndConsume to emit the diagnostic, even though we know it won't - // succeed. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError); - // Skip until we see a } or ;, but don't eat it. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - } - return Res; } @@ -583,8 +579,9 @@ /// '__leave' ';' /// StmtResult Parser::ParseSEHLeaveStatement() { - SourceLocation LeaveLoc = ConsumeToken(); // eat the '__leave'. - return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope()); + const SourceLocation LeaveLoc = ConsumeToken(); // eat the '__leave'. + const SourceLocation EndLoc = consumeStatementEndingSemicolon("__leave"); + return Actions.ActOnSEHLeaveStmt(LeaveLoc, EndLoc, getCurScope()); } /// ParseLabeledStatement - We have an identifier and a ':' after it. @@ -1607,7 +1604,6 @@ /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' -/// Note: this lets the caller parse the end ';'. StmtResult Parser::ParseDoStatement() { assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -1643,7 +1639,7 @@ if (!Body.isInvalid()) { Diag(Tok, diag::err_expected_while); Diag(DoLoc, diag::note_matching) << "'do'"; - SkipUntil(tok::semi, StopBeforeMatch); + SkipUntil(tok::semi); } return StmtError(); } @@ -1651,7 +1647,7 @@ if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "do/while"; - SkipUntil(tok::semi, StopBeforeMatch); + SkipUntil(tok::semi); return StmtError(); } @@ -1672,8 +1668,10 @@ if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); + SourceLocation EndLoc = consumeStatementEndingSemicolon("do/while"); + return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(), - Cond.get(), T.getCloseLocation()); + Cond.get(), T.getCloseLocation(), EndLoc); } bool Parser::isForRangeIdentifier() { @@ -2058,9 +2056,6 @@ /// jump-statement: /// 'goto' identifier ';' /// [GNU] 'goto' '*' expression ';' -/// -/// Note: this lets the caller parse the end ';'. -/// StmtResult Parser::ParseGotoStatement() { assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. @@ -2069,8 +2064,10 @@ if (Tok.is(tok::identifier)) { LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), Tok.getLocation()); - Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD); ConsumeToken(); + const SourceLocation EndLoc = consumeStatementEndingSemicolon("goto"); + Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), EndLoc, LD); + } else if (Tok.is(tok::star)) { // GNU indirect goto extension. Diag(Tok, diag::ext_gnu_indirect_goto); @@ -2080,7 +2077,8 @@ SkipUntil(tok::semi, StopBeforeMatch); return StmtError(); } - Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.get()); + const SourceLocation EndLoc = consumeStatementEndingSemicolon("goto"); + Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, EndLoc, R.get()); } else { Diag(Tok, diag::err_expected) << tok::identifier; return StmtError(); @@ -2092,23 +2090,19 @@ /// ParseContinueStatement /// jump-statement: /// 'continue' ';' -/// -/// Note: this lets the caller parse the end ';'. -/// StmtResult Parser::ParseContinueStatement() { - SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. - return Actions.ActOnContinueStmt(ContinueLoc, getCurScope()); + const SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. + const SourceLocation EndLoc = consumeStatementEndingSemicolon("continue"); + return Actions.ActOnContinueStmt(ContinueLoc, EndLoc, getCurScope()); } /// ParseBreakStatement /// jump-statement: /// 'break' ';' -/// -/// Note: this lets the caller parse the end ';'. -/// StmtResult Parser::ParseBreakStatement() { - SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. - return Actions.ActOnBreakStmt(BreakLoc, getCurScope()); + const SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. + const SourceLocation EndLoc = consumeStatementEndingSemicolon("continue"); + return Actions.ActOnBreakStmt(BreakLoc, EndLoc, getCurScope()); } /// ParseReturnStatement @@ -2150,9 +2144,12 @@ return StmtError(); } } + + const SourceLocation EndLoc = consumeStatementEndingSemicolon("return"); + if (IsCoreturn) - return Actions.ActOnCoreturnStmt(getCurScope(), ReturnLoc, R.get()); - return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope()); + return Actions.ActOnCoreturnStmt(getCurScope(), ReturnLoc, EndLoc, R.get()); + return Actions.ActOnReturnStmt(ReturnLoc, EndLoc, R.get(), getCurScope()); } StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, Index: clang/lib/Sema/SemaCoroutine.cpp =================================================================== --- clang/lib/Sema/SemaCoroutine.cpp +++ clang/lib/Sema/SemaCoroutine.cpp @@ -844,12 +844,13 @@ return Res; } -StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) { +StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, + SourceLocation EndLoc, Expr *E) { if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) { CorrectDelayedTyposInExpr(E); return StmtError(); } - return BuildCoreturnStmt(Loc, E); + return BuildCoreturnStmt(Loc, /* EndLoc, */ E); } StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E, @@ -1101,8 +1102,8 @@ if (ReturnObjectOnAllocationFailure.isInvalid()) return false; - StmtResult ReturnStmt = - S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get()); + StmtResult ReturnStmt = S.BuildReturnStmt( + Loc, /*End*/ Loc, ReturnObjectOnAllocationFailure.get()); if (ReturnStmt.isInvalid()) { S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here) << DN; @@ -1482,7 +1483,7 @@ if (declRef.isInvalid()) return false; - StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get()); + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, /*End*/ Loc, declRef.get()); if (ReturnStmt.isInvalid()) { noteMemberDeclaredHere(S, ReturnValue, Fn); return false; Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -7698,7 +7698,7 @@ // Build the final return statement. if (RetVal.isInvalid()) return StmtError(); - StmtResult ReturnStmt = S.BuildReturnStmt(Loc, RetVal.get()); + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, /*End*/ Loc, RetVal.get()); if (ReturnStmt.isInvalid()) return StmtError(); Stmts.Stmts.push_back(ReturnStmt.get()); @@ -7770,7 +7770,7 @@ ExprResult False = S.ActOnCXXBoolLiteral(Loc, tok::kw_false); assert(!False.isInvalid() && "should never fail"); - StmtResult ReturnFalse = S.BuildReturnStmt(Loc, False.get()); + StmtResult ReturnFalse = S.BuildReturnStmt(Loc, /*End*/ Loc, False.get()); if (ReturnFalse.isInvalid()) return StmtError(); @@ -7924,7 +7924,7 @@ VDRef = getDecl(VD); if (VDRef.isInvalid()) return StmtError(); - StmtResult ReturnStmt = S.BuildReturnStmt(Loc, VDRef.get()); + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, /*End*/ Loc, VDRef.get()); if (ReturnStmt.isInvalid()) return StmtError(); @@ -13804,7 +13804,7 @@ // Add a "return *this;" ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); - StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); + StmtResult Return = BuildReturnStmt(Loc, /*End*/ Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; else @@ -14177,7 +14177,7 @@ ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); - StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); + StmtResult Return = BuildReturnStmt(Loc, /*End*/ Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; else @@ -14517,7 +14517,9 @@ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), VK_LValue, Conv->getLocation()); assert(FunctionRef && "Can't refer to __invoke function?"); - Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); + Stmt *Return = + BuildReturnStmt(Conv->getLocation(), Conv->getEndLoc(), FunctionRef) + .get(); Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(), Conv->getLocation())); Conv->markUsed(Context); @@ -14564,7 +14566,8 @@ // Create the return statement that returns the block from the conversion // function. - StmtResult Return = BuildReturnStmt(Conv->getLocation(), BuildBlock.get()); + StmtResult Return = + BuildReturnStmt(Conv->getLocation(), Conv->getEndLoc(), BuildBlock.get()); if (Return.isInvalid()) { Diag(CurrentLocation, diag::note_lambda_to_block_conv); Conv->setInvalidDecl(); Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -1332,10 +1332,10 @@ WhileLoc); } -StmtResult -Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, - SourceLocation WhileLoc, SourceLocation CondLParen, - Expr *Cond, SourceLocation CondRParen) { +StmtResult Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, + SourceLocation WhileLoc, SourceLocation CondLParen, + Expr *Cond, SourceLocation CondRParen, + SourceLocation EndLoc) { assert(Cond && "ActOnDoStmt(): missing expression"); CheckBreakContinueBinding(Cond); @@ -1354,7 +1354,7 @@ !Diags.isIgnored(diag::warn_comma_operator, Cond->getExprLoc())) CommaVisitor(*this).Visit(Cond); - return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen); + return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen, EndLoc); } namespace { @@ -2899,17 +2899,16 @@ return S; } -StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, - SourceLocation LabelLoc, - LabelDecl *TheDecl) { +StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, + SourceLocation EndLoc, LabelDecl *TheDecl) { setFunctionHasBranchIntoScope(); TheDecl->markUsed(Context); - return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc); + return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc, EndLoc); } -StmtResult -Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, - Expr *E) { +StmtResult Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + SourceLocation EndLoc, Expr *E) { // Convert operand to void* if (!E->isTypeDependent()) { QualType ETy = E->getType(); @@ -2942,8 +2941,8 @@ } } -StmtResult -Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { +StmtResult Sema::ActOnContinueStmt(SourceLocation ContinueLoc, + SourceLocation EndLoc, Scope *CurScope) { Scope *S = CurScope->getContinueParent(); if (!S) { // C99 6.8.6.2p1: A break shall appear only in or as a loop body. @@ -2951,11 +2950,11 @@ } CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S); - return new (Context) ContinueStmt(ContinueLoc); + return new (Context) ContinueStmt(ContinueLoc, EndLoc); } -StmtResult -Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { +StmtResult Sema::ActOnBreakStmt(SourceLocation BreakLoc, SourceLocation EndLoc, + Scope *CurScope) { Scope *S = CurScope->getBreakParent(); if (!S) { // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body. @@ -2966,7 +2965,7 @@ << "break"); CheckJumpOutOfSEHFinally(*this, BreakLoc, *S); - return new (Context) BreakStmt(BreakLoc); + return new (Context) BreakStmt(BreakLoc, EndLoc); } /// Determine whether the given expression is a candidate for @@ -3260,8 +3259,9 @@ /// ActOnCapScopeReturnStmt - Utility routine to type-check return statements /// for capturing scopes. /// -StmtResult -Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { +StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, + SourceLocation EndLoc, + Expr *RetValExp) { // If this is the first return we've seen, infer the return type. // [expr.prim.lambda]p4 in C++11; block literals follow the same rules. CapturingScopeInfo *CurCap = cast(getCurFunction()); @@ -3280,7 +3280,7 @@ return StmtError(); RetValExp = ER.get(); } - return ReturnStmt::Create(Context, ReturnLoc, RetValExp, + return ReturnStmt::Create(Context, ReturnLoc, EndLoc, RetValExp, /* NRVOCandidate=*/nullptr); } @@ -3409,7 +3409,7 @@ RetValExp = ER.get(); } auto *Result = - ReturnStmt::Create(Context, ReturnLoc, RetValExp, NRVOCandidate); + ReturnStmt::Create(Context, ReturnLoc, EndLoc, RetValExp, NRVOCandidate); // If we need to check for the named return value optimization, // or if we need to infer the return type, @@ -3576,15 +3576,15 @@ return false; } -StmtResult -Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, - Scope *CurScope) { +StmtResult Sema::ActOnReturnStmt(const SourceLocation ReturnLoc, + const SourceLocation EndLoc, + Expr *const RetValExp, Scope *const CurScope) { // Correct typos, in case the containing function returns 'auto' and // RetValExp should determine the deduced type. ExprResult RetVal = CorrectDelayedTyposInExpr(RetValExp); if (RetVal.isInvalid()) return StmtError(); - StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get()); + StmtResult R = BuildReturnStmt(ReturnLoc, EndLoc, RetVal.get()); if (R.isInvalid() || ExprEvalContexts.back().Context == ExpressionEvaluationContext::DiscardedStatement) return R; @@ -3601,13 +3601,14 @@ return R; } -StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { +StmtResult Sema::BuildReturnStmt(const SourceLocation ReturnLoc, + const SourceLocation EndLoc, Expr *RetValExp) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); if (isa(getCurFunction())) - return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); + return ActOnCapScopeReturnStmt(ReturnLoc, EndLoc, RetValExp); QualType FnRetType; QualType RelatedRetType; @@ -3652,7 +3653,7 @@ return StmtError(); RetValExp = ER.get(); } - return ReturnStmt::Create(Context, ReturnLoc, RetValExp, + return ReturnStmt::Create(Context, ReturnLoc, EndLoc, RetValExp, /* NRVOCandidate=*/nullptr); } @@ -3749,7 +3750,7 @@ } } - Result = ReturnStmt::Create(Context, ReturnLoc, RetValExp, + Result = ReturnStmt::Create(Context, ReturnLoc, EndLoc, RetValExp, /* NRVOCandidate=*/nullptr); } else if (!RetValExp && !HasDependentReturnType) { FunctionDecl *FD = getCurFunctionDecl(); @@ -3773,8 +3774,9 @@ else Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; - Result = ReturnStmt::Create(Context, ReturnLoc, /* RetExpr=*/nullptr, - /* NRVOCandidate=*/nullptr); + Result = + ReturnStmt::Create(Context, ReturnLoc, EndLoc, /* RetExpr=*/nullptr, + /* NRVOCandidate=*/nullptr); } else { assert(RetValExp || HasDependentReturnType); const VarDecl *NRVOCandidate = nullptr; @@ -3828,7 +3830,8 @@ return StmtError(); RetValExp = ER.get(); } - Result = ReturnStmt::Create(Context, ReturnLoc, RetValExp, NRVOCandidate); + Result = ReturnStmt::Create(Context, ReturnLoc, EndLoc, RetValExp, + NRVOCandidate); } // If we need to check for the named return value optimization, save the @@ -4236,8 +4239,8 @@ return SEHFinallyStmt::Create(Context, Loc, Block); } -StmtResult -Sema::ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope) { +StmtResult Sema::ActOnSEHLeaveStmt(SourceLocation Loc, SourceLocation EndLoc, + Scope *CurScope) { Scope *SEHTryParent = CurScope; while (SEHTryParent && !SEHTryParent->isSEHTryScope()) SEHTryParent = SEHTryParent->getParent(); @@ -4245,7 +4248,7 @@ return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try)); CheckJumpOutOfSEHFinally(*this, Loc, *SEHTryParent); - return new (Context) SEHLeaveStmt(Loc); + return new (Context) SEHLeaveStmt(Loc, EndLoc); } StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc, Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -1324,9 +1324,10 @@ /// Subclasses may override this routine to provide different behavior. StmtResult RebuildDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation LParenLoc, - Expr *Cond, SourceLocation RParenLoc) { - return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc, - Cond, RParenLoc); + Expr *Cond, SourceLocation RParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc, Cond, + RParenLoc, EndLoc); } /// Build a new for statement. @@ -1346,8 +1347,8 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, - LabelDecl *Label) { - return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label); + SourceLocation EndLoc, LabelDecl *Label) { + return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, EndLoc, Label); } /// Build a new indirect goto statement. @@ -1356,16 +1357,17 @@ /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, - Expr *Target) { - return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, Target); + SourceLocation EndLoc, Expr *Target) { + return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, EndLoc, Target); } /// Build a new return statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, Expr *Result) { - return getSema().BuildReturnStmt(ReturnLoc, Result); + StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, SourceLocation EndLoc, + Expr *Result) { + return getSema().BuildReturnStmt(ReturnLoc, EndLoc, Result); } /// Build a new declaration statement. @@ -7076,8 +7078,8 @@ return S; return getDerived().RebuildDoStmt(S->getDoLoc(), Body.get(), S->getWhileLoc(), - /*FIXME:*/S->getWhileLoc(), Cond.get(), - S->getRParenLoc()); + /*FIXME:*/ S->getWhileLoc(), Cond.get(), + S->getRParenLoc(), S->getEndLoc()); } template @@ -7139,7 +7141,7 @@ // Goto statements must always be rebuilt, to resolve the label. return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(), - cast(LD)); + S->getEndLoc(), cast(LD)); } template @@ -7155,7 +7157,7 @@ return S; return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(), - Target.get()); + S->getEndLoc(), Target.get()); } template @@ -7180,7 +7182,8 @@ // FIXME: We always rebuild the return statement because there is no way // to tell whether the return type of the function has changed. - return getDerived().RebuildReturnStmt(S->getReturnLoc(), Result.get()); + return getDerived().RebuildReturnStmt(S->getReturnLoc(), S->getEndLoc(), + Result.get()); } template