Branch data Line data Source code
1 : : /* Dynamic testing for abstract is-a relationships.
2 : : Copyright (C) 2012-2025 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 *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 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 : :
57 : : TYPE 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 : : TYPE safe_dyn_cast <TYPE> (pointer)
107 : :
108 : : Like dyn_cast <TYPE> (pointer), except that it accepts null pointers
109 : : and returns null results for them.
110 : :
111 : :
112 : : If you use these functions and get a 'inline function not defined' or a
113 : : 'missing symbol' error message for 'is_a_helper<....>::test', it means that
114 : : the connection between the types has not been made. See below.
115 : :
116 : :
117 : : EXTENDING THE GENERIC TYPE FACILITY
118 : :
119 : : Method 1
120 : : --------
121 : :
122 : : If DERIVED is derived from BASE, and if BASE contains enough information
123 : : to determine whether an object is actually an instance of DERIVED,
124 : : then you can make the above routines work for DERIVED by defining
125 : : a specialization of is_a_helper such as:
126 : :
127 : : template<>
128 : : struct is_a_helper<DERIVED *> : static_is_a_helper<DERIVED *>
129 : : {
130 : : static inline bool test (const BASE *p) { return ...; }
131 : : };
132 : :
133 : : This test function should return true if P is an instanced of DERIVED.
134 : : This on its own is enough; the comments below for method 2 do not apply.
135 : :
136 : : Method 2
137 : : --------
138 : :
139 : : Alternatively, if two types are connected in ways other than C++
140 : : inheritance, each connection between them must be made by defining a
141 : : specialization of the template member function 'test' of the template
142 : : class 'is_a_helper'. For example,
143 : :
144 : : template <>
145 : : template <>
146 : : inline bool
147 : : is_a_helper <cgraph_node *>::test (symtab_node *p)
148 : : {
149 : : return p->type == SYMTAB_FUNCTION;
150 : : }
151 : :
152 : : If a simple reinterpret_cast between the pointer types is incorrect, then you
153 : : must also specialize the template member function 'cast'. Failure to do so
154 : : when needed may result in a crash. For example,
155 : :
156 : : template <>
157 : : template <>
158 : : inline bool
159 : : is_a_helper <cgraph_node *>::cast (symtab_node *p)
160 : : {
161 : : return &p->x_function;
162 : : }
163 : :
164 : : */
165 : :
166 : : #ifndef GCC_IS_A_H
167 : : #define GCC_IS_A_H
168 : :
169 : : /* A base class that specializations of is_a_helper can use if casting
170 : : U * to T is simply a reinterpret_cast. */
171 : :
172 : : template <typename T>
173 : : struct reinterpret_is_a_helper
174 : : {
175 : : template <typename U>
176 : : static inline T cast (U *p) { return reinterpret_cast <T> (p); }
177 : : };
178 : :
179 : : /* A base class that specializations of is_a_helper can use if casting
180 : : U * to T is simply a static_cast. This is more type-safe than
181 : : reinterpret_is_a_helper. */
182 : :
183 : : template <typename T>
184 : : struct static_is_a_helper
185 : : {
186 : : template <typename U>
187 : : static inline T cast (U *p) { return static_cast <T> (p); }
188 : : };
189 : :
190 : : /* A generic type conversion internal helper class. */
191 : :
192 : : template <typename T>
193 : : struct is_a_helper : reinterpret_is_a_helper<T>
194 : : {
195 : : template <typename U>
196 : : static inline bool test (U *p);
197 : : };
198 : :
199 : : /* Reuse the definition of is_a_helper<T *> to implement
200 : : is_a_helper<const T *>. */
201 : :
202 : : template <typename T>
203 : : struct is_a_helper<const T *>
204 : : {
205 : : template <typename U>
206 : : static inline const T *cast (const U *p)
207 : : {
208 : : return is_a_helper<T *>::cast (const_cast <U *> (p));
209 : : }
210 : : template <typename U>
211 : 419674910 : static inline bool test (const U *p)
212 : : {
213 : 419674910 : return is_a_helper<T *>::test (p);
214 : : }
215 : : };
216 : :
217 : : /* Note that we deliberately do not define the 'test' member template. Not
218 : : doing so will result in a build-time error for type relationships that have
219 : : not been defined, rather than a run-time error. See the discussion above
220 : : for when to define this member. */
221 : :
222 : : /* The public interface. */
223 : :
224 : : /* A generic test for a type relationship. See the discussion above for when
225 : : to use this function. The question answered is "Is type T a derived type of
226 : : type U?". */
227 : :
228 : : template <typename T, typename U>
229 : : inline bool
230 : >24831*10^7 : is_a (U *p)
231 : : {
232 : >45108*10^7 : return is_a_helper<T>::test (p);
233 : : }
234 : :
235 : : /* Similar to is_a<>, but where the pointer can be NULL, even if
236 : : is_a_helper<T> doesn't check for NULL. */
237 : :
238 : : template <typename T, typename U>
239 : : inline bool
240 : 188066036 : safe_is_a (U *p)
241 : : {
242 : 143079515 : if (p)
243 : 95406280 : return is_a_helper <T>::test (p);
244 : : else
245 : : return false;
246 : : }
247 : :
248 : : /* A generic conversion from a base type U to a derived type T. See the
249 : : discussion above for when to use this function. */
250 : :
251 : : template <typename T, typename U>
252 : : inline T
253 : 35901931423 : as_a (U *p)
254 : : {
255 : 35833822349 : gcc_checking_assert (is_a <T> (p));
256 : 35901931423 : return is_a_helper <T>::cast (p);
257 : : }
258 : :
259 : : /* Similar to as_a<>, but where the pointer can be NULL, even if
260 : : is_a_helper<T> doesn't check for NULL. */
261 : :
262 : : template <typename T, typename U>
263 : : inline T
264 : >16449*10^7 : safe_as_a (U *p)
265 : : {
266 : >16449*10^7 : if (p)
267 : : {
268 : >15951*10^7 : gcc_checking_assert (is_a <T> (p));
269 : : return is_a_helper <T>::cast (p);
270 : : }
271 : : else
272 : : return NULL;
273 : : }
274 : :
275 : : /* A generic checked conversion from a base type U to a derived type T. See
276 : : the discussion above for when to use this function. */
277 : :
278 : : template <typename T, typename U>
279 : : inline T
280 : >24507*10^7 : dyn_cast (U *p)
281 : : {
282 : >28204*10^7 : if (is_a <T> (p))
283 : : return is_a_helper <T>::cast (p);
284 : : else
285 : 944536287 : return static_cast <T> (0);
286 : : }
287 : :
288 : : /* Similar to dyn_cast, except that the pointer may be null. */
289 : :
290 : : template <typename T, typename U>
291 : : inline T
292 : 1229439936 : safe_dyn_cast (U *p)
293 : : {
294 : 3686723883 : return p ? dyn_cast <T> (p) : 0;
295 : : }
296 : :
297 : : #endif /* GCC_IS_A_H */
|