111
|
1 /* Dynamic testing for abstract is-a relationships.
|
145
|
2 Copyright (C) 2012-2020 Free Software Foundation, Inc.
|
111
|
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 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
|
|
126 is_a_helper <cgraph_node *>::test (symtab_node *p)
|
|
127 {
|
|
128 return p->type == SYMTAB_FUNCTION;
|
|
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
|
|
138 is_a_helper <cgraph_node *>::cast (symtab_node *p)
|
|
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>
|
|
156 static inline T cast (U *p);
|
|
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>
|
|
170 inline T
|
|
171 is_a_helper <T>::cast (U *p)
|
|
172 {
|
|
173 return reinterpret_cast <T> (p);
|
|
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>
|
|
194 inline T
|
|
195 as_a (U *p)
|
|
196 {
|
|
197 gcc_checking_assert (is_a <T> (p));
|
|
198 return is_a_helper <T>::cast (p);
|
|
199 }
|
|
200
|
|
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
|
|
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>
|
|
221 inline T
|
|
222 dyn_cast (U *p)
|
|
223 {
|
|
224 if (is_a <T> (p))
|
|
225 return is_a_helper <T>::cast (p);
|
|
226 else
|
|
227 return static_cast <T> (0);
|
|
228 }
|
|
229
|
|
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
|
|
239 #endif /* GCC_IS_A_H */
|