/* Functions related to building classes and their related objects.
Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
+ Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
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/>. */
/* High-level class interface. */
static int resort_method_name_cmp (const void *, const void *);
static void add_implicitly_declared_members (tree, int, int);
static tree fixed_type_or_null (tree, int *, int *);
-static tree resolve_address_of_overloaded_function (tree, tree, tsubst_flags_t,
- bool, tree);
static tree build_simple_base_path (tree expr, tree binfo);
static tree build_vtbl_ref_1 (tree, tree);
static tree build_vtbl_initializer (tree, tree, tree, tree, int *);
static int count_fields (tree);
static int add_fields_to_record_type (tree, struct sorted_fields_type*, int);
-static void check_bitfield_decl (tree);
+static bool check_bitfield_decl (tree);
static void check_field_decl (tree, tree, int *, int *, int *);
static void check_field_decls (tree, tree *, int *, int *);
static tree *build_base_field (record_layout_info, tree, splay_tree, tree *);
static void layout_nonempty_base_or_field (record_layout_info,
tree, tree, splay_tree);
static tree end_of_class (tree, int);
-static bool layout_empty_base (tree, tree, splay_tree);
+static bool layout_empty_base (record_layout_info, tree, tree, splay_tree);
static void accumulate_vtbl_inits (tree, tree, tree, tree, tree);
static tree dfs_accumulate_vtbl_inits (tree, tree, tree, tree,
tree);
field, because other parts of the compiler know that such
expressions are always non-NULL. */
if (!virtual_access && integer_zerop (offset))
- return build_nop (build_pointer_type (target_type), expr);
+ {
+ tree class_type;
+ /* TARGET_TYPE has been extracted from BINFO, and, is
+ therefore always cv-unqualified. Extract the
+ cv-qualifiers from EXPR so that the expression returned
+ matches the input. */
+ class_type = TREE_TYPE (TREE_TYPE (expr));
+ target_type
+ = cp_build_qualified_type (target_type,
+ cp_type_quals (class_type));
+ return build_nop (build_pointer_type (target_type), expr);
+ }
null_test = error_mark_node;
}
v_offset = build_vfield_ref (build_indirect_ref (expr, NULL),
TREE_TYPE (TREE_TYPE (expr)));
- v_offset = build2 (PLUS_EXPR, TREE_TYPE (v_offset),
- v_offset, BINFO_VPTR_FIELD (v_binfo));
+ v_offset = build2 (POINTER_PLUS_EXPR, TREE_TYPE (v_offset),
+ v_offset, fold_convert (sizetype, BINFO_VPTR_FIELD (v_binfo)));
v_offset = build1 (NOP_EXPR,
build_pointer_type (ptrdiff_type_node),
v_offset);
expr = build1 (NOP_EXPR, ptr_target_type, expr);
if (!integer_zerop (offset))
- expr = build2 (code, ptr_target_type, expr, offset);
+ {
+ offset = fold_convert (sizetype, offset);
+ if (code == MINUS_EXPR)
+ offset = fold_build1 (NEGATE_EXPR, sizetype, offset);
+ expr = build2 (POINTER_PLUS_EXPR, ptr_target_type, expr, offset);
+ }
else
null_test = NULL;
/* Transform `(a, b).x' into `(*(a, &b)).x', `(a ? b : c).x'
into `(*(a ? &b : &c)).x', and so on. A COND_EXPR is only
- an lvalue in the frontend; only _DECLs and _REFs are lvalues
- in the backend. */
+ an lvalue in the front end; only _DECLs and _REFs are lvalues
+ in the back end. */
temp = unary_complex_lvalue (ADDR_EXPR, expr);
if (temp)
expr = build_indirect_ref (temp, NULL);
tree pointer_type;
pointer_type = build_pointer_type (expr_type);
+
+ /* We use fold_build2 and fold_convert below to simplify the trees
+ provided to the optimizers. It is not safe to call these functions
+ when processing a template because they do not handle C++-specific
+ trees. */
+ gcc_assert (!processing_template_decl);
expr = build_unary_op (ADDR_EXPR, expr, /*noconvert=*/1);
if (!integer_zerop (BINFO_OFFSET (base)))
- expr = build2 (PLUS_EXPR, pointer_type, expr,
- build_nop (pointer_type, BINFO_OFFSET (base)));
- expr = build_nop (build_pointer_type (BINFO_TYPE (base)), expr);
- expr = build1 (INDIRECT_REF, BINFO_TYPE (base), expr);
+ expr = fold_build2 (POINTER_PLUS_EXPR, pointer_type, expr,
+ fold_convert (sizetype, BINFO_OFFSET (base)));
+ expr = fold_convert (build_pointer_type (BINFO_TYPE (base)), expr);
+ expr = build_fold_indirect_ref (expr);
}
return expr;
bool complete_p;
bool insert_p = false;
tree current_fns;
+ tree fns;
if (method == error_mark_node)
return false;
}
current_fns = insert_p ? NULL_TREE : VEC_index (tree, method_vec, slot);
- if (processing_template_decl)
- /* TYPE is a template class. Don't issue any errors now; wait
- until instantiation time to complain. */
- ;
- else
+ /* Check to see if we've already got this method. */
+ for (fns = current_fns; fns; fns = OVL_NEXT (fns))
{
- tree fns;
-
- /* Check to see if we've already got this method. */
- for (fns = current_fns; fns; fns = OVL_NEXT (fns))
- {
- tree fn = OVL_CURRENT (fns);
- tree fn_type;
- tree method_type;
- tree parms1;
- tree parms2;
+ tree fn = OVL_CURRENT (fns);
+ tree fn_type;
+ tree method_type;
+ tree parms1;
+ tree parms2;
- if (TREE_CODE (fn) != TREE_CODE (method))
- continue;
+ if (TREE_CODE (fn) != TREE_CODE (method))
+ continue;
- /* [over.load] Member function declarations with the
- same name and the same parameter types cannot be
- overloaded if any of them is a static member
- function declaration.
-
- [namespace.udecl] When a using-declaration brings names
- from a base class into a derived class scope, member
- functions in the derived class override and/or hide member
- functions with the same name and parameter types in a base
- class (rather than conflicting). */
- fn_type = TREE_TYPE (fn);
- method_type = TREE_TYPE (method);
- parms1 = TYPE_ARG_TYPES (fn_type);
- parms2 = TYPE_ARG_TYPES (method_type);
-
- /* Compare the quals on the 'this' parm. Don't compare
- the whole types, as used functions are treated as
- coming from the using class in overload resolution. */
- if (! DECL_STATIC_FUNCTION_P (fn)
- && ! DECL_STATIC_FUNCTION_P (method)
- && (TYPE_QUALS (TREE_TYPE (TREE_VALUE (parms1)))
- != TYPE_QUALS (TREE_TYPE (TREE_VALUE (parms2)))))
- continue;
+ /* [over.load] Member function declarations with the
+ same name and the same parameter types cannot be
+ overloaded if any of them is a static member
+ function declaration.
+
+ [namespace.udecl] When a using-declaration brings names
+ from a base class into a derived class scope, member
+ functions in the derived class override and/or hide member
+ functions with the same name and parameter types in a base
+ class (rather than conflicting). */
+ fn_type = TREE_TYPE (fn);
+ method_type = TREE_TYPE (method);
+ parms1 = TYPE_ARG_TYPES (fn_type);
+ parms2 = TYPE_ARG_TYPES (method_type);
+
+ /* Compare the quals on the 'this' parm. Don't compare
+ the whole types, as used functions are treated as
+ coming from the using class in overload resolution. */
+ if (! DECL_STATIC_FUNCTION_P (fn)
+ && ! DECL_STATIC_FUNCTION_P (method)
+ && (TYPE_QUALS (TREE_TYPE (TREE_VALUE (parms1)))
+ != TYPE_QUALS (TREE_TYPE (TREE_VALUE (parms2)))))
+ continue;
- /* For templates, the return type and template parameters
- must be identical. */
- if (TREE_CODE (fn) == TEMPLATE_DECL
- && (!same_type_p (TREE_TYPE (fn_type),
- TREE_TYPE (method_type))
- || !comp_template_parms (DECL_TEMPLATE_PARMS (fn),
- DECL_TEMPLATE_PARMS (method))))
- continue;
+ /* For templates, the return type and template parameters
+ must be identical. */
+ if (TREE_CODE (fn) == TEMPLATE_DECL
+ && (!same_type_p (TREE_TYPE (fn_type),
+ TREE_TYPE (method_type))
+ || !comp_template_parms (DECL_TEMPLATE_PARMS (fn),
+ DECL_TEMPLATE_PARMS (method))))
+ continue;
- if (! DECL_STATIC_FUNCTION_P (fn))
- parms1 = TREE_CHAIN (parms1);
- if (! DECL_STATIC_FUNCTION_P (method))
- parms2 = TREE_CHAIN (parms2);
+ if (! DECL_STATIC_FUNCTION_P (fn))
+ parms1 = TREE_CHAIN (parms1);
+ if (! DECL_STATIC_FUNCTION_P (method))
+ parms2 = TREE_CHAIN (parms2);
- if (compparms (parms1, parms2)
- && (!DECL_CONV_FN_P (fn)
- || same_type_p (TREE_TYPE (fn_type),
- TREE_TYPE (method_type))))
+ if (compparms (parms1, parms2)
+ && (!DECL_CONV_FN_P (fn)
+ || same_type_p (TREE_TYPE (fn_type),
+ TREE_TYPE (method_type))))
+ {
+ if (using_decl)
{
- if (using_decl)
- {
- if (DECL_CONTEXT (fn) == type)
- /* Defer to the local function. */
- return false;
- if (DECL_CONTEXT (fn) == DECL_CONTEXT (method))
- error ("repeated using declaration %q+D", using_decl);
- else
- error ("using declaration %q+D conflicts with a previous using declaration",
- using_decl);
- }
+ if (DECL_CONTEXT (fn) == type)
+ /* Defer to the local function. */
+ return false;
+ if (DECL_CONTEXT (fn) == DECL_CONTEXT (method))
+ error ("repeated using declaration %q+D", using_decl);
else
- {
- error ("%q+#D cannot be overloaded", method);
- error ("with %q+#D", fn);
- }
-
- /* We don't call duplicate_decls here to merge the
- declarations because that will confuse things if the
- methods have inline definitions. In particular, we
- will crash while processing the definitions. */
- return false;
+ error ("using declaration %q+D conflicts with a previous using declaration",
+ using_decl);
}
+ else
+ {
+ error ("%q+#D cannot be overloaded", method);
+ error ("with %q+#D", fn);
+ }
+
+ /* We don't call duplicate_decls here to merge the
+ declarations because that will confuse things if the
+ methods have inline definitions. In particular, we
+ will crash while processing the definitions. */
+ return false;
}
}
- /* A class should never have more than one destructor. */
+ /* A class should never have more than one destructor. */
if (current_fns && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
return false;
if (insert_p)
{
+ bool reallocated;
+
/* We only expect to add few methods in the COMPLETE_P case, so
just make room for one more method in that case. */
- if (VEC_reserve (tree, gc, method_vec, complete_p ? -1 : 1))
+ if (complete_p)
+ reallocated = VEC_reserve_exact (tree, gc, method_vec, 1);
+ else
+ reallocated = VEC_reserve (tree, gc, method_vec, 1);
+ if (reallocated)
CLASSTYPE_METHOD_VEC (type) = method_vec;
if (slot == VEC_length (tree, method_vec))
VEC_quick_push (tree, method_vec, overload);
}
else
{
- perform_or_defer_access_check (TYPE_BINFO (t), fdecl);
+ perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl);
DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
return 1;
}
dtor is handled in finish_struct_1. */
if (!TYPE_POLYMORPHIC_P (basetype))
warning (OPT_Weffc__,
- "base class %q#T has a non-virtual destructor", basetype);
+ "base class %q#T has a non-virtual destructor", basetype);
/* If the base class doesn't have copy constructors or
assignment operators that take const references, then the
TYPE_POLYMORPHIC_P (t) |= TYPE_POLYMORPHIC_P (basetype);
CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t)
|= CLASSTYPE_CONTAINS_EMPTY_CLASS_P (basetype);
+ TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (basetype);
}
}
TYPE_VFIELD (variants) = TYPE_VFIELD (t);
TYPE_METHODS (variants) = TYPE_METHODS (t);
TYPE_FIELDS (variants) = TYPE_FIELDS (t);
- TYPE_SIZE (variants) = TYPE_SIZE (t);
- TYPE_SIZE_UNIT (variants) = TYPE_SIZE_UNIT (t);
+
+ /* All variants of a class have the same attributes. */
+ TYPE_ATTRIBUTES (variants) = TYPE_ATTRIBUTES (t);
}
if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) && TYPE_POLYMORPHIC_P (t))
if (!has_nonprivate_method)
{
warning (OPT_Wctor_dtor_privacy,
- "all member functions in class %qT are private", t);
+ "all member functions in class %qT are private", t);
return;
}
}
if (fn && TREE_PRIVATE (fn))
{
warning (OPT_Wctor_dtor_privacy,
- "%q#T only defines a private destructor and has no friends",
+ "%q#T only defines a private destructor and has no friends",
t);
return;
}
if (nonprivate_ctor == 0)
{
warning (OPT_Wctor_dtor_privacy,
- "%q#T only defines private constructors and has no friends",
+ "%q#T only defines private constructors and has no friends",
t);
return;
}
}
/* Make BINFO's vtable have N entries, including RTTI entries,
- vbase and vcall offsets, etc. Set its type and call the backend
+ vbase and vcall offsets, etc. Set its type and call the back end
to lay it out. */
static void
have the same signature. */
int
-same_signature_p (tree fndecl, tree base_fndecl)
+same_signature_p (const_tree fndecl, const_tree base_fndecl)
{
/* One destructor overrides another if they are the same kind of
destructor. */
fixed_offset, virtual_offset);
}
else
- gcc_assert (!DECL_THUNK_P (fn));
+ gcc_assert (DECL_INVALID_OVERRIDER_P (overrider_target) ||
+ !DECL_THUNK_P (fn));
/* Assume that we will produce a thunk that convert all the way to
the final overrider, and not to an intermediate virtual base. */
while (base_fndecls)
{
/* Here we know it is a hider, and no overrider exists. */
- warning (0, "%q+D was hidden", TREE_VALUE (base_fndecls));
- warning (0, " by %q+D", fns);
+ warning (OPT_Woverloaded_virtual, "%q+D was hidden", TREE_VALUE (base_fndecls));
+ warning (OPT_Woverloaded_virtual, " by %q+D", fns);
base_fndecls = TREE_CHAIN (base_fndecls);
}
}
if (DECL_NAME (field) == NULL_TREE
&& ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
+ bool is_union = TREE_CODE (TREE_TYPE (field)) == UNION_TYPE;
tree elt = TYPE_FIELDS (TREE_TYPE (field));
for (; elt; elt = TREE_CHAIN (elt))
{
if (TREE_CODE (elt) != FIELD_DECL)
{
- pedwarn ("%q+#D invalid; an anonymous union can "
- "only have non-static data members", elt);
+ if (is_union)
+ pedwarn ("%q+#D invalid; an anonymous union can "
+ "only have non-static data members", elt);
+ else
+ pedwarn ("%q+#D invalid; an anonymous struct can "
+ "only have non-static data members", elt);
continue;
}
if (TREE_PRIVATE (elt))
- pedwarn ("private member %q+#D in anonymous union", elt);
+ {
+ if (is_union)
+ pedwarn ("private member %q+#D in anonymous union", elt);
+ else
+ pedwarn ("private member %q+#D in anonymous struct", elt);
+ }
else if (TREE_PROTECTED (elt))
- pedwarn ("protected member %q+#D in anonymous union", elt);
+ {
+ if (is_union)
+ pedwarn ("protected member %q+#D in anonymous union", elt);
+ else
+ pedwarn ("protected member %q+#D in anonymous struct", elt);
+ }
TREE_PRIVATE (elt) = TREE_PRIVATE (field);
TREE_PROTECTED (elt) = TREE_PROTECTED (field);
/* FIELD is a bit-field. We are finishing the processing for its
enclosing type. Issue any appropriate messages and set appropriate
- flags. */
+ flags. Returns false if an error has been diagnosed. */
-static void
+static bool
check_bitfield_decl (tree field)
{
tree type = TREE_TYPE (field);
/* Extract the declared width of the bitfield, which has been
temporarily stashed in DECL_INITIAL. */
w = DECL_INITIAL (field);
- gcc_assert (w != NULL_TREE);
+ gcc_assert (w != NULL_TREE);
/* Remove the bit-field width indicator so that the rest of the
compiler does not treat that value as an initializer. */
DECL_INITIAL (field) = NULL_TREE;
if (!INTEGRAL_TYPE_P (type))
{
error ("bit-field %q+#D with non-integral type", field);
- TREE_TYPE (field) = error_mark_node;
w = error_mark_node;
}
else
{
DECL_SIZE (field) = convert (bitsizetype, w);
DECL_BIT_FIELD (field) = 1;
+ return true;
}
else
{
/* Non-bit-fields are aligned for their type. */
DECL_BIT_FIELD (field) = 0;
CLEAR_DECL_C_BIT_FIELD (field);
+ return false;
}
}
|= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type);
+ TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (type);
}
if (!TYPE_HAS_CONST_INIT_REF (type))
tree *next;
bool has_pointers;
int any_default_members;
+ int cant_pack = 0;
/* Assume there are no access declarations. */
*access_decls = NULL_TREE;
next = &TREE_CHAIN (x);
- if (TREE_CODE (x) == FIELD_DECL)
- {
- if (TYPE_PACKED (t))
- {
- if (!pod_type_p (TREE_TYPE (x)) && !TYPE_PACKED (TREE_TYPE (x)))
- warning
- (0,
- "ignoring packed attribute on unpacked non-POD field %q+#D",
- x);
- else if (TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)
- DECL_PACKED (x) = 1;
- }
-
- if (DECL_C_BIT_FIELD (x) && integer_zerop (DECL_INITIAL (x)))
- /* We don't treat zero-width bitfields as making a class
- non-empty. */
- ;
- else
- {
- tree element_type;
-
- /* The class is non-empty. */
- CLASSTYPE_EMPTY_P (t) = 0;
- /* The class is not even nearly empty. */
- CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
- /* If one of the data members contains an empty class,
- so does T. */
- element_type = strip_array_types (type);
- if (CLASS_TYPE_P (element_type)
- && CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type))
- CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 1;
- }
- }
-
if (TREE_CODE (x) == USING_DECL)
{
/* Prune the access declaration from the list of fields. */
}
}
- /* ``A local class cannot have static data members.'' ARM 9.4 */
- if (current_function_decl && TREE_STATIC (x))
- error ("field %q+D in local class cannot be static", x);
-
/* Perform error checking that did not get done in
grokdeclarator. */
if (TREE_CODE (type) == FUNCTION_TYPE)
type = strip_array_types (type);
+ if (TYPE_PACKED (t))
+ {
+ if (!pod_type_p (type) && !TYPE_PACKED (type))
+ {
+ warning
+ (0,
+ "ignoring packed attribute because of unpacked non-POD field %q+#D",
+ x);
+ cant_pack = 1;
+ }
+ else if (TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT)
+ DECL_PACKED (x) = 1;
+ }
+
+ if (DECL_C_BIT_FIELD (x) && integer_zerop (DECL_INITIAL (x)))
+ /* We don't treat zero-width bitfields as making a class
+ non-empty. */
+ ;
+ else
+ {
+ /* The class is non-empty. */
+ CLASSTYPE_EMPTY_P (t) = 0;
+ /* The class is not even nearly empty. */
+ CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
+ /* If one of the data members contains an empty class,
+ so does T. */
+ if (CLASS_TYPE_P (type)
+ && CLASSTYPE_CONTAINS_EMPTY_CLASS_P (type))
+ CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 1;
+ }
+
/* This is used by -Weffc++ (see below). Warn only for pointers
to members which might hold dynamic memory. So do not warn
for pointers to functions or pointers to members. */
/* We set DECL_C_BIT_FIELD in grokbitfield.
If the type and width are valid, we'll also set DECL_BIT_FIELD. */
- if (DECL_C_BIT_FIELD (x))
- check_bitfield_decl (x);
- else
+ if (! DECL_C_BIT_FIELD (x) || ! check_bitfield_decl (x))
check_field_decl (x, t,
cant_have_const_ctor_p,
no_const_asn_ref_p,
is needed to free dynamic memory.
This seems enough for practical purposes. */
- if (warn_ecpp
- && has_pointers
- && TYPE_HAS_CONSTRUCTOR (t)
- && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
- && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
+ if (warn_ecpp
+ && has_pointers
+ && TYPE_HAS_CONSTRUCTOR (t)
+ && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+ && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
{
warning (OPT_Weffc__, "%q#T has pointer data members", t);
if (! TYPE_HAS_INIT_REF (t))
{
warning (OPT_Weffc__,
- " but does not override %<%T(const %T&)%>", t, t);
+ " but does not override %<%T(const %T&)%>", t, t);
if (!TYPE_HAS_ASSIGN_REF (t))
warning (OPT_Weffc__, " or %<operator=(const %T&)%>", t);
}
else if (! TYPE_HAS_ASSIGN_REF (t))
warning (OPT_Weffc__,
- " but does not override %<operator=(const %T&)%>", t);
+ " but does not override %<operator=(const %T&)%>", t);
}
+ /* If any of the fields couldn't be packed, unset TYPE_PACKED. */
+ if (cant_pack)
+ TYPE_PACKED (t) = 0;
/* Check anonymous struct/anonymous union fields. */
finish_struct_anon (t);
if (type == error_mark_node)
return 0;
-
+
if (!TYPE_P (type))
{
if (abi_version_at_least (2))
other empty classes might later be placed) or at the end of the
class (where other objects might then be placed, so other empty
subobjects might later overlap). */
- if (is_data_member
+ if (is_data_member
|| !is_empty_class (BINFO_TYPE (type)))
max_offset = sizeof_biggest_empty_class;
else
type. Return nonzero iff we added it at the end. */
static bool
-layout_empty_base (tree binfo, tree eoc, splay_tree offsets)
+layout_empty_base (record_layout_info rli, tree binfo,
+ tree eoc, splay_tree offsets)
{
tree alignment;
tree basetype = BINFO_TYPE (binfo);
(binfo, size_diffop (size_zero_node, BINFO_OFFSET (binfo)));
else
warning (OPT_Wabi,
- "offset of empty base %qT may not be ABI-compliant and may"
+ "offset of empty base %qT may not be ABI-compliant and may"
"change in a future version of GCC",
BINFO_TYPE (binfo));
}
propagate_binfo_offsets (binfo, alignment);
}
}
+
+ if (CLASSTYPE_USER_ALIGN (basetype))
+ {
+ rli->record_align = MAX (rli->record_align, CLASSTYPE_ALIGN (basetype));
+ if (warn_packed)
+ rli->unpacked_align = MAX (rli->unpacked_align, CLASSTYPE_ALIGN (basetype));
+ TYPE_USER_ALIGN (rli->t) = 1;
+ }
+
return atend;
}
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
DECL_FIELD_CONTEXT (decl) = t;
- DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
- DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
- DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
- DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
- DECL_MODE (decl) = TYPE_MODE (basetype);
- DECL_FIELD_IS_BASE (decl) = 1;
-
- /* Try to place the field. It may take more than one try if we
- have a hard time placing the field without putting two
- objects of the same type at the same address. */
- layout_nonempty_base_or_field (rli, decl, binfo, offsets);
- /* Add the new FIELD_DECL to the list of fields for T. */
- TREE_CHAIN (decl) = *next_field;
- *next_field = decl;
- next_field = &TREE_CHAIN (decl);
+ if (CLASSTYPE_AS_BASE (basetype))
+ {
+ DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
+ DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
+ DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
+ DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
+ DECL_MODE (decl) = TYPE_MODE (basetype);
+ DECL_FIELD_IS_BASE (decl) = 1;
+
+ /* Try to place the field. It may take more than one try if we
+ have a hard time placing the field without putting two
+ objects of the same type at the same address. */
+ layout_nonempty_base_or_field (rli, decl, binfo, offsets);
+ /* Add the new FIELD_DECL to the list of fields for T. */
+ TREE_CHAIN (decl) = *next_field;
+ *next_field = decl;
+ next_field = &TREE_CHAIN (decl);
+ }
}
else
{
byte-aligned. */
eoc = round_up (rli_size_unit_so_far (rli),
CLASSTYPE_ALIGN_UNIT (basetype));
- atend = layout_empty_base (binfo, eoc, offsets);
+ atend = layout_empty_base (rli, binfo, eoc, offsets);
/* A nearly-empty class "has no proper base class that is empty,
not morally virtual, and at an offset other than zero." */
if (!BINFO_VIRTUAL_P (binfo) && CLASSTYPE_NEARLY_EMPTY_P (t))
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
else
warning (OPT_Wabi,
- "class %qT will be considered nearly empty in a "
+ "class %qT will be considered nearly empty in a "
"future version of GCC", t);
}
}
argument is `size_t', it will be the usual deallocation
function -- unless there is one-argument function, too. */
if (TREE_CHAIN (second_parm) == void_list_node
- && same_type_p (TREE_VALUE (second_parm), sizetype))
+ && same_type_p (TREE_VALUE (second_parm), size_type_node))
has_two_argument_delete_p = true;
}
|| TYPE_HAS_ASSIGN_REF (t));
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);
+ TYPE_HAS_COMPLEX_DFLT (t)
+ |= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
/* Synthesize any needed methods. */
add_implicitly_declared_members (t,
bitsize_unit_node),
BINFO_OFFSET (vbase))))
warning (OPT_Wabi,
- "offset of virtual base %qT is not ABI-compliant and "
+ "offset of virtual base %qT is not ABI-compliant and "
"may change in a future version of GCC",
basetype);
{
tree size;
- if (is_empty_class (BINFO_TYPE (binfo)))
+ if (!CLASSTYPE_AS_BASE (BINFO_TYPE (binfo)))
+ size = TYPE_SIZE_UNIT (char_type_node);
+ else if (is_empty_class (BINFO_TYPE (binfo)))
/* An empty class has zero CLASSTYPE_SIZE_UNIT, but we need to
allocate some space for it. It cannot have virtual bases, so
TYPE_SIZE_UNIT is fine. */
tree padding;
/* We still pass things that aren't non-static data members to
- the back-end, in case it wants to do something with them. */
+ the back end, in case it wants to do something with them. */
if (TREE_CODE (field) != FIELD_DECL)
{
place_field (rli, field);
/* Versions of G++ before G++ 3.4 did not reset the
DECL_MODE. */
warning (OPT_Wabi,
- "the offset of %qD may not be ABI-compliant and may "
+ "the offset of %qD may not be ABI-compliant and may "
"change in a future version of GCC", field);
}
else
/* The middle end uses the type of expressions to determine the
possible range of expression values. In order to optimize
"x.i > 7" to "false" for a 2-bit bitfield "i", the middle end
- must be made aware of the width of "i", via its type.
+ must be made aware of the width of "i", via its type.
- Because C++ does not have integer types of arbitrary width,
+ Because C++ does not have integer types of arbitrary width,
we must (for the purposes of the front end) convert from the
type assigned here to the declared type of the bitfield
whenever a bitfield expression is used as an rvalue.
ftype = TREE_TYPE (field);
width = tree_low_cst (DECL_SIZE (field), /*unsignedp=*/1);
if (width != TYPE_PRECISION (ftype))
- TREE_TYPE (field)
- = c_build_bitfield_integer_type (width,
+ TREE_TYPE (field)
+ = c_build_bitfield_integer_type (width,
TYPE_UNSIGNED (ftype));
}
TYPE_SIZE_UNIT (base_t) = size_zero_node;
if (warn_abi && !integer_zerop (rli_size_unit_so_far (rli)))
warning (OPT_Wabi,
- "layout of classes derived from empty class %qT "
+ "layout of classes derived from empty class %qT "
"may change in a future version of GCC",
t);
}
place_field (rli,
build_decl (FIELD_DECL, NULL_TREE, char_type_node));
- /* Let the back-end lay out the type. */
+ /* Let the back end lay out the type. */
finish_record_layout (rli, /*free_p=*/true);
/* Warn about bases that can't be talked about due to ambiguity. */
splay_tree_delete (empty_base_offsets);
if (CLASSTYPE_EMPTY_P (t)
- && tree_int_cst_lt (sizeof_biggest_empty_class,
+ && tree_int_cst_lt (sizeof_biggest_empty_class,
TYPE_SIZE_UNIT (t)))
sizeof_biggest_empty_class = TYPE_SIZE_UNIT (t);
}
working on. */
for (x = TYPE_FIELDS (t); x; x = TREE_CHAIN (x))
if (TREE_CODE (x) == VAR_DECL && TREE_STATIC (x)
+ && TREE_TYPE (x) != error_mark_node
&& same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (x)), t))
DECL_MODE (x) = TYPE_MODE (t);
DECL_SORTED_FIELDS (TYPE_MAIN_DECL (t)) = field_vec;
}
+ /* Complain if one of the field types requires lower visibility. */
+ constrain_class_visibility (t);
+
/* Make the rtl for any new vtables we have created, and unmark
the base types we marked. */
finish_vtbls (t);
tree dtor;
dtor = CLASSTYPE_DESTRUCTORS (t);
- /* Warn only if the dtor is non-private or the class has
- friends. */
if (/* An implicitly declared destructor is always public. And,
if it were virtual, we would have created it by now. */
!dtor
|| (!DECL_VINDEX (dtor)
- && (!TREE_PRIVATE (dtor)
- || CLASSTYPE_FRIEND_CLASSES (t)
- || DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))))
- warning (0, "%q#T has virtual functions but non-virtual destructor",
- t);
+ && (/* public non-virtual */
+ (!TREE_PRIVATE (dtor) && !TREE_PROTECTED (dtor))
+ || (/* non-public non-virtual with friends */
+ (TREE_PRIVATE (dtor) || TREE_PROTECTED (dtor))
+ && (CLASSTYPE_FRIEND_CLASSES (t)
+ || DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))))))
+ warning (OPT_Wnon_virtual_dtor,
+ "%q#T has virtual functions and accessible"
+ " non-virtual destructor", t);
}
complete_vars (t);
before this function is called. */
static tree
-fixed_type_or_null (tree instance, int* nonnull, int* cdtorp)
+fixed_type_or_null (tree instance, int *nonnull, int *cdtorp)
{
+#define RECUR(T) fixed_type_or_null((T), nonnull, cdtorp)
+
switch (TREE_CODE (instance))
{
case INDIRECT_REF:
if (POINTER_TYPE_P (TREE_TYPE (instance)))
return NULL_TREE;
else
- return fixed_type_or_null (TREE_OPERAND (instance, 0),
- nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
case CALL_EXPR:
/* This is a call to a constructor, hence it's never zero. */
*nonnull = 1;
return TREE_TYPE (instance);
}
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
+ case POINTER_PLUS_EXPR:
case PLUS_EXPR:
case MINUS_EXPR:
if (TREE_CODE (TREE_OPERAND (instance, 0)) == ADDR_EXPR)
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
if (TREE_CODE (TREE_OPERAND (instance, 1)) == INTEGER_CST)
/* Propagate nonnull. */
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
+
return NULL_TREE;
case NOP_EXPR:
case CONVERT_EXPR:
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
case ADDR_EXPR:
instance = TREE_OPERAND (instance, 0);
if (t && DECL_P (t))
*nonnull = 1;
}
- return fixed_type_or_null (instance, nonnull, cdtorp);
+ return RECUR (instance);
case COMPONENT_REF:
/* If this component is really a base class reference, then the field
itself isn't definitive. */
if (DECL_FIELD_IS_BASE (TREE_OPERAND (instance, 1)))
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
- return fixed_type_or_null (TREE_OPERAND (instance, 1), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
+ return RECUR (TREE_OPERAND (instance, 1));
case VAR_DECL:
case FIELD_DECL:
}
else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
{
+ /* We only need one hash table because it is always left empty. */
+ static htab_t ht;
+ if (!ht)
+ ht = htab_create (37,
+ htab_hash_pointer,
+ htab_eq_pointer,
+ /*htab_del=*/NULL);
+
/* Reference variables should be references to objects. */
if (nonnull)
*nonnull = 1;
- /* DECL_VAR_MARKED_P is used to prevent recursion; a
+ /* Enter the INSTANCE in a table to prevent recursion; a
variable's initializer may refer to the variable
itself. */
if (TREE_CODE (instance) == VAR_DECL
&& DECL_INITIAL (instance)
- && !DECL_VAR_MARKED_P (instance))
+ && !htab_find (ht, instance))
{
tree type;
- DECL_VAR_MARKED_P (instance) = 1;
- type = fixed_type_or_null (DECL_INITIAL (instance),
- nonnull, cdtorp);
- DECL_VAR_MARKED_P (instance) = 0;
+ void **slot;
+
+ slot = htab_find_slot (ht, instance, INSERT);
+ *slot = instance;
+ type = RECUR (DECL_INITIAL (instance));
+ htab_remove_elt (ht, instance);
+
return type;
}
}
default:
return NULL_TREE;
}
+#undef RECUR
}
/* Return nonzero if the dynamic type of INSTANCE is known, and
{
tree t = TREE_TYPE (instance);
int cdtorp = 0;
-
tree fixed = fixed_type_or_null (instance, nonnull, &cdtorp);
if (fixed == NULL_TREE)
return 0;
current_class_stack_size *= 2;
current_class_stack
= XRESIZEVEC (struct class_stack_node, current_class_stack,
- current_class_stack_size);
+ current_class_stack_size);
}
/* Insert a new entry on the class stack. */
void
push_nested_class (tree type)
{
- tree context;
-
/* A namespace might be passed in error cases, like A::B:C. */
if (type == NULL_TREE
- || type == error_mark_node
- || TREE_CODE (type) == NAMESPACE_DECL
- || ! IS_AGGR_TYPE (type)
- || TREE_CODE (type) == TEMPLATE_TYPE_PARM
- || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ || !CLASS_TYPE_P (type))
return;
- context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
+ push_nested_class (DECL_CONTEXT (TYPE_MAIN_DECL (type)));
- if (context && CLASS_TYPE_P (context))
- push_nested_class (context);
pushclass (type);
}
/* Given an OVERLOAD and a TARGET_TYPE, return the function that
matches the TARGET_TYPE. If there is no satisfactory match, return
- error_mark_node, and issue an error & warning messages under control
- of FLAGS. Permit pointers to member function if FLAGS permits. If
- TEMPLATE_ONLY, the name of the overloaded function was a
- template-id, and EXPLICIT_TARGS are the explicitly provided
- template arguments. */
+ error_mark_node, and issue an error & warning messages under
+ control of FLAGS. Permit pointers to member function if FLAGS
+ permits. If TEMPLATE_ONLY, the name of the overloaded function was
+ a template-id, and EXPLICIT_TARGS are the explicitly provided
+ template arguments. If OVERLOAD is for one or more member
+ functions, then ACCESS_PATH is the base path used to reference
+ those member functions. */
static tree
resolve_address_of_overloaded_function (tree target_type,
tree overload,
tsubst_flags_t flags,
bool template_only,
- tree explicit_targs)
+ tree explicit_targs,
+ tree access_path)
{
/* Here's what the standard says:
build_ptrmemfunc_type (build_pointer_type (instantiation_type));
else if (!is_reference)
instantiation_type = build_pointer_type (instantiation_type);
- if (can_convert_arg (target_type, instantiation_type, instantiation,
+ if (can_convert_arg (target_type, instantiation_type, instantiation,
LOOKUP_NORMAL))
matches = tree_cons (instantiation, fn, matches);
}
tree match = most_specialized_instantiation (matches);
if (match != error_mark_node)
- matches = tree_cons (TREE_PURPOSE (match),
- NULL_TREE,
+ matches = tree_cons (TREE_PURPOSE (match),
+ NULL_TREE,
NULL_TREE);
}
}
function used. If this conversion sequence is selected, the
function will be marked as used at this point. */
if (!(flags & tf_conv))
- mark_used (fn);
+ {
+ mark_used (fn);
+ /* We could not check access when this expression was originally
+ created since we did not know at that time to which function
+ the expression referred. */
+ if (DECL_FUNCTION_MEMBER_P (fn))
+ {
+ gcc_assert (access_path);
+ perform_or_defer_access_check (access_path, fn, fn);
+ }
+ }
if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
return build_unary_op (ADDR_EXPR, fn, 0);
instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags)
{
tsubst_flags_t flags_in = flags;
+ tree access_path = NULL_TREE;
flags &= ~tf_ptrmem_ok;
}
if (TREE_CODE (rhs) == BASELINK)
- rhs = BASELINK_FUNCTIONS (rhs);
+ {
+ access_path = BASELINK_ACCESS_BINFO (rhs);
+ rhs = BASELINK_FUNCTIONS (rhs);
+ }
/* If we are in a template, and have a NON_DEPENDENT_EXPR, we cannot
deduce any type information. */
return error_mark_node;
}
+ /* There only a few kinds of expressions that may have a type
+ dependent on overload resolution. */
+ gcc_assert (TREE_CODE (rhs) == ADDR_EXPR
+ || TREE_CODE (rhs) == COMPONENT_REF
+ || TREE_CODE (rhs) == COMPOUND_EXPR
+ || really_overloaded_fn (rhs));
+
/* We don't overwrite rhs if it is an overloaded function.
Copying it would destroy the tree link. */
if (TREE_CODE (rhs) != OVERLOAD)
switch (TREE_CODE (rhs))
{
- case TYPE_EXPR:
- case CONVERT_EXPR:
- case SAVE_EXPR:
- case CONSTRUCTOR:
- gcc_unreachable ();
-
- case INDIRECT_REF:
- case ARRAY_REF:
- {
- tree new_rhs;
-
- new_rhs = instantiate_type (build_pointer_type (lhstype),
- TREE_OPERAND (rhs, 0), flags);
- if (new_rhs == error_mark_node)
- return error_mark_node;
-
- TREE_TYPE (rhs) = lhstype;
- TREE_OPERAND (rhs, 0) = new_rhs;
- return rhs;
- }
-
- case NOP_EXPR:
- rhs = copy_node (TREE_OPERAND (rhs, 0));
- TREE_TYPE (rhs) = unknown_type_node;
- return instantiate_type (lhstype, rhs, flags);
-
case COMPONENT_REF:
{
tree member = TREE_OPERAND (rhs, 1);
case OFFSET_REF:
rhs = TREE_OPERAND (rhs, 1);
if (BASELINK_P (rhs))
- return instantiate_type (lhstype, BASELINK_FUNCTIONS (rhs), flags_in);
+ return instantiate_type (lhstype, rhs, flags_in);
/* This can happen if we are forming a pointer-to-member for a
member template. */
return
resolve_address_of_overloaded_function (lhstype, fns, flags_in,
/*template_only=*/true,
- args);
+ args, access_path);
}
case OVERLOAD:
return
resolve_address_of_overloaded_function (lhstype, rhs, flags_in,
/*template_only=*/false,
- /*explicit_targs=*/NULL_TREE);
+ /*explicit_targs=*/NULL_TREE,
+ access_path);
- case CALL_EXPR:
- /* This is too hard for now. */
- gcc_unreachable ();
-
- case PLUS_EXPR:
- case MINUS_EXPR:
case COMPOUND_EXPR:
TREE_OPERAND (rhs, 0)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
TREE_TYPE (rhs) = lhstype;
return rhs;
- case MULT_EXPR:
- case TRUNC_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case RDIV_EXPR:
- case TRUNC_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- case CEIL_MOD_EXPR:
- case ROUND_MOD_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_CEIL_EXPR:
- case FIX_TRUNC_EXPR:
- case FLOAT_EXPR:
- case NEGATE_EXPR:
- case ABS_EXPR:
- case MAX_EXPR:
- case MIN_EXPR:
-
- case BIT_AND_EXPR:
- case BIT_IOR_EXPR:
- case BIT_XOR_EXPR:
- case LSHIFT_EXPR:
- case RSHIFT_EXPR:
- case LROTATE_EXPR:
- case RROTATE_EXPR:
-
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case POSTINCREMENT_EXPR:
- case POSTDECREMENT_EXPR:
- if (flags & tf_error)
- error ("invalid operation on uninstantiated type");
- return error_mark_node;
-
- case TRUTH_AND_EXPR:
- case TRUTH_OR_EXPR:
- case TRUTH_XOR_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- case GT_EXPR:
- case GE_EXPR:
- case EQ_EXPR:
- case NE_EXPR:
- case TRUTH_ANDIF_EXPR:
- case TRUTH_ORIF_EXPR:
- case TRUTH_NOT_EXPR:
- if (flags & tf_error)
- error ("not enough type information");
- return error_mark_node;
-
- case COND_EXPR:
- if (type_unknown_p (TREE_OPERAND (rhs, 0)))
- {
- if (flags & tf_error)
- error ("not enough type information");
- return error_mark_node;
- }
- TREE_OPERAND (rhs, 1)
- = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
- if (TREE_OPERAND (rhs, 1) == error_mark_node)
- return error_mark_node;
- TREE_OPERAND (rhs, 2)
- = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), flags);
- if (TREE_OPERAND (rhs, 2) == error_mark_node)
- return error_mark_node;
-
- TREE_TYPE (rhs) = lhstype;
- return rhs;
-
- case MODIFY_EXPR:
- TREE_OPERAND (rhs, 1)
- = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
- if (TREE_OPERAND (rhs, 1) == error_mark_node)
- return error_mark_node;
-
- TREE_TYPE (rhs) = lhstype;
- return rhs;
-
case ADDR_EXPR:
{
if (PTRMEM_OK_P (rhs))
type = BINFO_TYPE (binfo);
buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
- + TYPE_NAME_LENGTH (type) + 2);
+ + TYPE_NAME_LENGTH (type) + 2);
sprintf (buf, VFIELD_NAME_FORMAT,
IDENTIFIER_POINTER (constructor_name (type)));
return get_identifier (buf);
A name N used in a class S shall refer to the same declaration
in its context and when re-evaluated in the completed scope of
S. */
- error ("declaration of %q#D", decl);
- error ("changes meaning of %qD from %q+#D",
- DECL_NAME (OVL_CURRENT (decl)), (tree) n->value);
+ pedwarn ("declaration of %q#D", decl);
+ pedwarn ("changes meaning of %qD from %q+#D",
+ DECL_NAME (OVL_CURRENT (decl)), (tree) n->value);
}
}
tree decl;
decl = BINFO_VTABLE (binfo);
- if (decl && TREE_CODE (decl) == PLUS_EXPR)
+ if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
{
gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
/* Figure out the type of the construction vtable. */
type = build_index_type (size_int (list_length (inits) - 1));
type = build_cplus_array_type (vtable_entry_type, type);
+ layout_type (type);
TREE_TYPE (vtbl) = type;
+ DECL_SIZE (vtbl) = DECL_SIZE_UNIT (vtbl) = NULL_TREE;
+ layout_decl (vtbl, 0);
/* Initialize the construction vtable. */
CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
index = size_binop (MULT_EXPR,
TYPE_SIZE_UNIT (vtable_entry_type),
index);
- vtbl = build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
+ vtbl = build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
}
if (ctor_vtbl_p)
/* We only need these entries if this base is a virtual base. We
compute the indices -- but do not add to the vtable -- when
building the main vtable for a class. */
- if (BINFO_VIRTUAL_P (binfo) || binfo == TYPE_BINFO (vid->derived))
+ if (binfo == TYPE_BINFO (vid->derived)
+ || (BINFO_VIRTUAL_P (binfo)
+ /* If BINFO is RTTI_BINFO, then (since BINFO does not
+ correspond to VID->DERIVED), we are building a primary
+ construction virtual table. Since this is a primary
+ virtual table, we do not need the vcall offsets for
+ BINFO. */
+ && binfo != vid->rtti_binfo))
{
/* We need a vcall offset for each of the virtual functions in this
vtable. For example: