]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/is-a.h
Convert symtab, cgraph and varpool nodes into a real class hierarchy
[thirdparty/gcc.git] / gcc / is-a.h
CommitLineData
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
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
25USING THE GENERIC TYPE FACILITY
26
27
28The user functions are:
29
30bool 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
41TYPE *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
49TYPE *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
99If 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
101the connection between the types has not been made. See below.
102
103
104EXTENDING THE GENERIC TYPE FACILITY
105
106Each connection between types must be made by defining a specialization of the
107template member function 'test' of the template class 'is_a_helper'. For
108example,
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
118If a simple reinterpret_cast between the pointer types is incorrect, then you
119must also specialize the template member function 'cast'. Failure to do so
120when 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
137template <typename T>
138struct 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
155template <typename T>
156template <typename U>
157inline T *
158is_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
170template <typename T, typename U>
171inline bool
172is_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
180template <typename T, typename U>
181inline T *
182as_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
191template <typename T, typename U>
192inline T *
193dyn_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 */