Tweak the way that is_a is implemented
authorRichard Sandiford <richard.sandiford@arm.com>
Sun, 13 Dec 2020 10:41:09 +0000 (10:41 +0000)
committerRichard Sandiford <richard.sandiford@arm.com>
Sun, 13 Dec 2020 10:41:09 +0000 (10:41 +0000)
commit1498b1a8fb82834a8578a2a9a3525f38c3483d1e
tree100a00b14b25b7f5bee08c5bea2d47bacb5d8c70
parent1751a78ecafb1d16d4a843dd22e739b8fd1cfede
Tweak the way that is_a is implemented

At the moment, class hierarchies that use is_a are expected
to define specialisations like:

  template <>
  template <>
  inline bool
  is_a_helper <cgraph_node *>::test (symtab_node *p)
  {
    return p->type == SYMTAB_FUNCTION;
  }

But this doesn't scale well to larger hierarchies, because it only
defines ::test for an argument that is exactly “symtab_node *”
(and not for example “const symtab_node *” or something that
comes between cgraph_node and symtab_node in the hierarchy).

For example:

  struct A { int x; };
  struct B : A {};
  struct C : B {};

  template <>
  template <>
  inline bool
  is_a_helper <C *>::test (A *a)
  {
    return a->x == 1;
  }

  bool f(B *b) { return is_a<C *> (b); }

gives:

  warning: inline function ‘static bool is_a_helper<T>::test(U*) [with U = B; T = C*]’ used but never defined

and:

  bool f(const A *a) { return is_a<const C *> (a); }

gives:

  warning: inline function ‘static bool is_a_helper<T>::test(U*) [with U = const A; T = const C*]’ used but never defined

This patch instead allows is_a to be implemented by specialising
is_a_helper as a whole, for example:

  template<>
  struct is_a_helper<C *> : static_is_a_helper<C *>
  {
    static inline bool test (const A *a) { return a->x == 1; }
  };

It also adds a general specialisation of is_a_helper for const
pointers.  Together, this makes both of the above examples work.

gcc/
* is-a.h (reinterpret_is_a_helper): New class.
(static_is_a_helper): Likewise.
(is_a_helper): Inherit from reinterpret_is_a_helper.
(is_a_helper<const T *>): New specialization.
gcc/is-a.h