[libc-commits] [libc] [libc] add basic lifetime annotations for support data structures (PR #145933)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Sat Jun 28 20:54:13 PDT 2025
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/145933
>From ee433d211c1987fb4bdae2bbf19ec6a4acdf4940 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 26 Jun 2025 13:24:48 -0400
Subject: [PATCH 1/3] [libc] add basic lifetime annotations for support data
structures
---
libc/src/__support/CPP/algorithm.h | 8 ++++++--
libc/src/__support/CPP/array.h | 19 +++++++++++++------
libc/src/__support/CPP/atomic.h | 2 +-
libc/src/__support/CPP/mutex.h | 10 +++++++---
libc/src/__support/CPP/optional.h | 12 ++++++++----
libc/src/__support/CPP/span.h | 7 ++++---
libc/src/__support/CPP/string.h | 15 +++++++++++----
libc/src/__support/CPP/string_view.h | 7 ++++++-
libc/src/__support/CPP/stringstream.h | 4 +++-
libc/src/__support/CPP/utility/forward.h | 6 ++++--
libc/src/__support/CPP/utility/move.h | 3 ++-
libc/src/__support/macros/attributes.h | 24 ++++++++++++++++++++++++
12 files changed, 89 insertions(+), 28 deletions(-)
diff --git a/libc/src/__support/CPP/algorithm.h b/libc/src/__support/CPP/algorithm.h
index 7704b3fa81f0c..3ea48db5b2d5e 100644
--- a/libc/src/__support/CPP/algorithm.h
+++ b/libc/src/__support/CPP/algorithm.h
@@ -18,11 +18,15 @@
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
-template <class T> LIBC_INLINE constexpr const T &max(const T &a, const T &b) {
+template <class T>
+LIBC_INLINE constexpr const T &max(LIBC_LIFETIMEBOUND const T &a,
+ LIBC_LIFETIMEBOUND const T &b) {
return (a < b) ? b : a;
}
-template <class T> LIBC_INLINE constexpr const T &min(const T &a, const T &b) {
+template <class T>
+LIBC_INLINE constexpr const T &min(LIBC_LIFETIMEBOUND const T &a,
+ LIBC_LIFETIMEBOUND const T &b) {
return (a < b) ? a : b;
}
diff --git a/libc/src/__support/CPP/array.h b/libc/src/__support/CPP/array.h
index db0a986b71205..b0c0add5f9727 100644
--- a/libc/src/__support/CPP/array.h
+++ b/libc/src/__support/CPP/array.h
@@ -31,15 +31,22 @@ template <class T, size_t N> struct array {
LIBC_INLINE constexpr T *data() { return Data; }
LIBC_INLINE constexpr const T *data() const { return Data; }
- LIBC_INLINE constexpr T &front() { return Data[0]; }
- LIBC_INLINE constexpr const T &front() const { return Data[0]; }
+ LIBC_INLINE constexpr T &front() LIBC_LIFETIMEBOUND { return Data[0]; }
+ LIBC_INLINE constexpr const T &front() const LIBC_LIFETIMEBOUND {
+ return Data[0];
+ }
- LIBC_INLINE constexpr T &back() { return Data[N - 1]; }
- LIBC_INLINE constexpr const T &back() const { return Data[N - 1]; }
+ LIBC_INLINE constexpr T &back() LIBC_LIFETIMEBOUND { return Data[N - 1]; }
+ LIBC_INLINE constexpr const T &back() const LIBC_LIFETIMEBOUND {
+ return Data[N - 1];
+ }
- LIBC_INLINE constexpr T &operator[](size_t Index) { return Data[Index]; }
+ LIBC_INLINE constexpr T &operator[](size_t Index) LIBC_LIFETIMEBOUND {
+ return Data[Index];
+ }
- LIBC_INLINE constexpr const T &operator[](size_t Index) const {
+ LIBC_INLINE constexpr const T &
+ operator[](size_t Index) const LIBC_LIFETIMEBOUND {
return Data[Index];
}
diff --git a/libc/src/__support/CPP/atomic.h b/libc/src/__support/CPP/atomic.h
index 2f00b3ed32811..4e084beaf8ef5 100644
--- a/libc/src/__support/CPP/atomic.h
+++ b/libc/src/__support/CPP/atomic.h
@@ -255,7 +255,7 @@ template <typename T> struct Atomic {
LIBC_INLINE void set(T rhs) { val = rhs; }
};
-template <typename T> struct AtomicRef {
+template <typename T> struct LIBC_GSL_POINTER AtomicRef {
static_assert(is_trivially_copyable_v<T> && is_copy_constructible_v<T> &&
is_move_constructible_v<T> && is_copy_assignable_v<T> &&
is_move_assignable_v<T>,
diff --git a/libc/src/__support/CPP/mutex.h b/libc/src/__support/CPP/mutex.h
index 8a3102426e2d6..407125c6e452b 100644
--- a/libc/src/__support/CPP/mutex.h
+++ b/libc/src/__support/CPP/mutex.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H
+#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
@@ -28,14 +29,17 @@ template <typename MutexType> class lock_guard {
public:
// Calls `m.lock()` upon resource acquisition.
- explicit lock_guard(MutexType &m) : mutex(m) { mutex.lock(); }
+ LIBC_INLINE explicit lock_guard(LIBC_LIFETIMEBOUND MutexType &m) : mutex(m) {
+ mutex.lock();
+ }
// Acquires ownership of the mutex object `m` without attempting to lock
// it. The behavior is undefined if the current thread does not hold the
// lock on `m`. Does not call `m.lock()` upon resource acquisition.
- lock_guard(MutexType &m, adopt_lock_t /* t */) : mutex(m) {}
+ LIBC_INLINE lock_guard(LIBC_LIFETIMEBOUND MutexType &m, adopt_lock_t /* t */)
+ : mutex(m) {}
- ~lock_guard() { mutex.unlock(); }
+ LIBC_INLINE ~lock_guard() { mutex.unlock(); }
// non-copyable
lock_guard &operator=(const lock_guard &) = delete;
diff --git a/libc/src/__support/CPP/optional.h b/libc/src/__support/CPP/optional.h
index aed2269db1b11..06cb0e3e992d1 100644
--- a/libc/src/__support/CPP/optional.h
+++ b/libc/src/__support/CPP/optional.h
@@ -108,11 +108,13 @@ template <typename T> class optional {
LIBC_INLINE constexpr void reset() { storage.reset(); }
- LIBC_INLINE constexpr const T &value() const & {
+ LIBC_INLINE constexpr const T &value() const &LIBC_LIFETIMEBOUND {
return storage.stored_value;
}
- LIBC_INLINE constexpr T &value() & { return storage.stored_value; }
+ LIBC_INLINE constexpr T &value() & LIBC_LIFETIMEBOUND {
+ return storage.stored_value;
+ }
LIBC_INLINE constexpr explicit operator bool() const {
return storage.in_use;
@@ -122,10 +124,12 @@ template <typename T> class optional {
return &storage.stored_value;
}
LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; }
- LIBC_INLINE constexpr const T &operator*() const & {
+ LIBC_INLINE constexpr const T &operator*() const &LIBC_LIFETIMEBOUND {
+ return storage.stored_value;
+ }
+ LIBC_INLINE constexpr T &operator*() & LIBC_LIFETIMEBOUND {
return storage.stored_value;
}
- LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; }
LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); }
LIBC_INLINE constexpr T &&operator*() && {
diff --git a/libc/src/__support/CPP/span.h b/libc/src/__support/CPP/span.h
index 9234a26d201cd..c02a139299e51 100644
--- a/libc/src/__support/CPP/span.h
+++ b/libc/src/__support/CPP/span.h
@@ -28,7 +28,7 @@ namespace cpp {
// - No implicit type conversion (e.g. Span<B>, initialized with As where A
// inherits from B),
// - No reverse iterators
-template <typename T> class span {
+template <typename T> class LIBC_GSL_POINTER span {
template <typename U>
LIBC_INLINE_VAR static constexpr bool is_const_view_v =
!cpp::is_const_v<U> && cpp::is_const_v<T> &&
@@ -64,11 +64,12 @@ template <typename T> class span {
template <typename U, size_t N,
cpp::enable_if_t<is_compatible_v<U>, bool> = true>
- LIBC_INLINE constexpr span(U (&arr)[N]) : span_data(arr), span_size(N) {}
+ LIBC_INLINE constexpr span(LIBC_LIFETIMEBOUND U (&arr)[N])
+ : span_data(arr), span_size(N) {}
template <typename U, size_t N,
cpp::enable_if_t<is_compatible_v<U>, bool> = true>
- LIBC_INLINE constexpr span(array<U, N> &arr)
+ LIBC_INLINE constexpr span(LIBC_LIFETIMEBOUND array<U, N> &arr)
: span_data(arr.data()), span_size(arr.size()) {}
template <typename U, cpp::enable_if_t<is_compatible_v<U>, bool> = true>
diff --git a/libc/src/__support/CPP/string.h b/libc/src/__support/CPP/string.h
index 1ac04c7f1f9dc..27748eeb953e3 100644
--- a/libc/src/__support/CPP/string.h
+++ b/libc/src/__support/CPP/string.h
@@ -106,16 +106,23 @@ class string {
LIBC_INLINE constexpr const char *end() const { return data() + size_; }
LIBC_INLINE char *end() { return data() + size_; }
- LIBC_INLINE constexpr const char &front() const { return data()[0]; }
+ LIBC_INLINE constexpr const char &front() const LIBC_LIFETIMEBOUND {
+ return data()[0];
+ }
LIBC_INLINE char &front() { return data()[0]; }
- LIBC_INLINE constexpr const char &back() const { return data()[size_ - 1]; }
+ LIBC_INLINE constexpr const char &back() const LIBC_LIFETIMEBOUND {
+ return data()[size_ - 1];
+ }
LIBC_INLINE char &back() { return data()[size_ - 1]; }
- LIBC_INLINE constexpr const char &operator[](size_t index) const {
+ LIBC_INLINE constexpr const char &
+ operator[](size_t index) const LIBC_LIFETIMEBOUND {
+ return data()[index];
+ }
+ LIBC_INLINE char &operator[](size_t index) LIBC_LIFETIMEBOUND {
return data()[index];
}
- LIBC_INLINE char &operator[](size_t index) { return data()[index]; }
LIBC_INLINE const char *c_str() const { return data(); }
diff --git a/libc/src/__support/CPP/string_view.h b/libc/src/__support/CPP/string_view.h
index aa15814b2e149..b9182cdaa1856 100644
--- a/libc/src/__support/CPP/string_view.h
+++ b/libc/src/__support/CPP/string_view.h
@@ -18,12 +18,13 @@
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
+class string;
// This is very simple alternate of the std::string_view class. There is no
// bounds check performed in any of the methods. The callers are expected to
// do the checks before invoking the methods.
//
// This class will be extended as needed in future.
-class string_view {
+class LIBC_GSL_POINTER string_view {
private:
const char *Data;
size_t Len;
@@ -77,6 +78,10 @@ class string_view {
LIBC_INLINE constexpr string_view(const char *Str, size_t N)
: Data(Str), Len(N) {}
+ template <size_t N>
+ LIBC_INLINE constexpr string_view(LIBC_LIFETIMEBOUND const char (&Str)[N])
+ : Data(Str), Len(N) {}
+
LIBC_INLINE constexpr const char *data() const { return Data; }
// Returns the size of the string_view.
diff --git a/libc/src/__support/CPP/stringstream.h b/libc/src/__support/CPP/stringstream.h
index a16084c848688..a0039f2de4858 100644
--- a/libc/src/__support/CPP/stringstream.h
+++ b/libc/src/__support/CPP/stringstream.h
@@ -48,7 +48,9 @@ class StringStream {
// null terminator was not explicitly written, then the return value
// will not include one. In order to produce a string_view to a null
// terminated string, write ENDS explicitly.
- string_view str() const { return string_view(data.data(), write_ptr); }
+ [[nodiscard]] LIBC_INLINE string_view str() const {
+ return string_view(data.data(), write_ptr);
+ }
// Write the characters from |str| to the stream.
StringStream &operator<<(string_view str) {
diff --git a/libc/src/__support/CPP/utility/forward.h b/libc/src/__support/CPP/utility/forward.h
index 085b3d16f999b..7383687d7b7c8 100644
--- a/libc/src/__support/CPP/utility/forward.h
+++ b/libc/src/__support/CPP/utility/forward.h
@@ -18,12 +18,14 @@ namespace cpp {
// forward
template <typename T>
-LIBC_INLINE constexpr T &&forward(remove_reference_t<T> &value) {
+LIBC_INLINE constexpr T &&
+forward(LIBC_LIFETIMEBOUND remove_reference_t<T> &value) {
return static_cast<T &&>(value);
}
template <typename T>
-LIBC_INLINE constexpr T &&forward(remove_reference_t<T> &&value) {
+LIBC_INLINE constexpr T &&
+forward(LIBC_LIFETIMEBOUND remove_reference_t<T> &&value) {
static_assert(!is_lvalue_reference_v<T>,
"cannot forward an rvalue as an lvalue");
return static_cast<T &&>(value);
diff --git a/libc/src/__support/CPP/utility/move.h b/libc/src/__support/CPP/utility/move.h
index b61f723e8d4cb..3bbc5f1df4498 100644
--- a/libc/src/__support/CPP/utility/move.h
+++ b/libc/src/__support/CPP/utility/move.h
@@ -17,7 +17,8 @@ namespace cpp {
// move
template <class T>
-LIBC_INLINE constexpr cpp::remove_reference_t<T> &&move(T &&t) {
+LIBC_INLINE constexpr cpp::remove_reference_t<T> &&
+move(LIBC_LIFETIMEBOUND T &&t) {
return static_cast<typename cpp::remove_reference_t<T> &&>(t);
}
diff --git a/libc/src/__support/macros/attributes.h b/libc/src/__support/macros/attributes.h
index c6474673de85a..72fb3bd6e204b 100644
--- a/libc/src/__support/macros/attributes.h
+++ b/libc/src/__support/macros/attributes.h
@@ -48,4 +48,28 @@
#define LIBC_PREFERED_TYPE(TYPE)
#endif
+#if __has_attribute(lifetimebound)
+#define LIBC_LIFETIMEBOUND [[clang::lifetimebound]]
+#else
+#define LIBC_LIFETIMEBOUND
+#endif
+
+#if __has_attribute(lifetime_capture_by)
+#define LIBC_LIFETIME_CAPTURE_BY(X) [[clang::lifetime_capture_by(X)]]
+#else
+#define LIBC_LIFETIME_CAPTURE_BY(X)
+#endif
+
+#if defined(__clang__)
+#define LIBC_GSL_POINTER [[gsl::Pointer]]
+#else
+#define LIBC_GSL_POINTER
+#endif
+
+#if defined(__clang__)
+#define LIBC_GSL_OWNER [[gsl::Owner]]
+#else
+#define LIBC_GSL_OWNER
+#endif
+
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H
>From 6d87229960145b3a7b8004be8f9503026a17a7cc Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 26 Jun 2025 13:27:03 -0400
Subject: [PATCH 2/3] more
---
libc/src/__support/CPP/string_view.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libc/src/__support/CPP/string_view.h b/libc/src/__support/CPP/string_view.h
index b9182cdaa1856..bcdfe0eec4758 100644
--- a/libc/src/__support/CPP/string_view.h
+++ b/libc/src/__support/CPP/string_view.h
@@ -18,7 +18,6 @@
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
-class string;
// This is very simple alternate of the std::string_view class. There is no
// bounds check performed in any of the methods. The callers are expected to
// do the checks before invoking the methods.
>From 1cc9cf1358630afddfe359c176873f856a5febae Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Sat, 28 Jun 2025 23:54:05 -0400
Subject: [PATCH 3/3] Update libc/src/__support/CPP/string.h
Co-authored-by: Copilot <175728472+Copilot at users.noreply.github.com>
---
libc/src/__support/CPP/string.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/CPP/string.h b/libc/src/__support/CPP/string.h
index 27748eeb953e3..ad33fc8e536cd 100644
--- a/libc/src/__support/CPP/string.h
+++ b/libc/src/__support/CPP/string.h
@@ -109,7 +109,7 @@ class string {
LIBC_INLINE constexpr const char &front() const LIBC_LIFETIMEBOUND {
return data()[0];
}
- LIBC_INLINE char &front() { return data()[0]; }
+ LIBC_INLINE char &front() LIBC_LIFETIMEBOUND { return data()[0]; }
LIBC_INLINE constexpr const char &back() const LIBC_LIFETIMEBOUND {
return data()[size_ - 1];
More information about the libc-commits
mailing list