https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/183058

>From 20719aca4f7222109ef0ab437f7127ba9cac45dc Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <[email protected]>
Date: Tue, 24 Feb 2026 13:59:05 +0000
Subject: [PATCH 1/3] user-docs

---
 clang/docs/LifetimeSafety.rst | 449 ++++++++++++++++++++++++++++++++++
 1 file changed, 449 insertions(+)
 create mode 100644 clang/docs/LifetimeSafety.rst

diff --git a/clang/docs/LifetimeSafety.rst b/clang/docs/LifetimeSafety.rst
new file mode 100644
index 0000000000000..4c27f3aea5244
--- /dev/null
+++ b/clang/docs/LifetimeSafety.rst
@@ -0,0 +1,449 @@
+======================
+Lifetime Safety Analysis
+======================
+
+.. contents::
+   :local:
+
+Introduction
+============
+
+Clang Lifetime Safety Analysis is a C++ language extension which warns about
+potential dangling pointer defects in code. The analysis aims to detect
+when a pointer, reference or view type (such as ``std::string_view``) refers 
to an object
+that is no longer alive, a condition that leads to use-after-free bugs and
+security vulnerabilities. Common examples include pointers to stack variables
+that have gone out of scope, fields holding views to stack-allocated objects
+(dangling-field), returning pointers/references to stack variables 
+(return stack address) or iterators into container elements invalidated by
+container operations (e.g., ``std::vector::push_back``)
+
+The analysis design is inspired by `Polonius, the Rust borrow checker 
<https://github.com/rust-lang/polonius>`_,
+but adapted to C++ idioms and constraints, such as the lack of borrow checker 
exclusivity (alias-xor-mutability). 
+Further details on the analysis method can be found in the `RFC on Discourse 
<https://discourse.llvm.org/t/rfc-intra-procedural-lifetime-analysis-in-clang/86291/>`_.
+
+This is compile-time analysis; there is no run-time overhead. 
+It tracks pointer validity through intra-procedural data-flow analysis, 
supporting a form of gradual typing. While it does
+not require lifetime annotations to get started, in their absence, the analysis
+treats function calls with opaque semantics, potentially missing dangling 
pointer issues or producing false positives. As more functions are annotated
+with attributes like ``[[clang::lifetimebound]]``, ``[[gsl::Owner]]``, and
+``[[gsl::Pointer]]``, the analysis can see through these contracts and enforce
+lifetime safety at call sites with higher accuracy. This approach supports
+gradual adoption in existing codebases. It is still very much under active 
development,
+but it is mature enough to be used in production codebases.
+
+Getting Started
+----------------
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+
+  void simple_dangle() {
+    std::string_view v;
+    {
+      std::string s = "hello";
+      v = s;  // 'v' borrows from 's'.
+    }       // 's' is destroyed here, 'v' becomes dangling.
+    (void)v;  // WARNING! 'v' is used after 's' has been destroyed.
+  }
+
+This example demonstrates
+a basic use-after-scope defect. The ``std::string_view`` object ``v`` holds a
+reference to ``s``, a ``std::string``. When ``s`` goes out of
+scope at the end of the inner block, ``v`` becomes a dangling reference, and
+its subsequent use is flagged by the analysis.
+
+Running The Analysis
+--------------------
+
+To run the analysis, compile with the ``-Wlifetime-safety`` flag, e.g.
+
+.. code-block:: bash
+
+  clang -c -Wlifetime-safety example.cpp
+
+This flag enables a core set of lifetime safety checks. For more fine-grained
+control over warnings, see :ref:`warning_flags`.
+
+Lifetime Annotations
+====================
+
+While lifetime analysis can detect many issues without annotations, its
+precision increases significantly when types and functions are annotated with
+lifetime contracts. These annotations clarify ownership semantics and lifetime
+dependencies, enabling the analysis to reason more accurately about pointer
+validity across function calls.
+
+Owner and Pointer Types
+-----------------------
+
+Lifetime analysis distinguishes between types that own the data they point to
+(Owners) and types that are non-owning views or references to data owned by
+others (Pointers). This distinction is made using GSL-style attributes:
+
+*   ``[[gsl::Owner]]``: For types that manage the lifetime of a resource,
+    like ``std::string``, ``std::vector``, ``std::unique_ptr``.
+*   ``[[gsl::Pointer]]``: For non-owning types that borrow resources,
+    like ``std::string_view``, ``gsl::span``, or raw pointers (which are
+    implicitly treated as pointers).
+
+Many common STL types, such as ``std::string_view`` and container iterators,
+are automatically recognized as Pointers or Owners. You can annotate your own
+types using these attributes:
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+
+  // Owning type
+  struct [[gsl::Owner]] MyObj {
+    std::string Data = "Hello";
+  };
+
+  // Non-owning view type
+  struct [[gsl::Pointer]] View {
+    std::string_view SV;
+    View() = default;
+    View(const MyObj& O) : SV(O.Data) {}
+    void use() const {}
+  };
+
+  void test() {
+    View v;
+    {
+      MyObj o;
+      v = o;
+    } // o is destroyed
+    v.use(); // WARNING: object whose reference is captured does not live long 
enough
+  }
+
+Without these annotations, the analysis may not be able to determine whether a
+type is owning or borrowing, which can affect analysis precision. For more
+details on these attributes, see the Clang attribute reference for
+`gsl::Owner <https://clang.llvm.org/docs/AttributeReference.html#gsl-owner>`_ 
and
+`gsl::Pointer 
<https://clang.llvm.org/docs/AttributeReference.html#gsl-pointer>`_.
+
+LifetimeBound
+-------------
+
+The ``[[clang::lifetimebound]]`` attribute can be applied to function 
parameters
+or to the implicit ``this`` parameter of a method (by placing it after the
+method declarator). It indicates that the returned pointer or reference is
+valid only as long as the attributed parameter or ``this`` object is alive.
+This is crucial for functions that return views or references to their
+arguments.
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+
+  struct MyOwner {
+    std::string s;
+    std::string_view getView() const [[clang::lifetimebound]] { return s; }
+  };
+
+  void test_lifetimebound() {
+    std::string_view sv;
+    sv = MyOwner().getView(); // getView() is called on a temporary MyOwner
+                             // MyOwner temporary is destroyed here.
+    (void)sv;                // WARNING: object whose reference is captured 
does not live long enough
+  }
+
+Without ``[[clang::lifetimebound]]`` on ``getView()``, the analysis would not
+know that the value returned by ``getView()`` depends on the temporary
+``MyOwner`` object, and it would not be able to diagnose the dangling ``sv``.
+
+For more details, see `lifetimebound 
<https://clang.llvm.org/docs/AttributeReference.html#lifetimebound>`_.
+
+NoEscape
+--------
+
+The ``[[clang::noescape]]`` attribute can be applied to function parameters of
+pointer or reference type. It indicates that the function will not allow the
+parameter to escape its scope, for example, by returning it or assigning it to
+a field or global variable. This is useful for parameters passed to callbacks
+or visitors that are only used during the call and not stored.
+
+For more details, see `noescape 
<https://clang.llvm.org/docs/AttributeReference.html#noescape>`_.
+
+Checks Performed
+================
+
+Use-After-Scope
+---------------
+
+This is the simplest dangling pointer scenario, where a pointer or reference
+outlives the stack variable it refers to.
+
+.. code-block:: c++
+
+  void use_after_scope() {
+    int* p;
+    {
+      int i = 0;
+      p = &i; // p borrows from i
+    }       // i is destroyed, p dangles
+    (void)*p; // WARNING: use-after-scope
+  }
+
+Return of stack address
+-----------------------
+
+This check warns when a function returns a pointer or reference to a
+stack-allocated variable, which will be destroyed when the function returns,
+leaving the caller with a dangling pointer.
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+
+  std::string_view return_stack_string_view() {
+    std::string s = "hello";
+    return s; // WARNING: address of stack memory is returned
+  }
+
+Dangling field
+--------------
+
+This check warns when a constructor or method assigns a pointer to a
+stack-allocated variable or temporary to a field of the class, and the
+stack variable's lifetime is shorter than the object's lifetime.
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+
+  struct DanglingField {
+    std::string_view view;
+    // WARNING: 's' is a temporary that will be destroyed after the
+    // constructor finishes, leaving 'view' dangling.
+    DanglingField(std::string s) : view(s) {}
+  };
+
+Use-after-invalidation (experimental)
+-------------------------------------
+
+This check warns when a reference to a container element (such as an iterator,
+pointer or reference) is used after a container operation that may have
+invalidated it. For example, adding elements to ``std::vector`` may cause
+reallocation, invalidating all existing iterators, pointers and references to
+its elements.
+
+.. note::
+  Container invalidation checking is highly experimental and may produce false
+  positives or miss some invalidations. Field-sensitivity is also limited.
+
+.. code-block:: c++
+
+  #include <vector>
+
+  void use_after_invalidation(std::vector<int>& v) {
+    int* p = &v[0];
+    v.push_back(4); // push_back might reallocate and invalidate p
+    *p = 10;        // WARNING: use after invalidation
+  }
+
+Annotation Inference and Suggestions
+====================================
+
+In addition to detecting lifetime violations, the analysis can suggest adding
+``[[clang::lifetimebound]]`` to function parameters or methods when it detects
+that a pointer/reference to a parameter or ``this`` escapes via the return
+value. This helps improve API contracts and allows the analysis to perform
+more accurate checks in calling code.
+
+To enable annotation suggestions, use ``-Wlifetime-safety-suggestions``.
+
+.. code-block:: c++
+
+  #include <string_view>
+
+  // The analysis will suggest adding [[clang::lifetimebound]] to 'a'
+  // because 'a' is returned.
+  std::string_view return_view(std::string_view a) { // warning: parameter in 
intra-TU function should be marked [[clang::lifetimebound]]
+    return a;               // note: param returned here
+  }
+
+TU-Wide analysis and Inference
+------------------------------
+
+By default, lifetime analysis is intra-procedural for error checking.
+However, for annotation inference to be effective, lifetime information needs
+to propagate across function calls. You can enable experimental
+Translation-Unit-wide analysis using:
+
+*   ``-flifetime-safety-inference``: Enables inference of ``lifetimebound``
+    attributes across functions in a TU.
+*   ``-fexperimental-lifetime-safety-tu-analysis``: Enables TU-wide analysis
+    for better inference results.
+
+.. _warning_flags:
+
+Warning flags
+=============
+
+Lifetime safety warnings are organized into hierarchical groups, allowing 
users to
+enable categories of checks incrementally. For example, ``-Wlifetime-safety``
+enables all dangling pointer checks, while ``-Wlifetime-safety-permissive``
+enables only the high-confidence subset of these checks.
+
+*   **``-Wlifetime-safety-all``**: Enables all lifetime safety warnings, 
including
+    dangling pointer checks, annotation suggestions, and annotation 
validations.
+
+*   **``-Wlifetime-safety``**: Enables dangling pointer checks from both the
+    ``permissive`` and ``strict`` groups listed below.
+    *   **``-Wlifetime-safety-permissive``**: Enables high-confidence checks 
for dangling
+        pointers. Recommended for initial adoption.
+        *   **``-Wlifetime-safety-use-after-scope``**: Warns when a pointer to
+            a stack variable is used after the variable's lifetime has ended.
+        *   **``-Wlifetime-safety-return-stack-addr``**: Warns when a function
+            returns a pointer or reference to one of its local stack variables.
+        *   **``-Wlifetime-safety-dangling-field``**: Warns when a class field 
is
+            assigned a pointer to a temporary or stack variable whose lifetime
+            is shorter than the class instance.
+    *   **``-Wlifetime-safety-strict``**: Enables stricter and experimental 
checks. These
+        may produce false positives in code that uses move semantics heavily, 
as
+        the analysis might conservatively assume a use-after-free even if
+        ownership was transferred.
+        *   **``-Wlifetime-safety-use-after-scope-moved``**: Same as
+            ``-Wlifetime-safety-use-after-scope`` but for cases where the
+            variable may have been moved from before its destruction.
+        *   **``-Wlifetime-safety-return-stack-addr-moved``**: Same as
+            ``-Wlifetime-safety-return-stack-addr`` but for cases where the
+            variable may have been moved from.
+        *   **``-Wlifetime-safety-dangling-field-moved``**: Same as
+            ``-Wlifetime-safety-dangling-field`` but for cases where the
+            variable may have been moved from.
+        *   **``-Wlifetime-safety-invalidation``**: Warns when a container
+            iterator or reference to an element is used after an operation
+            that may invalidate it (Experimental).
+
+*   **``-Wlifetime-safety-suggestions``**: Enables suggestions to add
+    ``[[clang::lifetimebound]]`` to function parameters and ``this``
+    parameters.
+    *   **``-Wlifetime-safety-intra-tu-suggestions``**: Suggestions for 
functions
+        local to the translation unit.
+    *   **``-Wlifetime-safety-cross-tu-suggestions``**: Suggestions for 
functions
+        visible across translation units (e.g., in headers).
+
+*   **``-Wlifetime-safety-validations``**: Enables checks that validate 
existing
+    lifetime annotations.
+    *   **``-Wlifetime-safety-noescape``**: Warns when a parameter marked with
+        ``[[clang::noescape]]`` escapes the function.
+
+Limitations
+===========
+
+Move Semantics and False Positives
+----------------------------------
+When an object is moved from, its state becomes unspecified. If pointers or
+views were created that refer to the object *before* it was moved, those
+pointers may become invalid after the move. Because the analysis cannot always
+know if a move operation invalidates outstanding pointers or simply transfers
+ownership, it issues ``-Wlifetime-safety-*-moved`` warnings in these 
situations.
+These warnings indicate a *potential* dangling issue but may be false positives
+if ownership was safely transferred and the resource remains alive.
+``std::unique_ptr::release()`` is treated similarly to ``std::move()`` in this
+regard, as it also relinquishes ownership.
+
+To avoid these warnings and prevent potential bugs, follow the
+**"move-first-then-alias"** pattern: ensure that views or raw pointers are
+created *after* a potential move, sourcing them from the new owner rather than
+aliasing an object that is about to be moved.
+
+For example, when initializing fields in a constructor, moving from a 
parameter *after* using it to initialize a view field can lead to warnings:
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+  #include <utility>
+
+  struct BadFieldOrder {
+    std::string_view view;
+    std::string s_owned;
+    // WARNING: 'view' is initialized from 's', then 's' is moved-from,
+    // leaving 'view' pointing to a moved-from string.
+    BadFieldOrder(std::string s) : view(s), s_owned(std::move(s)) {} // 
-Wlifetime-safety-dangling-field-moved
+  };
+
+  // CORRECT: Move 's' into 's_owned' first, then initialize 'view' from 
's_owned'.
+  struct GoodFieldOrder {
+    std::string s_owned;
+    std::string_view view;
+    GoodFieldOrder(std::string s) : s_owned(std::move(s)), view(s_owned) {} // 
OK
+  };
+
+The same principle applies when creating other aliases via ``get()`` or 
``release()`` before moving or releasing ownership:
+
+.. code-block:: c++
+
+  #include <memory>
+  #include <utility>
+
+  void use(int*);
+  void take_ownership(std::unique_ptr<int>);
+
+  void test_aliasing_before_move() {
+    int* p;
+    {
+      auto u = std::make_unique<int>(1);
+      p = u.get(); // p aliases u's content
+      take_ownership(std::move(u)); // u is moved-from
+    }
+    // 'p' now points to memory whose ownership was transferred,
+    // and it might be invalid depending on what take_ownership does.
+    use(p); // WARNING: -Wlifetime-safety-use-after-scope-moved
+  }
+
+Dangling Fields and Intra-Procedural Analysis
+---------------------------------------------
+The lifetime analysis is intra-procedural. It analyzes one function or method 
at
+a time.
+This means if a field is assigned a pointer to a local variable or temporary
+inside a constructor or method, and that local's lifetime ends before the 
method
+returns, the analysis will issue a ``-Wlifetime-safety-dangling-field`` 
warning.
+It must do so even if no *other* method of the class ever accesses this field,
+because it cannot see how other methods are implemented or used.
+
+.. code-block:: c++
+
+  #include <string>
+  #include <string_view>
+
+  struct MyWidget {
+    std::string_view name_;
+    MyWidget(std::string name) : name_(name) {} // WARNING: 'name' is 
destroyed when ctor ends, leaving 'name_' dangling
+    const char* data() { return name_.data(); } // Potential use-after-free if 
called
+  };
+
+In this case, ``name_`` dangles after the constructor finishes.
+Even if ``data()`` is never called, the analysis flags the dangling assignment
+in the constructor because it represents a latent bug.
+The recommended approach is to ensure fields only point to objects that outlive
+the field itself, for example by storing an owned object (e.g., 
``std::string``)
+or ensuring the borrowed object (e.g., one passed by ``const&``) has a
+sufficient lifetime.
+
+
+Heap and Globals
+----------------
+
+Currently, the analysis focuses on dangling pointers to stack variables,
+temporaries, and function parameters. It does not track lifetimes of heap-
+allocated memory or global variables.
+
+Performance
+===========
+
+Lifetime analysis relies on Clang's CFG (Control Flow Graph). For functions
+with very large or complex CFGs, analysis time can be significant. To mitigate
+this, the analysis will skip functions where the number of CFG blocks exceeds
+a certain threshold, controlled by the ``-flifetime-safety-max-cfg-blocks=N`` 
language
+option.

>From f2264d87b54266a5b3ab0edc6600830d394df8bf Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <[email protected]>
Date: Tue, 24 Feb 2026 15:06:25 +0100
Subject: [PATCH 2/3] Apply changes from code browser

Apply changes from code browser
---
 clang/docs/LifetimeSafety.rst | 41 ++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/clang/docs/LifetimeSafety.rst b/clang/docs/LifetimeSafety.rst
index 4c27f3aea5244..6a4f18ef50e53 100644
--- a/clang/docs/LifetimeSafety.rst
+++ b/clang/docs/LifetimeSafety.rst
@@ -357,28 +357,35 @@ To avoid these warnings and prevent potential bugs, 
follow the
 created *after* a potential move, sourcing them from the new owner rather than
 aliasing an object that is about to be moved.
 
-For example, when initializing fields in a constructor, moving from a 
parameter *after* using it to initialize a view field can lead to warnings:
+For example:
 
 .. code-block:: c++
 
-  #include <string>
-  #include <string_view>
-  #include <utility>
+  #include <memory>
 
-  struct BadFieldOrder {
-    std::string_view view;
-    std::string s_owned;
-    // WARNING: 'view' is initialized from 's', then 's' is moved-from,
-    // leaving 'view' pointing to a moved-from string.
-    BadFieldOrder(std::string s) : view(s), s_owned(std::move(s)) {} // 
-Wlifetime-safety-dangling-field-moved
-  };
+  void use(int*);
+  void take(std::unique_ptr<int>&&);
 
-  // CORRECT: Move 's' into 's_owned' first, then initialize 'view' from 
's_owned'.
-  struct GoodFieldOrder {
-    std::string s_owned;
-    std::string_view view;
-    GoodFieldOrder(std::string s) : s_owned(std::move(s)), view(s_owned) {} // 
OK
-  };
+  void bar() {
+    std::unique_ptr<int> b;
+    int* p;
+    {
+      auto a = std::make_unique<int>(42);
+      p = a.get(); // p aliases a's content
+      b = std::move(a); // a is moved-from
+    }
+    use(p); // WARNING: -Wlifetime-safety-use-after-scope-moved
+  }
+
+  void foo() {
+    int* p;
+    {
+      auto a = std::make_unique<int>(42);
+      p = a.get(); // p aliases a's content
+      take(std::move(a)); // a is moved-from and goes out of scope
+    }
+    use(p); // WARNING: -Wlifetime-safety-use-after-scope-moved
+  }
 
 The same principle applies when creating other aliases via ``get()`` or 
``release()`` before moving or releasing ownership:
 

>From a4985805d9c8b4b0ad0964cc2716386e33f5937f Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <[email protected]>
Date: Tue, 24 Feb 2026 15:11:33 +0100
Subject: [PATCH 3/3] Apply changes from code browser

Apply changes from code browser
---
 clang/docs/LifetimeSafety.rst | 458 ++++++++++++++++++++++------------
 clang/docs/index.rst          |   1 +
 2 files changed, 301 insertions(+), 158 deletions(-)

diff --git a/clang/docs/LifetimeSafety.rst b/clang/docs/LifetimeSafety.rst
index 6a4f18ef50e53..ff657fa42a2fb 100644
--- a/clang/docs/LifetimeSafety.rst
+++ b/clang/docs/LifetimeSafety.rst
@@ -1,6 +1,6 @@
-======================
+========================
 Lifetime Safety Analysis
-======================
+========================
 
 .. contents::
    :local:
@@ -44,16 +44,18 @@ Getting Started
     std::string_view v;
     {
       std::string s = "hello";
-      v = s;  // 'v' borrows from 's'.
-    }       // 's' is destroyed here, 'v' becomes dangling.
-    (void)v;  // WARNING! 'v' is used after 's' has been destroyed.
+      v = s;  // warning: object whose reference is captured does not live 
long enough
+    }         // note: destroyed here
+    std::cout << v; // note: later used here
   }
 
 This example demonstrates
-a basic use-after-scope defect. The ``std::string_view`` object ``v`` holds a
+a basic use-after-scope bug. The ``std::string_view`` object ``v`` holds a
 reference to ``s``, a ``std::string``. When ``s`` goes out of
-scope at the end of the inner block, ``v`` becomes a dangling reference, and
-its subsequent use is flagged by the analysis.
+scope at the end of the inner block, ``v`` becomes a dangling reference.
+The analysis flags the assignment ``v = s`` as defective because ``s`` is
+destroyed while ``v`` is still alive and points to ``s``, and adds a note
+to where ``v`` is used after ``s`` has been destroyed.
 
 Running The Analysis
 --------------------
@@ -98,12 +100,12 @@ types using these attributes:
   #include <string>
   #include <string_view>
 
-  // Owning type
+  // Owner type
   struct [[gsl::Owner]] MyObj {
     std::string Data = "Hello";
   };
 
-  // Non-owning view type
+  // View type
   struct [[gsl::Pointer]] View {
     std::string_view SV;
     View() = default;
@@ -115,9 +117,9 @@ types using these attributes:
     View v;
     {
       MyObj o;
-      v = o;
-    } // o is destroyed
-    v.use(); // WARNING: object whose reference is captured does not live long 
enough
+      v = o; // warning: object whose reference is captured does not live long 
enough
+    }        // note: destroyed here
+    v.use(); // note: later used here
   }
 
 Without these annotations, the analysis may not be able to determine whether a
@@ -149,8 +151,9 @@ arguments.
   void test_lifetimebound() {
     std::string_view sv;
     sv = MyOwner().getView(); // getView() is called on a temporary MyOwner
-                             // MyOwner temporary is destroyed here.
-    (void)sv;                // WARNING: object whose reference is captured 
does not live long enough
+                             // warning: object whose reference is captured 
does not live long enough
+                             // note: destroyed here
+    (void)sv;                // note: later used here
   }
 
 Without ``[[clang::lifetimebound]]`` on ``getView()``, the analysis would not
@@ -173,39 +176,97 @@ For more details, see `noescape 
<https://clang.llvm.org/docs/AttributeReference.
 Checks Performed
 ================
 
-Use-After-Scope
+
+.. raw:: html
+
+   <style>
+   /* Align text to left and add red/green colors */
+   table.colored-code-table td, table.colored-code-table th { text-align: left 
!important; }
+   table.colored-code-table td:first-child, table.colored-code-table 
th:first-child { background-color: #ffeaea !important; }
+   table.colored-code-table td:nth-child(2), table.colored-code-table 
th:nth-child(2) { background-color: #eafaea !important; }
+   table.colored-code-table td .highlight, table.colored-code-table td pre { 
background-color: transparent !important; border: none !important; }
+
+   div.bad-code { background-color: #ffeaea !important; padding: 5px; 
border-left: 4px solid #ff6b6b; text-align: left !important; }
+   div.bad-code .highlight, div.bad-code pre { background-color: transparent 
!important; border: none !important; }
+
+   div.good-code { background-color: #eafaea !important; padding: 5px; 
border-left: 4px solid #51cf66; text-align: left !important; }
+   div.good-code .highlight, div.good-code pre { background-color: transparent 
!important; border: none !important; }
+   </style>
+
+Use after scope
 ---------------
 
 This is the simplest dangling pointer scenario, where a pointer or reference
 outlives the stack variable it refers to.
 
-.. code-block:: c++
-
-  void use_after_scope() {
-    int* p;
-    {
-      int i = 0;
-      p = &i; // p borrows from i
-    }       // i is destroyed, p dangles
-    (void)*p; // WARNING: use-after-scope
-  }
+.. list-table::
+   :widths: 50 50
+   :header-rows: 1
+   :class: colored-code-table
+
+   * - Use after scope
+     - Correct
+   * -
+       .. code-block:: c++
+
+         void foo() {
+           int* p;
+           {
+             int i = 0;
+             p = &i;  // warning: 'p' does not live long enough
+           }          // note: destroyed here
+           (void)*p;  // note: later used here
+         }
+     -
+       .. code-block:: c++
+
+         void foo() {
+           int i = 0;
+           int* p;
+           {
+             p = &i; // OK!
+           }
+           (void)*p;
+         }
 
 Return of stack address
 -----------------------
 
 This check warns when a function returns a pointer or reference to a
 stack-allocated variable, which will be destroyed when the function returns,
-leaving the caller with a dangling pointer.
+leaving the caller with a dangling pointer.◊
 
-.. code-block:: c++
+.. list-table::
+   :widths: 50 50
+   :header-rows: 1
+   :class: colored-code-table
 
-  #include <string>
-  #include <string_view>
+   * - Return of stack address
+     - Correct
+   * -
+       .. code-block:: c++
+
+        #include <string>
+        #include <string_view>
+
+        std::string_view bar() {
+          std::string s = "on stack";
+          std::string_view result = s;
+          // warning: address of stack variable 's' is returned later
+          return result; // note: returned here
+        }
+     -
+       .. code-block:: c++
+
+        #include <string>
+        #include <string_view>
+
+        std::string bar() {
+          std::string s = "on stack";
+          std::string_view result = s;
+          return result; // OK!
+        }
 
-  std::string_view return_stack_string_view() {
-    std::string s = "hello";
-    return s; // WARNING: address of stack memory is returned
-  }
 
 Dangling field
 --------------
@@ -214,19 +275,48 @@ This check warns when a constructor or method assigns a 
pointer to a
 stack-allocated variable or temporary to a field of the class, and the
 stack variable's lifetime is shorter than the object's lifetime.
 
-.. code-block:: c++
-
-  #include <string>
-  #include <string_view>
-
-  struct DanglingField {
-    std::string_view view;
-    // WARNING: 's' is a temporary that will be destroyed after the
-    // constructor finishes, leaving 'view' dangling.
-    DanglingField(std::string s) : view(s) {}
-  };
-
-Use-after-invalidation (experimental)
+.. list-table::
+   :widths: 50 50
+   :header-rows: 1
+   :class: colored-code-table
+
+
+   * - Dangling field
+     - Correct
+   * -
+       .. code-block:: c++
+
+          #include <string>
+          #include <string_view>
+
+          // Constructor finishes, leaving 'field' dangling.
+          struct DanglingField {
+            std::string_view field; // note: this field dangles
+            DanglingField(std::string s) {
+              field = s; // warning: stack variable 's' escapes to a field
+            }
+          };
+     -
+       .. code-block:: c++
+
+          // Make the field an owner.
+          struct DanglingField {
+            std::string field;
+            DanglingField(std::string s) {
+              field = s;
+            }
+          };
+          // Or take a string_view parameter.
+          struct DanglingField {
+            std::string_view field;
+            DanglingField(std::string_view s [[clang::lifetimebound]]) {
+              field = s;
+            }
+          };
+         };
+
+
+Use after invalidation (experimental)
 -------------------------------------
 
 This check warns when a reference to a container element (such as an iterator,
@@ -239,15 +329,35 @@ its elements.
   Container invalidation checking is highly experimental and may produce false
   positives or miss some invalidations. Field-sensitivity is also limited.
 
-.. code-block:: c++
+.. list-table::
+   :widths: 50 50
+   :header-rows: 1
+   :class: colored-code-table
 
-  #include <vector>
 
-  void use_after_invalidation(std::vector<int>& v) {
-    int* p = &v[0];
-    v.push_back(4); // push_back might reallocate and invalidate p
-    *p = 10;        // WARNING: use after invalidation
-  }
+   * - Use after invalidation (experimental)
+     - Correct
+   * -
+       .. code-block:: c++
+
+        #include <vector>
+
+        void baz(std::vector<int>& v) {
+          int* p = &v[0]; // warning: 'v' is later invalidated
+          v.push_back(4); // note: invalidated here
+          *p = 10;        // note: later used here
+        }
+     -
+       .. code-block:: c++
+
+        #include <vector>
+
+        void baz(std::vector<int>& v) {
+          v.push_back(4);
+          int* p = &v[0]; // OK!
+          *p = 10;
+        }
+
 
 Annotation Inference and Suggestions
 ====================================
@@ -264,14 +374,15 @@ To enable annotation suggestions, use 
``-Wlifetime-safety-suggestions``.
 
   #include <string_view>
 
-  // The analysis will suggest adding [[clang::lifetimebound]] to 'a'
-  // because 'a' is returned.
-  std::string_view return_view(std::string_view a) { // warning: parameter in 
intra-TU function should be marked [[clang::lifetimebound]]
+  // The analysis will suggest adding [[clang::lifetimebound]] to 'a'.
+  std::string_view return_view(std::string_view a) { 
+                            // ^^^^^^^^^^^^^^^^^^
+                            // warning: parameter 'a' should be marked 
[[clang::lifetimebound]]
     return a;               // note: param returned here
   }
 
-TU-Wide analysis and Inference
-------------------------------
+Translation-Unit-Wide Analysis and Inference
+--------------------------------------------
 
 By default, lifetime analysis is intra-procedural for error checking.
 However, for annotation inference to be effective, lifetime information needs
@@ -293,124 +404,162 @@ enable categories of checks incrementally. For example, 
``-Wlifetime-safety``
 enables all dangling pointer checks, while ``-Wlifetime-safety-permissive``
 enables only the high-confidence subset of these checks.
 
-*   **``-Wlifetime-safety-all``**: Enables all lifetime safety warnings, 
including
+*  ``-Wlifetime-safety-all``: Enables all lifetime safety warnings, including
     dangling pointer checks, annotation suggestions, and annotation 
validations.
 
-*   **``-Wlifetime-safety``**: Enables dangling pointer checks from both the
-    ``permissive`` and ``strict`` groups listed below.
-    *   **``-Wlifetime-safety-permissive``**: Enables high-confidence checks 
for dangling
-        pointers. Recommended for initial adoption.
-        *   **``-Wlifetime-safety-use-after-scope``**: Warns when a pointer to
-            a stack variable is used after the variable's lifetime has ended.
-        *   **``-Wlifetime-safety-return-stack-addr``**: Warns when a function
-            returns a pointer or reference to one of its local stack variables.
-        *   **``-Wlifetime-safety-dangling-field``**: Warns when a class field 
is
-            assigned a pointer to a temporary or stack variable whose lifetime
-            is shorter than the class instance.
-    *   **``-Wlifetime-safety-strict``**: Enables stricter and experimental 
checks. These
-        may produce false positives in code that uses move semantics heavily, 
as
-        the analysis might conservatively assume a use-after-free even if
-        ownership was transferred.
-        *   **``-Wlifetime-safety-use-after-scope-moved``**: Same as
-            ``-Wlifetime-safety-use-after-scope`` but for cases where the
-            variable may have been moved from before its destruction.
-        *   **``-Wlifetime-safety-return-stack-addr-moved``**: Same as
-            ``-Wlifetime-safety-return-stack-addr`` but for cases where the
-            variable may have been moved from.
-        *   **``-Wlifetime-safety-dangling-field-moved``**: Same as
-            ``-Wlifetime-safety-dangling-field`` but for cases where the
-            variable may have been moved from.
-        *   **``-Wlifetime-safety-invalidation``**: Warns when a container
-            iterator or reference to an element is used after an operation
-            that may invalidate it (Experimental).
-
-*   **``-Wlifetime-safety-suggestions``**: Enables suggestions to add
-    ``[[clang::lifetimebound]]`` to function parameters and ``this``
-    parameters.
-    *   **``-Wlifetime-safety-intra-tu-suggestions``**: Suggestions for 
functions
-        local to the translation unit.
-    *   **``-Wlifetime-safety-cross-tu-suggestions``**: Suggestions for 
functions
-        visible across translation units (e.g., in headers).
-
-*   **``-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``: Enables dangling pointer checks from both the 
``permissive`` and ``strict`` groups listed below.
+
+  * ``-Wlifetime-safety-permissive``: Enables high-confidence checks for 
dangling pointers. **Recommended for initial adoption.**
+
+    * ``-Wlifetime-safety-use-after-scope``: Warns when a pointer to a stack 
variable is used after the variable's lifetime has ended.
+    * ``-Wlifetime-safety-return-stack-addr``: Warns when a function returns a 
pointer or reference to one of its local stack variables.
+    * ``-Wlifetime-safety-dangling-field``: Warns when a class field is 
assigned a pointer to a temporary or stack variable whose lifetime is shorter 
than the class instance.
+  
+  * ``-Wlifetime-safety-strict``: Enables stricter and experimental checks. 
These may produce false positives in code that uses move semantics heavily, as 
the analysis might conservatively assume a use-after-free even if ownership was 
transferred.
+
+    *   ``-Wlifetime-safety-use-after-scope-moved``: Same as 
``-Wlifetime-safety-use-after-scope`` but for cases where the variable may have 
been moved from before its destruction.
+    *   ``-Wlifetime-safety-return-stack-addr-moved``: Same as 
``-Wlifetime-safety-return-stack-addr`` but for cases where the variable may 
have been moved from.
+    *   ``-Wlifetime-safety-dangling-field-moved``: Same as 
``-Wlifetime-safety-dangling-field`` but for cases where the variable may have 
been moved from.
+    *   ``-Wlifetime-safety-invalidation``: Warns when a container iterator or 
reference to an element is used after an operation that may invalidate it 
(Experimental).
+
+*   ``-Wlifetime-safety-suggestions``: Enables suggestions to add 
``[[clang::lifetimebound]]`` to function parameters and ``this`` parameters.
+
+  * ``-Wlifetime-safety-intra-tu-suggestions``: Suggestions for functions 
local to the translation unit.
+  * ``-Wlifetime-safety-cross-tu-suggestions``: Suggestions for functions 
visible across translation units (e.g., in headers).
+
+* ``-Wlifetime-safety-validations``: Enables checks that validate existing 
lifetime annotations.
+
+  * ``-Wlifetime-safety-noescape``: Warns when a parameter marked with 
``[[clang::noescape]]`` escapes the function.
 
 Limitations
 ===========
 
-Move Semantics and False Positives
-----------------------------------
-When an object is moved from, its state becomes unspecified. If pointers or
-views were created that refer to the object *before* it was moved, those
-pointers may become invalid after the move. Because the analysis cannot always
-know if a move operation invalidates outstanding pointers or simply transfers
-ownership, it issues ``-Wlifetime-safety-*-moved`` warnings in these 
situations.
-These warnings indicate a *potential* dangling issue but may be false positives
-if ownership was safely transferred and the resource remains alive.
-``std::unique_ptr::release()`` is treated similarly to ``std::move()`` in this
-regard, as it also relinquishes ownership.
-
-To avoid these warnings and prevent potential bugs, follow the
-**"move-first-then-alias"** pattern: ensure that views or raw pointers are
-created *after* a potential move, sourcing them from the new owner rather than
-aliasing an object that is about to be moved.
+Move Semantics
+--------------
+The analysis does not currently track ownership transfers through move 
operations.
+Instead, it uses scope-based lifetime tracking: when an owner goes out of 
scope,
+the analysis assumes the resource is destroyed, even if ownership was 
transferred
+via ``std::move()`` or ``std::unique_ptr::release()``.
+
+This means that if a pointer or view is created from an owner, and that owner 
is
+later moved-from and goes out of scope, the analysis will issue a
+``-Wlifetime-safety-*-moved`` warning. This warning indicates that the pointer
+may be dangling, even though the resource may still be alive under a new owner.
+These are often false positives when ownership has been safely transferred.
+
+To avoid these warnings and ensure correctness, follow the
+**"move-first-then-alias"** pattern: create views or raw pointers *after* the
+ownership transfer, sourcing them from the new owner rather than the original
+owner that will go out of scope.
 
 For example:
 
+.. list-table::
+   :widths: 50 50
+   :header-rows: 1
+   :align: left
+   :class: colored-code-table
+
+   * - Anti-Pattern: Aliasing Before Move
+     - Good Practice: Move-First-Then-Alias
+   * -
+       .. code-block:: c++
+
+         #include <memory>
+
+         void use(int*);
+
+         void bar() {
+           std::unique_ptr<int> b;
+           int* p;
+           {
+             auto a = std::make_unique<int>(42);
+             p = a.get(); // warning!
+             b = std::move(a);
+           }
+           use(p);
+         }
+     -
+       .. code-block:: c++
+
+         #include <memory>
+
+         void use(int*);
+
+         void bar() {
+           std::unique_ptr<int> b;
+           int* p;
+           {
+             auto a = std::make_unique<int>(42);
+             b = std::move(a);
+             p = b.get(); // OK!
+           }
+           use(p);
+         }
+
+The same principle applies when moving ownership using 
``std::unique_ptr::release()``:
+
 .. code-block:: c++
+  :class: bad-code
 
   #include <memory>
+  #include <utility>
 
   void use(int*);
-  void take(std::unique_ptr<int>&&);
+  void take_ownership(int*);
 
-  void bar() {
-    std::unique_ptr<int> b;
+  void test_aliasing_before_release() {
     int* p;
     {
-      auto a = std::make_unique<int>(42);
-      p = a.get(); // p aliases a's content
-      b = std::move(a); // a is moved-from
-    }
-    use(p); // WARNING: -Wlifetime-safety-use-after-scope-moved
-  }
-
-  void foo() {
-    int* p;
-    {
-      auto a = std::make_unique<int>(42);
-      p = a.get(); // p aliases a's content
-      take(std::move(a)); // a is moved-from and goes out of scope
-    }
-    use(p); // WARNING: -Wlifetime-safety-use-after-scope-moved
+      auto u = std::make_unique<int>(1);
+      p = u.get();
+      //  ^ warning: 'u' does not live long enough!
+      take_ownership(u.release());
+    } 
+    use(p);  
   }
 
-The same principle applies when creating other aliases via ``get()`` or 
``release()`` before moving or releasing ownership:
+``std::unique_ptr`` with custom deleters
+----------------------------------------
+The analysis assumes standard ownership semantics for owner types like
+``std::unique_ptr``: when a ``unique_ptr`` goes out of scope, it is assumed
+that the owned object is destroyed and its memory is deallocated.
+However, ``std::unique_ptr`` can be used with a custom deleter that modifies
+this behavior. For example, a custom deleter might keep the memory alive
+by transferring it to a memory pool, or simply do nothing, allowing
+another system to manage the lifetime.
+
+Because the analysis relies on scope-based lifetime for owners, it does not
+support custom deleters that extend the lifetime of the owned object beyond
+the lifetime of the ``std::unique_ptr``. In such cases, the analysis will
+assume the object is destroyed when the ``std::unique_ptr`` goes out of scope,
+leading to false positive warnings if pointers to the object are used 
afterward.
 
 .. code-block:: c++
 
   #include <memory>
-  #include <utility>
 
   void use(int*);
-  void take_ownership(std::unique_ptr<int>);
 
-  void test_aliasing_before_move() {
+  struct NoOpDeleter {
+    void operator()(int* p) const {
+      // Do not delete p, memory is managed elsewhere.
+    }
+  };
+
+  void test_custom_deleter() {
     int* p;
     {
-      auto u = std::make_unique<int>(1);
-      p = u.get(); // p aliases u's content
-      take_ownership(std::move(u)); // u is moved-from
-    }
-    // 'p' now points to memory whose ownership was transferred,
-    // and it might be invalid depending on what take_ownership does.
-    use(p); // WARNING: -Wlifetime-safety-use-after-scope-moved
+      std::unique_ptr<int, NoOpDeleter> u(new int(42));
+      p = u.get();  // warning: object whose reference is captured does not 
live long enough
+    }               // note: destroyed here
+    // With NoOpDeleter, p would still be valid here.
+    // But analysis assumes standard unique_ptr semantics and memory being 
freed.
+    use(p);         // note: later used here
   }
 
-Dangling Fields and Intra-Procedural Analysis
----------------------------------------------
+Dangling Fields
+---------------
 The lifetime analysis is intra-procedural. It analyzes one function or method 
at
 a time.
 This means if a field is assigned a pointer to a local variable or temporary
@@ -425,8 +574,8 @@ because it cannot see how other methods are implemented or 
used.
   #include <string_view>
 
   struct MyWidget {
-    std::string_view name_;
-    MyWidget(std::string name) : name_(name) {} // WARNING: 'name' is 
destroyed when ctor ends, leaving 'name_' dangling
+    std::string_view name_; // note: this field dangles
+    MyWidget(std::string name) : name_(name) {} // warning: address of stack 
memory escapes to a field
     const char* data() { return name_.data(); } // Potential use-after-free if 
called
   };
 
@@ -439,18 +588,11 @@ or ensuring the borrowed object (e.g., one passed by 
``const&``) has a
 sufficient lifetime.
 
 
-Heap and Globals
-----------------
-
-Currently, the analysis focuses on dangling pointers to stack variables,
-temporaries, and function parameters. It does not track lifetimes of heap-
-allocated memory or global variables.
-
 Performance
 ===========
 
 Lifetime analysis relies on Clang's CFG (Control Flow Graph). For functions
-with very large or complex CFGs, analysis time can be significant. To mitigate
-this, the analysis will skip functions where the number of CFG blocks exceeds
+with very large or complex CFGs, analysis time can sometimes be significant. 
To mitigate
+this, the analysis allows to skip functions where the number of CFG blocks 
exceeds
 a certain threshold, controlled by the ``-flifetime-safety-max-cfg-blocks=N`` 
language
 option.
diff --git a/clang/docs/index.rst b/clang/docs/index.rst
index 9647d1cd2fae9..f086daee9181f 100644
--- a/clang/docs/index.rst
+++ b/clang/docs/index.rst
@@ -26,6 +26,7 @@ Using Clang as a Compiler
    CrossCompilation
    ClangStaticAnalyzer
    ThreadSafetyAnalysis
+   LifetimeSafety
    SafeBuffers
    ScalableStaticAnalysisFramework/Framework
    DataFlowAnalysisIntro

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

Reply via email to