[llvm] [ADT] Add `[[clang::lifetimebound]]` annotations to Twine.h (PR #210474)
Benedek Kaibas via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 18 02:11:01 PDT 2026
https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/210474
>From 21f4b40f01b55fac0219f5d6ed2ef9a891da817c Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sat, 18 Jul 2026 03:39:13 +0200
Subject: [PATCH 1/3] Add Twine.h annotation.
---
llvm/include/llvm/ADT/Twine.h | 49 ++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h
index e3b4d5e26fa17..a994804c6de68 100644
--- a/llvm/include/llvm/ADT/Twine.h
+++ b/llvm/include/llvm/ADT/Twine.h
@@ -174,7 +174,8 @@ class Twine {
}
/// Construct a binary twine.
- explicit Twine(const Twine &LHS, const Twine &RHS)
+ explicit Twine(const Twine &LHS LLVM_LIFETIME_BOUND,
+ const Twine &RHS LLVM_LIFETIME_BOUND)
: LHSKind(TwineKind), RHSKind(TwineKind) {
this->LHS.twine = &LHS;
this->RHS.twine = &RHS;
@@ -182,7 +183,8 @@ class Twine {
}
/// Construct a twine from explicit values.
- explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind)
+ explicit Twine(Child LHS LLVM_LIFETIME_BOUND, NodeKind LHSKind,
+ Child RHS LLVM_LIFETIME_BOUND, NodeKind RHSKind)
: LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) {
assert(isValid() && "Invalid twine!");
}
@@ -254,7 +256,7 @@ class Twine {
/// We take care here to optimize "" into the empty twine -- this will be
/// optimized out for string constants. This allows Twine arguments have
/// default "" values, without introducing unnecessary string constants.
- /*implicit*/ Twine(const char *Str) {
+ /*implicit*/ Twine(const char *Str LLVM_LIFETIME_BOUND) {
if (Str[0] != '\0') {
LHS.cString = Str;
LHSKind = CStringKind;
@@ -269,7 +271,8 @@ class Twine {
/*implicit*/ Twine(std::nullptr_t) = delete;
/// Construct from an std::string.
- /*implicit*/ Twine(const std::string &Str) : LHSKind(StdStringKind) {
+ /*implicit*/ Twine(const std::string &Str LLVM_LIFETIME_BOUND)
+ : LHSKind(StdStringKind) {
LHS.stdString = &Str;
assert(isValid() && "Invalid twine!");
}
@@ -278,14 +281,16 @@ class Twine {
/// length. This handles string_views on a pure API basis, and avoids
/// storing one (or a pointer to one) inside a Twine, which avoids problems
/// when mixing code compiled under various C++ standards.
- /*implicit*/ Twine(const std::string_view &Str) : LHSKind(PtrAndLengthKind) {
+ /*implicit*/ Twine(const std::string_view &Str LLVM_LIFETIME_BOUND)
+ : LHSKind(PtrAndLengthKind) {
LHS.ptrAndLength.ptr = Str.data();
LHS.ptrAndLength.length = Str.length();
assert(isValid() && "Invalid twine!");
}
/// Construct from a StringRef.
- /*implicit*/ Twine(StringRef Str) : LHSKind(PtrAndLengthKind) {
+ /*implicit*/ Twine(StringRef Str LLVM_LIFETIME_BOUND)
+ : LHSKind(PtrAndLengthKind) {
LHS.ptrAndLength.ptr = Str.data();
LHS.ptrAndLength.length = Str.size();
assert(isValid() && "Invalid twine!");
@@ -299,7 +304,7 @@ class Twine {
}
/// Construct from a SmallString.
- /*implicit*/ Twine(const SmallVectorImpl<char> &Str)
+ /*implicit*/ Twine(const SmallVectorImpl<char> &Str LLVM_LIFETIME_BOUND)
: LHSKind(PtrAndLengthKind) {
LHS.ptrAndLength.ptr = Str.data();
LHS.ptrAndLength.length = Str.size();
@@ -307,7 +312,7 @@ class Twine {
}
/// Construct from a formatv_object_base.
- /*implicit*/ Twine(const formatv_object_base &Fmt)
+ /*implicit*/ Twine(const formatv_object_base &Fmt LLVM_LIFETIME_BOUND)
: LHSKind(FormatvObjectKind) {
LHS.formatvObject = &Fmt;
assert(isValid() && "Invalid twine!");
@@ -352,7 +357,8 @@ class Twine {
// right thing. Yet.
/// Construct as the concatenation of a C string and a StringRef.
- /*implicit*/ Twine(const char *LHS, StringRef RHS)
+ /*implicit*/ Twine(const char *LHS LLVM_LIFETIME_BOUND,
+ StringRef RHS LLVM_LIFETIME_BOUND)
: LHSKind(CStringKind), RHSKind(PtrAndLengthKind) {
this->LHS.cString = LHS;
this->RHS.ptrAndLength.ptr = RHS.data();
@@ -361,7 +367,8 @@ class Twine {
}
/// Construct as the concatenation of a StringRef and a C string.
- /*implicit*/ Twine(StringRef LHS, const char *RHS)
+ /*implicit*/ Twine(StringRef LHS LLVM_LIFETIME_BOUND,
+ const char *RHS LLVM_LIFETIME_BOUND)
: LHSKind(PtrAndLengthKind), RHSKind(CStringKind) {
this->LHS.ptrAndLength.ptr = LHS.data();
this->LHS.ptrAndLength.length = LHS.size();
@@ -424,7 +431,8 @@ class Twine {
/// @name String Operations
/// @{
- Twine concat(const Twine &Suffix) const;
+ Twine
+ concat(const Twine &Suffix LLVM_LIFETIME_BOUND) const LLVM_LIFETIME_BOUND;
/// @}
/// @name Output & Conversion.
@@ -458,7 +466,8 @@ class Twine {
/// This returns the twine as a single StringRef if it can be
/// represented as such. Otherwise the twine is written into the given
/// SmallVector and a StringRef to the SmallVector's data is returned.
- StringRef toStringRef(SmallVectorImpl<char> &Out) const {
+ StringRef toStringRef(SmallVectorImpl<char> &Out LLVM_LIFETIME_BOUND) const
+ LLVM_LIFETIME_BOUND {
if (isSingleStringRef())
return getSingleStringRef();
toVector(Out);
@@ -470,8 +479,8 @@ class Twine {
/// given SmallVector and a StringRef to the SmallVector's data is returned.
///
/// The returned StringRef's size does not include the null terminator.
- LLVM_ABI StringRef
- toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const;
+ LLVM_ABI StringRef toNullTerminatedStringRef(
+ SmallVectorImpl<char> &Out LLVM_LIFETIME_BOUND) const;
/// Write the concatenated string represented by this twine to the
/// stream \p OS.
@@ -523,25 +532,29 @@ inline Twine Twine::concat(const Twine &Suffix) const {
return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind);
}
-inline Twine operator+(const Twine &LHS, const Twine &RHS) {
+inline Twine operator+(const Twine &LHS LLVM_LIFETIME_BOUND,
+ const Twine &RHS LLVM_LIFETIME_BOUND) {
return LHS.concat(RHS);
}
/// Additional overload to guarantee simplified codegen; this is equivalent to
/// concat().
-inline Twine operator+(const char *LHS, StringRef RHS) {
+inline Twine operator+(const char *LHS LLVM_LIFETIME_BOUND,
+ StringRef RHS LLVM_LIFETIME_BOUND) {
return Twine(LHS, RHS);
}
/// Additional overload to guarantee simplified codegen; this is equivalent to
/// concat().
-inline Twine operator+(StringRef LHS, const char *RHS) {
+inline Twine operator+(StringRef LHS LLVM_LIFETIME_BOUND,
+ const char *RHS LLVM_LIFETIME_BOUND) {
return Twine(LHS, RHS);
}
-inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) {
+inline raw_ostream &operator<<(raw_ostream &OS LLVM_LIFETIME_BOUND,
+ const Twine &RHS) {
RHS.print(OS);
return OS;
}
>From ea5a904db2f7a81cb80536f1f11e30c5b23ce5a3 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sat, 18 Jul 2026 10:35:55 +0200
Subject: [PATCH 2/3] Remove annotation from fns where the parameter outlives
the twine.
---
llvm/include/llvm/ADT/Twine.h | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h
index a994804c6de68..6c4fe42b3b52e 100644
--- a/llvm/include/llvm/ADT/Twine.h
+++ b/llvm/include/llvm/ADT/Twine.h
@@ -466,8 +466,7 @@ class Twine {
/// This returns the twine as a single StringRef if it can be
/// represented as such. Otherwise the twine is written into the given
/// SmallVector and a StringRef to the SmallVector's data is returned.
- StringRef toStringRef(SmallVectorImpl<char> &Out LLVM_LIFETIME_BOUND) const
- LLVM_LIFETIME_BOUND {
+ StringRef toStringRef(SmallVectorImpl<char> &Out) const {
if (isSingleStringRef())
return getSingleStringRef();
toVector(Out);
@@ -479,8 +478,8 @@ class Twine {
/// given SmallVector and a StringRef to the SmallVector's data is returned.
///
/// The returned StringRef's size does not include the null terminator.
- LLVM_ABI StringRef toNullTerminatedStringRef(
- SmallVectorImpl<char> &Out LLVM_LIFETIME_BOUND) const;
+ LLVM_ABI StringRef
+ toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const;
/// Write the concatenated string represented by this twine to the
/// stream \p OS.
@@ -553,8 +552,7 @@ inline Twine operator+(StringRef LHS LLVM_LIFETIME_BOUND,
return Twine(LHS, RHS);
}
-inline raw_ostream &operator<<(raw_ostream &OS LLVM_LIFETIME_BOUND,
- const Twine &RHS) {
+inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) {
RHS.print(OS);
return OS;
}
>From a745b38241a20d3143827c1837458c56d27c3459 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sat, 18 Jul 2026 11:10:24 +0200
Subject: [PATCH 3/3] Add annotations to this.
---
llvm/include/llvm/ADT/Twine.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/ADT/Twine.h b/llvm/include/llvm/ADT/Twine.h
index 6c4fe42b3b52e..e0a80ece61cca 100644
--- a/llvm/include/llvm/ADT/Twine.h
+++ b/llvm/include/llvm/ADT/Twine.h
@@ -466,7 +466,7 @@ class Twine {
/// This returns the twine as a single StringRef if it can be
/// represented as such. Otherwise the twine is written into the given
/// SmallVector and a StringRef to the SmallVector's data is returned.
- StringRef toStringRef(SmallVectorImpl<char> &Out) const {
+ StringRef toStringRef(SmallVectorImpl<char> &Out) const LLVM_LIFETIME_BOUND {
if (isSingleStringRef())
return getSingleStringRef();
toVector(Out);
@@ -478,8 +478,8 @@ class Twine {
/// given SmallVector and a StringRef to the SmallVector's data is returned.
///
/// The returned StringRef's size does not include the null terminator.
- LLVM_ABI StringRef
- toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const;
+ LLVM_ABI StringRef toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const
+ LLVM_LIFETIME_BOUND;
/// Write the concatenated string represented by this twine to the
/// stream \p OS.
More information about the llvm-commits
mailing list