Reimplement dynamic cast and catch matching.
* cp-tree.h (get_dynamic_cast_base_type): Prototype new function * search.c (dynamic_cast_base_recurse): New function. (get_dynamic_cast_base_type): New function for dynamic cast. * rtti.c (build_dynamic_cast_1): Determine source and target class relationship. Call __dynamic_cast_2. * tinfo.h (__user_type_info::upcast): New catch dispatcher. (__user_type_info::dyncast): New dynamic cast dispatcher. (__user_type_info::sub_kind): New nested enumeration. (__user_type_info::contained_p): sub_kind predicate. (__user_type_info::contained_public_p): Likewise. (__user_type_info::contained_nonpublic_p): Likewise. (__user_type_info::contained_nonvirtual_p: Likewise. (__user_type_info::upcast_result): New nested struct. (__user_type_info::dyncast_result): New nested struct. (*::do_upcast): New catch function. (*::do_dyncast): New dynamic cast function. (__user_type_info::find_public_subobj): New dynamic cast helper dispatcher. (*::do_find_public_subobj): New dynamic cast helper function. * tinfo.cc (__user_type_info::upcast): Define catch dispatcher. (__user_type_info::dyncast): Define dynamic cast dispatcher. (*::do_upcast): Define catch function. (*::do_dyncast): Define dynamic cast function. (*::do_find_public_subobj): Define dynamic cast helper function. * tinfo2.cc (__throw_type_match_rtti_2): Use upcast. (__dynamic_cast): Backwards compatibility wrapper. Use dyncast. (__dynamic_cast_2): New dynamic cast runtime. From-SVN: r29544
This commit is contained in:
parent
e36e6e0261
commit
4a9e5c6725
|
@ -1,3 +1,34 @@
|
||||||
|
1999-09-21 Nathan Sidwell <nathan@acm.org>
|
||||||
|
|
||||||
|
Reimplement dynamic cast and catch matching.
|
||||||
|
* cp-tree.h (get_dynamic_cast_base_type): Prototype new function
|
||||||
|
* search.c (dynamic_cast_base_recurse): New function.
|
||||||
|
(get_dynamic_cast_base_type): New function for dynamic cast.
|
||||||
|
* rtti.c (build_dynamic_cast_1): Determine source and target
|
||||||
|
class relationship. Call __dynamic_cast_2.
|
||||||
|
* tinfo.h (__user_type_info::upcast): New catch dispatcher.
|
||||||
|
(__user_type_info::dyncast): New dynamic cast dispatcher.
|
||||||
|
(__user_type_info::sub_kind): New nested enumeration.
|
||||||
|
(__user_type_info::contained_p): sub_kind predicate.
|
||||||
|
(__user_type_info::contained_public_p): Likewise.
|
||||||
|
(__user_type_info::contained_nonpublic_p): Likewise.
|
||||||
|
(__user_type_info::contained_nonvirtual_p: Likewise.
|
||||||
|
(__user_type_info::upcast_result): New nested struct.
|
||||||
|
(__user_type_info::dyncast_result): New nested struct.
|
||||||
|
(*::do_upcast): New catch function.
|
||||||
|
(*::do_dyncast): New dynamic cast function.
|
||||||
|
(__user_type_info::find_public_subobj): New dynamic cast
|
||||||
|
helper dispatcher.
|
||||||
|
(*::do_find_public_subobj): New dynamic cast helper function.
|
||||||
|
* tinfo.cc (__user_type_info::upcast): Define catch dispatcher.
|
||||||
|
(__user_type_info::dyncast): Define dynamic cast dispatcher.
|
||||||
|
(*::do_upcast): Define catch function.
|
||||||
|
(*::do_dyncast): Define dynamic cast function.
|
||||||
|
(*::do_find_public_subobj): Define dynamic cast helper function.
|
||||||
|
* tinfo2.cc (__throw_type_match_rtti_2): Use upcast.
|
||||||
|
(__dynamic_cast): Backwards compatibility wrapper. Use dyncast.
|
||||||
|
(__dynamic_cast_2): New dynamic cast runtime.
|
||||||
|
|
||||||
1999-09-20 Mark Mitchell <mark@codesourcery.com>
|
1999-09-20 Mark Mitchell <mark@codesourcery.com>
|
||||||
|
|
||||||
* cp-tree.h (finish_stmt_expr): Change prototype.
|
* cp-tree.h (finish_stmt_expr): Change prototype.
|
||||||
|
|
|
@ -3596,6 +3596,7 @@ extern int types_overlap_p PROTO((tree, tree));
|
||||||
extern tree get_vbase PROTO((tree, tree));
|
extern tree get_vbase PROTO((tree, tree));
|
||||||
extern tree get_binfo PROTO((tree, tree, int));
|
extern tree get_binfo PROTO((tree, tree, int));
|
||||||
extern int get_base_distance PROTO((tree, tree, int, tree *));
|
extern int get_base_distance PROTO((tree, tree, int, tree *));
|
||||||
|
extern tree get_dynamic_cast_base_type PROTO((tree, tree));
|
||||||
extern int accessible_p PROTO((tree, tree));
|
extern int accessible_p PROTO((tree, tree));
|
||||||
extern tree lookup_field PROTO((tree, tree, int, int));
|
extern tree lookup_field PROTO((tree, tree, int, int));
|
||||||
extern int lookup_fnfields_1 PROTO((tree, tree));
|
extern int lookup_fnfields_1 PROTO((tree, tree));
|
||||||
|
|
|
@ -588,6 +588,7 @@ build_dynamic_cast_1 (type, expr)
|
||||||
{
|
{
|
||||||
tree retval;
|
tree retval;
|
||||||
tree result, td1, td2, td3, elems, expr2;
|
tree result, td1, td2, td3, elems, expr2;
|
||||||
|
tree static_type, target_type, boff;
|
||||||
|
|
||||||
/* If we got here, we can't convert statically. Therefore,
|
/* If we got here, we can't convert statically. Therefore,
|
||||||
dynamic_cast<D&>(b) (b an object) cannot succeed. */
|
dynamic_cast<D&>(b) (b an object) cannot succeed. */
|
||||||
|
@ -632,20 +633,23 @@ build_dynamic_cast_1 (type, expr)
|
||||||
td1 = get_tinfo_fn_dynamic (expr);
|
td1 = get_tinfo_fn_dynamic (expr);
|
||||||
td1 = decay_conversion (td1);
|
td1 = decay_conversion (td1);
|
||||||
|
|
||||||
td2 = decay_conversion
|
target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
|
||||||
(get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (type))));
|
static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
|
||||||
td3 = decay_conversion
|
td2 = decay_conversion (get_tinfo_fn (target_type));
|
||||||
(get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (exprtype))));
|
td3 = decay_conversion (get_tinfo_fn (static_type));
|
||||||
|
|
||||||
|
/* Determine how T and V are related. */
|
||||||
|
boff = get_dynamic_cast_base_type (static_type, target_type);
|
||||||
|
|
||||||
elems = tree_cons
|
elems = tree_cons
|
||||||
(NULL_TREE, td1, tree_cons
|
(NULL_TREE, td1, tree_cons
|
||||||
(NULL_TREE, td2, tree_cons
|
(NULL_TREE, td2, tree_cons
|
||||||
(NULL_TREE, build_int_2 (1, 0), tree_cons
|
(NULL_TREE, boff, tree_cons
|
||||||
(NULL_TREE, expr2, tree_cons
|
(NULL_TREE, expr2, tree_cons
|
||||||
(NULL_TREE, td3, tree_cons
|
(NULL_TREE, td3, tree_cons
|
||||||
(NULL_TREE, expr1, NULL_TREE))))));
|
(NULL_TREE, expr1, NULL_TREE))))));
|
||||||
|
|
||||||
dcast_fn = get_identifier ("__dynamic_cast");
|
dcast_fn = get_identifier ("__dynamic_cast_2");
|
||||||
if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
|
if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
|
||||||
dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
|
dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
|
||||||
else
|
else
|
||||||
|
@ -656,7 +660,7 @@ build_dynamic_cast_1 (type, expr)
|
||||||
tmp = tree_cons
|
tmp = tree_cons
|
||||||
(NULL_TREE, TREE_TYPE (td1), tree_cons
|
(NULL_TREE, TREE_TYPE (td1), tree_cons
|
||||||
(NULL_TREE, TREE_TYPE (td1), tree_cons
|
(NULL_TREE, TREE_TYPE (td1), tree_cons
|
||||||
(NULL_TREE, integer_type_node, tree_cons
|
(NULL_TREE, integer_type_node, tree_cons
|
||||||
(NULL_TREE, ptr_type_node, tree_cons
|
(NULL_TREE, ptr_type_node, tree_cons
|
||||||
(NULL_TREE, TREE_TYPE (td1), tree_cons
|
(NULL_TREE, TREE_TYPE (td1), tree_cons
|
||||||
(NULL_TREE, ptr_type_node, void_list_node))))));
|
(NULL_TREE, ptr_type_node, void_list_node))))));
|
||||||
|
|
|
@ -90,6 +90,7 @@ static tree dfs_no_overlap_yet PROTO((tree, void *));
|
||||||
static int get_base_distance_recursive
|
static int get_base_distance_recursive
|
||||||
PROTO((tree, int, int, int, int *, tree *, tree,
|
PROTO((tree, int, int, int, int *, tree *, tree,
|
||||||
int, int *, int, int));
|
int, int *, int, int));
|
||||||
|
static int dynamic_cast_base_recurse PROTO((tree, tree, int, tree *));
|
||||||
static void expand_upcast_fixups
|
static void expand_upcast_fixups
|
||||||
PROTO((tree, tree, tree, tree, tree, tree, tree *));
|
PROTO((tree, tree, tree, tree, tree, tree, tree *));
|
||||||
static void fixup_virtual_upcast_offsets
|
static void fixup_virtual_upcast_offsets
|
||||||
|
@ -494,6 +495,77 @@ get_base_distance (parent, binfo, protect, path_ptr)
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Worker function for get_dynamic_cast_base_type. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
|
||||||
|
tree subtype;
|
||||||
|
tree binfo;
|
||||||
|
int via_virtual;
|
||||||
|
tree *offset_ptr;
|
||||||
|
{
|
||||||
|
tree binfos;
|
||||||
|
int i, n_baselinks;
|
||||||
|
int worst = -3;
|
||||||
|
|
||||||
|
if (BINFO_TYPE (binfo) == subtype)
|
||||||
|
{
|
||||||
|
if (via_virtual)
|
||||||
|
return -2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*offset_ptr = BINFO_OFFSET (binfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binfos = BINFO_BASETYPES (binfo);
|
||||||
|
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
|
||||||
|
for (i = 0; i < n_baselinks; i++)
|
||||||
|
{
|
||||||
|
tree base_binfo = TREE_VEC_ELT (binfos, i);
|
||||||
|
int rval;
|
||||||
|
|
||||||
|
if (!TREE_VIA_PUBLIC (base_binfo))
|
||||||
|
continue;
|
||||||
|
rval = dynamic_cast_base_recurse
|
||||||
|
(subtype, base_binfo,
|
||||||
|
via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
|
||||||
|
if (worst == -3)
|
||||||
|
worst = rval;
|
||||||
|
else if (rval >= 0)
|
||||||
|
worst = worst >= 0 ? -1 : worst;
|
||||||
|
else if (rval > -3)
|
||||||
|
worst = worst < rval ? worst : rval;
|
||||||
|
}
|
||||||
|
return worst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The dynamic cast runtime needs a hint about how the static SUBTYPE type started
|
||||||
|
from is related to the required TARGET type, in order to optimize the
|
||||||
|
inheritance graph search. This information is independant of the
|
||||||
|
current context, and ignores private paths, hence get_base_distance is
|
||||||
|
inappropriate. Return a TREE specifying the base offset, BOFF.
|
||||||
|
BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset BOFF,
|
||||||
|
and there are no public virtual SUBTYPE bases.
|
||||||
|
BOFF == -1, SUBTYPE occurs as multiple public non-virtual bases.
|
||||||
|
BOFF == -2, SUBTYPE occurs as multiple public virtual or non-virtual bases.
|
||||||
|
BOFF == -3, SUBTYPE is not a public base. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
get_dynamic_cast_base_type (subtype, target)
|
||||||
|
tree subtype;
|
||||||
|
tree target;
|
||||||
|
{
|
||||||
|
tree offset = NULL_TREE;
|
||||||
|
int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
|
||||||
|
0, &offset);
|
||||||
|
|
||||||
|
if (!boff)
|
||||||
|
return offset;
|
||||||
|
return build_int_2 (boff, -1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Search for a member with name NAME in a multiple inheritance lattice
|
/* Search for a member with name NAME in a multiple inheritance lattice
|
||||||
specified by TYPE. If it does not exist, return NULL_TREE.
|
specified by TYPE. If it does not exist, return NULL_TREE.
|
||||||
If the member is ambiguously referenced, return `error_mark_node'.
|
If the member is ambiguously referenced, return `error_mark_node'.
|
||||||
|
|
513
gcc/cp/tinfo.cc
513
gcc/cp/tinfo.cc
|
@ -62,100 +62,453 @@ extern "C" void
|
||||||
__rtti_user (void *addr, const char *name)
|
__rtti_user (void *addr, const char *name)
|
||||||
{ new (addr) __user_type_info (name); }
|
{ new (addr) __user_type_info (name); }
|
||||||
|
|
||||||
// dynamic_cast helper methods.
|
// Upcast for catch checking. OBJPTR points to the thrown object and might be
|
||||||
// Returns 1 if the cast succeeds, 0 otherwise. Stores the adjusted value
|
// NULL. Return 0 on failure, non-zero on success. Set *ADJPTR to adjusted
|
||||||
// in VALP.
|
// object pointer.
|
||||||
|
|
||||||
int __user_type_info::
|
int __user_type_info::
|
||||||
dcast (const type_info& to, int, void *addr, void **valp,
|
upcast (const type_info &target, void *objptr,
|
||||||
const type_info *, void *) const
|
void **adjptr) const
|
||||||
{
|
{
|
||||||
*valp = addr;
|
upcast_result result;
|
||||||
return (*this == to);
|
|
||||||
|
if (do_upcast (contained_public, target, objptr, result))
|
||||||
|
return 0;
|
||||||
|
*adjptr = result.target_obj;
|
||||||
|
return contained_public_p (result.whole2target);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __si_type_info::
|
// Down or cross cast for dynamic_cast. OBJPTR points to the most derrived
|
||||||
dcast (const type_info& to, int require_public, void *addr, void **valp,
|
// object, SUBPTR points to the static base object. Both must not be NULL.
|
||||||
const type_info *sub, void *subptr) const
|
// 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
|
||||||
{
|
{
|
||||||
if (*this == to)
|
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)
|
||||||
{
|
{
|
||||||
*valp = addr;
|
result.target_obj = objptr;
|
||||||
return 1;
|
result.base_type = nonvirtual_base_type;
|
||||||
|
result.whole2target = access_path;
|
||||||
|
return contained_nonpublic_p (access_path);
|
||||||
}
|
}
|
||||||
return base.dcast (to, require_public, addr, valp, sub, subptr);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __class_type_info::
|
// dynamic cast helper. ACCESS_PATH gives the access from the most derived
|
||||||
dcast (const type_info& desired, int is_public, void *objptr, void **valp,
|
// object to this base. TARGET indicates the desired type we want. OBJPTR
|
||||||
const type_info *sub, void *subptr) const
|
// 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
|
||||||
{
|
{
|
||||||
*valp = objptr;
|
if (objptr == subptr && *this == subtype)
|
||||||
|
|
||||||
if (*this == desired)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
int match_found = 0;
|
|
||||||
void *match = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n_bases; i++)
|
|
||||||
{
|
{
|
||||||
if (is_public && base_list[i].access != PUBLIC)
|
// The subobject we started from. Indicate how we are accessible from
|
||||||
continue;
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
void *p;
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
if (objptr)
|
// catch helper for single public inheritance types. See
|
||||||
{
|
// __user_type_info::do_upcast for semantics.
|
||||||
p = (char *)objptr + base_list[i].offset;
|
bool __si_type_info::
|
||||||
if (base_list[i].is_virtual)
|
do_upcast (sub_kind access_path,
|
||||||
p = *(void **)p;
|
const type_info &target, void *objptr,
|
||||||
}
|
upcast_result &__restrict result) const
|
||||||
else
|
{
|
||||||
/* Preserve null pointer. */
|
if (*this == target)
|
||||||
p = objptr;
|
{
|
||||||
|
result.target_obj = objptr;
|
||||||
if (base_list[i].base->dcast (desired, is_public, p, &p, sub, subptr))
|
result.base_type = nonvirtual_base_type;
|
||||||
{
|
result.whole2target = access_path;
|
||||||
if (! match_found)
|
return contained_nonpublic_p (access_path);
|
||||||
{
|
}
|
||||||
match_found = 1;
|
return base.do_upcast (access_path, target, objptr, result);
|
||||||
match = p;
|
}
|
||||||
}
|
|
||||||
else if (match != p)
|
// dynamic cast helper for single public inheritance types. See
|
||||||
{
|
// __user_type_info::do_dyncast for semantics. BOFF indicates how SUBTYPE
|
||||||
if (sub)
|
// types are inherited by TARGET types.
|
||||||
{
|
bool __si_type_info::
|
||||||
// Perhaps we're downcasting from *sub to desired; see if
|
do_dyncast (int boff, sub_kind access_path,
|
||||||
// subptr is a subobject of exactly one of {match_found,p}.
|
const type_info &target, void *objptr,
|
||||||
|
const type_info &subtype, void *subptr,
|
||||||
const __user_type_info &d =
|
dyncast_result &__restrict result) const
|
||||||
static_cast <const __user_type_info &> (desired);
|
{
|
||||||
|
if (objptr == subptr && *this == subtype)
|
||||||
void *os;
|
{
|
||||||
d.dcast (*sub, 1, match, &os);
|
// The subobject we started from. Indicate how we are accessible from
|
||||||
void *ns;
|
// the most derived object.
|
||||||
d.dcast (*sub, 1, p, &ns);
|
result.whole2sub = access_path;
|
||||||
|
return false;
|
||||||
if (os == ns)
|
}
|
||||||
// Both have the same subobject, so we can't disambiguate;
|
if (*this == target)
|
||||||
// i.e. subptr is a virtual base.
|
{
|
||||||
return 0;
|
result.target_obj = objptr;
|
||||||
else if (os == subptr)
|
result.whole2target = access_path;
|
||||||
continue;
|
if (boff >= 0)
|
||||||
else if (ns == subptr)
|
result.target2sub = ((char *)subptr - (char *)objptr) == boff
|
||||||
{
|
? contained_public : not_contained;
|
||||||
match = p;
|
else if (boff == -3)
|
||||||
continue;
|
result.target2sub = not_contained;
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
else
|
return base.do_dyncast (boff, access_path,
|
||||||
// We're not downcasting, so we can't disambiguate.
|
target, objptr, subtype, subptr, result);
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
|
// 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;
|
||||||
|
if (p)
|
||||||
|
p = (char *)p + base_list[i].offset;
|
||||||
|
if (base_list[i].is_virtual)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p = *(void **)p;
|
||||||
|
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))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 == -3)
|
||||||
|
result.target2sub = not_contained;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool result_ambig = false;
|
||||||
|
for (size_t i = n_bases; i--;)
|
||||||
|
{
|
||||||
|
dyncast_result result2;
|
||||||
|
void *p = (char *)objptr + base_list[i].offset;
|
||||||
|
sub_kind sub_access = access_path;
|
||||||
|
if (base_list[i].is_virtual)
|
||||||
|
{
|
||||||
|
p = *(void **)p;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
*valp = match;
|
return result_ambig;
|
||||||
return match_found;
|
}
|
||||||
|
|
||||||
|
// 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 = (char *)objptr + base_list[i].offset;
|
||||||
|
if (base_list[i].is_virtual)
|
||||||
|
{
|
||||||
|
if (boff == -1)
|
||||||
|
continue; // Not a virtual base, so can't be here.
|
||||||
|
p = *(void **)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
161
gcc/cp/tinfo.h
161
gcc/cp/tinfo.h
|
@ -10,10 +10,138 @@
|
||||||
struct __user_type_info : public std::type_info {
|
struct __user_type_info : public std::type_info {
|
||||||
__user_type_info (const char *n) : type_info (n) {}
|
__user_type_info (const char *n) : type_info (n) {}
|
||||||
|
|
||||||
// If our type can be converted to the desired type,
|
// If our type can be upcast to a public and unambiguous base, then return
|
||||||
// return the pointer, adjusted accordingly; else return 0.
|
// non-zero and set RES to point to the base object. OBJ points to the throw
|
||||||
virtual int dcast (const type_info &, int, void *, void **,
|
// object and can be NULL, if there is no object to adjust.
|
||||||
const type_info * = 0, void * = 0) const;
|
int upcast (const type_info &target, void *obj, void **res) const;
|
||||||
|
|
||||||
|
// If our type can be dynamicly cast to the target type, then return
|
||||||
|
// pointer to the target object. OBJ is the pointer to the most derived
|
||||||
|
// type and cannot be NULL. SUBTYPE and SUBOBJ indicate the static type
|
||||||
|
// base object from whence we came, it cannot be NULL. SUBTYPE cannot be
|
||||||
|
// the same as TARGET. TARGET cannot be a base of SUBTYPE.
|
||||||
|
// BOFF indicates how SUBTYPE is related to TARGET.
|
||||||
|
// BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset
|
||||||
|
// BOFF, and there are no public virtual SUBTYPE bases.
|
||||||
|
// Therefore check if SUBOBJ is at offset BOFF when we find a target
|
||||||
|
// BOFF == -1, SUBTYPE occurs as multiple public non-virtual bases.
|
||||||
|
// Lazily search the non-virtual bases of TARGET.
|
||||||
|
// BOFF == -2, SUBTYPE occurs as multiple public virtual or non-virtual bases.
|
||||||
|
// Lazily search all the bases of TARGET.
|
||||||
|
// BOFF == -3, SUBTYPE is not a public base.
|
||||||
|
// For backwards compatibility set BOFF to -2, that is the safe `don't know'
|
||||||
|
// value. We don't care about SUBTYPES as private bases of TARGET, as they
|
||||||
|
// can never succeed as downcasts, only as crosscasts -- and then only if
|
||||||
|
// they are virtual. This is more complicated that it might seem.
|
||||||
|
void *dyncast (int boff,
|
||||||
|
const type_info &target, void *obj,
|
||||||
|
const type_info &subtype, void *subobj) const;
|
||||||
|
|
||||||
|
// non_virtual_base_type is used to indicate that a base class is via a
|
||||||
|
// non-virtual access path.
|
||||||
|
static const type_info *const nonvirtual_base_type
|
||||||
|
= static_cast <const type_info *> (0) + 1;
|
||||||
|
|
||||||
|
// 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_mask = 4, // contained within us
|
||||||
|
contained_virtual_mask = 1, // via a virtual path
|
||||||
|
contained_public_mask = 2, // via a public path
|
||||||
|
contained_private = contained_mask,
|
||||||
|
contained_public = contained_mask | contained_public_mask
|
||||||
|
};
|
||||||
|
// some predicate functions for sub_kind
|
||||||
|
static inline bool contained_p (sub_kind access_path)
|
||||||
|
{
|
||||||
|
return access_path >= contained_mask;
|
||||||
|
}
|
||||||
|
static inline bool contained_public_p (sub_kind access_path)
|
||||||
|
{
|
||||||
|
return access_path >= contained_public;
|
||||||
|
}
|
||||||
|
static inline bool contained_nonpublic_p (sub_kind access_path)
|
||||||
|
{
|
||||||
|
return (access_path & contained_public) == contained_mask;
|
||||||
|
}
|
||||||
|
static inline bool contained_nonvirtual_p (sub_kind access_path)
|
||||||
|
{
|
||||||
|
return (access_path & (contained_mask | contained_virtual_mask))
|
||||||
|
== contained_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct upcast_result
|
||||||
|
{
|
||||||
|
void *target_obj; // pointer to target object or NULL (init NULL)
|
||||||
|
sub_kind whole2target; // path from most derived object to target
|
||||||
|
const type_info *base_type; // where we found the target, (init NULL)
|
||||||
|
// if in vbase the __user_type_info of vbase)
|
||||||
|
// if a non-virtual base then 1
|
||||||
|
// else NULL
|
||||||
|
public:
|
||||||
|
upcast_result ()
|
||||||
|
:target_obj (NULL), whole2target (unknown), base_type (NULL)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
struct dyncast_result
|
||||||
|
{
|
||||||
|
void *target_obj; // pointer to target object or NULL (init NULL)
|
||||||
|
sub_kind whole2target; // path from most derived object to target
|
||||||
|
sub_kind whole2sub; // path from most derived object to sub object
|
||||||
|
sub_kind target2sub; // path from target to sub object
|
||||||
|
|
||||||
|
public:
|
||||||
|
dyncast_result ()
|
||||||
|
:target_obj (NULL), whole2target (unknown),
|
||||||
|
whole2sub (unknown), target2sub (unknown)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Helper for upcast. See if TARGET is us, or one of our bases. ACCESS_PATH
|
||||||
|
// gives the access from the start object. Return TRUE if we know the catch
|
||||||
|
// fails.
|
||||||
|
virtual bool do_upcast (sub_kind access_path,
|
||||||
|
const type_info &target, void *obj,
|
||||||
|
upcast_result &__restrict result) const;
|
||||||
|
// Helper for dyncast. BOFF indicates how the SUBTYPE is related to TARGET.
|
||||||
|
// ACCESS_PATH indicates the access from the most derived object. It is
|
||||||
|
// used to prune the DAG walk. All information about what we find is put
|
||||||
|
// into RESULT. Return true, if the match we have found is ambiguous.
|
||||||
|
virtual bool do_dyncast (int boff, sub_kind access_path,
|
||||||
|
const type_info &target, void *obj,
|
||||||
|
const type_info &subtype, void *subptr,
|
||||||
|
dyncast_result &__restrict result) const;
|
||||||
|
public:
|
||||||
|
// Indicate whether SUBPTR of type SUBTYPE is contained publicly within
|
||||||
|
// OBJPTR. OBJPTR points to this base object. BOFF indicates how SUBTYPE
|
||||||
|
// objects might be contained within this type. If SUBPTR is one of our
|
||||||
|
// SUBTYPE bases, indicate virtuality. Returns not_contained for non
|
||||||
|
// containment or private containment.
|
||||||
|
sub_kind find_public_subobj (int boff, const type_info &subtype,
|
||||||
|
void *objptr, void *subptr) const
|
||||||
|
{
|
||||||
|
if (boff >= 0)
|
||||||
|
return ((char *)subptr - (char *)objptr) == boff
|
||||||
|
? contained_public : not_contained;
|
||||||
|
if (boff == -3)
|
||||||
|
return not_contained;
|
||||||
|
return do_find_public_subobj (boff, subtype, objptr, subptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Helper for find_subobj. BOFF indicates how SUBTYPE bases are inherited by
|
||||||
|
// the type started from -- which is not necessarily the current type.
|
||||||
|
// OBJPTR points to the current base.
|
||||||
|
virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
|
||||||
|
void *objptr, void *subptr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// type_info for a class with one public, nonvirtual base class.
|
// type_info for a class with one public, nonvirtual base class.
|
||||||
|
@ -25,8 +153,16 @@ public:
|
||||||
__si_type_info (const char *n, const __user_type_info &b)
|
__si_type_info (const char *n, const __user_type_info &b)
|
||||||
: __user_type_info (n), base (b) { }
|
: __user_type_info (n), base (b) { }
|
||||||
|
|
||||||
virtual int dcast (const type_info &, int, void *, void **,
|
private:
|
||||||
const type_info * = 0, void * = 0) const;
|
virtual bool do_upcast (sub_kind access_path,
|
||||||
|
const type_info &target, void *obj,
|
||||||
|
upcast_result &__restrict result) const;
|
||||||
|
virtual bool do_dyncast (int boff, sub_kind access_path,
|
||||||
|
const type_info &target, void *obj,
|
||||||
|
const type_info &subtype, void *subptr,
|
||||||
|
dyncast_result &__restrict result) const;
|
||||||
|
virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
|
||||||
|
void *objptr, void *subptr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// type_info for a general class.
|
// type_info for a general class.
|
||||||
|
@ -49,7 +185,14 @@ struct __class_type_info : public __user_type_info {
|
||||||
__class_type_info (const char *name, const base_info *bl, size_t bn)
|
__class_type_info (const char *name, const base_info *bl, size_t bn)
|
||||||
: __user_type_info (name), base_list (bl), n_bases (bn) {}
|
: __user_type_info (name), base_list (bl), n_bases (bn) {}
|
||||||
|
|
||||||
// This is a little complex.
|
public:
|
||||||
virtual int dcast (const type_info &, int, void *, void **,
|
virtual bool do_upcast (sub_kind access_path,
|
||||||
const type_info * = 0, void * = 0) const;
|
const type_info &target, void *obj,
|
||||||
|
upcast_result &__restrict result) const;
|
||||||
|
virtual bool do_dyncast (int boff, sub_kind access_path,
|
||||||
|
const type_info &target, void *obj,
|
||||||
|
const type_info &subtype, void *subptr,
|
||||||
|
dyncast_result &__restrict result) const;
|
||||||
|
virtual sub_kind do_find_public_subobj (int boff, const type_info &subtype,
|
||||||
|
void *objptr, void *subptr) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,8 +108,7 @@ __throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r,
|
||||||
if (const __user_type_info *p
|
if (const __user_type_info *p
|
||||||
= dynamic_cast <const __user_type_info *> (&throw_type))
|
= dynamic_cast <const __user_type_info *> (&throw_type))
|
||||||
{
|
{
|
||||||
/* The 1 skips conversions to private bases. */
|
return p->upcast (catch_type, objptr, valp);
|
||||||
return p->dcast (catch_type, 1, objptr, valp);
|
|
||||||
}
|
}
|
||||||
else if (const __pointer_type_info *fr =
|
else if (const __pointer_type_info *fr =
|
||||||
dynamic_cast <const __pointer_type_info *> (&throw_type))
|
dynamic_cast <const __pointer_type_info *> (&throw_type))
|
||||||
|
@ -154,10 +153,7 @@ __throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r,
|
||||||
return 1;
|
return 1;
|
||||||
else if (const __user_type_info *p
|
else if (const __user_type_info *p
|
||||||
= dynamic_cast <const __user_type_info *> (subfr))
|
= dynamic_cast <const __user_type_info *> (subfr))
|
||||||
{
|
return p->upcast (*subto, objptr, valp);
|
||||||
/* The 1 skips conversions to private bases. */
|
|
||||||
return p->dcast (*subto, 1, objptr, valp);
|
|
||||||
}
|
|
||||||
else if (const __pointer_type_info *pfr
|
else if (const __pointer_type_info *pfr
|
||||||
= dynamic_cast <const __pointer_type_info *> (subfr))
|
= dynamic_cast <const __pointer_type_info *> (subfr))
|
||||||
{
|
{
|
||||||
|
@ -274,14 +270,20 @@ __rtti_array (void *addr, const char *name)
|
||||||
|
|
||||||
extern "C" void *
|
extern "C" void *
|
||||||
__dynamic_cast (const type_info& (*from)(void), const type_info& (*to)(void),
|
__dynamic_cast (const type_info& (*from)(void), const type_info& (*to)(void),
|
||||||
int require_public, void *address,
|
int require_public, void *address, const type_info & (*sub)(void), void *subptr)
|
||||||
const type_info & (*sub)(void), void *subptr)
|
|
||||||
{
|
{
|
||||||
void *ret;
|
if (!require_public) abort();
|
||||||
if (static_cast <const __user_type_info &> (from ()).dcast
|
return static_cast <__user_type_info const &> (from ()).dyncast
|
||||||
(to (), require_public, address, &ret, &(sub ()), subptr))
|
(/*boff=*/-2, to (), address, sub (), subptr);
|
||||||
return ret;
|
}
|
||||||
return 0;
|
|
||||||
|
extern "C" void *
|
||||||
|
__dynamic_cast_2 (const type_info& (*from)(void), const type_info& (*to)(void),
|
||||||
|
int boff,
|
||||||
|
void *address, const type_info & (*sub)(void), void *subptr)
|
||||||
|
{
|
||||||
|
return static_cast <__user_type_info const &> (from ()).dyncast
|
||||||
|
(boff, to (), address, sub (), subptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// type_info nodes and functions for the builtin types. The mangling here
|
// type_info nodes and functions for the builtin types. The mangling here
|
||||||
|
|
Loading…
Reference in New Issue