xref: /netbsd/external/gpl3/gcc.old/dist/gcc/is-a.h (revision ec02198a)
1 /* Dynamic testing for abstract is-a relationships.
2    Copyright (C) 2012-2020 Free Software Foundation, Inc.
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
cast(U * p)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
is_a(U * p)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
as_a(U * p)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
safe_as_a(U * p)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
dyn_cast(U * p)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
safe_dyn_cast(U * p)234 safe_dyn_cast (U *p)
235 {
236   return p ? dyn_cast <T> (p) : 0;
237 }
238 
239 #endif  /* GCC_IS_A_H  */
240