149 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++2310// UNSUPPORTED: gcc-15, apple-clang-1711 12// <type_traits>13 14// template <class T>15// consteval bool is_within_lifetime(const T*) noexcept; // C++2616 17#include <cassert>18#include <type_traits>19#include <utility>20 21#include "test_macros.h"22 23ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<int*>())), bool);24ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<const int*>())), bool);25ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<void*>())), bool);26ASSERT_SAME_TYPE(decltype(std::is_within_lifetime(std::declval<const void*>())), bool);27 28ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<int*>()));29ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<const int*>()));30ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<void*>()));31ASSERT_NOEXCEPT(std::is_within_lifetime(std::declval<const void*>()));32 33template <class T>34concept is_within_lifetime_exists = requires(T t) { std::is_within_lifetime(t); };35 36struct S {};37 38static_assert(is_within_lifetime_exists<int*>);39static_assert(is_within_lifetime_exists<const int*>);40static_assert(is_within_lifetime_exists<void*>);41static_assert(is_within_lifetime_exists<const void*>);42static_assert(!is_within_lifetime_exists<int>); // Not a pointer43static_assert(!is_within_lifetime_exists<decltype(nullptr)>); // Not a pointer44static_assert(!is_within_lifetime_exists<void() const>); // Not a pointer45static_assert(!is_within_lifetime_exists<int S::*>); // Doesn't accept pointer-to-data-member46static_assert(!is_within_lifetime_exists<void (S::*)()>); // Doesn't accept pointer-to-member-function47static_assert(!is_within_lifetime_exists<void (*)()>); // Doesn't match `const T*`48 49consteval bool f() {50 // Test that it works with global variables whose lifetime is in a51 // different constant expression52 {53 static constexpr int i = 0;54 static_assert(std::is_within_lifetime(&i));55 // (Even when cast to a different type)56 static_assert(std::is_within_lifetime(const_cast<int*>(&i)));57 static_assert(std::is_within_lifetime(static_cast<const void*>(&i)));58 static_assert(std::is_within_lifetime(static_cast<void*>(const_cast<int*>(&i))));59 static_assert(std::is_within_lifetime<const int>(&i));60 static_assert(std::is_within_lifetime<int>(const_cast<int*>(&i)));61 static_assert(std::is_within_lifetime<const void>(static_cast<const void*>(&i)));62 static_assert(std::is_within_lifetime<void>(static_cast<void*>(const_cast<int*>(&i))));63 }64 65 {66 static constexpr union {67 int member1;68 int member2;69 } u{.member2 = 1};70 static_assert(!std::is_within_lifetime(&u.member1) && std::is_within_lifetime(&u.member2));71 }72 73 // Test that it works for varibles inside the same constant expression74 {75 int i = 0;76 assert(std::is_within_lifetime(&i));77 // (Even when cast to a different type)78 assert(std::is_within_lifetime(const_cast<int*>(&i)));79 assert(std::is_within_lifetime(static_cast<const void*>(&i)));80 assert(std::is_within_lifetime(static_cast<void*>(const_cast<int*>(&i))));81 assert(std::is_within_lifetime<const int>(&i));82 assert(std::is_within_lifetime<int>(const_cast<int*>(&i)));83 assert(std::is_within_lifetime<const void>(static_cast<const void*>(&i)));84 assert(std::is_within_lifetime<void>(static_cast<void*>(const_cast<int*>(&i))));85 }86 // Anonymous union87 {88 union {89 int member1;90 int member2;91 };92 assert(!std::is_within_lifetime(&member1) && !std::is_within_lifetime(&member2));93 member1 = 1;94 assert(std::is_within_lifetime(&member1) && !std::is_within_lifetime(&member2));95 member2 = 1;96 assert(!std::is_within_lifetime(&member1) && std::is_within_lifetime(&member2));97 }98 // Variant members99 {100 struct X {101 union {102 int member1;103 int member2;104 };105 } x;106 assert(!std::is_within_lifetime(&x.member1) && !std::is_within_lifetime(&x.member2));107 x.member1 = 1;108 assert(std::is_within_lifetime(&x.member1) && !std::is_within_lifetime(&x.member2));109 x.member2 = 1;110 assert(!std::is_within_lifetime(&x.member1) && std::is_within_lifetime(&x.member2));111 }112 // Unions113 {114 union X {115 int member1;116 int member2;117 } x;118 assert(!std::is_within_lifetime(&x.member1) && !std::is_within_lifetime(&x.member2));119 x.member1 = 1;120 assert(std::is_within_lifetime(&x.member1) && !std::is_within_lifetime(&x.member2));121 x.member2 = 1;122 assert(!std::is_within_lifetime(&x.member1) && std::is_within_lifetime(&x.member2));123 }124 {125 S s; // uninitialised126 assert(std::is_within_lifetime(&s));127 }128 129 return true;130}131static_assert(f());132 133// Check that it is a consteval (and consteval-propagating) function134// (i.e., taking the address of below will fail because it will be an immediate function)135template <typename T>136constexpr void does_escalate(T p) {137 std::is_within_lifetime(p);138}139template <typename T, void (*)(T) = &does_escalate<T>>140constexpr bool check_escalated(int) {141 return false;142}143template <typename T>144constexpr bool check_escalated(long) {145 return true;146}147static_assert(check_escalated<int*>(0), "");148static_assert(check_escalated<void*>(0), "");149