<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/64805>64805</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Source range of deleted or defaulted function outside class body is inaccurate
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          smcpeak
      </td>
    </tr>
</table>

<pre>
    ## Problem

For this translation unit:

```
void delfunc() = delete;
```

the source range of `delfunc` should cover the entire text to the final `e` in `delete`, but when using Clang 16.0.0 (and also a recent-ish trunk build from source), it does not:

```
$ clang -Xclang -ast-dump -fsyntax-only tmp.cc
[...]
`-FunctionDecl 0x5613b9a09b28 <tmp.cc:1:1, col:14> col:6 delfunc 'void ()' delete implicit-inline
 ^^ expecting 23 here
```

The same thing happens for methods defined outside their class body:

```
$ cat tmp3.cc
struct S {
  inline S();
};

inline S::S() = default;

$ clang -Xclang -ast-dump -fsyntax-only tmp3.cc
[...]
`-CXXConstructorDecl 0x557217b67278 parent 0x557217b66af0 prev 0x557217b66d28 <line:5:1, col:13> col:11 used S 'void ()' inline default
  `-CompoundStmt 0x557217b67368 <col:13>
```

where `col:13` should be `col:23`.

## Suspected origin

Commit 5f4d76efd365c (2015-03-23) addressed a similar issue for declarations in the class body in `ParseCXXInlineMethods.cpp`, but did not change the handling of those outside class bodies in `Parser.cpp`.

## Rough sketch of a fix

The following diff handles the simple testcases above.  However, it does not handle templates, and I don't know enough about the parser to fix that myself.  I also have not done any testing with real code.  So, this diff is merely evidence that something in this vicinity probably needs to change rather than a serious proposal for exactly how to change it.

```
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1354,6 +1359,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
   ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
 Scope::CompoundStmtScope);
 
+  // If this is set, we need to adjust the end location to account for
+  // the '= delete' or '= default'.
+  SourceLocation KWEndLoc_toUpdate;
+
   // Parse function body eagerly if it is either '= delete;' or '= default;' as
   // ActOnStartOfFunctionDef needs to know whether the function is deleted.
 Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other;
@@ -1361,18 +1370,21 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
   if (TryConsumeToken(tok::equal)) {
     assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
 
+    SourceLocation KWEndLoc = Tok.getEndLoc().getLocWithOffset(-1);
     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;
+      KWEndLoc_toUpdate = 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 */;
       BodyKind = Sema::FnBodyKind::Default;
+ KWEndLoc_toUpdate = KWEndLoc;
     } else {
 llvm_unreachable("function definition after = not 'delete' or 'default'");
     }
@@ -1398,6 +1410,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
 : MultiTemplateParamsArg(),
 &SkipBody, BodyKind);
 
+  if (KWEndLoc_toUpdate.isValid()) {
+    // TODO: This does not handle templates.
+    if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(Res)) {
+      DeclAsFunction->setRangeEnd(KWEndLoc_toUpdate);
+    }
+ }
+
   if (SkipBody.ShouldSkip) {
     // Do NOT enter SkipFunctionBody if we already consumed the tokens.
     if (BodyKind == Sema::FnBodyKind::Other)

```

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzcWF1T4zoS_TXipSspW47z8cBDSKB2auYuUxN2Z94o2WrHusiS15IJ-fdbLduJCQzLbtV9WQoSf0jdrXO6j1oI59TeIF6z9Ial2yvR-tI2167KaxRPV5mVx2vGE8YT-N7YTGPFoi2L1t3nnW3Al8qBb4RxWnhlDbRGeZasx-PYPOp_w-2zVRIk6qI1OeNLxlfAki09QY8suXl3UvfpSwRn2yZHaITZI9gC2DwajM0jcKVttYTcPiMFh4DGqwbB44sHb8OjQhmhaR7SDGV6E-R9HjG-gaz1cCjRQOuU2cNGC7OHeD6NphEwvhRGgtDOgoAGczR-olwJvmnNE2St0hKKxlZ9oIyvyKTyIC06MPY_oMP4DPLgcPKr_xbOT2Rb1TAp3NF48TKxRh_BV_U0z_tZ6c10OmXp9mRzcteanBjZYq4heknncZKtRLTK-BJYsulnJ-s4_PEN5FbT5Ywlt_31fKAJGF8E2jq-GF_0dIGqaq1y5SfKaGWwcw8svWXpLeBLjbknCHkCJTb4AbUPRK2okDLK7KEUdY3GQWEbqNCXVjqQWCiDEmzrnZI0ElVDYDkHlKqfAFZ4gi054eZ80-YedsAWfd4BdCuBXb_WU0Iutufr8HkamKxZst69yuVCtNpfjP-vqE0-4nbz69fGmi542wwMpwseL7L5gi-WUIsGjR89nYsigrrB5_Ez2eVCYC5ZpxeZkJwzIY6hdSgJqDeZ0MMwrLlHMYRpq9q2Ru58NQ5lkcyD25GbDxLjQIlD5k7Dz2WejV5wejF9jXdQrl3rKA0pcRq1V2Y8ZGOrSnlIi5lczLGQyTylZF_yKE4nUTIhCysQUjboaP0CnKqUFg0o51oM6Skx16IJ6udITUhizknZ68t30Tjc_Pr1JYD1R5fR07yuR5IjlSR9gLwM2kZ2SmGkpnqwBfjSOjwl_8mDQjf20fRG30Pih233Jbgn9HlJFgUU6uWyCAurtT2QT6mKoosAXYjGUbWTljqfC4cORGafcQrwN3vAZ2wuhK6fCx6rWguPjt6TeH4BaQ3jCw9Pxh4ATYhLZLb1wU8dFkJyXagX8KXwUB0d6mIK8KWT3lI8Y_AhrUEQ5hiioqgPypfQoNCQW0nB7Sz5DRtVWJFyUGGD-gj4rCSaHDsXzpLQkIlAonLwrHJllD9C3dhMZPoIBlE6CqznqBG-DBuNMJQb2CjbOhpeWyd0SA98EbnXRyjtYTRR-ekHWjWZTEAwfhdUgvE7rTLG7wK_w3fHc8_uTfcL2efnzCI2i2ASJ-mM8c0cGL-Jk5T2qjiC_m0QFsbX3eRO5sL1eW8pCCBFbC7pjTL7bV8OtgHG51vGN4MkQJi7y22NcGPlMVwxviSsiaLuPni5M90wtnj1mGyfXvRmR6_HetMbP-s3nMACYPyO8Tv4UnQ8KwcOPYVwwEAxESXkn63zfQ8hQdu8a3DoVZ7b1nii961RmsD4YtTS8AUEMBbjrYEvpqO5u9ArfBt8fP15a-Q3mz96-49ainFbxE_71OAwoApFT0knOij22OgjqIIKUjlAFRL1dWDJzfuxdc-Fu_S0zv292XnR-PtilALnqgjlfCixL4pRVFR8wamcDrxhJQayKRu-KiPhdEHhvDeiu78nB2dMTrk8p-0rXnbJvCBh5fFflcyqoI3ioTnSTtxW-GCfkGZ6-9QZx3-1Qoc9cjVuLwBAOIeNZ3y5R_9NmP197V23n04333Xr6I_8MU51ye-pJdj0JX5CVJ7CdZ0adiTSJ-e_S_zfZloA_ME-Tffouyd9QBSizX8qX94XRaiS5SR-ZR4-A8bT4XGohg18_Rnsv4MMwFaJPePLfsgGPoAojl_NvPxhyR1IshYCOIjGPOYvL6vlY26rWvjHPttR9pHJxwHbAbdkPTKALx9O4as3wbBkw5INxF35rIcCoCSkJycAP5n024sDUscnvBWLYGd4-ponttgCaoefJKyXqt8x9v_HVXTmqp_9hq3u59OcXRwE-M3_xtcZdK2fq8fWNCjyUmQaA9L8HVkAUXiS_GQbGiXGF5f70XkvupSM3velvq6Wp15hFpO8xslfI69E5x-t9uqh7x2_i0ZUbt3sh3PHaSSf755UTbBTCp7g_40Adnn_hoKpcv8UWsnB-ijL-zrrt8CH--09BfcQ2snfNbrTV1M7n6L1lgCiNa_dgEp3XDyax1w4z5LN-NRO5yK-_EF987shAby2NWHJrUP_gxrMW4Lg7TpfHWj7hZ1o5jevbi52ugHl6S6cvej2rX73KG0t_P3-AdBQAtLIIcSbcCIqqM8SukEhj5B3AiRDv-BJhgb4RjvLuNw-0xoMFf5ud30lrxO5SlbiCq_j-Yon81Wczq_Ka5lk0TJbypTzXGKU5Vk0w9k8iuJltkojcaWuecSTaBkv41nCk3Say1WBSZ7KSCZpIpdsFmEllJ5SlU5ts78K58Tr-WwZpVdaZKhd-Gcb5wYP3SGSai_dXjXXNGeStXvHZpFWzruzFa-8xuvdxb--hg0lHEIHvTopwZuT4pG6MGVEnreN8HjVNvq69L52hFwgbq982WbT3FZ0gNDPw9ekbuyfmHvG70LIjvG7sKR_BwAA__9Y_w7S">