]>
Commit | Line | Data |
---|---|---|
5d59b5e1 | 1 | /* Dynamic testing for abstract is-a relationships. |
cbe34bb5 | 2 | Copyright (C) 2012-2017 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 | ||
119 | Each connection between types must be made by defining a specialization of the | |
120 | template member function 'test' of the template class 'is_a_helper'. For | |
121 | example, | |
122 | ||
123 | template <> | |
124 | template <> | |
125 | inline bool | |
7de90a6c | 126 | is_a_helper <cgraph_node *>::test (symtab_node *p) |
5d59b5e1 | 127 | { |
67348ccc | 128 | return p->type == SYMTAB_FUNCTION; |
5d59b5e1 LC |
129 | } |
130 | ||
131 | If a simple reinterpret_cast between the pointer types is incorrect, then you | |
132 | must also specialize the template member function 'cast'. Failure to do so | |
133 | when needed may result in a crash. For example, | |
134 | ||
135 | template <> | |
136 | template <> | |
137 | inline bool | |
7de90a6c | 138 | is_a_helper <cgraph_node *>::cast (symtab_node *p) |
5d59b5e1 LC |
139 | { |
140 | return &p->x_function; | |
141 | } | |
142 | ||
143 | */ | |
144 | ||
145 | #ifndef GCC_IS_A_H | |
146 | #define GCC_IS_A_H | |
147 | ||
148 | /* A generic type conversion internal helper class. */ | |
149 | ||
150 | template <typename T> | |
151 | struct is_a_helper | |
152 | { | |
153 | template <typename U> | |
154 | static inline bool test (U *p); | |
155 | template <typename U> | |
7de90a6c | 156 | static inline T cast (U *p); |
5d59b5e1 LC |
157 | }; |
158 | ||
159 | /* Note that we deliberately do not define the 'test' member template. Not | |
160 | doing so will result in a build-time error for type relationships that have | |
161 | not been defined, rather than a run-time error. See the discussion above | |
162 | for when to define this member. */ | |
163 | ||
164 | /* This is the generic implementation for casting from one type to another. | |
165 | Do not use this routine directly; it is an internal function. See the | |
166 | discussion above for when to define this member. */ | |
167 | ||
168 | template <typename T> | |
169 | template <typename U> | |
7de90a6c | 170 | inline T |
5d59b5e1 LC |
171 | is_a_helper <T>::cast (U *p) |
172 | { | |
7de90a6c | 173 | return reinterpret_cast <T> (p); |
5d59b5e1 LC |
174 | } |
175 | ||
176 | ||
177 | /* The public interface. */ | |
178 | ||
179 | /* A generic test for a type relationship. See the discussion above for when | |
180 | to use this function. The question answered is "Is type T a derived type of | |
181 | type U?". */ | |
182 | ||
183 | template <typename T, typename U> | |
184 | inline bool | |
185 | is_a (U *p) | |
186 | { | |
187 | return is_a_helper<T>::test (p); | |
188 | } | |
189 | ||
190 | /* A generic conversion from a base type U to a derived type T. See the | |
191 | discussion above for when to use this function. */ | |
192 | ||
193 | template <typename T, typename U> | |
7de90a6c | 194 | inline T |
5d59b5e1 LC |
195 | as_a (U *p) |
196 | { | |
f046e81b | 197 | gcc_checking_assert (is_a <T> (p)); |
5d59b5e1 LC |
198 | return is_a_helper <T>::cast (p); |
199 | } | |
200 | ||
26b3538b DM |
201 | /* Similar to as_a<>, but where the pointer can be NULL, even if |
202 | is_a_helper<T> doesn't check for NULL. */ | |
203 | ||
204 | template <typename T, typename U> | |
205 | inline T | |
206 | safe_as_a (U *p) | |
207 | { | |
208 | if (p) | |
209 | { | |
210 | gcc_checking_assert (is_a <T> (p)); | |
211 | return is_a_helper <T>::cast (p); | |
212 | } | |
213 | else | |
214 | return NULL; | |
215 | } | |
216 | ||
5d59b5e1 LC |
217 | /* A generic checked conversion from a base type U to a derived type T. See |
218 | the discussion above for when to use this function. */ | |
219 | ||
220 | template <typename T, typename U> | |
7de90a6c | 221 | inline T |
5d59b5e1 LC |
222 | dyn_cast (U *p) |
223 | { | |
224 | if (is_a <T> (p)) | |
225 | return is_a_helper <T>::cast (p); | |
226 | else | |
7de90a6c | 227 | return static_cast <T> (0); |
5d59b5e1 LC |
228 | } |
229 | ||
d305ca88 RS |
230 | /* Similar to dyn_cast, except that the pointer may be null. */ |
231 | ||
232 | template <typename T, typename U> | |
233 | inline T | |
234 | safe_dyn_cast (U *p) | |
235 | { | |
236 | return p ? dyn_cast <T> (p) : 0; | |
237 | } | |
238 | ||
5d59b5e1 | 239 | #endif /* GCC_IS_A_H */ |