[llvm] [LangRef] Do not allow free via synchronization in nofree (PR #195658)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 4 07:14:45 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Nikita Popov (nikic)

<details>
<summary>Changes</summary>

The nofree attribute is currently specified to only forbid direct free calls inside the function. A nofree function is still allowed to compel a pointer to be freed by a different thread through synchronization.

This is currently only spelled out for the function-level nofree attribute, but I assume the same semantics also hold for argument nofree (and this matches how the Attributor implementation infers it).

The original motivation for this definition was to keep the attributes orthogonal and independently inferable. However, the problem is that nosync is a too strong condition: It excludes *any* synchronization, not just synchronization that results in the free of a pointer.

Some frontends like Rust can guarantee that most pointer arguments cannot be freed for the duration of a function call, including via synchronization. However, they cannot guarantee that no synchronization takes place at all. The current definition of nofree makes this inexpressible in LLVM IR, which blocks further progress on dereferenceable-at-point semantics.

This PR makes a few changes to the nofree spec:

 * Function-level nofree now disallows free via synchronization.
 * Argument-level nofree now also disallows free via synchronization (it previously made not statement in either direction).
 * Argument-level nofree is now specified to only apply to the particular pointer (similar to `captures` etc). The underlying object may still be freed via a different argument to which the same pointer is passed. (I'm open to changing this, but that would essentially limit inference to noalias arguments.)

Note: This PR doesn't include the necessary inference changes to comply with the new semantics yet. I'd like to make sure we're aligned on the direction first.

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


1 Files Affected:

- (modified) llvm/docs/LangRef.rst (+13-13) 


``````````diff
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 912cca72e1ad5..57e5743dde39e 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1543,8 +1543,11 @@ Currently, only the following parameter attributes are defined:
       is null is captured in some other way.
 
 ``nofree``
-    This indicates that the callee does not free the pointer argument. This is not
-    a valid attribute for return values.
+    This indicates that the callee does not free the pointer argument, or
+    cause it to be freed through synchronization.
+
+    This is not a valid attribute for return values. This attribute applies
+    only to the particular copy of the pointer passed in this argument.
 
 .. _nest:
 
@@ -2328,20 +2331,17 @@ For example:
 ``nofree``
     This function attribute indicates that the function does not, directly or
     transitively, call a memory-deallocation function (``free``, for example)
-    on a memory allocation which existed before the call.
+    on a memory allocation which existed before the call, or make such a call
+    visible through synchronization.
 
-    As a result, uncaptured pointers that are known to be dereferenceable
-    prior to a call to a function with the ``nofree`` attribute are still
-    known to be dereferenceable after the call. The capturing condition is
-    necessary in environments where the function might communicate the
-    pointer to another thread which then deallocates the memory.  Alternatively,
-    ``nosync`` would ensure such communication cannot happen and even captured
-    pointers cannot be freed by the function.
+    As a result, pointers that are known to be dereferenceable prior to a call
+    to a function with the ``nofree`` attribute are still known to be
+    dereferenceable after the call.
 
     A ``nofree`` function is explicitly allowed to free memory which it
-    allocated or (if not ``nosync``) arrange for another thread to free
-    memory on its behalf.  As a result, perhaps surprisingly, a ``nofree``
-    function can return a pointer to a previously deallocated
+    allocated or arrange for another thread to free such memory on its behalf.
+    As a result, perhaps surprisingly, a ``nofree`` function can return a
+    pointer to a previously deallocated
     :ref:`allocated object<allocatedobjects>`.
 ``noimplicitfloat``
     Disallows implicit floating-point code. This inhibits optimizations that

``````````

</details>


https://github.com/llvm/llvm-project/pull/195658


More information about the llvm-commits mailing list