LCOV - code coverage report
Current view: top level - gcc - is-a.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 100.0 % 18 18
Test Date: 2026-02-28 14:20:25 Functions: 89.9 % 169 152
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Dynamic testing for abstract is-a relationships.
       2              :    Copyright (C) 2012-2026 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    501450713 :   static inline bool test (const U *p)
     212              :   {
     213    501450713 :     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  >25680*10^7 : is_a (U *p)
     231              : {
     232  >47604*10^7 :   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    198639011 : safe_is_a (U *p)
     241              : {
     242    151864243 :   if (p)
     243    102102342 :     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  37921130579 : as_a (U *p)
     254              : {
     255  37821223441 :   gcc_checking_assert (is_a <T> (p));
     256  37921130579 :   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  >18710*10^7 : safe_as_a (U *p)
     265              : {
     266  >18710*10^7 :   if (p)
     267              :     {
     268  >17821*10^7 :       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  >26765*10^7 : dyn_cast (U *p)
     281              : {
     282  >30588*10^7 :   if (is_a <T> (p))
     283              :     return is_a_helper <T>::cast (p);
     284              :   else
     285   1703234392 :     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   1905158509 : safe_dyn_cast (U *p)
     293              : {
     294   5749060879 :   return p ? dyn_cast <T> (p) : 0;
     295              : }
     296              : 
     297              : #endif  /* GCC_IS_A_H  */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.