[libcxx-commits] [libcxx] [libc++] P2641R4: Checking if a `union` alternative is active (`std::is_within_lifetime`) (PR #107450)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Sep 10 06:49:18 PDT 2024


================
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+// <type_traits>
+
+// template <class T>
+//   consteval bool is_within_lifetime(const T*) noexcept; // C++26
+
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+#ifndef __cpp_lib_is_within_lifetime
+
+// Check that it doesn't exist if the feature test macro isn't defined (via ADL)
+template <class T>
+constexpr decltype(static_cast<void>(is_within_lifetime(std::declval<T>())), bool{}) is_within_lifetime_exists(int) {
+  return true;
+}
+template <class T>
+constexpr bool is_within_lifetime_exists(long) {
+  return false;
+}
+
+static_assert(!is_within_lifetime_exists<const std::integral_constant<bool, false>*>(0), "");
+
+#elif TEST_STD_VER < 26
+#  error __cpp_lib_is_within_lifetime defined before C++26
+#else // defined(__cpp_lib_is_within_lifetime) && TEST_STD_VER >= 26
+
+ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<int*>())), bool);
+ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<const int*>())), bool);
+ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<void*>())), bool);
+ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<const void*>())), bool);
+
+ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<int*>()));
+ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<const int*>()));
+ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<void*>()));
+ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<const void*>()));
+
+template <class T>
+concept is_within_lifetime_exists = requires(T t) { std::is_within_lifetime(t); };
+
+struct S {};
+
+static_assert(is_within_lifetime_exists<int*>);
+static_assert(is_within_lifetime_exists<const int*>);
+static_assert(is_within_lifetime_exists<void*>);
+static_assert(is_within_lifetime_exists<const void*>);
+static_assert(!is_within_lifetime_exists<int>);               // Not a pointer
+static_assert(!is_within_lifetime_exists<decltype(nullptr)>); // Not a pointer
+static_assert(!is_within_lifetime_exists<void() const>);      // Not a pointer
+static_assert(!is_within_lifetime_exists<int S::*>);          // Doesn't accept pointer-to-member
+static_assert(!is_within_lifetime_exists<void (S::*)()>);
+static_assert(!is_within_lifetime_exists<void (*)()>); // Doesn't match `const T*`
+
+constexpr int i = 0;
----------------
ldionne wrote:

I would write these tests like this instead, for readability:

```
consteval bool test() {
    // short comment explaining what you're testing
    {
        constexpr int i = 0;
        assert(std::is_within_lifetime(&i));
        assert(std::is_within_lifetime(const_cast<int*>(&i)));
        assert(std::is_within_lifetime(static_cast<const void*>(&i)));
        assert(std::is_within_lifetime(static_cast<void*>(const_cast<int*>(&i))));
        assert(std::is_within_lifetime<const int>(&i));
        assert(std::is_within_lifetime<int>(const_cast<int*>(&i)));
        assert(std::is_within_lifetime<const void>(static_cast<const void*>(&i)));
        assert(std::is_within_lifetime<void>(static_cast<void*>(const_cast<int*>(&i))));
    }

    // short comment explaining what you're testing
    {
        constexpr union {
            int active;
            int inactive;
        } u{.active = 1};
        assert(std::is_within_lifetime(&u.active));
        assert(!std::is_within_lifetime(&u.inactive));
    }

    // short comment explaining what you're testing
    {
        union {
            int active;
            int inactive;
        };
        assert(!std::is_within_lifetime(&active));
        assert(!std::is_within_lifetime(&inactive));
        active = 1;
        assert(std::is_within_lifetime(&active));
        assert(!std::is_within_lifetime(&inactive));
        inactive = 1;
        assert(!std::is_within_lifetime(&active));
        assert(std::is_within_lifetime(&inactive));
    }

    // short comment explaining what you're testing
    {
        int j;
        S s;
        assert(std::is_within_lifetime(&j));
        assert(std::is_within_lifetime(&s));
    }

    return true;
}

static_assert(test());
```

https://github.com/llvm/llvm-project/pull/107450


More information about the libcxx-commits mailing list