is-a.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /* Dynamic testing for abstract is-a relationships.
  2. Copyright (C) 2012-2015 Free Software Foundation, Inc.
  3. Contributed by Lawrence Crowl.
  4. This file is part of GCC.
  5. GCC is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 3, or (at your option) any later
  8. version.
  9. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GCC; see the file COPYING3. If not see
  15. <http://www.gnu.org/licenses/>. */
  16. /* This header generic type query and conversion functions.
  17. USING THE GENERIC TYPE FACILITY
  18. The user functions are:
  19. bool is_a <TYPE> (pointer)
  20. Tests whether the pointer actually points to a more derived TYPE.
  21. Suppose you have a symtab_node *ptr, AKA symtab_node *ptr. You can test
  22. whether it points to a 'derived' cgraph_node as follows.
  23. if (is_a <cgraph_node *> (ptr))
  24. ....
  25. TYPE as_a <TYPE> (pointer)
  26. Converts pointer to a TYPE.
  27. You can just assume that it is such a node.
  28. do_something_with (as_a <cgraph_node *> *ptr);
  29. TYPE safe_as_a <TYPE> (pointer)
  30. Like as_a <TYPE> (pointer), but where pointer could be NULL. This
  31. adds a check against NULL where the regular is_a_helper hook for TYPE
  32. assumes non-NULL.
  33. do_something_with (safe_as_a <cgraph_node *> *ptr);
  34. TYPE dyn_cast <TYPE> (pointer)
  35. Converts pointer to TYPE if and only if "is_a <TYPE> pointer". Otherwise,
  36. returns NULL. This function is essentially a checked down cast.
  37. This functions reduce compile time and increase type safety when treating a
  38. generic item as a more specific item.
  39. You can test and obtain a pointer to the 'derived' type in one indivisible
  40. operation.
  41. if (cgraph_node *cptr = dyn_cast <cgraph_node *> (ptr))
  42. ....
  43. As an example, the code change is from
  44. if (symtab_function_p (node))
  45. {
  46. struct cgraph_node *cnode = cgraph (node);
  47. ....
  48. }
  49. to
  50. if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node))
  51. {
  52. ....
  53. }
  54. The necessary conditional test defines a variable that holds a known good
  55. pointer to the specific item and avoids subsequent conversion calls and
  56. the assertion checks that may come with them.
  57. When, the property test is embedded within a larger condition, the
  58. variable declaration gets pulled out of the condition. (This approach
  59. leaves some room for using the variable inappropriately.)
  60. if (symtab_variable_p (node) && varpool (node)->finalized)
  61. varpool_analyze_node (varpool (node));
  62. becomes
  63. varpool_node *vnode = dyn_cast <varpool_node *> (node);
  64. if (vnode && vnode->finalized)
  65. varpool_analyze_node (vnode);
  66. Note that we have converted two sets of assertions in the calls to varpool
  67. into safe and efficient use of a variable.
  68. If you use these functions and get a 'inline function not defined' or a
  69. 'missing symbol' error message for 'is_a_helper<....>::test', it means that
  70. the connection between the types has not been made. See below.
  71. EXTENDING THE GENERIC TYPE FACILITY
  72. Each connection between types must be made by defining a specialization of the
  73. template member function 'test' of the template class 'is_a_helper'. For
  74. example,
  75. template <>
  76. template <>
  77. inline bool
  78. is_a_helper <cgraph_node *>::test (symtab_node *p)
  79. {
  80. return p->type == SYMTAB_FUNCTION;
  81. }
  82. If a simple reinterpret_cast between the pointer types is incorrect, then you
  83. must also specialize the template member function 'cast'. Failure to do so
  84. when needed may result in a crash. For example,
  85. template <>
  86. template <>
  87. inline bool
  88. is_a_helper <cgraph_node *>::cast (symtab_node *p)
  89. {
  90. return &p->x_function;
  91. }
  92. */
  93. #ifndef GCC_IS_A_H
  94. #define GCC_IS_A_H
  95. /* A generic type conversion internal helper class. */
  96. template <typename T>
  97. struct is_a_helper
  98. {
  99. template <typename U>
  100. static inline bool test (U *p);
  101. template <typename U>
  102. static inline T cast (U *p);
  103. };
  104. /* Note that we deliberately do not define the 'test' member template. Not
  105. doing so will result in a build-time error for type relationships that have
  106. not been defined, rather than a run-time error. See the discussion above
  107. for when to define this member. */
  108. /* This is the generic implementation for casting from one type to another.
  109. Do not use this routine directly; it is an internal function. See the
  110. discussion above for when to define this member. */
  111. template <typename T>
  112. template <typename U>
  113. inline T
  114. is_a_helper <T>::cast (U *p)
  115. {
  116. return reinterpret_cast <T> (p);
  117. }
  118. /* The public interface. */
  119. /* A generic test for a type relationship. See the discussion above for when
  120. to use this function. The question answered is "Is type T a derived type of
  121. type U?". */
  122. template <typename T, typename U>
  123. inline bool
  124. is_a (U *p)
  125. {
  126. return is_a_helper<T>::test (p);
  127. }
  128. /* A generic conversion from a base type U to a derived type T. See the
  129. discussion above for when to use this function. */
  130. template <typename T, typename U>
  131. inline T
  132. as_a (U *p)
  133. {
  134. gcc_checking_assert (is_a <T> (p));
  135. return is_a_helper <T>::cast (p);
  136. }
  137. /* Similar to as_a<>, but where the pointer can be NULL, even if
  138. is_a_helper<T> doesn't check for NULL. */
  139. template <typename T, typename U>
  140. inline T
  141. safe_as_a (U *p)
  142. {
  143. if (p)
  144. {
  145. gcc_checking_assert (is_a <T> (p));
  146. return is_a_helper <T>::cast (p);
  147. }
  148. else
  149. return NULL;
  150. }
  151. /* A generic checked conversion from a base type U to a derived type T. See
  152. the discussion above for when to use this function. */
  153. template <typename T, typename U>
  154. inline T
  155. dyn_cast (U *p)
  156. {
  157. if (is_a <T> (p))
  158. return is_a_helper <T>::cast (p);
  159. else
  160. return static_cast <T> (0);
  161. }
  162. #endif /* GCC_IS_A_H */