]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===---------- llvm/unittest/Support/Casting.cpp - Casting tests ---------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | ||
10 | #include "llvm/Support/Casting.h" | |
1a4d82fc | 11 | #include "llvm/IR/User.h" |
223e47cc LB |
12 | #include "llvm/Support/Debug.h" |
13 | #include "llvm/Support/raw_ostream.h" | |
223e47cc LB |
14 | #include "gtest/gtest.h" |
15 | #include <cstdlib> | |
16 | ||
17 | namespace llvm { | |
1a4d82fc JJ |
18 | // Used to test illegal cast. If a cast doesn't match any of the "real" ones, |
19 | // it will match this one. | |
20 | struct IllegalCast; | |
21 | template <typename T> IllegalCast *cast(...) { return nullptr; } | |
223e47cc LB |
22 | |
23 | // set up two example classes | |
24 | // with conversion facility | |
25 | // | |
26 | struct bar { | |
27 | bar() {} | |
28 | struct foo *baz(); | |
29 | struct foo *caz(); | |
30 | struct foo *daz(); | |
31 | struct foo *naz(); | |
32 | private: | |
33 | bar(const bar &); | |
34 | }; | |
35 | struct foo { | |
36 | void ext() const; | |
37 | /* static bool classof(const bar *X) { | |
38 | cerr << "Classof: " << X << "\n"; | |
39 | return true; | |
40 | }*/ | |
41 | }; | |
42 | ||
43 | template <> struct isa_impl<foo, bar> { | |
44 | static inline bool doit(const bar &Val) { | |
45 | dbgs() << "Classof: " << &Val << "\n"; | |
46 | return true; | |
47 | } | |
48 | }; | |
49 | ||
50 | foo *bar::baz() { | |
51 | return cast<foo>(this); | |
52 | } | |
53 | ||
54 | foo *bar::caz() { | |
55 | return cast_or_null<foo>(this); | |
56 | } | |
57 | ||
58 | foo *bar::daz() { | |
59 | return dyn_cast<foo>(this); | |
60 | } | |
61 | ||
62 | foo *bar::naz() { | |
63 | return dyn_cast_or_null<foo>(this); | |
64 | } | |
65 | ||
66 | ||
67 | bar *fub(); | |
1a4d82fc JJ |
68 | |
69 | template <> struct simplify_type<foo> { | |
70 | typedef int SimpleType; | |
71 | static SimpleType getSimplifiedValue(foo &Val) { return 0; } | |
72 | }; | |
73 | ||
223e47cc LB |
74 | } // End llvm namespace |
75 | ||
76 | using namespace llvm; | |
77 | ||
1a4d82fc JJ |
78 | |
79 | // Test the peculiar behavior of Use in simplify_type. | |
80 | static_assert(std::is_same<simplify_type<Use>::SimpleType, Value *>::value, | |
81 | "Use doesn't simplify correctly!"); | |
82 | static_assert(std::is_same<simplify_type<Use *>::SimpleType, Value *>::value, | |
83 | "Use doesn't simplify correctly!"); | |
84 | ||
85 | // Test that a regular class behaves as expected. | |
86 | static_assert(std::is_same<simplify_type<foo>::SimpleType, int>::value, | |
87 | "Unexpected simplify_type result!"); | |
88 | static_assert(std::is_same<simplify_type<foo *>::SimpleType, foo *>::value, | |
89 | "Unexpected simplify_type result!"); | |
90 | ||
223e47cc LB |
91 | namespace { |
92 | ||
1a4d82fc | 93 | const foo *null_foo = nullptr; |
223e47cc LB |
94 | |
95 | bar B; | |
96 | extern bar &B1; | |
97 | bar &B1 = B; | |
98 | extern const bar *B2; | |
99 | // test various configurations of const | |
100 | const bar &B3 = B1; | |
101 | const bar *const B4 = B2; | |
102 | ||
103 | TEST(CastingTest, isa) { | |
104 | EXPECT_TRUE(isa<foo>(B1)); | |
105 | EXPECT_TRUE(isa<foo>(B2)); | |
106 | EXPECT_TRUE(isa<foo>(B3)); | |
107 | EXPECT_TRUE(isa<foo>(B4)); | |
108 | } | |
109 | ||
110 | TEST(CastingTest, cast) { | |
111 | foo &F1 = cast<foo>(B1); | |
112 | EXPECT_NE(&F1, null_foo); | |
113 | const foo *F3 = cast<foo>(B2); | |
114 | EXPECT_NE(F3, null_foo); | |
115 | const foo *F4 = cast<foo>(B2); | |
116 | EXPECT_NE(F4, null_foo); | |
117 | const foo &F5 = cast<foo>(B3); | |
118 | EXPECT_NE(&F5, null_foo); | |
119 | const foo *F6 = cast<foo>(B4); | |
120 | EXPECT_NE(F6, null_foo); | |
121 | // Can't pass null pointer to cast<>. | |
122 | // foo *F7 = cast<foo>(fub()); | |
123 | // EXPECT_EQ(F7, null_foo); | |
124 | foo *F8 = B1.baz(); | |
125 | EXPECT_NE(F8, null_foo); | |
126 | } | |
127 | ||
128 | TEST(CastingTest, cast_or_null) { | |
129 | const foo *F11 = cast_or_null<foo>(B2); | |
130 | EXPECT_NE(F11, null_foo); | |
131 | const foo *F12 = cast_or_null<foo>(B2); | |
132 | EXPECT_NE(F12, null_foo); | |
133 | const foo *F13 = cast_or_null<foo>(B4); | |
134 | EXPECT_NE(F13, null_foo); | |
135 | const foo *F14 = cast_or_null<foo>(fub()); // Shouldn't print. | |
136 | EXPECT_EQ(F14, null_foo); | |
137 | foo *F15 = B1.caz(); | |
138 | EXPECT_NE(F15, null_foo); | |
139 | } | |
140 | ||
141 | TEST(CastingTest, dyn_cast) { | |
142 | const foo *F1 = dyn_cast<foo>(B2); | |
143 | EXPECT_NE(F1, null_foo); | |
144 | const foo *F2 = dyn_cast<foo>(B2); | |
145 | EXPECT_NE(F2, null_foo); | |
146 | const foo *F3 = dyn_cast<foo>(B4); | |
147 | EXPECT_NE(F3, null_foo); | |
148 | // Can't pass null pointer to dyn_cast<>. | |
149 | // foo *F4 = dyn_cast<foo>(fub()); | |
150 | // EXPECT_EQ(F4, null_foo); | |
151 | foo *F5 = B1.daz(); | |
152 | EXPECT_NE(F5, null_foo); | |
153 | } | |
154 | ||
155 | TEST(CastingTest, dyn_cast_or_null) { | |
156 | const foo *F1 = dyn_cast_or_null<foo>(B2); | |
157 | EXPECT_NE(F1, null_foo); | |
158 | const foo *F2 = dyn_cast_or_null<foo>(B2); | |
159 | EXPECT_NE(F2, null_foo); | |
160 | const foo *F3 = dyn_cast_or_null<foo>(B4); | |
161 | EXPECT_NE(F3, null_foo); | |
162 | foo *F4 = dyn_cast_or_null<foo>(fub()); | |
163 | EXPECT_EQ(F4, null_foo); | |
164 | foo *F5 = B1.naz(); | |
165 | EXPECT_NE(F5, null_foo); | |
166 | } | |
167 | ||
168 | // These lines are errors... | |
169 | //foo *F20 = cast<foo>(B2); // Yields const foo* | |
170 | //foo &F21 = cast<foo>(B3); // Yields const foo& | |
171 | //foo *F22 = cast<foo>(B4); // Yields const foo* | |
172 | //foo &F23 = cast_or_null<foo>(B1); | |
173 | //const foo &F24 = cast_or_null<foo>(B3); | |
174 | ||
175 | const bar *B2 = &B; | |
176 | } // anonymous namespace | |
177 | ||
1a4d82fc | 178 | bar *llvm::fub() { return nullptr; } |
970d7e83 LB |
179 | |
180 | namespace { | |
181 | namespace inferred_upcasting { | |
182 | // This test case verifies correct behavior of inferred upcasts when the | |
183 | // types are statically known to be OK to upcast. This is the case when, | |
184 | // for example, Derived inherits from Base, and we do `isa<Base>(Derived)`. | |
185 | ||
186 | // Note: This test will actually fail to compile without inferred | |
187 | // upcasting. | |
188 | ||
189 | class Base { | |
190 | public: | |
191 | // No classof. We are testing that the upcast is inferred. | |
192 | Base() {} | |
193 | }; | |
194 | ||
195 | class Derived : public Base { | |
196 | public: | |
197 | Derived() {} | |
198 | }; | |
199 | ||
200 | // Even with no explicit classof() in Base, we should still be able to cast | |
201 | // Derived to its base class. | |
202 | TEST(CastingTest, UpcastIsInferred) { | |
203 | Derived D; | |
204 | EXPECT_TRUE(isa<Base>(D)); | |
205 | Base *BP = dyn_cast<Base>(&D); | |
1a4d82fc | 206 | EXPECT_TRUE(BP != nullptr); |
970d7e83 LB |
207 | } |
208 | ||
209 | ||
210 | // This test verifies that the inferred upcast takes precedence over an | |
211 | // explicitly written one. This is important because it verifies that the | |
212 | // dynamic check gets optimized away. | |
213 | class UseInferredUpcast { | |
214 | public: | |
215 | int Dummy; | |
216 | static bool classof(const UseInferredUpcast *) { | |
217 | return false; | |
218 | } | |
219 | }; | |
220 | ||
221 | TEST(CastingTest, InferredUpcastTakesPrecedence) { | |
222 | UseInferredUpcast UIU; | |
223 | // Since the explicit classof() returns false, this will fail if the | |
224 | // explicit one is used. | |
225 | EXPECT_TRUE(isa<UseInferredUpcast>(&UIU)); | |
226 | } | |
227 | ||
228 | } // end namespace inferred_upcasting | |
229 | } // end anonymous namespace | |
1a4d82fc JJ |
230 | // Test that we reject casts of temporaries (and so the illegal cast gets used). |
231 | namespace TemporaryCast { | |
232 | struct pod {}; | |
233 | IllegalCast *testIllegalCast() { return cast<foo>(pod()); } | |
234 | } | |
85aaf69f SL |
235 | |
236 | namespace { | |
237 | namespace pointer_wrappers { | |
238 | ||
239 | struct Base { | |
240 | bool IsDerived; | |
241 | Base(bool IsDerived = false) : IsDerived(IsDerived) {} | |
242 | }; | |
243 | ||
244 | struct Derived : Base { | |
245 | Derived() : Base(true) {} | |
246 | static bool classof(const Base *B) { return B->IsDerived; } | |
247 | }; | |
248 | ||
249 | class PTy { | |
250 | Base *B; | |
251 | public: | |
252 | PTy(Base *B) : B(B) {} | |
253 | LLVM_EXPLICIT operator bool() const { return get(); } | |
254 | Base *get() const { return B; } | |
255 | }; | |
256 | ||
257 | } // end namespace pointer_wrappers | |
258 | } // end namespace | |
259 | ||
260 | namespace llvm { | |
261 | ||
262 | template <> struct simplify_type<pointer_wrappers::PTy> { | |
263 | typedef pointer_wrappers::Base *SimpleType; | |
264 | static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) { | |
265 | return P.get(); | |
266 | } | |
267 | }; | |
268 | template <> struct simplify_type<const pointer_wrappers::PTy> { | |
269 | typedef pointer_wrappers::Base *SimpleType; | |
270 | static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) { | |
271 | return P.get(); | |
272 | } | |
273 | }; | |
274 | ||
275 | } // end namespace llvm | |
276 | ||
277 | namespace { | |
278 | namespace pointer_wrappers { | |
279 | ||
280 | // Some objects. | |
281 | pointer_wrappers::Base B; | |
282 | pointer_wrappers::Derived D; | |
283 | ||
284 | // Mutable "smart" pointers. | |
285 | pointer_wrappers::PTy MN(nullptr); | |
286 | pointer_wrappers::PTy MB(&B); | |
287 | pointer_wrappers::PTy MD(&D); | |
288 | ||
289 | // Const "smart" pointers. | |
290 | const pointer_wrappers::PTy CN(nullptr); | |
291 | const pointer_wrappers::PTy CB(&B); | |
292 | const pointer_wrappers::PTy CD(&D); | |
293 | ||
294 | TEST(CastingTest, smart_isa) { | |
295 | EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB)); | |
296 | EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB)); | |
297 | EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD)); | |
298 | EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD)); | |
299 | } | |
300 | ||
301 | TEST(CastingTest, smart_cast) { | |
302 | EXPECT_TRUE(cast<pointer_wrappers::Derived>(MD) == &D); | |
303 | EXPECT_TRUE(cast<pointer_wrappers::Derived>(CD) == &D); | |
304 | } | |
305 | ||
306 | TEST(CastingTest, smart_cast_or_null) { | |
307 | EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MN) == nullptr); | |
308 | EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CN) == nullptr); | |
309 | EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MD) == &D); | |
310 | EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CD) == &D); | |
311 | } | |
312 | ||
313 | TEST(CastingTest, smart_dyn_cast) { | |
314 | EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MB) == nullptr); | |
315 | EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CB) == nullptr); | |
316 | EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MD) == &D); | |
317 | EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CD) == &D); | |
318 | } | |
319 | ||
320 | TEST(CastingTest, smart_dyn_cast_or_null) { | |
321 | EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MN) == nullptr); | |
322 | EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CN) == nullptr); | |
323 | EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MB) == nullptr); | |
324 | EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CB) == nullptr); | |
325 | EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MD) == &D); | |
326 | EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CD) == &D); | |
327 | } | |
328 | ||
329 | } // end namespace pointer_wrappers | |
330 | } // end namespace |