xref: /dragonfly/contrib/gcc-8.0/gcc/is-a.h (revision 38fd1498)
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