From 808c61c8d3802376a4f83c8acecc0de4059a70d7 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 31 Jan 2000 10:21:47 +0000 Subject: [PATCH] cp-tree.h (new_abi_rtti_p): Use flag_new_abi. * cp-tree.h (new_abi_rtti_p): Use flag_new_abi. Runtime support for new-abi rtti. * inc/typeinfo (type_info::operator!=): Define in class. (type_info::before, type_info::name, type_info::operator==, type_info::operator!=): Define new ABI implementations. (type_info::is_pointer_p, type_info::is_function_p): Declare new virtual functions. (type_info::do_catch, type_info::do_upcast): Likewise. * tinfo.h (__base_class_info): Define new class. (__class_type_info): Likewise. (__si_class_type_info): Likewise. (__vmi_class_type_info): Likewise. (__dynamic_cast): Prototype. * tinfo.cc: Conditionalize old and new rtti mechanisms. (type_info::is_pointer_p): Define new function. (type_info::is_function_p): Likewise. (type_info::do_catch): Likewise. (type_info::do_upcast): Likewise. (vtable_prefix): New structure for vtable access. (adjust_pointer): Define new template function. (contained_p, public_p, virtual_p, contained_public_p, contained_nonpublic_p, contained_nonvirtual_p): Define new functions. (nonvirtual_base_type): New local variable. (__class_type_info::~__class_type_info): Define. (__si_class_type_info::~__si_class_type_info): Likewise. (__vmi_class_type_info::~__vmi_class_type_info): Likewise. (__class_type_info::do_catch): Define new function. (__class_type_info::do_upcast): Likewise. (__class_type_info::find_public_src): Likewise. (__class_type_info::do_find_public_src): Likewise. (__si_class_type_info::do_find_public_src): Likewise. (__vmi_class_type_info::do_find_public_src): Likewise. (__class_type_info::do_dyncast): Likewise. (__si_class_type_info::do_dyncast): Likewise. (__vmi_class_type_info::do_dyncast): Likewise. (__class_type_info::do_upcast): Likewise. (__si_class_type_info::do_upcast): Likewise. (__vmi_class_type_info::do_upcast): Likewise. (__dynamic_cast): Likewise. * tinfo2.cc (__fundamental_type_info): Define new class. (__pointer_type_info): Likewise. (__reference_type_info): Likewise. (__array_type_info): Likewise. (__function_type_info): Likewise. (__enum_type_info): Likewise. (__ptr_to_member_type_info): Likewise. (__fundamental_type_info::~__fundamental_type_info): Define. (__pointer_type_info::~__pointer_type_info): Likewise. (__reference_type_info::~__reference_type_info): Likewise. (__array_type_info::~__array_type_info): Likewise. (__function_type_info::~__function_type_info): Likewise. (__enum_type_info::~__enum_type_info): Likewise. (__ptr_to_member_type_info::~__ptr_to_member_type_info): Likewise. (__pointer_type_info::do_catch): Define new function. (__ptr_to_member_type_info::do_catch): Define new function. (__throw_type_match_rtti_2): Use new ABI interface, if enabled. (__is_pointer): Likewise. * exception.cc (__cplus_type_matcher): Deal with new-abi rtti. From-SVN: r31713 --- gcc/cp/ChangeLog | 68 +++++ gcc/cp/cp-tree.h | 2 +- gcc/cp/exception.cc | 6 +- gcc/cp/inc/typeinfo | 74 ++++-- gcc/cp/tinfo.cc | 602 ++++++++++++++++++++++++++++++++++++++++++++ gcc/cp/tinfo.h | 234 ++++++++++++++++- gcc/cp/tinfo2.cc | 269 +++++++++++++++++++- 7 files changed, 1234 insertions(+), 21 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b5198b3daa4..192daf4e0a8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,71 @@ +2000-01-31 Nathan Sidwell + + * cp-tree.h (new_abi_rtti_p): Use flag_new_abi. + + Runtime support for new-abi rtti. + * inc/typeinfo (type_info::operator!=): Define in class. + (type_info::before, type_info::name, type_info::operator==, + type_info::operator!=): Define new ABI implementations. + (type_info::is_pointer_p, type_info::is_function_p): Declare + new virtual functions. + (type_info::do_catch, type_info::do_upcast): Likewise. + + * tinfo.h (__base_class_info): Define new class. + (__class_type_info): Likewise. + (__si_class_type_info): Likewise. + (__vmi_class_type_info): Likewise. + (__dynamic_cast): Prototype. + + * tinfo.cc: Conditionalize old and new rtti mechanisms. + (type_info::is_pointer_p): Define new function. + (type_info::is_function_p): Likewise. + (type_info::do_catch): Likewise. + (type_info::do_upcast): Likewise. + (vtable_prefix): New structure for vtable access. + (adjust_pointer): Define new template function. + (contained_p, public_p, virtual_p, contained_public_p, + contained_nonpublic_p, contained_nonvirtual_p): Define new + functions. + (nonvirtual_base_type): New local variable. + (__class_type_info::~__class_type_info): Define. + (__si_class_type_info::~__si_class_type_info): Likewise. + (__vmi_class_type_info::~__vmi_class_type_info): Likewise. + (__class_type_info::do_catch): Define new function. + (__class_type_info::do_upcast): Likewise. + (__class_type_info::find_public_src): Likewise. + (__class_type_info::do_find_public_src): Likewise. + (__si_class_type_info::do_find_public_src): Likewise. + (__vmi_class_type_info::do_find_public_src): Likewise. + (__class_type_info::do_dyncast): Likewise. + (__si_class_type_info::do_dyncast): Likewise. + (__vmi_class_type_info::do_dyncast): Likewise. + (__class_type_info::do_upcast): Likewise. + (__si_class_type_info::do_upcast): Likewise. + (__vmi_class_type_info::do_upcast): Likewise. + (__dynamic_cast): Likewise. + + * tinfo2.cc (__fundamental_type_info): Define new class. + (__pointer_type_info): Likewise. + (__reference_type_info): Likewise. + (__array_type_info): Likewise. + (__function_type_info): Likewise. + (__enum_type_info): Likewise. + (__ptr_to_member_type_info): Likewise. + (__fundamental_type_info::~__fundamental_type_info): Define. + (__pointer_type_info::~__pointer_type_info): Likewise. + (__reference_type_info::~__reference_type_info): Likewise. + (__array_type_info::~__array_type_info): Likewise. + (__function_type_info::~__function_type_info): Likewise. + (__enum_type_info::~__enum_type_info): Likewise. + (__ptr_to_member_type_info::~__ptr_to_member_type_info): Likewise. + (__pointer_type_info::do_catch): Define new function. + (__ptr_to_member_type_info::do_catch): Define new function. + + (__throw_type_match_rtti_2): Use new ABI interface, if enabled. + (__is_pointer): Likewise. + + * exception.cc (__cplus_type_matcher): Deal with new-abi rtti. + 2000-01-30 Mark Mitchell * cp/class.c (build_vtable): Rename to build_primary_vtable. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d7aabbefc6a..f1d86e56f17 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -244,7 +244,7 @@ extern int flag_rtti; /* Nonzero if we use access type_info objects directly, and use the cross-vendor layout for them. Zero if we use an accessor function to get the type_info object address. */ -#define new_abi_rtti_p() (0) +#define new_abi_rtti_p() (flag_new_abi) /* Language-dependent contents of an identifier. */ diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index d00e0f28a38..0c806e6cf00 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -184,7 +184,11 @@ __cplus_type_matcher (__eh_info *info_, void *match_info, /* we don't worry about version info yet, there is only one version! */ - void *match_type = ((void *(*)())match_info) (); + void *match_type = match_info; + +#if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 + match_type = ((void *(*)())match_type) (); +#endif if (__throw_type_match_rtti_2 (match_type, info->type, info->original_value, &info->value)) diff --git a/gcc/cp/inc/typeinfo b/gcc/cp/inc/typeinfo index 934784968c5..b631d6e2d24 100644 --- a/gcc/cp/inc/typeinfo +++ b/gcc/cp/inc/typeinfo @@ -1,5 +1,10 @@ // RTTI support for -*- C++ -*- -// Copyright (C) 1994, 95-97, 1998 Free Software Foundation +// Copyright (C) 1994, 95-97, 1998, 2000 Free Software Foundation + +// __GXX_ABI_VERSION distinguishes the ABI that is being used. Values <100 +// indicate the `old' abi, which grew as C++ was defined. Values >=100 +// indicate the `new' abi, which is a cross vendor C++ abi, documented at +// `http://reality.sgi.com/dehnert_engr/cxx/'. #ifndef __TYPEINFO__ #define __TYPEINFO__ @@ -12,33 +17,74 @@ extern "C++" { namespace std { +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 +class __class_type_info; +#endif + class type_info { +public: + // Destructor. Being the first non-inline virtual function, this controls in + // which translation unit the vtable is emitted. The compiler makes use of + // that information to know where to emit the runtime-mandated type_info + // structures in the new-abi. + virtual ~type_info (); + private: - // assigning type_info is not supported. made private. + // Assigning type_info is not supported. made private. type_info& operator= (const type_info&); type_info (const type_info&); protected: - explicit type_info (const char *n): _name (n) { } - const char *_name; +protected: + explicit type_info (const char *n): _name (n) { } + public: - // destructor - virtual ~type_info (); - + // the public interface +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 + // In old abi, there can be multiple instances of a type_info object for one + // type. Uniqueness must use the _name value, not object address. bool before (const type_info& arg) const; const char* name () const { return _name; } bool operator== (const type_info& arg) const; - bool operator!= (const type_info& arg) const; -}; + bool operator!= (const type_info& arg) const + { return !operator== (arg); } + +#else + // In new abi we can rely on type_info's being unique, + // and therefore address comparisons are sufficient. + bool before (const type_info& arg) const + { return this < &arg; } + const char* name () const + { return _name; } + bool operator== (const type_info& arg) const + { return &arg == this; } + bool operator!= (const type_info& arg) const + { return !operator== (arg); } +#endif -inline bool type_info:: -operator!= (const type_info& arg) const -{ - return !operator== (arg); -} + // the internal interface +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 +public: + // return true if this is a pointer type of some kind + virtual bool is_pointer_p () const; + // return true if this is a function type + virtual bool is_function_p () const; + + // Try and catch a thrown type. Store an adjusted pointer to the caught type + // in THR_OBJ. If THR_TYPE is not a pointer type, then THR_OBJ points to the + // thrown object. If THR_TYPE is a pointer type, then THR_OBJ is the pointer + // itself. OUTER indicates the number of outer pointers, and whether they + // were const qualified. + virtual bool do_catch (const type_info *thr_type, void **thr_obj, + unsigned outer) const; + + // internally used during catch matching + virtual bool do_upcast (const __class_type_info *target, void **obj_ptr) const; +#endif +}; class bad_cast : public exception { public: diff --git a/gcc/cp/tinfo.cc b/gcc/cp/tinfo.cc index 292fb3c3ef3..557c88c1807 100644 --- a/gcc/cp/tinfo.cc +++ b/gcc/cp/tinfo.cc @@ -67,6 +67,9 @@ std::type_info:: ~type_info () { } +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 +// original (old) abi + // We can't rely on common symbols being shared between shared objects. bool std::type_info:: operator== (const std::type_info& arg) const @@ -539,3 +542,602 @@ do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *s 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 __class_type_info *, void **) const +{ + return false; +} + +}; + +namespace { + +using namespace std; + +// 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 +inline const T * +adjust_pointer (const void *base, ptrdiff_t offset) +{ + return reinterpret_cast + (reinterpret_cast (base) + 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 (0) + 1; + +}; // namespace + +namespace std { + +__class_type_info:: +~__class_type_info () +{} + +__si_class_type_info:: +~__si_class_type_info () +{} + +__vmi_class_type_info:: +~__vmi_class_type_info () +{} + +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 (details); + + if (do_upcast (contained_public, dst_type, *obj_ptr, result)) + return false; + *obj_ptr = const_cast (result.dst_ptr); + return contained_public_p (result.whole2dst); +} + +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 (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->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 = n_bases; i--;) + { + if (!base_list[i].is_public_p ()) + continue; // Not public, can't be here. + + const void *base = obj_ptr; + ptrdiff_t offset = base_list[i].offset; + + if (base_list[i].is_virtual_p ()) + { + if (src2dst == -3) + continue; // Not a virtual base, so can't be here. + const ptrdiff_t *vtable = *static_cast (base); + + offset = vtable[offset]; + } + base = adjust_pointer (base, offset); + + sub_kind base_kind = base_list[i].type->do_find_public_src + (src2dst, base, src_type, src_ptr); + if (contained_p (base_kind)) + { + if (base_list[i].is_virtual_p ()) + 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 (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->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 (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 (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 = n_bases; i--;) + { + dyncast_result result2; + void const *base = obj_ptr; + sub_kind base_access = access_path; + ptrdiff_t offset = base_list[i].offset; + + if (base_list[i].is_virtual_p ()) + { + base_access = sub_kind (base_access | contained_virtual_mask); + const ptrdiff_t *vtable = *static_cast (base); + + offset = vtable[offset]; + } + base = adjust_pointer (base, offset); + + if (!base_list[i].is_public_p ()) + base_access = sub_kind (base_access & ~contained_public_mask); + + bool result2_ambig + = base_list[i].type->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; + } + 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 && result2.dst_ptr) + || (result_ambig && result2.dst_ptr) + || (result2_ambig && result.dst_ptr)) + { + // 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_nonvirtual_p (result.whole2src)) + { + // We already found SRC_PTR 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 + { + 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 = dst_type->find_public_src + (src2dst, result.dst_ptr, src_type, src_ptr); + + 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 = 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 (sub_kind access_path, + 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.whole2dst = access_path; + return contained_nonpublic_p (access_path); + } + return false; +} + +bool __si_class_type_info:: +do_upcast (sub_kind access_path, + const __class_type_info *dst, const void *obj_ptr, + upcast_result &__restrict result) const +{ + if (*this == *dst) + { + result.dst_ptr = obj_ptr; + result.base_type = nonvirtual_base_type; + result.whole2dst = access_path; + return contained_nonpublic_p (access_path); + } + return base->do_upcast (access_path, dst, obj_ptr, result); +} + +bool __vmi_class_type_info:: +do_upcast (sub_kind access_path, + const __class_type_info *dst, const void *obj_ptr, + upcast_result &__restrict result) const +{ + if (*this == *dst) + { + result.dst_ptr = obj_ptr; + result.base_type = nonvirtual_base_type; + result.whole2dst = access_path; + return contained_nonpublic_p (access_path); + } + + for (size_t i = n_bases; i--;) + { + upcast_result result2 (result.src_details); + const void *base = obj_ptr; + sub_kind sub_access = access_path; + ptrdiff_t offset = base_list[i].offset; + + if (!base_list[i].is_public_p ()) + { + if (!(result.src_details & multiple_base_mask)) + // original cannot have an ambiguous base + continue; + sub_access = sub_kind (sub_access & ~contained_public_mask); + } + if (base_list[i].is_virtual_p ()) + { + sub_access = sub_kind (sub_access | contained_virtual_mask); + + if (base) + { + const ptrdiff_t *vtable = *static_cast (base); + offset = vtable[offset]; + } + } + if (base) + base = adjust_pointer (base, offset); + + if (base_list[i].type->do_upcast (sub_access, dst, base, result2)) + return true; // must fail + if (result2.base_type) + { + if (result2.base_type == nonvirtual_base_type + && base_list[i].is_virtual_p ()) + result2.base_type = base_list[i].type; + if (!result.base_type) + { + result = result2; + if (!(details & multiple_base_mask)) + // cannot have an ambiguous other base + return false; + } + else if (result.dst_ptr != result2.dst_ptr) + { + // Found an ambiguity. + result.dst_ptr = NULL; + result.whole2dst = contained_ambig; + return true; + } + else if (result.dst_ptr) + { + // Ok, found real object via a virtual path. + result.whole2dst + = sub_kind (result.whole2dst | result2.whole2dst); + } + 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.whole2dst = contained_ambig; + return true; + } + } + } + } + return false; +} + +// this is the external interface to the dynamic cast machinery +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 (src_ptr); + const vtable_prefix *prefix = + adjust_pointer (vtable, 0); + // FIXME: the above offset should be -offsetof (vtable_prefix, origin)); + // but we don't currently layout vtables correctly. + const void *whole_ptr = + adjust_pointer (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)) + return const_cast (result.dst_ptr); + if (contained_public_p (__class_type_info::sub_kind (result.whole2src & result.whole2dst))) + // Found a valid cross cast + return const_cast (result.dst_ptr); + if (contained_nonvirtual_p (result.whole2src)) + // Found an invalid cross cast, which cannot also be a down cast + return NULL; + if (!(whole_type->details & __class_type_info::private_base_mask)) + // whole type has no private bases + return const_cast (result.dst_ptr); + 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 (result.dst_ptr); + // Must be an invalid down cast, or the cross cast wasn't bettered + return NULL; +} + +}; // namespace std +#endif diff --git a/gcc/cp/tinfo.h b/gcc/cp/tinfo.h index 9bf06cab3d2..2894ed6ca15 100644 --- a/gcc/cp/tinfo.h +++ b/gcc/cp/tinfo.h @@ -5,6 +5,9 @@ // Class declarations shared between the typeinfo implementation files. +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 +// original (old) abi + // type_info for a class with no base classes (or an enum). struct __user_type_info : public std::type_info { @@ -167,11 +170,7 @@ public: // type_info for a general class. -#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 typedef int USItype __attribute__ ((mode (SI))); -#else -typedef unsigned int USItype __attribute__ ((mode (SI))); -#endif struct __class_type_info : public __user_type_info { enum access { PUBLIC = 1, PROTECTED = 2, PRIVATE = 3 }; @@ -200,3 +199,230 @@ struct __class_type_info : public __user_type_info { virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *subptr) const; }; +#else +// new abi +#include "stddef.h" + +typedef int USItype __attribute__ ((mode (SI))); + +namespace std { + +class __class_type_info; + +// helper class for __vmi_class_type +struct __base_class_info { + const __class_type_info *type; // base class type + ptrdiff_t offset; // offset to the sub object + int vmi_flags; // about the base + +// implementation specific parts + enum vmi_masks { + virtual_mask = 0x1, + public_mask = 0x2, + hwm_bit = 2 + }; + +public: + bool is_virtual_p () const + { return vmi_flags & virtual_mask; } + bool is_public_p () const + { return vmi_flags & public_mask; } +}; + +// type information for a class +class __class_type_info : public type_info { +protected: + virtual ~__class_type_info (); +public: + int details; // details about the class heirarchy + +// implementation specific parts + enum detail_masks { + multiple_base_mask = 0x1, // multiple inheritance of the same base type + polymorphic_mask = 0x2, // is a polymorphic type + virtual_base_mask = 0x4, // has virtual bases (direct or indirect) + private_base_mask = 0x8 // has private bases (direct or indirect) + }; + +public: + // sub_kind tells us about how a base object is contained within a derived + // object. We often do this lazily, hence the UNKNOWN value. At other times + // we may use NOT_CONTAINED to mean not publicly contained. + enum sub_kind + { + unknown = 0, // we have no idea + not_contained, // not contained within us (in some + // circumstances this might mean not contained + // publicly) + contained_ambig, // contained ambiguously + + contained_virtual_mask = __base_class_info::virtual_mask, // via a virtual path + contained_public_mask = __base_class_info::public_mask, // via a public path + contained_mask = 1 << __base_class_info::hwm_bit, // contained within us + + contained_private = contained_mask, + contained_public = contained_mask | contained_public_mask + }; + +public: + struct upcast_result + { + const void *dst_ptr; // pointer to caught object + sub_kind whole2dst; // path from most derived object to target + int src_details; // hints about the source type + 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), whole2dst (unknown), src_details (d), base_type (NULL) + {} + }; + +public: + // dyncast_result is used to hold information during traversal of a class + // heirarchy when dynamic casting. + struct 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 + + public: + dyncast_result () + :dst_ptr (NULL), whole2dst (unknown), + whole2src (unknown), dst2src (unknown) + {} + }; + +public: + explicit __class_type_info (const char *n, + int details_) + : type_info (n), details (details_) + { } + +protected: + virtual bool do_upcast (const __class_type_info *dst_type, void **obj_ptr) const; + +protected: + virtual bool do_catch (const type_info *thr_type, void **thr_obj, + unsigned outer) const; + + +public: + // Helper for upcast. See if DST is us, or one of our bases. ACCESS_PATH + // gives the access from the start object. Return TRUE if we know the upcast + // fails. + virtual bool do_upcast (sub_kind access_path, + const __class_type_info *dst, const void *obj, + upcast_result &__restrict result) const; + +public: + // Indicate whether SRC_PTR of type SRC_TYPE is contained publicly within + // OBJ_PTR. OBJ_PTR points to a base object of our type, which is the + // destination type. SRC2DST indicates how SRC objects might be contained + // within this type. If SRC_PTR is one of our SRC_TYPE bases, indicate the + // virtuality. Returns not_contained for non containment or private + // containment. + inline sub_kind find_public_src (ptrdiff_t src2dst, const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr) const; + +public: + // dynamic cast helper. ACCESS_PATH gives the access from the most derived + // object to this base. DST_TYPE indicates the desired type we want. OBJ_PTR + // points to a base of our type within the complete object. SRC_TYPE + // indicates the static type started from and SRC_PTR 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. + virtual bool 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 &result) const; +public: + // Helper for find_public_subobj. SRC2DST indicates how SRC_TYPE bases are + // inherited by the type started from -- which is not necessarily the + // current type. The current type will be a base of the destination type. + // OBJ_PTR points to the current base. + virtual sub_kind do_find_public_src (ptrdiff_t src2dst, const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr) const; +}; + +// type information for a class with a single non-virtual base +class __si_class_type_info : public __class_type_info { +protected: + virtual ~__si_class_type_info (); +protected: + const __class_type_info *base; // base type + +public: + explicit __si_class_type_info (const char *n, + int details_, + const __class_type_info *base_) + : __class_type_info (n, details_), base (base_) + { } + +// implementation specific parts +protected: + virtual bool 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 &result) const; + virtual sub_kind do_find_public_src (ptrdiff_t src2dst, const void *obj_ptr, + const __class_type_info *src_type, + const void *sub_ptr) const; + virtual bool do_upcast (sub_kind access_path, + const __class_type_info *dst, const void *obj, + upcast_result &__restrict result) const; +}; + +// type information for a class with multiple and/or virtual bases +class __vmi_class_type_info : public __class_type_info { +protected: + virtual ~__vmi_class_type_info (); +protected: + int n_bases; // number of direct bases + __base_class_info base_list[1]; // array of bases + // The array of bases uses the trailing array struct hack + // so this class is not constructable with a normal constructor. It is + // internally generated by the compiler. + +public: + explicit __vmi_class_type_info (const char *n, + int details_) + : __class_type_info (n, details_), n_bases (0) + { } + +// implementation specific parts +protected: + virtual bool 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 &result) const; + virtual sub_kind do_find_public_src (ptrdiff_t src2dst, const void *obj_ptr, + const __class_type_info *src_type, + const void *src_ptr) const; + virtual bool do_upcast (sub_kind access_path, + const __class_type_info *dst, const void *obj, + upcast_result &__restrict result) const; +}; + +// dynamic cast runtime +void *__dynamic_cast (const void *src_ptr, // object started from + const __class_type_info *src_type, // static type of object + const __class_type_info *dst_type, // desired target type + ptrdiff_t src2dst); // how src and dst are related + + // src2dst has the following possible values + // >= 0: src_type is a unique public non-virtual base of dst_type + // dst_ptr + src2dst == src_ptr + // -1: unspecified relationship + // -2: src_type is not a public base of dst_type + // -3: src_type is a multiple public non-virtual base of dst_type + +}; // namespace std + +#endif diff --git a/gcc/cp/tinfo2.cc b/gcc/cp/tinfo2.cc index f1b9d92f8f5..3f879c2e4b9 100644 --- a/gcc/cp/tinfo2.cc +++ b/gcc/cp/tinfo2.cc @@ -31,6 +31,7 @@ using std::type_info; +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 bool type_info::before (const type_info &arg) const { @@ -88,6 +89,248 @@ struct __array_type_info : public type_info { __array_type_info (const char *n): type_info (n) {} }; +#else + +namespace std { + +// type information for int, float etc +class __fundamental_type_info : public type_info { +public: + virtual ~__fundamental_type_info (); +public: + explicit __fundamental_type_info (const char *n) + : type_info (n) + { } +}; + +// type information for pointer to data or function, but not pointer to member +class __pointer_type_info : public type_info { +public: + virtual ~__pointer_type_info (); +// external parts + int quals; // qualification of the target object + const type_info *target; // type of object being pointed to + +// internal parts + enum quals_masks { + const_mask = 0x1, + volatile_mask = 0x2 + }; + +public: + explicit __pointer_type_info (const char *n, + int quals_, + const type_info *target_) + : type_info (n), quals (quals_), target (target_) + { } + +protected: + virtual bool is_pointer_p () const; + virtual bool do_catch (const type_info *thr_type, void **thr_obj, + unsigned outer) const; +}; + +// type information for reference to data +class __reference_type_info : public type_info { +public: + virtual ~__reference_type_info (); + int quals; // qualification of the target object + const type_info *target; // type of object being referenced + +// internal parts + enum quals_masks { + const_mask = 0x1, + volatile_mask = 0x2 + }; + +public: + explicit __reference_type_info (const char *n, + int quals_, + const type_info *target_) + : type_info (n), quals (quals_), target (target_) + { } +}; + +// type information for array objects +class __array_type_info : public type_info { +public: + virtual ~__array_type_info (); +public: + explicit __array_type_info (const char *n) + : type_info (n) + { } +}; + +// type information for functions (both member and non-member) +class __function_type_info : public type_info { +public: + virtual ~__function_type_info (); +public: + explicit __function_type_info (const char *n) + : type_info (n) + { } +protected: + virtual bool is_function_p () const; +}; + +// type information for enumerations +class __enum_type_info : public type_info { +public: + virtual ~__enum_type_info (); +public: + explicit __enum_type_info (const char *n) + : type_info (n) + { } +}; + +// type information for a pointer to member variable (not function) +class __ptr_to_member_type_info : public type_info { +public: + virtual ~__ptr_to_member_type_info (); +// external parts + const __class_type_info *klass; // class of the member + const type_info *type; // type of the member + int quals; // qualifications of the pointed to type + +// internal parts + enum quals_masks { + const_mask = 0x1, + volatile_mask = 0x2 + }; + +public: + explicit __ptr_to_member_type_info (const char *n, + const __class_type_info *klass_, + const type_info *type_, + int quals_) + : type_info (n), klass (klass_), type (type_), quals (quals_) + { } + +protected: + virtual bool do_catch (const type_info *thr_type, void **thr_obj, + unsigned outer) const; +}; + +}; // namespace std + +#endif + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 +namespace std { + +// This has special meaning to the compiler, and will cause it +// to emit the type_info structures for the fundamental types which are +// mandated to exist in the runtime. +__fundamental_type_info:: +~__fundamental_type_info () +{} + +__pointer_type_info:: +~__pointer_type_info () +{} + +__reference_type_info:: +~__reference_type_info () +{} + +__array_type_info:: +~__array_type_info () +{} + +__function_type_info:: +~__function_type_info () +{} + +__enum_type_info:: +~__enum_type_info () +{} + +__ptr_to_member_type_info:: +~__ptr_to_member_type_info () +{} + +bool __pointer_type_info:: +is_pointer_p () const +{ + return true; +} + +bool __function_type_info:: +is_function_p () const +{ + return true; +} + +bool __pointer_type_info:: +do_catch (const type_info *thr_type, + void **thr_obj, + unsigned outer) const +{ + if (*this == *thr_type) + return true; // same type + if (typeid (*this) != typeid (*thr_type)) + return false; // not both pointers + + if (!(outer & 1)) + // We're not the same and our outer pointers are not all const qualified + // Therefore there must at least be a qualification conversion involved + // But for that to be valid, our outer pointers must be const qualified. + return false; + + const __pointer_type_info *thrown_type = + static_cast (thr_type); + + if (thrown_type->quals & ~quals) + // We're less qualified. + return false; + + if (!(quals & const_mask)) + outer &= ~1; + + if (outer < 2 && *target == typeid (void)) + { + // conversion to void + return !thrown_type->is_function_p (); + } + + return target->do_catch (thrown_type->target, thr_obj, outer + 2); +} + +bool __ptr_to_member_type_info:: +do_catch (const type_info *thr_type, + void **thr_obj, + unsigned outer) const +{ + if (*this == *thr_type) + return true; // same type + if (typeid (*this) != typeid (*thr_type)) + return false; // not both pointers to member + + if (!(outer & 1)) + // We're not the same and our outer pointers are not all const qualified + // Therefore there must at least be a qualification conversion involved. + // But for that to be valid, our outer pointers must be const qualified. + return false; + + const __ptr_to_member_type_info *thrown_type = + static_cast (thr_type); + + if (thrown_type->quals & ~quals) + // We're less qualified. + return false; + + if (!(quals & const_mask)) + outer &= ~1; + + if (*klass != *thrown_type->klass) + return false; // not pointers to member of same class + + return type->do_catch (thrown_type->type, thr_obj, outer + 2); +} + +} // namespace std +#endif + // Entry points for the compiler. /* Low level match routine used by compiler to match types of catch @@ -102,6 +345,8 @@ __throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r, *valp = objptr; +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 +// old abi if (catch_type == throw_type) return 1; @@ -213,10 +458,15 @@ __throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r, } } } - +#else +// new abi + + return catch_type.do_catch (&throw_type, valp, 1); +#endif return 0; } +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 /* Backward compatibility wrapper. */ extern "C" void* @@ -228,6 +478,7 @@ __throw_type_match_rtti (const void *catch_type_r, const void *throw_type_r, return ret; return NULL; } +#endif /* Called from __cp_pop_exception. Is P the type_info node for a pointer of some kind? */ @@ -236,11 +487,20 @@ bool __is_pointer (void *p) { const type_info *t = reinterpret_cast (p); +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 +// old abi const __pointer_type_info *pt = dynamic_cast (t); return pt != 0; +#else +// new abi + return t->is_pointer_p (); +#endif } +#if !defined(__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100 +// old abi + extern "C" void __rtti_ptr (void *addr, const char *n, const type_info *ti) { new (addr) __pointer_type_info (n, *ti); } @@ -302,3 +562,10 @@ BUILTIN (v); BUILTIN (x); BUILTIN (l); BUILTIN (i); BUILTIN (s); BUILTIN (b); BUILTIN (c); BUILTIN (w); BUILTIN (r); BUILTIN (d); BUILTIN (f); BUILTIN (Ui); BUILTIN (Ul); BUILTIN (Ux); BUILTIN (Us); BUILTIN (Uc); BUILTIN (Sc); +#else +// new abi + +// we need to define the fundamental type type_info's, but the name mangling is +// not yet defined. + +#endif -- 2.30.2