[clang] [LifetimeSafety] Replace `getCrossTUDecl` with `getCanonicalDeclForAttr` (PR #198784)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 20 06:34:58 PDT 2026
https://github.com/NeKon69 created https://github.com/llvm/llvm-project/pull/198784
With this patch, we suggest adding the `clang::lifetimebound` attribute on the canonical declaration instead of first trying to find a redeclaration of the function in another file and falling back to the definition when none is found.
Fixes #198624
>From f95dcf6ef9be88c85f4a94735e93077046ecfe68 Mon Sep 17 00:00:00 2001
From: NeKon69 <nobodqwe at gmail.com>
Date: Wed, 20 May 2026 16:30:14 +0300
Subject: [PATCH] remove function
---
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 57 ++++---------------
.../test/Sema/warn-lifetime-safety-fixits.cpp | 9 ++-
.../Sema/warn-lifetime-safety-suggestions.cpp | 24 ++++----
3 files changed, 27 insertions(+), 63 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index d6a15139aa4ea..4b9d195411179 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -353,66 +353,31 @@ class LifetimeChecker {
Scope};
}
- /// Returns the declaration of a function that is visible across translation
- /// units, if such a declaration exists and is different from the definition.
- static const FunctionDecl *getCrossTUDecl(const FunctionDecl &FD,
- SourceManager &SM) {
- if (!FD.isExternallyVisible())
- return nullptr;
- const FileID DefinitionFile = SM.getFileID(FD.getLocation());
- for (const FunctionDecl *Redecl : FD.redecls())
- if (SM.getFileID(Redecl->getLocation()) != DefinitionFile)
- return Redecl;
-
- return nullptr;
- }
-
- static const FunctionDecl *getCrossTUDecl(const ParmVarDecl &PVD,
- SourceManager &SM) {
- if (const auto *FD = dyn_cast<FunctionDecl>(PVD.getDeclContext()))
- return getCrossTUDecl(*FD, SM);
- return nullptr;
- }
-
- static void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *SemaHelper,
- const ParmVarDecl *PVD,
- SourceManager &SM,
- EscapingTarget EscapeTarget) {
+ void suggestWithScopeForParmVar(const ParmVarDecl *PVD,
+ EscapingTarget EscapeTarget) {
if (llvm::isa<const VarDecl *>(EscapeTarget))
return;
- if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
- SemaHelper->suggestLifetimeboundToParmVar(
- WarningScope::CrossTU,
- CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
- EscapeTarget);
- else
- SemaHelper->suggestLifetimeboundToParmVar(WarningScope::IntraTU, PVD,
- EscapeTarget);
+ auto [Parm, Scope] = getCanonicalDeclForAttr(cast<FunctionDecl>(FD), PVD);
+ SemaHelper->suggestLifetimeboundToParmVar(Scope, Parm, EscapeTarget);
}
- static void
- suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *SemaHelper,
- const CXXMethodDecl *MD, SourceManager &SM,
- const Expr *EscapeExpr) {
- if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
- SemaHelper->suggestLifetimeboundToImplicitThis(
- WarningScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl), EscapeExpr);
- else
- SemaHelper->suggestLifetimeboundToImplicitThis(WarningScope::IntraTU, MD,
- EscapeExpr);
+ void suggestWithScopeForImplicitThis(const CXXMethodDecl *MD,
+ const Expr *EscapeExpr) {
+ auto [MethodDecl, Scope] = getCanonicalDeclForAttr(MD);
+ SemaHelper->suggestLifetimeboundToImplicitThis(Scope, MethodDecl,
+ EscapeExpr);
}
void suggestAnnotations() {
if (!SemaHelper)
return;
- SourceManager &SM = AST.getSourceManager();
for (auto [Target, EscapeTarget] : AnnotationWarningsMap) {
if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
- suggestWithScopeForParmVar(SemaHelper, PVD, SM, EscapeTarget);
+ suggestWithScopeForParmVar(PVD, EscapeTarget);
else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
if (const auto *EscapeExpr = EscapeTarget.dyn_cast<const Expr *>())
- suggestWithScopeForImplicitThis(SemaHelper, MD, SM, EscapeExpr);
+ suggestWithScopeForImplicitThis(MD, EscapeExpr);
else
llvm_unreachable("Implicit this can only escape via Expr (return)");
}
diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
index 88d8bd379de8b..d9c7e8d3f0519 100644
--- a/clang/test/Sema/warn-lifetime-safety-fixits.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
@@ -69,12 +69,11 @@ int *arr_default(int a[2] = nullptr) {
return a;
}
-// FIXME: Iterate over redecls and add [[clang::lifetimebound]]
View multi_decl(View a);
+// CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked
+// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
View multi_decl(View a);
View multi_decl(View a) {
- // CHECK: :[[@LINE-1]]:17: warning: parameter in intra-TU function should be marked
- // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
return a;
}
@@ -145,10 +144,10 @@ struct OutOfLine {
OutOfLine() {}
~OutOfLine() {}
const OutOfLine &get() const;
+ // CHECK: :[[@LINE-1]]:31: warning: implicit this in intra-TU function should be marked
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:31-[[@LINE-2]]:31}:" {{\[\[}}clang::lifetimebound]]"
};
const OutOfLine &OutOfLine::get() const {
- // CHECK: :[[@LINE-1]]:40: warning: implicit this in intra-TU function should be marked
- // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:40-[[@LINE-2]]:40}:" {{\[\[}}clang::lifetimebound]]"
return *this;
}
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 973c610eb58ab..5122e634e594f 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -46,8 +46,8 @@ inline View inline_header_return_view(View a) { // expected-warning {{parameter
return a; // expected-note {{param returned here}}
}
-View redeclared_in_header(View a);
-inline View redeclared_in_header(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+View redeclared_in_header(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+inline View redeclared_in_header(View a) {
return a; // expected-note {{param returned here}}
}
@@ -177,8 +177,8 @@ View reassigned_to_another_parameter(
return a; // expected-note {{param returned here}}
}
-View intra_tu_func_redecl(View a);
-View intra_tu_func_redecl(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View intra_tu_func_redecl(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View intra_tu_func_redecl(View a) {
return a; // expected-note {{param returned here}}
}
}
@@ -282,25 +282,25 @@ MyObj* return_pointer_by_func(MyObj* a) { // expected-warning {{paramete
} // namespace correct_order_inference
namespace incorrect_order_inference_view {
-View return_view_callee(View a);
+View return_view_callee(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
View return_view_caller(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
return return_view_callee(a); // expected-note {{param returned here}}
}
-View return_view_callee(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View return_view_callee(View a) {
return a; // expected-note {{param returned here}}
}
} // namespace incorrect_order_inference_view
namespace incorrect_order_inference_object {
-MyObj* return_object_callee(MyObj* a);
+MyObj* return_object_callee(MyObj* a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
MyObj* return_object_caller(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
return return_object_callee(a); // expected-note {{param returned here}}
}
-MyObj* return_object_callee(MyObj* a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+MyObj* return_object_callee(MyObj* a) {
return a; // expected-note {{param returned here}}
}
} // namespace incorrect_order_inference_object
@@ -322,13 +322,13 @@ View inference_top_level_return_stack_view() {
} // namespace simple_annotation_inference
namespace inference_in_order_with_redecls {
-View inference_callee_return_identity(View a);
-View inference_callee_return_identity(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_callee_return_identity(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_callee_return_identity(View a) {
return a; // expected-note {{param returned here}}
}
-View inference_caller_forwards_callee(View a);
-View inference_caller_forwards_callee(View a) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_caller_forwards_callee(View a); // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
+View inference_caller_forwards_callee(View a) {
return inference_callee_return_identity(a); // expected-note {{param returned here}}
}
More information about the cfe-commits
mailing list