Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down Expand Up @@ -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 '='");

Expand All @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= delete("reason") (C++26 feature) is not handled correctly.


} 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'");
}
Expand Down Expand Up @@ -1374,6 +1379,18 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
: MultiTemplateParamsArg(),
&SkipBody, BodyKind);

auto updateFuncRangeEnd = [&](Decl *D) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!FuncRangeEnd.isValid() || !D)
return;
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
FD->setRangeEnd(FuncRangeEnd);
} else if (auto *FT = dyn_cast<FunctionTemplateDecl>(D)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ActOnStartOfFunctionDef always returns FunctionDecl * or FunctionTemplateDecl *. You don't need to call dyn_cast.

if (auto *InnerFD = FT->getTemplatedDecl())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getTemplatedDecl should never return nullptr. Use assert instead if you still want to check the return value.

InnerFD->setRangeEnd(FuncRangeEnd);
}
};


if (SkipBody.ShouldSkip) {
// Do NOT enter SkipFunctionBody if we already consumed the tokens.
if (BodyKind == Sema::FnBodyKind::Other)
Expand All @@ -1390,6 +1407,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// and PopExpressionEvaluationContext().
if (!isLambdaCallOperator(dyn_cast_if_present<FunctionDecl>(Res)))
Actions.PopExpressionEvaluationContext();

updateFuncRangeEnd(Res);
return Res;
}

Expand All @@ -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;
}

Expand All @@ -1424,12 +1444,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
trySkippingFunctionBody()) {
BodyScope.Exit();
updateFuncRangeEnd(Res);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to call updateFuncRangeEnd here? Could you give an example?

Actions.ActOnSkippedFunctionBody(Res);
return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
}

if (Tok.is(tok::kw_try))
if (Tok.is(tok::kw_try)){
updateFuncRangeEnd(Res);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

return ParseFunctionTryBlock(Res, BodyScope);
}

// If we have a colon, then we're probably parsing a C++
// ctor-initializer.
Expand All @@ -1439,12 +1462,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Recover from error.
if (!Tok.is(tok::l_brace)) {
BodyScope.Exit();
updateFuncRangeEnd(Res);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Actions.ActOnFinishFunctionBody(Res, nullptr);
return Res;
}
} else
Actions.ActOnDefaultCtorInitializers(Res);

updateFuncRangeEnd(Res);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

return ParseFunctionStatementBody(Res, BodyScope);
}

Expand Down
28 changes: 28 additions & 0 deletions clang/test/Parser/deleted_defaulted_func_range.cpp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should be in "clang/test/AST/" folder.

Original file line number Diff line number Diff line change
@@ -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 <typename T>
class U {
U();
~U();
};

//CHECK: CXXConstructorDecl {{.*}} <{{.*}}:24:1, line:25:19> {{.*}}
template <typename T>
U<T>::U() = default;
Comment on lines +23 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verifying line numbers is brittle. Other people may add something before this line. Ditto elsewhere.

You might consider writing code in one line.

template ... = default;

//CHECK: CXXDestructorDecl {{.*}} <{{.*}}:27:1, line:28:20> {{.*}}
template <typename T>
U<T>::~U() = default;
Loading