PR c/56980
[official-gcc.git] / gcc / is-a.h
blob176066b42bcaeb97ddc5c19243f61ccf6cba9b0d
1 /* Dynamic testing for abstract is-a relationships.
2 Copyright (C) 2012-2014 Free Software Foundation, Inc.
3 Contributed by Lawrence Crowl.
5 This file is part of GCC.
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.
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.
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/>. */
22 /* This header generic type query and conversion functions.
25 USING THE GENERIC TYPE FACILITY
28 The user functions are:
30 bool is_a <TYPE> (pointer)
32 Tests whether the pointer actually points to a more derived TYPE.
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.
37 if (is_a <cgraph_node *> (ptr))
38 ....
41 TYPE as_a <TYPE> (pointer)
43 Converts pointer to a TYPE.
45 You can just assume that it is such a node.
47 do_something_with (as_a <cgraph_node *> *ptr);
49 TYPE safe_as_a <TYPE> (pointer)
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.
55 do_something_with (safe_as_a <cgraph_node *> *ptr);
57 TYPE dyn_cast <TYPE> (pointer)
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.
62 This functions reduce compile time and increase type safety when treating a
63 generic item as a more specific item.
65 You can test and obtain a pointer to the 'derived' type in one indivisible
66 operation.
68 if (cgraph_node *cptr = dyn_cast <cgraph_node *> (ptr))
69 ....
71 As an example, the code change is from
73 if (symtab_function_p (node))
75 struct cgraph_node *cnode = cgraph (node);
76 ....
81 if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node))
83 ....
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.
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.)
94 if (symtab_variable_p (node) && varpool (node)->finalized)
95 varpool_analyze_node (varpool (node));
97 becomes
99 varpool_node *vnode = dyn_cast <varpool_node *> (node);
100 if (vnode && vnode->finalized)
101 varpool_analyze_node (vnode);
103 Note that we have converted two sets of assertions in the calls to varpool
104 into safe and efficient use of a variable.
107 If you use these functions and get a 'inline function not defined' or a
108 'missing symbol' error message for 'is_a_helper<....>::test', it means that
109 the connection between the types has not been made. See below.
112 EXTENDING THE GENERIC TYPE FACILITY
114 Each connection between types must be made by defining a specialization of the
115 template member function 'test' of the template class 'is_a_helper'. For
116 example,
118 template <>
119 template <>
120 inline bool
121 is_a_helper <cgraph_node *>::test (symtab_node *p)
123 return p->type == SYMTAB_FUNCTION;
126 If a simple reinterpret_cast between the pointer types is incorrect, then you
127 must also specialize the template member function 'cast'. Failure to do so
128 when needed may result in a crash. For example,
130 template <>
131 template <>
132 inline bool
133 is_a_helper <cgraph_node *>::cast (symtab_node *p)
135 return &p->x_function;
140 #ifndef GCC_IS_A_H
141 #define GCC_IS_A_H
143 /* A generic type conversion internal helper class. */
145 template <typename T>
146 struct is_a_helper
148 template <typename U>
149 static inline bool test (U *p);
150 template <typename U>
151 static inline T cast (U *p);
154 /* Note that we deliberately do not define the 'test' member template. Not
155 doing so will result in a build-time error for type relationships that have
156 not been defined, rather than a run-time error. See the discussion above
157 for when to define this member. */
159 /* This is the generic implementation for casting from one type to another.
160 Do not use this routine directly; it is an internal function. See the
161 discussion above for when to define this member. */
163 template <typename T>
164 template <typename U>
165 inline T
166 is_a_helper <T>::cast (U *p)
168 return reinterpret_cast <T> (p);
172 /* The public interface. */
174 /* A generic test for a type relationship. See the discussion above for when
175 to use this function. The question answered is "Is type T a derived type of
176 type U?". */
178 template <typename T, typename U>
179 inline bool
180 is_a (U *p)
182 return is_a_helper<T>::test (p);
185 /* A generic conversion from a base type U to a derived type T. See the
186 discussion above for when to use this function. */
188 template <typename T, typename U>
189 inline T
190 as_a (U *p)
192 gcc_checking_assert (is_a <T> (p));
193 return is_a_helper <T>::cast (p);
196 /* Similar to as_a<>, but where the pointer can be NULL, even if
197 is_a_helper<T> doesn't check for NULL. */
199 template <typename T, typename U>
200 inline T
201 safe_as_a (U *p)
203 if (p)
205 gcc_checking_assert (is_a <T> (p));
206 return is_a_helper <T>::cast (p);
208 else
209 return NULL;
212 /* A generic checked conversion from a base type U to a derived type T. See
213 the discussion above for when to use this function. */
215 template <typename T, typename U>
216 inline T
217 dyn_cast (U *p)
219 if (is_a <T> (p))
220 return is_a_helper <T>::cast (p);
221 else
222 return static_cast <T> (0);
225 #endif /* GCC_IS_A_H */