| /* Dynamic testing for abstract is-a relationships. |
| Copyright (C) 2012-2022 Free Software Foundation, Inc. |
| Contributed by Lawrence Crowl. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| |
| /* This header generic type query and conversion functions. |
| |
| |
| USING THE GENERIC TYPE FACILITY |
| |
| |
| The user functions are: |
| |
| bool is_a <TYPE> (pointer) |
| |
| Tests whether the pointer actually points to a more derived TYPE. |
| |
| Suppose you have a symtab_node *ptr, AKA symtab_node *ptr. You can test |
| whether it points to a 'derived' cgraph_node as follows. |
| |
| if (is_a <cgraph_node *> (ptr)) |
| .... |
| |
| |
| TYPE as_a <TYPE> (pointer) |
| |
| Converts pointer to a TYPE. |
| |
| You can just assume that it is such a node. |
| |
| do_something_with (as_a <cgraph_node *> *ptr); |
| |
| TYPE safe_as_a <TYPE> (pointer) |
| |
| Like as_a <TYPE> (pointer), but where pointer could be NULL. This |
| adds a check against NULL where the regular is_a_helper hook for TYPE |
| assumes non-NULL. |
| |
| do_something_with (safe_as_a <cgraph_node *> *ptr); |
| |
| TYPE dyn_cast <TYPE> (pointer) |
| |
| Converts pointer to TYPE if and only if "is_a <TYPE> pointer". Otherwise, |
| returns NULL. This function is essentially a checked down cast. |
| |
| This functions reduce compile time and increase type safety when treating a |
| generic item as a more specific item. |
| |
| You can test and obtain a pointer to the 'derived' type in one indivisible |
| operation. |
| |
| if (cgraph_node *cptr = dyn_cast <cgraph_node *> (ptr)) |
| .... |
| |
| As an example, the code change is from |
| |
| if (symtab_function_p (node)) |
| { |
| struct cgraph_node *cnode = cgraph (node); |
| .... |
| } |
| |
| to |
| |
| if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) |
| { |
| .... |
| } |
| |
| The necessary conditional test defines a variable that holds a known good |
| pointer to the specific item and avoids subsequent conversion calls and |
| the assertion checks that may come with them. |
| |
| When, the property test is embedded within a larger condition, the |
| variable declaration gets pulled out of the condition. (This approach |
| leaves some room for using the variable inappropriately.) |
| |
| if (symtab_variable_p (node) && varpool (node)->finalized) |
| varpool_analyze_node (varpool (node)); |
| |
| becomes |
| |
| varpool_node *vnode = dyn_cast <varpool_node *> (node); |
| if (vnode && vnode->finalized) |
| varpool_analyze_node (vnode); |
| |
| Note that we have converted two sets of assertions in the calls to varpool |
| into safe and efficient use of a variable. |
| |
| TYPE safe_dyn_cast <TYPE> (pointer) |
| |
| Like dyn_cast <TYPE> (pointer), except that it accepts null pointers |
| and returns null results for them. |
| |
| |
| If you use these functions and get a 'inline function not defined' or a |
| 'missing symbol' error message for 'is_a_helper<....>::test', it means that |
| the connection between the types has not been made. See below. |
| |
| |
| EXTENDING THE GENERIC TYPE FACILITY |
| |
| Method 1 |
| -------- |
| |
| If DERIVED is derived from BASE, and if BASE contains enough information |
| to determine whether an object is actually an instance of DERIVED, |
| then you can make the above routines work for DERIVED by defining |
| a specialization of is_a_helper such as: |
| |
| template<> |
| struct is_a_helper<DERIVED *> : static_is_a_helper<DERIVED *> |
| { |
| static inline bool test (const BASE *p) { return ...; } |
| }; |
| |
| This test function should return true if P is an instanced of DERIVED. |
| This on its own is enough; the comments below for method 2 do not apply. |
| |
| Method 2 |
| -------- |
| |
| Alternatively, if two types are connected in ways other than C++ |
| inheritance, each connection between them must be made by defining a |
| specialization of the template member function 'test' of the template |
| class 'is_a_helper'. For example, |
| |
| template <> |
| template <> |
| inline bool |
| is_a_helper <cgraph_node *>::test (symtab_node *p) |
| { |
| return p->type == SYMTAB_FUNCTION; |
| } |
| |
| If a simple reinterpret_cast between the pointer types is incorrect, then you |
| must also specialize the template member function 'cast'. Failure to do so |
| when needed may result in a crash. For example, |
| |
| template <> |
| template <> |
| inline bool |
| is_a_helper <cgraph_node *>::cast (symtab_node *p) |
| { |
| return &p->x_function; |
| } |
| |
| */ |
| |
| #ifndef GCC_IS_A_H |
| #define GCC_IS_A_H |
| |
| /* A base class that specializations of is_a_helper can use if casting |
| U * to T is simply a reinterpret_cast. */ |
| |
| template <typename T> |
| struct reinterpret_is_a_helper |
| { |
| template <typename U> |
| static inline T cast (U *p) { return reinterpret_cast <T> (p); } |
| }; |
| |
| /* A base class that specializations of is_a_helper can use if casting |
| U * to T is simply a static_cast. This is more type-safe than |
| reinterpret_is_a_helper. */ |
| |
| template <typename T> |
| struct static_is_a_helper |
| { |
| template <typename U> |
| static inline T cast (U *p) { return static_cast <T> (p); } |
| }; |
| |
| /* A generic type conversion internal helper class. */ |
| |
| template <typename T> |
| struct is_a_helper : reinterpret_is_a_helper<T> |
| { |
| template <typename U> |
| static inline bool test (U *p); |
| }; |
| |
| /* Reuse the definition of is_a_helper<T *> to implement |
| is_a_helper<const T *>. */ |
| |
| template <typename T> |
| struct is_a_helper<const T *> |
| { |
| template <typename U> |
| static inline const T *cast (const U *p) |
| { |
| return is_a_helper<T *>::cast (const_cast <U *> (p)); |
| } |
| template <typename U> |
| static inline bool test (const U *p) |
| { |
| return is_a_helper<T *>::test (p); |
| } |
| }; |
| |
| /* Note that we deliberately do not define the 'test' member template. Not |
| doing so will result in a build-time error for type relationships that have |
| not been defined, rather than a run-time error. See the discussion above |
| for when to define this member. */ |
| |
| /* The public interface. */ |
| |
| /* A generic test for a type relationship. See the discussion above for when |
| to use this function. The question answered is "Is type T a derived type of |
| type U?". */ |
| |
| template <typename T, typename U> |
| inline bool |
| is_a (U *p) |
| { |
| return is_a_helper<T>::test (p); |
| } |
| |
| /* A generic conversion from a base type U to a derived type T. See the |
| discussion above for when to use this function. */ |
| |
| template <typename T, typename U> |
| inline T |
| as_a (U *p) |
| { |
| gcc_checking_assert (is_a <T> (p)); |
| return is_a_helper <T>::cast (p); |
| } |
| |
| /* Similar to as_a<>, but where the pointer can be NULL, even if |
| is_a_helper<T> doesn't check for NULL. */ |
| |
| template <typename T, typename U> |
| inline T |
| safe_as_a (U *p) |
| { |
| if (p) |
| { |
| gcc_checking_assert (is_a <T> (p)); |
| return is_a_helper <T>::cast (p); |
| } |
| else |
| return NULL; |
| } |
| |
| /* A generic checked conversion from a base type U to a derived type T. See |
| the discussion above for when to use this function. */ |
| |
| template <typename T, typename U> |
| inline T |
| dyn_cast (U *p) |
| { |
| if (is_a <T> (p)) |
| return is_a_helper <T>::cast (p); |
| else |
| return static_cast <T> (0); |
| } |
| |
| /* Similar to dyn_cast, except that the pointer may be null. */ |
| |
| template <typename T, typename U> |
| inline T |
| safe_dyn_cast (U *p) |
| { |
| return p ? dyn_cast <T> (p) : 0; |
| } |
| |
| #endif /* GCC_IS_A_H */ |