Author: Henrik G. Olsson
Date: 2026-05-22T12:20:52-07:00
New Revision: 1a264a9c0e628caf65b28fd4ba66af11fb6c6f1b

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

LOG: [docs] update noescape semantics to disallow free (#195973)

This changes the documented semantics of the `noescape` attribute to
disallow freeing the pointer, and allow escapes of the integer value of
the memory address, as discussed in

https://discourse.llvm.org/t/rfc-updating-the-semantics-of-the-noescape-attribute/90326.

It also clarifies that the attribute may only be used to annotate the
outermost pointer level of nested pointer parameters.

Added: 
    

Modified: 
    clang/docs/LifetimeSafety.rst
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/AttrDocs.td

Removed: 
    


################################################################################
diff  --git a/clang/docs/LifetimeSafety.rst b/clang/docs/LifetimeSafety.rst
index 324ee51d85242..9ae2e6ee54826 100644
--- a/clang/docs/LifetimeSafety.rst
+++ b/clang/docs/LifetimeSafety.rst
@@ -204,6 +204,8 @@ For more details, see `lifetimebound 
<https://clang.llvm.org/docs/AttributeRefer
 NoEscape
 --------
 
+.. _Wlifetime-safety-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

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3d8837266739f..3c1eacfc05dc8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -413,6 +413,13 @@ Attribute Changes in Clang
 
 - Clang now allows GNU attributes between a member declarator and bit-field 
width. (#GH184954)
 
+- The ``[[clang::noescape]]`` attribute now disallows deallocating memory
+  through the annotated parameter. This information is currently not exposed to
+  LLVM for optimization purposes, to prevent breaking existing adopters. It may
+  instead be used by warnings and static analyses to provide more information
+  about pointer lifetimes. It may be used to power optimizations in the future,
+  however there are no concrete plans to do so at the moment.
+
 Improvements to Clang's diagnostics
 -----------------------------------
 - Fixed bug in ``-Wdocumentation`` so that it correctly handles explicit

diff  --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 19d14837679d3..87b9053be7cb6 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -297,8 +297,14 @@ def NoEscapeDocs : Documentation {
 the compiler that the pointer cannot escape: that is, no reference to the 
object
 the pointer points to that is derived from the parameter value will survive
 after the function returns. Users are responsible for making sure parameters
-annotated with ``noescape`` do not actually escape. Calling ``free()`` on such
-a parameter does not constitute an escape.
+annotated with ``noescape`` do not actually escape. The optimizer may make
+assumptions based on the fact that it knows that a call to the function does
+not escape a certain parameter, so incorrectly annotating a parameter with
+``noescape`` leads to undefined behavior. The callee is also not allowed to
+deallocate memory through a ``noescape`` parameter: the optimizer does not make
+assumptions based on this information at the moment, but may do so in the
+future. Some cases of invalid uses of ``noescape`` can be found with
+:ref:`-Wlifetime-safety-noescape <Wlifetime-safety-noescape>`.
 
 For example:
 
@@ -314,6 +320,23 @@ For example:
     gp = p; // Not OK.
   }
 
+  void freeingFunc(__attribute__((noescape)) int *p) {
+    free(p); // Not OK.
+  }
+
+Since ``noescape`` is a parameter attribute and not a type attribute, it only
+applies to the outermost pointer level, regardless of where in the parameter
+declaration you place it:
+
+.. code-block:: c
+
+  int **gp;
+
+  void nestingEscapes(__attribute__((noescape)) int **p) {
+    gp = p; // Not OK.
+    *gp = *p; // OK, p does not escape.
+  }
+
 Additionally, when the parameter is a `block pointer
 <https://clang.llvm.org/docs/BlockLanguageSpec.html>`, the same restriction
 applies to copies of the block. For example:
@@ -332,6 +355,36 @@ applies to copies of the block. For example:
     g1 = Block_copy(block); // Not OK either.
   }
 
+The function *is* allowed to leak information about the memory address of the
+pointer, but not any provenance of the allocation:
+
+.. code-block:: c
+
+  bool isNull(__attribute__((noescape)) void *p) {
+    return !p; // OK.
+  }
+
+  uintptr_t gi;
+
+  void escapingAddress(__attribute__((noescape)) int *p) {
+    // OK *if and only if* gi is never casted back to a pointer.
+    gi = (uintptr_t)p;
+  }
+
+  bool usingEscapedAddress(int *p) {
+    return (uintptr_t)p > gi; // OK.
+  }
+
+  bool usingEscapedPointer(int *p) {
+    return p > (int*)gi; // Not OK.
+  }
+
+  int *gp;
+
+  void escapingEndFunc(__attribute__((noescape)) int *p, size_t len) {
+    gp = p + len; // Not OK.
+  }
+
   }];
 }
 


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

Reply via email to