/* RunTime Type Identification
Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006
+ 2005, 2006, 2007
Free Software Foundation, Inc.
Mostly written by Jason Merrill (jason@cygnus.com).
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "assert.h"
#include "toplev.h"
#include "convert.h"
+#include "target.h"
/* C++ returns type information to the user in struct type_info
objects. We also use type information to implement dynamic_cast and
typedef enum tinfo_kind
{
- TK_TYPE_INFO_TYPE, /* std::type_info */
+ TK_TYPE_INFO_TYPE, /* abi::__type_info_pseudo */
TK_BASE_TYPE, /* abi::__base_class_type_info */
TK_BUILTIN_TYPE, /* abi::__fundamental_type_info */
TK_ARRAY_TYPE, /* abi::__array_type_info */
TK_POINTER_MEMBER_TYPE, /* abi::__pointer_to_member_type_info */
TK_CLASS_TYPE, /* abi::__class_type_info */
TK_SI_CLASS_TYPE, /* abi::__si_class_type_info */
- TK_FIXED /* end of fixed descriptors. */
- /* ... abi::__vmi_type_info<I> */
+ TK_FIXED /* end of fixed descriptors. */
+ /* ... abi::__vmi_type_info<I> */
} tinfo_kind;
/* A vector of all tinfo decls that haven't yet been emitted. */
and are generated as needed. */
static GTY (()) VEC(tinfo_s,gc) *tinfo_descs;
-static tree build_headof (tree);
static tree ifnonnull (tree, tree);
static tree tinfo_name (tree);
static tree build_dynamic_cast_1 (tree, tree);
virtual functions (TYPE_POLYMORPHIC_P), else just return the
expression. */
-static tree
+tree
build_headof (tree exp)
{
tree type = TREE_TYPE (exp);
type = build_qualified_type (ptr_type_node,
cp_type_quals (TREE_TYPE (exp)));
- return build2 (PLUS_EXPR, type, exp,
- convert_to_integer (ptrdiff_type_node, offset));
+ return build2 (POINTER_PLUS_EXPR, type, exp,
+ convert_to_integer (sizetype, offset));
}
/* Get a bad_cast node for the program to throw...
fn = push_throw_library_fn (fn, build_function_type (ptr_type_node,
void_list_node));
- return build_cxx_call (fn, NULL_TREE);
+ return build_cxx_call (fn, 0, NULL);
}
/* Return an expression for "__cxa_bad_typeid()". The expression
fn = push_throw_library_fn (fn, t);
}
- return build_cxx_call (fn, NULL_TREE);
+ return build_cxx_call (fn, 0, NULL);
}
\f
/* Return an lvalue expression whose type is "const std::type_info"
tree type;
tree t;
- if (exp == error_mark_node)
+ if (error_operand_p (exp))
return error_mark_node;
/* peel back references, so they match. */
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
- if (!VOID_TYPE_P (type))
+ if (CLASS_TYPE_P (type))
type = complete_type_or_else (type, exp);
if (!type)
static bool
typeid_ok_p (void)
{
+ tree pseudo_type_info, type_info_type;
+
if (! flag_rtti)
{
error ("cannot use typeid with -fno-rtti");
return false;
}
+ pseudo_type_info
+ = VEC_index (tinfo_s, tinfo_descs, TK_TYPE_INFO_TYPE)->type;
+ type_info_type = TYPE_MAIN_VARIANT (const_type_info_type_node);
+
+ /* Make sure abi::__type_info_pseudo has the same alias set
+ as std::type_info. */
+ if (! TYPE_ALIAS_SET_KNOWN_P (pseudo_type_info))
+ TYPE_ALIAS_SET (pseudo_type_info) = get_alias_set (type_info_type);
+ else
+ gcc_assert (TYPE_ALIAS_SET (pseudo_type_info)
+ == get_alias_set (type_info_type));
+
return true;
}
tree name;
tree d;
- if (COMPLETE_TYPE_P (type)
- && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ if (variably_modified_type_p (type, /*fn=*/NULL_TREE))
{
error ("cannot create type information for type %qT because "
- "its size is variable",
+ "it involves types of variable size",
type);
return error_mark_node;
}
define it later if we need to do so. */
DECL_EXTERNAL (d) = 1;
DECL_NOT_REALLY_EXTERN (d) = 1;
+ set_linkage_according_to_type (type, d);
+
+ d = pushdecl_top_level_and_finish (d, NULL_TREE);
if (CLASS_TYPE_P (type))
CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
- set_linkage_according_to_type (type, d);
- pushdecl_top_level_and_finish (d, NULL_TREE);
/* Add decl to the global array of tinfo decls. */
VEC_safe_push (tree, gc, unemitted_tinfo_decls, d);
that is the operand of typeid are always ignored. */
type = TYPE_MAIN_VARIANT (type);
- if (!VOID_TYPE_P (type))
+ if (CLASS_TYPE_P (type))
type = complete_type_or_else (type, NULL_TREE);
if (!type)
tree old_expr = expr;
const char *errstr = NULL;
+ /* Save casted types in the function's used types hash table. */
+ used_types_insert (type);
+
/* T shall be a pointer or reference to a complete class type, or
`pointer to cv void''. */
switch (tc)
}
else
{
- /* Apply trivial conversion T -> T& for dereferenced ptrs. */
exprtype = build_reference_type (exprtype);
- expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
- LOOKUP_NORMAL, NULL_TREE);
/* T is a reference type, v shall be an lvalue of a complete class
type, and the result is an lvalue of the type referred to by T. */
goto fail;
}
+ /* Apply trivial conversion T -> T& for dereferenced ptrs. */
+ expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
+ LOOKUP_NORMAL, NULL_TREE);
}
/* The dynamic_cast operator shall not cast away constness. */
else
{
tree retval;
- tree result, td2, td3, elems;
+ tree result, td2, td3;
+ tree elems[4];
tree static_type, target_type, boff;
/* If we got here, we can't convert statically. Therefore,
}
}
+ /* Use of dynamic_cast when -fno-rtti is prohibited. */
+ if (!flag_rtti)
+ {
+ error ("%<dynamic_cast%> not permitted with -fno-rtti");
+ return error_mark_node;
+ }
+
target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
td2 = get_tinfo_decl (target_type);
if (tc == REFERENCE_TYPE)
expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
- elems = tree_cons
- (NULL_TREE, expr1, tree_cons
- (NULL_TREE, td3, tree_cons
- (NULL_TREE, td2, tree_cons
- (NULL_TREE, boff, NULL_TREE))));
+ elems[0] = expr1;
+ elems[1] = td3;
+ elems[2] = td2;
+ elems[3] = boff;
dcast_fn = dynamic_cast_node;
if (!dcast_fn)
pop_nested_namespace (ns);
dynamic_cast_node = dcast_fn;
}
- result = build_cxx_call (dcast_fn, elems);
+ result = build_cxx_call (dcast_fn, 4, elems);
if (tc == REFERENCE_TYPE)
{
tree bad = throw_bad_cast ();
+ tree neq;
result = save_expr (result);
- return build3 (COND_EXPR, type, result, result, bad);
+ neq = c_common_truthvalue_conversion (result);
+ return build3 (COND_EXPR, type, neq, result, bad);
}
/* Now back to the type we want from a void*. */
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
- /* Use of dynamic_cast when -fno-rtti is prohibited. */
- if (!flag_rtti)
- {
- error ("%<dynamic_cast%> not permitted with -fno-rtti");
- return error_mark_node;
- }
-
if (processing_template_decl)
{
expr = build_min (DYNAMIC_CAST_EXPR, type, expr);
TREE_SIDE_EFFECTS (expr) = 1;
-
- return expr;
+ return convert_from_reference (expr);
}
return convert_from_reference (build_dynamic_cast_1 (type, expr));
TREE_STATIC (name_decl) = 1;
DECL_EXTERNAL (name_decl) = 0;
DECL_TINFO_P (name_decl) = 1;
- if (involves_incomplete_p (target))
- {
- TREE_PUBLIC (name_decl) = 0;
- DECL_INTERFACE_KNOWN (name_decl) = 1;
- }
- else
- set_linkage_according_to_type (target, name_decl);
+ set_linkage_according_to_type (target, name_decl);
import_export_decl (name_decl);
DECL_INITIAL (name_decl) = name_string;
mark_used (name_decl);
/* We need to point into the middle of the vtable. */
vtable_ptr = build2
- (PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,
+ (POINTER_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)));
-
+
ti->vtable = vtable_ptr;
}
generic_initializer (tinfo_s *ti, tree target)
{
tree init = tinfo_base_init (ti, target);
-
+
init = build_constructor_from_list (NULL_TREE, init);
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
init = tree_cons (NULL_TREE,
get_tinfo_ptr (klass),
init);
-
+
init = build_constructor_from_list (NULL_TREE, nreverse (init));
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
get_pseudo_ti_init (tree type, unsigned tk_index)
{
tinfo_s *ti = VEC_index (tinfo_s, tinfo_descs, tk_index);
-
+
gcc_assert (at_eof);
switch (tk_index)
{
case TK_POINTER_MEMBER_TYPE:
return ptm_initializer (ti, type);
-
+
case TK_POINTER_TYPE:
return ptr_initializer (ti, type);
-
+
case TK_BUILTIN_TYPE:
case TK_ENUMERAL_TYPE:
case TK_FUNCTION_TYPE:
tree binfo = TYPE_BINFO (type);
int nbases = BINFO_N_BASE_BINFOS (binfo);
VEC(tree,gc) *base_accesses = BINFO_BASE_ACCESSES (binfo);
+ tree offset_type = integer_types[itk_long];
tree base_inits = NULL_TREE;
int ix;
-
+
gcc_assert (tk_index >= TK_FIXED);
-
+
/* Generate the base information initializer. */
for (ix = nbases; ix--;)
{
int flags = 0;
tree tinfo;
tree offset;
-
+
if (VEC_index (tree, base_accesses, ix) == access_public_node)
flags |= 2;
tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
if (BINFO_VIRTUAL_P (base_binfo))
{
/* We store the vtable offset at which the virtual
- base offset can be found. */
+ base offset can be found. */
offset = BINFO_VPTR_FIELD (base_binfo);
- offset = convert (sizetype, offset);
flags |= 1;
}
else
offset = BINFO_OFFSET (base_binfo);
-
+
/* Combine offset and flags into one field. */
- offset = cp_build_binary_op (LSHIFT_EXPR, offset,
- build_int_cst (NULL_TREE, 8));
- offset = cp_build_binary_op (BIT_IOR_EXPR, offset,
- build_int_cst (NULL_TREE, flags));
+ offset = fold_convert (offset_type, offset);
+ offset = fold_build2 (LSHIFT_EXPR, offset_type, offset,
+ build_int_cst (offset_type, 8));
+ offset = fold_build2 (BIT_IOR_EXPR, offset_type, offset,
+ build_int_cst (offset_type, flags));
base_init = tree_cons (NULL_TREE, offset, base_init);
base_init = tree_cons (NULL_TREE, tinfo, base_init);
base_init = build_constructor_from_list (NULL_TREE, base_init);
ti->name = get_identifier (real_name);
ti->vtable = NULL_TREE;
+ /* Pretend this is public so determine_visibility doesn't give vtables
+ internal linkage. */
+ TREE_PUBLIC (TYPE_MAIN_DECL (ti->type)) = 1;
+
va_end (ap);
}
get_pseudo_ti_index (tree type)
{
unsigned ix;
-
+
switch (TREE_CODE (type))
{
case OFFSET_TYPE:
ix = TK_POINTER_MEMBER_TYPE;
break;
-
+
case POINTER_TYPE:
ix = TK_POINTER_TYPE;
break;
-
+
case ENUMERAL_TYPE:
ix = TK_ENUMERAL_TYPE;
break;
-
+
case FUNCTION_TYPE:
ix = TK_FUNCTION_TYPE;
break;
-
+
case ARRAY_TYPE:
ix = TK_ARRAY_TYPE;
break;
-
+
case UNION_TYPE:
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
{
/* too short, extend. */
unsigned len = VEC_length (tinfo_s, tinfo_descs);
-
+
VEC_safe_grow (tinfo_s, gc, tinfo_descs, ix + 1);
while (VEC_iterate (tinfo_s, tinfo_descs, len++, ti))
ti->type = ti->vtable = ti->name = NULL_TREE;
create_tinfo_types (void)
{
tinfo_s *ti;
-
+
gcc_assert (!tinfo_descs);
VEC_safe_grow (tinfo_s, gc, tinfo_descs, TK_FIXED);
-
+
push_nested_namespace (abi_node);
/* Create the internal type_info structure. This is used as a base for
create_pseudo_type_info (TK_ARRAY_TYPE, "__array_type_info", NULL);
create_pseudo_type_info (TK_FUNCTION_TYPE, "__function_type_info", NULL);
create_pseudo_type_info (TK_ENUMERAL_TYPE, "__enum_type_info", NULL);
-
+
/* Class type_info. No additional fields. */
create_pseudo_type_info (TK_CLASS_TYPE, "__class_type_info", NULL);
-
- /* Single public non-virtual base class. Add pointer to base class.
+
+ /* Single public non-virtual base class. Add pointer to base class.
This is really a descendant of __class_type_info. */
create_pseudo_type_info (TK_SI_CLASS_TYPE, "__si_class_type_info",
- build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
- NULL);
+ build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
+ NULL);
/* Base class internal helper. Pointer to base type, offset to base,
flags. */
field = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
TREE_CHAIN (field) = fields;
fields = field;
-
+
ti = VEC_index (tinfo_s, tinfo_descs, TK_BASE_TYPE);
-
+
ti->type = make_aggr_type (RECORD_TYPE);
ti->vtable = NULL_TREE;
ti->name = NULL_TREE;
This is really a descendant of __pbase_type_info. */
create_pseudo_type_info (TK_POINTER_MEMBER_TYPE,
"__pointer_to_member_type_info",
- build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
- build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
- build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
- NULL);
+ build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
+ 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);
}
comdat_linkage for details.) Since we want these objects
to have external linkage so that copies do not have to be
emitted in code outside the runtime library, we make them
- non-COMDAT here. */
- if (!flag_weak)
+ non-COMDAT here.
+
+ It might also not be necessary to follow this detail of the
+ ABI. */
+ if (!flag_weak || ! targetm.cxx.library_rtti_comdat ())
{
gcc_assert (TREE_PUBLIC (tinfo) && !DECL_COMDAT (tinfo));
DECL_INTERFACE_KNOWN (tinfo) = 1;
if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))
{
tree init;
-
+
DECL_EXTERNAL (decl) = 0;
init = get_pseudo_ti_init (type, get_pseudo_ti_index (type));
DECL_INITIAL (decl) = init;
mark_used (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0);
+ finish_decl (decl, init, NULL_TREE);
return true;
}
else