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