Author: Utkarsh Saxena
Date: 2026-02-23T12:55:42+01:00
New Revision: fd44b06a8dc3a3ef89d6c31268747d714f381610

URL: 
https://github.com/llvm/llvm-project/commit/fd44b06a8dc3a3ef89d6c31268747d714f381610
DIFF: 
https://github.com/llvm/llvm-project/commit/fd44b06a8dc3a3ef89d6c31268747d714f381610.diff

LOG: [LifetimeSafety] Reorganize diagnostic groups and remove confidence-based 
warnings (#179309)

Reorganized lifetime safety diagnostic groups to be more granular and
renamed diagnostic messages for better clarity.

- **Diagnostic Group Restructuring**: Split lifetime safety warnings
into more specific categories:
- `lifetime-safety-use-after-scope` and
`lifetime-safety-use-after-scope-moved` for scope-related issues
- `lifetime-safety-return-stack-addr` and
`lifetime-safety-return-stack-addr-moved` for return address issues
- `lifetime-safety-dangling-field` and
`lifetime-safety-dangling-field-moved` for field reference issues
- Added new umbrella groups `lifetime-safety-validations` and
`lifetime-safety-all`
- **Diagnostic Message Updates**: Renamed warning diagnostics from
generic "loan expires" terminology to more specific messages like "use
after scope" and "return stack addr"
- **Code Cleanup**: Removed `Confidence` logic (based on possible vs
guaranteed control-flow) from diagnostic reporting functions. Added TODO
comment to deprecate the `Confidence` enum

The new diagnostic group tree is:

```
lifetime-safety-all
├── lifetime-safety
│   ├── lifetime-safety-permissive
│   │   ├── lifetime-safety-use-after-scope
│   │   ├── lifetime-safety-return-stack-addr
│   │   └── lifetime-safety-dangling-field
│   └── lifetime-safety-strict
│       ├── lifetime-safety-use-after-scope-moved
│       ├── lifetime-safety-return-stack-addr-moved
│       ├── lifetime-safety-dangling-field-moved
│       └── lifetime-safety-invalidation
├── lifetime-safety-suggestions
│   ├── lifetime-safety-cross-tu-suggestions
│   └── lifetime-safety-intra-tu-suggestions
└── lifetime-safety-validations
    └── lifetime-safety-noescape
```

Added: 
    

Modified: 
    clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/AnalysisBasedWarnings.cpp
    clang/test/Sema/warn-lifetime-safety.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 7761a5c24c606..d7aadf4cf04ca 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -33,6 +33,8 @@
 
 namespace clang::lifetimes {
 
+// TODO: Deprecate and remove Confidence as this is no more used as a
+// 
diff erentiator between strict and permissive warnings.
 /// Enum to track the confidence level of a potential error.
 enum class Confidence : uint8_t {
   None,

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index aaf8275a78707..7df83d2a4011f 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -556,36 +556,65 @@ def Dangling : DiagGroup<"dangling", [DanglingAssignment,
                                       DanglingGsl,
                                       ReturnStackAddress]>;
 
-def LifetimeSafetyDanglingField : DiagGroup<"lifetime-safety-dangling-field"> {
+// Use-After-Scope
+def LifetimeSafetyUseAfterScope : DiagGroup<"lifetime-safety-use-after-scope"> 
{
+  code Documentation = [{
+Warning to detect dangling references introduced by use-after-scope.
+  }];
+}
+def LifetimeSafetyUseAfterScopeMoved : 
DiagGroup<"lifetime-safety-use-after-scope-moved"> {
   code Documentation = [{
-    Warning to detect dangling field references.
+Warning to detect dangling references introduced by use-after-scope.
+This may contain false-positives, e.g. when the borrowed storage is 
potentially moved and is not destroyed at scope exit.
   }];
 }
 
-def LifetimeSafetyDanglingFieldStrict : 
DiagGroup<"lifetime-safety-dangling-field-strict"> {
+// Return-Stack-Address (aka Use-After-Return)
+def LifetimeSafetyReturnStackAddr : 
DiagGroup<"lifetime-safety-return-stack-addr"> {
+  code Documentation = [{
+Warning to detect use-after-return introduced by returning stack address.
+  }];
+}
+def LifetimeSafetyReturnStackAddrMoved : 
DiagGroup<"lifetime-safety-return-stack-addr-moved"> {
   code Documentation = [{
-    Warning to detect dangling field references.
-    This may contain false-positives, e.g. when the borrowed storage is 
potentially moved and is not destroyed at function exit.
+Warning to detect use-after-return introduced by returning stack address.
+This may contain false-positives, e.g. when the borrowed storage is 
potentially moved and is not destroyed at function exit.
   }];
 }
 
+// Dangling-Field (aka Escape-To-Field)
+def LifetimeSafetyDanglingField : DiagGroup<"lifetime-safety-dangling-field"> {
+  code Documentation = [{
+Warning to detect dangling field references.
+  }];
+}
+def LifetimeSafetyDanglingFieldMoved : 
DiagGroup<"lifetime-safety-dangling-field-moved"> {
+  code Documentation = [{
+Warning to detect dangling field references.
+This may contain false-positives, e.g. when the borrowed storage is 
potentially moved and is not destroyed at function exit.
+  }];
+}
 
 def LifetimeSafetyInvalidation : DiagGroup<"lifetime-safety-invalidation"> {
   code Documentation = [{
-    Warning to detect invalidation of references.
+Warning to detect invalidation of references.
   }];
 }
 
 def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive",
-                                         [LifetimeSafetyDanglingField]>;
+                                         [LifetimeSafetyUseAfterScope,
+                                         LifetimeSafetyReturnStackAddr,
+                                         LifetimeSafetyDanglingField]>;
 def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict",
-                                    [LifetimeSafetyDanglingFieldStrict,
+                                    [LifetimeSafetyUseAfterScopeMoved,
+                                    LifetimeSafetyReturnStackAddrMoved,
+                                    LifetimeSafetyDanglingFieldMoved,
                                     LifetimeSafetyInvalidation]>;
 
 def LifetimeSafety : DiagGroup<"lifetime-safety",
                                [LifetimeSafetyPermissive, 
LifetimeSafetyStrict]> {
   code Documentation = [{
-    Warnings to detect use-after-free and related temporal safety bugs based 
on lifetime safety analysis.
+Warnings to detect use-after-free and related temporal safety bugs based on 
lifetime safety analysis.
   }];
 }
 
@@ -598,13 +627,31 @@ def LifetimeSafetySuggestions
                 [LifetimeSafetyCrossTUSuggestions,
                  LifetimeSafetyIntraTUSuggestions]> {
   code Documentation = [{
-    Lifetime annotation suggestions for function parameters that should be 
marked [[clang::lifetimebound]] based on lifetime analysis.
+Lifetime annotation suggestions for function parameters that should be marked 
[[clang::lifetimebound]] based on lifetime analysis.
   }];
 }
+
 def LifetimeSafetyNoescape
     : DiagGroup<"lifetime-safety-noescape"> {
   code Documentation = [{
-    Detects misuse of [[clang::noescape]] annotation where the parameter 
escapes (for example, through return).
+Detects misuse of [[clang::noescape]] annotation where the parameter escapes 
(for example, through return).
+  }];
+}
+
+def LifetimeSafetyValidations : DiagGroup<"lifetime-safety-validations",
+                                          [LifetimeSafetyNoescape]> {
+  code Documentation = [{
+Verify function implementations adhere to the annotated lifetime contracts 
through lifetime safety
+like verifying [[clang::noescape]] and [[clang::lifetimebound]] (upcoming).
+  }];
+}
+
+def LifetimeSafetyAll : DiagGroup<"lifetime-safety-all",
+                                  [LifetimeSafety,
+                                  LifetimeSafetySuggestions,
+                                  LifetimeSafetyValidations]> {
+  code Documentation = [{
+Turns on all the warnings in the lifetime-safety umbrella.
   }];
 }
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5254003f0c21e..68016ec4d58a3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10897,26 +10897,23 @@ def warn_dangling_reference_captured_by_unknown : 
Warning<
    "the full-expression">, InGroup<DanglingCapture>;
 
 // Diagnostics based on the Lifetime safety analysis.
-def warn_lifetime_safety_loan_expires_permissive : Warning<
+def warn_lifetime_safety_use_after_scope : Warning<
    "object whose reference is captured does not live long enough">,
-   InGroup<LifetimeSafetyPermissive>, DefaultIgnore;
-def warn_lifetime_safety_loan_expires_strict : Warning<
-   "object whose reference is captured may not live long enough">,
-   InGroup<LifetimeSafetyStrict>, DefaultIgnore;
-def warn_lifetime_safety_loan_expires_moved_strict : Warning<
+   InGroup<LifetimeSafetyUseAfterScope>, DefaultIgnore;
+def warn_lifetime_safety_use_after_scope_moved : Warning<
    "object whose reference is captured may not live long enough. "
    "This could be false positive as the storage may have been moved later">,
-   InGroup<LifetimeSafetyStrict>, DefaultIgnore;
+   InGroup<LifetimeSafetyUseAfterScopeMoved>, DefaultIgnore;
 
-def warn_lifetime_safety_return_stack_addr_permissive
+def warn_lifetime_safety_return_stack_addr
     : Warning<"address of stack memory is returned later">,
-      InGroup<LifetimeSafetyPermissive>,
+      InGroup<LifetimeSafetyReturnStackAddr>,
       DefaultIgnore;
-def warn_lifetime_safety_return_stack_addr_moved_strict
+def warn_lifetime_safety_return_stack_addr_moved
     : Warning<"address of stack memory may be returned later. "
       "This could be false positive as the storage may have been moved. "
       "Consider moving first and then aliasing later to resolve the issue">,
-      InGroup<LifetimeSafetyStrict>,
+      InGroup<LifetimeSafetyReturnStackAddrMoved>,
       DefaultIgnore;
 
 def warn_lifetime_safety_invalidation
@@ -10932,7 +10929,7 @@ def warn_lifetime_safety_dangling_field_moved
     : Warning<"address of stack memory escapes to a field. "
       "This could be a false positive as the storage may have been moved. "
       "Consider moving first and then aliasing later to resolve the issue">,
-      InGroup<LifetimeSafetyDanglingFieldStrict>,
+      InGroup<LifetimeSafetyDanglingFieldMoved>,
       DefaultIgnore;
 
 def note_lifetime_safety_used_here : Note<"later used here">;

diff  --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp 
b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 45adab94e07da..20c41096501fb 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2862,12 +2862,10 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
 
   void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
                           const Expr *MovedExpr, SourceLocation FreeLoc,
-                          Confidence C) override {
+                          Confidence) override {
     S.Diag(IssueExpr->getExprLoc(),
-           MovedExpr ? diag::warn_lifetime_safety_loan_expires_moved_strict
-           : C == Confidence::Definite
-               ? diag::warn_lifetime_safety_loan_expires_permissive
-               : diag::warn_lifetime_safety_loan_expires_strict)
+           MovedExpr ? diag::warn_lifetime_safety_use_after_scope_moved
+                     : diag::warn_lifetime_safety_use_after_scope)
         << IssueExpr->getSourceRange();
     if (MovedExpr)
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
@@ -2879,10 +2877,10 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
 
   void reportUseAfterReturn(const Expr *IssueExpr, const Expr *ReturnExpr,
                             const Expr *MovedExpr, SourceLocation ExpiryLoc,
-                            Confidence C) override {
+                            Confidence) override {
     S.Diag(IssueExpr->getExprLoc(),
-           MovedExpr ? 
diag::warn_lifetime_safety_return_stack_addr_moved_strict
-                     : diag::warn_lifetime_safety_return_stack_addr_permissive)
+           MovedExpr ? diag::warn_lifetime_safety_return_stack_addr_moved
+                     : diag::warn_lifetime_safety_return_stack_addr)
         << IssueExpr->getSourceRange();
     if (MovedExpr)
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
@@ -3148,17 +3146,14 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
   AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
 
   bool IsLifetimeSafetyDiagnosticEnabled =
-      !Diags.isIgnored(diag::warn_lifetime_safety_loan_expires_permissive,
+      !Diags.isIgnored(diag::warn_lifetime_safety_use_after_scope,
                        D->getBeginLoc()) ||
-      !Diags.isIgnored(diag::warn_lifetime_safety_loan_expires_strict,
+      !Diags.isIgnored(diag::warn_lifetime_safety_use_after_scope_moved,
                        D->getBeginLoc()) ||
-      !Diags.isIgnored(diag::warn_lifetime_safety_loan_expires_moved_strict,
+      !Diags.isIgnored(diag::warn_lifetime_safety_return_stack_addr,
                        D->getBeginLoc()) ||
-      !Diags.isIgnored(diag::warn_lifetime_safety_return_stack_addr_permissive,
+      !Diags.isIgnored(diag::warn_lifetime_safety_return_stack_addr_moved,
                        D->getBeginLoc()) ||
-      !Diags.isIgnored(
-          diag::warn_lifetime_safety_return_stack_addr_moved_strict,
-          D->getBeginLoc()) ||
       !Diags.isIgnored(diag::warn_lifetime_safety_invalidation,
                        D->getBeginLoc()) ||
       !Diags.isIgnored(diag::warn_lifetime_safety_noescape_escapes,

diff  --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 8cca9b3402366..097f3279d8e54 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -174,7 +174,7 @@ void potential_if_branch(bool cond) {
   MyObj* p = &safe;
   if (cond) {
     MyObj temp;
-    p = &temp;  // expected-warning {{object whose reference is captured may 
not live long enough}}
+    p = &temp;  // expected-warning {{object whose reference is captured does 
not live long enough}}
   }             // expected-note {{destroyed here}}
   if (!cond)
     (void)*p;   // expected-note {{later used here}}
@@ -202,7 +202,7 @@ void definite_potential_together(bool cond) {
     if (cond)
       p_definite = &s;  // expected-warning {{does not live long enough}}
     if (cond)
-      p_maybe = &s;     // expected-warning {{may not live long enough}}       
  
+      p_maybe = &s;     // expected-warning {{does not live long enough}}      
   
   }                     // expected-note 2 {{destroyed here}}
   (void)*p_definite;    // expected-note {{later used here}}
   if (!cond)
@@ -235,7 +235,7 @@ void potential_due_to_conditional_killing(bool cond) {
   MyObj* q;
   {
     MyObj s;
-    q = &s;       // expected-warning {{may not live long enough}}
+    q = &s;       // expected-warning {{does not live long enough}}
   }               // expected-note {{destroyed here}}
   if (cond) {
     // 'q' is conditionally "rescued". 'p' is not.
@@ -248,7 +248,7 @@ void potential_for_loop_use_after_loop_body(MyObj safe) {
   MyObj* p = &safe;
   for (int i = 0; i < 1; ++i) {
     MyObj s;
-    p = &s;     // expected-warning {{may not live long enough}}
+    p = &s;     // expected-warning {{does not live long enough}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -268,7 +268,7 @@ void potential_for_loop_gsl() {
   View v = safe;
   for (int i = 0; i < 1; ++i) {
     MyObj s;
-    v = s;      // expected-warning {{object whose reference is captured may 
not live long enough}}
+    v = s;      // expected-warning {{object whose reference is captured does 
not live long enough}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -366,7 +366,7 @@ void potential_switch(int mode) {
   switch (mode) {
   case 1: {
     MyObj temp;
-    p = &temp;  // expected-warning {{object whose reference is captured may 
not live long enough}}
+    p = &temp;  // expected-warning {{object whose reference is captured does 
not live long enough}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
@@ -430,7 +430,7 @@ void loan_from_previous_iteration(MyObj safe, bool 
condition) {
 
   while (condition) {
     MyObj x;
-    p = &x;     // expected-warning {{may not live long enough}}
+    p = &x;     // expected-warning {{does not live long enough}}
 
     if (condition)
       q = p;
@@ -994,7 +994,7 @@ void conditional_operator_one_unsafe_branch(bool cond) {
   MyObj* p = &safe;
   {
     MyObj temp;
-    p = cond ? &temp  // expected-warning {{object whose reference is captured 
may not live long enough}}
+    p = cond ? &temp  // expected-warning {{object whose reference is captured 
does not live long enough}}
              : &safe;
   }  // expected-note {{destroyed here}}
 
@@ -1190,7 +1190,7 @@ void range_based_for_not_reference() {
   {
     MyObjStorage s;
     for (MyObj o : s) { // expected-note {{destroyed here}}
-      v = o; // expected-warning {{object whose reference is captured may not 
live long enough}}
+      v = o; // expected-warning {{object whose reference is captured does not 
live long enough}}
     }
   }
   v.use();  // expected-note {{later used here}}


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

Reply via email to