xref: /llvm-project/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp (revision e331bbb3465f51f858a578fa9fa6449a1abbd4cd)
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;
P1P126     constexpr explicit P1(int *p) : p_(p) { }
operator ->P127     constexpr int *operator->() const { return p_; }
28     int *p_;
29 };
30 
31 struct P2 {
32     using element_type = Irrelevant;
P2P233     constexpr explicit P2(int *p) : p_(p) { }
operator ->P234     constexpr P1 operator->() const { return p_; }
35     P1 p_;
36 };
37 
38 struct P3 {
P3P339     constexpr explicit P3(int *p) : p_(p) { }
40     int *p_;
41 };
42 
43 template<>
44 struct std::pointer_traits<P3> {
to_addressstd::pointer_traits45     static constexpr int *to_address(const P3& p) { return p.p_; }
46 };
47 
48 struct P4 {
P4P449     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> {
to_addressstd::pointer_traits56     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 {
operator ->P7::CanQual76         CanProxy<T> operator->() const { return CanProxy<T>(); }
77     };
78     template<typename T>
79     struct CanProxy {
operator ->P7::CanProxy80         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_;
FancyPtrAP8::FancyPtrA89         TEST_CONSTEXPR FancyPtrA(T *p) : p_(p) {}
90         T& operator*() const;
operator ->P8::FancyPtrA91         TEST_CONSTEXPR T *operator->() const { return p_; }
92     };
93     template<class T>
94     struct FancyPtrB {
95         T *p_;
FancyPtrBP8::FancyPtrB96         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> > {
to_addressstd::pointer_traits103     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 
test()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 
main(int,char **)167 int main(int, char**) {
168     test();
169     static_assert(test());
170     return 0;
171 }
172