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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // <memory> |
10 | |
11 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
12 | |
13 | // template <class T> constexpr T* to_address(T* p) noexcept; |
14 | // template <class Ptr> constexpr auto to_address(const Ptr& p) noexcept; |
15 | |
16 | #include <memory> |
17 | #include <cassert> |
18 | #include <utility> |
19 | |
20 | #include "test_macros.h" |
21 | |
22 | struct Irrelevant; |
23 | |
24 | struct P1 { |
25 | using element_type = Irrelevant; |
26 | constexpr explicit P1(int *p) : p_(p) { } |
27 | constexpr int *operator->() const { return p_; } |
28 | int *p_; |
29 | }; |
30 | |
31 | struct P2 { |
32 | using element_type = Irrelevant; |
33 | constexpr explicit P2(int *p) : p_(p) { } |
34 | constexpr P1 operator->() const { return p_; } |
35 | P1 p_; |
36 | }; |
37 | |
38 | struct P3 { |
39 | constexpr explicit P3(int *p) : p_(p) { } |
40 | int *p_; |
41 | }; |
42 | |
43 | template<> |
44 | struct std::pointer_traits<P3> { |
45 | static constexpr int *to_address(const P3& p) { return p.p_; } |
46 | }; |
47 | |
48 | struct P4 { |
49 | constexpr explicit P4(int *p) : p_(p) { } |
50 | int *operator->() const; // should never be called |
51 | int *p_; |
52 | }; |
53 | |
54 | template<> |
55 | struct std::pointer_traits<P4> { |
56 | static constexpr int *to_address(const P4& p) { return p.p_; } |
57 | }; |
58 | |
59 | struct P5 { |
60 | using element_type = Irrelevant; |
61 | int const* const& operator->() const; |
62 | }; |
63 | |
64 | struct P6 {}; |
65 | |
66 | template<> |
67 | struct std::pointer_traits<P6> { |
68 | static int const* const& to_address(const P6&); |
69 | }; |
70 | |
71 | // Taken from a build breakage caused in Clang |
72 | namespace P7 { |
73 | template<typename T> struct CanProxy; |
74 | template<typename T> |
75 | struct CanQual { |
76 | CanProxy<T> operator->() const { return CanProxy<T>(); } |
77 | }; |
78 | template<typename T> |
79 | struct CanProxy { |
80 | const CanProxy<T> *operator->() const { return nullptr; } |
81 | }; |
82 | } // namespace P7 |
83 | |
84 | namespace P8 { |
85 | template<class T> |
86 | struct FancyPtrA { |
87 | using element_type = Irrelevant; |
88 | T *p_; |
89 | TEST_CONSTEXPR FancyPtrA(T *p) : p_(p) {} |
90 | T& operator*() const; |
91 | TEST_CONSTEXPR T *operator->() const { return p_; } |
92 | }; |
93 | template<class T> |
94 | struct FancyPtrB { |
95 | T *p_; |
96 | TEST_CONSTEXPR FancyPtrB(T *p) : p_(p) {} |
97 | T& operator*() const; |
98 | }; |
99 | } // namespace P8 |
100 | |
101 | template<class T> |
102 | struct std::pointer_traits<P8::FancyPtrB<T> > { |
103 | static TEST_CONSTEXPR T *to_address(const P8::FancyPtrB<T>& p) { return p.p_; } |
104 | }; |
105 | |
106 | struct Incomplete; |
107 | template<class T> struct Holder { T t; }; |
108 | |
109 | |
110 | constexpr bool test() { |
111 | int i = 0; |
112 | ASSERT_NOEXCEPT(std::to_address(&i)); |
113 | assert(std::to_address(&i) == &i); |
114 | P1 p1(&i); |
115 | ASSERT_NOEXCEPT(std::to_address(p1)); |
116 | assert(std::to_address(p1) == &i); |
117 | P2 p2(&i); |
118 | ASSERT_NOEXCEPT(std::to_address(p2)); |
119 | assert(std::to_address(p2) == &i); |
120 | P3 p3(&i); |
121 | ASSERT_NOEXCEPT(std::to_address(p3)); |
122 | assert(std::to_address(p3) == &i); |
123 | P4 p4(&i); |
124 | ASSERT_NOEXCEPT(std::to_address(p4)); |
125 | assert(std::to_address(p4) == &i); |
126 | |
127 | ASSERT_SAME_TYPE(decltype(std::to_address(std::declval<int const*>())), int const*); |
128 | ASSERT_SAME_TYPE(decltype(std::to_address(std::declval<P5>())), int const*); |
129 | ASSERT_SAME_TYPE(decltype(std::to_address(std::declval<P6>())), int const*); |
130 | |
131 | P7::CanQual<int>* p7 = nullptr; |
132 | assert(std::to_address(p7) == nullptr); |
133 | ASSERT_SAME_TYPE(decltype(std::to_address(p7)), P7::CanQual<int>*); |
134 | |
135 | Holder<Incomplete> *p8_nil = nullptr; // for C++03 compatibility |
136 | P8::FancyPtrA<Holder<Incomplete> > p8a = p8_nil; |
137 | assert(std::to_address(p8a) == p8_nil); |
138 | ASSERT_SAME_TYPE(decltype(std::to_address(p8a)), decltype(p8_nil)); |
139 | |
140 | P8::FancyPtrB<Holder<Incomplete> > p8b = p8_nil; |
141 | assert(std::to_address(p8b) == p8_nil); |
142 | ASSERT_SAME_TYPE(decltype(std::to_address(p8b)), decltype(p8_nil)); |
143 | |
144 | int p9[2] = {}; |
145 | assert(std::to_address(p9) == p9); |
146 | ASSERT_SAME_TYPE(decltype(std::to_address(p9)), int*); |
147 | |
148 | const int p10[2] = {}; |
149 | assert(std::to_address(p10) == p10); |
150 | ASSERT_SAME_TYPE(decltype(std::to_address(p10)), const int*); |
151 | |
152 | int (*p11)() = nullptr; |
153 | assert(std::to_address(&p11) == &p11); |
154 | ASSERT_SAME_TYPE(decltype(std::to_address(&p11)), int(**)()); |
155 | |
156 | // See https://github.com/llvm/llvm-project/issues/67449 |
157 | { |
158 | struct S { }; |
159 | S* p = nullptr; |
160 | assert(std::to_address<S>(p) == p); |
161 | ASSERT_SAME_TYPE(decltype(std::to_address<S>(p)), S*); |
162 | } |
163 | |
164 | return true; |
165 | } |
166 | |
167 | int main(int, char**) { |
168 | test(); |
169 | static_assert(test()); |
170 | return 0; |
171 | } |
172 | |