From 34c5dc0583ddd49aa985e4100f6d395b7974afd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Thu, 3 Sep 2026 00:20:59 -0700 Subject: [PATCH 1/2] util: annotate string view input lifetimes The string-view helpers return views into their input, while `LineReader` stores one. Annotate their inputs so Clang can warn when a returned or stored view outlives a temporary string. --- src/util/string.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/string.h b/src/util/string.h index 265bf987e50..fd0255d1625 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -160,7 +160,7 @@ std::vector Split(const std::span& sp, char sep, bool include_sep return Split(str, separators); } -[[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v") +[[nodiscard]] inline std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern = " \f\n\r\t\v") { std::string::size_type front = str.find_first_not_of(pattern); if (front == std::string::npos) { @@ -175,7 +175,7 @@ std::vector Split(const std::span& sp, char sep, bool include_sep return std::string(TrimStringView(str, pattern)); } -[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix) +[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix) { if (str.ends_with(suffix)) { return str.substr(0, str.size() - suffix.size()); @@ -183,7 +183,7 @@ std::vector Split(const std::span& sp, char sep, bool include_sep return str; } -[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix) +[[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str LIFETIMEBOUND, std::string_view prefix) { if (str.starts_with(prefix)) { return str.substr(prefix.size()); @@ -273,7 +273,7 @@ class LineReader std::string_view::iterator m_it; public: - explicit LineReader(std::string_view str, size_t max_line_length); + explicit LineReader(std::string_view str LIFETIMEBOUND, size_t max_line_length); /** * Returns a string from current iterator position up to (but not including) next \n From b57b0dbebd56dac69d702e508af188e059db9c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Thu, 3 Sep 2026 16:02:36 -0700 Subject: [PATCH 2/2] util: annotate `Split` input lifetime `Split` can return views into its input, but annotating its old reference warns for lvalue strings. Take the span by value so Clang follows the backing storage. `Split` copies results but can still warn, while `SplitString` is unaffected. --- src/util/string.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/string.h b/src/util/string.h index fd0255d1625..b2be2e7f644 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -117,7 +117,7 @@ void ReplaceAll(std::string& in_out, std::string_view search, std::string_view s * - 3) */ template > -std::vector Split(const std::span& sp, std::string_view separators, bool include_sep = false) +std::vector Split(std::span sp LIFETIMEBOUND, std::string_view separators, bool include_sep = false) { std::vector ret; auto it = sp.begin(); @@ -145,7 +145,7 @@ std::vector Split(const std::span& sp, std::string_view separator * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. */ template > -std::vector Split(const std::span& sp, char sep, bool include_sep = false) +std::vector Split(std::span sp LIFETIMEBOUND, char sep, bool include_sep = false) { return Split(sp, std::string_view{&sep, 1}, include_sep); }