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:
parent
e3223ea293
commit
d689a8f192
@ -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>
|
2002-06-27 Mark Mitchell <mark@codesourcery.com>
|
||||||
|
|
||||||
PR c++/6695
|
PR c++/6695
|
||||||
|
@ -567,7 +567,7 @@ enum cp_tree_index
|
|||||||
CPTI_STD,
|
CPTI_STD,
|
||||||
CPTI_ABI,
|
CPTI_ABI,
|
||||||
CPTI_TYPE_INFO_TYPE,
|
CPTI_TYPE_INFO_TYPE,
|
||||||
CPTI_TINFO_DECL_TYPE,
|
CPTI_TYPE_INFO_PTR_TYPE,
|
||||||
CPTI_ABORT_FNDECL,
|
CPTI_ABORT_FNDECL,
|
||||||
CPTI_GLOBAL_DELETE_FNDECL,
|
CPTI_GLOBAL_DELETE_FNDECL,
|
||||||
CPTI_AGGR_TAG,
|
CPTI_AGGR_TAG,
|
||||||
@ -654,7 +654,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
|||||||
#define std_node cp_global_trees[CPTI_STD]
|
#define std_node cp_global_trees[CPTI_STD]
|
||||||
#define abi_node cp_global_trees[CPTI_ABI]
|
#define abi_node cp_global_trees[CPTI_ABI]
|
||||||
#define type_info_type_node cp_global_trees[CPTI_TYPE_INFO_TYPE]
|
#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 abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL]
|
||||||
#define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
|
#define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
|
||||||
#define current_aggr cp_global_trees[CPTI_AGGR_TAG]
|
#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 comdat_linkage PARAMS ((tree));
|
||||||
extern void import_export_vtable PARAMS ((tree, tree, int));
|
extern void import_export_vtable PARAMS ((tree, tree, int));
|
||||||
extern void import_export_decl PARAMS ((tree));
|
extern void import_export_decl PARAMS ((tree));
|
||||||
|
extern void import_export_tinfo PARAMS ((tree, tree));
|
||||||
extern tree build_cleanup PARAMS ((tree));
|
extern tree build_cleanup PARAMS ((tree));
|
||||||
extern void finish_file PARAMS ((void));
|
extern void finish_file PARAMS ((void));
|
||||||
extern tree reparse_absdcl_as_expr PARAMS ((tree, tree));
|
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 get_typeid PARAMS((tree));
|
||||||
extern tree build_dynamic_cast PARAMS((tree, tree));
|
extern tree build_dynamic_cast PARAMS((tree, tree));
|
||||||
extern void emit_support_tinfos PARAMS((void));
|
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 *));
|
extern int emit_tinfo_decl PARAMS((tree *, void *));
|
||||||
|
|
||||||
/* in search.c */
|
/* in search.c */
|
||||||
|
@ -2509,47 +2509,44 @@ import_export_decl (decl)
|
|||||||
else
|
else
|
||||||
comdat_linkage (decl);
|
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
|
else
|
||||||
comdat_linkage (decl);
|
comdat_linkage (decl);
|
||||||
|
|
||||||
DECL_INTERFACE_KNOWN (decl) = 1;
|
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
|
tree
|
||||||
build_cleanup (decl)
|
build_cleanup (decl)
|
||||||
tree decl;
|
tree decl;
|
||||||
@ -3344,7 +3341,7 @@ finish_file ()
|
|||||||
|
|
||||||
/* Write out needed type info variables. Writing out one variable
|
/* Write out needed type info variables. Writing out one variable
|
||||||
might cause others to be needed. */
|
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;
|
reconsider = 1;
|
||||||
|
|
||||||
/* The list of objects with static storage duration is built up
|
/* The list of objects with static storage duration is built up
|
||||||
|
614
gcc/cp/rtti.c
614
gcc/cp/rtti.c
@ -1,5 +1,5 @@
|
|||||||
/* RunTime Type Identification
|
/* 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.
|
Free Software Foundation, Inc.
|
||||||
Mostly written by Jason Merrill (jason@cygnus.com).
|
Mostly written by Jason Merrill (jason@cygnus.com).
|
||||||
|
|
||||||
@ -30,16 +30,46 @@ Boston, MA 02111-1307, USA. */
|
|||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "toplev.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
|
/* 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
|
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
|
bltn_desc_type_node are TREE_LISTs, and these macros are used to access
|
||||||
the required information. */
|
the required information. */
|
||||||
/* The RECORD_TYPE of a type_info derived class. */
|
/* The RECORD_TYPE of a type_info derived class. */
|
||||||
#define TINFO_PSEUDO_TYPE(NODE) TREE_TYPE (NODE)
|
#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)
|
#define TINFO_VTABLE_DECL(NODE) TREE_VALUE (NODE)
|
||||||
|
/* The IDENTIFIER_NODE naming the real class. */
|
||||||
extern struct obstack permanent_obstack;
|
#define TINFO_REAL_NAME(NODE) TREE_PURPOSE (NODE)
|
||||||
|
|
||||||
static tree build_headof PARAMS((tree));
|
static tree build_headof PARAMS((tree));
|
||||||
static tree ifnonnull PARAMS((tree, 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_cast PARAMS((void));
|
||||||
static tree throw_bad_typeid PARAMS((void));
|
static tree throw_bad_typeid PARAMS((void));
|
||||||
static tree get_tinfo_decl_dynamic PARAMS((tree));
|
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 qualifier_flags PARAMS((tree));
|
||||||
static int target_incomplete_p PARAMS((tree));
|
static int target_incomplete_p PARAMS((tree));
|
||||||
static tree tinfo_base_init PARAMS((tree, 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 tree dfs_class_hint_unmark PARAMS ((tree, void *));
|
||||||
static int class_hint_flags PARAMS((tree));
|
static int class_hint_flags PARAMS((tree));
|
||||||
static tree class_initializer PARAMS((tree, tree, 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 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 void create_tinfo_types PARAMS((void));
|
||||||
static int typeinfo_in_lib_p PARAMS((tree));
|
static int typeinfo_in_lib_p PARAMS((tree));
|
||||||
|
|
||||||
static int doing_runtime = 0;
|
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
|
void
|
||||||
init_rtti_processing ()
|
init_rtti_processing ()
|
||||||
{
|
{
|
||||||
@ -76,8 +113,11 @@ init_rtti_processing ()
|
|||||||
= xref_tag (class_type, get_identifier ("type_info"),
|
= xref_tag (class_type, get_identifier ("type_info"),
|
||||||
/*attributes=*/NULL_TREE, 1);
|
/*attributes=*/NULL_TREE, 1);
|
||||||
pop_namespace ();
|
pop_namespace ();
|
||||||
tinfo_decl_type =
|
type_info_ptr_type =
|
||||||
build_qualified_type (type_info_type_node, TYPE_QUAL_CONST);
|
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
|
/* 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. */
|
/* The RTTI information is at index -1. */
|
||||||
index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1);
|
index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1);
|
||||||
t = build_vtbl_ref (exp, index);
|
t = build_vtbl_ref (exp, index);
|
||||||
TREE_TYPE (t) = build_pointer_type (tinfo_decl_type);
|
TREE_TYPE (t) = type_info_ptr_type;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise return the type_info for the static type of the expr. */
|
/* Otherwise return the type_info for the static type of the expr. */
|
||||||
exp = get_tinfo_decl (TYPE_MAIN_VARIANT (type));
|
return get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
|
||||||
return build_unary_op (ADDR_EXPR, exp, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -264,9 +303,9 @@ tinfo_name (type)
|
|||||||
return name_string;
|
return name_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a decl for the type_info variable for TYPE. You must
|
/* Return a VAR_DECL for the internal ABI defined type_info object for
|
||||||
arrange that the decl is mark_used, if actually use it --- decls in
|
TYPE. You must arrange that the decl is mark_used, if actually use
|
||||||
vtables are only used if the vtable is output. */
|
it --- decls in vtables are only used if the vtable is output. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
get_tinfo_decl (type)
|
get_tinfo_decl (type)
|
||||||
@ -279,7 +318,7 @@ get_tinfo_decl (type)
|
|||||||
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
|
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
|
||||||
{
|
{
|
||||||
error ("cannot create type information for type `%T' because its size is variable",
|
error ("cannot create type information for type `%T' because its size is variable",
|
||||||
type);
|
type);
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,36 +331,44 @@ get_tinfo_decl (type)
|
|||||||
name = mangle_typeinfo_for_type (type);
|
name = mangle_typeinfo_for_type (type);
|
||||||
|
|
||||||
d = IDENTIFIER_GLOBAL_VALUE (name);
|
d = IDENTIFIER_GLOBAL_VALUE (name);
|
||||||
if (d)
|
if (!d)
|
||||||
/* OK */;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* The tinfo decl is the type_info object itself. We make all
|
tree var_desc = get_pseudo_ti_desc (type);
|
||||||
tinfo objects look as type_info, even though they will end up
|
|
||||||
being a subclass of that when emitted. This means that we'll
|
d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
|
||||||
erroneously think we know the dynamic type -- be careful in the
|
|
||||||
runtime. */
|
|
||||||
d = build_lang_decl (VAR_DECL, name, tinfo_decl_type);
|
|
||||||
|
|
||||||
DECL_ARTIFICIAL (d) = 1;
|
DECL_ARTIFICIAL (d) = 1;
|
||||||
DECL_ALIGN (d) = TYPE_ALIGN (ptr_type_node);
|
|
||||||
DECL_USER_ALIGN (d) = 0;
|
|
||||||
TREE_READONLY (d) = 1;
|
TREE_READONLY (d) = 1;
|
||||||
TREE_STATIC (d) = 1;
|
TREE_STATIC (d) = 1;
|
||||||
DECL_EXTERNAL (d) = 1;
|
DECL_EXTERNAL (d) = 1;
|
||||||
TREE_PUBLIC (d) = 1;
|
|
||||||
SET_DECL_ASSEMBLER_NAME (d, name);
|
SET_DECL_ASSEMBLER_NAME (d, name);
|
||||||
DECL_COMDAT (d) = 1;
|
|
||||||
cp_finish_decl (d, NULL_TREE, NULL_TREE, 0);
|
cp_finish_decl (d, NULL_TREE, NULL_TREE, 0);
|
||||||
|
|
||||||
pushdecl_top_level (d);
|
pushdecl_top_level (d);
|
||||||
|
|
||||||
/* Remember the type it is for. */
|
/* Remember the type it is for. */
|
||||||
TREE_TYPE (name) = type;
|
TREE_TYPE (name) = type;
|
||||||
TREE_USED (name) = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return d;
|
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. */
|
/* Return the type_info object for TYPE. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
@ -350,7 +397,7 @@ get_typeid (type)
|
|||||||
if (!type)
|
if (!type)
|
||||||
return error_mark_node;
|
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
|
/* 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 init = NULL_TREE;
|
||||||
tree name_decl;
|
tree name_decl;
|
||||||
|
tree vtable_ptr;
|
||||||
|
|
||||||
{
|
{
|
||||||
tree name_name;
|
tree name_name;
|
||||||
@ -711,12 +759,41 @@ tinfo_base_init (desc, target)
|
|||||||
cp_finish_decl (name_decl, name_string, NULL_TREE, 0);
|
cp_finish_decl (name_decl, name_string, NULL_TREE, 0);
|
||||||
pushdecl_top_level (name_decl);
|
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);
|
tree real_type;
|
||||||
init = tree_cons (NULL_TREE, vtbl_ptr, init);
|
|
||||||
|
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);
|
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_int_2 (flags, 0), init);
|
||||||
init = tree_cons (NULL_TREE,
|
init = tree_cons (NULL_TREE,
|
||||||
build_unary_op (ADDR_EXPR,
|
get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
|
||||||
get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
|
|
||||||
init);
|
init);
|
||||||
|
|
||||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (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_int_2 (flags, 0), init);
|
||||||
init = tree_cons (NULL_TREE,
|
init = tree_cons (NULL_TREE,
|
||||||
build_unary_op (ADDR_EXPR,
|
get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
|
||||||
get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
|
|
||||||
init);
|
init);
|
||||||
init = tree_cons (NULL_TREE,
|
init = tree_cons (NULL_TREE,
|
||||||
build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
|
get_tinfo_ptr (klass),
|
||||||
init);
|
init);
|
||||||
|
|
||||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
|
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
|
||||||
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
|
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
|
/* Generate the initializer for the type info describing
|
||||||
TARGET_TYPE and corresponding to PUBLIC_DECL. This is the structure expected by
|
TYPE. VAR_DESC is a . NON_PUBLIC_P is set non-zero, if the VAR_DECL
|
||||||
the runtime, and therefore has additional fields. If we need not emit a
|
should not be exported from this object file. This should only be
|
||||||
definition (because the runtime must contain it), return NULL_TREE,
|
called at the end of translation, when we know that no further
|
||||||
otherwise return the VAR_DECL. */
|
types will be completed. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
synthesize_tinfo_var (public_decl)
|
get_pseudo_ti_init (type, var_desc, non_public_p)
|
||||||
tree public_decl;
|
tree type;
|
||||||
|
tree var_desc;
|
||||||
|
int *non_public_p;
|
||||||
{
|
{
|
||||||
tree var_init = NULL_TREE;
|
my_friendly_assert (at_eof, 20021120);
|
||||||
tree var_type = NULL_TREE;
|
switch (TREE_CODE (type))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
case POINTER_TYPE:
|
case POINTER_TYPE:
|
||||||
if (TYPE_PTRMEM_P (target_type))
|
if (TYPE_PTRMEM_P (type))
|
||||||
{
|
return ptm_initializer (var_desc, type, non_public_p);
|
||||||
var_type = ptm_desc_type_node;
|
|
||||||
var_init = ptm_initializer (var_type, target_type, &non_public);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
return ptr_initializer (var_desc, type, non_public_p);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ENUMERAL_TYPE:
|
case ENUMERAL_TYPE:
|
||||||
var_type = enum_desc_type_node;
|
return generic_initializer (var_desc, type);
|
||||||
var_init = generic_initializer (var_type, target_type);
|
|
||||||
break;
|
break;
|
||||||
case FUNCTION_TYPE:
|
case FUNCTION_TYPE:
|
||||||
var_type = func_desc_type_node;
|
return generic_initializer (var_desc, type);
|
||||||
var_init = generic_initializer (var_type, target_type);
|
|
||||||
break;
|
break;
|
||||||
case ARRAY_TYPE:
|
case ARRAY_TYPE:
|
||||||
var_type = ary_desc_type_node;
|
return generic_initializer (var_desc, type);
|
||||||
var_init = generic_initializer (var_type, target_type);
|
|
||||||
break;
|
break;
|
||||||
case UNION_TYPE:
|
case UNION_TYPE:
|
||||||
case RECORD_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;
|
if (!COMPLETE_TYPE_P (type))
|
||||||
var_init = ptm_initializer (var_type, target_type, &non_public);
|
/* Emit a non-public class_type_info. */
|
||||||
}
|
*non_public_p = 1;
|
||||||
else if (!COMPLETE_TYPE_P (target_type))
|
return class_initializer (var_desc, type, NULL_TREE);
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
/* if this has a single public non-virtual base, it's easier */
|
int hint = class_hint_flags (type);
|
||||||
tree binfo = TYPE_BINFO (target_type);
|
tree binfo = TYPE_BINFO (type);
|
||||||
int nbases = BINFO_N_BASETYPES (binfo);
|
int nbases = BINFO_N_BASETYPES (binfo);
|
||||||
tree base_binfos = BINFO_BASETYPES (binfo);
|
tree base_binfos = BINFO_BASETYPES (binfo);
|
||||||
tree base_inits = NULL_TREE;
|
tree base_inits = NULL_TREE;
|
||||||
int is_simple = nbases == 1;
|
|
||||||
int ix;
|
int ix;
|
||||||
|
|
||||||
/* Generate the base information initializer. */
|
/* Generate the base information initializer. */
|
||||||
@ -1017,28 +1074,19 @@ synthesize_tinfo_var (public_decl)
|
|||||||
|
|
||||||
if (TREE_PUBLIC (base_binfo))
|
if (TREE_PUBLIC (base_binfo))
|
||||||
flags |= 2;
|
flags |= 2;
|
||||||
tinfo = get_tinfo_decl (BINFO_TYPE (base_binfo));
|
tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
|
||||||
tinfo = build_unary_op (ADDR_EXPR, tinfo, 0);
|
|
||||||
if (TREE_VIA_VIRTUAL (base_binfo))
|
if (TREE_VIA_VIRTUAL (base_binfo))
|
||||||
{
|
{
|
||||||
/* We store the vtable offset at which the virtual
|
/* We store the vtable offset at which the virtual
|
||||||
base offset can be found. */
|
base offset can be found. */
|
||||||
offset = BINFO_VPTR_FIELD (binfo_for_vbase (BINFO_TYPE (base_binfo),
|
offset = BINFO_VPTR_FIELD
|
||||||
target_type));
|
(binfo_for_vbase (BINFO_TYPE (base_binfo), type));
|
||||||
offset = convert (sizetype, offset);
|
offset = convert (sizetype, offset);
|
||||||
flags |= 1;
|
flags |= 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
offset = BINFO_OFFSET (base_binfo);
|
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 */
|
/* combine offset and flags into one field */
|
||||||
offset = cp_build_binary_op (LSHIFT_EXPR, offset,
|
offset = cp_build_binary_op (LSHIFT_EXPR, offset,
|
||||||
build_int_2 (8, 0));
|
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_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
|
||||||
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
|
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
|
||||||
}
|
}
|
||||||
|
base_inits = build (CONSTRUCTOR,
|
||||||
if (is_simple)
|
NULL_TREE, NULL_TREE, base_inits);
|
||||||
var_type = si_class_desc_type_node;
|
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
|
||||||
else
|
/* Prepend the number of bases. */
|
||||||
{
|
base_inits = tree_cons (NULL_TREE,
|
||||||
int hint = class_hint_flags (target_type);
|
build_int_2 (nbases, 0), base_inits);
|
||||||
|
/* Prepend the hint flags. */
|
||||||
base_inits = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_inits);
|
base_inits = tree_cons (NULL_TREE,
|
||||||
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
|
build_int_2 (hint, 0), base_inits);
|
||||||
/* Prepend the number of bases. */
|
|
||||||
base_inits = tree_cons (NULL_TREE,
|
return class_initializer (var_desc, type, base_inits);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (typeinfo_in_lib_p (target_type))
|
return generic_initializer (var_desc, 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 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
|
/* 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
|
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,
|
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
|
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
|
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
|
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
|
static tree
|
||||||
create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
|
create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
|
||||||
{
|
{
|
||||||
tree real_type, pseudo_type;
|
tree pseudo_type;
|
||||||
char *pseudo_name;
|
char *pseudo_name;
|
||||||
tree vtable_decl;
|
|
||||||
int ix;
|
int ix;
|
||||||
tree fields[10];
|
tree fields[10];
|
||||||
tree field_decl;
|
tree field_decl;
|
||||||
@ -1167,29 +1152,6 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
|
|||||||
if (ident)
|
if (ident)
|
||||||
sprintf (pseudo_name + strlen (pseudo_name), "%d", 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. */
|
/* First field is the pseudo type_info base class. */
|
||||||
fields[0] = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
|
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;
|
TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
|
||||||
|
|
||||||
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
|
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
|
||||||
TINFO_VTABLE_DECL (result) = vtable_decl;
|
TINFO_REAL_NAME (result) = get_identifier (real_name);
|
||||||
TINFO_PSEUDO_TYPE (result) = pseudo_type;
|
TINFO_PSEUDO_TYPE (result) =
|
||||||
|
cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
|
||||||
|
|
||||||
VA_CLOSE (ap);
|
VA_CLOSE (ap);
|
||||||
return result;
|
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
|
static tree
|
||||||
get_vmi_pseudo_type_info (num_bases)
|
get_pseudo_ti_desc (type)
|
||||||
int num_bases;
|
tree type;
|
||||||
{
|
{
|
||||||
tree desc;
|
switch (TREE_CODE (type))
|
||||||
tree array_domain, base_array;
|
|
||||||
|
|
||||||
if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
|
|
||||||
{
|
{
|
||||||
int ix;
|
case POINTER_TYPE:
|
||||||
tree extend = make_tree_vec (num_bases + 5);
|
return TYPE_PTRMEM_P (type) ? ptm_desc_type_node : ptr_desc_type_node;
|
||||||
|
case ENUMERAL_TYPE:
|
||||||
for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
|
return enum_desc_type_node;
|
||||||
TREE_VEC_ELT (extend, ix) = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
|
case FUNCTION_TYPE:
|
||||||
vmi_class_desc_type_node = extend;
|
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
|
/* 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
|
static void
|
||||||
create_tinfo_types ()
|
create_tinfo_types ()
|
||||||
{
|
{
|
||||||
tree ptr_type_info;
|
my_friendly_assert (!ti_desc_type_node, 20020609);
|
||||||
|
|
||||||
if (bltn_desc_type_node)
|
|
||||||
return;
|
|
||||||
push_nested_namespace (abi_node);
|
|
||||||
|
|
||||||
ptr_type_info = build_pointer_type
|
push_nested_namespace (abi_node);
|
||||||
(build_qualified_type
|
|
||||||
(type_info_type_node, TYPE_QUAL_CONST));
|
|
||||||
|
|
||||||
/* Create the internal type_info structure. This is used as a base for
|
/* Create the internal type_info structure. This is used as a base for
|
||||||
the other structures. */
|
the other structures. */
|
||||||
@ -1306,7 +1305,7 @@ create_tinfo_types ()
|
|||||||
This is really a descendant of __class_type_info. */
|
This is really a descendant of __class_type_info. */
|
||||||
si_class_desc_type_node = create_pseudo_type_info
|
si_class_desc_type_node = create_pseudo_type_info
|
||||||
("__si_class_type_info", 0,
|
("__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);
|
NULL);
|
||||||
|
|
||||||
/* Base class internal helper. Pointer to base type, offset to base,
|
/* Base class internal helper. Pointer to base type, offset to base,
|
||||||
@ -1314,7 +1313,7 @@ create_tinfo_types ()
|
|||||||
{
|
{
|
||||||
tree fields[2];
|
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]);
|
fields[1] = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
|
||||||
base_desc_type_node = make_aggr_type (RECORD_TYPE);
|
base_desc_type_node = make_aggr_type (RECORD_TYPE);
|
||||||
finish_builtin_type (base_desc_type_node, "__base_class_type_info_pseudo",
|
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
|
ptr_desc_type_node = create_pseudo_type_info
|
||||||
("__pointer_type_info", 0,
|
("__pointer_type_info", 0,
|
||||||
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
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);
|
NULL);
|
||||||
|
|
||||||
/* Pointer to member data type_info. Add qualifications flags,
|
/* Pointer to member data type_info. Add qualifications flags,
|
||||||
@ -1340,8 +1339,8 @@ create_tinfo_types ()
|
|||||||
ptm_desc_type_node = create_pseudo_type_info
|
ptm_desc_type_node = create_pseudo_type_info
|
||||||
("__pointer_to_member_type_info", 0,
|
("__pointer_to_member_type_info", 0,
|
||||||
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
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),
|
||||||
build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
pop_nested_namespace (abi_node);
|
pop_nested_namespace (abi_node);
|
||||||
@ -1410,72 +1409,59 @@ emit_support_tinfos ()
|
|||||||
definition emitted for it. */
|
definition emitted for it. */
|
||||||
|
|
||||||
int
|
int
|
||||||
tinfo_decl_p (t, data)
|
unemitted_tinfo_decl_p (t, data)
|
||||||
tree t;
|
tree t;
|
||||||
void *data ATTRIBUTE_UNUSED;
|
void *data ATTRIBUTE_UNUSED;
|
||||||
{
|
{
|
||||||
return TREE_CODE (t) == VAR_DECL
|
if (/* It's a var decl */
|
||||||
&& IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == (t)
|
TREE_CODE (t) == VAR_DECL
|
||||||
&& TREE_TYPE (t) == tinfo_decl_type
|
/* whos name points back to itself */
|
||||||
&& TREE_TYPE (DECL_NAME (t));
|
&& 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
|
/* Finish a type info decl. DECL_PTR is a pointer to an unemitted
|
||||||
DECL_PTR. We emit a completely new variable, of the correct type for the
|
tinfo decl. Determine whether it needs emitting, and if so
|
||||||
actual type this is describing. The DECL_ASSEMBLER_NAME of the generated
|
generate the initializer. */
|
||||||
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. */
|
|
||||||
|
|
||||||
int
|
int
|
||||||
emit_tinfo_decl (decl_ptr, data)
|
emit_tinfo_decl (decl_ptr, data)
|
||||||
tree *decl_ptr;
|
tree *decl_ptr;
|
||||||
void *data ATTRIBUTE_UNUSED;
|
void *data ATTRIBUTE_UNUSED;
|
||||||
{
|
{
|
||||||
tree tinfo_decl = *decl_ptr;
|
tree decl = *decl_ptr;
|
||||||
tree decl;
|
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_tinfo (decl, type);
|
||||||
|
if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))
|
||||||
import_export_decl (tinfo_decl);
|
|
||||||
if (DECL_REALLY_EXTERN (tinfo_decl) || !DECL_NEEDED_P (tinfo_decl))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
create_tinfo_types ();
|
if (!doing_runtime && typeinfo_in_lib_p (type))
|
||||||
decl = synthesize_tinfo_var (tinfo_decl);
|
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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user