[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread via cfe-commits


@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}

NeKon69 wrote:

I'll change diagnostic wording and pass in "unnamed" if no name is available.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread via cfe-commits


@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}

NeKon69 wrote:

Oh, actually, that code does not compile. I suspected that might happen (I 
remember running into this a few times). So I guess my code should not account 
for that? Or maybe it is a bug that such code should compile? 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread via cfe-commits


@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_lifetimebound_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb(obj);
+}
+
+View lose_lb(const MyObj &obj [[clang::lifetimebound]]) { // expected-warning 
{{could not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_alias(const MyObj &obj [[clang::lifetimebound]]) {
+  const MyObj &alias = obj;
+  return alias;
+}
+
+View return_alias_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  const MyObj &alias = obj;
+  return not_lb(alias);
+}
+
+View not_lb_view(View v);
+
+View lb_view(View v [[clang::lifetimebound]]);
+
+
+View return_through_two_lifetimebound_calls(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb_view(lb(obj));
+}
+
+View return_through_nested_broken_chain(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb_view(lb_view(View(obj)));
+}
+
+View return_constructed_view_through_unannotated_forwarder(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb_view(View(obj));
+}
+
+View return_constructed_view_through_lifetimebound_forwarder(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb_view(View(obj));
+}
+
+View verify_each_annotated_param_independently(
+const MyObj &a [[clang::lifetimebound]],
+const MyObj &b [[clang::lifetimebound]], // expected-warning {{could not 
verify that the return value can be lifetime bound to 'b'}}
+const MyObj &c [[clang::lifetimebound]]) { // expected-warning {{could not 
verify that the return value can be lifetime bound to 'c'}}
+  return cond() ? a : not_lb(b);
+}
+
+View unnamed_lifetimebound_param(
+[[clang::lifetimebound]] const MyObj &) { // expected-warning {{could not 
verify that the return value can be lifetime bound to an unnamed parameter}}
+  return View();
+}
+
+// FIXME: Should warn on declaration, not definiton
+View annotated_decl_but_not_def_not_returned(const MyObj &obj 
[[clang::lifetimebound]]);
+
+View annotated_decl_but_not_def_not_returned(const MyObj &obj) { // 
expected-warning {{could not verify that the return value can be lifetime bound 
to 'obj'}}
+  return not_lb(obj);
+}

NeKon69 wrote:

I will see what I can do, and will submit a PR soon-ish.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread via cfe-commits


@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}

NeKon69 wrote:

Turns out you have to place the attribute before all that type stuff for 
unnamed parameters, didn't know that!

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 01/13] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 closed https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 approved this pull request.

LGTM.

Added one suggestion for a followup PR.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-10 Thread Utkarsh Saxena via cfe-commits


@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_lifetimebound_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb(obj);
+}
+
+View lose_lb(const MyObj &obj [[clang::lifetimebound]]) { // expected-warning 
{{could not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_alias(const MyObj &obj [[clang::lifetimebound]]) {
+  const MyObj &alias = obj;
+  return alias;
+}
+
+View return_alias_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  const MyObj &alias = obj;
+  return not_lb(alias);
+}
+
+View not_lb_view(View v);
+
+View lb_view(View v [[clang::lifetimebound]]);
+
+
+View return_through_two_lifetimebound_calls(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb_view(lb(obj));
+}
+
+View return_through_nested_broken_chain(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb_view(lb_view(View(obj)));
+}
+
+View return_constructed_view_through_unannotated_forwarder(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb_view(View(obj));
+}
+
+View return_constructed_view_through_lifetimebound_forwarder(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb_view(View(obj));
+}
+
+View verify_each_annotated_param_independently(
+const MyObj &a [[clang::lifetimebound]],
+const MyObj &b [[clang::lifetimebound]], // expected-warning {{could not 
verify that the return value can be lifetime bound to 'b'}}
+const MyObj &c [[clang::lifetimebound]]) { // expected-warning {{could not 
verify that the return value can be lifetime bound to 'c'}}
+  return cond() ? a : not_lb(b);
+}
+
+View unnamed_lifetimebound_param(
+[[clang::lifetimebound]] const MyObj &) { // expected-warning {{could not 
verify that the return value can be lifetime bound to an unnamed parameter}}
+  return View();
+}
+
+// FIXME: Should warn on declaration, not definiton
+View annotated_decl_but_not_def_not_returned(const MyObj &obj 
[[clang::lifetimebound]]);
+
+View annotated_decl_but_not_def_not_returned(const MyObj &obj) { // 
expected-warning {{could not verify that the return value can be lifetime bound 
to 'obj'}}
+  return not_lb(obj);
+}

usx95 wrote:

I am fine doing this in a followup: Ideally the correct fix should be highlight 
the annotation src range and not the parameter src range. This would resolve 
this issue by design of inherited attribute.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -666,10 +672,10 @@ Detects misuse of [[clang::noescape]] annotation where 
the parameter escapes (fo
 }
 
 def LifetimeSafetyValidations : DiagGroup<"lifetime-safety-validations",
-  [LifetimeSafetyNoescape]> {
+  [LifetimeSafetyNoescape, 
LifetimeSafetyLifetimeboundViolation]> {

usx95 wrote:

super nit: add this on new line

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Gábor Horváth via cfe-commits


@@ -624,6 +624,13 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Detects parameters marked as [[clang::lifetimebound]] for which we could not 
verify that the return value can be lifetime bound to them.

Xazax-hun wrote:

```suggestion
Detects parameters marked as [[clang::lifetimebound]] for which the analysis 
could not verify that the return value can be lifetime bound to the parameter.
```

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Gábor Horváth via cfe-commits

https://github.com/Xazax-hun edited 
https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 01/10] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Gábor Horváth via cfe-commits


@@ -467,6 +467,7 @@ enables only the high-confidence subset of these checks.
 * ``-Wlifetime-safety-validations``: Enables checks that validate existing 
lifetime annotations.
 
   * ``-Wlifetime-safety-noescape``: Warns when a parameter marked with 
``[[clang::noescape]]`` escapes the function.
+  * ``-Wlifetime-safety-lifetimebound-violation``: Warns when a parameter 
marked with ``[[clang::lifetimebound]]`` is not returned from the function.

Xazax-hun wrote:

Nit: we should also change the "returned" here. 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 commented:

Overall LG.

We are missing to verify `lifetimebound` for implicit this arg, this only 
targets function parameters atm. I am doing that in a separate PR.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 1/9] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class L

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}

usx95 wrote:

For this PR, can you add a test where the lifetimebound is attached to unnamed 
param.

```cpp
View return_through_unannotated_passthrough(
  const MyObj & [[clang::lifetimebound]]) {
  return View();
}
```

Mostly concerned about the `ParmWithLifetimebound->getName()` to not crash.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -358,6 +362,21 @@ class LifetimeChecker {
 }
   }
 
+  void reportLifetimeboundViolations() {
+if (!isa(FD))
+  return;
+for (const ParmVarDecl *PVD : cast(FD)->parameters()) {
+  if (!PVD->hasAttr())
+continue;
+  bool isImplicit = PVD->getAttr()->isImplicit();
+  bool Escapes = VerifiedLiftimeboundEscapes.contains(PVD);
+  if (isImplicit && !Escapes && !isInStlNamespace(FD))
+assert(false && "Implicit lifetimebound parameters should be 
verified");
+  if (!isImplicit && !Escapes)

usx95 wrote:

nit:

`assert((!isImplicit || Escapes || isInStlNamespace(FD)) &&"Implicit 
lifetimebound parameters should escape through return");`

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Gábor Horváth via cfe-commits


@@ -624,6 +624,13 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Detects parameters marked as [[clang::lifetimebound]] for which we could not 
verify that the return value can be lifetime bound to them.
+This may contain false-positives, e.g. when we fail to track origin 
propagation for the return value.

Xazax-hun wrote:

```suggestion
This warning may produce false-positives diagnostics when it cannot fully model 
the code.
```

I think the terms like `origin propagation` are for us. When we target our 
users let's try to keep things a bit more high level. 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread via cfe-commits

NeKon69 wrote:

@Xazax-hun I changed the wording, please check if this looks better now.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 01/11] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Gábor Horváth via cfe-commits


@@ -358,6 +362,18 @@ class LifetimeChecker {
 }
   }
 
+  void reportLifetimeboundViolations() {
+if (!isa(FD))
+  return;
+for (const ParmVarDecl *PVD : cast(FD)->parameters()) {
+  if (!PVD->hasAttr())
+continue;
+  if (!PVD->getAttr()->isImplicit() &&

Xazax-hun wrote:

Yeah, I was thinking of an assert fail. That being said if we cannot come up 
with a sensible assert that would not be triggered currently, I am also fine 
leaving this as is. 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }

usx95 wrote:

nit: consider inverting the condition to remove the negation:

```cpp
if (PVD->hasAttr()) {
  // Track that this lifetimebound parameter correctly escapes through return.
  VerifiedLiftimeboundEscapes.insert(PVD);
} else {
  // Otherwise, suggest lifetimebound for parameter escaping through return
  // or a field in constructor.
  if (auto *ReturnEsc = dyn_cast(OEF))
AnnotationWarningsMap.try_emplace(PVD, ReturnEsc->getReturnExpr());
  else if (auto *FieldEsc = dyn_cast(OEF);
   FieldEsc && isa(FD))
AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
}
```

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_lifetimebound_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb(obj);
+}
+
+View lb2(const MyObj &obj [[clang::lifetimebound]]) {
+  return lb(obj);
+}
+
+View lose_lb(const MyObj &obj [[clang::lifetimebound]]) { // expected-warning 
{{could not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_alias(const MyObj &obj [[clang::lifetimebound]]) {
+  const MyObj &alias = obj;
+  return alias;
+}
+
+View return_alias_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  const MyObj &alias = obj;
+  return not_lb(alias);
+}
+
+View return_through_two_lifetimebound_calls(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb2(obj);
+}

usx95 wrote:

This does not look useful as compared to other test with a `lb(obj)`. Maybe 
have `lb(lb(obj))` or something similar

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Gábor Horváth via cfe-commits

https://github.com/Xazax-hun approved this pull request.

Overall, looks good to me. 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -358,6 +362,18 @@ class LifetimeChecker {
 }
   }
 
+  void reportLifetimeboundViolations() {
+if (!isa(FD))
+  return;
+for (const ParmVarDecl *PVD : cast(FD)->parameters()) {
+  if (!PVD->hasAttr())
+continue;
+  if (!PVD->getAttr()->isImplicit() &&

usx95 wrote:

Maybe not do this for STL but still do for other implicit annotation. 

That said, implicit annotation violation is not actionable by the user so I am 
fine not having for these at all as currently. If we want to detect this, 
assert fail is better suited here ?

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -35,7 +35,10 @@ inline bool IsLifetimeSafetyDiagnosticEnabled(Sema &S, const 
Decl *D) {
  !Diags.isIgnored(diag::warn_lifetime_safety_invalidation,
   D->getBeginLoc()) ||
  !Diags.isIgnored(diag::warn_lifetime_safety_noescape_escapes,
-  D->getBeginLoc());
+  D->getBeginLoc()) ||
+ !Diags.isIgnored(
+ diag::warn_lifetime_safety_param_lifetimebound_violation,
+ D->getBeginLoc());
 }

usx95 wrote:

While you are at it, maybe convert this into a `for` for readability.

```cpp
constexpr unsigned DiagIDs[] = {
  diag::warn_lifetime_safety_use_after_scope,
  diag::warn_lifetime_safety_use_after_scope_moved,
  diag::warn_lifetime_safety_return_stack_addr,
  diag::warn_lifetime_safety_return_stack_addr_moved,
  diag::warn_lifetime_safety_invalidation,
  diag::warn_lifetime_safety_noescape_escapes,
  diag::warn_lifetime_safety_param_lifetimebound_violation,
  };
  for (unsigned DiagID : DiagIDs)
if (!Diags.isIgnored(DiagID, D->getBeginLoc()))
  return true;
  return false;
```



We are also missing quite a few newly added diags as well here like uaf, 
dangling-field/global, etc. Feel free to add them here or in a separate PR.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread Utkarsh Saxena via cfe-commits


@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety-lifetimebound-violation 
-verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct [[gsl::Owner]] MyObj {
+  int id;
+  ~MyObj() {}  // Non-trivial destructor
+};
+
+struct [[gsl::Pointer()]] View {
+  View(const MyObj &); // Borrows from MyObj
+  View();
+  void use() const;
+};
+
+bool cond();
+
+View not_lb(const MyObj &obj);
+
+View lb(const MyObj &obj [[clang::lifetimebound]]);
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // expected-warning {{could 
not verify that the return value can be lifetime bound to 'obj'}}
+  return not_lb(obj);
+}
+
+View return_through_lifetimebound_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return lb(obj);
+}

usx95 wrote:

This PR doesn't handle decl vs definition atm. Maybe we don't have to because 
of inherited attributes.  
If this doesn't work, it is fine to address in a separate PR with a FIXME.

```cpp
View annotated_decl_but_not_def_not_returned(
  const MyObj &obj [[clang::lifetimebound]])); // error loc must be this!

View annotated_decl_but_not_def_not_returned(const MyObj &obj) {
  return no_lb(obj);
}


View annotated_decl_but_not_def_returned(
  const MyObj &obj [[clang::lifetimebound]]));

View annotated_decl_but_not_def_returned(const MyObj &obj) {
  return lb(obj);
}
```

(...similar tests)ibutes

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread via cfe-commits


@@ -35,7 +35,10 @@ inline bool IsLifetimeSafetyDiagnosticEnabled(Sema &S, const 
Decl *D) {
  !Diags.isIgnored(diag::warn_lifetime_safety_invalidation,
   D->getBeginLoc()) ||
  !Diags.isIgnored(diag::warn_lifetime_safety_noescape_escapes,
-  D->getBeginLoc());
+  D->getBeginLoc()) ||
+ !Diags.isIgnored(
+ diag::warn_lifetime_safety_param_lifetimebound_violation,
+ D->getBeginLoc());
 }

NeKon69 wrote:

I think I'll add them in this PR, I also have my own warning which I didn't put 
here before.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-09 Thread via cfe-commits


@@ -358,6 +362,18 @@ class LifetimeChecker {
 }
   }
 
+  void reportLifetimeboundViolations() {
+if (!isa(FD))
+  return;
+for (const ParmVarDecl *PVD : cast(FD)->parameters()) {
+  if (!PVD->hasAttr())
+continue;
+  if (!PVD->getAttr()->isImplicit() &&

NeKon69 wrote:

We should probably ask @Xazax-hun about his opinion on this.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits


@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not returning it in any way.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,

usx95 wrote:

[Re: lines 
+675 to +681]
Please add the warning to this group.
See this comment 
inline on https://app.graphite.com/github/pr/llvm/llvm-project/196144?utm_source=unchanged-line-comment";>Graphite.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits


@@ -3279,8 +3279,80 @@ struct [[gsl::Pointer]] function_ref {
 // avoid this warning for non-capturing lambdas.
 void assign_non_capturing_to_function_ref(function_ref &r) {
   r = []() {}; // expected-warning {{object whose reference is captured does 
not live long enough}} \
-   // expected-note {{destroyed here}}
+   // expected-note {{destroyed here}} function-note {{requested 
here}}
   (void)r; // expected-note {{later used here}}
 }
 
 } // namespace GH126600
+
+namespace LifetimeboundReturnVerification {
+
+bool cond();
+
+View drop_lb(const MyObj &obj) { return obj; }
+
+View keep_lb(const MyObj &obj [[clang::lifetimebound]]) {
+  return obj;
+}
+
+View return_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // function-warning 
{{parameter is marked as [[clang::lifetimebound]] but isn't returned}}
+  return drop_lb(obj);
+}
+
+View return_through_lifetimebound_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return keep_lb(obj);
+}
+
+View keep_lb2(const MyObj &obj [[clang::lifetimebound]]) {
+  return keep_lb(obj);
+}
+
+View lose_lb(const MyObj &obj [[clang::lifetimebound]]) { // function-warning 
{{parameter is marked as [[clang::lifetimebound]] but isn't returned}}
+  return drop_lb(obj);
+}
+
+View return_through_alias(const MyObj &obj [[clang::lifetimebound]]) {
+  const MyObj &alias = obj;
+  return alias;
+}
+
+View return_alias_through_unannotated_passthrough(
+const MyObj &obj [[clang::lifetimebound]]) { // function-warning 
{{parameter is marked as [[clang::lifetimebound]] but isn't returned}}
+  const MyObj &alias = obj;
+  return drop_lb(alias);
+}
+
+View return_through_two_lifetimebound_calls(
+const MyObj &obj [[clang::lifetimebound]]) {
+  return keep_lb2(obj);
+}
+
+View fwd_view(View v) { return v; }
+
+View fwd_view_lb(View v [[clang::lifetimebound]]) { return v; }

usx95 wrote:

Same for these.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits


@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}

usx95 wrote:

nit: Consider documenting this.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread via cfe-commits

https://github.com/NeKon69 edited 
https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread via cfe-commits


@@ -358,6 +362,18 @@ class LifetimeChecker {
 }
   }
 
+  void reportLifetimeboundViolations() {
+if (!isa(FD))
+  return;
+for (const ParmVarDecl *PVD : cast(FD)->parameters()) {
+  if (!PVD->hasAttr())
+continue;
+  if (!PVD->getAttr()->isImplicit() &&

NeKon69 wrote:

This did happen earlier when I did some testing for `make_unique`. It's really 
hard to track what have gone wrong though...

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits


@@ -3279,8 +3279,80 @@ struct [[gsl::Pointer]] function_ref {
 // avoid this warning for non-capturing lambdas.
 void assign_non_capturing_to_function_ref(function_ref &r) {
   r = []() {}; // expected-warning {{object whose reference is captured does 
not live long enough}} \
-   // expected-note {{destroyed here}}
+   // expected-note {{destroyed here}} function-note {{requested 
here}}
   (void)r; // expected-note {{later used here}}
 }
 
 } // namespace GH126600
+
+namespace LifetimeboundReturnVerification {
+
+bool cond();
+
+View drop_lb(const MyObj &obj) { return obj; }
+
+View keep_lb(const MyObj &obj [[clang::lifetimebound]]) {
+  return obj;
+}

usx95 wrote:

I would not keep inference related tests here. The idea is to minimum 
divergence in this file among the test modes and use `expected` prefix as much 
as we can.

A Simple fix would be to drop the function bodies for both the functions here.
Maybe also rename to `not_lb` and `lb` for these.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits

https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Utkarsh Saxena via cfe-commits


@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not returning it in any way.

usx95 wrote:

suggestion: `Detects parameters marked as [[clang::lifetimebound]] that do not 
escape through the return value.`

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Gábor Horváth via cfe-commits


@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not returning it in any way.

Xazax-hun wrote:

Technically, it is not necessarily the parameter that needs to escape.

Consider:
```
int * f(const std::vector& v [[clang::lifetimebound]]) {
  return v.data();
}
```

Here, we do not escape the address of vector itself, but we return a pointer to 
an inner buffer. So technically, we did not escape the lifetimebound marked 
value, but this code is still fine! 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Gábor Horváth via cfe-commits


@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not returning it in any way.

Xazax-hun wrote:

I wonder if we need a different wording here. It is very much possible that the 
code actually does return something that was lifetimebound to this parameter 
but we cannot track it due to missing annotations or the analysis not covering 
some constructs. 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Gábor Horváth via cfe-commits


@@ -358,6 +362,18 @@ class LifetimeChecker {
 }
   }
 
+  void reportLifetimeboundViolations() {
+if (!isa(FD))
+  return;
+for (const ParmVarDecl *PVD : cast(FD)->parameters()) {
+  if (!PVD->hasAttr())
+continue;
+  if (!PVD->getAttr()->isImplicit() &&

Xazax-hun wrote:

Hmm, I wonder if this can ever happen, that we infer an implicit lifetime 
attribute and later cannot verify it? 

I wonder if we want to be notified of those cases, should this be turned into 
an assert?

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread Gábor Horváth via cfe-commits


@@ -11007,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but isn't 
returned">,

Xazax-hun wrote:

Similar concerns here:
* The issue might be missing annotations
* We do not actually need to literally return the parameter. We just need to 
return something that is lifetimebound to the parameter.

I wonder if the warning should be something like "could not verify that the 
return value can be lifetime bound to this parameter" 

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 1/8] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class L

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 1/6] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class L

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread via cfe-commits

NeKon69 wrote:

I will create a separate test file as we do for testing noescape attributes 
already, since the warnings do not appear with just -Wlifetime-safety.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-08 Thread via cfe-commits

https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/196144

>From 61b80f15e64db8cdbc4ef6cc813d8d2af8cb60d8 Mon Sep 17 00:00:00 2001
From: NeKon69 
Date: Sun, 3 May 2026 21:31:39 +0300
Subject: [PATCH 1/7] basic impl

---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  2 ++
 clang/include/clang/Basic/DiagnosticGroups.td |  9 -
 clang/include/clang/Basic/DiagnosticSemaKinds.td  |  5 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 +++
 clang/lib/Sema/SemaLifetimeSafety.h   |  7 +++
 clang/test/Sema/warn-lifetime-safety.cpp  |  4 ++--
 6 files changed, 39 insertions(+), 3 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d20ac87a7c8d9..6e352ee50e011 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -108,6 +108,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
const VarDecl *EscapeGlobal) {}
 
+  virtual void reportLifetimeboundViolation(const ParmVarDecl *VD) {}
+
   // Suggests lifetime bound annotations for implicit this.
   virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
   const CXXMethodDecl *MD,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 2b3055d6d6bdd..b454b68a7f5ac 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -624,12 +624,19 @@ Warning to detect invalidation of references.
   }];
 }
 
+def LifetimeSafetyLifetimeboundViolation : 
DiagGroup<"lifetime-safety-lifetimebound-violation"> {
+  code Documentation = [{
+Warning to detect lifetimebound violations introduced by marking parameter as 
lifetimebound but not actually returning it.
+  }];
+}
+
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
  [LifetimeSafetyUseAfterScope,
  LifetimeSafetyReturnStackAddr,
  LifetimeSafetyDanglingField,
  LifetimeSafetyDanglingGlobal,
- LifetimeSafetyUseAfterFree]>;
+ LifetimeSafetyUseAfterFree,
+ 
LifetimeSafetyLifetimeboundViolation]>;
 
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
 [LifetimeSafetyPermissive,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..40409c0174470 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11003,6 +11003,11 @@ def warn_lifetime_safety_dangling_global_moved
   InGroup,
   DefaultIgnore;
 
+def warn_lifetime_safety_param_lifetimebound_violation
+: Warning<"parameter is marked as [[clang::lifetimebound]] but doesn't 
escape">,
+  InGroup,
+  DefaultIgnore;
+
 def note_lifetime_safety_used_here : Note<"later used here">;
 def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
 def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 4ae90cf751ec3..581e469d0e507 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -60,6 +60,7 @@ class LifetimeChecker {
   llvm::DenseMap FinalWarningsMap;
   llvm::DenseMap AnnotationWarningsMap;
   llvm::DenseMap NoescapeWarningsMap;
+  llvm::DenseSet VerifiedLiftimeboundEscapes;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
   const LiveOriginsAnalysis &LiveOrigins;
@@ -101,6 +102,7 @@ class LifetimeChecker {
 issuePendingWarnings();
 suggestAnnotations();
 reportNoescapeViolations();
+reportLifetimeboundViolations();
 //  Annotation inference is currently guarded by a frontend flag. In the
 //  future, this might be replaced by a design that differentiates between
 //  explicit and inferred findings with separate warning groups.
@@ -137,6 +139,8 @@ class LifetimeChecker {
 else if (auto *FieldEsc = dyn_cast(OEF);
  FieldEsc && isa(FD))
   AnnotationWarningsMap.try_emplace(PVD, FieldEsc->getFieldDecl());
+  } else {
+VerifiedLiftimeboundEscapes.insert(PVD);
   }
   // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
   // field!
@@ -358,6 +362,17 @@ class L

[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-07 Thread via cfe-commits

NeKon69 wrote:

Thanks for the suggestion, I will take a mental note of that.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-07 Thread via cfe-commits

https://github.com/NeKon69 edited 
https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [LifetimeSafety] Warn on incorrectly placed `[[clang::lifetimebound]]` attributes (PR #196144)

2026-05-07 Thread Gábor Horváth via cfe-commits

Xazax-hun wrote:

Nit about writing PR descriptions:
* You do not need to say "In this PR", just say what the PR does. It is evident 
from the context.
* No need to explicitly call out that you added tests. That is the basic bar 
that we have for all contributions. We usually only call out of there is a 
reason why we cannot add a test.

https://github.com/llvm/llvm-project/pull/196144
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits