1/* Dynamic testing for abstract is-a relationships.
2   Copyright (C) 2012-2015 Free Software Foundation, Inc.
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
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
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 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
57TYPE 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
107If 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
109the connection between the types has not been made.  See below.
110
111
112EXTENDING THE GENERIC TYPE FACILITY
113
114Each connection between types must be made by defining a specialization of the
115template member function 'test' of the template class 'is_a_helper'.  For
116example,
117
118  template <>
119  template <>
120  inline bool
121  is_a_helper <cgraph_node *>::test (symtab_node *p)
122  {
123    return p->type == SYMTAB_FUNCTION;
124  }
125
126If a simple reinterpret_cast between the pointer types is incorrect, then you
127must also specialize the template member function 'cast'.  Failure to do so
128when needed may result in a crash.  For example,
129
130  template <>
131  template <>
132  inline bool
133  is_a_helper <cgraph_node *>::cast (symtab_node *p)
134  {
135    return &p->x_function;
136  }
137
138*/
139
140#ifndef GCC_IS_A_H
141#define GCC_IS_A_H
142
143/* A generic type conversion internal helper class.  */
144
145template <typename T>
146struct is_a_helper
147{
148  template <typename U>
149  static inline bool test (U *p);
150  template <typename U>
151  static inline T cast (U *p);
152};
153
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.  */
158
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.  */
162
163template <typename T>
164template <typename U>
165inline T
166is_a_helper <T>::cast (U *p)
167{
168  return reinterpret_cast <T> (p);
169}
170
171
172/* The public interface.  */
173
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?".  */
177
178template <typename T, typename U>
179inline bool
180is_a (U *p)
181{
182  return is_a_helper<T>::test (p);
183}
184
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.  */
187
188template <typename T, typename U>
189inline T
190as_a (U *p)
191{
192  gcc_checking_assert (is_a <T> (p));
193  return is_a_helper <T>::cast (p);
194}
195
196/* Similar to as_a<>, but where the pointer can be NULL, even if
197   is_a_helper<T> doesn't check for NULL.  */
198
199template <typename T, typename U>
200inline T
201safe_as_a (U *p)
202{
203  if (p)
204    {
205      gcc_checking_assert (is_a <T> (p));
206      return is_a_helper <T>::cast (p);
207    }
208  else
209    return NULL;
210}
211
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.  */
214
215template <typename T, typename U>
216inline T
217dyn_cast (U *p)
218{
219  if (is_a <T> (p))
220    return is_a_helper <T>::cast (p);
221  else
222    return static_cast <T> (0);
223}
224
225#endif  /* GCC_IS_A_H  */
226