(root)/
gcc-13.2.0/
gcc/
is-a.h
       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  is_a (U *p)
     231  {
     232    return is_a_helper<T>::test (p);
     233  }
     234  
     235  /* A generic conversion from a base type U to a derived type T.  See the
     236     discussion above for when to use this function.  */
     237  
     238  template <typename T, typename U>
     239  inline T
     240  as_a (U *p)
     241  {
     242    gcc_checking_assert (is_a <T> (p));
     243    return is_a_helper <T>::cast (p);
     244  }
     245  
     246  /* Similar to as_a<>, but where the pointer can be NULL, even if
     247     is_a_helper<T> doesn't check for NULL.  */
     248  
     249  template <typename T, typename U>
     250  inline T
     251  safe_as_a (U *p)
     252  {
     253    if (p)
     254      {
     255        gcc_checking_assert (is_a <T> (p));
     256        return is_a_helper <T>::cast (p);
     257      }
     258    else
     259      return NULL;
     260  }
     261  
     262  /* A generic checked conversion from a base type U to a derived type T.  See
     263     the discussion above for when to use this function.  */
     264  
     265  template <typename T, typename U>
     266  inline T
     267  dyn_cast (U *p)
     268  {
     269    if (is_a <T> (p))
     270      return is_a_helper <T>::cast (p);
     271    else
     272      return static_cast <T> (0);
     273  }
     274  
     275  /* Similar to dyn_cast, except that the pointer may be null.  */
     276  
     277  template <typename T, typename U>
     278  inline T
     279  safe_dyn_cast (U *p)
     280  {
     281    return p ? dyn_cast <T> (p) : 0;
     282  }
     283  
     284  #endif  /* GCC_IS_A_H  */