https://github.com/Samhitha1212 created 
https://github.com/llvm/llvm-project/pull/167007

### Summary 
Fixes incorrect source range for default/delete function definations outside 
struct/class.

### Description
Previously, function and constructor definitions written outside the class body 
using '= delete' or '= default' had incorrect SourceRange end locations in the 
AST. This patch updates Parser.cpp to record the end location of the keyword 
token and apply it after Sema finalization.

Includes new tests under clang/test/Parser/deleted_defaulted_func_range.cpp

>From bc7eaa94dbfc0b413c2bdd7c47f4073757e134f0 Mon Sep 17 00:00:00 2001
From: ShravaniRamanolla <[email protected]>
Date: Fri, 7 Nov 2025 00:53:23 +0530
Subject: [PATCH 1/3] [clang][Parser] Fix FunctionDecl source range for
 out-of-class '= delete'/'= default' definitions

---
 clang/lib/Parse/Parser.cpp | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index a6fc676f23a51..446a74177ea36 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -26,6 +26,7 @@
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/TimeProfiler.h"
+#include "clang/Lex/Lexer.h"
 using namespace clang;
 
 
@@ -1331,6 +1332,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
   StringLiteral *DeletedMessage = nullptr;
   Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other;
   SourceLocation KWLoc;
+  SourceLocation FuncRangeEnd;
   if (TryConsumeToken(tok::equal)) {
     assert(getLangOpts().CPlusPlus && "Only C++ function definitions have 
'='");
 
@@ -1341,12 +1343,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
           << 1 /* deleted */;
       BodyKind = Sema::FnBodyKind::Delete;
       DeletedMessage = ParseCXXDeletedFunctionMessage();
+      FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, 
PP.getSourceManager(), getLangOpts());
+
     } 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;
+      FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, 
PP.getSourceManager(), getLangOpts());
     } else {
       llvm_unreachable("function definition after = not 'delete' or 
'default'");
     }
@@ -1374,6 +1379,18 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
                                                   : MultiTemplateParamsArg(),
                                               &SkipBody, BodyKind);
 
+  auto updateFuncRangeEnd = [&](Decl *D) {
+    if (!FuncRangeEnd.isValid() || !D)
+      return;
+    if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+      FD->setRangeEnd(FuncRangeEnd);
+    } else if (auto *FT = dyn_cast<FunctionTemplateDecl>(D)) {
+      if (auto *InnerFD = FT->getTemplatedDecl())
+        InnerFD->setRangeEnd(FuncRangeEnd);
+    }
+  };
+
+
   if (SkipBody.ShouldSkip) {
     // Do NOT enter SkipFunctionBody if we already consumed the tokens.
     if (BodyKind == Sema::FnBodyKind::Other)
@@ -1390,6 +1407,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
     // and PopExpressionEvaluationContext().
     if (!isLambdaCallOperator(dyn_cast_if_present<FunctionDecl>(Res)))
       Actions.PopExpressionEvaluationContext();
+
+      updateFuncRangeEnd(Res);
     return Res;
   }
 
@@ -1404,6 +1423,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
     Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind, DeletedMessage);
     Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
     Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
+    updateFuncRangeEnd(Res);
     return Res;
   }
 
@@ -1424,12 +1444,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
   if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
       trySkippingFunctionBody()) {
     BodyScope.Exit();
+    updateFuncRangeEnd(Res);
     Actions.ActOnSkippedFunctionBody(Res);
     return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
   }
 
-  if (Tok.is(tok::kw_try))
+  if (Tok.is(tok::kw_try)){
+    updateFuncRangeEnd(Res);
     return ParseFunctionTryBlock(Res, BodyScope);
+  }
 
   // If we have a colon, then we're probably parsing a C++
   // ctor-initializer.
@@ -1439,12 +1462,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
     // Recover from error.
     if (!Tok.is(tok::l_brace)) {
       BodyScope.Exit();
+      updateFuncRangeEnd(Res);
       Actions.ActOnFinishFunctionBody(Res, nullptr);
       return Res;
     }
   } else
     Actions.ActOnDefaultCtorInitializers(Res);
 
+  updateFuncRangeEnd(Res);
   return ParseFunctionStatementBody(Res, BodyScope);
 }
 

>From 5898d0804a68e0d32d4f6c36af1157f501882f85 Mon Sep 17 00:00:00 2001
From: Samhitha1212 <[email protected]>
Date: Fri, 7 Nov 2025 23:39:03 +0530
Subject: [PATCH 2/3] feat:Added testcase

---
 .../Parser/deleted_defaulted_func_range.cpp   | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 clang/test/Parser/deleted_defaulted_func_range.cpp

diff --git a/clang/test/Parser/deleted_defaulted_func_range.cpp 
b/clang/test/Parser/deleted_defaulted_func_range.cpp
new file mode 100644
index 0000000000000..bb85a9cf7c243
--- /dev/null
+++ b/clang/test/Parser/deleted_defaulted_func_range.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+
+// CHECK: FunctionDecl {{.*}} <{{.*}}:4:1, col:17> {{.*}}
+void f() = delete;
+
+
+struct S {
+  inline S();
+  ~S();
+};
+
+//CHECK: CXXConstructorDecl {{.*}} <{{.*}}:13:1, col:23> {{.*}}
+inline S::S() = default;
+//CHECK: CXXDestructorDecl {{.*}} <{{.*}}:15:1, col:17> {{.*}}
+S::~S() = default;
+
+template <typename T>
+class U {
+  U();
+  ~U();
+};
+
+//CHECK: CXXConstructorDecl {{.*}} <{{.*}}:24:1, line:25:19> {{.*}}
+template <typename T>
+U<T>::U() = default;
+//CHECK: CXXDestructorDecl {{.*}} <{{.*}}:27:1, line:28:20> {{.*}}
+template <typename T>
+U<T>::~U() = default;
\ No newline at end of file

>From cec4c3c1e4179ffc23c7992955474318b665f2f4 Mon Sep 17 00:00:00 2001
From: PoojithaGopu <[email protected]>
Date: Fri, 7 Nov 2025 23:50:46 +0530
Subject: [PATCH 3/3] fix: endlocation

---
 clang/lib/Parse/Parser.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 446a74177ea36..7d68821b71b8d 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1343,7 +1343,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
           << 1 /* deleted */;
       BodyKind = Sema::FnBodyKind::Delete;
       DeletedMessage = ParseCXXDeletedFunctionMessage();
-      FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, 
PP.getSourceManager(), getLangOpts());
+      FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, 
PP.getSourceManager(), getLangOpts()).getLocWithOffset(-1);
 
     } else if (TryConsumeToken(tok::kw_default, KWLoc)) {
       Diag(KWLoc, getLangOpts().CPlusPlus11
@@ -1351,7 +1351,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
                       : diag::ext_defaulted_deleted_function)
           << 0 /* defaulted */;
       BodyKind = Sema::FnBodyKind::Default;
-      FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, 
PP.getSourceManager(), getLangOpts());
+      FuncRangeEnd = clang::Lexer::getLocForEndOfToken(KWLoc, 0, 
PP.getSourceManager(), getLangOpts()).getLocWithOffset(-1);
     } else {
       llvm_unreachable("function definition after = not 'delete' or 
'default'");
     }

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

Reply via email to