RTTI draft proposal
Jason Merrill
jason at cygnus.com
Thu Aug 19 22:31:49 UTC 1999
>>>>> Daveed Vandevoorde <daveed at edg.com> writes:
> the typeid, throw or catch. Basic type information (such as for "int",
> "bool", etc.) could be kept in the run-time support library but the benefits
> of that may be limited.
g++ currently does this.
> Assuming that after linking and loading only one type_info structure is
> active for any particular type symbol
We've found that we can't always rely on that, when people build shared
libraries with -B symbolic. So we fall back on strcmp of the mangled name.
> std::extended_type_info derives from std::type_info but adds no fields
> to the latter; it is introduced solely to follow the suggestion of the
> C++ standard.
That seems wrong; the idea of extended_type_info was supposed to extend the
type_info API so that the user could access more information about
classes. Stuff like member lists and whatnot. If we aren't doing anything
like that, we shouldn't introduce extended_type_info.
> 6. std::__qualifier_type_info is similar to std::__pointer_type_info but
> describes top level qualifiers as in "int const" and "char *const".
Where would this be used? I included it in the G++ implementation, but
have since come to the conclusion that it was a mistake.
> 7. std::__class_type_info introduces a variable length structure.
> The variable part that follows consists of a sequence of base class
> descriptions having the following structure:
> struct std::__base_class_info {
> std::type_info *type; /* Null if unused. */
> std::ptrdiff_t offset;
> std::__base_class_index next; /* Hash table link. */
> int is_direct: 1;
> int is_floating: 1; /* I.e., virtual or base of virtual subobject. */
> int is_virtual: 1; /* Implies is_floating. */
> int is_shared: 1; /* Implies is_floating and the virtual subobject
> appears on multiple derivation paths. */
> int is_accessible: 1;
> int is_ambiguous: 1;
> };
So you're proposing that we store the info about all bases in the type_info
for a class, not just the info for direct bases? That would certainly make
upcasts (i.e. EH matching and cross dynamic_casts) faster, at the price of
larger RTTI info.
> The fixed length introduction adds the following fields to std::type_info:
> . a word with flags describing details about the class such as whether
> it is a class/struct/union and whether it is polymorphic.
Why?
> . a hashvalue that can be used for quick lookups in a variable length
> structure describing base classes.
How is this calculated/used?
> . the number of base class descriptions that follow it (a power of two).
Why a power of two?
> The dynamic_cast algorithm
> --------------------------
> . If, in the most derived object pointed (referred) to by v, v points
> (refers) to a public base class sub-object of a T object [note: this can
> be checked at compile time], and if only one object of type T is derived
> from the sub-object pointed (referred) to by v, the result is a pointer
> (an lvalue referring) to that T object.
More precisely, we can check at compile time whether T has a unique base
subobject of type typeof(*v). We don't know anything about the true
referent of v.
> . Otherwise, if v points (refers) to a public base class sub-object of the
> most derived object, and the type of the most derived object has an
> unambiguous public base class of type T, the result is a pointer (an
> lvalue referring) to the T sub-object of the most derived object.
> . Otherwise, the run-time check fails.
> The first check corresponds to a "base-to-derived cast" and the second to a
> "cross cast". These tests are implemented by std::__dynamic_cast.
> void* std::__dynamic_cast(void *sub, std::__class_type_info *src,
> std::__class_type_info *dst,
> std::ptrdiff_t src2dst_offset) {
> // Pick up vtable pointer from given object:
> void *vptr = *(void**)sub;
> if (src2dst_offset>=0 && NO_VBASE(sub, vptr)) {
> // If the type of "v" was not an accessible nonvirtual base type of
> // "T", src2dst_offset should have been set to -1 if it was an
> // accessible but floating base of "T" and to -2 if it was not at all
> // an accessible base of "T".
> // In addition, the vtable should contain an entry to indicate that
> // the complete object has no virtual bases (e.g., a count of the
> // vbase locator entries).
> return (char*)sub+src2dst_offset;
What about the case where v doesn't point to a base subobject of T at all,
even though the compile time check says it could? Consider
struct V;
struct T: public V;
struct A: public V;
struct B: public A, public T;
B b;
V* v = (V*)(A*)&b;
dynamic_cast<T*>(v);
The static check says this could be a downcast, but it's really a cross-cast.
Who passes in src2dst_offset?
In a typical downcast, the offset from src to dst will be negative.
> } else {
> // Slower case
> void *result = 0;
> if (src2dst_offset==-1) {
> // Possibly a "floating" base-to-derived cast:
> result = floating_base2derived(sub, src, dst);
> }
> if (result==0) {
> // The base-to-derived case did not succeed, so we should attempt
> // the cross-cast (which is really a derived-to-base cast from the
> // complete object):
> result = derived2base(complete, dst);
> }
> }
> return result;
> }
Where are the defns of floating_base2derived and derived2base?
> The exception handler matching algorithm
> ----------------------------------------
> bool __eh_match(std::type_info *thrown_type,
> std::type_info *handled_type) {
> if (thrown_type == handled_type) {
> return true;
> } else if (IS_REFTYPE(handled_type)) {
> std::type_info *caught_type = REMOVE_REFTYPE(handled_type);
> if (IS_CVQUAL(caught_type)) {
> caught_type = REMOVE_CVQUAL(caught_type);
> }
> return thrown_type==caught_type;
We do derived-to-base conversions for non-pointers, too.
3 A handler is a match for a throw-expression with an object of type E
if
--The handler is of type cv T or cv T& and E and T are the same type
(ignoring the top-level cv-qualifiers), or
--the handler is of type cv T or cv T& and T is an unambiguous public
base class of E, or
--the handler is of type cv1 T* cv2 and E is a pointer type that can
be converted to the type of the handler by either or both of
--a standard pointer conversion (_conv.ptr_) not involving conver-
sions to pointers to private or protected or ambiguous classes
--a qualification conversion
FWIW, g++ turns all dynamic_casts into upcasts, using the original pointer
for disambiguation. I'm not yet convinced that there's a good way to
accelerate downcasts.
Jason
More information about the cxx-abi-dev
mailing list