tinfo.cc revision 110614
1// Methods for type_info for -*- C++ -*- Run Time Type Identification.
2// Copyright (C) 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2003
3// Free Software Foundation
4//
5// This file is part of GNU CC.
6//
7// GNU CC is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2, or (at your option)
10// any later version.
11
12// GNU CC is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16
17// You should have received a copy of the GNU General Public License
18// along with GNU CC; see the file COPYING.  If not, write to
19// the Free Software Foundation, 59 Temple Place - Suite 330,
20// Boston, MA 02111-1307, USA.
21
22// As a special exception, you may use this file as part of a free software
23// library without restriction.  Specifically, if other files instantiate
24// templates or use macros or inline functions from this file, or you compile
25// this file and link it with other files to produce an executable, this
26// file does not by itself cause the resulting executable to be covered by
27// the GNU General Public License.  This exception does not however
28// invalidate any other reasons why the executable file might be covered by
29// the GNU General Public License.
30
31#include <cstddef>
32#include "tinfo.h"
33#include "new"			// for placement new
34
35// This file contains the minimal working set necessary to link with code
36// that uses virtual functions and -frtti but does not actually use RTTI
37// functionality.
38
39std::type_info::
40~type_info ()
41{ }
42
43std::bad_cast::~bad_cast() throw() { }
44std::bad_typeid::~bad_typeid() throw() { }
45
46#if !__GXX_MERGED_TYPEINFO_NAMES
47
48// We can't rely on common symbols being shared between shared objects.
49bool std::type_info::
50operator== (const std::type_info& arg) const
51{
52  return (&arg == this) || (__builtin_strcmp (name (), arg.name ()) == 0);
53}
54
55#endif
56
57namespace std {
58
59// return true if this is a type_info for a pointer type
60bool type_info::
61__is_pointer_p () const
62{
63  return false;
64}
65
66// return true if this is a type_info for a function type
67bool type_info::
68__is_function_p () const
69{
70  return false;
71}
72
73// try and catch a thrown object.
74bool type_info::
75__do_catch (const type_info *thr_type, void **, unsigned) const
76{
77  return *this == *thr_type;
78}
79
80// upcast from this type to the target. __class_type_info will override
81bool type_info::
82__do_upcast (const abi::__class_type_info *, void **) const
83{
84  return false;
85}
86
87};
88
89namespace {
90
91using namespace std;
92using namespace abi;
93
94// initial part of a vtable, this structure is used with offsetof, so we don't
95// have to keep alignments consistent manually.
96struct vtable_prefix {
97  ptrdiff_t whole_object;           // offset to most derived object
98  const __class_type_info *whole_type;  // pointer to most derived type_info
99  const void *origin;               // what a class's vptr points to
100};
101
102template <typename T>
103inline const T *
104adjust_pointer (const void *base, ptrdiff_t offset)
105{
106  return reinterpret_cast <const T *>
107    (reinterpret_cast <const char *> (base) + offset);
108}
109
110// ADDR is a pointer to an object.  Convert it to a pointer to a base,
111// using OFFSET. IS_VIRTUAL is true, if we are getting a virtual base.
112inline void const *
113convert_to_base (void const *addr, bool is_virtual, ptrdiff_t offset)
114{
115  if (is_virtual)
116    {
117      const void *vtable = *static_cast <const void *const *> (addr);
118
119      offset = *adjust_pointer<ptrdiff_t> (vtable, offset);
120    }
121
122  return adjust_pointer<void> (addr, offset);
123}
124
125// some predicate functions for __class_type_info::__sub_kind
126inline bool contained_p (__class_type_info::__sub_kind access_path)
127{
128  return access_path >= __class_type_info::__contained_mask;
129}
130inline bool public_p (__class_type_info::__sub_kind access_path)
131{
132  return access_path & __class_type_info::__contained_public_mask;
133}
134inline bool virtual_p (__class_type_info::__sub_kind access_path)
135{
136  return (access_path & __class_type_info::__contained_virtual_mask);
137}
138inline bool contained_public_p (__class_type_info::__sub_kind access_path)
139{
140  return ((access_path & __class_type_info::__contained_public)
141          == __class_type_info::__contained_public);
142}
143inline bool contained_nonpublic_p (__class_type_info::__sub_kind access_path)
144{
145  return ((access_path & __class_type_info::__contained_public)
146          == __class_type_info::__contained_mask);
147}
148inline bool contained_nonvirtual_p (__class_type_info::__sub_kind access_path)
149{
150  return ((access_path & (__class_type_info::__contained_mask
151                          | __class_type_info::__contained_virtual_mask))
152          == __class_type_info::__contained_mask);
153}
154
155static const __class_type_info *const nonvirtual_base_type =
156    static_cast <const __class_type_info *> (0) + 1;
157
158}; // namespace
159
160namespace __cxxabiv1
161{
162
163__class_type_info::
164~__class_type_info ()
165{}
166
167__si_class_type_info::
168~__si_class_type_info ()
169{}
170
171__vmi_class_type_info::
172~__vmi_class_type_info ()
173{}
174
175// __upcast_result is used to hold information during traversal of a class
176// hierarchy when catch matching.
177struct __class_type_info::__upcast_result
178{
179  const void *dst_ptr;        // pointer to caught object
180  __sub_kind part2dst;        // path from current base to target
181  int src_details;            // hints about the source type hierarchy
182  const __class_type_info *base_type; // where we found the target,
183                              // if in vbase the __class_type_info of vbase
184                              // if a non-virtual base then 1
185                              // else NULL
186  public:
187  __upcast_result (int d)
188    :dst_ptr (NULL), part2dst (__unknown), src_details (d), base_type (NULL)
189    {}
190};
191
192// __dyncast_result is used to hold information during traversal of a class
193// hierarchy when dynamic casting.
194struct __class_type_info::__dyncast_result
195{
196  const void *dst_ptr;        // pointer to target object or NULL
197  __sub_kind whole2dst;       // path from most derived object to target
198  __sub_kind whole2src;       // path from most derived object to sub object
199  __sub_kind dst2src;         // path from target to sub object
200  int whole_details;          // details of the whole class hierarchy
201
202  public:
203  __dyncast_result (int details_ = __vmi_class_type_info::__flags_unknown_mask)
204    :dst_ptr (NULL), whole2dst (__unknown),
205     whole2src (__unknown), dst2src (__unknown),
206     whole_details (details_)
207    {}
208};
209
210bool __class_type_info::
211__do_catch (const type_info *thr_type,
212            void **thr_obj,
213            unsigned outer) const
214{
215  if (*this == *thr_type)
216    return true;
217  if (outer >= 4)
218    // Neither `A' nor `A *'.
219    return false;
220  return thr_type->__do_upcast (this, thr_obj);
221}
222
223bool __class_type_info::
224__do_upcast (const __class_type_info *dst_type,
225             void **obj_ptr) const
226{
227  __upcast_result result (__vmi_class_type_info::__flags_unknown_mask);
228
229  __do_upcast (dst_type, *obj_ptr, result);
230  if (!contained_public_p (result.part2dst))
231    return false;
232  *obj_ptr = const_cast <void *> (result.dst_ptr);
233  return true;
234}
235
236inline __class_type_info::__sub_kind __class_type_info::
237__find_public_src (ptrdiff_t src2dst,
238                   const void *obj_ptr,
239                   const __class_type_info *src_type,
240                   const void *src_ptr) const
241{
242  if (src2dst >= 0)
243    return adjust_pointer <void> (obj_ptr, src2dst) == src_ptr
244            ? __contained_public : __not_contained;
245  if (src2dst == -2)
246    return __not_contained;
247  return __do_find_public_src (src2dst, obj_ptr, src_type, src_ptr);
248}
249
250__class_type_info::__sub_kind __class_type_info::
251__do_find_public_src (ptrdiff_t,
252                      const void *obj_ptr,
253                      const __class_type_info *,
254                      const void *src_ptr) const
255{
256  if (src_ptr == obj_ptr)
257    // Must be our type, as the pointers match.
258    return __contained_public;
259  return __not_contained;
260}
261
262__class_type_info::__sub_kind __si_class_type_info::
263__do_find_public_src (ptrdiff_t src2dst,
264                      const void *obj_ptr,
265                      const __class_type_info *src_type,
266                      const void *src_ptr) const
267{
268  if (src_ptr == obj_ptr && *this == *src_type)
269    return __contained_public;
270  return __base_type->__do_find_public_src (src2dst, obj_ptr, src_type, src_ptr);
271}
272
273__class_type_info::__sub_kind __vmi_class_type_info::
274__do_find_public_src (ptrdiff_t src2dst,
275                      const void *obj_ptr,
276                      const __class_type_info *src_type,
277                      const void *src_ptr) const
278{
279  if (obj_ptr == src_ptr && *this == *src_type)
280    return __contained_public;
281
282  for (std::size_t i = __base_count; i--;)
283    {
284      if (!__base_info[i].__is_public_p ())
285        continue; // Not public, can't be here.
286
287      const void *base = obj_ptr;
288      ptrdiff_t offset = __base_info[i].__offset ();
289      bool is_virtual = __base_info[i].__is_virtual_p ();
290
291      if (is_virtual)
292        {
293          if (src2dst == -3)
294            continue; // Not a virtual base, so can't be here.
295        }
296      base = convert_to_base (base, is_virtual, offset);
297
298      __sub_kind base_kind = __base_info[i].__base_type->__do_find_public_src
299                              (src2dst, base, src_type, src_ptr);
300      if (contained_p (base_kind))
301        {
302          if (is_virtual)
303            base_kind = __sub_kind (base_kind | __contained_virtual_mask);
304          return base_kind;
305        }
306    }
307
308  return __not_contained;
309}
310
311bool __class_type_info::
312__do_dyncast (ptrdiff_t,
313              __sub_kind access_path,
314              const __class_type_info *dst_type,
315              const void *obj_ptr,
316              const __class_type_info *src_type,
317              const void *src_ptr,
318              __dyncast_result &__restrict result) const
319{
320  if (obj_ptr == src_ptr && *this == *src_type)
321    {
322      // The src object we started from. Indicate how we are accessible from
323      // the most derived object.
324      result.whole2src = access_path;
325      return false;
326    }
327  if (*this == *dst_type)
328    {
329      result.dst_ptr = obj_ptr;
330      result.whole2dst = access_path;
331      result.dst2src = __not_contained;
332      return false;
333    }
334  return false;
335}
336
337bool __si_class_type_info::
338__do_dyncast (ptrdiff_t src2dst,
339              __sub_kind access_path,
340              const __class_type_info *dst_type,
341              const void *obj_ptr,
342              const __class_type_info *src_type,
343              const void *src_ptr,
344              __dyncast_result &__restrict result) const
345{
346  if (*this == *dst_type)
347    {
348      result.dst_ptr = obj_ptr;
349      result.whole2dst = access_path;
350      if (src2dst >= 0)
351        result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr
352              ? __contained_public : __not_contained;
353      else if (src2dst == -2)
354        result.dst2src = __not_contained;
355      return false;
356    }
357  if (obj_ptr == src_ptr && *this == *src_type)
358    {
359      // The src object we started from. Indicate how we are accessible from
360      // the most derived object.
361      result.whole2src = access_path;
362      return false;
363    }
364  return __base_type->__do_dyncast (src2dst, access_path, dst_type, obj_ptr,
365                             src_type, src_ptr, result);
366}
367
368// This is a big hairy function. Although the run-time behaviour of
369// dynamic_cast is simple to describe, it gives rise to some non-obvious
370// behaviour. We also desire to determine as early as possible any definite
371// answer we can get. Because it is unknown what the run-time ratio of
372// succeeding to failing dynamic casts is, we do not know in which direction
373// to bias any optimizations. To that end we make no particular effort towards
374// early fail answers or early success answers. Instead we try to minimize
375// work by filling in things lazily (when we know we need the information),
376// and opportunisticly take early success or failure results.
377bool __vmi_class_type_info::
378__do_dyncast (ptrdiff_t src2dst,
379              __sub_kind access_path,
380              const __class_type_info *dst_type,
381              const void *obj_ptr,
382              const __class_type_info *src_type,
383              const void *src_ptr,
384              __dyncast_result &__restrict result) const
385{
386  if (result.whole_details & __flags_unknown_mask)
387    result.whole_details = __flags;
388
389  if (obj_ptr == src_ptr && *this == *src_type)
390    {
391      // The src object we started from. Indicate how we are accessible from
392      // the most derived object.
393      result.whole2src = access_path;
394      return false;
395    }
396  if (*this == *dst_type)
397    {
398      result.dst_ptr = obj_ptr;
399      result.whole2dst = access_path;
400      if (src2dst >= 0)
401        result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr
402              ? __contained_public : __not_contained;
403      else if (src2dst == -2)
404        result.dst2src = __not_contained;
405      return false;
406    }
407
408  bool result_ambig = false;
409  for (std::size_t i = __base_count; i--;)
410    {
411      __dyncast_result result2 (result.whole_details);
412      void const *base = obj_ptr;
413      __sub_kind base_access = access_path;
414      ptrdiff_t offset = __base_info[i].__offset ();
415      bool is_virtual = __base_info[i].__is_virtual_p ();
416
417      if (is_virtual)
418        base_access = __sub_kind (base_access | __contained_virtual_mask);
419      base = convert_to_base (base, is_virtual, offset);
420
421      if (!__base_info[i].__is_public_p ())
422        {
423          if (src2dst == -2 &&
424              !(result.whole_details
425                & (__non_diamond_repeat_mask | __diamond_shaped_mask)))
426            // The hierarchy has no duplicate bases (which might ambiguate
427            // things) and where we started is not a public base of what we
428            // want (so it cannot be a downcast). There is nothing of interest
429            // hiding in a non-public base.
430            continue;
431          base_access = __sub_kind (base_access & ~__contained_public_mask);
432        }
433
434      bool result2_ambig
435          = __base_info[i].__base_type->__do_dyncast (src2dst, base_access,
436                                             dst_type, base,
437                                             src_type, src_ptr, result2);
438      result.whole2src = __sub_kind (result.whole2src | result2.whole2src);
439      if (result2.dst2src == __contained_public
440          || result2.dst2src == __contained_ambig)
441        {
442          result.dst_ptr = result2.dst_ptr;
443          result.whole2dst = result2.whole2dst;
444          result.dst2src = result2.dst2src;
445          // Found a downcast which can't be bettered or an ambiguous downcast
446          // which can't be disambiguated
447          return result2_ambig;
448        }
449
450      if (!result_ambig && !result.dst_ptr)
451        {
452          // Not found anything yet.
453          result.dst_ptr = result2.dst_ptr;
454          result.whole2dst = result2.whole2dst;
455          result_ambig = result2_ambig;
456          if (result.dst_ptr && result.whole2src != __unknown
457              && !(__flags & __non_diamond_repeat_mask))
458            // Found dst and src and we don't have repeated bases.
459            return result_ambig;
460        }
461      else if (result.dst_ptr && result.dst_ptr == result2.dst_ptr)
462        {
463          // Found at same address, must be via virtual.  Pick the most
464          // accessible path.
465          result.whole2dst =
466              __sub_kind (result.whole2dst | result2.whole2dst);
467        }
468      else if ((result.dst_ptr != 0 & result2.dst_ptr != 0)
469	       || (result.dst_ptr != 0 & result2_ambig)
470	       || (result2.dst_ptr != 0 & result_ambig))
471        {
472          // Found two different DST_TYPE bases, or a valid one and a set of
473          // ambiguous ones, must disambiguate. See whether SRC_PTR is
474          // contained publicly within one of the non-ambiguous choices. If it
475          // is in only one, then that's the choice. If it is in both, then
476          // we're ambiguous and fail. If it is in neither, we're ambiguous,
477          // but don't yet fail as we might later find a third base which does
478          // contain SRC_PTR.
479
480          __sub_kind new_sub_kind = result2.dst2src;
481          __sub_kind old_sub_kind = result.dst2src;
482
483          if (contained_p (result.whole2src)
484              && (!virtual_p (result.whole2src)
485                  || !(result.whole_details & __diamond_shaped_mask)))
486            {
487              // We already found SRC_PTR as a base of most derived, and
488              // either it was non-virtual, or the whole hierarchy is
489              // not-diamond shaped. Therefore if it is in either choice, it
490              // can only be in one of them, and we will already know.
491              if (old_sub_kind == __unknown)
492                old_sub_kind = __not_contained;
493              if (new_sub_kind == __unknown)
494                new_sub_kind = __not_contained;
495            }
496          else
497            {
498              if (old_sub_kind >= __not_contained)
499                ;// already calculated
500              else if (contained_p (new_sub_kind)
501                       && (!virtual_p (new_sub_kind)
502                           || !(__flags & __diamond_shaped_mask)))
503                // Already found inside the other choice, and it was
504                // non-virtual or we are not diamond shaped.
505                old_sub_kind = __not_contained;
506              else
507                old_sub_kind = dst_type->__find_public_src
508                                (src2dst, result.dst_ptr, src_type, src_ptr);
509
510              if (new_sub_kind >= __not_contained)
511                ;// already calculated
512              else if (contained_p (old_sub_kind)
513                       && (!virtual_p (old_sub_kind)
514                           || !(__flags & __diamond_shaped_mask)))
515                // Already found inside the other choice, and it was
516                // non-virtual or we are not diamond shaped.
517                new_sub_kind = __not_contained;
518              else
519                new_sub_kind = dst_type->__find_public_src
520                                (src2dst, result2.dst_ptr, src_type, src_ptr);
521            }
522
523          // Neither sub_kind can be contained_ambig -- we bail out early
524          // when we find those.
525          if (contained_p (__sub_kind (new_sub_kind ^ old_sub_kind)))
526            {
527              // Only on one choice, not ambiguous.
528              if (contained_p (new_sub_kind))
529                {
530                  // Only in new.
531                  result.dst_ptr = result2.dst_ptr;
532                  result.whole2dst = result2.whole2dst;
533                  result_ambig = false;
534                  old_sub_kind = new_sub_kind;
535                }
536              result.dst2src = old_sub_kind;
537              if (public_p (result.dst2src))
538                return false; // Can't be an ambiguating downcast for later discovery.
539              if (!virtual_p (result.dst2src))
540                return false; // Found non-virtually can't be bettered
541            }
542          else if (contained_p (__sub_kind (new_sub_kind & old_sub_kind)))
543            {
544              // In both.
545              result.dst_ptr = NULL;
546              result.dst2src = __contained_ambig;
547              return true;  // Fail.
548            }
549          else
550            {
551              // In neither publicly, ambiguous for the moment, but keep
552              // looking. It is possible that it was private in one or
553              // both and therefore we should fail, but that's just tough.
554              result.dst_ptr = NULL;
555              result.dst2src = __not_contained;
556              result_ambig = true;
557            }
558        }
559
560      if (result.whole2src == __contained_private)
561        // We found SRC_PTR as a private non-virtual base, therefore all
562        // cross casts will fail. We have already found a down cast, if
563        // there is one.
564        return result_ambig;
565    }
566
567  return result_ambig;
568}
569
570bool __class_type_info::
571__do_upcast (const __class_type_info *dst, const void *obj,
572             __upcast_result &__restrict result) const
573{
574  if (*this == *dst)
575    {
576      result.dst_ptr = obj;
577      result.base_type = nonvirtual_base_type;
578      result.part2dst = __contained_public;
579      return true;
580    }
581  return false;
582}
583
584bool __si_class_type_info::
585__do_upcast (const __class_type_info *dst, const void *obj_ptr,
586             __upcast_result &__restrict result) const
587{
588  if (__class_type_info::__do_upcast (dst, obj_ptr, result))
589    return true;
590
591  return __base_type->__do_upcast (dst, obj_ptr, result);
592}
593
594bool __vmi_class_type_info::
595__do_upcast (const __class_type_info *dst, const void *obj_ptr,
596             __upcast_result &__restrict result) const
597{
598  if (__class_type_info::__do_upcast (dst, obj_ptr, result))
599    return true;
600
601  int src_details = result.src_details;
602  if (src_details & __flags_unknown_mask)
603    src_details = __flags;
604
605  for (std::size_t i = __base_count; i--;)
606    {
607      __upcast_result result2 (src_details);
608      const void *base = obj_ptr;
609      ptrdiff_t offset = __base_info[i].__offset ();
610      bool is_virtual = __base_info[i].__is_virtual_p ();
611      bool is_public = __base_info[i].__is_public_p ();
612
613      if (!is_public && !(src_details & __non_diamond_repeat_mask))
614        // original cannot have an ambiguous base, so skip private bases
615        continue;
616
617      if (base)
618        base = convert_to_base (base, is_virtual, offset);
619
620      if (__base_info[i].__base_type->__do_upcast (dst, base, result2))
621        {
622          if (result2.base_type == nonvirtual_base_type && is_virtual)
623            result2.base_type = __base_info[i].__base_type;
624          if (contained_p (result2.part2dst) && !is_public)
625            result2.part2dst = __sub_kind (result2.part2dst & ~__contained_public_mask);
626
627          if (!result.base_type)
628            {
629              result = result2;
630              if (!contained_p (result.part2dst))
631                return true; // found ambiguously
632
633              if (result.part2dst & __contained_public_mask)
634                {
635                  if (!(__flags & __non_diamond_repeat_mask))
636                    return true;  // cannot have an ambiguous other base
637                }
638              else
639                {
640                  if (!virtual_p (result.part2dst))
641                    return true; // cannot have another path
642                  if (!(__flags & __diamond_shaped_mask))
643                    return true; // cannot have a more accessible path
644                }
645            }
646          else if (result.dst_ptr != result2.dst_ptr)
647            {
648              // Found an ambiguity.
649	      result.dst_ptr = NULL;
650	      result.part2dst = __contained_ambig;
651	      return true;
652            }
653          else if (result.dst_ptr)
654            {
655              // Ok, found real object via a virtual path.
656              result.part2dst
657                  = __sub_kind (result.part2dst | result2.part2dst);
658            }
659          else
660            {
661              // Dealing with a null pointer, need to check vbase
662              // containing each of the two choices.
663              if (result2.base_type == nonvirtual_base_type
664                  || result.base_type == nonvirtual_base_type
665                  || !(*result2.base_type == *result.base_type))
666                {
667                  // Already ambiguous, not virtual or via different virtuals.
668                  // Cannot match.
669                  result.part2dst = __contained_ambig;
670                  return true;
671                }
672              result.part2dst
673                  = __sub_kind (result.part2dst | result2.part2dst);
674            }
675        }
676    }
677  return result.part2dst != __unknown;
678}
679
680// this is the external interface to the dynamic cast machinery
681extern "C" void *
682__dynamic_cast (const void *src_ptr,    // object started from
683                const __class_type_info *src_type, // type of the starting object
684                const __class_type_info *dst_type, // desired target type
685                ptrdiff_t src2dst) // how src and dst are related
686{
687  const void *vtable = *static_cast <const void *const *> (src_ptr);
688  const vtable_prefix *prefix =
689      adjust_pointer <vtable_prefix> (vtable,
690				      -offsetof (vtable_prefix, origin));
691  const void *whole_ptr =
692      adjust_pointer <void> (src_ptr, prefix->whole_object);
693  const __class_type_info *whole_type = prefix->whole_type;
694  __class_type_info::__dyncast_result result;
695
696  whole_type->__do_dyncast (src2dst, __class_type_info::__contained_public,
697                            dst_type, whole_ptr, src_type, src_ptr, result);
698  if (!result.dst_ptr)
699    return NULL;
700  if (contained_public_p (result.dst2src))
701    // Src is known to be a public base of dst.
702    return const_cast <void *> (result.dst_ptr);
703  if (contained_public_p (__class_type_info::__sub_kind (result.whole2src & result.whole2dst)))
704    // Both src and dst are known to be public bases of whole. Found a valid
705    // cross cast.
706    return const_cast <void *> (result.dst_ptr);
707  if (contained_nonvirtual_p (result.whole2src))
708    // Src is known to be a non-public nonvirtual base of whole, and not a
709    // base of dst. Found an invalid cross cast, which cannot also be a down
710    // cast
711    return NULL;
712  if (result.dst2src == __class_type_info::__unknown)
713    result.dst2src = dst_type->__find_public_src (src2dst, result.dst_ptr,
714                                                  src_type, src_ptr);
715  if (contained_public_p (result.dst2src))
716    // Found a valid down cast
717    return const_cast <void *> (result.dst_ptr);
718  // Must be an invalid down cast, or the cross cast wasn't bettered
719  return NULL;
720}
721
722}; // namespace __cxxabiv1
723