197403Sobrien// Methods for type_info for -*- C++ -*- Run Time Type Identification. 2169691Skan// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 3169691Skan// 2003, 2004, 2005, 2006, 2007 497403Sobrien// Free Software Foundation 597403Sobrien// 6132720Skan// This file is part of GCC. 797403Sobrien// 8132720Skan// GCC is free software; you can redistribute it and/or modify 997403Sobrien// it under the terms of the GNU General Public License as published by 1097403Sobrien// the Free Software Foundation; either version 2, or (at your option) 1197403Sobrien// any later version. 1297403Sobrien 13132720Skan// GCC is distributed in the hope that it will be useful, 1497403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1597403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1697403Sobrien// GNU General Public License for more details. 1797403Sobrien 1897403Sobrien// You should have received a copy of the GNU General Public License 19132720Skan// along with GCC; see the file COPYING. If not, write to 20169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 21169691Skan// Boston, MA 02110-1301, USA. 2297403Sobrien 2397403Sobrien// As a special exception, you may use this file as part of a free software 2497403Sobrien// library without restriction. Specifically, if other files instantiate 2597403Sobrien// templates or use macros or inline functions from this file, or you compile 2697403Sobrien// this file and link it with other files to produce an executable, this 2797403Sobrien// file does not by itself cause the resulting executable to be covered by 2897403Sobrien// the GNU General Public License. This exception does not however 2997403Sobrien// invalidate any other reasons why the executable file might be covered by 3097403Sobrien// the GNU General Public License. 3197403Sobrien 32117397Skan#include <bits/c++config.h> 3397403Sobrien#include <cstddef> 3497403Sobrien#include "tinfo.h" 3597403Sobrien#include "new" // for placement new 3697403Sobrien 3797403Sobrien// This file contains the minimal working set necessary to link with code 3897403Sobrien// that uses virtual functions and -frtti but does not actually use RTTI 3997403Sobrien// functionality. 4097403Sobrien 4197403Sobrienstd::type_info:: 4297403Sobrien~type_info () 4397403Sobrien{ } 4497403Sobrien 4597403Sobrienstd::bad_cast::~bad_cast() throw() { } 4697403Sobrienstd::bad_typeid::~bad_typeid() throw() { } 4797403Sobrien 48169691Skanconst char* 49169691Skanstd::bad_cast::what() const throw() 50169691Skan{ 51169691Skan return "std::bad_cast"; 52169691Skan} 53169691Skan 54169691Skanconst char* 55169691Skanstd::bad_typeid::what() const throw() 56169691Skan{ 57169691Skan return "std::bad_typeid"; 58169691Skan} 59169691Skan 6097403Sobrien#if !__GXX_MERGED_TYPEINFO_NAMES 6197403Sobrien 6297403Sobrien// We can't rely on common symbols being shared between shared objects. 6397403Sobrienbool std::type_info:: 6497403Sobrienoperator== (const std::type_info& arg) const 6597403Sobrien{ 6697403Sobrien return (&arg == this) || (__builtin_strcmp (name (), arg.name ()) == 0); 6797403Sobrien} 6897403Sobrien 6997403Sobrien#endif 7097403Sobrien 7197403Sobriennamespace std { 7297403Sobrien 7397403Sobrien// return true if this is a type_info for a pointer type 7497403Sobrienbool type_info:: 7597403Sobrien__is_pointer_p () const 7697403Sobrien{ 7797403Sobrien return false; 7897403Sobrien} 7997403Sobrien 8097403Sobrien// return true if this is a type_info for a function type 8197403Sobrienbool type_info:: 8297403Sobrien__is_function_p () const 8397403Sobrien{ 8497403Sobrien return false; 8597403Sobrien} 8697403Sobrien 8797403Sobrien// try and catch a thrown object. 8897403Sobrienbool type_info:: 8997403Sobrien__do_catch (const type_info *thr_type, void **, unsigned) const 9097403Sobrien{ 9197403Sobrien return *this == *thr_type; 9297403Sobrien} 9397403Sobrien 9497403Sobrien// upcast from this type to the target. __class_type_info will override 9597403Sobrienbool type_info:: 9697403Sobrien__do_upcast (const abi::__class_type_info *, void **) const 9797403Sobrien{ 9897403Sobrien return false; 9997403Sobrien} 10097403Sobrien 101132720Skan} 10297403Sobrien 10397403Sobriennamespace { 10497403Sobrien 10597403Sobrienusing namespace std; 10697403Sobrienusing namespace abi; 10797403Sobrien 108117397Skan// Initial part of a vtable, this structure is used with offsetof, so we don't 10997403Sobrien// have to keep alignments consistent manually. 110117397Skanstruct vtable_prefix 111117397Skan{ 112117397Skan // Offset to most derived object. 113117397Skan ptrdiff_t whole_object; 114117397Skan 115117397Skan // Additional padding if necessary. 116132720Skan#ifdef _GLIBCXX_VTABLE_PADDING 117117397Skan ptrdiff_t padding1; 118117397Skan#endif 119117397Skan 120117397Skan // Pointer to most derived type_info. 121117397Skan const __class_type_info *whole_type; 122117397Skan 123117397Skan // Additional padding if necessary. 124132720Skan#ifdef _GLIBCXX_VTABLE_PADDING 125117397Skan ptrdiff_t padding2; 126117397Skan#endif 127117397Skan 128117397Skan // What a class's vptr points to. 129117397Skan const void *origin; 13097403Sobrien}; 13197403Sobrien 13297403Sobrientemplate <typename T> 13397403Sobrieninline const T * 13497403Sobrienadjust_pointer (const void *base, ptrdiff_t offset) 13597403Sobrien{ 13697403Sobrien return reinterpret_cast <const T *> 13797403Sobrien (reinterpret_cast <const char *> (base) + offset); 13897403Sobrien} 13997403Sobrien 14097403Sobrien// ADDR is a pointer to an object. Convert it to a pointer to a base, 14197403Sobrien// using OFFSET. IS_VIRTUAL is true, if we are getting a virtual base. 14297403Sobrieninline void const * 14397403Sobrienconvert_to_base (void const *addr, bool is_virtual, ptrdiff_t offset) 14497403Sobrien{ 14597403Sobrien if (is_virtual) 14697403Sobrien { 14797403Sobrien const void *vtable = *static_cast <const void *const *> (addr); 14897403Sobrien 14997403Sobrien offset = *adjust_pointer<ptrdiff_t> (vtable, offset); 15097403Sobrien } 15197403Sobrien 15297403Sobrien return adjust_pointer<void> (addr, offset); 15397403Sobrien} 15497403Sobrien 15597403Sobrien// some predicate functions for __class_type_info::__sub_kind 15697403Sobrieninline bool contained_p (__class_type_info::__sub_kind access_path) 15797403Sobrien{ 15897403Sobrien return access_path >= __class_type_info::__contained_mask; 15997403Sobrien} 16097403Sobrieninline bool public_p (__class_type_info::__sub_kind access_path) 16197403Sobrien{ 16297403Sobrien return access_path & __class_type_info::__contained_public_mask; 16397403Sobrien} 16497403Sobrieninline bool virtual_p (__class_type_info::__sub_kind access_path) 16597403Sobrien{ 16697403Sobrien return (access_path & __class_type_info::__contained_virtual_mask); 16797403Sobrien} 16897403Sobrieninline bool contained_public_p (__class_type_info::__sub_kind access_path) 16997403Sobrien{ 17097403Sobrien return ((access_path & __class_type_info::__contained_public) 17197403Sobrien == __class_type_info::__contained_public); 17297403Sobrien} 17397403Sobrieninline bool contained_nonpublic_p (__class_type_info::__sub_kind access_path) 17497403Sobrien{ 17597403Sobrien return ((access_path & __class_type_info::__contained_public) 17697403Sobrien == __class_type_info::__contained_mask); 17797403Sobrien} 17897403Sobrieninline bool contained_nonvirtual_p (__class_type_info::__sub_kind access_path) 17997403Sobrien{ 18097403Sobrien return ((access_path & (__class_type_info::__contained_mask 18197403Sobrien | __class_type_info::__contained_virtual_mask)) 18297403Sobrien == __class_type_info::__contained_mask); 18397403Sobrien} 18497403Sobrien 18597403Sobrienstatic const __class_type_info *const nonvirtual_base_type = 18697403Sobrien static_cast <const __class_type_info *> (0) + 1; 18797403Sobrien 188132720Skan} // namespace 18997403Sobrien 19097403Sobriennamespace __cxxabiv1 19197403Sobrien{ 19297403Sobrien 19397403Sobrien__class_type_info:: 19497403Sobrien~__class_type_info () 19597403Sobrien{} 19697403Sobrien 19797403Sobrien__si_class_type_info:: 19897403Sobrien~__si_class_type_info () 19997403Sobrien{} 20097403Sobrien 20197403Sobrien__vmi_class_type_info:: 20297403Sobrien~__vmi_class_type_info () 20397403Sobrien{} 20497403Sobrien 20597403Sobrien// __upcast_result is used to hold information during traversal of a class 20697403Sobrien// hierarchy when catch matching. 20797403Sobrienstruct __class_type_info::__upcast_result 20897403Sobrien{ 20997403Sobrien const void *dst_ptr; // pointer to caught object 21097403Sobrien __sub_kind part2dst; // path from current base to target 21197403Sobrien int src_details; // hints about the source type hierarchy 21297403Sobrien const __class_type_info *base_type; // where we found the target, 21397403Sobrien // if in vbase the __class_type_info of vbase 21497403Sobrien // if a non-virtual base then 1 21597403Sobrien // else NULL 21697403Sobrien __upcast_result (int d) 21797403Sobrien :dst_ptr (NULL), part2dst (__unknown), src_details (d), base_type (NULL) 21897403Sobrien {} 21997403Sobrien}; 22097403Sobrien 22197403Sobrien// __dyncast_result is used to hold information during traversal of a class 22297403Sobrien// hierarchy when dynamic casting. 22397403Sobrienstruct __class_type_info::__dyncast_result 22497403Sobrien{ 22597403Sobrien const void *dst_ptr; // pointer to target object or NULL 22697403Sobrien __sub_kind whole2dst; // path from most derived object to target 22797403Sobrien __sub_kind whole2src; // path from most derived object to sub object 22897403Sobrien __sub_kind dst2src; // path from target to sub object 22997403Sobrien int whole_details; // details of the whole class hierarchy 23097403Sobrien 23197403Sobrien __dyncast_result (int details_ = __vmi_class_type_info::__flags_unknown_mask) 23297403Sobrien :dst_ptr (NULL), whole2dst (__unknown), 23397403Sobrien whole2src (__unknown), dst2src (__unknown), 23497403Sobrien whole_details (details_) 23597403Sobrien {} 236132720Skan 237132720Skanprotected: 238132720Skan __dyncast_result(const __dyncast_result&); 239132720Skan 240132720Skan __dyncast_result& 241132720Skan operator=(const __dyncast_result&); 24297403Sobrien}; 24397403Sobrien 24497403Sobrienbool __class_type_info:: 24597403Sobrien__do_catch (const type_info *thr_type, 24697403Sobrien void **thr_obj, 24797403Sobrien unsigned outer) const 24897403Sobrien{ 24997403Sobrien if (*this == *thr_type) 25097403Sobrien return true; 25197403Sobrien if (outer >= 4) 25297403Sobrien // Neither `A' nor `A *'. 25397403Sobrien return false; 25497403Sobrien return thr_type->__do_upcast (this, thr_obj); 25597403Sobrien} 25697403Sobrien 25797403Sobrienbool __class_type_info:: 25897403Sobrien__do_upcast (const __class_type_info *dst_type, 25997403Sobrien void **obj_ptr) const 26097403Sobrien{ 26197403Sobrien __upcast_result result (__vmi_class_type_info::__flags_unknown_mask); 26297403Sobrien 26397403Sobrien __do_upcast (dst_type, *obj_ptr, result); 26497403Sobrien if (!contained_public_p (result.part2dst)) 26597403Sobrien return false; 26697403Sobrien *obj_ptr = const_cast <void *> (result.dst_ptr); 26797403Sobrien return true; 26897403Sobrien} 26997403Sobrien 27097403Sobrieninline __class_type_info::__sub_kind __class_type_info:: 27197403Sobrien__find_public_src (ptrdiff_t src2dst, 27297403Sobrien const void *obj_ptr, 27397403Sobrien const __class_type_info *src_type, 27497403Sobrien const void *src_ptr) const 27597403Sobrien{ 27697403Sobrien if (src2dst >= 0) 27797403Sobrien return adjust_pointer <void> (obj_ptr, src2dst) == src_ptr 27897403Sobrien ? __contained_public : __not_contained; 27997403Sobrien if (src2dst == -2) 28097403Sobrien return __not_contained; 28197403Sobrien return __do_find_public_src (src2dst, obj_ptr, src_type, src_ptr); 28297403Sobrien} 28397403Sobrien 28497403Sobrien__class_type_info::__sub_kind __class_type_info:: 28597403Sobrien__do_find_public_src (ptrdiff_t, 28697403Sobrien const void *obj_ptr, 28797403Sobrien const __class_type_info *, 28897403Sobrien const void *src_ptr) const 28997403Sobrien{ 29097403Sobrien if (src_ptr == obj_ptr) 29197403Sobrien // Must be our type, as the pointers match. 29297403Sobrien return __contained_public; 29397403Sobrien return __not_contained; 29497403Sobrien} 29597403Sobrien 29697403Sobrien__class_type_info::__sub_kind __si_class_type_info:: 29797403Sobrien__do_find_public_src (ptrdiff_t src2dst, 29897403Sobrien const void *obj_ptr, 29997403Sobrien const __class_type_info *src_type, 30097403Sobrien const void *src_ptr) const 30197403Sobrien{ 30297403Sobrien if (src_ptr == obj_ptr && *this == *src_type) 30397403Sobrien return __contained_public; 30497403Sobrien return __base_type->__do_find_public_src (src2dst, obj_ptr, src_type, src_ptr); 30597403Sobrien} 30697403Sobrien 30797403Sobrien__class_type_info::__sub_kind __vmi_class_type_info:: 30897403Sobrien__do_find_public_src (ptrdiff_t src2dst, 30997403Sobrien const void *obj_ptr, 31097403Sobrien const __class_type_info *src_type, 31197403Sobrien const void *src_ptr) const 31297403Sobrien{ 31397403Sobrien if (obj_ptr == src_ptr && *this == *src_type) 31497403Sobrien return __contained_public; 31597403Sobrien 31697403Sobrien for (std::size_t i = __base_count; i--;) 31797403Sobrien { 31897403Sobrien if (!__base_info[i].__is_public_p ()) 31997403Sobrien continue; // Not public, can't be here. 32097403Sobrien 32197403Sobrien const void *base = obj_ptr; 32297403Sobrien ptrdiff_t offset = __base_info[i].__offset (); 32397403Sobrien bool is_virtual = __base_info[i].__is_virtual_p (); 32497403Sobrien 32597403Sobrien if (is_virtual) 32697403Sobrien { 32797403Sobrien if (src2dst == -3) 32897403Sobrien continue; // Not a virtual base, so can't be here. 32997403Sobrien } 33097403Sobrien base = convert_to_base (base, is_virtual, offset); 33197403Sobrien 332102782Skan __sub_kind base_kind = __base_info[i].__base_type->__do_find_public_src 33397403Sobrien (src2dst, base, src_type, src_ptr); 33497403Sobrien if (contained_p (base_kind)) 33597403Sobrien { 33697403Sobrien if (is_virtual) 33797403Sobrien base_kind = __sub_kind (base_kind | __contained_virtual_mask); 33897403Sobrien return base_kind; 33997403Sobrien } 34097403Sobrien } 34197403Sobrien 34297403Sobrien return __not_contained; 34397403Sobrien} 34497403Sobrien 34597403Sobrienbool __class_type_info:: 34697403Sobrien__do_dyncast (ptrdiff_t, 34797403Sobrien __sub_kind access_path, 34897403Sobrien const __class_type_info *dst_type, 34997403Sobrien const void *obj_ptr, 35097403Sobrien const __class_type_info *src_type, 35197403Sobrien const void *src_ptr, 35297403Sobrien __dyncast_result &__restrict result) const 35397403Sobrien{ 35497403Sobrien if (obj_ptr == src_ptr && *this == *src_type) 35597403Sobrien { 35697403Sobrien // The src object we started from. Indicate how we are accessible from 35797403Sobrien // the most derived object. 35897403Sobrien result.whole2src = access_path; 35997403Sobrien return false; 36097403Sobrien } 36197403Sobrien if (*this == *dst_type) 36297403Sobrien { 36397403Sobrien result.dst_ptr = obj_ptr; 36497403Sobrien result.whole2dst = access_path; 36597403Sobrien result.dst2src = __not_contained; 36697403Sobrien return false; 36797403Sobrien } 36897403Sobrien return false; 36997403Sobrien} 37097403Sobrien 37197403Sobrienbool __si_class_type_info:: 37297403Sobrien__do_dyncast (ptrdiff_t src2dst, 37397403Sobrien __sub_kind access_path, 37497403Sobrien const __class_type_info *dst_type, 37597403Sobrien const void *obj_ptr, 37697403Sobrien const __class_type_info *src_type, 37797403Sobrien const void *src_ptr, 37897403Sobrien __dyncast_result &__restrict result) const 37997403Sobrien{ 38097403Sobrien if (*this == *dst_type) 38197403Sobrien { 38297403Sobrien result.dst_ptr = obj_ptr; 38397403Sobrien result.whole2dst = access_path; 38497403Sobrien if (src2dst >= 0) 38597403Sobrien result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr 38697403Sobrien ? __contained_public : __not_contained; 38797403Sobrien else if (src2dst == -2) 38897403Sobrien result.dst2src = __not_contained; 38997403Sobrien return false; 39097403Sobrien } 39197403Sobrien if (obj_ptr == src_ptr && *this == *src_type) 39297403Sobrien { 39397403Sobrien // The src object we started from. Indicate how we are accessible from 39497403Sobrien // the most derived object. 39597403Sobrien result.whole2src = access_path; 39697403Sobrien return false; 39797403Sobrien } 39897403Sobrien return __base_type->__do_dyncast (src2dst, access_path, dst_type, obj_ptr, 39997403Sobrien src_type, src_ptr, result); 40097403Sobrien} 40197403Sobrien 40297403Sobrien// This is a big hairy function. Although the run-time behaviour of 40397403Sobrien// dynamic_cast is simple to describe, it gives rise to some non-obvious 40497403Sobrien// behaviour. We also desire to determine as early as possible any definite 40597403Sobrien// answer we can get. Because it is unknown what the run-time ratio of 40697403Sobrien// succeeding to failing dynamic casts is, we do not know in which direction 40797403Sobrien// to bias any optimizations. To that end we make no particular effort towards 40897403Sobrien// early fail answers or early success answers. Instead we try to minimize 40997403Sobrien// work by filling in things lazily (when we know we need the information), 41097403Sobrien// and opportunisticly take early success or failure results. 41197403Sobrienbool __vmi_class_type_info:: 41297403Sobrien__do_dyncast (ptrdiff_t src2dst, 41397403Sobrien __sub_kind access_path, 41497403Sobrien const __class_type_info *dst_type, 41597403Sobrien const void *obj_ptr, 41697403Sobrien const __class_type_info *src_type, 41797403Sobrien const void *src_ptr, 41897403Sobrien __dyncast_result &__restrict result) const 41997403Sobrien{ 42097403Sobrien if (result.whole_details & __flags_unknown_mask) 42197403Sobrien result.whole_details = __flags; 42297403Sobrien 42397403Sobrien if (obj_ptr == src_ptr && *this == *src_type) 42497403Sobrien { 42597403Sobrien // The src object we started from. Indicate how we are accessible from 42697403Sobrien // the most derived object. 42797403Sobrien result.whole2src = access_path; 42897403Sobrien return false; 42997403Sobrien } 43097403Sobrien if (*this == *dst_type) 43197403Sobrien { 43297403Sobrien result.dst_ptr = obj_ptr; 43397403Sobrien result.whole2dst = access_path; 43497403Sobrien if (src2dst >= 0) 43597403Sobrien result.dst2src = adjust_pointer <void> (obj_ptr, src2dst) == src_ptr 43697403Sobrien ? __contained_public : __not_contained; 43797403Sobrien else if (src2dst == -2) 43897403Sobrien result.dst2src = __not_contained; 43997403Sobrien return false; 44097403Sobrien } 44197403Sobrien 44297403Sobrien bool result_ambig = false; 44397403Sobrien for (std::size_t i = __base_count; i--;) 44497403Sobrien { 44597403Sobrien __dyncast_result result2 (result.whole_details); 44697403Sobrien void const *base = obj_ptr; 44797403Sobrien __sub_kind base_access = access_path; 44897403Sobrien ptrdiff_t offset = __base_info[i].__offset (); 44997403Sobrien bool is_virtual = __base_info[i].__is_virtual_p (); 45097403Sobrien 45197403Sobrien if (is_virtual) 45297403Sobrien base_access = __sub_kind (base_access | __contained_virtual_mask); 45397403Sobrien base = convert_to_base (base, is_virtual, offset); 45497403Sobrien 45597403Sobrien if (!__base_info[i].__is_public_p ()) 45697403Sobrien { 45797403Sobrien if (src2dst == -2 && 45897403Sobrien !(result.whole_details 45997403Sobrien & (__non_diamond_repeat_mask | __diamond_shaped_mask))) 46097403Sobrien // The hierarchy has no duplicate bases (which might ambiguate 46197403Sobrien // things) and where we started is not a public base of what we 46297403Sobrien // want (so it cannot be a downcast). There is nothing of interest 46397403Sobrien // hiding in a non-public base. 46497403Sobrien continue; 46597403Sobrien base_access = __sub_kind (base_access & ~__contained_public_mask); 46697403Sobrien } 46797403Sobrien 46897403Sobrien bool result2_ambig 469102782Skan = __base_info[i].__base_type->__do_dyncast (src2dst, base_access, 47097403Sobrien dst_type, base, 47197403Sobrien src_type, src_ptr, result2); 47297403Sobrien result.whole2src = __sub_kind (result.whole2src | result2.whole2src); 47397403Sobrien if (result2.dst2src == __contained_public 47497403Sobrien || result2.dst2src == __contained_ambig) 47597403Sobrien { 47697403Sobrien result.dst_ptr = result2.dst_ptr; 47797403Sobrien result.whole2dst = result2.whole2dst; 47897403Sobrien result.dst2src = result2.dst2src; 47997403Sobrien // Found a downcast which can't be bettered or an ambiguous downcast 48097403Sobrien // which can't be disambiguated 48197403Sobrien return result2_ambig; 48297403Sobrien } 48397403Sobrien 48497403Sobrien if (!result_ambig && !result.dst_ptr) 48597403Sobrien { 48697403Sobrien // Not found anything yet. 48797403Sobrien result.dst_ptr = result2.dst_ptr; 48897403Sobrien result.whole2dst = result2.whole2dst; 48997403Sobrien result_ambig = result2_ambig; 49097403Sobrien if (result.dst_ptr && result.whole2src != __unknown 49197403Sobrien && !(__flags & __non_diamond_repeat_mask)) 49297403Sobrien // Found dst and src and we don't have repeated bases. 49397403Sobrien return result_ambig; 49497403Sobrien } 49597403Sobrien else if (result.dst_ptr && result.dst_ptr == result2.dst_ptr) 49697403Sobrien { 49797403Sobrien // Found at same address, must be via virtual. Pick the most 49897403Sobrien // accessible path. 49997403Sobrien result.whole2dst = 50097403Sobrien __sub_kind (result.whole2dst | result2.whole2dst); 50197403Sobrien } 502241959Sdim else if ((result.dst_ptr != 0 && result2.dst_ptr != 0) 503241959Sdim || (result.dst_ptr != 0 && result2_ambig) 504241959Sdim || (result2.dst_ptr != 0 && result_ambig)) 50597403Sobrien { 50697403Sobrien // Found two different DST_TYPE bases, or a valid one and a set of 50797403Sobrien // ambiguous ones, must disambiguate. See whether SRC_PTR is 50897403Sobrien // contained publicly within one of the non-ambiguous choices. If it 50997403Sobrien // is in only one, then that's the choice. If it is in both, then 51097403Sobrien // we're ambiguous and fail. If it is in neither, we're ambiguous, 51197403Sobrien // but don't yet fail as we might later find a third base which does 51297403Sobrien // contain SRC_PTR. 51397403Sobrien 51497403Sobrien __sub_kind new_sub_kind = result2.dst2src; 51597403Sobrien __sub_kind old_sub_kind = result.dst2src; 51697403Sobrien 51797403Sobrien if (contained_p (result.whole2src) 51897403Sobrien && (!virtual_p (result.whole2src) 51997403Sobrien || !(result.whole_details & __diamond_shaped_mask))) 52097403Sobrien { 52197403Sobrien // We already found SRC_PTR as a base of most derived, and 52297403Sobrien // either it was non-virtual, or the whole hierarchy is 52397403Sobrien // not-diamond shaped. Therefore if it is in either choice, it 52497403Sobrien // can only be in one of them, and we will already know. 52597403Sobrien if (old_sub_kind == __unknown) 52697403Sobrien old_sub_kind = __not_contained; 52797403Sobrien if (new_sub_kind == __unknown) 52897403Sobrien new_sub_kind = __not_contained; 52997403Sobrien } 53097403Sobrien else 53197403Sobrien { 53297403Sobrien if (old_sub_kind >= __not_contained) 53397403Sobrien ;// already calculated 53497403Sobrien else if (contained_p (new_sub_kind) 53597403Sobrien && (!virtual_p (new_sub_kind) 53697403Sobrien || !(__flags & __diamond_shaped_mask))) 53797403Sobrien // Already found inside the other choice, and it was 53897403Sobrien // non-virtual or we are not diamond shaped. 53997403Sobrien old_sub_kind = __not_contained; 54097403Sobrien else 54197403Sobrien old_sub_kind = dst_type->__find_public_src 54297403Sobrien (src2dst, result.dst_ptr, src_type, src_ptr); 54397403Sobrien 54497403Sobrien if (new_sub_kind >= __not_contained) 54597403Sobrien ;// already calculated 54697403Sobrien else if (contained_p (old_sub_kind) 54797403Sobrien && (!virtual_p (old_sub_kind) 54897403Sobrien || !(__flags & __diamond_shaped_mask))) 54997403Sobrien // Already found inside the other choice, and it was 55097403Sobrien // non-virtual or we are not diamond shaped. 55197403Sobrien new_sub_kind = __not_contained; 55297403Sobrien else 55397403Sobrien new_sub_kind = dst_type->__find_public_src 55497403Sobrien (src2dst, result2.dst_ptr, src_type, src_ptr); 55597403Sobrien } 55697403Sobrien 55797403Sobrien // Neither sub_kind can be contained_ambig -- we bail out early 55897403Sobrien // when we find those. 55997403Sobrien if (contained_p (__sub_kind (new_sub_kind ^ old_sub_kind))) 56097403Sobrien { 56197403Sobrien // Only on one choice, not ambiguous. 56297403Sobrien if (contained_p (new_sub_kind)) 56397403Sobrien { 56497403Sobrien // Only in new. 56597403Sobrien result.dst_ptr = result2.dst_ptr; 56697403Sobrien result.whole2dst = result2.whole2dst; 56797403Sobrien result_ambig = false; 56897403Sobrien old_sub_kind = new_sub_kind; 56997403Sobrien } 57097403Sobrien result.dst2src = old_sub_kind; 57197403Sobrien if (public_p (result.dst2src)) 57297403Sobrien return false; // Can't be an ambiguating downcast for later discovery. 57397403Sobrien if (!virtual_p (result.dst2src)) 57497403Sobrien return false; // Found non-virtually can't be bettered 57597403Sobrien } 57697403Sobrien else if (contained_p (__sub_kind (new_sub_kind & old_sub_kind))) 57797403Sobrien { 57897403Sobrien // In both. 57997403Sobrien result.dst_ptr = NULL; 58097403Sobrien result.dst2src = __contained_ambig; 58197403Sobrien return true; // Fail. 58297403Sobrien } 58397403Sobrien else 58497403Sobrien { 58597403Sobrien // In neither publicly, ambiguous for the moment, but keep 58697403Sobrien // looking. It is possible that it was private in one or 58797403Sobrien // both and therefore we should fail, but that's just tough. 58897403Sobrien result.dst_ptr = NULL; 58997403Sobrien result.dst2src = __not_contained; 59097403Sobrien result_ambig = true; 59197403Sobrien } 59297403Sobrien } 59397403Sobrien 59497403Sobrien if (result.whole2src == __contained_private) 59597403Sobrien // We found SRC_PTR as a private non-virtual base, therefore all 59697403Sobrien // cross casts will fail. We have already found a down cast, if 59797403Sobrien // there is one. 59897403Sobrien return result_ambig; 59997403Sobrien } 60097403Sobrien 60197403Sobrien return result_ambig; 60297403Sobrien} 60397403Sobrien 60497403Sobrienbool __class_type_info:: 60597403Sobrien__do_upcast (const __class_type_info *dst, const void *obj, 60697403Sobrien __upcast_result &__restrict result) const 60797403Sobrien{ 60897403Sobrien if (*this == *dst) 60997403Sobrien { 61097403Sobrien result.dst_ptr = obj; 61197403Sobrien result.base_type = nonvirtual_base_type; 61297403Sobrien result.part2dst = __contained_public; 61397403Sobrien return true; 61497403Sobrien } 61597403Sobrien return false; 61697403Sobrien} 61797403Sobrien 61897403Sobrienbool __si_class_type_info:: 61997403Sobrien__do_upcast (const __class_type_info *dst, const void *obj_ptr, 62097403Sobrien __upcast_result &__restrict result) const 62197403Sobrien{ 62297403Sobrien if (__class_type_info::__do_upcast (dst, obj_ptr, result)) 62397403Sobrien return true; 62497403Sobrien 62597403Sobrien return __base_type->__do_upcast (dst, obj_ptr, result); 62697403Sobrien} 62797403Sobrien 62897403Sobrienbool __vmi_class_type_info:: 62997403Sobrien__do_upcast (const __class_type_info *dst, const void *obj_ptr, 63097403Sobrien __upcast_result &__restrict result) const 63197403Sobrien{ 63297403Sobrien if (__class_type_info::__do_upcast (dst, obj_ptr, result)) 63397403Sobrien return true; 63497403Sobrien 63597403Sobrien int src_details = result.src_details; 63697403Sobrien if (src_details & __flags_unknown_mask) 63797403Sobrien src_details = __flags; 63897403Sobrien 63997403Sobrien for (std::size_t i = __base_count; i--;) 64097403Sobrien { 64197403Sobrien __upcast_result result2 (src_details); 64297403Sobrien const void *base = obj_ptr; 64397403Sobrien ptrdiff_t offset = __base_info[i].__offset (); 64497403Sobrien bool is_virtual = __base_info[i].__is_virtual_p (); 64597403Sobrien bool is_public = __base_info[i].__is_public_p (); 64697403Sobrien 64797403Sobrien if (!is_public && !(src_details & __non_diamond_repeat_mask)) 64897403Sobrien // original cannot have an ambiguous base, so skip private bases 64997403Sobrien continue; 65097403Sobrien 65197403Sobrien if (base) 65297403Sobrien base = convert_to_base (base, is_virtual, offset); 65397403Sobrien 654102782Skan if (__base_info[i].__base_type->__do_upcast (dst, base, result2)) 65597403Sobrien { 65697403Sobrien if (result2.base_type == nonvirtual_base_type && is_virtual) 657102782Skan result2.base_type = __base_info[i].__base_type; 65897403Sobrien if (contained_p (result2.part2dst) && !is_public) 65997403Sobrien result2.part2dst = __sub_kind (result2.part2dst & ~__contained_public_mask); 66097403Sobrien 66197403Sobrien if (!result.base_type) 66297403Sobrien { 66397403Sobrien result = result2; 66497403Sobrien if (!contained_p (result.part2dst)) 66597403Sobrien return true; // found ambiguously 66697403Sobrien 66797403Sobrien if (result.part2dst & __contained_public_mask) 66897403Sobrien { 66997403Sobrien if (!(__flags & __non_diamond_repeat_mask)) 67097403Sobrien return true; // cannot have an ambiguous other base 67197403Sobrien } 67297403Sobrien else 67397403Sobrien { 67497403Sobrien if (!virtual_p (result.part2dst)) 67597403Sobrien return true; // cannot have another path 67697403Sobrien if (!(__flags & __diamond_shaped_mask)) 67797403Sobrien return true; // cannot have a more accessible path 67897403Sobrien } 67997403Sobrien } 68097403Sobrien else if (result.dst_ptr != result2.dst_ptr) 68197403Sobrien { 68297403Sobrien // Found an ambiguity. 68397403Sobrien result.dst_ptr = NULL; 68497403Sobrien result.part2dst = __contained_ambig; 68597403Sobrien return true; 68697403Sobrien } 68797403Sobrien else if (result.dst_ptr) 68897403Sobrien { 68997403Sobrien // Ok, found real object via a virtual path. 69097403Sobrien result.part2dst 69197403Sobrien = __sub_kind (result.part2dst | result2.part2dst); 69297403Sobrien } 69397403Sobrien else 69497403Sobrien { 69597403Sobrien // Dealing with a null pointer, need to check vbase 69697403Sobrien // containing each of the two choices. 69797403Sobrien if (result2.base_type == nonvirtual_base_type 69897403Sobrien || result.base_type == nonvirtual_base_type 69997403Sobrien || !(*result2.base_type == *result.base_type)) 70097403Sobrien { 70197403Sobrien // Already ambiguous, not virtual or via different virtuals. 70297403Sobrien // Cannot match. 70397403Sobrien result.part2dst = __contained_ambig; 70497403Sobrien return true; 70597403Sobrien } 70697403Sobrien result.part2dst 70797403Sobrien = __sub_kind (result.part2dst | result2.part2dst); 70897403Sobrien } 70997403Sobrien } 71097403Sobrien } 71197403Sobrien return result.part2dst != __unknown; 71297403Sobrien} 71397403Sobrien 71497403Sobrien// this is the external interface to the dynamic cast machinery 71597403Sobrienextern "C" void * 71697403Sobrien__dynamic_cast (const void *src_ptr, // object started from 71797403Sobrien const __class_type_info *src_type, // type of the starting object 71897403Sobrien const __class_type_info *dst_type, // desired target type 71997403Sobrien ptrdiff_t src2dst) // how src and dst are related 72097403Sobrien{ 72197403Sobrien const void *vtable = *static_cast <const void *const *> (src_ptr); 72297403Sobrien const vtable_prefix *prefix = 72397403Sobrien adjust_pointer <vtable_prefix> (vtable, 72497403Sobrien -offsetof (vtable_prefix, origin)); 72597403Sobrien const void *whole_ptr = 72697403Sobrien adjust_pointer <void> (src_ptr, prefix->whole_object); 72797403Sobrien const __class_type_info *whole_type = prefix->whole_type; 72897403Sobrien __class_type_info::__dyncast_result result; 72997403Sobrien 73097403Sobrien whole_type->__do_dyncast (src2dst, __class_type_info::__contained_public, 73197403Sobrien dst_type, whole_ptr, src_type, src_ptr, result); 73297403Sobrien if (!result.dst_ptr) 73397403Sobrien return NULL; 73497403Sobrien if (contained_public_p (result.dst2src)) 73597403Sobrien // Src is known to be a public base of dst. 73697403Sobrien return const_cast <void *> (result.dst_ptr); 73797403Sobrien if (contained_public_p (__class_type_info::__sub_kind (result.whole2src & result.whole2dst))) 73897403Sobrien // Both src and dst are known to be public bases of whole. Found a valid 73997403Sobrien // cross cast. 74097403Sobrien return const_cast <void *> (result.dst_ptr); 74197403Sobrien if (contained_nonvirtual_p (result.whole2src)) 74297403Sobrien // Src is known to be a non-public nonvirtual base of whole, and not a 74397403Sobrien // base of dst. Found an invalid cross cast, which cannot also be a down 74497403Sobrien // cast 74597403Sobrien return NULL; 74697403Sobrien if (result.dst2src == __class_type_info::__unknown) 74797403Sobrien result.dst2src = dst_type->__find_public_src (src2dst, result.dst_ptr, 74897403Sobrien src_type, src_ptr); 74997403Sobrien if (contained_public_p (result.dst2src)) 75097403Sobrien // Found a valid down cast 75197403Sobrien return const_cast <void *> (result.dst_ptr); 75297403Sobrien // Must be an invalid down cast, or the cross cast wasn't bettered 75397403Sobrien return NULL; 75497403Sobrien} 75597403Sobrien 756132720Skan} // namespace __cxxabiv1 757