1 /* Dynamic testing for abstract is-a relationships. 2 Copyright (C) 2012-2013 Free Software Foundation, Inc. 3 Contributed by Lawrence Crowl. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 22 /* This header generic type query and conversion functions. 23 24 25 USING THE GENERIC TYPE FACILITY 26 27 28 The user functions are: 29 30 bool is_a <TYPE> (pointer) 31 32 Tests whether the pointer actually points to a more derived TYPE. 33 34 Suppose you have a symtab_node_def *ptr, AKA symtab_node ptr. You can test 35 whether it points to a 'derived' cgraph_node as follows. 36 37 if (is_a <cgraph_node> (ptr)) 38 .... 39 40 41 TYPE *as_a <TYPE> (pointer) 42 43 Converts pointer to a TYPE*. 44 45 You can just assume that it is such a node. 46 47 do_something_with (as_a <cgraph_node> *ptr); 48 49 TYPE *dyn_cast <TYPE> (pointer) 50 51 Converts pointer to TYPE* if and only if "is_a <TYPE> pointer". Otherwise, 52 returns NULL. This function is essentially a checked down cast. 53 54 This functions reduce compile time and increase type safety when treating a 55 generic item as a more specific item. 56 57 You can test and obtain a pointer to the 'derived' type in one indivisible 58 operation. 59 60 if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr)) 61 .... 62 63 As an example, the code change is from 64 65 if (symtab_function_p (node)) 66 { 67 struct cgraph_node *cnode = cgraph (node); 68 .... 69 } 70 71 to 72 73 if (cgraph_node *cnode = dyn_cast <cgraph_node> (node)) 74 { 75 .... 76 } 77 78 The necessary conditional test defines a variable that holds a known good 79 pointer to the specific item and avoids subsequent conversion calls and 80 the assertion checks that may come with them. 81 82 When, the property test is embedded within a larger condition, the 83 variable declaration gets pulled out of the condition. (This approach 84 leaves some room for using the variable inappropriately.) 85 86 if (symtab_variable_p (node) && varpool (node)->finalized) 87 varpool_analyze_node (varpool (node)); 88 89 becomes 90 91 varpool_node *vnode = dyn_cast <varpool_node> (node); 92 if (vnode && vnode->finalized) 93 varpool_analyze_node (vnode); 94 95 Note that we have converted two sets of assertions in the calls to varpool 96 into safe and efficient use of a variable. 97 98 99 If you use these functions and get a 'inline function not defined' or a 100 'missing symbol' error message for 'is_a_helper<....>::test', it means that 101 the connection between the types has not been made. See below. 102 103 104 EXTENDING THE GENERIC TYPE FACILITY 105 106 Each connection between types must be made by defining a specialization of the 107 template member function 'test' of the template class 'is_a_helper'. For 108 example, 109 110 template <> 111 template <> 112 inline bool 113 is_a_helper <cgraph_node>::test (symtab_node_def *p) 114 { 115 return p->symbol.type == SYMTAB_FUNCTION; 116 } 117 118 If a simple reinterpret_cast between the pointer types is incorrect, then you 119 must also specialize the template member function 'cast'. Failure to do so 120 when needed may result in a crash. For example, 121 122 template <> 123 template <> 124 inline bool 125 is_a_helper <cgraph_node>::cast (symtab_node_def *p) 126 { 127 return &p->x_function; 128 } 129 130 */ 131 132 #ifndef GCC_IS_A_H 133 #define GCC_IS_A_H 134 135 /* A generic type conversion internal helper class. */ 136 137 template <typename T> 138 struct is_a_helper 139 { 140 template <typename U> 141 static inline bool test (U *p); 142 template <typename U> 143 static inline T *cast (U *p); 144 }; 145 146 /* Note that we deliberately do not define the 'test' member template. Not 147 doing so will result in a build-time error for type relationships that have 148 not been defined, rather than a run-time error. See the discussion above 149 for when to define this member. */ 150 151 /* This is the generic implementation for casting from one type to another. 152 Do not use this routine directly; it is an internal function. See the 153 discussion above for when to define this member. */ 154 155 template <typename T> 156 template <typename U> 157 inline T * 158 is_a_helper <T>::cast (U *p) 159 { 160 return reinterpret_cast <T *> (p); 161 } 162 163 164 /* The public interface. */ 165 166 /* A generic test for a type relationship. See the discussion above for when 167 to use this function. The question answered is "Is type T a derived type of 168 type U?". */ 169 170 template <typename T, typename U> 171 inline bool 172 is_a (U *p) 173 { 174 return is_a_helper<T>::test (p); 175 } 176 177 /* A generic conversion from a base type U to a derived type T. See the 178 discussion above for when to use this function. */ 179 180 template <typename T, typename U> 181 inline T * 182 as_a (U *p) 183 { 184 gcc_assert (is_a <T> (p)); 185 return is_a_helper <T>::cast (p); 186 } 187 188 /* A generic checked conversion from a base type U to a derived type T. See 189 the discussion above for when to use this function. */ 190 191 template <typename T, typename U> 192 inline T * 193 dyn_cast (U *p) 194 { 195 if (is_a <T> (p)) 196 return is_a_helper <T>::cast (p); 197 else 198 return static_cast <T *> (0); 199 } 200 201 #endif /* GCC_IS_A_H */ 202