diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a6fc676f23a51..7d68821b71b8d 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/STLForwardCompat.h" #include "llvm/Support/Path.h" #include "llvm/Support/TimeProfiler.h" +#include "clang/Lex/Lexer.h" using namespace clang; @@ -1331,6 +1332,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, StringLiteral *DeletedMessage = nullptr; Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other; SourceLocation KWLoc; + SourceLocation FuncRangeEnd; if (TryConsumeToken(tok::equal)) { assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); @@ -1341,12 +1343,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, << 1 /* deleted */; BodyKind = Sema::FnBodyKind::Delete; DeletedMessage = ParseCXXDeletedFunctionMessage(); + FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, PP.getSourceManager(), getLangOpts()).getLocWithOffset(-1); + } else if (TryConsumeToken(tok::kw_default, KWLoc)) { Diag(KWLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_defaulted_deleted_function : diag::ext_defaulted_deleted_function) << 0 /* defaulted */; BodyKind = Sema::FnBodyKind::Default; + FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, PP.getSourceManager(), getLangOpts()).getLocWithOffset(-1); } else { llvm_unreachable("function definition after = not 'delete' or 'default'"); } @@ -1374,6 +1379,18 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, : MultiTemplateParamsArg(), &SkipBody, BodyKind); + auto updateFuncRangeEnd = [&](Decl *D) { + if (!FuncRangeEnd.isValid() || !D) + return; + if (auto *FD = dyn_cast(D)) { + FD->setRangeEnd(FuncRangeEnd); + } else if (auto *FT = dyn_cast(D)) { + if (auto *InnerFD = FT->getTemplatedDecl()) + InnerFD->setRangeEnd(FuncRangeEnd); + } + }; + + if (SkipBody.ShouldSkip) { // Do NOT enter SkipFunctionBody if we already consumed the tokens. if (BodyKind == Sema::FnBodyKind::Other) @@ -1390,6 +1407,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // and PopExpressionEvaluationContext(). if (!isLambdaCallOperator(dyn_cast_if_present(Res))) Actions.PopExpressionEvaluationContext(); + + updateFuncRangeEnd(Res); return Res; } @@ -1404,6 +1423,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind, DeletedMessage); Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); + updateFuncRangeEnd(Res); return Res; } @@ -1424,12 +1444,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) && trySkippingFunctionBody()) { BodyScope.Exit(); + updateFuncRangeEnd(Res); Actions.ActOnSkippedFunctionBody(Res); return Actions.ActOnFinishFunctionBody(Res, nullptr, false); } - if (Tok.is(tok::kw_try)) + if (Tok.is(tok::kw_try)){ + updateFuncRangeEnd(Res); return ParseFunctionTryBlock(Res, BodyScope); + } // If we have a colon, then we're probably parsing a C++ // ctor-initializer. @@ -1439,12 +1462,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Recover from error. if (!Tok.is(tok::l_brace)) { BodyScope.Exit(); + updateFuncRangeEnd(Res); Actions.ActOnFinishFunctionBody(Res, nullptr); return Res; } } else Actions.ActOnDefaultCtorInitializers(Res); + updateFuncRangeEnd(Res); return ParseFunctionStatementBody(Res, BodyScope); } diff --git a/clang/test/Parser/deleted_defaulted_func_range.cpp b/clang/test/Parser/deleted_defaulted_func_range.cpp new file mode 100644 index 0000000000000..bb85a9cf7c243 --- /dev/null +++ b/clang/test/Parser/deleted_defaulted_func_range.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s + +// CHECK: FunctionDecl {{.*}} <{{.*}}:4:1, col:17> {{.*}} +void f() = delete; + + +struct S { + inline S(); + ~S(); +}; + +//CHECK: CXXConstructorDecl {{.*}} <{{.*}}:13:1, col:23> {{.*}} +inline S::S() = default; +//CHECK: CXXDestructorDecl {{.*}} <{{.*}}:15:1, col:17> {{.*}} +S::~S() = default; + +template +class U { + U(); + ~U(); +}; + +//CHECK: CXXConstructorDecl {{.*}} <{{.*}}:24:1, line:25:19> {{.*}} +template +U::U() = default; +//CHECK: CXXDestructorDecl {{.*}} <{{.*}}:27:1, line:28:20> {{.*}} +template +U::~U() = default; \ No newline at end of file