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
