Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- C++ -*-===// |
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 | // This file defines the isa<X>(), cast<X>(), dyn_cast<X>(), |
||
10 | // cast_if_present<X>(), and dyn_cast_if_present<X>() templates. |
||
11 | // |
||
12 | //===----------------------------------------------------------------------===// |
||
13 | |||
14 | #ifndef LLVM_SUPPORT_CASTING_H |
||
15 | #define LLVM_SUPPORT_CASTING_H |
||
16 | |||
17 | #include "llvm/Support/Compiler.h" |
||
18 | #include "llvm/Support/type_traits.h" |
||
19 | #include <cassert> |
||
20 | #include <memory> |
||
21 | #include <optional> |
||
22 | #include <type_traits> |
||
23 | |||
24 | namespace llvm { |
||
25 | |||
26 | //===----------------------------------------------------------------------===// |
||
27 | // simplify_type |
||
28 | //===----------------------------------------------------------------------===// |
||
29 | |||
30 | /// Define a template that can be specialized by smart pointers to reflect the |
||
31 | /// fact that they are automatically dereferenced, and are not involved with the |
||
32 | /// template selection process... the default implementation is a noop. |
||
33 | // TODO: rename this and/or replace it with other cast traits. |
||
34 | template <typename From> struct simplify_type { |
||
35 | using SimpleType = From; // The real type this represents... |
||
36 | |||
37 | // An accessor to get the real value... |
||
38 | static SimpleType &getSimplifiedValue(From &Val) { return Val; } |
||
39 | }; |
||
40 | |||
41 | template <typename From> struct simplify_type<const From> { |
||
42 | using NonConstSimpleType = typename simplify_type<From>::SimpleType; |
||
43 | using SimpleType = typename add_const_past_pointer<NonConstSimpleType>::type; |
||
44 | using RetType = |
||
45 | typename add_lvalue_reference_if_not_pointer<SimpleType>::type; |
||
46 | |||
47 | static RetType getSimplifiedValue(const From &Val) { |
||
48 | return simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val)); |
||
49 | } |
||
50 | }; |
||
51 | |||
52 | // TODO: add this namespace once everyone is switched to using the new |
||
53 | // interface. |
||
54 | // namespace detail { |
||
55 | |||
56 | //===----------------------------------------------------------------------===// |
||
57 | // isa_impl |
||
58 | //===----------------------------------------------------------------------===// |
||
59 | |||
60 | // The core of the implementation of isa<X> is here; To and From should be |
||
61 | // the names of classes. This template can be specialized to customize the |
||
62 | // implementation of isa<> without rewriting it from scratch. |
||
63 | template <typename To, typename From, typename Enabler = void> struct isa_impl { |
||
64 | static inline bool doit(const From &Val) { return To::classof(&Val); } |
||
65 | }; |
||
66 | |||
67 | // Always allow upcasts, and perform no dynamic check for them. |
||
68 | template <typename To, typename From> |
||
69 | struct isa_impl<To, From, std::enable_if_t<std::is_base_of<To, From>::value>> { |
||
70 | static inline bool doit(const From &) { return true; } |
||
71 | }; |
||
72 | |||
73 | template <typename To, typename From> struct isa_impl_cl { |
||
74 | static inline bool doit(const From &Val) { |
||
75 | return isa_impl<To, From>::doit(Val); |
||
76 | } |
||
77 | }; |
||
78 | |||
79 | template <typename To, typename From> struct isa_impl_cl<To, const From> { |
||
80 | static inline bool doit(const From &Val) { |
||
81 | return isa_impl<To, From>::doit(Val); |
||
82 | } |
||
83 | }; |
||
84 | |||
85 | template <typename To, typename From> |
||
86 | struct isa_impl_cl<To, const std::unique_ptr<From>> { |
||
87 | static inline bool doit(const std::unique_ptr<From> &Val) { |
||
88 | assert(Val && "isa<> used on a null pointer"); |
||
89 | return isa_impl_cl<To, From>::doit(*Val); |
||
90 | } |
||
91 | }; |
||
92 | |||
93 | template <typename To, typename From> struct isa_impl_cl<To, From *> { |
||
94 | static inline bool doit(const From *Val) { |
||
95 | assert(Val && "isa<> used on a null pointer"); |
||
96 | return isa_impl<To, From>::doit(*Val); |
||
97 | } |
||
98 | }; |
||
99 | |||
100 | template <typename To, typename From> struct isa_impl_cl<To, From *const> { |
||
101 | static inline bool doit(const From *Val) { |
||
102 | assert(Val && "isa<> used on a null pointer"); |
||
103 | return isa_impl<To, From>::doit(*Val); |
||
104 | } |
||
105 | }; |
||
106 | |||
107 | template <typename To, typename From> struct isa_impl_cl<To, const From *> { |
||
108 | static inline bool doit(const From *Val) { |
||
109 | assert(Val && "isa<> used on a null pointer"); |
||
110 | return isa_impl<To, From>::doit(*Val); |
||
111 | } |
||
112 | }; |
||
113 | |||
114 | template <typename To, typename From> |
||
115 | struct isa_impl_cl<To, const From *const> { |
||
116 | static inline bool doit(const From *Val) { |
||
117 | assert(Val && "isa<> used on a null pointer"); |
||
118 | return isa_impl<To, From>::doit(*Val); |
||
119 | } |
||
120 | }; |
||
121 | |||
122 | template <typename To, typename From, typename SimpleFrom> |
||
123 | struct isa_impl_wrap { |
||
124 | // When From != SimplifiedType, we can simplify the type some more by using |
||
125 | // the simplify_type template. |
||
126 | static bool doit(const From &Val) { |
||
127 | return isa_impl_wrap<To, SimpleFrom, |
||
128 | typename simplify_type<SimpleFrom>::SimpleType>:: |
||
129 | doit(simplify_type<const From>::getSimplifiedValue(Val)); |
||
130 | } |
||
131 | }; |
||
132 | |||
133 | template <typename To, typename FromTy> |
||
134 | struct isa_impl_wrap<To, FromTy, FromTy> { |
||
135 | // When From == SimpleType, we are as simple as we are going to get. |
||
136 | static bool doit(const FromTy &Val) { |
||
137 | return isa_impl_cl<To, FromTy>::doit(Val); |
||
138 | } |
||
139 | }; |
||
140 | |||
141 | //===----------------------------------------------------------------------===// |
||
142 | // cast_retty + cast_retty_impl |
||
143 | //===----------------------------------------------------------------------===// |
||
144 | |||
145 | template <class To, class From> struct cast_retty; |
||
146 | |||
147 | // Calculate what type the 'cast' function should return, based on a requested |
||
148 | // type of To and a source type of From. |
||
149 | template <class To, class From> struct cast_retty_impl { |
||
150 | using ret_type = To &; // Normal case, return Ty& |
||
151 | }; |
||
152 | template <class To, class From> struct cast_retty_impl<To, const From> { |
||
153 | using ret_type = const To &; // Normal case, return Ty& |
||
154 | }; |
||
155 | |||
156 | template <class To, class From> struct cast_retty_impl<To, From *> { |
||
157 | using ret_type = To *; // Pointer arg case, return Ty* |
||
158 | }; |
||
159 | |||
160 | template <class To, class From> struct cast_retty_impl<To, const From *> { |
||
161 | using ret_type = const To *; // Constant pointer arg case, return const Ty* |
||
162 | }; |
||
163 | |||
164 | template <class To, class From> struct cast_retty_impl<To, const From *const> { |
||
165 | using ret_type = const To *; // Constant pointer arg case, return const Ty* |
||
166 | }; |
||
167 | |||
168 | template <class To, class From> |
||
169 | struct cast_retty_impl<To, std::unique_ptr<From>> { |
||
170 | private: |
||
171 | using PointerType = typename cast_retty_impl<To, From *>::ret_type; |
||
172 | using ResultType = std::remove_pointer_t<PointerType>; |
||
173 | |||
174 | public: |
||
175 | using ret_type = std::unique_ptr<ResultType>; |
||
176 | }; |
||
177 | |||
178 | template <class To, class From, class SimpleFrom> struct cast_retty_wrap { |
||
179 | // When the simplified type and the from type are not the same, use the type |
||
180 | // simplifier to reduce the type, then reuse cast_retty_impl to get the |
||
181 | // resultant type. |
||
182 | using ret_type = typename cast_retty<To, SimpleFrom>::ret_type; |
||
183 | }; |
||
184 | |||
185 | template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> { |
||
186 | // When the simplified type is equal to the from type, use it directly. |
||
187 | using ret_type = typename cast_retty_impl<To, FromTy>::ret_type; |
||
188 | }; |
||
189 | |||
190 | template <class To, class From> struct cast_retty { |
||
191 | using ret_type = typename cast_retty_wrap< |
||
192 | To, From, typename simplify_type<From>::SimpleType>::ret_type; |
||
193 | }; |
||
194 | |||
195 | //===----------------------------------------------------------------------===// |
||
196 | // cast_convert_val |
||
197 | //===----------------------------------------------------------------------===// |
||
198 | |||
199 | // Ensure the non-simple values are converted using the simplify_type template |
||
200 | // that may be specialized by smart pointers... |
||
201 | // |
||
202 | template <class To, class From, class SimpleFrom> struct cast_convert_val { |
||
203 | // This is not a simple type, use the template to simplify it... |
||
204 | static typename cast_retty<To, From>::ret_type doit(const From &Val) { |
||
205 | return cast_convert_val<To, SimpleFrom, |
||
206 | typename simplify_type<SimpleFrom>::SimpleType>:: |
||
207 | doit(simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val))); |
||
208 | } |
||
209 | }; |
||
210 | |||
211 | template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> { |
||
212 | // If it's a reference, switch to a pointer to do the cast and then deref it. |
||
213 | static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) { |
||
214 | return *(std::remove_reference_t<typename cast_retty<To, FromTy>::ret_type> |
||
215 | *)&const_cast<FromTy &>(Val); |
||
216 | } |
||
217 | }; |
||
218 | |||
219 | template <class To, class FromTy> |
||
220 | struct cast_convert_val<To, FromTy *, FromTy *> { |
||
221 | // If it's a pointer, we can use c-style casting directly. |
||
222 | static typename cast_retty<To, FromTy *>::ret_type doit(const FromTy *Val) { |
||
223 | return (typename cast_retty<To, FromTy *>::ret_type) const_cast<FromTy *>( |
||
224 | Val); |
||
225 | } |
||
226 | }; |
||
227 | |||
228 | //===----------------------------------------------------------------------===// |
||
229 | // is_simple_type |
||
230 | //===----------------------------------------------------------------------===// |
||
231 | |||
232 | template <class X> struct is_simple_type { |
||
233 | static const bool value = |
||
234 | std::is_same<X, typename simplify_type<X>::SimpleType>::value; |
||
235 | }; |
||
236 | |||
237 | // } // namespace detail |
||
238 | |||
239 | //===----------------------------------------------------------------------===// |
||
240 | // CastIsPossible |
||
241 | //===----------------------------------------------------------------------===// |
||
242 | |||
243 | /// This struct provides a way to check if a given cast is possible. It provides |
||
244 | /// a static function called isPossible that is used to check if a cast can be |
||
245 | /// performed. It should be overridden like this: |
||
246 | /// |
||
247 | /// template<> struct CastIsPossible<foo, bar> { |
||
248 | /// static inline bool isPossible(const bar &b) { |
||
249 | /// return bar.isFoo(); |
||
250 | /// } |
||
251 | /// }; |
||
252 | template <typename To, typename From, typename Enable = void> |
||
253 | struct CastIsPossible { |
||
254 | static inline bool isPossible(const From &f) { |
||
255 | return isa_impl_wrap< |
||
256 | To, const From, |
||
257 | typename simplify_type<const From>::SimpleType>::doit(f); |
||
258 | } |
||
259 | }; |
||
260 | |||
261 | // Needed for optional unwrapping. This could be implemented with isa_impl, but |
||
262 | // we want to implement things in the new method and move old implementations |
||
263 | // over. In fact, some of the isa_impl templates should be moved over to |
||
264 | // CastIsPossible. |
||
265 | template <typename To, typename From> |
||
266 | struct CastIsPossible<To, std::optional<From>> { |
||
267 | static inline bool isPossible(const std::optional<From> &f) { |
||
268 | assert(f && "CastIsPossible::isPossible called on a nullopt!"); |
||
269 | return isa_impl_wrap< |
||
270 | To, const From, |
||
271 | typename simplify_type<const From>::SimpleType>::doit(*f); |
||
272 | } |
||
273 | }; |
||
274 | |||
275 | /// Upcasting (from derived to base) and casting from a type to itself should |
||
276 | /// always be possible. |
||
277 | template <typename To, typename From> |
||
278 | struct CastIsPossible<To, From, |
||
279 | std::enable_if_t<std::is_base_of<To, From>::value>> { |
||
280 | static inline bool isPossible(const From &f) { return true; } |
||
281 | }; |
||
282 | |||
283 | //===----------------------------------------------------------------------===// |
||
284 | // Cast traits |
||
285 | //===----------------------------------------------------------------------===// |
||
286 | |||
287 | /// All of these cast traits are meant to be implementations for useful casts |
||
288 | /// that users may want to use that are outside the standard behavior. An |
||
289 | /// example of how to use a special cast called `CastTrait` is: |
||
290 | /// |
||
291 | /// template<> struct CastInfo<foo, bar> : public CastTrait<foo, bar> {}; |
||
292 | /// |
||
293 | /// Essentially, if your use case falls directly into one of the use cases |
||
294 | /// supported by a given cast trait, simply inherit your special CastInfo |
||
295 | /// directly from one of these to avoid having to reimplement the boilerplate |
||
296 | /// `isPossible/castFailed/doCast/doCastIfPossible`. A cast trait can also |
||
297 | /// provide a subset of those functions. |
||
298 | |||
299 | /// This cast trait just provides castFailed for the specified `To` type to make |
||
300 | /// CastInfo specializations more declarative. In order to use this, the target |
||
301 | /// result type must be `To` and `To` must be constructible from `nullptr`. |
||
302 | template <typename To> struct NullableValueCastFailed { |
||
303 | static To castFailed() { return To(nullptr); } |
||
304 | }; |
||
305 | |||
306 | /// This cast trait just provides the default implementation of doCastIfPossible |
||
307 | /// to make CastInfo specializations more declarative. The `Derived` template |
||
308 | /// parameter *must* be provided for forwarding castFailed and doCast. |
||
309 | template <typename To, typename From, typename Derived> |
||
310 | struct DefaultDoCastIfPossible { |
||
311 | static To doCastIfPossible(From f) { |
||
312 | if (!Derived::isPossible(f)) |
||
313 | return Derived::castFailed(); |
||
314 | return Derived::doCast(f); |
||
315 | } |
||
316 | }; |
||
317 | |||
318 | namespace detail { |
||
319 | /// A helper to derive the type to use with `Self` for cast traits, when the |
||
320 | /// provided CRTP derived type is allowed to be void. |
||
321 | template <typename OptionalDerived, typename Default> |
||
322 | using SelfType = std::conditional_t<std::is_same<OptionalDerived, void>::value, |
||
323 | Default, OptionalDerived>; |
||
324 | } // namespace detail |
||
325 | |||
326 | /// This cast trait provides casting for the specific case of casting to a |
||
327 | /// value-typed object from a pointer-typed object. Note that `To` must be |
||
328 | /// nullable/constructible from a pointer to `From` to use this cast. |
||
329 | template <typename To, typename From, typename Derived = void> |
||
330 | struct ValueFromPointerCast |
||
331 | : public CastIsPossible<To, From *>, |
||
332 | public NullableValueCastFailed<To>, |
||
333 | public DefaultDoCastIfPossible< |
||
334 | To, From *, |
||
335 | detail::SelfType<Derived, ValueFromPointerCast<To, From>>> { |
||
336 | static inline To doCast(From *f) { return To(f); } |
||
337 | }; |
||
338 | |||
339 | /// This cast trait provides std::unique_ptr casting. It has the semantics of |
||
340 | /// moving the contents of the input unique_ptr into the output unique_ptr |
||
341 | /// during the cast. It's also a good example of how to implement a move-only |
||
342 | /// cast. |
||
343 | template <typename To, typename From, typename Derived = void> |
||
344 | struct UniquePtrCast : public CastIsPossible<To, From *> { |
||
345 | using Self = detail::SelfType<Derived, UniquePtrCast<To, From>>; |
||
346 | using CastResultType = std::unique_ptr< |
||
347 | std::remove_reference_t<typename cast_retty<To, From>::ret_type>>; |
||
348 | |||
349 | static inline CastResultType doCast(std::unique_ptr<From> &&f) { |
||
350 | return CastResultType((typename CastResultType::element_type *)f.release()); |
||
351 | } |
||
352 | |||
353 | static inline CastResultType castFailed() { return CastResultType(nullptr); } |
||
354 | |||
355 | static inline CastResultType doCastIfPossible(std::unique_ptr<From> &&f) { |
||
356 | if (!Self::isPossible(f)) |
||
357 | return castFailed(); |
||
358 | return doCast(f); |
||
359 | } |
||
360 | }; |
||
361 | |||
362 | /// This cast trait provides std::optional<T> casting. This means that if you |
||
363 | /// have a value type, you can cast it to another value type and have dyn_cast |
||
364 | /// return an std::optional<T>. |
||
365 | template <typename To, typename From, typename Derived = void> |
||
366 | struct OptionalValueCast |
||
367 | : public CastIsPossible<To, From>, |
||
368 | public DefaultDoCastIfPossible< |
||
369 | std::optional<To>, From, |
||
370 | detail::SelfType<Derived, OptionalValueCast<To, From>>> { |
||
371 | static inline std::optional<To> castFailed() { return std::optional<To>{}; } |
||
372 | |||
373 | static inline std::optional<To> doCast(const From &f) { return To(f); } |
||
374 | }; |
||
375 | |||
376 | /// Provides a cast trait that strips `const` from types to make it easier to |
||
377 | /// implement a const-version of a non-const cast. It just removes boilerplate |
||
378 | /// and reduces the amount of code you as the user need to implement. You can |
||
379 | /// use it like this: |
||
380 | /// |
||
381 | /// template<> struct CastInfo<foo, bar> { |
||
382 | /// ...verbose implementation... |
||
383 | /// }; |
||
384 | /// |
||
385 | /// template<> struct CastInfo<foo, const bar> : public |
||
386 | /// ConstStrippingForwardingCast<foo, const bar, CastInfo<foo, bar>> {}; |
||
387 | /// |
||
388 | template <typename To, typename From, typename ForwardTo> |
||
389 | struct ConstStrippingForwardingCast { |
||
390 | // Remove the pointer if it exists, then we can get rid of consts/volatiles. |
||
391 | using DecayedFrom = std::remove_cv_t<std::remove_pointer_t<From>>; |
||
392 | // Now if it's a pointer, add it back. Otherwise, we want a ref. |
||
393 | using NonConstFrom = std::conditional_t<std::is_pointer<From>::value, |
||
394 | DecayedFrom *, DecayedFrom &>; |
||
395 | |||
396 | static inline bool isPossible(const From &f) { |
||
397 | return ForwardTo::isPossible(const_cast<NonConstFrom>(f)); |
||
398 | } |
||
399 | |||
400 | static inline decltype(auto) castFailed() { return ForwardTo::castFailed(); } |
||
401 | |||
402 | static inline decltype(auto) doCast(const From &f) { |
||
403 | return ForwardTo::doCast(const_cast<NonConstFrom>(f)); |
||
404 | } |
||
405 | |||
406 | static inline decltype(auto) doCastIfPossible(const From &f) { |
||
407 | return ForwardTo::doCastIfPossible(const_cast<NonConstFrom>(f)); |
||
408 | } |
||
409 | }; |
||
410 | |||
411 | /// Provides a cast trait that uses a defined pointer to pointer cast as a base |
||
412 | /// for reference-to-reference casts. Note that it does not provide castFailed |
||
413 | /// and doCastIfPossible because a pointer-to-pointer cast would likely just |
||
414 | /// return `nullptr` which could cause nullptr dereference. You can use it like |
||
415 | /// this: |
||
416 | /// |
||
417 | /// template <> struct CastInfo<foo, bar *> { ... verbose implementation... }; |
||
418 | /// |
||
419 | /// template <> |
||
420 | /// struct CastInfo<foo, bar> |
||
421 | /// : public ForwardToPointerCast<foo, bar, CastInfo<foo, bar *>> {}; |
||
422 | /// |
||
423 | template <typename To, typename From, typename ForwardTo> |
||
424 | struct ForwardToPointerCast { |
||
425 | static inline bool isPossible(const From &f) { |
||
426 | return ForwardTo::isPossible(&f); |
||
427 | } |
||
428 | |||
429 | static inline decltype(auto) doCast(const From &f) { |
||
430 | return *ForwardTo::doCast(&f); |
||
431 | } |
||
432 | }; |
||
433 | |||
434 | //===----------------------------------------------------------------------===// |
||
435 | // CastInfo |
||
436 | //===----------------------------------------------------------------------===// |
||
437 | |||
438 | /// This struct provides a method for customizing the way a cast is performed. |
||
439 | /// It inherits from CastIsPossible, to support the case of declaring many |
||
440 | /// CastIsPossible specializations without having to specialize the full |
||
441 | /// CastInfo. |
||
442 | /// |
||
443 | /// In order to specialize different behaviors, specify different functions in |
||
444 | /// your CastInfo specialization. |
||
445 | /// For isa<> customization, provide: |
||
446 | /// |
||
447 | /// `static bool isPossible(const From &f)` |
||
448 | /// |
||
449 | /// For cast<> customization, provide: |
||
450 | /// |
||
451 | /// `static To doCast(const From &f)` |
||
452 | /// |
||
453 | /// For dyn_cast<> and the *_if_present<> variants' customization, provide: |
||
454 | /// |
||
455 | /// `static To castFailed()` and `static To doCastIfPossible(const From &f)` |
||
456 | /// |
||
457 | /// Your specialization might look something like this: |
||
458 | /// |
||
459 | /// template<> struct CastInfo<foo, bar> : public CastIsPossible<foo, bar> { |
||
460 | /// static inline foo doCast(const bar &b) { |
||
461 | /// return foo(const_cast<bar &>(b)); |
||
462 | /// } |
||
463 | /// static inline foo castFailed() { return foo(); } |
||
464 | /// static inline foo doCastIfPossible(const bar &b) { |
||
465 | /// if (!CastInfo<foo, bar>::isPossible(b)) |
||
466 | /// return castFailed(); |
||
467 | /// return doCast(b); |
||
468 | /// } |
||
469 | /// }; |
||
470 | |||
471 | // The default implementations of CastInfo don't use cast traits for now because |
||
472 | // we need to specify types all over the place due to the current expected |
||
473 | // casting behavior and the way cast_retty works. New use cases can and should |
||
474 | // take advantage of the cast traits whenever possible! |
||
475 | |||
476 | template <typename To, typename From, typename Enable = void> |
||
477 | struct CastInfo : public CastIsPossible<To, From> { |
||
478 | using Self = CastInfo<To, From, Enable>; |
||
479 | |||
480 | using CastReturnType = typename cast_retty<To, From>::ret_type; |
||
481 | |||
482 | static inline CastReturnType doCast(const From &f) { |
||
483 | return cast_convert_val< |
||
484 | To, From, |
||
485 | typename simplify_type<From>::SimpleType>::doit(const_cast<From &>(f)); |
||
486 | } |
||
487 | |||
488 | // This assumes that you can construct the cast return type from `nullptr`. |
||
489 | // This is largely to support legacy use cases - if you don't want this |
||
490 | // behavior you should specialize CastInfo for your use case. |
||
491 | static inline CastReturnType castFailed() { return CastReturnType(nullptr); } |
||
492 | |||
493 | static inline CastReturnType doCastIfPossible(const From &f) { |
||
494 | if (!Self::isPossible(f)) |
||
495 | return castFailed(); |
||
496 | return doCast(f); |
||
497 | } |
||
498 | }; |
||
499 | |||
500 | /// This struct provides an overload for CastInfo where From has simplify_type |
||
501 | /// defined. This simply forwards to the appropriate CastInfo with the |
||
502 | /// simplified type/value, so you don't have to implement both. |
||
503 | template <typename To, typename From> |
||
504 | struct CastInfo<To, From, std::enable_if_t<!is_simple_type<From>::value>> { |
||
505 | using Self = CastInfo<To, From>; |
||
506 | using SimpleFrom = typename simplify_type<From>::SimpleType; |
||
507 | using SimplifiedSelf = CastInfo<To, SimpleFrom>; |
||
508 | |||
509 | static inline bool isPossible(From &f) { |
||
510 | return SimplifiedSelf::isPossible( |
||
511 | simplify_type<From>::getSimplifiedValue(f)); |
||
512 | } |
||
513 | |||
514 | static inline decltype(auto) doCast(From &f) { |
||
515 | return SimplifiedSelf::doCast(simplify_type<From>::getSimplifiedValue(f)); |
||
516 | } |
||
517 | |||
518 | static inline decltype(auto) castFailed() { |
||
519 | return SimplifiedSelf::castFailed(); |
||
520 | } |
||
521 | |||
522 | static inline decltype(auto) doCastIfPossible(From &f) { |
||
523 | return SimplifiedSelf::doCastIfPossible( |
||
524 | simplify_type<From>::getSimplifiedValue(f)); |
||
525 | } |
||
526 | }; |
||
527 | |||
528 | //===----------------------------------------------------------------------===// |
||
529 | // Pre-specialized CastInfo |
||
530 | //===----------------------------------------------------------------------===// |
||
531 | |||
532 | /// Provide a CastInfo specialized for std::unique_ptr. |
||
533 | template <typename To, typename From> |
||
534 | struct CastInfo<To, std::unique_ptr<From>> : public UniquePtrCast<To, From> {}; |
||
535 | |||
536 | /// Provide a CastInfo specialized for std::optional<From>. It's assumed that if |
||
537 | /// the input is std::optional<From> that the output can be std::optional<To>. |
||
538 | /// If that's not the case, specialize CastInfo for your use case. |
||
539 | template <typename To, typename From> |
||
540 | struct CastInfo<To, std::optional<From>> : public OptionalValueCast<To, From> { |
||
541 | }; |
||
542 | |||
543 | /// isa<X> - Return true if the parameter to the template is an instance of one |
||
544 | /// of the template type arguments. Used like this: |
||
545 | /// |
||
546 | /// if (isa<Type>(myVal)) { ... } |
||
547 | /// if (isa<Type0, Type1, Type2>(myVal)) { ... } |
||
548 | template <typename To, typename From> |
||
549 | [[nodiscard]] inline bool isa(const From &Val) { |
||
550 | return CastInfo<To, const From>::isPossible(Val); |
||
551 | } |
||
552 | |||
553 | template <typename First, typename Second, typename... Rest, typename From> |
||
554 | [[nodiscard]] inline bool isa(const From &Val) { |
||
555 | return isa<First>(Val) || isa<Second, Rest...>(Val); |
||
556 | } |
||
557 | |||
558 | /// cast<X> - Return the argument parameter cast to the specified type. This |
||
559 | /// casting operator asserts that the type is correct, so it does not return |
||
560 | /// null on failure. It does not allow a null argument (use cast_if_present for |
||
561 | /// that). It is typically used like this: |
||
562 | /// |
||
563 | /// cast<Instruction>(myVal)->getParent() |
||
564 | |||
565 | template <typename To, typename From> |
||
566 | [[nodiscard]] inline decltype(auto) cast(const From &Val) { |
||
567 | assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!"); |
||
568 | return CastInfo<To, const From>::doCast(Val); |
||
569 | } |
||
570 | |||
571 | template <typename To, typename From> |
||
572 | [[nodiscard]] inline decltype(auto) cast(From &Val) { |
||
573 | assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!"); |
||
574 | return CastInfo<To, From>::doCast(Val); |
||
575 | } |
||
576 | |||
577 | template <typename To, typename From> |
||
578 | [[nodiscard]] inline decltype(auto) cast(From *Val) { |
||
579 | assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!"); |
||
580 | return CastInfo<To, From *>::doCast(Val); |
||
581 | } |
||
582 | |||
583 | template <typename To, typename From> |
||
584 | [[nodiscard]] inline decltype(auto) cast(std::unique_ptr<From> &&Val) { |
||
585 | assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!"); |
||
586 | return CastInfo<To, std::unique_ptr<From>>::doCast(std::move(Val)); |
||
587 | } |
||
588 | |||
589 | //===----------------------------------------------------------------------===// |
||
590 | // ValueIsPresent |
||
591 | //===----------------------------------------------------------------------===// |
||
592 | |||
593 | template <typename T> |
||
594 | constexpr bool IsNullable = |
||
595 | std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>; |
||
596 | |||
597 | /// ValueIsPresent provides a way to check if a value is, well, present. For |
||
598 | /// pointers, this is the equivalent of checking against nullptr, for Optionals |
||
599 | /// this is the equivalent of checking hasValue(). It also provides a method for |
||
600 | /// unwrapping a value (think calling .value() on an optional). |
||
601 | |||
602 | // Generic values can't *not* be present. |
||
603 | template <typename T, typename Enable = void> struct ValueIsPresent { |
||
604 | using UnwrappedType = T; |
||
605 | static inline bool isPresent(const T &t) { return true; } |
||
606 | static inline decltype(auto) unwrapValue(T &t) { return t; } |
||
607 | }; |
||
608 | |||
609 | // Optional provides its own way to check if something is present. |
||
610 | template <typename T> struct ValueIsPresent<std::optional<T>> { |
||
611 | using UnwrappedType = T; |
||
612 | static inline bool isPresent(const std::optional<T> &t) { |
||
613 | return t.has_value(); |
||
614 | } |
||
615 | static inline decltype(auto) unwrapValue(std::optional<T> &t) { return *t; } |
||
616 | }; |
||
617 | |||
618 | // If something is "nullable" then we just compare it to nullptr to see if it |
||
619 | // exists. |
||
620 | template <typename T> |
||
621 | struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> { |
||
622 | using UnwrappedType = T; |
||
623 | static inline bool isPresent(const T &t) { return t != T(nullptr); } |
||
624 | static inline decltype(auto) unwrapValue(T &t) { return t; } |
||
625 | }; |
||
626 | |||
627 | namespace detail { |
||
628 | // Convenience function we can use to check if a value is present. Because of |
||
629 | // simplify_type, we have to call it on the simplified type for now. |
||
630 | template <typename T> inline bool isPresent(const T &t) { |
||
631 | return ValueIsPresent<typename simplify_type<T>::SimpleType>::isPresent( |
||
632 | simplify_type<T>::getSimplifiedValue(const_cast<T &>(t))); |
||
633 | } |
||
634 | |||
635 | // Convenience function we can use to unwrap a value. |
||
636 | template <typename T> inline decltype(auto) unwrapValue(T &t) { |
||
637 | return ValueIsPresent<T>::unwrapValue(t); |
||
638 | } |
||
639 | } // namespace detail |
||
640 | |||
641 | /// dyn_cast<X> - Return the argument parameter cast to the specified type. This |
||
642 | /// casting operator returns null if the argument is of the wrong type, so it |
||
643 | /// can be used to test for a type as well as cast if successful. The value |
||
644 | /// passed in must be present, if not, use dyn_cast_if_present. This should be |
||
645 | /// used in the context of an if statement like this: |
||
646 | /// |
||
647 | /// if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... } |
||
648 | |||
649 | template <typename To, typename From> |
||
650 | [[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) { |
||
651 | assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); |
||
652 | return CastInfo<To, const From>::doCastIfPossible(Val); |
||
653 | } |
||
654 | |||
655 | template <typename To, typename From> |
||
656 | [[nodiscard]] inline decltype(auto) dyn_cast(From &Val) { |
||
657 | assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); |
||
658 | return CastInfo<To, From>::doCastIfPossible(Val); |
||
659 | } |
||
660 | |||
661 | template <typename To, typename From> |
||
662 | [[nodiscard]] inline decltype(auto) dyn_cast(From *Val) { |
||
663 | assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); |
||
664 | return CastInfo<To, From *>::doCastIfPossible(Val); |
||
665 | } |
||
666 | |||
667 | template <typename To, typename From> |
||
668 | [[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &&Val) { |
||
669 | assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); |
||
670 | return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible( |
||
671 | std::forward<std::unique_ptr<From> &&>(Val)); |
||
672 | } |
||
673 | |||
674 | /// isa_and_present<X> - Functionally identical to isa, except that a null value |
||
675 | /// is accepted. |
||
676 | template <typename... X, class Y> |
||
677 | [[nodiscard]] inline bool isa_and_present(const Y &Val) { |
||
678 | if (!detail::isPresent(Val)) |
||
679 | return false; |
||
680 | return isa<X...>(Val); |
||
681 | } |
||
682 | |||
683 | template <typename... X, class Y> |
||
684 | [[nodiscard]] inline bool isa_and_nonnull(const Y &Val) { |
||
685 | return isa_and_present<X...>(Val); |
||
686 | } |
||
687 | |||
688 | /// cast_if_present<X> - Functionally identical to cast, except that a null |
||
689 | /// value is accepted. |
||
690 | template <class X, class Y> |
||
691 | [[nodiscard]] inline auto cast_if_present(const Y &Val) { |
||
692 | if (!detail::isPresent(Val)) |
||
693 | return CastInfo<X, const Y>::castFailed(); |
||
694 | assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!"); |
||
695 | return cast<X>(detail::unwrapValue(Val)); |
||
696 | } |
||
697 | |||
698 | template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y &Val) { |
||
699 | if (!detail::isPresent(Val)) |
||
700 | return CastInfo<X, Y>::castFailed(); |
||
701 | assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!"); |
||
702 | return cast<X>(detail::unwrapValue(Val)); |
||
703 | } |
||
704 | |||
705 | template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y *Val) { |
||
706 | if (!detail::isPresent(Val)) |
||
707 | return CastInfo<X, Y *>::castFailed(); |
||
708 | assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!"); |
||
709 | return cast<X>(detail::unwrapValue(Val)); |
||
710 | } |
||
711 | |||
712 | template <class X, class Y> |
||
713 | [[nodiscard]] inline auto cast_if_present(std::unique_ptr<Y> &&Val) { |
||
714 | if (!detail::isPresent(Val)) |
||
715 | return UniquePtrCast<X, Y>::castFailed(); |
||
716 | return UniquePtrCast<X, Y>::doCast(std::move(Val)); |
||
717 | } |
||
718 | |||
719 | // Provide a forwarding from cast_or_null to cast_if_present for current |
||
720 | // users. This is deprecated and will be removed in a future patch, use |
||
721 | // cast_if_present instead. |
||
722 | template <class X, class Y> auto cast_or_null(const Y &Val) { |
||
723 | return cast_if_present<X>(Val); |
||
724 | } |
||
725 | |||
726 | template <class X, class Y> auto cast_or_null(Y &Val) { |
||
727 | return cast_if_present<X>(Val); |
||
728 | } |
||
729 | |||
730 | template <class X, class Y> auto cast_or_null(Y *Val) { |
||
731 | return cast_if_present<X>(Val); |
||
732 | } |
||
733 | |||
734 | template <class X, class Y> auto cast_or_null(std::unique_ptr<Y> &&Val) { |
||
735 | return cast_if_present<X>(std::move(Val)); |
||
736 | } |
||
737 | |||
738 | /// dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a |
||
739 | /// null (or none in the case of optionals) value is accepted. |
||
740 | template <class X, class Y> auto dyn_cast_if_present(const Y &Val) { |
||
741 | if (!detail::isPresent(Val)) |
||
742 | return CastInfo<X, const Y>::castFailed(); |
||
743 | return CastInfo<X, const Y>::doCastIfPossible(detail::unwrapValue(Val)); |
||
744 | } |
||
745 | |||
746 | template <class X, class Y> auto dyn_cast_if_present(Y &Val) { |
||
747 | if (!detail::isPresent(Val)) |
||
748 | return CastInfo<X, Y>::castFailed(); |
||
749 | return CastInfo<X, Y>::doCastIfPossible(detail::unwrapValue(Val)); |
||
750 | } |
||
751 | |||
752 | template <class X, class Y> auto dyn_cast_if_present(Y *Val) { |
||
753 | if (!detail::isPresent(Val)) |
||
754 | return CastInfo<X, Y *>::castFailed(); |
||
755 | return CastInfo<X, Y *>::doCastIfPossible(detail::unwrapValue(Val)); |
||
756 | } |
||
757 | |||
758 | // Forwards to dyn_cast_if_present to avoid breaking current users. This is |
||
759 | // deprecated and will be removed in a future patch, use |
||
760 | // cast_if_present instead. |
||
761 | template <class X, class Y> auto dyn_cast_or_null(const Y &Val) { |
||
762 | return dyn_cast_if_present<X>(Val); |
||
763 | } |
||
764 | |||
765 | template <class X, class Y> auto dyn_cast_or_null(Y &Val) { |
||
766 | return dyn_cast_if_present<X>(Val); |
||
767 | } |
||
768 | |||
769 | template <class X, class Y> auto dyn_cast_or_null(Y *Val) { |
||
770 | return dyn_cast_if_present<X>(Val); |
||
771 | } |
||
772 | |||
773 | /// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>, |
||
774 | /// taking ownership of the input pointer iff isa<X>(Val) is true. If the |
||
775 | /// cast is successful, From refers to nullptr on exit and the casted value |
||
776 | /// is returned. If the cast is unsuccessful, the function returns nullptr |
||
777 | /// and From is unchanged. |
||
778 | template <class X, class Y> |
||
779 | [[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType |
||
780 | unique_dyn_cast(std::unique_ptr<Y> &Val) { |
||
781 | if (!isa<X>(Val)) |
||
782 | return nullptr; |
||
783 | return cast<X>(std::move(Val)); |
||
784 | } |
||
785 | |||
786 | template <class X, class Y> |
||
787 | [[nodiscard]] inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) { |
||
788 | return unique_dyn_cast<X, Y>(Val); |
||
789 | } |
||
790 | |||
791 | // unique_dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, |
||
792 | // except that a null value is accepted. |
||
793 | template <class X, class Y> |
||
794 | [[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType |
||
795 | unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) { |
||
796 | if (!Val) |
||
797 | return nullptr; |
||
798 | return unique_dyn_cast<X, Y>(Val); |
||
799 | } |
||
800 | |||
801 | template <class X, class Y> |
||
802 | [[nodiscard]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) { |
||
803 | return unique_dyn_cast_or_null<X, Y>(Val); |
||
804 | } |
||
805 | |||
806 | } // end namespace llvm |
||
807 | |||
808 | #endif // LLVM_SUPPORT_CASTING_H |