Add internal traits for lifetimebound detection

This will helps compilers that understand `ABSL_ATTRIBUTE_LIFETIME_BOUND` flag constructs such as
`absl::StatusOr<std::string_view> str = std::string(...)`
as error-prone.

For standard types, this is done via specializing the type traits.
For all other types, this is done by detecting the presence of a Boolean member trait such as:
`using absl_internal_is_view = std::true_type;`
in the type.

This is purely intended as a safety feature, and the values of these traits (even if wrong!) must NOT be depended on for correct behavior.
Furthermore, only high-value types (such as `absl::StatusOr`) are the intended users here.
Do not declare or use these traits on arbitrary types that are unlikely to be misused.

Do not depend on any of these to be stable, as they not (yet) public APIs.
Moreover, the trait declarations and mechanisms are all subject to change.
(For example, if `[[clang::lifetimebound]]` becomes possible to detect directly, the traits may need to be altered to utilize that, and distinguish between assignments and constructions.)

Should these or similar APIs be made public at a later point, the detection mechanisms may be altered quickly, and may (either loudly or silently) break existing code depending on these internal APIs without notice.

PiperOrigin-RevId: 620868493
Change-Id: I4a528a1dcf0df6ffbc3641d09537bc4c674aee4e
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index a15059d..ded5582 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -37,11 +37,21 @@
 
 #include <cstddef>
 #include <functional>
+#include <string>
 #include <type_traits>
+#include <vector>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 
+#ifdef __cpp_lib_span
+#include <span>  // NOLINT(build/c++20)
+#endif
+
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+#include <string_view>
+#endif
+
 // Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17
 // feature.
 #if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
@@ -553,6 +563,97 @@
 #endif
 }
 #endif  // ABSL_HAVE_CONSTANT_EVALUATED
+
+namespace type_traits_internal {
+
+// Detects if a class's definition has declared itself to be an owner by
+// declaring
+//   using absl_internal_is_view = std::true_type;
+// as a member.
+// Types that don't want either must either omit this declaration entirely, or
+// (if e.g. inheriting from a base class) define the member to something that
+// isn't a Boolean trait class, such as `void`.
+// Do not specialize or use this directly. It's an implementation detail.
+template <typename T, typename = void>
+struct IsOwnerImpl : std::false_type {
+  static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value,
+                "type must lack qualifiers");
+};
+
+template <typename T>
+struct IsOwnerImpl<
+    T,
+    std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>>
+    : absl::negation<typename T::absl_internal_is_view> {};
+
+// A trait to determine whether a type is an owner.
+// Do *not* depend on the correctness of this trait for correct code behavior.
+// It is only a safety feature and its value may change in the future.
+// Do not specialize this; instead, define the member trait inside your type so
+// that it can be auto-detected, and to prevent ODR violations.
+// If it ever becomes possible to detect [[gsl::Owner]], we should leverage it:
+// https://wg21.link/p1179
+template <typename T>
+struct IsOwner : IsOwnerImpl<T> {};
+
+template <typename T, typename Traits, typename Alloc>
+struct IsOwner<std::basic_string<T, Traits, Alloc>> : std::true_type {};
+
+template <typename T, typename Alloc>
+struct IsOwner<std::vector<T, Alloc>> : std::true_type {};
+
+// Detects if a class's definition has declared itself to be a view by declaring
+//   using absl_internal_is_view = std::true_type;
+// as a member.
+// Do not specialize or use this directly.
+template <typename T, typename = void>
+struct IsViewImpl : std::false_type {
+  static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value,
+                "type must lack qualifiers");
+};
+
+template <typename T>
+struct IsViewImpl<
+    T,
+    std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>>
+    : T::absl_internal_is_view {};
+
+// A trait to determine whether a type is a view.
+// Do *not* depend on the correctness of this trait for correct code behavior.
+// It is only a safety feature, and its value may change in the future.
+// Do not specialize this trait. Instead, define the member
+//   using absl_internal_is_view = std::true_type;
+// in your class to allow its detection while preventing ODR violations.
+// If it ever becomes possible to detect [[gsl::Pointer]], we should leverage
+// it: https://wg21.link/p1179
+template <typename T>
+struct IsView : std::integral_constant<bool, std::is_pointer<T>::value ||
+                                                 IsViewImpl<T>::value> {};
+
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+template <typename Char, typename Traits>
+struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {};
+#endif
+
+#ifdef __cpp_lib_span
+template <typename T>
+struct IsView<std::span<T>> : std::true_type {};
+#endif
+
+// Determines whether the assignment of the given types is lifetime-bound.
+// Do *not* depend on the correctness of this trait for correct code behavior.
+// It is only a safety feature and its value may change in the future.
+// If it ever becomes possible to detect [[clang::lifetimebound]] directly,
+// we should change the implementation to leverage that.
+// Until then, we consider an assignment from an "owner" (such as std::string)
+// to a "view" (such as std::string_view) to be a lifetime-bound assignment.
+template <typename T, typename U>
+using IsLifetimeBoundAssignment =
+    std::integral_constant<bool, IsView<absl::remove_cvref_t<T>>::value &&
+                                     IsOwner<absl::remove_cvref_t<U>>::value>;
+
+}  // namespace type_traits_internal
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index 6080bee..1e056bb 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -26,10 +26,32 @@
 #include "absl/time/clock.h"
 #include "absl/time/time.h"
 
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+#include <string_view>
+#endif
+
 namespace {
 
 using ::testing::StaticAssertTypeEq;
 
+template <typename T>
+using IsOwnerAndNotView =
+    absl::conjunction<absl::type_traits_internal::IsOwner<T>,
+                      absl::negation<absl::type_traits_internal::IsView<T>>>;
+
+static_assert(IsOwnerAndNotView<std::vector<int>>::value,
+              "vector is an owner, not a view");
+static_assert(IsOwnerAndNotView<std::string>::value,
+              "string is an owner, not a view");
+static_assert(IsOwnerAndNotView<std::wstring>::value,
+              "wstring is an owner, not a view");
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+static_assert(!IsOwnerAndNotView<std::string_view>::value,
+              "string_view is a view, not an owner");
+static_assert(!IsOwnerAndNotView<std::wstring_view>::value,
+              "wstring_view is a view, not an owner");
+#endif
+
 template <class T, class U>
 struct simple_pair {
   T first;