LCOV - code coverage report
Current view: top level - gcc - is-a.h (source / functions) Hit Total Coverage
Test: gcc.info Lines: 5 5 100.0 %
Date: 2023-07-19 08:18:47 Functions: 0 0 -

          Line data    Source code
       1             : /* Dynamic testing for abstract is-a relationships.
       2             :    Copyright (C) 2012-2023 Free Software Foundation, Inc.
       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             : 
      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             : 
      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 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             : 
      57             : TYPE 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             : TYPE safe_dyn_cast <TYPE> (pointer)
     107             : 
     108             :     Like dyn_cast <TYPE> (pointer), except that it accepts null pointers
     109             :     and returns null results for them.
     110             : 
     111             : 
     112             : If you use these functions and get a 'inline function not defined' or a
     113             : 'missing symbol' error message for 'is_a_helper<....>::test', it means that
     114             : the connection between the types has not been made.  See below.
     115             : 
     116             : 
     117             : EXTENDING THE GENERIC TYPE FACILITY
     118             : 
     119             : Method 1
     120             : --------
     121             : 
     122             : If DERIVED is derived from BASE, and if BASE contains enough information
     123             : to determine whether an object is actually an instance of DERIVED,
     124             : then you can make the above routines work for DERIVED by defining
     125             : a specialization of is_a_helper such as:
     126             : 
     127             :   template<>
     128             :   struct is_a_helper<DERIVED *> : static_is_a_helper<DERIVED *>
     129             :   {
     130             :     static inline bool test (const BASE *p) { return ...; }
     131             :   };
     132             : 
     133             : This test function should return true if P is an instanced of DERIVED.
     134             : This on its own is enough; the comments below for method 2 do not apply.
     135             : 
     136             : Method 2
     137             : --------
     138             : 
     139             : Alternatively, if two types are connected in ways other than C++
     140             : inheritance, each connection between them must be made by defining a
     141             : specialization of the template member function 'test' of the template
     142             : class 'is_a_helper'.  For example,
     143             : 
     144             :   template <>
     145             :   template <>
     146             :   inline bool
     147             :   is_a_helper <cgraph_node *>::test (symtab_node *p)
     148             :   {
     149             :     return p->type == SYMTAB_FUNCTION;
     150             :   }
     151             : 
     152             : If a simple reinterpret_cast between the pointer types is incorrect, then you
     153             : must also specialize the template member function 'cast'.  Failure to do so
     154             : when needed may result in a crash.  For example,
     155             : 
     156             :   template <>
     157             :   template <>
     158             :   inline bool
     159             :   is_a_helper <cgraph_node *>::cast (symtab_node *p)
     160             :   {
     161             :     return &p->x_function;
     162             :   }
     163             : 
     164             : */
     165             : 
     166             : #ifndef GCC_IS_A_H
     167             : #define GCC_IS_A_H
     168             : 
     169             : /* A base class that specializations of is_a_helper can use if casting
     170             :    U * to T is simply a reinterpret_cast.  */
     171             : 
     172             : template <typename T>
     173             : struct reinterpret_is_a_helper
     174             : {
     175             :   template <typename U>
     176             :   static inline T cast (U *p) { return reinterpret_cast <T> (p); }
     177             : };
     178             : 
     179             : /* A base class that specializations of is_a_helper can use if casting
     180             :    U * to T is simply a static_cast.  This is more type-safe than
     181             :    reinterpret_is_a_helper.  */
     182             : 
     183             : template <typename T>
     184             : struct static_is_a_helper
     185             : {
     186             :   template <typename U>
     187             :   static inline T cast (U *p) { return static_cast <T> (p); }
     188             : };
     189             : 
     190             : /* A generic type conversion internal helper class.  */
     191             : 
     192             : template <typename T>
     193             : struct is_a_helper : reinterpret_is_a_helper<T>
     194             : {
     195             :   template <typename U>
     196             :   static inline bool test (U *p);
     197             : };
     198             : 
     199             : /* Reuse the definition of is_a_helper<T *> to implement
     200             :    is_a_helper<const T *>.  */
     201             : 
     202             : template <typename T>
     203             : struct is_a_helper<const T *>
     204             : {
     205             :   template <typename U>
     206             :   static inline const T *cast (const U *p)
     207             :   {
     208             :     return is_a_helper<T *>::cast (const_cast <U *> (p));
     209             :   }
     210             :   template <typename U>
     211             :   static inline bool test (const U *p)
     212             :   {
     213             :     return is_a_helper<T *>::test (p);
     214             :   }
     215             : };
     216             : 
     217             : /* Note that we deliberately do not define the 'test' member template.  Not
     218             :    doing so will result in a build-time error for type relationships that have
     219             :    not been defined, rather than a run-time error.  See the discussion above
     220             :    for when to define this member.  */
     221             : 
     222             : /* The public interface.  */
     223             : 
     224             : /* A generic test for a type relationship.  See the discussion above for when
     225             :    to use this function.  The question answered is "Is type T a derived type of
     226             :    type U?".  */
     227             : 
     228             : template <typename T, typename U>
     229             : inline bool
     230   115460952 : is_a (U *p)
     231             : {
     232   135244790 :   return is_a_helper<T>::test (p);
     233             : }
     234             : 
     235             : /* Similar to is_a<>, but where the pointer can be NULL, even if
     236             :    is_a_helper<T> doesn't check for NULL.  */
     237             : 
     238             : template <typename T, typename U>
     239             : inline bool
     240             : safe_is_a (U *p)
     241             : {
     242             :   if (p)
     243             :     return is_a_helper <T>::test (p);
     244             :   else
     245             :     return false;
     246             : }
     247             : 
     248             : /* A generic conversion from a base type U to a derived type T.  See the
     249             :    discussion above for when to use this function.  */
     250             : 
     251             : template <typename T, typename U>
     252             : inline T
     253             : as_a (U *p)
     254             : {
     255             :   gcc_checking_assert (is_a <T> (p));
     256             :   return is_a_helper <T>::cast (p);
     257             : }
     258             : 
     259             : /* Similar to as_a<>, but where the pointer can be NULL, even if
     260             :    is_a_helper<T> doesn't check for NULL.  */
     261             : 
     262             : template <typename T, typename U>
     263             : inline T
     264             : safe_as_a (U *p)
     265             : {
     266             :   if (p)
     267             :     {
     268             :       gcc_checking_assert (is_a <T> (p));
     269             :       return is_a_helper <T>::cast (p);
     270             :     }
     271             :   else
     272             :     return NULL;
     273             : }
     274             : 
     275             : /* A generic checked conversion from a base type U to a derived type T.  See
     276             :    the discussion above for when to use this function.  */
     277             : 
     278             : template <typename T, typename U>
     279             : inline T
     280  1156037764 : dyn_cast (U *p)
     281             : {
     282   184921123 :   if (is_a <T> (p))
     283             :     return is_a_helper <T>::cast (p);
     284             :   else
     285   111139870 :     return static_cast <T> (0);
     286             : }
     287             : 
     288             : /* Similar to dyn_cast, except that the pointer may be null.  */
     289             : 
     290             : template <typename T, typename U>
     291             : inline T
     292             : safe_dyn_cast (U *p)
     293             : {
     294             :   return p ? dyn_cast <T> (p) : 0;
     295             : }
     296             : 
     297             : #endif  /* GCC_IS_A_H  */

Generated by: LCOV version 1.16