https://github.com/hnrklssn created 
https://github.com/llvm/llvm-project/pull/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.

>From 86f7d636f5287de881712973f5c1b4e4ac5ca793 Mon Sep 17 00:00:00 2001
From: "Henrik G. Olsson" <[email protected]>
Date: Tue, 5 May 2026 18:13:44 -0700
Subject: [PATCH] [docs] update noescape semantics to disallow free

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.
---
 clang/docs/LifetimeSafety.rst         |  1 +
 clang/docs/ReleaseNotes.rst           |  7 ++++
 clang/include/clang/Basic/AttrDocs.td | 57 ++++++++++++++++++++++++++-
 3 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/clang/docs/LifetimeSafety.rst b/clang/docs/LifetimeSafety.rst
index c71816dd75a82..2bd44c17b4c36 100644
--- a/clang/docs/LifetimeSafety.rst
+++ b/clang/docs/LifetimeSafety.rst
@@ -200,6 +200,7 @@ with ``[[clang::lifetimebound]]`` annotated parameters:
 
 For more details, see `lifetimebound 
<https://clang.llvm.org/docs/AttributeReference.html#lifetimebound>`_.
 
+.. _Wlifetime-safety-noescape:
 NoEscape
 --------
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b2e62106506f0..d2994bf9ae97b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -257,6 +257,13 @@ Attribute Changes in Clang
   ``[[clang::always_inline]]`` with additional checks to ensure that they
   are only accepted in places where MSVC also does.
 
+- 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
 -----------------------------------
 - ``-Wunused-but-set-variable`` now diagnoses file-scope variables with
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 502af9b562ef0..59e052431a7a2 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