1 | /* Dynamic testing for abstract is-a relationships. |
2 | Copyright (C) 2012-2023 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 | static inline bool test (const U *p) |
212 | { |
213 | 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 | is_a (U *p) |
231 | { |
232 | 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 | safe_is_a (U *p) |
241 | { |
242 | if (p) |
243 | 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 | as_a (U *p) |
254 | { |
255 | gcc_checking_assert (is_a <T> (p)); |
256 | 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 | safe_as_a (U *p) |
265 | { |
266 | if (p) |
267 | { |
268 | 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 | dyn_cast (U *p) |
281 | { |
282 | if (is_a <T> (p)) |
283 | return is_a_helper <T>::cast (p); |
284 | else |
285 | 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 | safe_dyn_cast (U *p) |
293 | { |
294 | return p ? dyn_cast <T> (p) : 0; |
295 | } |
296 | |
297 | #endif /* GCC_IS_A_H */ |
298 | |