-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[libc] add basic lifetime annotations for support data structures #145933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[libc] add basic lifetime annotations for support data structures #145933
Conversation
@llvm/pr-subscribers-libc Author: Schrodinger ZHU Yifan (SchrodingerZhu) Changesfix #145932 Full diff: https://github.com/llvm/llvm-project/pull/145933.diff 12 Files Affected:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds basic lifetime annotations to support data structures to improve static lifetime checking
- Defines LIBC_LIFETIMEBOUND, LIBC_LIFETIME_CAPTURE_BY, LIBC_GSL_POINTER, and LIBC_GSL_OWNER macros
- Annotates utility functions, classes, and methods (move, forward, span, optional, string, array, algorithm, mutex, atomic) with lifetime attributes
- Adds
[[nodiscard]]
toStringStream::str()
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
libc/src/__support/macros/attributes.h | Introduce lifetime and GSL attribute macros |
libc/src/__support/CPP/utility/move.h | Annotate move() parameter with LIBC_LIFETIMEBOUND |
libc/src/__support/CPP/utility/forward.h | Annotate forward() parameters with LIBC_LIFETIMEBOUND |
libc/src/__support/CPP/stringstream.h | Add [[nodiscard]] to str() |
libc/src/__support/CPP/string_view.h | Annotate class and add lifetime-bound literal constructor |
libc/src/__support/CPP/string.h | Add LIBC_LIFETIMEBOUND to const overloads of front , back , and operator[] |
libc/src/__support/CPP/span.h | Annotate span class and constructors with lifetime attributes |
libc/src/__support/CPP/optional.h | Annotate value() and operator* overloads with LIBC_LIFETIMEBOUND |
libc/src/__support/CPP/mutex.h | Annotate lock_guard constructors with LIBC_LIFETIMEBOUND |
libc/src/__support/CPP/atomic.h | Annotate AtomicRef with LIBC_GSL_POINTER |
libc/src/__support/CPP/array.h | Annotate array front , back , and operator[] with LIBC_LIFETIMEBOUND |
libc/src/__support/CPP/algorithm.h | Annotate min /max parameters with LIBC_LIFETIMEBOUND |
Comments suppressed due to low confidence (1)
libc/src/__support/CPP/string_view.h:82
- The literal-pair constructor sets
Len(N)
, which includes the null terminator in the view. It should useLen(N - 1)
to exclude the trailing '\0'.
: Data(Str), Len(N) {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these attributes available for all the versions of clang we support? If not we may also need a version check
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
fix #145932