[clang] 6f64e7c - [Clang][AST] Add source range for deleted and defaulted functions (#205408)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 17 07:28:49 PDT 2026
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;
More information about the cfe-commits
mailing list