cp-tree.h (CPTI_TINFO_DECL_TYPE): Replace with ...

* cp-tree.h (CPTI_TINFO_DECL_TYPE): Replace with ...
	(CPTI_TYPE_INFO_PTR_TYPE): ... this.
	(tinfo_decl_type): Replace with ...
	(type_info_ptr_type): ... this.
	(import_export_tinfo): Declare.
	(tinfo_decl_p): Rename to ...
	(unemitted_tinfo_decl_p): ... this.
	* decl2.c (import_export_decl): Break out tinfo handling into ...
	(import_export_tinfo): ... here. New function.
	(finish_file): Adjust.
	* rtti.c (TINFO_REAL_NAME): New macro.
	(init_rtti_processing): Create the tinfo types.
	(get_tinfo_decl_dynamic): Use type_info_ptr_type, get_tinfo_ptr.
	(get_tinfo_decl): Adjust.
	(get_tinfo_ptr): New function.
	(get_type_id): Use it.
	(tinfo_base_init): Create vtable decl here, if it doesn't exist.
	(ptr_initializer): Use get_tinfo_ptr.
	(ptm_initializer): Likewise.
	(synthesize_tinfo_var): Break into ...
	(get_pseudo_ti_init): ... this. Just create the initializer.
	(get_pseudo_ti_desc): .. and this.
	(create_real_tinfo_var): Remove.
	(create_pseudo_type_info): Don't create the vtable decl here.
	(get_vmi_pseudo_type_info): Remove.
	(create_tinfo_types): Adjust.
	(tinfo_decl_p): Rename to ...
	(unemitted_tinfo_decl_p): ... here. Adjust.
	(emit_tinfo_decl): Adjust. Create the initializer.

From-SVN: r55124
This commit is contained in:
Nathan Sidwell 2002-06-30 20:41:38 +00:00 committed by Nathan Sidwell
parent e3223ea293
commit d689a8f192
4 changed files with 369 additions and 353 deletions

View File

@ -1,3 +1,35 @@
2002-06-30 Nathan Sidwell <nathan@codesourcery.com>
* cp-tree.h (CPTI_TINFO_DECL_TYPE): Replace with ...
(CPTI_TYPE_INFO_PTR_TYPE): ... this.
(tinfo_decl_type): Replace with ...
(type_info_ptr_type): ... this.
(import_export_tinfo): Declare.
(tinfo_decl_p): Rename to ...
(unemitted_tinfo_decl_p): ... this.
* decl2.c (import_export_decl): Break out tinfo handling into ...
(import_export_tinfo): ... here. New function.
(finish_file): Adjust.
* rtti.c (TINFO_REAL_NAME): New macro.
(init_rtti_processing): Create the tinfo types.
(get_tinfo_decl_dynamic): Use type_info_ptr_type, get_tinfo_ptr.
(get_tinfo_decl): Adjust.
(get_tinfo_ptr): New function.
(get_type_id): Use it.
(tinfo_base_init): Create vtable decl here, if it doesn't exist.
(ptr_initializer): Use get_tinfo_ptr.
(ptm_initializer): Likewise.
(synthesize_tinfo_var): Break into ...
(get_pseudo_ti_init): ... this. Just create the initializer.
(get_pseudo_ti_desc): .. and this.
(create_real_tinfo_var): Remove.
(create_pseudo_type_info): Don't create the vtable decl here.
(get_vmi_pseudo_type_info): Remove.
(create_tinfo_types): Adjust.
(tinfo_decl_p): Rename to ...
(unemitted_tinfo_decl_p): ... here. Adjust.
(emit_tinfo_decl): Adjust. Create the initializer.
2002-06-27 Mark Mitchell <mark@codesourcery.com>
PR c++/6695

View File

@ -567,7 +567,7 @@ enum cp_tree_index
CPTI_STD,
CPTI_ABI,
CPTI_TYPE_INFO_TYPE,
CPTI_TINFO_DECL_TYPE,
CPTI_TYPE_INFO_PTR_TYPE,
CPTI_ABORT_FNDECL,
CPTI_GLOBAL_DELETE_FNDECL,
CPTI_AGGR_TAG,
@ -654,7 +654,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#define std_node cp_global_trees[CPTI_STD]
#define abi_node cp_global_trees[CPTI_ABI]
#define type_info_type_node cp_global_trees[CPTI_TYPE_INFO_TYPE]
#define tinfo_decl_type cp_global_trees[CPTI_TINFO_DECL_TYPE]
#define type_info_ptr_type cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE]
#define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL]
#define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
#define current_aggr cp_global_trees[CPTI_AGGR_TAG]
@ -3935,6 +3935,7 @@ extern tree coerce_delete_type PARAMS ((tree));
extern void comdat_linkage PARAMS ((tree));
extern void import_export_vtable PARAMS ((tree, tree, int));
extern void import_export_decl PARAMS ((tree));
extern void import_export_tinfo PARAMS ((tree, tree));
extern tree build_cleanup PARAMS ((tree));
extern void finish_file PARAMS ((void));
extern tree reparse_absdcl_as_expr PARAMS ((tree, tree));
@ -4163,7 +4164,7 @@ extern tree get_tinfo_decl PARAMS((tree));
extern tree get_typeid PARAMS((tree));
extern tree build_dynamic_cast PARAMS((tree, tree));
extern void emit_support_tinfos PARAMS((void));
extern int tinfo_decl_p PARAMS((tree, void *));
extern int unemitted_tinfo_decl_p PARAMS((tree, void *));
extern int emit_tinfo_decl PARAMS((tree *, void *));
/* in search.c */

View File

@ -2509,47 +2509,44 @@ import_export_decl (decl)
else
comdat_linkage (decl);
}
else if (tinfo_decl_p (decl, 0))
{
/* Here, we only decide whether or not the tinfo node should be
emitted with the vtable. The decl we're considering isn't
actually the one which gets emitted; that one is generated in
create_real_tinfo_var. */
tree ctype = TREE_TYPE (DECL_NAME (decl));
if (IS_AGGR_TYPE (ctype))
import_export_class (ctype);
if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype)
&& TYPE_POLYMORPHIC_P (ctype)
/* If -fno-rtti, we're not necessarily emitting this stuff with
the class, so go ahead and emit it now. This can happen
when a class is used in exception handling. */
&& flag_rtti
/* If the type is a cv-qualified variant of a type, then we
must emit the tinfo function in this translation unit
since it will not be emitted when the vtable for the type
is output (which is when the unqualified version is
generated). */
&& same_type_p (ctype, TYPE_MAIN_VARIANT (ctype)))
{
DECL_NOT_REALLY_EXTERN (decl)
= ! CLASSTYPE_INTERFACE_ONLY (ctype);
DECL_COMDAT (decl) = 0;
}
else
{
DECL_NOT_REALLY_EXTERN (decl) = 1;
DECL_COMDAT (decl) = 1;
}
}
else
comdat_linkage (decl);
DECL_INTERFACE_KNOWN (decl) = 1;
}
/* Here, we only decide whether or not the tinfo node should be
emitted with the vtable. */
void
import_export_tinfo (decl, type)
tree decl;
tree type;
{
if (DECL_INTERFACE_KNOWN (decl))
return;
if (IS_AGGR_TYPE (type))
import_export_class (type);
if (IS_AGGR_TYPE (type) && CLASSTYPE_INTERFACE_KNOWN (type)
&& TYPE_POLYMORPHIC_P (type)
/* If -fno-rtti, we're not necessarily emitting this stuff with
the class, so go ahead and emit it now. This can happen when
a class is used in exception handling. */
&& flag_rtti)
{
DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type);
DECL_COMDAT (decl) = 0;
}
else
{
DECL_NOT_REALLY_EXTERN (decl) = 1;
DECL_COMDAT (decl) = 1;
}
DECL_INTERFACE_KNOWN (decl) = 1;
}
tree
build_cleanup (decl)
tree decl;
@ -3344,7 +3341,7 @@ finish_file ()
/* Write out needed type info variables. Writing out one variable
might cause others to be needed. */
if (walk_globals (tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
reconsider = 1;
/* The list of objects with static storage duration is built up

View File

@ -1,5 +1,5 @@
/* RunTime Type Identification
Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
Mostly written by Jason Merrill (jason@cygnus.com).
@ -30,16 +30,46 @@ Boston, MA 02111-1307, USA. */
#include "assert.h"
#include "toplev.h"
/* C++ returns type information to the user in struct type_info
objects. We also use type information to implement dynamic_cast and
exception handlers. Type information for a particular type is
indicated with an ABI defined structure derived from type_info.
This would all be very straight forward, but for the fact that the
runtime library provides the definitions of the type_info structure
and the ABI defined derived classes. We cannot build declarations
of them directly in the compiler, but we need to layout objects of
their type. Somewhere we have to lie.
We define layout compatible POD-structs with compiler-defined names
and generate the appropriate initializations for them (complete
with explicit mention of their vtable). When we have to provide a
type_info to the user we reinterpret_cast the internal compiler
type to type_info. A well formed program can only explicitly refer
to the type_infos of complete types (& cv void). However, we chain
pointer type_infos to the pointed-to-type, and that can be
incomplete. We only need the addresses of such incomplete
type_info objects for static initialization.
The type information VAR_DECL of a type is held on the
IDENTIFIER_GLOBAL_VALUE of the type's mangled name. That VAR_DECL
will be the internal type. It will usually have the correct
internal type reflecting the kind of type it represents (pointer,
array, function, class, inherited class, etc). When the type it
represents is incomplete, it will have the internal type
corresponding to type_info. That will only happen at the end of
translation, when we are emitting the type info objects. */
/* Accessors for the type_info objects. We need to remember several things
about each of the type_info types. The global tree nodes such as
bltn_desc_type_node are TREE_LISTs, and these macros are used to access
the required information. */
/* The RECORD_TYPE of a type_info derived class. */
#define TINFO_PSEUDO_TYPE(NODE) TREE_TYPE (NODE)
/* The VAR_DECL of the vtable for the type_info derived class. */
/* The VAR_DECL of the vtable for the type_info derived class.
This is only filled in at the end of the translation. */
#define TINFO_VTABLE_DECL(NODE) TREE_VALUE (NODE)
extern struct obstack permanent_obstack;
/* The IDENTIFIER_NODE naming the real class. */
#define TINFO_REAL_NAME(NODE) TREE_PURPOSE (NODE)
static tree build_headof PARAMS((tree));
static tree ifnonnull PARAMS((tree, tree));
@ -48,7 +78,8 @@ static tree build_dynamic_cast_1 PARAMS((tree, tree));
static tree throw_bad_cast PARAMS((void));
static tree throw_bad_typeid PARAMS((void));
static tree get_tinfo_decl_dynamic PARAMS((tree));
static bool typeid_ok_p PARAMS ((void));
static tree get_tinfo_ptr PARAMS((tree));
static bool typeid_ok_p PARAMS((void));
static int qualifier_flags PARAMS((tree));
static int target_incomplete_p PARAMS((tree));
static tree tinfo_base_init PARAMS((tree, tree));
@ -59,15 +90,21 @@ static tree dfs_class_hint_mark PARAMS ((tree, void *));
static tree dfs_class_hint_unmark PARAMS ((tree, void *));
static int class_hint_flags PARAMS((tree));
static tree class_initializer PARAMS((tree, tree, tree));
static tree synthesize_tinfo_var PARAMS((tree));
static tree create_real_tinfo_var PARAMS((tree, tree, tree, tree, int));
static tree create_pseudo_type_info PARAMS((const char *, int, ...));
static tree get_vmi_pseudo_type_info PARAMS((int));
static tree get_pseudo_ti_init PARAMS ((tree, tree, int *));
static tree get_pseudo_ti_desc PARAMS((tree));
static void create_tinfo_types PARAMS((void));
static int typeinfo_in_lib_p PARAMS((tree));
static int doing_runtime = 0;
/* Declare language defined type_info type and a pointer to const
type_info. This is incomplete here, and will be completed when
the user #includes <typeinfo>. There are language defined
restrictions on what can be done until that is included. Create
the internal versions of the ABI types. */
void
init_rtti_processing ()
{
@ -76,8 +113,11 @@ init_rtti_processing ()
= xref_tag (class_type, get_identifier ("type_info"),
/*attributes=*/NULL_TREE, 1);
pop_namespace ();
tinfo_decl_type =
build_qualified_type (type_info_type_node, TYPE_QUAL_CONST);
type_info_ptr_type =
build_pointer_type
(build_qualified_type (type_info_type_node, TYPE_QUAL_CONST));
create_tinfo_types ();
}
/* Given the expression EXP of type `class *', return the head of the
@ -184,13 +224,12 @@ get_tinfo_decl_dynamic (exp)
/* The RTTI information is at index -1. */
index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1);
t = build_vtbl_ref (exp, index);
TREE_TYPE (t) = build_pointer_type (tinfo_decl_type);
TREE_TYPE (t) = type_info_ptr_type;
return t;
}
/* otherwise return the type_info for the static type of the expr. */
exp = get_tinfo_decl (TYPE_MAIN_VARIANT (type));
return build_unary_op (ADDR_EXPR, exp, 0);
/* Otherwise return the type_info for the static type of the expr. */
return get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
}
static bool
@ -264,9 +303,9 @@ tinfo_name (type)
return name_string;
}
/* Returns a decl for the type_info variable for TYPE. You must
arrange that the decl is mark_used, if actually use it --- decls in
vtables are only used if the vtable is output. */
/* Return a VAR_DECL for the internal ABI defined type_info object for
TYPE. You must arrange that the decl is mark_used, if actually use
it --- decls in vtables are only used if the vtable is output. */
tree
get_tinfo_decl (type)
@ -279,7 +318,7 @@ get_tinfo_decl (type)
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{
error ("cannot create type information for type `%T' because its size is variable",
type);
type);
return error_mark_node;
}
@ -292,36 +331,44 @@ get_tinfo_decl (type)
name = mangle_typeinfo_for_type (type);
d = IDENTIFIER_GLOBAL_VALUE (name);
if (d)
/* OK */;
else
if (!d)
{
/* The tinfo decl is the type_info object itself. We make all
tinfo objects look as type_info, even though they will end up
being a subclass of that when emitted. This means that we'll
erroneously think we know the dynamic type -- be careful in the
runtime. */
d = build_lang_decl (VAR_DECL, name, tinfo_decl_type);
tree var_desc = get_pseudo_ti_desc (type);
d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
DECL_ARTIFICIAL (d) = 1;
DECL_ALIGN (d) = TYPE_ALIGN (ptr_type_node);
DECL_USER_ALIGN (d) = 0;
TREE_READONLY (d) = 1;
TREE_STATIC (d) = 1;
DECL_EXTERNAL (d) = 1;
TREE_PUBLIC (d) = 1;
SET_DECL_ASSEMBLER_NAME (d, name);
DECL_COMDAT (d) = 1;
cp_finish_decl (d, NULL_TREE, NULL_TREE, 0);
pushdecl_top_level (d);
/* Remember the type it is for. */
TREE_TYPE (name) = type;
TREE_USED (name) = 1;
}
return d;
}
/* Return a pointer to a type_info object describing TYPE, suitably
cast to the language defined type. */
static tree
get_tinfo_ptr (type)
tree type;
{
tree exp = get_tinfo_decl (type);
/* Convert to type_info type. */
exp = build_unary_op (ADDR_EXPR, exp, 0);
exp = ocp_convert (type_info_ptr_type, exp, CONV_REINTERPRET, 0);
return exp;
}
/* Return the type_info object for TYPE. */
tree
@ -350,7 +397,7 @@ get_typeid (type)
if (!type)
return error_mark_node;
return get_tinfo_decl (type);
return build_indirect_ref (get_tinfo_ptr (type), NULL);
}
/* Check whether TEST is null before returning RESULT. If TEST is used in
@ -684,6 +731,7 @@ tinfo_base_init (desc, target)
{
tree init = NULL_TREE;
tree name_decl;
tree vtable_ptr;
{
tree name_name;
@ -711,12 +759,41 @@ tinfo_base_init (desc, target)
cp_finish_decl (name_decl, name_string, NULL_TREE, 0);
pushdecl_top_level (name_decl);
}
if (TINFO_VTABLE_DECL (desc))
vtable_ptr = TINFO_VTABLE_DECL (desc);
if (!vtable_ptr)
{
tree vtbl_ptr = TINFO_VTABLE_DECL (desc);
init = tree_cons (NULL_TREE, vtbl_ptr, init);
tree real_type;
push_nested_namespace (abi_node);
real_type = xref_tag (class_type, TINFO_REAL_NAME (desc),
/*attributes=*/NULL_TREE, 1);
pop_nested_namespace (abi_node);
if (!COMPLETE_TYPE_P (real_type))
{
/* We never saw a definition of this type, so we need to
tell the compiler that this is an exported class, as
indeed all of the __*_type_info classes are. */
SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
}
vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);
vtable_ptr = build_unary_op (ADDR_EXPR, vtable_ptr, 0);
/* We need to point into the middle of the vtable. */
vtable_ptr = build
(PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,
size_binop (MULT_EXPR,
size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
TYPE_SIZE_UNIT (vtable_entry_type)));
TREE_CONSTANT (vtable_ptr) = 1;
TINFO_VTABLE_DECL (desc) = vtable_ptr;
}
init = tree_cons (NULL_TREE, vtable_ptr, init);
init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
@ -765,8 +842,7 @@ ptr_initializer (desc, target, non_public_ptr)
}
init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
init = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR,
get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
init);
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
@ -803,12 +879,11 @@ ptm_initializer (desc, target, non_public_ptr)
}
init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
init = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR,
get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
init);
init = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
init);
get_tinfo_ptr (klass),
init);
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
@ -929,81 +1004,63 @@ typeinfo_in_lib_p (type)
}
}
/* Generate a pseudo_type_info VAR_DECL suitable for the supplied
TARGET_TYPE and corresponding to PUBLIC_DECL. This is the structure expected by
the runtime, and therefore has additional fields. If we need not emit a
definition (because the runtime must contain it), return NULL_TREE,
otherwise return the VAR_DECL. */
/* Generate the initializer for the type info describing
TYPE. VAR_DESC is a . NON_PUBLIC_P is set non-zero, if the VAR_DECL
should not be exported from this object file. This should only be
called at the end of translation, when we know that no further
types will be completed. */
static tree
synthesize_tinfo_var (public_decl)
tree public_decl;
get_pseudo_ti_init (type, var_desc, non_public_p)
tree type;
tree var_desc;
int *non_public_p;
{
tree var_init = NULL_TREE;
tree var_type = NULL_TREE;
int non_public = 0;
tree target_type = TREE_TYPE (DECL_NAME (public_decl));
my_friendly_assert (target_type != NULL_TREE, 20000120);
/* Say we've dealt with it. */
TREE_TYPE (DECL_NAME (public_decl)) = NULL_TREE;
switch (TREE_CODE (target_type))
my_friendly_assert (at_eof, 20021120);
switch (TREE_CODE (type))
{
case POINTER_TYPE:
if (TYPE_PTRMEM_P (target_type))
{
var_type = ptm_desc_type_node;
var_init = ptm_initializer (var_type, target_type, &non_public);
}
if (TYPE_PTRMEM_P (type))
return ptm_initializer (var_desc, type, non_public_p);
else
{
if (typeinfo_in_lib_p (target_type) && !doing_runtime)
/* These are in the runtime. */
return NULL_TREE;
var_type = ptr_desc_type_node;
var_init = ptr_initializer (var_type, target_type, &non_public);
}
return ptr_initializer (var_desc, type, non_public_p);
break;
case ENUMERAL_TYPE:
var_type = enum_desc_type_node;
var_init = generic_initializer (var_type, target_type);
return generic_initializer (var_desc, type);
break;
case FUNCTION_TYPE:
var_type = func_desc_type_node;
var_init = generic_initializer (var_type, target_type);
return generic_initializer (var_desc, type);
break;
case ARRAY_TYPE:
var_type = ary_desc_type_node;
var_init = generic_initializer (var_type, target_type);
return generic_initializer (var_desc, type);
break;
case UNION_TYPE:
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (target_type))
if (TYPE_PTRMEMFUNC_P (type))
return ptm_initializer (var_desc, type, non_public_p);
else if (var_desc == class_desc_type_node)
{
var_type = ptm_desc_type_node;
var_init = ptm_initializer (var_type, target_type, &non_public);
}
else if (!COMPLETE_TYPE_P (target_type))
{
/* Emit a non-public class_type_info. */
non_public = 1;
var_type = class_desc_type_node;
var_init = class_initializer (var_type, target_type, NULL_TREE);
}
else if (!CLASSTYPE_N_BASECLASSES (target_type))
{
var_type = class_desc_type_node;
var_init = class_initializer (var_type, target_type, NULL_TREE);
if (!COMPLETE_TYPE_P (type))
/* Emit a non-public class_type_info. */
*non_public_p = 1;
return class_initializer (var_desc, type, NULL_TREE);
}
else if (var_desc == si_class_desc_type_node)
{
tree base_binfos = BINFO_BASETYPES (TYPE_BINFO (type));
tree base_binfo = TREE_VEC_ELT (base_binfos, 0);
tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
return class_initializer (var_desc, type, base_inits);
}
else
{
/* if this has a single public non-virtual base, it's easier */
tree binfo = TYPE_BINFO (target_type);
int hint = class_hint_flags (type);
tree binfo = TYPE_BINFO (type);
int nbases = BINFO_N_BASETYPES (binfo);
tree base_binfos = BINFO_BASETYPES (binfo);
tree base_inits = NULL_TREE;
int is_simple = nbases == 1;
int ix;
/* Generate the base information initializer. */
@ -1017,28 +1074,19 @@ synthesize_tinfo_var (public_decl)
if (TREE_PUBLIC (base_binfo))
flags |= 2;
tinfo = get_tinfo_decl (BINFO_TYPE (base_binfo));
tinfo = build_unary_op (ADDR_EXPR, tinfo, 0);
tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
if (TREE_VIA_VIRTUAL (base_binfo))
{
/* We store the vtable offset at which the virtual
base offset can be found. */
offset = BINFO_VPTR_FIELD (binfo_for_vbase (BINFO_TYPE (base_binfo),
target_type));
offset = BINFO_VPTR_FIELD
(binfo_for_vbase (BINFO_TYPE (base_binfo), type));
offset = convert (sizetype, offset);
flags |= 1;
}
else
offset = BINFO_OFFSET (base_binfo);
/* is it a single public inheritance? */
if (is_simple && flags == 2 && integer_zerop (offset))
{
base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
break;
}
is_simple = 0;
/* combine offset and flags into one field */
offset = cp_build_binary_op (LSHIFT_EXPR, offset,
build_int_2 (8, 0));
@ -1049,88 +1097,23 @@ synthesize_tinfo_var (public_decl)
base_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
}
if (is_simple)
var_type = si_class_desc_type_node;
else
{
int hint = class_hint_flags (target_type);
base_inits = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_inits);
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
/* Prepend the number of bases. */
base_inits = tree_cons (NULL_TREE,
build_int_2 (nbases, 0), base_inits);
/* Prepend the hint flags. */
base_inits = tree_cons (NULL_TREE,
build_int_2 (hint, 0), base_inits);
var_type = get_vmi_pseudo_type_info (nbases);
}
var_init = class_initializer (var_type, target_type, base_inits);
base_inits = build (CONSTRUCTOR,
NULL_TREE, NULL_TREE, base_inits);
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
/* Prepend the number of bases. */
base_inits = tree_cons (NULL_TREE,
build_int_2 (nbases, 0), base_inits);
/* Prepend the hint flags. */
base_inits = tree_cons (NULL_TREE,
build_int_2 (hint, 0), base_inits);
return class_initializer (var_desc, type, base_inits);
}
break;
default:
if (typeinfo_in_lib_p (target_type))
{
if (!doing_runtime)
/* These are guaranteed to be in the runtime. */
return NULL_TREE;
var_type = bltn_desc_type_node;
var_init = generic_initializer (var_type, target_type);
break;
}
abort ();
return generic_initializer (var_desc, type);
}
return create_real_tinfo_var (target_type,
public_decl, TINFO_PSEUDO_TYPE (var_type),
var_init, non_public);
}
/* Create the real typeinfo variable. NON_PUBLIC indicates that we cannot
make this variable public (comdat). */
static tree
create_real_tinfo_var (target_type, public_decl, type, init, non_public)
tree target_type;
tree public_decl;
tree type;
tree init;
int non_public;
{
static int count = 0;
tree decl;
tree hidden_name;
char hidden[30];
tree name = DECL_ASSEMBLER_NAME (public_decl);
/* We cannot give this the name NAME, as that already is globally
bound to the tinfo_decl we originally created for this type in
get_tinfo_decl. */
sprintf (hidden, "__ti_%d", count++);
hidden_name = get_identifier (hidden);
decl = build_lang_decl (VAR_DECL, hidden_name,
build_qualified_type (type, TYPE_QUAL_CONST));
DECL_ARTIFICIAL (decl) = 1;
TREE_READONLY (decl) = 1;
TREE_STATIC (decl) = 1;
DECL_EXTERNAL (decl) = 0;
if (!non_public)
{
TREE_PUBLIC (decl) = 1;
if (flag_weak
|| (DECL_COMDAT (public_decl) && !typeinfo_in_lib_p (target_type)))
comdat_linkage (decl);
}
SET_DECL_ASSEMBLER_NAME (decl, name);
DECL_INITIAL (decl) = init;
cp_finish_decl (decl, init, NULL_TREE, 0);
pushdecl_top_level (decl);
TREE_USED (decl) = 1;
return decl;
}
/* Generate the RECORD_TYPE containing the data layout of a type_info
@ -1139,7 +1122,10 @@ create_real_tinfo_var (target_type, public_decl, type, init, non_public)
type's vtable. We explicitly manage the vtable member, and name it for
real type as used in the runtime. The RECORD type has a different name,
to avoid collisions. Return a TREE_LIST who's TINFO_PSEUDO_TYPE
is the generated type and TINFO_VTABLE_DECL is the vtable decl.
is the generated type and TINFO_VTABLE_NAME is the name of the
vtable. We have to delay generating the VAR_DECL of the vtable
until the end of the translation, when we'll have seen the library
definition, if there was one.
REAL_NAME is the runtime's name of the type. Trailing arguments are
additional FIELD_DECL's for the structure. The final argument must be
@ -1148,9 +1134,8 @@ create_real_tinfo_var (target_type, public_decl, type, init, non_public)
static tree
create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
{
tree real_type, pseudo_type;
tree pseudo_type;
char *pseudo_name;
tree vtable_decl;
int ix;
tree fields[10];
tree field_decl;
@ -1167,29 +1152,6 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
if (ident)
sprintf (pseudo_name + strlen (pseudo_name), "%d", ident);
/* Get the vtable decl. */
real_type = xref_tag (class_type, get_identifier (real_name),
/*attributes=*/NULL_TREE, 1);
if (! TYPE_SIZE (real_type))
{
/* We never saw a definition of this type, so we need to tell the
compiler that this is an exported class, as indeed all of the
__*_type_info classes are. */
SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
}
vtable_decl = get_vtable_decl (real_type, /*complete=*/1);
vtable_decl = build_unary_op (ADDR_EXPR, vtable_decl, 0);
/* We need to point into the middle of the vtable. */
vtable_decl
= build (PLUS_EXPR, TREE_TYPE (vtable_decl), vtable_decl,
size_binop (MULT_EXPR,
size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
TYPE_SIZE_UNIT (vtable_entry_type)));
TREE_CONSTANT (vtable_decl) = 1;
/* First field is the pseudo type_info base class. */
fields[0] = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
@ -1203,53 +1165,96 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
TINFO_VTABLE_DECL (result) = vtable_decl;
TINFO_PSEUDO_TYPE (result) = pseudo_type;
TINFO_REAL_NAME (result) = get_identifier (real_name);
TINFO_PSEUDO_TYPE (result) =
cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
VA_CLOSE (ap);
return result;
}
/* Return a descriptor for a vmi type with NUM_BASES bases. */
/* Return a pseudo type info type node used to describe TYPE. TYPE
must be a complete type (or cv void), except at the end of the
translation unit. */
static tree
get_vmi_pseudo_type_info (num_bases)
int num_bases;
get_pseudo_ti_desc (type)
tree type;
{
tree desc;
tree array_domain, base_array;
if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
switch (TREE_CODE (type))
{
int ix;
tree extend = make_tree_vec (num_bases + 5);
for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
TREE_VEC_ELT (extend, ix) = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
vmi_class_desc_type_node = extend;
case POINTER_TYPE:
return TYPE_PTRMEM_P (type) ? ptm_desc_type_node : ptr_desc_type_node;
case ENUMERAL_TYPE:
return enum_desc_type_node;
case FUNCTION_TYPE:
return func_desc_type_node;
case ARRAY_TYPE:
return ary_desc_type_node;
case UNION_TYPE:
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
return ptm_desc_type_node;
else if (!COMPLETE_TYPE_P (type))
{
my_friendly_assert (at_eof, 20020609);
return class_desc_type_node;
}
else if (!CLASSTYPE_N_BASECLASSES (type))
return class_desc_type_node;
else
{
tree base_binfo =
TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (type)), 0);
int num_bases = BINFO_N_BASETYPES (TYPE_BINFO (type));
if (num_bases == 1
&& TREE_PUBLIC (base_binfo)
&& !TREE_VIA_VIRTUAL (base_binfo)
&& integer_zerop (BINFO_OFFSET (base_binfo)))
/* single non-virtual public. */
return si_class_desc_type_node;
else
{
tree var_desc;
tree array_domain, base_array;
if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
{
int ix;
tree extend = make_tree_vec (num_bases + 5);
for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
TREE_VEC_ELT (extend, ix)
= TREE_VEC_ELT (vmi_class_desc_type_node, ix);
vmi_class_desc_type_node = extend;
}
var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
if (var_desc)
return var_desc;
/* Add number of bases and trailing array of
base_class_type_info. */
array_domain = build_index_type (size_int (num_bases));
base_array =
build_array_type (base_desc_type_node, array_domain);
push_nested_namespace (abi_node);
var_desc = create_pseudo_type_info
("__vmi_class_type_info", num_bases,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, base_array),
NULL);
pop_nested_namespace (abi_node);
TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc;
return var_desc;
}
}
default:
return bltn_desc_type_node;
}
desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
if (desc)
return desc;
/* Add number of bases and trailing array of base_class_type_info. */
array_domain = build_index_type (size_int (num_bases));
base_array = build_array_type (base_desc_type_node, array_domain);
push_nested_namespace (abi_node);
desc = create_pseudo_type_info
("__vmi_class_type_info", num_bases,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, base_array),
NULL);
pop_nested_namespace (abi_node);
TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = desc;
return desc;
}
/* Make sure the required builtin types exist for generating the type_info
@ -1258,15 +1263,9 @@ get_vmi_pseudo_type_info (num_bases)
static void
create_tinfo_types ()
{
tree ptr_type_info;
if (bltn_desc_type_node)
return;
push_nested_namespace (abi_node);
my_friendly_assert (!ti_desc_type_node, 20020609);
ptr_type_info = build_pointer_type
(build_qualified_type
(type_info_type_node, TYPE_QUAL_CONST));
push_nested_namespace (abi_node);
/* Create the internal type_info structure. This is used as a base for
the other structures. */
@ -1306,7 +1305,7 @@ create_tinfo_types ()
This is really a descendant of __class_type_info. */
si_class_desc_type_node = create_pseudo_type_info
("__si_class_type_info", 0,
build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
/* Base class internal helper. Pointer to base type, offset to base,
@ -1314,7 +1313,7 @@ create_tinfo_types ()
{
tree fields[2];
fields[0] = build_decl (FIELD_DECL, NULL_TREE, ptr_type_info);
fields[0] = build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type);
fields[1] = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
base_desc_type_node = make_aggr_type (RECORD_TYPE);
finish_builtin_type (base_desc_type_node, "__base_class_type_info_pseudo",
@ -1331,7 +1330,7 @@ create_tinfo_types ()
ptr_desc_type_node = create_pseudo_type_info
("__pointer_type_info", 0,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
/* Pointer to member data type_info. Add qualifications flags,
@ -1340,8 +1339,8 @@ create_tinfo_types ()
ptm_desc_type_node = create_pseudo_type_info
("__pointer_to_member_type_info", 0,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
pop_nested_namespace (abi_node);
@ -1410,72 +1409,59 @@ emit_support_tinfos ()
definition emitted for it. */
int
tinfo_decl_p (t, data)
unemitted_tinfo_decl_p (t, data)
tree t;
void *data ATTRIBUTE_UNUSED;
{
return TREE_CODE (t) == VAR_DECL
&& IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == (t)
&& TREE_TYPE (t) == tinfo_decl_type
&& TREE_TYPE (DECL_NAME (t));
if (/* It's a var decl */
TREE_CODE (t) == VAR_DECL
/* whos name points back to itself */
&& IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
/* whos name's type is non-null */
&& TREE_TYPE (DECL_NAME (t))
/* and whos type is a struct */
&& TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
/* with a first field of our pseudo type info */
&& TREE_TYPE (TYPE_FIELDS (TREE_TYPE (t))) == ti_desc_type_node)
return 1;
return 0;
}
/* Emit a suitable type_info definition for the type_info decl pointed to by
DECL_PTR. We emit a completely new variable, of the correct type for the
actual type this is describing. The DECL_ASSEMBLER_NAME of the generated
definition is set to that of the supplied decl, so that they can be tied
up. Mark the supplied decl as having been dealt with. Emitting one
definition might cause other definitions to be required.
We need to do things this way, because we're trying to do something like
struct B : A {
...
};
extern const A tinfo_var;
const B tinfo_var = {...};
which is not permitted. Also, we've not necessarily seen the definition of B.
So we do something like the following,
extern const A tinfo_var;
struct pseudo_A {
const void *vtable_ptr;
const char *name;
};
struct pseudo_B {
pseudo_A base;
...
};
const pseudo_B proxy_tinfo_var attribute((assembler_name="tinfo_var")) =
{
{&B::vtable, "..."},
...
};
pseudo_A and pseudo_B must be layout equivalent to the real definitions in
the runtime. */
/* Finish a type info decl. DECL_PTR is a pointer to an unemitted
tinfo decl. Determine whether it needs emitting, and if so
generate the initializer. */
int
emit_tinfo_decl (decl_ptr, data)
tree *decl_ptr;
void *data ATTRIBUTE_UNUSED;
{
tree tinfo_decl = *decl_ptr;
tree decl;
tree decl = *decl_ptr;
tree type = TREE_TYPE (DECL_NAME (decl));
int non_public;
tree var_desc, var_init;
my_friendly_assert (TREE_TYPE (tinfo_decl) == tinfo_decl_type, 20000121);
import_export_decl (tinfo_decl);
if (DECL_REALLY_EXTERN (tinfo_decl) || !DECL_NEEDED_P (tinfo_decl))
import_export_tinfo (decl, type);
if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))
return 0;
create_tinfo_types ();
decl = synthesize_tinfo_var (tinfo_decl);
if (!doing_runtime && typeinfo_in_lib_p (type))
return 0;
non_public = 0;
var_desc = get_pseudo_ti_desc (type);
var_init = get_pseudo_ti_init (type, var_desc, &non_public);
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = !non_public;
if (!non_public
&& (flag_weak || (DECL_COMDAT (decl) && !typeinfo_in_lib_p (type))))
comdat_linkage (decl);
return decl != 0;
DECL_INITIAL (decl) = var_init;
cp_finish_decl (decl, var_init, NULL_TREE, 0);
/* Say we've dealt with it. */
TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
return 1;
}