[clang] c22474f - [LifetimeSafety] Prevent false-negative lifetimebound verification when origin escapes in an unrelated manner (#200786)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 2 00:08:24 PDT 2026
Author: Abhinav Pradeep
Date: 2026-06-02T09:08:18+02:00
New Revision: c22474fc02c1c26c81577d4cc147ed3b7c04a079
URL: https://github.com/llvm/llvm-project/commit/c22474fc02c1c26c81577d4cc147ed3b7c04a079
DIFF: https://github.com/llvm/llvm-project/commit/c22474fc02c1c26c81577d4cc147ed3b7c04a079.diff
LOG: [LifetimeSafety] Prevent false-negative lifetimebound verification when origin escapes in an unrelated manner (#200786)
This PR removes a false-negative `[[lifetimebound]]` verification result
that occurs when the annotated attribute escapes via unrelated origin
escape kinds (escape through global, escape through field).
Change summary:
- `Checker.cpp` has function `checkAnnotations` which checks if an
escaping `Origin` was an annotated parameter. Modified the logic there
to only verify `[[lifetimebound]]` in the case that the escape was
through a return statement.
Fixes #200412
---------
Signed-off-by: Abhinav Pradeep <abhinav.pradeep at oracle.com>
Added:
Modified:
clang/lib/Analysis/LifetimeSafety/Checker.cpp
clang/test/Sema/warn-lifetime-safety-lifetimebound.cpp
Removed:
################################################################################
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index d6d4ec6b5617e..2a71b5eb9a934 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -134,7 +134,8 @@ class LifetimeChecker {
return;
if (PVD->hasAttr<LifetimeBoundAttr>()) {
// Track that this lifetimebound parameter correctly escapes.
- VerifiedLiftimeboundEscapes.insert(PVD);
+ if (isa<ReturnEscapeFact>(OEF))
+ VerifiedLiftimeboundEscapes.insert(PVD);
} else {
// Otherwise, suggest lifetimebound for parameter escaping through
// return or a field in constructor.
@@ -148,10 +149,12 @@ class LifetimeChecker {
// field!
};
auto CheckImplicitThis = [&](const CXXMethodDecl *MD) {
- if (implicitObjectParamIsLifetimeBound(MD))
- VerifiedLiftimeboundEscapes.insert(MD);
- else if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
- AnnotationWarningsMap.try_emplace(MD, ReturnEsc->getReturnExpr());
+ if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF)) {
+ if (implicitObjectParamIsLifetimeBound(MD))
+ VerifiedLiftimeboundEscapes.insert(MD);
+ else
+ AnnotationWarningsMap.try_emplace(MD, ReturnEsc->getReturnExpr());
+ }
};
auto MovedAtEscape = MovedLoans.getMovedLoans(OEF);
for (LoanID LID : EscapedLoans) {
diff --git a/clang/test/Sema/warn-lifetime-safety-lifetimebound.cpp b/clang/test/Sema/warn-lifetime-safety-lifetimebound.cpp
index 5e22677f5269d..b0320bcbf4334 100644
--- a/clang/test/Sema/warn-lifetime-safety-lifetimebound.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-lifetimebound.cpp
@@ -44,6 +44,24 @@ View return_alias_through_unannotated_passthrough(
return not_lb(alias);
}
+View global_view;
+
+View assign_param_to_global(
+ const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could not verify that the return value can be lifetime bound to 'obj'}}
+ global_view = obj; // Wrong kind of escape.
+ return View(); // Unrelated view.
+}
+
+struct EnclosingState {
+ View member;
+
+ View assign_param_to_field(
+ const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could not verify that the return value can be lifetime bound to 'obj'}}
+ member = obj; // Wrong kind of escape.
+ return View(); // Unrelated view.
+ }
+};
+
View not_lb_view(View v);
View lb_view(View v [[clang::lifetimebound]]);
More information about the cfe-commits
mailing list