]>
Commit | Line | Data |
---|---|---|
5d59b5e1 | 1 | /* Dynamic testing for abstract is-a relationships. |
d1e082c2 | 2 | Copyright (C) 2012-2013 Free Software Foundation, Inc. |
5d59b5e1 LC |
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 | ||
a3bfa8b8 | 34 | Suppose you have a symtab_node_base *ptr, AKA symtab_node ptr. You can test |
5d59b5e1 LC |
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 *dyn_cast <TYPE> (pointer) | |
50 | ||
51 | Converts pointer to TYPE* if and only if "is_a <TYPE> pointer". Otherwise, | |
52 | returns NULL. This function is essentially a checked down cast. | |
53 | ||
54 | This functions reduce compile time and increase type safety when treating a | |
55 | generic item as a more specific item. | |
56 | ||
57 | You can test and obtain a pointer to the 'derived' type in one indivisible | |
58 | operation. | |
59 | ||
60 | if (cgraph_node *cptr = dyn_cast <cgraph_node> (ptr)) | |
61 | .... | |
62 | ||
63 | As an example, the code change is from | |
64 | ||
65 | if (symtab_function_p (node)) | |
66 | { | |
67 | struct cgraph_node *cnode = cgraph (node); | |
68 | .... | |
69 | } | |
70 | ||
71 | to | |
72 | ||
73 | if (cgraph_node *cnode = dyn_cast <cgraph_node> (node)) | |
74 | { | |
75 | .... | |
76 | } | |
77 | ||
78 | The necessary conditional test defines a variable that holds a known good | |
79 | pointer to the specific item and avoids subsequent conversion calls and | |
80 | the assertion checks that may come with them. | |
81 | ||
82 | When, the property test is embedded within a larger condition, the | |
83 | variable declaration gets pulled out of the condition. (This approach | |
84 | leaves some room for using the variable inappropriately.) | |
85 | ||
86 | if (symtab_variable_p (node) && varpool (node)->finalized) | |
87 | varpool_analyze_node (varpool (node)); | |
88 | ||
89 | becomes | |
90 | ||
91 | varpool_node *vnode = dyn_cast <varpool_node> (node); | |
92 | if (vnode && vnode->finalized) | |
93 | varpool_analyze_node (vnode); | |
94 | ||
95 | Note that we have converted two sets of assertions in the calls to varpool | |
96 | into safe and efficient use of a variable. | |
97 | ||
98 | ||
99 | If you use these functions and get a 'inline function not defined' or a | |
100 | 'missing symbol' error message for 'is_a_helper<....>::test', it means that | |
101 | the connection between the types has not been made. See below. | |
102 | ||
103 | ||
104 | EXTENDING THE GENERIC TYPE FACILITY | |
105 | ||
106 | Each connection between types must be made by defining a specialization of the | |
107 | template member function 'test' of the template class 'is_a_helper'. For | |
108 | example, | |
109 | ||
110 | template <> | |
111 | template <> | |
112 | inline bool | |
a3bfa8b8 | 113 | is_a_helper <cgraph_node>::test (symtab_node_base *p) |
5d59b5e1 LC |
114 | { |
115 | return p->symbol.type == SYMTAB_FUNCTION; | |
116 | } | |
117 | ||
118 | If a simple reinterpret_cast between the pointer types is incorrect, then you | |
119 | must also specialize the template member function 'cast'. Failure to do so | |
120 | when needed may result in a crash. For example, | |
121 | ||
122 | template <> | |
123 | template <> | |
124 | inline bool | |
a3bfa8b8 | 125 | is_a_helper <cgraph_node>::cast (symtab_node_base *p) |
5d59b5e1 LC |
126 | { |
127 | return &p->x_function; | |
128 | } | |
129 | ||
130 | */ | |
131 | ||
132 | #ifndef GCC_IS_A_H | |
133 | #define GCC_IS_A_H | |
134 | ||
135 | /* A generic type conversion internal helper class. */ | |
136 | ||
137 | template <typename T> | |
138 | struct is_a_helper | |
139 | { | |
140 | template <typename U> | |
141 | static inline bool test (U *p); | |
142 | template <typename U> | |
143 | static inline T *cast (U *p); | |
144 | }; | |
145 | ||
146 | /* Note that we deliberately do not define the 'test' member template. Not | |
147 | doing so will result in a build-time error for type relationships that have | |
148 | not been defined, rather than a run-time error. See the discussion above | |
149 | for when to define this member. */ | |
150 | ||
151 | /* This is the generic implementation for casting from one type to another. | |
152 | Do not use this routine directly; it is an internal function. See the | |
153 | discussion above for when to define this member. */ | |
154 | ||
155 | template <typename T> | |
156 | template <typename U> | |
157 | inline T * | |
158 | is_a_helper <T>::cast (U *p) | |
159 | { | |
160 | return reinterpret_cast <T *> (p); | |
161 | } | |
162 | ||
163 | ||
164 | /* The public interface. */ | |
165 | ||
166 | /* A generic test for a type relationship. See the discussion above for when | |
167 | to use this function. The question answered is "Is type T a derived type of | |
168 | type U?". */ | |
169 | ||
170 | template <typename T, typename U> | |
171 | inline bool | |
172 | is_a (U *p) | |
173 | { | |
174 | return is_a_helper<T>::test (p); | |
175 | } | |
176 | ||
177 | /* A generic conversion from a base type U to a derived type T. See the | |
178 | discussion above for when to use this function. */ | |
179 | ||
180 | template <typename T, typename U> | |
181 | inline T * | |
182 | as_a (U *p) | |
183 | { | |
f046e81b | 184 | gcc_checking_assert (is_a <T> (p)); |
5d59b5e1 LC |
185 | return is_a_helper <T>::cast (p); |
186 | } | |
187 | ||
188 | /* A generic checked conversion from a base type U to a derived type T. See | |
189 | the discussion above for when to use this function. */ | |
190 | ||
191 | template <typename T, typename U> | |
192 | inline T * | |
193 | dyn_cast (U *p) | |
194 | { | |
195 | if (is_a <T> (p)) | |
196 | return is_a_helper <T>::cast (p); | |
197 | else | |
198 | return static_cast <T *> (0); | |
199 | } | |
200 | ||
201 | #endif /* GCC_IS_A_H */ |