Author: Shreyansh Lodha
Date: 2026-07-17T10:28:44-04:00
New Revision: 6f64e7cf0ad7699a5f1e6b2418d4c2cdcdb26470

URL: 
https://github.com/llvm/llvm-project/commit/6f64e7cf0ad7699a5f1e6b2418d4c2cdcdb26470
DIFF: 
https://github.com/llvm/llvm-project/commit/6f64e7cf0ad7699a5f1e6b2418d4c2cdcdb26470.diff

LOG: [Clang][AST] Add source range for deleted and defaulted functions (#205408)

Earlier wrong ranges for default and deleted functions were reported.
Post this fix all ranges for functions are reported.

Fix: Extended the declarator's source range to include the delete /
default tokens by calling
D.SetRangeEnd(PP.getLocForEndOfToken(KilLoc).getLocWithOffset(-1)) after
consuming each keyword in ParseFunctionDefinition. Previously, the range
ended at the function name, onitting the delete/default specifier
entirely.

Regression tested and no regressions found.


Assisted-by: Claude Code (Anthropic) — used in developing this patch.

Closes #64805

Added: 
    clang/test/AST/ast-dump-deleted-defaulted-range.cpp

Modified: 
    clang/lib/Parse/ParseCXXInlineMethods.cpp
    clang/lib/Parse/Parser.cpp
    clang/test/AST/ast-dump-decl.cpp
    clang/test/AST/ast-dump-funcs.cpp
    clang/test/AST/ast-dump-record-definition-data-json.cpp
    clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
    clang/test/CoverageMapping/default-method.cpp
    clang/unittests/AST/SourceLocationTest.cpp
    clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMethodDecl.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp 
b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 9949adf199fd2..be531e567046e 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -101,7 +101,6 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
 
     bool Delete = false;
     SourceLocation KWLoc;
-    SourceLocation KWEndLoc = Tok.getEndLoc().getLocWithOffset(-1);
     if (TryConsumeToken(tok::kw_delete, KWLoc)) {
       Diag(KWLoc, getLangOpts().CPlusPlus11
                       ? diag::warn_cxx98_compat_defaulted_deleted_function
@@ -111,7 +110,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
       Actions.SetDeclDeleted(FnD, KWLoc, Message);
       Delete = true;
       if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
-        DeclAsFunction->setRangeEnd(KWEndLoc);
+        DeclAsFunction->setRangeEnd(PrevTokLocation);
       }
     } else if (TryConsumeToken(tok::kw_default, KWLoc)) {
       Diag(KWLoc, getLangOpts().CPlusPlus11
@@ -120,7 +119,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
         << 0 /* defaulted */;
       Actions.SetDeclDefaulted(FnD, KWLoc);
       if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
-        DeclAsFunction->setRangeEnd(KWEndLoc);
+        DeclAsFunction->setRangeEnd(PrevTokLocation);
       }
     } else {
       llvm_unreachable("function definition after = not 'delete' or 
'default'");

diff  --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index f30cd68bf1e6c..6a21acd9dc4ef 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1307,12 +1307,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
           << 1 /* deleted */;
       BodyKind = Sema::FnBodyKind::Delete;
       DeletedMessage = ParseCXXDeletedFunctionMessage();
+      D.SetRangeEnd(PrevTokLocation);
     } 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;
+      D.SetRangeEnd(PrevTokLocation);
     } else {
       llvm_unreachable("function definition after = not 'delete' or 
'default'");
     }

diff  --git a/clang/test/AST/ast-dump-decl.cpp 
b/clang/test/AST/ast-dump-decl.cpp
index 15c2e4e07e95c..ef5e0a55e431e 100644
--- a/clang/test/AST/ast-dump-decl.cpp
+++ b/clang/test/AST/ast-dump-decl.cpp
@@ -201,12 +201,12 @@ void SomeFunction() {
   A = static_cast<TestMemberRanges &&>(B);
   TestMemberRanges C(static_cast<TestMemberRanges &&>(A));
 }
-// CHECK:      CXXConstructorDecl{{.*}} <line:{{.*}}:3, col:30>
-// CHECK:      CXXConstructorDecl{{.*}} <line:{{.*}}:3, col:59>
-// CHECK:      CXXConstructorDecl{{.*}} <line:{{.*}}:3, col:54>
-// CHECK:      CXXDestructorDecl{{.*}} <line:{{.*}}:3, col:31>
-// CHECK:      CXXMethodDecl{{.*}} <line:{{.*}}:3, col:70>
-// CHECK:      CXXMethodDecl{{.*}} <line:{{.*}}:3, col:65>
+// CHECK:      CXXConstructorDecl{{.*}} <line:{{.*}}:3, col:24>
+// CHECK:      CXXConstructorDecl{{.*}} <line:{{.*}}:3, col:53>
+// CHECK:      CXXConstructorDecl{{.*}} <line:{{.*}}:3, col:48>
+// CHECK:      CXXDestructorDecl{{.*}} <line:{{.*}}:3, col:25>
+// CHECK:      CXXMethodDecl{{.*}} <line:{{.*}}:3, col:64>
+// CHECK:      CXXMethodDecl{{.*}} <line:{{.*}}:3, col:59>
 
 class TestCXXConversionDecl {
   operator int() { return 0; }

diff  --git a/clang/test/AST/ast-dump-deleted-defaulted-range.cpp 
b/clang/test/AST/ast-dump-deleted-defaulted-range.cpp
new file mode 100644
index 0000000000000..0e6872d88a350
--- /dev/null
+++ b/clang/test/AST/ast-dump-deleted-defaulted-range.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+
+void delfunc() = delete;
+// CHECK: FunctionDecl{{.*}} <{{.*}}[[@LINE-1]]:1, col:18> col:6 delfunc 'void 
()' delete
+
+struct S {
+  inline S();
+};
+
+inline S::S() = default;
+// CHECK: CXXConstructorDecl{{.*}} <line:[[@LINE-1]]:1, col:17>{{.*}}S 'void 
()' inline default
+
+struct v {
+  void f() = delete;
+};
+// CHECK: CXXMethodDecl{{.*}} <line:[[@LINE-2]]:3, col:14> col:8 f 'void ()' 
delete
+
+template <class T> void bubbleSort(T a[], int n) = delete;
+// CHECK: FunctionTemplateDecl{{.*}} <line:[[@LINE-1]]:1, col:52> col:25 
bubbleSort
+
+template <typename T> class Array {
+public:
+    Array(T arr[], int s);
+    void print() = delete;
+};
+// CHECK: CXXMethodDecl{{.*}} <line:[[@LINE-2]]:5, col:20> col:10 print 'void 
()' delete
+
+void delfunc2() = delete("reason");
+// CHECK: FunctionDecl{{.*}} <{{.*}}[[@LINE-1]]:1, col:34> col:6 delfunc2 
'void ()' delete
+
+struct w {
+  void g() = delete("reason");
+};
+// CHECK: CXXMethodDecl{{.*}} <line:[[@LINE-2]]:3, col:29> col:8 g 'void ()' 
delete

diff  --git a/clang/test/AST/ast-dump-funcs.cpp 
b/clang/test/AST/ast-dump-funcs.cpp
index 61fb5d4eb654e..5779ab7271900 100644
--- a/clang/test/AST/ast-dump-funcs.cpp
+++ b/clang/test/AST/ast-dump-funcs.cpp
@@ -10,13 +10,13 @@
 
 struct R {
   R() = default;
-  // CHECK: CXXConstructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:15> col:3 
used constexpr R 'void () noexcept' default trivial
+  // CHECK: CXXConstructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:9> col:3 
used constexpr R 'void () noexcept' default trivial
   ~R() {} // not trivial
   // CHECK: CXXDestructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:9> col:3 
used ~R 'void () noexcept'
   R(const R&) = delete;
-  // CHECK: CXXConstructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:22> col:3 
R 'void (const R &)' delete trivial
+  // CHECK: CXXConstructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:17> col:3 
R 'void (const R &)' delete trivial
   R(R&&) = default;
-  // CHECK: CXXConstructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:18> col:3 
constexpr R 'void (R &&)' default trivial noexcept-unevaluated
+  // CHECK: CXXConstructorDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:12> col:3 
constexpr R 'void (R &&)' default trivial noexcept-unevaluated
 
   // CHECK: CXXMethodDecl 0x{{[^ ]*}} <line:[[@LINE-10]]:8> col:8 implicit 
operator= 'R &(const R &)' inline default_delete trivial noexcept-unevaluated
 };

diff  --git a/clang/test/AST/ast-dump-record-definition-data-json.cpp 
b/clang/test/AST/ast-dump-record-definition-data-json.cpp
index d8ff6e980fb94..978b9e34f7b24 100644
--- a/clang/test/AST/ast-dump-record-definition-data-json.cpp
+++ b/clang/test/AST/ast-dump-record-definition-data-json.cpp
@@ -837,9 +837,9 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "tokLen": 18
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "end": {
-// CHECK-NEXT:      "offset": 289,
-// CHECK-NEXT:      "col": 57,
-// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:      "offset": 283,
+// CHECK-NEXT:      "col": 51,
+// CHECK-NEXT:      "tokLen": 7
 // CHECK-NEXT:     }
 // CHECK-NEXT:    },
 // CHECK-NEXT:    "name": "CanPassInRegisters",
@@ -980,9 +980,9 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "tokLen": 19
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "end": {
-// CHECK-NEXT:      "offset": 382,
-// CHECK-NEXT:      "col": 58,
-// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:      "offset": 377,
+// CHECK-NEXT:      "col": 53,
+// CHECK-NEXT:      "tokLen": 6
 // CHECK-NEXT:     }
 // CHECK-NEXT:    },
 // CHECK-NEXT:    "name": "CantPassInRegisters",
@@ -2547,9 +2547,9 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "tokLen": 9
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "end": {
-// CHECK-NEXT:      "offset": 847,
-// CHECK-NEXT:      "col": 23,
-// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:      "offset": 841,
+// CHECK-NEXT:      "col": 17,
+// CHECK-NEXT:      "tokLen": 7
 // CHECK-NEXT:     }
 // CHECK-NEXT:    },
 // CHECK-NEXT:    "name": "IsTrivial",
@@ -3747,9 +3747,9 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "tokLen": 1
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "end": {
-// CHECK-NEXT:      "offset": 1126,
-// CHECK-NEXT:      "col": 24,
-// CHECK-NEXT:      "tokLen": 1
+// CHECK-NEXT:      "offset": 1120,
+// CHECK-NEXT:      "col": 18,
+// CHECK-NEXT:      "tokLen": 7
 // CHECK-NEXT:     }
 // CHECK-NEXT:    },
 // CHECK-NEXT:    "name": "~IsLiteral",

diff  --git 
a/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist 
b/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
index 62aaf0fe8e2d5..d93a1715491bc 100644
--- a/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
+++ b/clang/test/Analysis/inlining/Inputs/expected-plists/path-notes.cpp.plist
@@ -2223,7 +2223,7 @@
          <array>
           <dict>
            <key>line</key><integer>105</integer>
-           <key>col</key><integer>63</integer>
+           <key>col</key><integer>57</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
@@ -2240,7 +2240,7 @@
      <key>location</key>
      <dict>
       <key>line</key><integer>105</integer>
-      <key>col</key><integer>63</integer>
+      <key>col</key><integer>57</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -2248,7 +2248,7 @@
        <array>
         <dict>
          <key>line</key><integer>105</integer>
-         <key>col</key><integer>63</integer>
+         <key>col</key><integer>57</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>

diff  --git a/clang/test/CoverageMapping/default-method.cpp 
b/clang/test/CoverageMapping/default-method.cpp
index beaac0db2fc78..43db31f2110c6 100644
--- a/clang/test/CoverageMapping/default-method.cpp
+++ b/clang/test/CoverageMapping/default-method.cpp
@@ -11,7 +11,7 @@ namespace PR39822 {
   };
 
   // CHECK: _ZN7PR398223fooaSERS0_:
-  // CHECK-NEXT: File 0, [[@LINE+1]]:28 -> [[@LINE+1]]:29 = #0
+  // CHECK-NEXT: File 0, [[@LINE+1]]:32 -> [[@LINE+1]]:39 = #0
   foo &foo::operator=(foo &) = default;
 } // namespace PR39822
 

diff  --git a/clang/unittests/AST/SourceLocationTest.cpp 
b/clang/unittests/AST/SourceLocationTest.cpp
index 5b461d1cf4400..7bd0de04b2582 100644
--- a/clang/unittests/AST/SourceLocationTest.cpp
+++ b/clang/unittests/AST/SourceLocationTest.cpp
@@ -353,13 +353,13 @@ TEST(CXXConstructorDecl, NoRetFunTypeLocRange) {
 
 TEST(CXXConstructorDecl, DefaultedCtorLocRange) {
   RangeVerifier<CXXConstructorDecl> Verifier;
-  Verifier.expectRange(1, 11, 1, 23);
+  Verifier.expectRange(1, 11, 1, 17);
   EXPECT_TRUE(Verifier.match("class C { C() = default; };", functionDecl()));
 }
 
 TEST(CXXConstructorDecl, DeletedCtorLocRange) {
   RangeVerifier<CXXConstructorDecl> Verifier;
-  Verifier.expectRange(1, 11, 1, 22);
+  Verifier.expectRange(1, 11, 1, 17);
   EXPECT_TRUE(Verifier.match("class C { C() = delete; };", functionDecl()));
 }
 

diff  --git 
a/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMethodDecl.cpp 
b/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMethodDecl.cpp
index 1eeb3df81a316..0d155dbfcc74c 100644
--- a/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMethodDecl.cpp
+++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMethodDecl.cpp
@@ -34,9 +34,9 @@ TEST(RecursiveASTVisitor, CXXMethodDeclNoDefaultBodyVisited) {
   for (bool VisitImplCode : {false, true}) {
     CXXMethodDeclVisitor Visitor(VisitImplCode);
     if (VisitImplCode)
-      Visitor.ExpectMatch("declref", 8, 28);
+      Visitor.ExpectMatch("declref", 8, 32);
     else
-      Visitor.DisallowMatch("declref", 8, 28);
+      Visitor.DisallowMatch("declref", 8, 32);
 
     Visitor.ExpectMatch("parm", 8, 27);
     llvm::StringRef Code = R"cpp(
@@ -56,9 +56,9 @@ TEST(RecursiveASTVisitor, FunctionDeclNoDefaultBodyVisited) {
   for (bool VisitImplCode : {false, true}) {
     CXXMethodDeclVisitor Visitor(VisitImplCode);
     if (VisitImplCode)
-      Visitor.ExpectMatch("declref", 4, 58, /*Times=*/2);
+      Visitor.ExpectMatch("declref", 4, 52, /*Times=*/2);
     else
-      Visitor.DisallowMatch("declref", 4, 58);
+      Visitor.DisallowMatch("declref", 4, 52);
     llvm::StringRef Code = R"cpp(
       struct s {
         int x;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to