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:
Nathan Sidwell 1999-09-21 14:40:13 +00:00 committed by Nathan Sidwell
parent e36e6e0261
commit 4a9e5c6725
7 changed files with 716 additions and 110 deletions

View File

@ -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>
* cp-tree.h (finish_stmt_expr): Change prototype.

View File

@ -3596,6 +3596,7 @@ extern int types_overlap_p PROTO((tree, tree));
extern tree get_vbase PROTO((tree, tree));
extern tree get_binfo PROTO((tree, tree, int));
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 tree lookup_field PROTO((tree, tree, int, int));
extern int lookup_fnfields_1 PROTO((tree, tree));

View File

@ -588,6 +588,7 @@ build_dynamic_cast_1 (type, expr)
{
tree retval;
tree result, td1, td2, td3, elems, expr2;
tree static_type, target_type, boff;
/* If we got here, we can't convert statically. Therefore,
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 = decay_conversion (td1);
td2 = decay_conversion
(get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (type))));
td3 = decay_conversion
(get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (exprtype))));
target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
td2 = decay_conversion (get_tinfo_fn (target_type));
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
(NULL_TREE, td1, 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, td3, tree_cons
(NULL_TREE, td3, tree_cons
(NULL_TREE, expr1, NULL_TREE))))));
dcast_fn = get_identifier ("__dynamic_cast");
dcast_fn = get_identifier ("__dynamic_cast_2");
if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
else
@ -656,7 +660,7 @@ build_dynamic_cast_1 (type, expr)
tmp = 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, TREE_TYPE (td1), tree_cons
(NULL_TREE, ptr_type_node, void_list_node))))));

View File

@ -90,6 +90,7 @@ static tree dfs_no_overlap_yet PROTO((tree, void *));
static int get_base_distance_recursive
PROTO((tree, int, int, int, int *, tree *, tree,
int, int *, int, int));
static int dynamic_cast_base_recurse PROTO((tree, tree, int, tree *));
static void expand_upcast_fixups
PROTO((tree, tree, tree, tree, tree, tree, tree *));
static void fixup_virtual_upcast_offsets
@ -494,6 +495,77 @@ get_base_distance (parent, binfo, protect, path_ptr)
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
specified by TYPE. If it does not exist, return NULL_TREE.
If the member is ambiguously referenced, return `error_mark_node'.

View File

@ -62,100 +62,453 @@ extern "C" void
__rtti_user (void *addr, const char *name)
{ new (addr) __user_type_info (name); }
// dynamic_cast helper methods.
// Returns 1 if the cast succeeds, 0 otherwise. Stores the adjusted value
// in VALP.
// Upcast for catch checking. OBJPTR points to the thrown object and might be
// NULL. Return 0 on failure, non-zero on success. Set *ADJPTR to adjusted
// object pointer.
int __user_type_info::
dcast (const type_info& to, int, void *addr, void **valp,
const type_info *, void *) const
upcast (const type_info &target, void *objptr,
void **adjptr) const
{
*valp = addr;
return (*this == to);
upcast_result result;
if (do_upcast (contained_public, target, objptr, result))
return 0;
*adjptr = result.target_obj;
return contained_public_p (result.whole2target);
}
int __si_type_info::
dcast (const type_info& to, int require_public, void *addr, void **valp,
const type_info *sub, void *subptr) const
// Down or cross cast for dynamic_cast. OBJPTR points to the most derrived
// object, SUBPTR points to the static base object. Both must not be NULL.
// TARGET specifies the desired target type, SUBTYPE specifies the static
// type. Both must be defined. Returns adjusted object pointer on success,
// NULL on failure. [expr.dynamic.cast]/8 says 'unambiguous public base'. This
// itself is an ambiguous statement. We choose it to mean the base must be
// separately unambiguous and public, rather than unambiguous considering only
// public bases.
void *__user_type_info::
dyncast (int boff,
const type_info &target, void *objptr,
const type_info &subtype, void *subptr) const
{
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;
return 1;
result.target_obj = objptr;
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::
dcast (const type_info& desired, int is_public, void *objptr, void **valp,
const type_info *sub, void *subptr) const
// dynamic cast helper. ACCESS_PATH gives the access from the most derived
// object to this base. TARGET indicates the desired type we want. OBJPTR
// points to this base within the object. SUBTYPE indicates the static type
// started from and SUBPTR points to that base within the most derived object.
// Fill in RESULT with what we find. Return true if we have located an
// ambiguous match.
bool __user_type_info::
do_dyncast (int, sub_kind access_path,
const type_info &target, void *objptr,
const type_info &subtype, void *subptr,
dyncast_result &__restrict result) const
{
*valp = objptr;
if (*this == desired)
return 1;
int match_found = 0;
void *match = 0;
for (size_t i = 0; i < n_bases; i++)
if (objptr == subptr && *this == subtype)
{
if (is_public && base_list[i].access != PUBLIC)
continue;
// The subobject we started from. Indicate how we are accessible from
// the most derived object.
result.whole2sub = access_path;
return false;
}
if (*this == target)
{
result.target_obj = objptr;
result.whole2target = access_path;
result.target2sub = not_contained;
return false;
}
return false;
}
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)
{
p = (char *)objptr + base_list[i].offset;
if (base_list[i].is_virtual)
p = *(void **)p;
}
else
/* Preserve null pointer. */
p = objptr;
if (base_list[i].base->dcast (desired, is_public, p, &p, sub, subptr))
{
if (! match_found)
{
match_found = 1;
match = p;
}
else if (match != p)
{
if (sub)
{
// Perhaps we're downcasting from *sub to desired; see if
// subptr is a subobject of exactly one of {match_found,p}.
const __user_type_info &d =
static_cast <const __user_type_info &> (desired);
void *os;
d.dcast (*sub, 1, match, &os);
void *ns;
d.dcast (*sub, 1, p, &ns);
if (os == ns)
// Both have the same subobject, so we can't disambiguate;
// i.e. subptr is a virtual base.
return 0;
else if (os == subptr)
continue;
else if (ns == subptr)
{
match = p;
continue;
}
}
else
// We're not downcasting, so we can't disambiguate.
return 0;
}
// catch helper for single public inheritance types. See
// __user_type_info::do_upcast for semantics.
bool __si_type_info::
do_upcast (sub_kind access_path,
const type_info &target, void *objptr,
upcast_result &__restrict result) const
{
if (*this == target)
{
result.target_obj = objptr;
result.base_type = nonvirtual_base_type;
result.whole2target = access_path;
return contained_nonpublic_p (access_path);
}
return base.do_upcast (access_path, target, objptr, result);
}
// dynamic cast helper for single public inheritance types. See
// __user_type_info::do_dyncast for semantics. BOFF indicates how SUBTYPE
// types are inherited by TARGET types.
bool __si_type_info::
do_dyncast (int boff, sub_kind access_path,
const type_info &target, void *objptr,
const type_info &subtype, void *subptr,
dyncast_result &__restrict result) const
{
if (objptr == subptr && *this == subtype)
{
// The subobject we started from. Indicate how we are accessible from
// the most derived object.
result.whole2sub = access_path;
return false;
}
if (*this == target)
{
result.target_obj = objptr;
result.whole2target = access_path;
if (boff >= 0)
result.target2sub = ((char *)subptr - (char *)objptr) == boff
? contained_public : not_contained;
else if (boff == -3)
result.target2sub = not_contained;
return false;
}
return base.do_dyncast (boff, access_path,
target, objptr, subtype, subptr, result);
}
// find_public_subobj helper. See __user_type_info::do_find_public_subobj or
// semantics. BOFF indicates how SUBTYPE types are inherited by the original
// target object.
__user_type_info::sub_kind __si_type_info::
do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *subptr) const
{
if (subptr == objptr && subtype == *this)
return contained_public;
return base.do_find_public_subobj (boff, subtype, objptr, subptr);
}
// catch helper for multiple or non-public inheritance types. See
// __user_type_info::do_upcast for semantics.
bool __class_type_info::
do_upcast (sub_kind access_path,
const type_info &target, void *objptr,
upcast_result &__restrict result) const
{
if (*this == target)
{
result.target_obj = objptr;
result.base_type = nonvirtual_base_type;
result.whole2target = access_path;
return contained_nonpublic_p (access_path);
}
for (size_t i = n_bases; i--;)
{
upcast_result result2;
void *p = objptr;
sub_kind sub_access = access_path;
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 match_found;
return result_ambig;
}
// find_public_subobj helper for non-public or multiple inheritance types. See
// __user_type_info::do_find_public_subobj for semantics. We make use of BOFF
// to prune the base class walk.
__user_type_info::sub_kind __class_type_info::
do_find_public_subobj (int boff, const type_info &subtype, void *objptr, void *subptr) const
{
if (objptr == subptr && subtype == *this)
return contained_public;
for (size_t i = n_bases; i--;)
{
if (base_list[i].access != PUBLIC)
continue; // Not public, can't be here.
void *p = (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;
}

View File

@ -10,10 +10,138 @@
struct __user_type_info : public std::type_info {
__user_type_info (const char *n) : type_info (n) {}
// If our type can be converted to the desired type,
// return the pointer, adjusted accordingly; else return 0.
virtual int dcast (const type_info &, int, void *, void **,
const type_info * = 0, void * = 0) const;
// If our type can be upcast to a public and unambiguous base, then return
// non-zero and set RES to point to the base object. OBJ points to the throw
// object and can be NULL, if there is no object to adjust.
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.
@ -25,8 +153,16 @@ public:
__si_type_info (const char *n, const __user_type_info &b)
: __user_type_info (n), base (b) { }
virtual int dcast (const type_info &, int, void *, void **,
const type_info * = 0, void * = 0) const;
private:
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.
@ -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)
: __user_type_info (name), base_list (bl), n_bases (bn) {}
// This is a little complex.
virtual int dcast (const type_info &, int, void *, void **,
const type_info * = 0, void * = 0) const;
public:
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;
};

View File

@ -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
= dynamic_cast <const __user_type_info *> (&throw_type))
{
/* The 1 skips conversions to private bases. */
return p->dcast (catch_type, 1, objptr, valp);
return p->upcast (catch_type, objptr, valp);
}
else if (const __pointer_type_info *fr =
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;
else if (const __user_type_info *p
= dynamic_cast <const __user_type_info *> (subfr))
{
/* The 1 skips conversions to private bases. */
return p->dcast (*subto, 1, objptr, valp);
}
return p->upcast (*subto, objptr, valp);
else if (const __pointer_type_info *pfr
= dynamic_cast <const __pointer_type_info *> (subfr))
{
@ -274,14 +270,20 @@ __rtti_array (void *addr, const char *name)
extern "C" void *
__dynamic_cast (const type_info& (*from)(void), const type_info& (*to)(void),
int require_public, void *address,
const type_info & (*sub)(void), void *subptr)
int require_public, void *address, const type_info & (*sub)(void), void *subptr)
{
void *ret;
if (static_cast <const __user_type_info &> (from ()).dcast
(to (), require_public, address, &ret, &(sub ()), subptr))
return ret;
return 0;
if (!require_public) abort();
return static_cast <__user_type_info const &> (from ()).dyncast
(/*boff=*/-2, to (), address, sub (), subptr);
}
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