+Fri Apr 12 09:08:27 1996 Bob Manson <manson@charmed.cygnus.com>
+
+ * search.c (expand_upcast_fixups): Mark the new fixup as
+ DECL_ARTIFICIAL.
+
+Thu Apr 11 03:57:09 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * init.c (build_new): Use a TARGET_EXPR for alloc_expr.
+
+ * class.c (set_rtti_entry): Fix for thunks.
+
+ * decl2.c (import_export_decl): Still emit typeinfo fns for
+ cv-variants of builtin types.
+
+ * rtti.c (expand_class_desc): Set up base_info_type_node here.
+ (init_rtti_processing): Instead of here.
+
+Wed Apr 10 14:17:13 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * rtti.c (init_rtti_processing): Do init regardless of -frtti.
+ (build_typeid): Only complain about taking dynamic typeid without
+ -frtti.
+
+ * decl2.c: flag_rtti defaults to 1.
+
+ * rtti.c (get_tinfo_var): The general class case is now smaller.
+ (init_rtti_processing): Pack the latter three fields of base_info
+ into 32 bits.
+
+Wed Apr 10 13:50:14 1996 Mike Stump <mrs@cygnus.com>
+
+ * init.c (expand_member_init): Don't dump if name is NULL_TREE.
+
+Wed Apr 10 12:56:02 1996 Mike Stump <mrs@cygnus.com>
+
+ * search.c (make_memoized_table_entry): Undefer the pop, if necessary.
+ (push_memoized_context): Split out code to undefer pop_type_level to
+ (clear_memoized_cache): here.
+ (pop_memoized_context): We can only handle one layer of deferral of
+ pop_type_level so clear the cache, if there was a previous level.
+
+Tue Apr 9 23:06:09 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * rtti.c (init_rtti_processing): Build up base_info_type_node.
+ (expand_class_desc): Use one pointer to an array of base_info
+ structs, passed using a CONSTRUCTOR.
+
+Tue Apr 9 14:20:57 1996 Mike Stump <mrs@cygnus.com>
+
+ * class.c (build_vbase_path): Remove block extern for
+ flag_assume_nonnull_objects here.
+ (build_vfn_ref): Split out functionality into build_vtbl_ref.
+ (build_vtbl_ref): New routine.
+ (build_vtable): Set up rtti info here.
+ (add_virtual_function): Note in CLASSTYPE_RTTI the best
+ place where we can get the rtti pointers from to avoid having to
+ search around for a place.
+ (finish_base_struct): Ditto.
+ (finish_struct_1): Ditto. Never create totally new vtables with totally
+ new vtable pointers for rtti. Disable code to layout vtable pointers
+ better until we want to break binary compatibility.
+ * rtti.c (build_headof_sub): New routine to convert down to a
+ sub-object that has an rtti pointer in the vtable.
+ (build_headof): Use it. Also, use build_vtbl_ref now to be more
+ maintainable.
+ (build_dynamic_cast): Make sure we have saved it, if we need to.
+ * search.c (dfs_init_vbase_pointers): Disable code that deals with
+ a more efficient vtable layout, enable later.
+ * call.c (flag_assume_nonnull_objects): Moved declaration to
+ * cp-tree.h: here. Declare build_vtbl_ref.
+ * pt.c (instantiate_class_template): Use NULL_TREE instead of 0 in
+ function calls that want a tree.
+
+Tue Apr 9 12:10:26 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * rtti.c (build_dynamic_cast): Handle downcasting to X* given
+ other X subobjects in the most derived type. Ack.
+
+ * rtti.c (build_dynamic_cast): No need to strip cv-quals here,
+ get_typeid will do it for us.
+ (get_typeid_1): Break out call-building for expand_*_desc to use.
+ (get_typeid): Call it.
+ (expand_*_desc): Ditto.
+ * decl.c (init_decl_processing): Don't set TYPE_BUILT_IN on char *
+ and void *.
+ (init_decl_processing): Lose builtin_type_tdescs lossage.
+ * decl2.c (finish_vtable_vardecl): Remove obsolete code.
+
+Mon Apr 8 17:23:23 1996 Bob Manson <manson@charmed.cygnus.com>
+
+ * pt.c (tsubst): When calling set_nested_typename, use
+ TYPE_NESTED_NAME (current_class_type) instead of
+ current_class_name.
+
+ * decl.c (pushdecl): Ditto.
+ (pushdecl_class_level): Ditto.
+ (grokdeclarator): Use NULL_TREE instead of 0 in the call to
+ set_nested_typename.
+
+Sun Apr 7 10:44:31 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * rtti.c (synthesize_tinfo_fn): Handle arrays.
+
+ * cp-tree.h (DECL_REALLY_EXTERN): New macro.
+
+Sat Apr 6 13:56:27 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * rtti.c (throw_bad_cast): Use entry point __throw_bad_cast.
+ (init_rtti_processing): Lose bad_cast_type.
+ (build_dynamic_cast): Use throw_bad_cast.
+
+ * rtti.c (synthesize_tinfo_fn): Handle enums and pmfs.
+
+ * decl2.c (finish_file): Don't synthesize artificial functions
+ that are external and not inline.
+
+ * rtti.c (get_tinfo_fn): If at_eof, call import_export_decl.
+
+ * decl2.c (finish_file): Handle having new inlines added to
+ saved_inlines by synthesis.
+
+ * rtti.c (get_bad_cast_node): Don't require <typeinfo>.
+
+Fri Apr 5 17:02:09 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ RTTI rewrite to initialize nodes as needed, not require that
+ users #include <typeinfo>, complete functionality and reduce wasted
+ space.
+ * rtti.c (init_rtti_processing): New fn.
+ (build_typeid): The vtable entry is now a function.
+ (get_tinfo_var): New fn.
+ (get_tinfo_fn): Ditto.
+ (get_typeid): Use it.
+ (build_dynamic_cast): Declare and use entry point __dynamic_cast.
+ (build_*_desc): Rename to expand_*_desc and rewrite to use entry
+ points __rtti_*.
+ (add_uninstantiated_desc, get_def_to_follow, build_t_desc): Lose.
+ (synthesize_tinfo_fn): New fn.
+ * method.c (build_t_desc_overload): Lose.
+ (build_overload_with_type): More generic.
+ * decl.c (init_decl_processing): Call init_rtti_processing.
+ * class.c (set_rtti_entry): Use get_tinfo_fn.
+ * decl2.c (mark_vtable_entries): Mark the rtti function.
+ (finish_prevtable_vardecl): Don't build_t_desc.
+ (import_export_decl): Handle tinfo functions.
+ (finish_file): Ditto.
+ * typeck.c (inline_conversion): New fn.
+ (build_function_call_real): Use it.
+ * cp-tree.h: Add decls.
+
+ * method.c (hack_identifier): Also convert component_refs from
+ references.
+
+ * lex.c (cons_up_default_function): Use the type, not the name, in
+ declspecs.
+
+ * decl2.c (import_export_vtable): Fix weak vtables.
+
+Fri Apr 5 13:30:17 1996 Bob Manson <manson@charmed.cygnus.com>
+
+ * search.c (get_base_distance_recursive): Fix access checks for
+ protected bases.
+
+Fri Apr 5 11:02:06 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * call.c (unary_complex_lvalue): Delete unneeded decl, it's in
+ cp-tree.h.
+ (convert_harshness): Add prototypes wrapped by PROTO.
+ * decl2.c (grok_function_init): Likewise.
+ (do_toplevel_using_decl): Change to void return type.
+ * class.c (build_vtable_entry): Remove decl of make_thunk.
+ (merge_overrides): Fix order of arg definitions.
+ (finish_vtbls): Likewise.
+ (fixup_vtable_deltas): Likewise.
+ (modify_all_direct_vtables): Likewise.
+ (modify_all_indirect_vtables): Likewise.
+ * search.c (get_base_distance_recursive): Likewise.
+ (get_abstract_virtuals_1): Likewise.
+ (fixup_virtual_upcast_offsets): Likewise.
+ (lookup_fnfields_1): Add prototypes wrapped by PROTO.
+ * init.c (perform_member_init): Fix order of arg definitions.
+ (expand_aggr_init_1): Add prototypes wrapped by PROTO.
+ * cp-tree.h (make_thunk): Add decl.
+ (overload_template_name, push_template_decl): Add decls.
+ (do_toplevel_using_decl): Change to void return type.
+ (vec_binfo_member): Add decl.
+
Thu Apr 4 13:33:10 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
* typeck.c (mark_addressable, convert_for_assignment,
extern void sorry ();
extern int inhibit_warnings;
-extern int flag_assume_nonnull_objects;
extern tree ctor_label, dtor_label;
-/* From typeck.c: */
-extern tree unary_complex_lvalue ();
-
/* Compute the ease with which a conversion can be performed
between an expected and the given type. */
-static struct harshness_code convert_harshness ();
+static struct harshness_code convert_harshness PROTO((register tree, register tree, tree));
#define EVIL_RETURN(ARG) ((ARG).code = EVIL_CODE, (ARG))
#define STD_RETURN(ARG) ((ARG).code = STD_CODE, (ARG))
if (changed)
{
- extern int flag_assume_nonnull_objects;
tree ind;
/* We already check for ambiguous things in the caller, just
if (flag_vtable_thunks)
{
HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta);
- extern tree make_thunk ();
if (idelta)
{
pfn = build1 (ADDR_EXPR, vtable_entry_type,
}
/* Given an object INSTANCE, return an expression which yields the
- virtual function corresponding to INDEX. There are many special
- cases for INSTANCE which we take care of here, mainly to avoid
- creating extra tree nodes when we don't have to. */
+ virtual function vtable element corresponding to INDEX. There are
+ many special cases for INSTANCE which we take care of here, mainly
+ to avoid creating extra tree nodes when we don't have to. */
tree
-build_vfn_ref (ptr_to_instptr, instance, idx)
- tree *ptr_to_instptr, instance;
- tree idx;
+build_vtbl_ref (instance, idx)
+ tree instance, idx;
{
tree vtbl, aref;
tree basetype = TREE_TYPE (instance);
assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
- /* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
- if (TREE_CODE (aref) == INDIRECT_REF)
- TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
+ return aref;
+}
+
+/* Given an object INSTANCE, return an expression which yields the
+ virtual function corresponding to INDEX. There are many special
+ cases for INSTANCE which we take care of here, mainly to avoid
+ creating extra tree nodes when we don't have to. */
+tree
+build_vfn_ref (ptr_to_instptr, instance, idx)
+ tree *ptr_to_instptr, instance;
+ tree idx;
+{
+ tree aref = build_vtbl_ref (instance, idx);
+ /* When using thunks, there is no extra delta, and we get the pfn
+ directly. */
if (flag_vtable_thunks)
return aref;
- else
+
+ if (ptr_to_instptr)
{
- if (ptr_to_instptr)
- *ptr_to_instptr
- = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
- *ptr_to_instptr,
- convert (ptrdiff_type_node,
- build_component_ref (aref, delta_identifier, 0, 0)));
- return build_component_ref (aref, pfn_identifier, 0, 0);
+ /* Save the intermediate result in a SAVE_EXPR so we don't have to
+ compute each component of the virtual function pointer twice. */
+ if (TREE_CODE (aref) == INDIRECT_REF)
+ TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
+
+ *ptr_to_instptr
+ = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
+ *ptr_to_instptr,
+ convert (ptrdiff_type_node,
+ build_component_ref (aref, delta_identifier, NULL_TREE, 0)));
}
+
+ return build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
}
/* Return the name of the virtual function table (as an IDENTIFIER_NODE)
return get_identifier (buf);
}
+/* Return the offset to the main vtable for a given base BINFO. */
+tree
+get_vfield_offset (binfo)
+ tree binfo;
+{
+ return size_binop (PLUS_EXPR,
+ size_binop (FLOOR_DIV_EXPR,
+ DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
+ size_int (BITS_PER_UNIT)),
+ BINFO_OFFSET (binfo));
+}
+
+/* Get the offset to the start of the original binfo that we derived
+ this binfo from. If we find TYPE first, return the offset only
+ that far. The shortened search is useful because the this pointer
+ on method calling is expected to point to a DECL_CONTEXT (fndecl)
+ object, and not a baseclass of it. */
+static tree
+get_derived_offset (binfo, type)
+ tree binfo, type;
+{
+ tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
+ tree offset2;
+ int i;
+ while (BINFO_BASETYPES (binfo)
+ && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ if (BINFO_TYPE (binfo) == type)
+ break;
+ binfo = TREE_VEC_ELT (binfos, i);
+ }
+ offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
+ return size_binop (MINUS_EXPR, offset1, offset2);
+}
+
+/* Update the rtti info for this class. */
+static void
+set_rtti_entry (virtuals, offset, type)
+ tree virtuals, offset, type;
+{
+ tree vfn;
+
+ if (flag_rtti)
+ vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn (type));
+ else
+ vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, integer_zero_node);
+ TREE_CONSTANT (vfn) = 1;
+
+ if (! flag_vtable_thunks)
+ TREE_VALUE (virtuals) = build_vtable_entry (offset, vfn);
+ else
+ {
+ tree voff = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+ TREE_CONSTANT (voff) = 1;
+
+ TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, voff);
+
+ /* The second slot is for the tdesc pointer when thunks are used. */
+ TREE_VALUE (TREE_CHAIN (virtuals))
+ = build_vtable_entry (integer_zero_node, vfn);
+ }
+}
+
/* Build a virtual function for type TYPE.
If BINFO is non-NULL, build the vtable starting with the initial
approximation that it is the same as the one which is the head of
if (binfo)
{
+ tree offset;
+
virtuals = copy_list (BINFO_VIRTUALS (binfo));
decl = build_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo)));
+
+ /* Now do rtti stuff. */
+ offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE);
+ offset = size_binop (MINUS_EXPR, integer_zero_node, offset);
+ set_rtti_entry (virtuals, offset, type);
}
else
{
return id;
}
-/* Update the rtti info for this class. */
-static void
-set_rtti_entry (virtuals, offset, type)
- tree virtuals, offset, type;
-{
- if (! flag_vtable_thunks)
- TREE_VALUE (virtuals)
- = build_vtable_entry (offset,
- (flag_rtti
- ? build_t_desc (type, 0)
- : integer_zero_node));
- else
- {
- tree vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
- TREE_CONSTANT (vfn) = 1;
-
- TREE_VALUE (virtuals)
- = build_vtable_entry (integer_zero_node, vfn);
- /* The second slot is for the tdesc pointer when thunks are used. */
- vfn = flag_rtti
- ? build_t_desc (type, 0)
- : integer_zero_node;
- vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, vfn);
- TREE_CONSTANT (vfn) = 1;
-
- TREE_VALUE (TREE_CHAIN (virtuals))
- = build_vtable_entry (integer_zero_node, vfn);
- }
-}
-
/* Give TYPE a new virtual function table which is initialized
with a skeleton-copy of its original initialization. The only
entry that changes is the `delta' entry, so we can really
BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
if (TREE_VIA_VIRTUAL (binfo))
- offset = BINFO_OFFSET (binfo_member (BINFO_TYPE (binfo),
- CLASSTYPE_VBASECLASSES (for_type)));
+ {
+ tree binfo1 = binfo_member (BINFO_TYPE (binfo),
+ CLASSTYPE_VBASECLASSES (for_type));
+
+ /* XXX - This should never happen, if it does, the caller should
+ ensure that the binfo is from for_type's binfos, not from any
+ base type's. We can remove all this code after a while. */
+ if (binfo1 != binfo)
+ warning ("internal inconsistency: binfo offset error for rtti");
+
+ offset = BINFO_OFFSET (binfo1);
+ }
else
offset = BINFO_OFFSET (binfo);
{
tree entry;
- if (flag_rtti && *has_virtual == 0)
- {
- /* CLASSTYPE_RTTI is only used as a Boolean (NULL or not). */
- CLASSTYPE_RTTI (t) = integer_one_node;
- }
+ /* We remember that this was the base sub-object for rtti. */
+ CLASSTYPE_RTTI (t) = t;
/* If we are using thunks, use two slots at the front, one
for the offset pointer, one for the tdesc pointer. */
return 0;
}
-/* Return the offset to the main vtable for a given base BINFO. */
-tree
-get_vfield_offset (binfo)
- tree binfo;
-{
- return size_binop (PLUS_EXPR,
- size_binop (FLOOR_DIV_EXPR,
- DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
- size_int (BITS_PER_UNIT)),
- BINFO_OFFSET (binfo));
-}
-
-/* Get the offset to the start of the original binfo that we derived
- this binfo from. If we find TYPE first, return the offset only
- that far. The shortened search is useful because the this pointer
- on method calling is expected to point to a DECL_CONTEXT (fndecl)
- object, and not a baseclass of it. */
-static tree
-get_derived_offset (binfo, type)
- tree binfo, type;
-{
- tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
- tree offset2;
- int i;
- while (BINFO_BASETYPES (binfo)
- && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
- {
- tree binfos = BINFO_BASETYPES (binfo);
- if (BINFO_TYPE (binfo) == type)
- break;
- binfo = TREE_VEC_ELT (binfos, i);
- }
- offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
- return size_binop (MINUS_EXPR, offset1, offset2);
-}
-
/* If FOR_TYPE needs to reinitialize virtual function table pointers
for TYPE's sub-objects, add such reinitializations to BASE_INIT_LIST.
Returns BASE_INIT_LIST appropriately modified. */
int n_ancestors;
tree vfield;
tree vfields;
+ tree rtti;
char cant_have_default_ctor;
char cant_have_const_ctor;
char cant_synth_copy_ctor;
TYPE_OVERLOADS_ARROW (t) |= TYPE_OVERLOADS_ARROW (basetype);
if (! TREE_VIA_VIRTUAL (base_binfo)
-#if 0
- /* This cannot be done, as prepare_fresh_vtable wants to modify
- binfos associated with vfields anywhere in the hierarchy, not
- just immediate base classes. Due to unsharing, the compiler
- might consume 3% more memory on a real program.
- */
- && ! BINFO_OFFSET_ZEROP (base_binfo)
-#endif
&& BINFO_BASETYPES (base_binfo))
{
tree base_binfos = BINFO_BASETYPES (base_binfo);
/* Remember that the baseclass has virtual members. */
b->base_has_virtual = 1;
+ /* Ensure that this is set from at least a virtual base
+ class. */
+ if (b->rtti == NULL_TREE)
+ b->rtti = CLASSTYPE_RTTI (basetype);
+
/* Don't borrow virtuals from virtual baseclasses. */
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
if (b->vfield == 0)
/* If all virtual functions come only from virtual baseclasses. */
return -1;
+
+ /* Update the rtti base if we have a non-virtual base class version
+ of it. */
+ b->rtti = CLASSTYPE_RTTI (BINFO_TYPE (TREE_VEC_ELT (binfos, first_vfn_base_index)));
+
return first_vfn_base_index;
}
/* finish up all new vtables. */
static void
finish_vtbls (binfo, do_self, t)
- tree binfo, t;
+ tree binfo;
int do_self;
+ tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
/* These are the ones that are not through virtual base classes. */
static void
modify_all_direct_vtables (binfo, do_self, t, fndecl, pfn)
- tree binfo, t, fndecl, pfn;
+ tree binfo;
int do_self;
+ tree t, fndecl, pfn;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
hierarchy, because the layout of the virtual bases has changed. */
static void
fixup_vtable_deltas (binfo, init_self, t)
- tree binfo, t;
+ tree binfo;
int init_self;
+ tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
/* These are the ones that are through virtual base classes. */
static void
modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
- tree binfo, t, fndecl, pfn;
+ tree binfo;
int do_self, via_virtual;
+ tree t, fndecl, pfn;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
overrides. */
static void
merge_overrides (binfo, old, do_self, t)
- tree binfo, old, t;
+ tree binfo, old;
int do_self;
+ tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
tree old_binfos = BINFO_BASETYPES (old);
fields = chainon (vf, fields);
first_vfn_base_index = finish_base_struct (t, &base_info, t_binfo);
- /* Remember where we got our vfield from */
+ /* Remember where we got our vfield from. */
CLASSTYPE_VFIELD_PARENT (t) = first_vfn_base_index;
has_virtual = base_info.has_virtual;
max_has_virtual = base_info.max_has_virtual;
CLASSTYPE_N_SUPERCLASSES (t) += base_info.n_ancestors;
vfield = base_info.vfield;
vfields = base_info.vfields;
+ CLASSTYPE_RTTI (t) = base_info.rtti;
cant_have_default_ctor = base_info.cant_have_default_ctor;
cant_have_const_ctor = base_info.cant_have_const_ctor;
cant_synth_copy_ctor = base_info.cant_synth_copy_ctor;
max_has_virtual = has_virtual;
vfield = NULL_TREE;
vfields = NULL_TREE;
+ CLASSTYPE_RTTI (t) = NULL_TREE;
last_x = NULL_TREE;
cant_have_default_ctor = 0;
cant_have_const_ctor = 0;
}
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
- if (flag_rtti && (max_has_virtual > 0 || base_has_virtual) &&
- has_virtual == 0)
- has_virtual = 1;
TYPE_HAS_COMPLEX_INIT_REF (t)
|= (TYPE_HAS_INIT_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
DECL_SAVED_INSNS (vfield) = NULL_RTX;
DECL_FIELD_SIZE (vfield) = 0;
DECL_ALIGN (vfield) = TYPE_ALIGN (ptr_type_node);
- if (CLASSTYPE_RTTI (t))
- {
- /* vfield is always first entry in structure. */
- TREE_CHAIN (vfield) = fields;
- fields = vfield;
- }
- else if (last_x)
+#if 0
+ /* This is more efficient, but breaks binary compatibility, turn
+ it on sometime when we don't care. If we turn it on, we also
+ have to enable the code in dfs_init_vbase_pointers. */
+ /* vfield is always first entry in structure. */
+ TREE_CHAIN (vfield) = fields;
+ fields = vfield;
+#else
+ if (last_x)
{
my_friendly_assert (TREE_CHAIN (last_x) == NULL_TREE, 175);
TREE_CHAIN (last_x) = vfield;
}
else
fields = vfield;
+#endif
vfields = chainon (vfields, CLASSTYPE_AS_LIST (t));
}
vbases = CLASSTYPE_VBASECLASSES (t);
CLASSTYPE_N_VBASECLASSES (t) = list_length (vbases);
- /* The rtti code should do this. (mrs) */
-#if 0
- while (vbases)
- {
- /* Update rtti info with offsets for virtual baseclasses. */
- if (flag_rtti && ! BINFO_NEW_VTABLE_MARKED (vbases))
- prepare_fresh_vtable (vbases, t);
- vbases = TREE_CHAIN (vbases);
- }
-#endif
-
{
/* Now fixup overrides of all functions in vtables from all
direct or indirect virtual base classes. */
/* Under our model of GC, every C++ class gets its own virtual
function table, at least virtually. */
- if (pending_virtuals || (flag_rtti && TYPE_VIRTUAL_P (t)))
+ if (pending_virtuals)
{
pending_virtuals = nreverse (pending_virtuals);
/* We must enter these virtuals into the table. */
if (first_vfn_base_index < 0)
{
- /* The first slot is for the rtti offset. */
- pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
-
/* The second slot is for the tdesc pointer when thunks are used. */
if (flag_vtable_thunks)
pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
+ /* The first slot is for the rtti offset. */
+ pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
+
set_rtti_entry (pending_virtuals, integer_zero_node, t);
build_vtable (NULL_TREE, t);
}
else
{
- tree offset;
/* Here we know enough to change the type of our virtual
function table, but we will wait until later this function. */
if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t)))
build_vtable (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index), t);
-
- offset = get_derived_offset (TYPE_BINFO (t), NULL_TREE);
- offset = size_binop (MINUS_EXPR, integer_zero_node, offset);
- set_rtti_entry (TYPE_BINFO_VIRTUALS (t), offset, t);
}
/* If this type has basetypes with constructors, then those
#define DECL_NOT_REALLY_EXTERN(NODE) \
(DECL_LANG_SPECIFIC (NODE)->decl_flags.not_really_extern)
+#define DECL_REALLY_EXTERN(NODE) \
+ (DECL_EXTERNAL (NODE) && ! DECL_NOT_REALLY_EXTERN (NODE))
+
#define DECL_PUBLIC(NODE) \
(TREE_CODE (NODE) == FUNCTION_DECL \
? ! DECL_C_STATIC (NODE) : TREE_PUBLIC (NODE))
extern tree build_vbase_pointer PROTO((tree, tree));
extern tree build_vbase_path PROTO((enum tree_code, tree, tree, tree, int));
extern tree build_vtable_entry PROTO((tree, tree));
+extern tree build_vtbl_ref PROTO((tree, tree));
extern tree build_vfn_ref PROTO((tree *, tree, tree));
extern void add_method PROTO((tree, tree *, tree));
extern tree get_vfield_offset PROTO((tree));
extern void grok_op_properties PROTO((tree, int, int));
/* in decl2.c */
+extern int flag_assume_nonnull_objects;
+
extern int lang_decode_option PROTO((char *));
extern tree grok_method_quals PROTO((tree, tree, tree));
extern void grokclassfn PROTO((tree, tree, tree, enum overload_flags, tree));
extern tree finish_decl_parsing PROTO((tree));
extern tree lookup_name_nonclass PROTO((tree));
extern tree check_cp_case_value PROTO((tree));
-extern tree do_toplevel_using_decl PROTO((tree));
+extern void do_toplevel_using_decl PROTO((tree));
extern tree do_class_using_decl PROTO((tree));
extern tree current_namespace_id PROTO((tree));
extern tree get_namespace_id PROTO((void));
extern void finish_repo PROTO((void));
/* in rtti.c */
-extern tree build_classof PROTO((tree));
-extern tree build_t_desc PROTO((tree, int));
-extern tree build_i_desc PROTO((tree));
-extern tree build_m_desc PROTO((tree));
+extern tree get_tinfo_fn PROTO((tree));
extern tree build_typeid PROTO((tree));
extern tree get_typeid PROTO((tree));
extern tree build_dynamic_cast PROTO((tree, tree));
extern tree cplus_exception_name PROTO((tree));
extern tree build_decl_overload PROTO((tree, tree, int));
extern tree build_typename_overload PROTO((tree));
-extern tree build_t_desc_overload PROTO((tree));
+extern tree build_overload_with_type PROTO((tree, tree));
extern void declare_overloaded PROTO((tree));
#ifdef NO_AUTO_OVERLOAD
extern int is_overloaded PROTO((tree));
extern tree build_opfncall PROTO((enum tree_code, int, tree, tree, tree));
extern tree hack_identifier PROTO((tree, tree));
extern tree build_component_type_expr PROTO((tree, tree, tree, int));
+extern tree make_thunk PROTO((tree, int));
extern void synthesize_method PROTO((tree));
/* in pt.c */
extern tree process_template_parm PROTO((tree, tree));
extern tree end_template_parm_list PROTO((tree));
extern void end_template_decl PROTO((void));
+extern void push_template_decl PROTO((tree));
extern tree lookup_template_class PROTO((tree, tree, tree));
extern int uses_template_parms PROTO((tree));
extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree *));
+extern void overload_template_name PROTO((tree));
extern int type_unification PROTO((tree, tree *, tree, tree, int *, int));
struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int));
extern tree unsave_expr PROTO((tree));
extern int cp_expand_decl_cleanup PROTO((tree, tree));
extern tree get_type_decl PROTO((tree));
+extern tree vec_binfo_member PROTO((tree, tree));
extern tree hack_decl_function_context PROTO((tree));
/* in typeck.c */
extern tree c_sizeof PROTO((tree));
extern tree c_sizeof_nowarn PROTO((tree));
extern tree c_alignof PROTO((tree));
+extern tree inline_conversion PROTO((tree));
extern tree decay_conversion PROTO((tree));
extern tree default_conversion PROTO((tree));
extern tree build_object_ref PROTO((tree, tree, tree));
Any artificial decls that need DECL_NESTED_TYPENAME will have it
set in pushtag. */
if (! DECL_NESTED_TYPENAME (x) && ! DECL_ARTIFICIAL (x))
- set_nested_typename (x, current_class_name, DECL_NAME (x), type);
+ set_nested_typename (x, current_class_type != NULL_TREE ? TYPE_NESTED_NAME (current_class_type) : current_class_name, DECL_NAME (x), type);
if (type != error_mark_node
&& TYPE_NAME (type)
Any artificial decls that need DECL_NESTED_TYPENAME will have it
set in pushtag. */
if (! DECL_NESTED_TYPENAME (x) && ! DECL_ARTIFICIAL (x))
- set_nested_typename (x, current_class_name, name, TREE_TYPE (x));
+ set_nested_typename (x, current_class_type != NULL_TREE ? TYPE_NESTED_NAME (current_class_type) : current_class_name, name, TREE_TYPE (x));
}
}
return x;
set_identifier_type_value (rname, NULL_TREE);
}
}
-
- if (flag_rtti)
- {
- if (builtin_type_tdescs_len+5 >= builtin_type_tdescs_max)
- {
- builtin_type_tdescs_max *= 2;
- builtin_type_tdescs_arr
- = (tree *)xrealloc (builtin_type_tdescs_arr,
- builtin_type_tdescs_max * sizeof (tree));
- }
- builtin_type_tdescs_arr[builtin_type_tdescs_len++] = type;
- if (TREE_CODE (type) != POINTER_TYPE)
- {
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_pointer_type (type);
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_pointer_type (build_type_variant (type, 1, 0));
- }
- if (TREE_CODE (type) != VOID_TYPE)
- {
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_reference_type (type);
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_reference_type (build_type_variant (type, 1, 0));
- }
- }
}
/* Push overloaded decl, in global scope, with one argument so it
#ifdef __GNUC__
__inline
#endif
-tree auto_function (name, type, code)
+tree
+auto_function (name, type, code)
tree name, type;
enum built_in_function code;
{
#endif
gcc_obstack_init (&decl_obstack);
- if (flag_rtti)
- {
- builtin_type_tdescs_max = 100;
- builtin_type_tdescs_arr = (tree *)xmalloc (100 * sizeof (tree));
- }
/* Must lay these out before anything else gets laid out. */
error_mark_node = make_node (ERROR_MARK);
string_type_node = build_pointer_type (char_type_node);
const_string_type_node =
build_pointer_type (build_type_variant (char_type_node, 1, 0));
+#if 0
record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
+#endif
/* Make a type to be the domain of a few array types
whose domains don't really matter.
ptr_type_node = build_pointer_type (void_type_node);
const_ptr_type_node =
build_pointer_type (build_type_variant (void_type_node, 1, 0));
+#if 0
record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
+#endif
endlink = void_list_node;
int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7,
integer_type_node);
}
-
- if (flag_rtti)
- {
- int i = builtin_type_tdescs_len;
- while (i > 0)
- {
- tree tdesc = build_t_desc (builtin_type_tdescs_arr[--i], 0);
- TREE_ASM_WRITTEN (tdesc) = 1;
- TREE_PUBLIC (TREE_OPERAND (tdesc, 0)) = 1;
- }
- }
#endif /*flag_rtti*/
/* Now, C++. */
init_class_processing ();
init_init_processing ();
init_search_processing ();
+ init_rtti_processing ();
if (flag_handle_exceptions)
init_exception_processing ();
tree d = TYPE_NAME (type), c = DECL_CONTEXT (d);
if (!c)
- set_nested_typename (d, 0, declarator, type);
+ set_nested_typename (d, NULL_TREE, declarator, type);
else if (TREE_CODE (c) == FUNCTION_DECL)
set_nested_typename (d, DECL_ASSEMBLER_NAME (c),
declarator, type);
extern tree get_file_function_name ();
extern tree cleanups_this_call;
-static void grok_function_init ();
+static void grok_function_init PROTO((tree, tree));
void import_export_decl ();
extern int current_class_depth;
/* Controls whether compiler generates 'type descriptor' that give
run-time type information. */
-int flag_rtti;
+int flag_rtti = 1;
/* Nonzero if we wish to output cross-referencing information
for the GNU class browser. */
{
tree entries = CONSTRUCTOR_ELTS (DECL_INITIAL (decl));
+ if (flag_rtti)
+ {
+ tree fnaddr = (flag_vtable_thunks ? TREE_VALUE (TREE_CHAIN (entries))
+ : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries)));
+ tree fn = TREE_OPERAND (fnaddr, 0);
+ TREE_ADDRESSABLE (fn) = 1;
+ mark_used (fn);
+ }
skip_rtti_stuff (&entries);
for (; entries; entries = TREE_CHAIN (entries))
cp_error ("all virtual functions redeclared inline");
#endif
if (flag_weak)
- DECL_WEAK (decl) = 1;
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_WEAK (decl) = 1;
+ }
else
TREE_PUBLIC (decl) = 0;
DECL_EXTERNAL (decl) = 0;
}
import_export_vtable (vars, ctype, 1);
-
- /* We cannot use TREE_USED here, as it may be set by the expanding of a
- ctor that is used to build a global object. The long term plan is to
- make the TD entries statically initialized and move this to
- finish_vtable_vardecl time. */
- if (flag_rtti && write_virtuals >= 0
- && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || 1 || TREE_USED (vars)))
- {
- /* Kick out the type descriptor before we dump out global
- initializers, as they are initialized at run time and
- we have to find them when we scan for things that need initialized
- at the top level. */
- build_t_desc (ctype, 1);
- }
-
return 1;
}
&& ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars))
&& ! TREE_ASM_WRITTEN (vars))
{
-#if 0
- /* The long term plan it to make the TD entries statically initialized,
- have the entries built and emitted here. When that happens, this
- can be enabled, and the other call to build_t_desc removed. */
- /* Kick out the type descriptor before writing out the vtable. */
- if (flag_rtti)
- build_t_desc (DECL_CONTEXT (vars), 1);
-#endif
-
/* Write it out. */
mark_vtable_entries (vars);
if (TREE_TYPE (DECL_INITIAL (vars)) == 0)
else
TREE_PUBLIC (decl) = 0;
}
+ /* tinfo function */
+ else if (DECL_ARTIFICIAL (decl) && DECL_MUTABLE_P (decl))
+ {
+ tree ctype = TREE_TYPE (DECL_NAME (decl));
+ if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype))
+ {
+ DECL_NOT_REALLY_EXTERN (decl)
+ = ! (CLASSTYPE_INTERFACE_ONLY (ctype)
+ || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
+ }
+ else if (TYPE_BUILT_IN (ctype) && ctype == TYPE_MAIN_VARIANT (ctype))
+ DECL_NOT_REALLY_EXTERN (decl) = 0;
+ else if (flag_weak)
+ DECL_WEAK (decl) = 1;
+ else
+ TREE_PUBLIC (decl) = 0;
+ }
else if (DECL_C_STATIC (decl))
TREE_PUBLIC (decl) = 0;
else if (flag_weak)
{
tree decl = TREE_VALUE (fnname);
import_export_decl (decl);
- if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
- && TREE_PUBLIC (decl) && ! DECL_WEAK (decl)
- && DECL_NOT_REALLY_EXTERN (decl))
- synthesize_method (decl);
}
/* Now write out inline functions which had their addresses taken and
tree decl = TREE_VALUE (*p);
if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
- && TREE_USED (decl))
+ && TREE_USED (decl)
+ && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
{
- synthesize_method (decl);
+ if (DECL_MUTABLE_P (decl))
+ synthesize_tinfo_fn (decl);
+ else
+ synthesize_method (decl);
reconsider = 1;
}
- if (TREE_ASM_WRITTEN (decl)
- || (DECL_SAVED_INSNS (decl) == 0 && ! DECL_ARTIFICIAL (decl)))
+ if (decl != TREE_VALUE (*p))
+ ;
+ else if (TREE_ASM_WRITTEN (decl)
+ || (DECL_SAVED_INSNS (decl) == 0
+ && ! DECL_ARTIFICIAL (decl)))
*p = TREE_CHAIN (*p);
else
p = &TREE_CHAIN (*p);
sorry ("namespace alias");
}
-tree
+void
do_toplevel_using_decl (decl)
tree decl;
{
void expand_member_init ();
void expand_aggr_init ();
-static void expand_aggr_init_1 ();
+static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int, int));
static void expand_virtual_init PROTO((tree, tree));
tree expand_vec_init ();
/* Subroutine of emit_base_init. */
static void
perform_member_init (member, name, init, explicit, protect_list)
- tree member, name, init, *protect_list;
+ tree member, name, init;
int explicit;
+ tree *protect_list;
{
tree decl;
tree type = TREE_TYPE (member);
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
- if (TREE_CODE (name) == TYPE_DECL)
+ if (name && TREE_CODE (name) == TYPE_DECL)
{
basetype = TREE_TYPE (name);
name = DECL_NAME (name);
not expanded as part of the RTL_EXPR for the initialization,
so we can't just use save_expr here. */
- alloc_temp = get_temp_name (TREE_TYPE (rval), 0);
- alloc_expr = build (MODIFY_EXPR, TREE_TYPE (rval), alloc_temp, rval);
+ alloc_temp = build (VAR_DECL, TREE_TYPE (rval));
+ layout_decl (alloc_temp, 0);
+ alloc_expr = build (TARGET_EXPR, TREE_TYPE (rval), alloc_temp, rval, 0);
TREE_SIDE_EFFECTS (alloc_expr) = 1;
rval = alloc_temp;
}
/* Fall through... */
case 6:
retref = 1;
- declspecs = build_decl_list (NULL_TREE, full_name);
+ declspecs = build_decl_list (NULL_TREE, type);
name = ansi_opname [(int) MODIFY_EXPR];
return id;
}
-#ifndef NO_DOLLAR_IN_LABEL
-#define T_DESC_FORMAT "TD$"
-#define I_DESC_FORMAT "ID$"
-#define M_DESC_FORMAT "MD$"
-#else
-#if !defined(NO_DOT_IN_LABEL)
-#define T_DESC_FORMAT "TD."
-#define I_DESC_FORMAT "ID."
-#define M_DESC_FORMAT "MD."
-#else
-#define T_DESC_FORMAT "__t_desc_"
-#define I_DESC_FORMAT "__i_desc_"
-#define M_DESC_FORMAT "__m_desc_"
-#endif
-#endif
-
-/* Build an overload name for the type expression TYPE. */
tree
-build_t_desc_overload (type)
- tree type;
+build_overload_with_type (name, type)
+ tree name, type;
{
OB_INIT ();
- OB_PUTS (T_DESC_FORMAT);
+ OB_PUTID (name);
nofold = 1;
-#if 0
- /* Use a different format if the type isn't defined yet. */
- if (TYPE_SIZE (type) == NULL_TREE)
- {
- char *p;
- int changed;
-
- for (p = tname; *p; p++)
- if (isupper (*p))
- {
- changed = 1;
- *p = tolower (*p);
- }
- /* If there's no change, we have an inappropriate T_DESC_FORMAT. */
- my_friendly_assert (changed != 0, 249);
- }
-#endif
-
build_overload_name (type, 0, 1);
return get_identifier (obstack_base (&scratch_obstack));
}
this field was initialized by a base initializer,
we can emit an error message. */
TREE_USED (value) = 1;
- return build_component_ref (C_C_D, name, 0, 1);
+ value = build_component_ref (C_C_D, name, 0, 1);
}
-
- if (really_overloaded_fn (value))
+ else if (really_overloaded_fn (value))
{
#if 0
tree t = get_first_fn (value);
}
if (TREE_CODE (type) == REFERENCE_TYPE && ! current_template_parms)
- {
- my_friendly_assert (TREE_CODE (value) == VAR_DECL
- || TREE_CODE (value) == PARM_DECL
- || TREE_CODE (value) == RESULT_DECL, 252);
- return convert_from_reference (value);
- }
+ value = convert_from_reference (value);
return value;
}
require_complete_type (tmp);
/* XXX handle attributes */
- type = finish_struct_1 (type, 0, 0);
+ type = finish_struct_1 (type, NULL_TREE, 0);
}
else
{
tree r = copy_node (t);
TREE_TYPE (r) = type;
DECL_CONTEXT (r) = current_class_type;
- set_nested_typename (r, current_class_name, DECL_NAME (r), type);
+ set_nested_typename (r, current_class_type != NULL_TREE ? TYPE_NESTED_NAME (current_class_type) : current_class_name, DECL_NAME (r), type);
TREE_CHAIN (r) = NULL_TREE;
return r;
}
/* RunTime Type Identification
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Mostly written by Jason Merrill (jason@cygnus.com).
This file is part of GNU CC.
extern tree build_t_desc_overload ();
extern struct obstack *permanent_obstack;
+tree type_info_type_node;
+tree tinfo_fn_id;
+tree tinfo_fn_type;
+
/* in c-common.c */
extern tree combine_strings PROTO((tree));
\f
-/* Given the expression EXP of type `class *', return the head
- of the object pointed to by EXP. */
+void
+init_rtti_processing ()
+{
+ type_info_type_node = xref_tag
+ (class_type_node, get_identifier ("type_info"), NULL_TREE, 1);
+ tinfo_fn_id = get_identifier ("__tf");
+ tinfo_fn_type = build_function_type
+ (build_reference_type (build_type_variant (type_info_type_node, 1, 0)),
+ void_list_node);
+}
+
+/* Given a pointer to an object with at least one virtual table
+ pointer somewhere, return a pointer to a possible sub-object that
+ has a virtual table pointer in it that is the vtable parent for
+ that sub-object. */
+static tree
+build_headof_sub (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (TREE_TYPE (exp));
+ tree basetype = CLASSTYPE_RTTI (type);
+ tree binfo = get_binfo (basetype, type, 0);
+
+ exp = convert_pointer_to_real (binfo, exp);
+ return exp;
+}
+
+/* Given the expression EXP of type `class *', return the head of the
+ object pointed to by EXP with type cv void*, if the class has any
+ virtual functions (TYPE_VIRTUAL_P), else just return the
+ expression. */
static tree
build_headof (exp)
tree exp;
{
tree type = TREE_TYPE (exp);
+ tree aref;
tree vptr, offset;
if (TREE_CODE (type) != POINTER_TYPE)
}
type = TREE_TYPE (type);
- if (!TYPE_VIRTUAL_P (type) || CLASSTYPE_VFIELD (type) == NULL_TREE)
+ if (!TYPE_VIRTUAL_P (type))
return exp;
- vptr = fold (size_binop (PLUS_EXPR,
- size_binop (FLOOR_DIV_EXPR,
- DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (type)),
- size_int (BITS_PER_UNIT)),
- exp));
- vptr = build1 (INDIRECT_REF, build_pointer_type (vtable_entry_type), vptr);
+ /* If we don't have rtti stuff, get to a sub-object that does. */
+ if (!CLASSTYPE_VFIELDS (TREE_TYPE (TREE_TYPE (exp))))
+ exp = build_headof_sub (exp);
+
+ /* We use this a couple of times below, protect it. */
+ exp = save_expr (exp);
+
+ aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node);
if (flag_vtable_thunks)
- offset = build_array_ref (vptr, integer_zero_node);
+ offset = aref;
else
- offset = build_component_ref (build_array_ref (vptr, integer_zero_node),
- delta_identifier,
- NULL_TREE, 0);
+ offset = build_component_ref (aref, delta_identifier, NULL_TREE, 0);
type = build_type_variant (ptr_type_node, TREE_READONLY (exp),
TREE_THIS_VOLATILE (exp));
{
tree type;
- if (!flag_rtti)
- cp_error ("cannot take typeid of object when -frtti is not specified");
-
if (exp == error_mark_node)
return error_mark_node;
/* build reference to type_info from vtable. */
tree t;
+ if (! flag_rtti)
+ warning ("taking dynamic typeid of object without -frtti");
+
+ /* If we don't have rtti stuff, get to a sub-object that does. */
+ if (!CLASSTYPE_VFIELDS (TREE_TYPE (type)))
+ {
+ exp = build_unary_op (ADDR_EXPR, exp, 0);
+ exp = build_headof_sub (exp);
+ exp = build_indirect_ref (exp, NULL_PTR);
+ }
+
if (flag_vtable_thunks)
- t = build_vfn_ref ((tree *) NULL_TREE, exp, integer_one_node);
+ t = build_vfn_ref ((tree *) 0, exp, integer_one_node);
else
- t = build_vfn_ref ((tree *) NULL_TREE, exp, integer_zero_node);
+ t = build_vfn_ref ((tree *) 0, exp, integer_zero_node);
+ TREE_TYPE (t) = build_pointer_type (tinfo_fn_type);
- TREE_TYPE (t) = build_pointer_type (__class_desc_type_node);
- t = build_indirect_ref (t, NULL);
- return t;
+ t = build (CALL_EXPR, TREE_TYPE (tinfo_fn_type), t, NULL_TREE, 0);
+ TREE_SIDE_EFFECTS (t) = 1;
+ return convert_from_reference (t);
}
/* otherwise return the type_info for the static type of the expr. */
return get_typeid (type);
}
+tree
+get_tinfo_var (type)
+ tree type;
+{
+ tree tname = build_overload_with_type (get_identifier ("__ti"), type);
+ tree tdecl, arrtype;
+ int size;
+
+ if (IDENTIFIER_GLOBAL_VALUE (tname))
+ return IDENTIFIER_GLOBAL_VALUE (tname);
+
+ /* Figure out how much space we need to allocate for the type_info object.
+ If our struct layout or the type_info classes are changed, this will
+ need to be modified. */
+ if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
+ size = 4 * POINTER_SIZE;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && ! (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
+ || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))
+ size = 3 * POINTER_SIZE;
+ else if (IS_AGGR_TYPE (type))
+ {
+ if (CLASSTYPE_N_BASECLASSES (type) == 0)
+ size = 2 * POINTER_SIZE;
+ else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
+ && (TREE_VIA_PUBLIC
+ (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
+ size = 3 * POINTER_SIZE;
+ else
+ size = 4 * POINTER_SIZE;
+ }
+ else
+ size = 2 * POINTER_SIZE;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ /* The type for a character array of the appropriate size. */
+ arrtype = build_cplus_array_type
+ (unsigned_char_type_node,
+ build_index_type (size_int (size / BITS_PER_UNIT - 1)));
+
+ tdecl = build_decl (VAR_DECL, tname, arrtype);
+ TREE_PUBLIC (tdecl) = 1;
+ DECL_EXTERNAL (tdecl) = 1;
+ DECL_ARTIFICIAL (tdecl) = 1;
+ pushdecl_top_level (tdecl);
+ cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+
+ pop_obstacks ();
+
+ return tdecl;
+}
+
+tree
+get_tinfo_fn (type)
+ tree type;
+{
+ tree name = build_overload_with_type (tinfo_fn_id, type);
+ tree d;
+
+ if (IDENTIFIER_GLOBAL_VALUE (name))
+ return IDENTIFIER_GLOBAL_VALUE (name);
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ d = build_lang_decl (FUNCTION_DECL, name, tinfo_fn_type);
+ DECL_EXTERNAL (d) = 1;
+ TREE_PUBLIC (d) = 1;
+ DECL_ARTIFICIAL (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = 1;
+ DECL_MUTABLE_P (d) = 1;
+ TREE_TYPE (name) = type;
+ pushdecl_top_level (d);
+ make_function_rtl (d);
+ mark_inline_for_output (d);
+ if (at_eof)
+ import_export_decl (d);
+
+ pop_obstacks ();
+
+ return d;
+}
+
+tree
+get_typeid_1 (type)
+ tree type;
+{
+ tree t = build (CALL_EXPR, TREE_TYPE (tinfo_fn_type),
+ default_conversion (get_tinfo_fn (type)), NULL_TREE, 0);
+ TREE_SIDE_EFFECTS (t) = 1;
+ return convert_from_reference (t);
+}
+
/* Return the type_info object for TYPE, creating it if necessary. */
tree
get_typeid (type)
tree type;
{
- tree t, td;
+ tree t;
if (type == error_mark_node)
return error_mark_node;
- /* Is it useful (and/or correct) to have different typeids for `T &'
- and `T'? */
+ /* If the type of the type-id is a reference type, the result of the
+ typeid expression refers to a type_info object representing the
+ referenced type. */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- td = build_t_desc (type, 1);
- if (td == error_mark_node)
- return error_mark_node;
+ /* The top-level cv-qualifiers of the lvalue expression or the type-id
+ that is the operand of typeid are always ignored. */
+ type = TYPE_MAIN_VARIANT (type);
- t = TREE_OPERAND (td, 0);
- return t;
+ return get_typeid_1 (type);
}
/* Get a bad_cast node for the program to throw...
- See libstdc++::exception{,.cc} for __bad_cast_object */
+ See libstdc++/exception.cc for __throw_bad_cast */
+
static tree
-get_bad_cast_node ()
+throw_bad_cast ()
{
- static tree t;
- if (t == NULL_TREE
- && (t = lookup_name (get_identifier ("__bad_cast_object"), 0))
- == NULL_TREE)
- {
- error ("you must #include <typeinfo>");
- return error_mark_node;
- }
- return t;
+ tree d = get_identifier ("__throw_bad_cast");
+ tree type;
+
+ if (IDENTIFIER_GLOBAL_VALUE (d))
+ return IDENTIFIER_GLOBAL_VALUE (d);
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ type = build_function_type (void_type_node, void_list_node);
+ d = build_lang_decl (FUNCTION_DECL, d, type);
+ DECL_EXTERNAL (d) = 1;
+ TREE_PUBLIC (d) = 1;
+ DECL_ARTIFICIAL (d) = 1;
+ pushdecl_top_level (d);
+ make_function_rtl (d);
+
+ pop_obstacks ();
+
+ d = build (CALL_EXPR, void_type_node, default_conversion (d), NULL_TREE, 0);
+ TREE_SIDE_EFFECTS (d) = 1;
+ return d;
}
/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
paper. */
+
tree
build_dynamic_cast (type, expr)
tree type, expr;
enum tree_code tc = TREE_CODE (type);
tree exprtype = TREE_TYPE (expr);
enum tree_code ec = TREE_CODE (exprtype);
+ tree dcast_fn;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
return build1 (NOP_EXPR, type, expr);
- return build_headof (expr);
+ expr = build_headof (expr);
+ if (TREE_TYPE (expr) != type)
+ expr = build1 (NOP_EXPR, type, expr);
+ return expr;
}
else
{
tree retval;
- tree result, td1, td2, elems, expr1;
+ tree result, td1, td2, td3, elems, expr1, expr2;
/* If we got here, we can't convert statically. Therefore,
dynamic_cast<D&>(b) (b an object) cannot succeed. */
{
cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
expr, type);
- return build_throw (get_bad_cast_node ());
+ return throw_bad_cast ();
}
}
/* Ditto for dynamic_cast<D*>(&b). */
}
}
+ /* Since expr is used twice below, save it. */
+ expr = save_expr (expr);
+
expr1 = expr;
if (tc == REFERENCE_TYPE)
expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
/* Build run-time conversion. */
- expr1 = build_headof (expr1);
+ expr2 = build_headof (expr1);
if (ec == POINTER_TYPE)
td1 = build_typeid (build_indirect_ref (expr, NULL_PTR));
else
td1 = build_typeid (expr);
- td2 = get_typeid (TYPE_MAIN_VARIANT (TREE_TYPE (type)));
-
- elems = tree_cons (NULL_TREE, td2,
- tree_cons (NULL_TREE, build_int_2 (1, 0),
- tree_cons (NULL_TREE, expr1, NULL_TREE)));
- result = build_method_call (td1,
- get_identifier ("__rtti_match"), elems, NULL_TREE, LOOKUP_NORMAL);
+ td2 = get_typeid (TREE_TYPE (type));
+ td3 = get_typeid (TREE_TYPE (exprtype));
+
+ elems = tree_cons
+ (NULL_TREE, TREE_OPERAND (td1, 0), tree_cons
+ (NULL_TREE, TREE_OPERAND (td2, 0), tree_cons
+ (NULL_TREE, build_int_2 (1, 0), tree_cons
+ (NULL_TREE, expr2, tree_cons
+ (NULL_TREE, TREE_OPERAND (td3, 0), tree_cons
+ (NULL_TREE, expr1, NULL_TREE))))));
+
+ dcast_fn = get_identifier ("__dynamic_cast");
+ if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
+ dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
+ else
+ {
+ tree tmp;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = build_reference_type
+ (build_type_variant (type_info_type_node, 1, 0));
+ tmp = tree_cons
+ (NULL_TREE, tmp, tree_cons
+ (NULL_TREE, tmp, tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, tmp, tree_cons
+ (NULL_TREE, ptr_type_node, void_list_node))))));
+ tmp = build_function_type (ptr_type_node, tmp);
+ dcast_fn = build_lang_decl (FUNCTION_DECL, dcast_fn, tmp);
+ DECL_EXTERNAL (dcast_fn) = 1;
+ TREE_PUBLIC (dcast_fn) = 1;
+ DECL_ARTIFICIAL (dcast_fn) = 1;
+ pushdecl_top_level (dcast_fn);
+ make_function_rtl (dcast_fn);
+ pop_obstacks ();
+ }
+
+ result = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (dcast_fn)),
+ decay_conversion (dcast_fn), elems, 0);
+ TREE_SIDE_EFFECTS (result) = 1;
if (tc == REFERENCE_TYPE)
{
- expr1 = build_throw (get_bad_cast_node ());
+ expr1 = throw_bad_cast ();
expr1 = build_compound_expr (tree_cons (NULL_TREE, expr1,
build_tree_list (NULL_TREE, convert (type, integer_zero_node))));
TREE_TYPE (expr1) = type;
Note: these constructors always return the address of the descriptor
info, since that is simplest for their mutual interaction. */
-static tree
-build_generic_desc (tdecl, type, elems)
- tree tdecl;
- tree type;
- tree elems;
-{
- tree init = elems;
- int toplev = global_bindings_p ();
+extern tree const_string_type_node;
- TREE_CONSTANT (init) = 1;
- TREE_STATIC (init) = 1;
- TREE_READONLY (init) = 1;
+/* Build an initializer for a __si_type_info node. */
- TREE_TYPE (tdecl) = type;
- DECL_INITIAL (tdecl) = init;
- TREE_STATIC (tdecl) = 1;
- DECL_SIZE (tdecl) = NULL_TREE;
- layout_decl (tdecl, 0);
- if (! toplev)
- push_to_top_level ();
- cp_finish_decl (tdecl, init, NULL_TREE, 0, 0);
- if (! toplev)
- pop_from_top_level ();
-
- if (! TREE_USED (tdecl))
- {
- assemble_external (tdecl);
- TREE_USED (tdecl) = 1;
- }
-
- return IDENTIFIER_AS_DESC (DECL_NAME (tdecl));
-}
-
-/* Build an initializer for a __bltn_desc node. */
-static tree
-build_bltn_desc (tdecl, type)
+static void
+expand_si_desc (tdecl, type)
tree tdecl;
tree type;
{
- tree elems, t;
-
- if (type == boolean_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_BOOL"),
- 0, 0);
- else if (type == char_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_CHAR"),
- 0, 0);
- else if (type == short_integer_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_SHORT"),
- 0, 0);
- else if (type == integer_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_INT"),
- 0, 0);
- else if (type == long_integer_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_LONG"),
- 0, 0);
- else if (type == long_long_integer_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_LONGLONG"), 0, 0);
- else if (type == float_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_FLOAT"),
- 0, 0);
- else if (type == double_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_DOUBLE"), 0, 0);
- else if (type == long_double_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_LDOUBLE"), 0, 0);
- else if (type == unsigned_char_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_UCHAR"),
- 0, 0);
- else if (type == short_unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_USHORT"),
- 0, 0);
- else if (type == unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_UINT"),
- 0, 0);
- else if (type == long_unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_ULONG"),
- 0, 0);
- else if (type == long_long_unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_ULONGLONG"), 0, 0);
- else if (type == signed_char_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_SCHAR"),
- 0, 0);
- else if (type == wchar_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_WCHAR"),
- 0, 0);
- else if (type == void_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_VOID"),
- 0, 0);
+ tree t, elems, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
+
+ type = BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0));
+ expand_expr_stmt (get_typeid_1 (type));
+ t = decay_conversion (get_tinfo_var (type));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, t, NULL_TREE)));
+
+ fn = get_identifier ("__rtti_si");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- cp_compiler_error ("type `%T' not handled as a built-in type");
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node)));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
}
- elems = tree_cons (NULL_TREE, t, NULL_TREE);
- return build_generic_desc (tdecl, __bltn_desc_type_node, elems);
-}
-
-/* Build an initializer for a __user_desc node. */
-static tree
-build_user_desc (tdecl)
- tree tdecl;
-{
- tree elems, name_string;
- tree tname = DECL_NAME (tdecl);
-
- name_string = combine_strings (build_string
- (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
- elems = name_string;
- return build_generic_desc (tdecl, __user_desc_type_node, elems);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
/* Build an initializer for a __class_type_info node. */
-static tree
-build_class_desc (tdecl, type)
+
+static void
+expand_class_desc (tdecl, type)
tree tdecl;
tree type;
{
- tree tname = DECL_NAME (tdecl);
+ tree tname = TYPE_NESTED_NAME (type);
tree name_string;
+ tree fn, tmp;
+ char *name;
int i = CLASSTYPE_N_BASECLASSES (type);
int base_cnt = 0;
int n_base = i;
#endif
tree base, elems, access, offset, isvir;
- tree base_list, off_list, acc_list, isvir_list;
- static tree acc_pub = NULL_TREE;
- static tree acc_pro = NULL_TREE;
- static tree acc_pri = NULL_TREE;
+ tree elt, elts = NULL_TREE;
+ static tree base_info_type_node;
- if (acc_pub == NULL_TREE)
+ if (base_info_type_node == NULL_TREE)
{
- acc_pub = lookup_field (__class_desc_type_node,
- get_identifier("_RTTI_ACCESS_PUBLIC"), 0, 0);
- acc_pro = lookup_field (__class_desc_type_node,
- get_identifier("_RTTI_ACCESS_PROTECTED"), 0, 0);
- acc_pri = lookup_field (__class_desc_type_node,
- get_identifier("_RTTI_ACCESS_PRIVATE"), 0, 0);
+ tree fields [4];
+
+ /* A reasonably close approximation of __class_type_info::base_info */
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ base_info_type_node = make_lang_type (RECORD_TYPE);
+
+ /* Actually const __user_type_info * */
+ fields [0] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE,
+ build_pointer_type (build_type_variant (type_info_type_node, 1, 0)));
+ fields [1] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, sizetype);
+ DECL_BIT_FIELD (fields[1]) = 1;
+ DECL_FIELD_SIZE (fields[1]) = 29;
+
+ fields [2] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, boolean_type_node);
+ DECL_BIT_FIELD (fields[2]) = 1;
+ DECL_FIELD_SIZE (fields[2]) = 1;
+
+ /* Actually enum access */
+ fields [3] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, integer_type_node);
+ DECL_BIT_FIELD (fields[3]) = 1;
+ DECL_FIELD_SIZE (fields[3]) = 2;
+
+ finish_builtin_type (base_info_type_node, "__base_info", fields,
+ 3, ptr_type_node);
+ pop_obstacks ();
}
- base_list = build_tree_list (NULL_TREE, integer_zero_node);
- off_list = build_tree_list (NULL_TREE, integer_zero_node);
- acc_list = build_tree_list (NULL_TREE, integer_zero_node);
- isvir_list = build_tree_list (NULL_TREE, integer_zero_node);
while (--i >= 0)
{
tree binfo = TREE_VEC_ELT (binfos, i);
- base = build_t_desc (BINFO_TYPE (binfo), 1);
+ expand_expr_stmt (get_typeid_1 (BINFO_TYPE (binfo)));
+ base = decay_conversion (get_tinfo_var (BINFO_TYPE (binfo)));
+
if (TREE_VIA_VIRTUAL (binfo))
{
tree t = BINFO_TYPE (binfo);
offset = BINFO_OFFSET (binfo);
if (TREE_VIA_PUBLIC (binfo))
- access = acc_pub;
+ access = access_public_node;
else if (TREE_VIA_PROTECTED (binfo))
- access = acc_pro;
+ access = access_protected_node;
else
- access = acc_pri;
+ access = access_private_node;
if (TREE_VIA_VIRTUAL (binfo))
- isvir = build_int_2 (1, 0);
+ isvir = boolean_true_node;
else
- isvir = build_int_2 (0, 0);
-
- base_list = tree_cons (NULL_TREE, base, base_list);
- isvir_list = tree_cons (NULL_TREE, isvir, isvir_list);
- acc_list = tree_cons (NULL_TREE, access, acc_list);
- off_list = tree_cons (NULL_TREE, offset, off_list);
+ isvir = boolean_false_node;
+
+ elt = build
+ (CONSTRUCTOR, base_info_type_node, NULL_TREE, tree_cons
+ (NULL_TREE, base, tree_cons
+ (NULL_TREE, offset, tree_cons
+ (NULL_TREE, isvir, tree_cons
+ (NULL_TREE, access, NULL_TREE)))));
+ TREE_HAS_CONSTRUCTOR (elt) = TREE_CONSTANT (elt) = TREE_STATIC (elt) = 1;
+ elts = tree_cons (NULL_TREE, elt, elts);
base_cnt++;
}
#if 0
while (vb)
{
tree b;
- access = acc_pub;
+ access = access_public_node;
while (--i >= 0)
{
b = TREE_VEC_ELT (binfos, i);
if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b))
{
if (TREE_VIA_PUBLIC (b))
- access = acc_pub;
+ access = access_public_node;
else if (TREE_VIA_PROTECTED (b))
- access = acc_pro;
+ access = access_protected_node;
else
- access = acc_pri;
+ access = access_private_node;
break;
}
}
vb = TREE_CHAIN (vb);
}
#endif
- base_list = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node),
- base_list, 0);
- off_list = finish_table (NULL_TREE, integer_type_node,
- off_list, 0);
- isvir_list = finish_table (NULL_TREE, integer_type_node,
- isvir_list, 0);
- acc_list = finish_table (NULL_TREE, __access_mode_type_node,
- acc_list, 0);
-
- name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
+ name = build_overload_name (type, 1, 1);
+ name_string = combine_strings (build_string (strlen (name), name));
- elems = tree_cons (NULL_TREE, name_string,
- tree_cons (NULL_TREE, default_conversion (base_list),
- tree_cons (NULL_TREE, default_conversion (off_list),
- tree_cons (NULL_TREE, default_conversion (isvir_list),
- tree_cons (NULL_TREE, default_conversion (acc_list),
- tree_cons (NULL_TREE, build_int_2 (base_cnt, 0), NULL_TREE))))));
+ {
+ tree arrtype = build_array_type (base_info_type_node, NULL_TREE);
+ elts = build (CONSTRUCTOR, arrtype, NULL_TREE, elts);
+ TREE_HAS_CONSTRUCTOR (elts) = TREE_CONSTANT (elts) =
+ TREE_STATIC (elts) = 1;
+ complete_array_type (arrtype, elts, 1);
+ }
- return build_generic_desc (tdecl, __class_desc_type_node, elems);
-}
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, decay_conversion (elts), tree_cons
+ (NULL_TREE, build_int_2 (base_cnt, 0), NULL_TREE))));
-/* Build an initializer for a __pointer_type_info node. */
-static tree
-build_ptr_desc (tdecl, type)
- tree tdecl;
- tree type;
-{
- tree t, elems;
+ fn = get_identifier ("__rtti_class");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (base_info_type_node), tree_cons
+ (NULL_TREE, sizetype, void_list_node))));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
+ }
- t = TREE_TYPE (type);
- t = build_t_desc (t, 1);
- t = build_indirect_ref (t, NULL);
- elems = tree_cons (NULL_TREE, t, NULL_TREE);
- return build_generic_desc (tdecl, __ptr_desc_type_node, elems);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
-/* Build an initializer for a __attr_type_info node. */
-static tree
-build_attr_desc (tdecl, type)
+/* Build an initializer for a __pointer_type_info node. */
+static void
+expand_ptr_desc (tdecl, type)
tree tdecl;
tree type;
{
- tree elems, t, attrval;
+ tree t, elems, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
- if (TYPE_READONLY (type))
- {
- if (TYPE_VOLATILE (type))
- attrval = lookup_field (__attr_desc_type_node,
- get_identifier("_RTTI_ATTR_CONSTVOL"), 0, 0);
- else
- attrval = lookup_field (__attr_desc_type_node,
- get_identifier("_RTTI_ATTR_CONST"), 0, 0);
- }
+ type = TREE_TYPE (type);
+ expand_expr_stmt (get_typeid_1 (type));
+ t = decay_conversion (get_tinfo_var (type));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, t, NULL_TREE)));
+
+ fn = get_identifier ("__rtti_ptr");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- if (TYPE_VOLATILE (type))
- attrval = lookup_field (__attr_desc_type_node,
- get_identifier("_RTTI_ATTR_VOLATILE"), 0, 0);
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node)));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
}
- t = build_t_desc (TYPE_MAIN_VARIANT (type), 1);
- t = build_indirect_ref (t , NULL);
- elems = tree_cons (NULL_TREE, attrval, tree_cons (NULL_TREE, t, NULL_TREE));
- return build_generic_desc (tdecl, __attr_desc_type_node, elems);
-}
-
-/* Build an initializer for a __func_type_info node. */
-static tree
-build_func_desc (tdecl)
- tree tdecl;
-{
- tree elems, name_string;
- tree tname = DECL_NAME (tdecl);
- name_string = combine_strings (build_string
- (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
- elems = name_string;
- return build_generic_desc (tdecl, __func_desc_type_node, elems);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
-/* Build an initializer for a __ptmf_type_info node. */
-static tree
-build_ptmf_desc (tdecl)
- tree tdecl;
-{
- tree elems, name_string;
- tree tname = DECL_NAME (tdecl);
-
- name_string = combine_strings (build_string
- (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
- elems = name_string;
- return build_generic_desc (tdecl, __ptmf_desc_type_node, elems);
-}
-
-/* Build an initializer for a __ptmd_type_info node. */
-static tree
-build_ptmd_desc (tdecl, type)
- tree tdecl;
- tree type;
-{
- tree tc, t, elems;
- tc = build_t_desc (TYPE_OFFSET_BASETYPE (type), 1);
- tc = build_indirect_ref (tc , NULL);
- t = build_t_desc (TREE_TYPE (type), 1);
- t = build_indirect_ref (t , NULL);
- elems = tree_cons (NULL_TREE, tc,
- tree_cons (NULL_TREE, t, NULL_TREE));
- return build_generic_desc (tdecl, __ptmd_desc_type_node, elems);
-}
-
-struct uninst_st {
- tree type;
- struct uninst_st *next;
-};
-typedef struct uninst_st uninst_node;
-static uninst_node * uninst_desc = (uninst_node *)NULL;
+/* Build an initializer for a __attr_type_info node. */
static void
-add_uninstantiated_desc (type)
+expand_attr_desc (tdecl, type)
+ tree tdecl;
tree type;
{
- uninst_node *t;
+ tree elems, t, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
+ tree attrval = build_int_2
+ (TYPE_READONLY (type) | TYPE_VOLATILE (type) * 2, 0);
+
+ expand_expr_stmt (get_typeid_1 (TYPE_MAIN_VARIANT (type)));
+ t = decay_conversion (get_tinfo_var (TYPE_MAIN_VARIANT (type)));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, attrval, tree_cons (NULL_TREE, t, NULL_TREE))));
+
+ fn = get_identifier ("__rtti_attr");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node))));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
+ }
- t = (uninst_node *) xmalloc (sizeof (struct uninst_st));
- t->type = type;
- t->next = uninst_desc;
- uninst_desc = t;
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
-/* We may choose to link the emitting of certain high use TDs for certain
- objects, we do that here. Return the type to link against if such a
- link exists, otherwise just return TYPE. */
+/* Build an initializer for a type_info node that just has a name. */
-static tree
-get_def_to_follow (type)
- tree type;
-{
-#if 0
- /* For now we don't lay out T&, T* TDs with the main TD for the object. */
- /* Let T* and T& be written only when T is written (if T is an aggr).
- We do this for const, but not for volatile, since volatile
- is rare and const is not. */
- if (!TYPE_VOLATILE (taggr)
- && (TREE_CODE (taggr) == POINTER_TYPE
- || TREE_CODE (taggr) == REFERENCE_TYPE)
- && IS_AGGR_TYPE (TREE_TYPE (taggr)))
- taggr = TREE_TYPE (taggr);
-#endif
- return type;
-}
-
-/* build a general type_info node. */
-tree
-build_t_desc (type, definition)
+static void
+expand_generic_desc (tdecl, type, fnname)
+ tree tdecl;
tree type;
- int definition;
+ char *fnname;
{
- tree tdecl, tname;
- tree t, taggr;
-
- if (__ptmd_desc_type_node == NULL_TREE)
- {
- init_type_desc();
- if (__ptmd_desc_type_node)
- {
- for ( ; uninst_desc; uninst_desc = uninst_desc->next )
- build_t_desc (uninst_desc->type, 1);
- }
- }
- if (__t_desc_type_node == NULL_TREE)
- {
- static int warned = 0;
- if (! warned)
- {
- cp_error ("failed to build type descriptor node of '%T', maybe <typeinfo> not included", type);
- }
- warned = 1;
- return error_mark_node;
- }
- if (__ptmd_desc_type_node == NULL_TREE)
- {
- add_uninstantiated_desc (type);
- definition = 0;
- }
-
- push_obstacks (&permanent_obstack, &permanent_obstack);
- tname = build_t_desc_overload (type);
-
- if (!IDENTIFIER_AS_DESC (tname))
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
+ tree elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), NULL_TREE));
+
+ tree fn = get_identifier (fnname);
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node);
- DECL_EXTERNAL (tdecl) = 1;
- TREE_PUBLIC (tdecl) = 1;
- tdecl = pushdecl_top_level (tdecl);
- SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0));
- if (!definition)
- cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, void_list_node));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
}
- else
- tdecl = TREE_OPERAND (IDENTIFIER_AS_DESC (tname), 0);
- /* If it's not a definition, don't do anything more. */
- if (!definition)
- return IDENTIFIER_AS_DESC (tname);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
+}
- /* If it has already been written, don't to anything more. */
- /* Should this be on tdecl? */
- if (TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))
- return IDENTIFIER_AS_DESC (tname);
+/* Generate the code for a type_info initialization function.
+ Note that we take advantage of the passage
- /* If we previously defined it, return the defined result. */
- if (DECL_INITIAL (tdecl))
- return IDENTIFIER_AS_DESC (tname);
-
- taggr = get_def_to_follow (type);
+ 5.2.7 Type identification [expr.typeid]
+
+ Whether or not the destructor is called for the type_info object at the
+ end of the program is unspecified.
- /* If we know that we don't need to write out this type's
- vtable, then don't write out it's type_info. Somebody
- else will take care of that. */
- if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr))
- {
- /* Let's play follow the vtable. */
- TREE_PUBLIC (tdecl) = CLASSTYPE_INTERFACE_KNOWN (taggr);
- DECL_EXTERNAL (tdecl) = CLASSTYPE_INTERFACE_ONLY (taggr);
- }
- else
- {
- DECL_EXTERNAL (tdecl) = 0;
- TREE_PUBLIC (tdecl) = (definition > 1);
- }
+ and don't bother to arrange for these objects to be destroyed. It
+ doesn't matter, anyway, since the destructors don't do anything.
+
+ This must only be called from toplevel (i.e. from finish_file)! */
- if (DECL_EXTERNAL (tdecl))
- return IDENTIFIER_AS_DESC (tname);
+void
+synthesize_tinfo_fn (fndecl)
+ tree fndecl;
+{
+ tree type = TREE_TYPE (DECL_NAME (fndecl));
+ tree tmp, addr;
- /* Show that we are defining the t_desc for this type. */
- DECL_INITIAL (tdecl) = error_mark_node;
- t = DECL_CONTEXT (tdecl);
- if ( t && TREE_CODE_CLASS (TREE_CODE (t)) == 't')
- pushclass (t, 2);
+ tree tdecl = get_tinfo_var (type);
+ DECL_EXTERNAL (tdecl) = 0;
+ TREE_STATIC (tdecl) = 1;
+ DECL_COMMON (tdecl) = 1;
+ TREE_USED (tdecl) = 1;
+ DECL_ALIGN (tdecl) = TYPE_ALIGN (ptr_type_node);
+ cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+
+ start_function (NULL_TREE, fndecl, NULL_TREE, NULL_TREE, 1);
+ store_parm_decls ();
+ clear_last_expr ();
+ push_momentary ();
+
+ /* If the first word of the array (the vtable) is non-zero, we've already
+ initialized the object, so don't do it again. */
+ addr = decay_conversion (tdecl);
+ tmp = convert (build_pointer_type (ptr_type_node), addr);
+ tmp = build_indirect_ref (tmp, 0);
+ tmp = build_binary_op (EQ_EXPR, tmp, integer_zero_node, 1);
+ expand_start_cond (tmp, 0);
if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
- t = build_attr_desc (tdecl, type);
+ expand_attr_desc (tdecl, type);
else if (TREE_CODE (type) == ARRAY_TYPE)
- t = build_ptr_desc (tdecl, type);
+ expand_generic_desc (tdecl, type, "__rtti_array");
else if (TREE_CODE (type) == POINTER_TYPE)
{
if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
- {
- type = TREE_TYPE (type);
- t = build_ptmd_desc (tdecl, type);
- }
+ expand_generic_desc (tdecl, type, "__rtti_ptmd");
+ else if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_ptmf");
else
- {
- t = build_ptr_desc (tdecl, type);
- }
+ expand_ptr_desc (tdecl, type);
}
- else if (TYPE_BUILT_IN (type))
- t = build_bltn_desc (tdecl, type);
+ else if (TYPE_PTRMEMFUNC_P (type))
+ expand_generic_desc (tdecl, type, "__rtti_ptmf");
else if (IS_AGGR_TYPE (type))
{
- if (TYPE_PTRMEMFUNC_P (type))
- t = build_ptmf_desc (tdecl);
+ if (CLASSTYPE_N_BASECLASSES (type) == 0)
+ expand_generic_desc (tdecl, type, "__rtti_user");
+ else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
+ && (TREE_VIA_PUBLIC
+ (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
+ expand_si_desc (tdecl, type);
else
- t = build_class_desc (tdecl, type);
+ expand_class_desc (tdecl, type);
}
+ else if (TREE_CODE (type) == ENUMERAL_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_user");
else if (TREE_CODE (type) == FUNCTION_TYPE)
- t = build_func_desc (tdecl);
- else
- t = build_user_desc (tdecl);
+ expand_generic_desc (tdecl, type, "__rtti_func");
+ else
+ my_friendly_abort (252);
- pop_obstacks ();
- return t;
+ expand_end_cond ();
+
+ /* OK, now return the type_info object. */
+ tmp = convert (build_pointer_type (type_info_type_node), addr);
+ tmp = build_indirect_ref (tmp, 0);
+ c_expand_return (tmp);
+ finish_function (lineno, 0, 0);
}
#if 0
static struct search_level *search_stack;
static tree lookup_field_1 ();
-static int lookup_fnfields_1 ();
+static int lookup_fnfields_1 PROTO((tree, tree));
static void dfs_walk ();
static int markedp ();
static void dfs_unmark ();
return p;
}
+/* Clears the deferred pop from pop_memoized_context, if any. */
+static void
+clear_memoized_cache ()
+{
+ if (prev_type_stack)
+ {
+ type_stack = pop_type_level (prev_type_stack);
+ prev_type_memoized = 0;
+ prev_type_stack = 0;
+ }
+}
+
/* Make an entry in the memoized table for type TYPE
that the entry for NAME is FIELD. */
int index = MEMOIZED_HASH_FN (name);
tree entry, *prev_entry;
+ /* Since we allocate from the type_obstack, we must pop any deferred
+ levels. */
+ clear_memoized_cache ();
+
memoized_adds[function_p] += 1;
if (CLASSTYPE_MTABLE_ENTRY (type) == 0)
{
return;
}
/* Otherwise, need to pop old stack here. */
- type_stack = pop_type_level (prev_type_stack);
- prev_type_memoized = 0;
- prev_type_stack = 0;
+ clear_memoized_cache ();
}
type_stack = push_type_level ((struct stack_level *)type_stack,
while (len--)
tem[len*2+1] = (tree)CLASSTYPE_MTABLE_ENTRY (tem[len*2]);
+ /* If there was a deferred pop, we need to pop it now. */
+ clear_memoized_cache ();
+
prev_type_stack = type_stack;
prev_type_memoized = type_stack->type;
}
static int
get_base_distance_recursive (binfo, depth, is_private, rval,
rval_private_ptr, new_binfo_ptr, parent, path_ptr,
- protect, via_virtual_ptr, via_virtual)
- tree binfo, *new_binfo_ptr, parent, *path_ptr;
- int *rval_private_ptr, depth, is_private, rval, protect, *via_virtual_ptr,
- via_virtual;
+ protect, via_virtual_ptr, via_virtual,
+ current_scope_in_chain)
+ tree binfo;
+ int depth, is_private, rval;
+ int *rval_private_ptr;
+ tree *new_binfo_ptr, parent, *path_ptr;
+ int protect, *via_virtual_ptr, via_virtual;
+ int current_scope_in_chain;
{
tree binfos;
int i, n_baselinks;
+ if (protect
+ && !current_scope_in_chain
+ && is_friend (BINFO_TYPE (binfo), current_scope ()))
+ current_scope_in_chain = 1;
+
if (BINFO_TYPE (binfo) == parent || binfo == parent)
{
if (rval == -1)
= (protect
&& (is_private
|| (!TREE_VIA_PUBLIC (base_binfo)
+ && !(TREE_VIA_PROTECTED (base_binfo)
+ && current_scope_in_chain)
&& !is_friend (BINFO_TYPE (binfo), current_scope ()))));
int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
int was;
rval, rval_private_ptr,
new_binfo_ptr, parent, path_ptr,
protect, via_virtual_ptr,
- this_virtual);
+ this_virtual,
+ current_scope_in_chain);
/* watch for updates; only update if path is good. */
if (path_ptr && WATCH_VALUES (rval, *via_virtual_ptr) != was)
BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
rval = get_base_distance_recursive (binfo, 0, 0, -1,
&rval_private, &new_binfo, parent,
- path_ptr, watch_access, &via_virtual, 0);
+ path_ptr, watch_access, &via_virtual, 0,
+ 0);
dfs_walk (binfo, dfs_unmark, markedp);
expand_direct_vtbls_init for the style of search we do. */
static tree
get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
- tree binfo, abstract_virtuals;
+ tree binfo;
int do_self;
+ tree abstract_virtuals;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
- /* If there is a rtti, it is the first field, though perhaps from
- the base class. Otherwise, the first fields are virtual base class
- pointer fields. */
- if (CLASSTYPE_RTTI (type) && VFIELD_NAME_P (DECL_NAME (fields)))
- /* Get past vtable for the object. */
+#if 0
+ /* See finish_struct_1 for when we can enable this. */
+ /* If we have a vtable pointer first, skip it. */
+ if (VFIELD_NAME_P (DECL_NAME (fields)))
fields = TREE_CHAIN (fields);
+#endif
if (fields == NULL_TREE
|| DECL_NAME (fields) == NULL_TREE
DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (nvtbl));
TREE_READONLY (nvtbl) = 0;
+ DECL_ARTIFICIAL (nvtbl) = 1;
nvtbl = pushdecl (nvtbl);
init = NULL_TREE;
cp_finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
expand_direct_vtbls_init. */
static void
fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets)
- tree real_binfo, binfo, addr, orig_addr, type, vbase, *vbase_offsets;
+ tree real_binfo, binfo;
int init_self, can_elide;
+ tree addr, orig_addr, type, vbase, *vbase_offsets;
{
tree real_binfos = BINFO_BASETYPES (real_binfo);
tree binfos = BINFO_BASETYPES (binfo);
return exp;
}
+
+/* Take the address of an inline function without setting TREE_ADDRESSABLE
+ or TREE_USED. */
+
+tree
+inline_conversion (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == FUNCTION_DECL)
+ {
+ tree type = build_type_variant
+ (TREE_TYPE (exp), TREE_READONLY (exp), TREE_THIS_VOLATILE (exp));
+ exp = build1 (ADDR_EXPR, build_pointer_type (type), exp);
+ }
+ return exp;
+}
\f
tree
build_object_ref (datum, basetype, field)
{
aref = save_expr (aref);
- /* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
- if (TREE_CODE (aref) == INDIRECT_REF)
- TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-
delta = build_binary_op (PLUS_EXPR,
build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
delta, 1);
&& current_function_decl)
synthesize_method (function);
- fntype = build_type_variant (TREE_TYPE (function),
- TREE_READONLY (function),
- TREE_THIS_VOLATILE (function));
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
+ function = inline_conversion (function);
}
else
function = default_conversion (function);