Commit 4a9e5c67 by Nathan Sidwell Committed by Nathan Sidwell

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
parent e36e6e02
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.
......
......@@ -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));
......
......@@ -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))))));
......
......@@ -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'.
......
......@@ -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;
};
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment