diff options
author | Benjamin Kosnik <bkoz@gcc.gnu.org> | 2000-10-06 23:31:22 +0000 |
---|---|---|
committer | Benjamin Kosnik <bkoz@gcc.gnu.org> | 2000-10-06 23:31:22 +0000 |
commit | 06bd10fb63d7bcdb508e34474fa72e75770b052d (patch) | |
tree | 2314d5dbdf5b1c34ddc9e7f6588386f6d3ba990b /libstdc++-v3/libsupc++/tinfo.cc | |
parent | 4071f896a0695fb3c31153e803bbb3d1bc880108 (diff) | |
download | gcc-06bd10fb63d7bcdb508e34474fa72e75770b052d.tar.gz |
libsupc++: New directory.
2000-10-06 Benjamin Kosnik <bkoz@cygnus.com>
Richard Henderson <rth@cygnus.com>
Alexandre Oliva <aoliva@redhat.com>
* libsupc++: New directory.
* libsupc++/*: Populate.
* libsupc++/Makefile.am (INCLUDES): Add -I../../gcc for
eh-common.h, gansidecl.h.
* configure.in: Add in libsupc++/Makefile to AC_OUTPUT.
* configure: Regenerate.
* Makefile.am (SUBDIRS): Add libsupc++.
* Makefile.in: Regenerate.
* src/Makefile.am (libstdc___la_LIBADD): Add in libsupc++.la
* src/Makefile.in: Regenerate.
* libio/Makefile.am: Remove extraneous, confusing bits.
* libio/Makefile.in: Regeneate.
From-SVN: r36763
Diffstat (limited to 'libstdc++-v3/libsupc++/tinfo.cc')
-rw-r--r-- | libstdc++-v3/libsupc++/tinfo.cc | 1210 |
1 files changed, 1210 insertions, 0 deletions
diff --git a/libstdc++-v3/libsupc++/tinfo.cc b/libstdc++-v3/libsupc++/tinfo.cc new file mode 100644 index 00000000000..c381ff11101 --- /dev/null +++ b/libstdc++-v3/libsupc++/tinfo.cc @@ -0,0 +1,1210 @@ +// Methods for type_info for -*- C++ -*- Run Time Type Identification. +// Copyright (C) 1994, 1996, 1998, 1999, 2000 Free Software Foundation + +// This file is part of GNU CC. + +// GNU CC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. + +// GNU CC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with GNU CC; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#pragma implementation "typeinfo" + +#include <stddef.h> +#include "tinfo.h" +#include "new" // for placement new + +// This file contains the minimal working set necessary to link with code +// that uses virtual functions and -frtti but does not actually use RTTI +// functionality. + +std::type_info:: +~type_info () +{ } + +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 +// original (old) abi + +namespace +{ +// ADDR is a pointer to an object. Convert it to a pointer to a base, +// using OFFSET. +inline void* +convert_to_base (void *addr, bool is_virtual, myint32 offset) +{ + if (!addr) + return NULL; + + if (!is_virtual) + return (char *) addr + offset; + + // Under the old ABI, the offset gives us the address of a pointer + // to the virtual base. + return *((void **) ((char *) addr + offset)); +} + +} + +// We can't rely on common symbols being shared between shared objects. +bool std::type_info:: +operator== (const std::type_info& arg) const +{ + return (&arg == this) || (__builtin_strcmp (name (), arg.name ()) == 0); +} + +extern "C" void +__rtti_class (void *addr, const char *name, + const __class_type_info::base_info *bl, size_t bn) +{ new (addr) __class_type_info (name, bl, bn); } + +extern "C" void +__rtti_si (void *addr, const char *n, const std::type_info *ti) +{ + new (addr) __si_type_info + (n, static_cast <const __user_type_info &> (*ti)); +} + +extern "C" void +__rtti_user (void *addr, const char *name) +{ new (addr) __user_type_info (name); } + +// Upcast for catch checking. OBJPTR points to the thrown object and might be +// NULL. Return 0 on failure, non-zero on success. Set *ADJPTR to adjusted +// object pointer. +int __user_type_info:: +upcast (const type_info &target, void *objptr, + void **adjptr) const +{ + upcast_result result; + + if (do_upcast (contained_public, target, objptr, result)) + return 0; + *adjptr = result.target_obj; + return contained_public_p (result.whole2target); +} + +// Down or cross cast for dynamic_cast. OBJPTR points to the most derrived +// object, SUBPTR points to the static base object. Both must not be NULL. +// TARGET specifies the desired target type, SUBTYPE specifies the static +// type. Both must be defined. Returns adjusted object pointer on success, +// NULL on failure. [expr.dynamic.cast]/8 says 'unambiguous public base'. This +// itself is an ambiguous statement. We choose it to mean the base must be +// separately unambiguous and public, rather than unambiguous considering only +// public bases. +void *__user_type_info:: +dyncast (int boff, + const type_info &target, void *objptr, + const type_info &subtype, void *subptr) const +{ + dyncast_result result; + + do_dyncast (boff, contained_public, + target, objptr, subtype, subptr, result); + if (!result.target_obj) + return NULL; + if (contained_public_p (result.target2sub)) + return result.target_obj; + if (contained_public_p (sub_kind (result.whole2sub & result.whole2target))) + // Found a valid cross cast + return result.target_obj; + if (contained_nonvirtual_p (result.whole2sub)) + // Found an invalid cross cast, which cannot also be a down cast + return NULL; + if (result.target2sub == unknown) + result.target2sub = static_cast <const __user_type_info &> (target) + .find_public_subobj (boff, subtype, + result.target_obj, subptr); + if (contained_public_p (result.target2sub)) + // Found a valid down cast + return result.target_obj; + // Must be an invalid down cast, or the cross cast wasn't bettered + return NULL; +} + +// Catch cast helper. ACCESS_PATH is the access from the complete thrown +// object to this base. TARGET is the desired type we want to catch. OBJPTR +// points to this base within the throw object, it might be NULL. Fill in +// RESULT with what we find. Return true, should we determine catch must fail. +bool __user_type_info:: +do_upcast (sub_kind access_path, + const type_info &target, void *objptr, + upcast_result &__restrict result) const +{ + if (*this == target) + { + result.target_obj = objptr; + result.base_type = nonvirtual_base_type; + result.whole2target = access_path; + return contained_nonpublic_p (access_path); + } + return false; +} + +// dynamic cast helper. ACCESS_PATH gives the access from the most derived +// object to this base. TARGET indicates the desired type we want. OBJPTR +// points to this base within the object. SUBTYPE indicates the static type +// started from and SUBPTR points to that base within the most derived object. +// Fill in RESULT with what we find. Return true if we have located an +// ambiguous match. +bool __user_type_info:: +do_dyncast (int, sub_kind access_path, + const type_info &target, void *objptr, + const type_info &subtype, void *subptr, + dyncast_result &__restrict result) const +{ + if (objptr == subptr && *this == subtype) + { + // The subobject we started from. Indicate how we are accessible from + // the most derived object. + result.whole2sub = access_path; + return false; + } + if (*this == target) + { + result.target_obj = objptr; + result.whole2target = access_path; + result.target2sub = not_contained; + return false; + } + return false; +} + +// find_public_subobj helper. Return contained_public if we are the desired +// subtype. OBJPTR points to this base type, SUBPTR points to the desired base +// object. +__user_type_info::sub_kind __user_type_info:: +do_find_public_subobj (int, const type_info &, void *objptr, void *subptr) const +{ + if (subptr == objptr) + // Must be our type, as the pointers match. + return contained_public; + return not_contained; +} + +// catch helper for single public inheritance types. See +// __user_type_info::do_upcast for semantics. +bool __si_type_info:: +do_upcast (sub_kind access_path, + const type_info &target, void *objptr, + upcast_result &__restrict result) const +{ + if (*this == target) + { + result.target_obj = objptr; + result.base_type = nonvirtual_base_type; + result.whole2target = access_path; + return contained_nonpublic_p (access_path); + } + return base.do_upcast (access_path, target, objptr, result); +} + +// dynamic cast helper for single public inheritance types. See +// __user_type_info::do_dyncast for semantics. BOFF indicates how SUBTYPE +// types are inherited by TARGET types. +bool __si_type_info:: +do_dyncast (int boff, sub_kind access_path, + const type_info &target, void *objptr, + const type_info &subtype, void *subptr, + dyncast_result &__restrict result) const +{ + if (objptr == subptr && *this == subtype) + { + // The subobject we started from. Indicate how we are accessible from + // the most derived object. + result.whole2sub = access_path; + return false; + } + if (*this == target) + { + result.target_obj = objptr; + result.whole2target = access_path; + if (boff >= 0) + result.target2sub = ((char *)subptr - (char *)objptr) == boff + ? contained_public : not_contained; + else if (boff == -2) + result.target2sub = not_contained; + return false; + } + return base.do_dyncast (boff, access_path, + target, objptr, subtype, subptr, result); +} + +// find_public_subobj helper. See __user_type_info::do_find_public_subobj or +// semantics. BOFF indicates how SUBTYPE types are inherited by the original +// target object. +__user_type_info::sub_kind __si_type_info:: +do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *subptr) const +{ + if (subptr == objptr && subtype == *this) + return contained_public; + return base.do_find_public_subobj (boff, subtype, objptr, subptr); +} + +// catch helper for multiple or non-public inheritance types. See +// __user_type_info::do_upcast for semantics. +bool __class_type_info:: +do_upcast (sub_kind access_path, + const type_info &target, void *objptr, + upcast_result &__restrict result) const +{ + if (*this == target) + { + result.target_obj = objptr; + result.base_type = nonvirtual_base_type; + result.whole2target = access_path; + return contained_nonpublic_p (access_path); + } + + for (size_t i = n_bases; i--;) + { + upcast_result result2; + void *p = objptr; + sub_kind sub_access = access_path; + p = convert_to_base (p, + base_list[i].is_virtual, + base_list[i].offset); + if (base_list[i].is_virtual) + sub_access = sub_kind (sub_access | contained_virtual_mask); + if (base_list[i].access != PUBLIC) + sub_access = sub_kind (sub_access & ~contained_public_mask); + if (base_list[i].base->do_upcast (sub_access, target, p, result2) + && !contained_virtual_p (result2.whole2target)) + return true; // must fail + if (result2.base_type) + { + if (result2.base_type == nonvirtual_base_type + && base_list[i].is_virtual) + result2.base_type = base_list[i].base; + if (!result.base_type) + result = result2; + else if (result.target_obj != result2.target_obj) + { + // Found an ambiguity. + result.target_obj = NULL; + result.whole2target = contained_ambig; + return true; + } + else if (result.target_obj) + { + // Ok, found real object via a virtual path. + result.whole2target + = sub_kind (result.whole2target | result2.whole2target); + } + else + { + // Dealing with a null pointer, need to check vbase + // containing each of the two choices. + if (result2.base_type == nonvirtual_base_type + || result.base_type == nonvirtual_base_type + || !(*result2.base_type == *result.base_type)) + { + // Already ambiguous, not virtual or via different virtuals. + // Cannot match. + result.whole2target = contained_ambig; + return true; + } + result.whole2target + = sub_kind (result.whole2target | result2.whole2target); + } + } + } + return false; +} + +// dynamic cast helper for non-public or multiple inheritance types. See +// __user_type_info::do_dyncast for overall semantics. +// This is a big hairy function. Although the run-time behaviour of +// dynamic_cast is simple to describe, it gives rise to some non-obvious +// behaviour. We also desire to determine as early as possible any definite +// answer we can get. Because it is unknown what the run-time ratio of +// succeeding to failing dynamic casts is, we do not know in which direction +// to bias any optimizations. To that end we make no particular effort towards +// early fail answers or early success answers. Instead we try to minimize +// work by filling in things lazily (when we know we need the information), +// and opportunisticly take early success or failure results. +bool __class_type_info:: +do_dyncast (int boff, sub_kind access_path, + const type_info &target, void *objptr, + const type_info &subtype, void *subptr, + dyncast_result &__restrict result) const +{ + if (objptr == subptr && *this == subtype) + { + // The subobject we started from. Indicate how we are accessible from + // the most derived object. + result.whole2sub = access_path; + return false; + } + if (*this == target) + { + result.target_obj = objptr; + result.whole2target = access_path; + if (boff >= 0) + result.target2sub = ((char *)subptr - (char *)objptr) == boff + ? contained_public : not_contained; + else if (boff == -2) + result.target2sub = not_contained; + return false; + } + bool result_ambig = false; + for (size_t i = n_bases; i--;) + { + dyncast_result result2; + void *p; + sub_kind sub_access = access_path; + p = convert_to_base (objptr, + base_list[i].is_virtual, + base_list[i].offset); + if (base_list[i].is_virtual) + sub_access = sub_kind (sub_access | contained_virtual_mask); + if (base_list[i].access != PUBLIC) + sub_access = sub_kind (sub_access & ~contained_public_mask); + + bool result2_ambig + = base_list[i].base->do_dyncast (boff, sub_access, + target, p, subtype, subptr, result2); + result.whole2sub = sub_kind (result.whole2sub | result2.whole2sub); + if (result2.target2sub == contained_public + || result2.target2sub == contained_ambig) + { + result.target_obj = result2.target_obj; + result.whole2target = result2.whole2target; + result.target2sub = result2.target2sub; + // Found a downcast which can't be bettered or an ambiguous downcast + // which can't be disambiguated + return result2_ambig; + } + + if (!result_ambig && !result.target_obj) + { + // Not found anything yet. + result.target_obj = result2.target_obj; + result.whole2target = result2.whole2target; + result_ambig = result2_ambig; + } + else if (result.target_obj && result.target_obj == result2.target_obj) + { + // Found at same address, must be via virtual. Pick the most + // accessible path. + result.whole2target = + sub_kind (result.whole2target | result2.whole2target); + } + else if ((result.target_obj && result2.target_obj) + || (result_ambig && result2.target_obj) + || (result2_ambig && result.target_obj)) + { + // Found two different TARGET bases, or a valid one and a set of + // ambiguous ones, must disambiguate. See whether SUBOBJ is + // contained publicly within one of the non-ambiguous choices. + // If it is in only one, then that's the choice. If it is in + // both, then we're ambiguous and fail. If it is in neither, + // we're ambiguous, but don't yet fail as we might later find a + // third base which does contain SUBPTR. + + sub_kind new_sub_kind = result2.target2sub; + sub_kind old_sub_kind = result.target2sub; + + if (contained_nonvirtual_p (result.whole2sub)) + { + // We already found SUBOBJ as a non-virtual base of most + // derived. Therefore if it is in either choice, it can only be + // in one of them, and we will already know. + if (old_sub_kind == unknown) + old_sub_kind = not_contained; + if (new_sub_kind == unknown) + new_sub_kind = not_contained; + } + else + { + const __user_type_info &t = + static_cast <const __user_type_info &> (target); + + if (old_sub_kind >= not_contained) + ;// already calculated + else if (contained_nonvirtual_p (new_sub_kind)) + // Already found non-virtually inside the other choice, + // cannot be in this. + old_sub_kind = not_contained; + else + old_sub_kind = t.find_public_subobj (boff, subtype, + result.target_obj, subptr); + + if (new_sub_kind >= not_contained) + ;// already calculated + else if (contained_nonvirtual_p (old_sub_kind)) + // Already found non-virtually inside the other choice, + // cannot be in this. + new_sub_kind = not_contained; + else + new_sub_kind = t.find_public_subobj (boff, subtype, + result2.target_obj, subptr); + } + + // Neither sub_kind can be contained_ambig -- we bail out early + // when we find those. + if (contained_p (sub_kind (new_sub_kind ^ old_sub_kind))) + { + // Only on one choice, not ambiguous. + if (contained_p (new_sub_kind)) + { + // Only in new. + result.target_obj = result2.target_obj; + result.whole2target = result2.whole2target; + result_ambig = false; + old_sub_kind = new_sub_kind; + } + result.target2sub = old_sub_kind; + if (result.target2sub == contained_public) + return false; // Can't be an ambiguating downcast for later discovery. + } + else if (contained_p (sub_kind (new_sub_kind & old_sub_kind))) + { + // In both. + result.target_obj = NULL; + result.target2sub = contained_ambig; + return true; // Fail. + } + else + { + // In neither publicly, ambiguous for the moment, but keep + // looking. It is possible that it was private in one or + // both and therefore we should fail, but that's just tough. + result.target_obj = NULL; + result.target2sub = not_contained; + result_ambig = true; + } + } + + if (result.whole2sub == contained_private) + // We found SUBOBJ as a private non-virtual base, therefore all + // cross casts will fail. We have already found a down cast, if + // there is one. + return result_ambig; + } + + return result_ambig; +} + +// find_public_subobj helper for non-public or multiple inheritance types. See +// __user_type_info::do_find_public_subobj for semantics. We make use of BOFF +// to prune the base class walk. +__user_type_info::sub_kind __class_type_info:: +do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *subptr) const +{ + if (objptr == subptr && subtype == *this) + return contained_public; + + for (size_t i = n_bases; i--;) + { + if (base_list[i].access != PUBLIC) + continue; // Not public, can't be here. + void *p; + + if (base_list[i].is_virtual && boff == -3) + // Not a virtual base, so can't be here. + continue; + + p = convert_to_base (objptr, + base_list[i].is_virtual, + base_list[i].offset); + + sub_kind base_kind = base_list[i].base->do_find_public_subobj + (boff, subtype, p, subptr); + if (contained_p (base_kind)) + { + if (base_list[i].is_virtual) + base_kind = sub_kind (base_kind | contained_virtual_mask); + return base_kind; + } + } + + return not_contained; +} +#else +// new abi + +namespace std { + +// return true if this is a type_info for a pointer type +bool type_info:: +__is_pointer_p () const +{ + return false; +} + +// return true if this is a type_info for a function type +bool type_info:: +__is_function_p () const +{ + return false; +} + +// try and catch a thrown object. +bool type_info:: +__do_catch (const type_info *thr_type, void **, unsigned) const +{ + return *this == *thr_type; +} + +// upcast from this type to the target. __class_type_info will override +bool type_info:: +__do_upcast (const abi::__class_type_info *, void **) const +{ + return false; +} + +}; + +namespace { + +using namespace std; +using namespace abi; + +// initial part of a vtable, this structure is used with offsetof, so we don't +// have to keep alignments consistent manually. +struct vtable_prefix { + ptrdiff_t whole_object; // offset to most derived object + const __class_type_info *whole_type; // pointer to most derived type_info + const void *origin; // what a class's vptr points to +}; + +template <typename T> +inline const T * +adjust_pointer (const void *base, ptrdiff_t offset) +{ + return reinterpret_cast <const T *> + (reinterpret_cast <const char *> (base) + offset); +} + +// ADDR is a pointer to an object. Convert it to a pointer to a base, +// using OFFSET. IS_VIRTUAL is true, if we are getting a virtual base. +inline void const * +convert_to_base (void const *addr, bool is_virtual, ptrdiff_t offset) +{ + if (is_virtual) + { + const void *vtable = *static_cast <const void *const *> (addr); + + offset = *adjust_pointer<ptrdiff_t> (vtable, offset); + } + + return adjust_pointer<void> (addr, offset); +} + +// some predicate functions for __class_type_info::__sub_kind +inline bool contained_p (__class_type_info::__sub_kind access_path) +{ + return access_path >= __class_type_info::__contained_mask; +} +inline bool public_p (__class_type_info::__sub_kind access_path) +{ + return access_path & __class_type_info::__contained_public_mask; +} +inline bool virtual_p (__class_type_info::__sub_kind access_path) +{ + return (access_path & __class_type_info::__contained_virtual_mask); +} +inline bool contained_public_p (__class_type_info::__sub_kind access_path) +{ + return ((access_path & __class_type_info::__contained_public) + == __class_type_info::__contained_public); +} +inline bool contained_nonpublic_p (__class_type_info::__sub_kind access_path) +{ + return ((access_path & __class_type_info::__contained_public) + == __class_type_info::__contained_mask); +} +inline bool contained_nonvirtual_p (__class_type_info::__sub_kind access_path) +{ + return ((access_path & (__class_type_info::__contained_mask + | __class_type_info::__contained_virtual_mask)) + == __class_type_info::__contained_mask); +} + +static const __class_type_info *const nonvirtual_base_type = + static_cast <const __class_type_info *> (0) + 1; + +}; // namespace + +namespace __cxxabiv1 +{ + +__class_type_info:: +~__class_type_info () +{} + +__si_class_type_info:: +~__si_class_type_info () +{} + +__vmi_class_type_info:: +~__vmi_class_type_info () +{} + +// __upcast_result is used to hold information during traversal of a class +// heirarchy when catch matching. +struct __class_type_info::__upcast_result +{ + const void *dst_ptr; // pointer to caught object + __sub_kind part2dst; // path from current base to target + int src_details; // hints about the source type heirarchy + const __class_type_info *base_type; // where we found the target, + // if in vbase the __class_type_info of vbase + // if a non-virtual base then 1 + // else NULL + public: + __upcast_result (int d) + :dst_ptr (NULL), part2dst (__unknown), src_details (d), base_type (NULL) + {} +}; + +// __dyncast_result is used to hold information during traversal of a class +// heirarchy when dynamic casting. +struct __class_type_info::__dyncast_result +{ + const void *dst_ptr; // pointer to target object or NULL + __sub_kind whole2dst; // path from most derived object to target + __sub_kind whole2src; // path from most derived object to sub object + __sub_kind dst2src; // path from target to sub object + int whole_details; // details of the whole class heirarchy + + public: + __dyncast_result (int details_ = __vmi_class_type_info::__flags_unknown_mask) + :dst_ptr (NULL), whole2dst (__unknown), + whole2src (__unknown), dst2src (__unknown), + whole_details (details_) + {} +}; + +bool __class_type_info:: +__do_catch (const type_info *thr_type, + void **thr_obj, + unsigned outer) const +{ + if (*this == *thr_type) + return true; + if (outer >= 4) + // Neither `A' nor `A *'. + return false; + return thr_type->__do_upcast (this, thr_obj); +} + +bool __class_type_info:: +__do_upcast (const __class_type_info *dst_type, + void **obj_ptr) const +{ + __upcast_result result (__vmi_class_type_info::__flags_unknown_mask); + + __do_upcast (dst_type, *obj_ptr, result); + if (!contained_public_p (result.part2dst)) + return false; + *obj_ptr = const_cast <void *> (result.dst_ptr); + return true; +} + +inline __class_type_info::__sub_kind __class_type_info:: +__find_public_src (ptrdiff_t src2dst, + const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr) const +{ + if (src2dst >= 0) + return adjust_pointer <void> (obj_ptr, src2dst) == src_ptr + ? __contained_public : __not_contained; + if (src2dst == -2) + return __not_contained; + return __do_find_public_src (src2dst, obj_ptr, src_type, src_ptr); +} + +__class_type_info::__sub_kind __class_type_info:: +__do_find_public_src (ptrdiff_t, + const void *obj_ptr, + const __class_type_info *, + const void *src_ptr) const +{ + if (src_ptr == obj_ptr) + // Must be our type, as the pointers match. + return __contained_public; + return __not_contained; +} + +__class_type_info::__sub_kind __si_class_type_info:: +__do_find_public_src (ptrdiff_t src2dst, + const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr) const +{ + if (src_ptr == obj_ptr && *this == *src_type) + return __contained_public; + return __base_type->__do_find_public_src (src2dst, obj_ptr, src_type, src_ptr); +} + +__class_type_info::__sub_kind __vmi_class_type_info:: +__do_find_public_src (ptrdiff_t src2dst, + const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr) const +{ + if (obj_ptr == src_ptr && *this == *src_type) + return __contained_public; + + for (size_t i = __base_count; i--;) + { + if (!__base_info[i].__is_public_p ()) + continue; // Not public, can't be here. + + const void *base = obj_ptr; + ptrdiff_t offset = __base_info[i].__offset (); + bool is_virtual = __base_info[i].__is_virtual_p (); + + if (is_virtual) + { + if (src2dst == -3) + continue; // Not a virtual base, so can't be here. + } + base = convert_to_base (base, is_virtual, offset); + + __sub_kind base_kind = __base_info[i].__base->__do_find_public_src + (src2dst, base, src_type, src_ptr); + if (contained_p (base_kind)) + { + if (is_virtual) + base_kind = __sub_kind (base_kind | __contained_virtual_mask); + return base_kind; + } + } + + return __not_contained; +} + +bool __class_type_info:: +__do_dyncast (ptrdiff_t, + __sub_kind access_path, + const __class_type_info *dst_type, + const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr, + __dyncast_result &__restrict result) const +{ + if (obj_ptr == src_ptr && *this == *src_type) + { + // The src object we started from. Indicate how we are accessible from + // the most derived object. + result.whole2src = access_path; + return false; + } + if (*this == *dst_type) + { + result.dst_ptr = obj_ptr; + result.whole2dst = access_path; + result.dst2src = __not_contained; + return false; + } + return false; +} + +bool __si_class_type_info:: +__do_dyncast (ptrdiff_t src2dst, + __sub_kind access_path, + const __class_type_info *dst_type, + const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr, + __dyncast_result &__restrict result) const +{ + if (*this == *dst_type) + { + result.dst_ptr = obj_ptr; + result.whole2dst = access_path; + if (src2dst >= 0) + result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr + ? __contained_public : __not_contained; + else if (src2dst == -2) + result.dst2src = __not_contained; + return false; + } + if (obj_ptr == src_ptr && *this == *src_type) + { + // The src object we started from. Indicate how we are accessible from + // the most derived object. + result.whole2src = access_path; + return false; + } + return __base_type->__do_dyncast (src2dst, access_path, dst_type, obj_ptr, + src_type, src_ptr, result); +} + +// This is a big hairy function. Although the run-time behaviour of +// dynamic_cast is simple to describe, it gives rise to some non-obvious +// behaviour. We also desire to determine as early as possible any definite +// answer we can get. Because it is unknown what the run-time ratio of +// succeeding to failing dynamic casts is, we do not know in which direction +// to bias any optimizations. To that end we make no particular effort towards +// early fail answers or early success answers. Instead we try to minimize +// work by filling in things lazily (when we know we need the information), +// and opportunisticly take early success or failure results. +bool __vmi_class_type_info:: +__do_dyncast (ptrdiff_t src2dst, + __sub_kind access_path, + const __class_type_info *dst_type, + const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr, + __dyncast_result &__restrict result) const +{ + if (result.whole_details & __flags_unknown_mask) + result.whole_details = __flags; + + if (obj_ptr == src_ptr && *this == *src_type) + { + // The src object we started from. Indicate how we are accessible from + // the most derived object. + result.whole2src = access_path; + return false; + } + if (*this == *dst_type) + { + result.dst_ptr = obj_ptr; + result.whole2dst = access_path; + if (src2dst >= 0) + result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr + ? __contained_public : __not_contained; + else if (src2dst == -2) + result.dst2src = __not_contained; + return false; + } + + bool result_ambig = false; + for (size_t i = __base_count; i--;) + { + __dyncast_result result2 (result.whole_details); + void const *base = obj_ptr; + __sub_kind base_access = access_path; + ptrdiff_t offset = __base_info[i].__offset (); + bool is_virtual = __base_info[i].__is_virtual_p (); + + if (is_virtual) + base_access = __sub_kind (base_access | __contained_virtual_mask); + base = convert_to_base (base, is_virtual, offset); + + if (!__base_info[i].__is_public_p ()) + { + if (src2dst == -2 && + !(result.whole_details + & (__non_diamond_repeat_mask | __diamond_shaped_mask))) + // The hierarchy has no duplicate bases (which might ambiguate + // things) and where we started is not a public base of what we + // want (so it cannot be a downcast). There is nothing of interest + // hiding in a non-public base. + continue; + base_access = __sub_kind (base_access & ~__contained_public_mask); + } + + bool result2_ambig + = __base_info[i].__base->__do_dyncast (src2dst, base_access, + dst_type, base, + src_type, src_ptr, result2); + result.whole2src = __sub_kind (result.whole2src | result2.whole2src); + if (result2.dst2src == __contained_public + || result2.dst2src == __contained_ambig) + { + result.dst_ptr = result2.dst_ptr; + result.whole2dst = result2.whole2dst; + result.dst2src = result2.dst2src; + // Found a downcast which can't be bettered or an ambiguous downcast + // which can't be disambiguated + return result2_ambig; + } + + if (!result_ambig && !result.dst_ptr) + { + // Not found anything yet. + result.dst_ptr = result2.dst_ptr; + result.whole2dst = result2.whole2dst; + result_ambig = result2_ambig; + if (result.dst_ptr && result.whole2src != __unknown + && !(__flags & __non_diamond_repeat_mask)) + // Found dst and src and we don't have repeated bases. + return result_ambig; + } + else if (result.dst_ptr && result.dst_ptr == result2.dst_ptr) + { + // Found at same address, must be via virtual. Pick the most + // accessible path. + result.whole2dst = + __sub_kind (result.whole2dst | result2.whole2dst); + } + else if ((result.dst_ptr != 0 | result_ambig) + && (result2.dst_ptr != 0 | result2_ambig)) + { + // Found two different DST_TYPE bases, or a valid one and a set of + // ambiguous ones, must disambiguate. See whether SRC_PTR is + // contained publicly within one of the non-ambiguous choices. If it + // is in only one, then that's the choice. If it is in both, then + // we're ambiguous and fail. If it is in neither, we're ambiguous, + // but don't yet fail as we might later find a third base which does + // contain SRC_PTR. + + __sub_kind new_sub_kind = result2.dst2src; + __sub_kind old_sub_kind = result.dst2src; + + if (contained_p (result.whole2src) + && (!virtual_p (result.whole2src) + || !(result.whole_details & __diamond_shaped_mask))) + { + // We already found SRC_PTR as a base of most derived, and + // either it was non-virtual, or the whole heirarchy is + // not-diamond shaped. Therefore if it is in either choice, it + // can only be in one of them, and we will already know. + if (old_sub_kind == __unknown) + old_sub_kind = __not_contained; + if (new_sub_kind == __unknown) + new_sub_kind = __not_contained; + } + else + { + if (old_sub_kind >= __not_contained) + ;// already calculated + else if (contained_p (new_sub_kind) + && (!virtual_p (new_sub_kind) + || !(__flags & __diamond_shaped_mask))) + // Already found inside the other choice, and it was + // non-virtual or we are not diamond shaped. + old_sub_kind = __not_contained; + else + old_sub_kind = dst_type->__find_public_src + (src2dst, result.dst_ptr, src_type, src_ptr); + + if (new_sub_kind >= __not_contained) + ;// already calculated + else if (contained_p (old_sub_kind) + && (!virtual_p (old_sub_kind) + || !(__flags & __diamond_shaped_mask))) + // Already found inside the other choice, and it was + // non-virtual or we are not diamond shaped. + new_sub_kind = __not_contained; + else + new_sub_kind = dst_type->__find_public_src + (src2dst, result2.dst_ptr, src_type, src_ptr); + } + + // Neither sub_kind can be contained_ambig -- we bail out early + // when we find those. + if (contained_p (__sub_kind (new_sub_kind ^ old_sub_kind))) + { + // Only on one choice, not ambiguous. + if (contained_p (new_sub_kind)) + { + // Only in new. + result.dst_ptr = result2.dst_ptr; + result.whole2dst = result2.whole2dst; + result_ambig = false; + old_sub_kind = new_sub_kind; + } + result.dst2src = old_sub_kind; + if (public_p (result.dst2src)) + return false; // Can't be an ambiguating downcast for later discovery. + if (!virtual_p (result.dst2src)) + return false; // Found non-virtually can't be bettered + } + else if (contained_p (__sub_kind (new_sub_kind & old_sub_kind))) + { + // In both. + result.dst_ptr = NULL; + result.dst2src = __contained_ambig; + return true; // Fail. + } + else + { + // In neither publicly, ambiguous for the moment, but keep + // looking. It is possible that it was private in one or + // both and therefore we should fail, but that's just tough. + result.dst_ptr = NULL; + result.dst2src = __not_contained; + result_ambig = true; + } + } + + if (result.whole2src == __contained_private) + // We found SRC_PTR as a private non-virtual base, therefore all + // cross casts will fail. We have already found a down cast, if + // there is one. + return result_ambig; + } + + return result_ambig; +} + +bool __class_type_info:: +__do_upcast (const __class_type_info *dst, const void *obj, + __upcast_result &__restrict result) const +{ + if (*this == *dst) + { + result.dst_ptr = obj; + result.base_type = nonvirtual_base_type; + result.part2dst = __contained_public; + return true; + } + return false; +} + +bool __si_class_type_info:: +__do_upcast (const __class_type_info *dst, const void *obj_ptr, + __upcast_result &__restrict result) const +{ + if (__class_type_info::__do_upcast (dst, obj_ptr, result)) + return true; + + return __base_type->__do_upcast (dst, obj_ptr, result); +} + +bool __vmi_class_type_info:: +__do_upcast (const __class_type_info *dst, const void *obj_ptr, + __upcast_result &__restrict result) const +{ + if (__class_type_info::__do_upcast (dst, obj_ptr, result)) + return true; + + int src_details = result.src_details; + if (src_details & __flags_unknown_mask) + src_details = __flags; + + for (size_t i = __base_count; i--;) + { + __upcast_result result2 (src_details); + const void *base = obj_ptr; + ptrdiff_t offset = __base_info[i].__offset (); + bool is_virtual = __base_info[i].__is_virtual_p (); + bool is_public = __base_info[i].__is_public_p (); + + if (!is_public && !(src_details & __non_diamond_repeat_mask)) + // original cannot have an ambiguous base, so skip private bases + continue; + + if (base) + base = convert_to_base (base, is_virtual, offset); + + if (__base_info[i].__base->__do_upcast (dst, base, result2)) + { + if (result2.base_type == nonvirtual_base_type && is_virtual) + result2.base_type = __base_info[i].__base; + if (contained_p (result2.part2dst) && !is_public) + result2.part2dst = __sub_kind (result2.part2dst & ~__contained_public_mask); + + if (!result.base_type) + { + result = result2; + if (!contained_p (result.part2dst)) + return true; // found ambiguously + + if (result.part2dst & __contained_public_mask) + { + if (!(__flags & __non_diamond_repeat_mask)) + return true; // cannot have an ambiguous other base + } + else + { + if (!virtual_p (result.part2dst)) + return true; // cannot have another path + if (!(__flags & __diamond_shaped_mask)) + return true; // cannot have a more accessible path + } + } + else if (result.dst_ptr != result2.dst_ptr) + { + // Found an ambiguity. + result.dst_ptr = NULL; + result.part2dst = __contained_ambig; + return true; + } + else if (result.dst_ptr) + { + // Ok, found real object via a virtual path. + result.part2dst + = __sub_kind (result.part2dst | result2.part2dst); + } + else + { + // Dealing with a null pointer, need to check vbase + // containing each of the two choices. + if (result2.base_type == nonvirtual_base_type + || result.base_type == nonvirtual_base_type + || !(*result2.base_type == *result.base_type)) + { + // Already ambiguous, not virtual or via different virtuals. + // Cannot match. + result.part2dst = __contained_ambig; + return true; + } + result.part2dst + = __sub_kind (result.part2dst | result2.part2dst); + } + } + } + return result.part2dst != __unknown; +} + +// this is the external interface to the dynamic cast machinery +extern "C" void * +__dynamic_cast (const void *src_ptr, // object started from + const __class_type_info *src_type, // type of the starting object + const __class_type_info *dst_type, // desired target type + ptrdiff_t src2dst) // how src and dst are related +{ + const void *vtable = *static_cast <const void *const *> (src_ptr); + const vtable_prefix *prefix = + adjust_pointer <vtable_prefix> (vtable, + -offsetof (vtable_prefix, origin)); + const void *whole_ptr = + adjust_pointer <void> (src_ptr, prefix->whole_object); + const __class_type_info *whole_type = prefix->whole_type; + __class_type_info::__dyncast_result result; + + whole_type->__do_dyncast (src2dst, __class_type_info::__contained_public, + dst_type, whole_ptr, src_type, src_ptr, result); + if (!result.dst_ptr) + return NULL; + if (contained_public_p (result.dst2src)) + // Src is known to be a public base of dst. + return const_cast <void *> (result.dst_ptr); + if (contained_public_p (__class_type_info::__sub_kind (result.whole2src & result.whole2dst))) + // Both src and dst are known to be public bases of whole. Found a valid + // cross cast. + return const_cast <void *> (result.dst_ptr); + if (contained_nonvirtual_p (result.whole2src)) + // Src is known to be a non-public nonvirtual base of whole, and not a + // base of dst. Found an invalid cross cast, which cannot also be a down + // cast + return NULL; + if (result.dst2src == __class_type_info::__unknown) + result.dst2src = dst_type->__find_public_src (src2dst, result.dst_ptr, + src_type, src_ptr); + if (contained_public_p (result.dst2src)) + // Found a valid down cast + return const_cast <void *> (result.dst_ptr); + // Must be an invalid down cast, or the cross cast wasn't bettered + return NULL; +} + +}; // namespace __cxxabiv1 +#endif |