1*38fd1498Szrj /* Dynamic testing for abstract is-a relationships.
2*38fd1498Szrj Copyright (C) 2012-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Lawrence Crowl.
4*38fd1498Szrj
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
8*38fd1498Szrj the terms of the GNU General Public License as published by the Free
9*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
10*38fd1498Szrj version.
11*38fd1498Szrj
12*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15*38fd1498Szrj for more details.
16*38fd1498Szrj
17*38fd1498Szrj You should have received a copy of the GNU General Public License
18*38fd1498Szrj along with GCC; see the file COPYING3. If not see
19*38fd1498Szrj <http://www.gnu.org/licenses/>. */
20*38fd1498Szrj
21*38fd1498Szrj
22*38fd1498Szrj /* This header generic type query and conversion functions.
23*38fd1498Szrj
24*38fd1498Szrj
25*38fd1498Szrj USING THE GENERIC TYPE FACILITY
26*38fd1498Szrj
27*38fd1498Szrj
28*38fd1498Szrj The user functions are:
29*38fd1498Szrj
30*38fd1498Szrj bool is_a <TYPE> (pointer)
31*38fd1498Szrj
32*38fd1498Szrj Tests whether the pointer actually points to a more derived TYPE.
33*38fd1498Szrj
34*38fd1498Szrj Suppose you have a symtab_node *ptr, AKA symtab_node *ptr. You can test
35*38fd1498Szrj whether it points to a 'derived' cgraph_node as follows.
36*38fd1498Szrj
37*38fd1498Szrj if (is_a <cgraph_node *> (ptr))
38*38fd1498Szrj ....
39*38fd1498Szrj
40*38fd1498Szrj
41*38fd1498Szrj TYPE as_a <TYPE> (pointer)
42*38fd1498Szrj
43*38fd1498Szrj Converts pointer to a TYPE.
44*38fd1498Szrj
45*38fd1498Szrj You can just assume that it is such a node.
46*38fd1498Szrj
47*38fd1498Szrj do_something_with (as_a <cgraph_node *> *ptr);
48*38fd1498Szrj
49*38fd1498Szrj TYPE safe_as_a <TYPE> (pointer)
50*38fd1498Szrj
51*38fd1498Szrj Like as_a <TYPE> (pointer), but where pointer could be NULL. This
52*38fd1498Szrj adds a check against NULL where the regular is_a_helper hook for TYPE
53*38fd1498Szrj assumes non-NULL.
54*38fd1498Szrj
55*38fd1498Szrj do_something_with (safe_as_a <cgraph_node *> *ptr);
56*38fd1498Szrj
57*38fd1498Szrj TYPE dyn_cast <TYPE> (pointer)
58*38fd1498Szrj
59*38fd1498Szrj Converts pointer to TYPE if and only if "is_a <TYPE> pointer". Otherwise,
60*38fd1498Szrj returns NULL. This function is essentially a checked down cast.
61*38fd1498Szrj
62*38fd1498Szrj This functions reduce compile time and increase type safety when treating a
63*38fd1498Szrj generic item as a more specific item.
64*38fd1498Szrj
65*38fd1498Szrj You can test and obtain a pointer to the 'derived' type in one indivisible
66*38fd1498Szrj operation.
67*38fd1498Szrj
68*38fd1498Szrj if (cgraph_node *cptr = dyn_cast <cgraph_node *> (ptr))
69*38fd1498Szrj ....
70*38fd1498Szrj
71*38fd1498Szrj As an example, the code change is from
72*38fd1498Szrj
73*38fd1498Szrj if (symtab_function_p (node))
74*38fd1498Szrj {
75*38fd1498Szrj struct cgraph_node *cnode = cgraph (node);
76*38fd1498Szrj ....
77*38fd1498Szrj }
78*38fd1498Szrj
79*38fd1498Szrj to
80*38fd1498Szrj
81*38fd1498Szrj if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node))
82*38fd1498Szrj {
83*38fd1498Szrj ....
84*38fd1498Szrj }
85*38fd1498Szrj
86*38fd1498Szrj The necessary conditional test defines a variable that holds a known good
87*38fd1498Szrj pointer to the specific item and avoids subsequent conversion calls and
88*38fd1498Szrj the assertion checks that may come with them.
89*38fd1498Szrj
90*38fd1498Szrj When, the property test is embedded within a larger condition, the
91*38fd1498Szrj variable declaration gets pulled out of the condition. (This approach
92*38fd1498Szrj leaves some room for using the variable inappropriately.)
93*38fd1498Szrj
94*38fd1498Szrj if (symtab_variable_p (node) && varpool (node)->finalized)
95*38fd1498Szrj varpool_analyze_node (varpool (node));
96*38fd1498Szrj
97*38fd1498Szrj becomes
98*38fd1498Szrj
99*38fd1498Szrj varpool_node *vnode = dyn_cast <varpool_node *> (node);
100*38fd1498Szrj if (vnode && vnode->finalized)
101*38fd1498Szrj varpool_analyze_node (vnode);
102*38fd1498Szrj
103*38fd1498Szrj Note that we have converted two sets of assertions in the calls to varpool
104*38fd1498Szrj into safe and efficient use of a variable.
105*38fd1498Szrj
106*38fd1498Szrj TYPE safe_dyn_cast <TYPE> (pointer)
107*38fd1498Szrj
108*38fd1498Szrj Like dyn_cast <TYPE> (pointer), except that it accepts null pointers
109*38fd1498Szrj and returns null results for them.
110*38fd1498Szrj
111*38fd1498Szrj
112*38fd1498Szrj If you use these functions and get a 'inline function not defined' or a
113*38fd1498Szrj 'missing symbol' error message for 'is_a_helper<....>::test', it means that
114*38fd1498Szrj the connection between the types has not been made. See below.
115*38fd1498Szrj
116*38fd1498Szrj
117*38fd1498Szrj EXTENDING THE GENERIC TYPE FACILITY
118*38fd1498Szrj
119*38fd1498Szrj Each connection between types must be made by defining a specialization of the
120*38fd1498Szrj template member function 'test' of the template class 'is_a_helper'. For
121*38fd1498Szrj example,
122*38fd1498Szrj
123*38fd1498Szrj template <>
124*38fd1498Szrj template <>
125*38fd1498Szrj inline bool
126*38fd1498Szrj is_a_helper <cgraph_node *>::test (symtab_node *p)
127*38fd1498Szrj {
128*38fd1498Szrj return p->type == SYMTAB_FUNCTION;
129*38fd1498Szrj }
130*38fd1498Szrj
131*38fd1498Szrj If a simple reinterpret_cast between the pointer types is incorrect, then you
132*38fd1498Szrj must also specialize the template member function 'cast'. Failure to do so
133*38fd1498Szrj when needed may result in a crash. For example,
134*38fd1498Szrj
135*38fd1498Szrj template <>
136*38fd1498Szrj template <>
137*38fd1498Szrj inline bool
138*38fd1498Szrj is_a_helper <cgraph_node *>::cast (symtab_node *p)
139*38fd1498Szrj {
140*38fd1498Szrj return &p->x_function;
141*38fd1498Szrj }
142*38fd1498Szrj
143*38fd1498Szrj */
144*38fd1498Szrj
145*38fd1498Szrj #ifndef GCC_IS_A_H
146*38fd1498Szrj #define GCC_IS_A_H
147*38fd1498Szrj
148*38fd1498Szrj /* A generic type conversion internal helper class. */
149*38fd1498Szrj
150*38fd1498Szrj template <typename T>
151*38fd1498Szrj struct is_a_helper
152*38fd1498Szrj {
153*38fd1498Szrj template <typename U>
154*38fd1498Szrj static inline bool test (U *p);
155*38fd1498Szrj template <typename U>
156*38fd1498Szrj static inline T cast (U *p);
157*38fd1498Szrj };
158*38fd1498Szrj
159*38fd1498Szrj /* Note that we deliberately do not define the 'test' member template. Not
160*38fd1498Szrj doing so will result in a build-time error for type relationships that have
161*38fd1498Szrj not been defined, rather than a run-time error. See the discussion above
162*38fd1498Szrj for when to define this member. */
163*38fd1498Szrj
164*38fd1498Szrj /* This is the generic implementation for casting from one type to another.
165*38fd1498Szrj Do not use this routine directly; it is an internal function. See the
166*38fd1498Szrj discussion above for when to define this member. */
167*38fd1498Szrj
168*38fd1498Szrj template <typename T>
169*38fd1498Szrj template <typename U>
170*38fd1498Szrj inline T
cast(U * p)171*38fd1498Szrj is_a_helper <T>::cast (U *p)
172*38fd1498Szrj {
173*38fd1498Szrj return reinterpret_cast <T> (p);
174*38fd1498Szrj }
175*38fd1498Szrj
176*38fd1498Szrj
177*38fd1498Szrj /* The public interface. */
178*38fd1498Szrj
179*38fd1498Szrj /* A generic test for a type relationship. See the discussion above for when
180*38fd1498Szrj to use this function. The question answered is "Is type T a derived type of
181*38fd1498Szrj type U?". */
182*38fd1498Szrj
183*38fd1498Szrj template <typename T, typename U>
184*38fd1498Szrj inline bool
is_a(U * p)185*38fd1498Szrj is_a (U *p)
186*38fd1498Szrj {
187*38fd1498Szrj return is_a_helper<T>::test (p);
188*38fd1498Szrj }
189*38fd1498Szrj
190*38fd1498Szrj /* A generic conversion from a base type U to a derived type T. See the
191*38fd1498Szrj discussion above for when to use this function. */
192*38fd1498Szrj
193*38fd1498Szrj template <typename T, typename U>
194*38fd1498Szrj inline T
as_a(U * p)195*38fd1498Szrj as_a (U *p)
196*38fd1498Szrj {
197*38fd1498Szrj gcc_checking_assert (is_a <T> (p));
198*38fd1498Szrj return is_a_helper <T>::cast (p);
199*38fd1498Szrj }
200*38fd1498Szrj
201*38fd1498Szrj /* Similar to as_a<>, but where the pointer can be NULL, even if
202*38fd1498Szrj is_a_helper<T> doesn't check for NULL. */
203*38fd1498Szrj
204*38fd1498Szrj template <typename T, typename U>
205*38fd1498Szrj inline T
safe_as_a(U * p)206*38fd1498Szrj safe_as_a (U *p)
207*38fd1498Szrj {
208*38fd1498Szrj if (p)
209*38fd1498Szrj {
210*38fd1498Szrj gcc_checking_assert (is_a <T> (p));
211*38fd1498Szrj return is_a_helper <T>::cast (p);
212*38fd1498Szrj }
213*38fd1498Szrj else
214*38fd1498Szrj return NULL;
215*38fd1498Szrj }
216*38fd1498Szrj
217*38fd1498Szrj /* A generic checked conversion from a base type U to a derived type T. See
218*38fd1498Szrj the discussion above for when to use this function. */
219*38fd1498Szrj
220*38fd1498Szrj template <typename T, typename U>
221*38fd1498Szrj inline T
dyn_cast(U * p)222*38fd1498Szrj dyn_cast (U *p)
223*38fd1498Szrj {
224*38fd1498Szrj if (is_a <T> (p))
225*38fd1498Szrj return is_a_helper <T>::cast (p);
226*38fd1498Szrj else
227*38fd1498Szrj return static_cast <T> (0);
228*38fd1498Szrj }
229*38fd1498Szrj
230*38fd1498Szrj /* Similar to dyn_cast, except that the pointer may be null. */
231*38fd1498Szrj
232*38fd1498Szrj template <typename T, typename U>
233*38fd1498Szrj inline T
safe_dyn_cast(U * p)234*38fd1498Szrj safe_dyn_cast (U *p)
235*38fd1498Szrj {
236*38fd1498Szrj return p ? dyn_cast <T> (p) : 0;
237*38fd1498Szrj }
238*38fd1498Szrj
239*38fd1498Szrj #endif /* GCC_IS_A_H */
240