]>
Commit | Line | Data |
---|---|---|
5d59b5e1 | 1 | /* Dynamic testing for abstract is-a relationships. |
7adcbafe | 2 | Copyright (C) 2012-2022 Free Software Foundation, Inc. |
5d59b5e1 LC |
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 | ||
5e20cdc9 | 34 | Suppose you have a symtab_node *ptr, AKA symtab_node *ptr. You can test |
5d59b5e1 LC |
35 | whether it points to a 'derived' cgraph_node as follows. |
36 | ||
7de90a6c | 37 | if (is_a <cgraph_node *> (ptr)) |
5d59b5e1 LC |
38 | .... |
39 | ||
40 | ||
7de90a6c | 41 | TYPE as_a <TYPE> (pointer) |
5d59b5e1 | 42 | |
7de90a6c | 43 | Converts pointer to a TYPE. |
5d59b5e1 LC |
44 | |
45 | You can just assume that it is such a node. | |
46 | ||
7de90a6c | 47 | do_something_with (as_a <cgraph_node *> *ptr); |
5d59b5e1 | 48 | |
26b3538b DM |
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 | ||
7de90a6c | 57 | TYPE dyn_cast <TYPE> (pointer) |
5d59b5e1 | 58 | |
7de90a6c | 59 | Converts pointer to TYPE if and only if "is_a <TYPE> pointer". Otherwise, |
5d59b5e1 LC |
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 | ||
7de90a6c | 68 | if (cgraph_node *cptr = dyn_cast <cgraph_node *> (ptr)) |
5d59b5e1 LC |
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 | ||
7de90a6c | 81 | if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) |
5d59b5e1 LC |
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 | ||
7de90a6c | 99 | varpool_node *vnode = dyn_cast <varpool_node *> (node); |
5d59b5e1 LC |
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 | ||
d305ca88 RS |
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 | ||
5d59b5e1 LC |
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 | ||
1498b1a8 RS |
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, | |
5d59b5e1 LC |
143 | |
144 | template <> | |
145 | template <> | |
146 | inline bool | |
7de90a6c | 147 | is_a_helper <cgraph_node *>::test (symtab_node *p) |
5d59b5e1 | 148 | { |
67348ccc | 149 | return p->type == SYMTAB_FUNCTION; |
5d59b5e1 LC |
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 | |
7de90a6c | 159 | is_a_helper <cgraph_node *>::cast (symtab_node *p) |
5d59b5e1 LC |
160 | { |
161 | return &p->x_function; | |
162 | } | |
163 | ||
164 | */ | |
165 | ||
166 | #ifndef GCC_IS_A_H | |
167 | #define GCC_IS_A_H | |
168 | ||
1498b1a8 RS |
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 | ||
5d59b5e1 LC |
190 | /* A generic type conversion internal helper class. */ |
191 | ||
192 | template <typename T> | |
1498b1a8 | 193 | struct is_a_helper : reinterpret_is_a_helper<T> |
5d59b5e1 LC |
194 | { |
195 | template <typename U> | |
196 | static inline bool test (U *p); | |
1498b1a8 RS |
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 | } | |
5d59b5e1 | 210 | template <typename U> |
1498b1a8 RS |
211 | static inline bool test (const U *p) |
212 | { | |
213 | return is_a_helper<T *>::test (p); | |
214 | } | |
5d59b5e1 LC |
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 | ||
5d59b5e1 LC |
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 | /* A generic conversion from a base type U to a derived type T. See the | |
236 | discussion above for when to use this function. */ | |
237 | ||
238 | template <typename T, typename U> | |
7de90a6c | 239 | inline T |
5d59b5e1 LC |
240 | as_a (U *p) |
241 | { | |
f046e81b | 242 | gcc_checking_assert (is_a <T> (p)); |
5d59b5e1 LC |
243 | return is_a_helper <T>::cast (p); |
244 | } | |
245 | ||
26b3538b DM |
246 | /* Similar to as_a<>, but where the pointer can be NULL, even if |
247 | is_a_helper<T> doesn't check for NULL. */ | |
248 | ||
249 | template <typename T, typename U> | |
250 | inline T | |
251 | safe_as_a (U *p) | |
252 | { | |
253 | if (p) | |
254 | { | |
255 | gcc_checking_assert (is_a <T> (p)); | |
256 | return is_a_helper <T>::cast (p); | |
257 | } | |
258 | else | |
259 | return NULL; | |
260 | } | |
261 | ||
5d59b5e1 LC |
262 | /* A generic checked conversion from a base type U to a derived type T. See |
263 | the discussion above for when to use this function. */ | |
264 | ||
265 | template <typename T, typename U> | |
7de90a6c | 266 | inline T |
5d59b5e1 LC |
267 | dyn_cast (U *p) |
268 | { | |
269 | if (is_a <T> (p)) | |
270 | return is_a_helper <T>::cast (p); | |
271 | else | |
7de90a6c | 272 | return static_cast <T> (0); |
5d59b5e1 LC |
273 | } |
274 | ||
d305ca88 RS |
275 | /* Similar to dyn_cast, except that the pointer may be null. */ |
276 | ||
277 | template <typename T, typename U> | |
278 | inline T | |
279 | safe_dyn_cast (U *p) | |
280 | { | |
281 | return p ? dyn_cast <T> (p) : 0; | |
282 | } | |
283 | ||
5d59b5e1 | 284 | #endif /* GCC_IS_A_H */ |