I'm reasonably confident this is a bug. The desired location isn't
available as far as I can tell. Moreover, I think I see where the bug
is.
In
clang/lib/Parse/ParseCXXInlineMethods.cpp
,
we have:
NamedDecl *Parser::ParseCXXInlineMethodDef(
[...]
if (TryConsumeToken(tok::equal)) {
[...]
if (TryConsumeToken(tok::kw_delete, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
DeclAsFunction->setRangeEnd(KWEndLoc); <============
}
} 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 */;
Actions.SetDeclDefaulted(FnD, KWLoc);
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
DeclAsFunction->setRangeEnd(KWEndLoc);
}
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
}
but in
clang/lib/Parse/Parser.cpp
,
we have what looks like a partial copy+paste:
Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
[...]
if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
if (TryConsumeToken(tok::kw_delete, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
BodyKind = Sema::FnBodyKind::Delete;
} 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;
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
}
The above is missing the setRangeEnd
call that the first block has.
I confirmed that adding the required updates fixes the bug, and filed this as Issue 64805.
Possible workaround: ad-hoc text search
In cases where the clang SourceLocation
information is missing or
inadequate, I've gotten reasonably good results by getting the raw
source from
SourceManager
::getBufferData
, turn SourceLocation
s into byte offsets with
the SourceManager::getFileOffset
method, and do ad-hoc text searches.
You could do something like that to recognize and skip the =delete
in this case.
Obviously it's not foolproof, since macros will mess things up, and
dealing with comments and preprocessor directives is annoying, but the
clang SourceLocation
also has some issues with macros when doing
source-to-source transformations so it's not like driving off a fidelity
cliff.
I'll also note that I have not had much luck trying to use the
Lexer
class
for this sort of thing, although it's of course possible I don't know
how to use it properly.
Update: OP has provided a nice example of using Lexer
to work around this problem. I stand corrected!