llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Utkarsh Saxena (usx95)

<details>
<summary>Changes</summary>

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
```

---
Full diff: https://github.com/llvm/llvm-project/pull/179309.diff


5 Files Affected:

- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h (+2) 
- (modified) clang/include/clang/Basic/DiagnosticGroups.td (+58-11) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+9-12) 
- (modified) clang/lib/Sema/AnalysisBasedWarnings.cpp (+10-15) 
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+9-9) 


``````````diff
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
+// differentiator 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 5c49e601840cf..76dd00ee96e35 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)
@@ -3150,17 +3148,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 8f52ff27bc6fd..3516ab14d925a 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}}
 
@@ -1191,7 +1191,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}}

``````````

</details>


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

Reply via email to