blob: f16e50b9de9d7dba8ebfffbdaf69365cbb09ff2c [file] [log] [blame]
/* Functions related to building -*- C++ -*- classes and their related objects.
Copyright (C) 1987-2021 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 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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 COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* High-level class interface. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "cp-tree.h"
#include "stringpool.h"
#include "cgraph.h"
#include "stor-layout.h"
#include "attribs.h"
#include "flags.h"
#include "toplev.h"
#include "convert.h"
#include "dumpfile.h"
#include "gimplify.h"
#include "intl.h"
#include "asan.h"
/* Id for dumping the class hierarchy. */
int class_dump_id;
/* The number of nested classes being processed. If we are not in the
scope of any class, this is zero. */
int current_class_depth;
/* In order to deal with nested classes, we keep a stack of classes.
The topmost entry is the innermost class, and is the entry at index
CURRENT_CLASS_DEPTH */
typedef struct class_stack_node {
/* The name of the class. */
tree name;
/* The _TYPE node for the class. */
tree type;
/* The access specifier pending for new declarations in the scope of
this class. */
tree access;
/* If were defining TYPE, the names used in this class. */
splay_tree names_used;
/* Nonzero if this class is no longer open, because of a call to
push_to_top_level. */
size_t hidden;
}* class_stack_node_t;
struct vtbl_init_data
{
/* The base for which we're building initializers. */
tree binfo;
/* The type of the most-derived type. */
tree derived;
/* The binfo for the dynamic type. This will be TYPE_BINFO (derived),
unless ctor_vtbl_p is true. */
tree rtti_binfo;
/* The negative-index vtable initializers built up so far. These
are in order from least negative index to most negative index. */
vec<constructor_elt, va_gc> *inits;
/* The binfo for the virtual base for which we're building
vcall offset initializers. */
tree vbase;
/* The functions in vbase for which we have already provided vcall
offsets. */
vec<tree, va_gc> *fns;
/* The vtable index of the next vcall or vbase offset. */
tree index;
/* Nonzero if we are building the initializer for the primary
vtable. */
int primary_vtbl_p;
/* Nonzero if we are building the initializer for a construction
vtable. */
int ctor_vtbl_p;
/* True when adding vcall offset entries to the vtable. False when
merely computing the indices. */
bool generate_vcall_entries;
};
/* The type of a function passed to walk_subobject_offsets. */
typedef int (*subobject_offset_fn) (tree, tree, splay_tree);
/* The stack itself. This is a dynamically resized array. The
number of elements allocated is CURRENT_CLASS_STACK_SIZE. */
static int current_class_stack_size;
static class_stack_node_t current_class_stack;
/* The size of the largest empty class seen in this translation unit. */
static GTY (()) tree sizeof_biggest_empty_class;
static tree get_vfield_name (tree);
static void finish_struct_anon (tree);
static tree get_vtable_name (tree);
static void get_basefndecls (tree, tree, vec<tree> *);
static int build_primary_vtable (tree, tree);
static int build_secondary_vtable (tree);
static void finish_vtbls (tree);
static void modify_vtable_entry (tree, tree, tree, tree, tree *);
static void finish_struct_bits (tree);
static int alter_access (tree, tree, tree);
static void handle_using_decl (tree, tree);
static tree dfs_modify_vtables (tree, void *);
static tree modify_all_vtables (tree, tree);
static void determine_primary_bases (tree);
static void maybe_warn_about_overly_private_class (tree);
static void add_implicitly_declared_members (tree, tree*, int, int);
static tree fixed_type_or_null (tree, int *, int *);
static tree build_simple_base_path (tree expr, tree binfo);
static void build_vtbl_initializer (tree, tree, tree, tree, int *,
vec<constructor_elt, va_gc> **);
static bool check_bitfield_decl (tree);
static bool check_field_decl (tree, tree, int *, int *);
static void check_field_decls (tree, tree *, int *, int *);
static void build_base_fields (record_layout_info, splay_tree, tree *);
static void check_methods (tree);
static bool accessible_nvdtor_p (tree);
/* Used by find_flexarrays and related functions. */
struct flexmems_t;
static void diagnose_flexarrays (tree, const flexmems_t *);
static void find_flexarrays (tree, flexmems_t *, bool = false,
tree = NULL_TREE, tree = NULL_TREE);
static void check_flexarrays (tree, flexmems_t * = NULL, bool = false);
static void check_bases (tree, int *, int *);
static void check_bases_and_members (tree);
static tree create_vtable_ptr (tree, tree *);
static void include_empty_classes (record_layout_info);
static void layout_class_type (tree, tree *);
static void propagate_binfo_offsets (tree, tree);
static void layout_virtual_bases (record_layout_info, splay_tree);
static void build_vbase_offset_vtbl_entries (tree, vtbl_init_data *);
static void add_vcall_offset_vtbl_entries_r (tree, vtbl_init_data *);
static void add_vcall_offset_vtbl_entries_1 (tree, vtbl_init_data *);
static void build_vcall_offset_vtbl_entries (tree, vtbl_init_data *);
static void add_vcall_offset (tree, tree, vtbl_init_data *);
static void layout_vtable_decl (tree, int);
static tree dfs_find_final_overrider_pre (tree, void *);
static tree dfs_find_final_overrider_post (tree, void *);
static tree find_final_overrider (tree, tree, tree);
static int make_new_vtable (tree, tree);
static tree get_primary_binfo (tree);
static int maybe_indent_hierarchy (FILE *, int, int);
static tree dump_class_hierarchy_r (FILE *, dump_flags_t, tree, tree, int);
static void dump_class_hierarchy (tree);
static void dump_class_hierarchy_1 (FILE *, dump_flags_t, tree);
static void dump_array (FILE *, tree);
static void dump_vtable (tree, tree, tree);
static void dump_vtt (tree, tree);
static void dump_thunk (FILE *, int, tree);
static tree build_vtable (tree, tree, tree);
static void initialize_vtable (tree, vec<constructor_elt, va_gc> *);
static void layout_nonempty_base_or_field (record_layout_info,
tree, tree, splay_tree);
static void accumulate_vtbl_inits (tree, tree, tree, tree, tree,
vec<constructor_elt, va_gc> **);
static void dfs_accumulate_vtbl_inits (tree, tree, tree, tree, tree,
vec<constructor_elt, va_gc> **);
static void build_rtti_vtbl_entries (tree, vtbl_init_data *);
static void build_vcall_and_vbase_vtbl_entries (tree, vtbl_init_data *);
static void clone_constructors_and_destructors (tree);
static void update_vtable_entry_for_fn (tree, tree, tree, tree *, unsigned);
static void build_ctor_vtbl_group (tree, tree);
static void build_vtt (tree);
static tree binfo_ctor_vtable (tree);
static void build_vtt_inits (tree, tree, vec<constructor_elt, va_gc> **,
tree *);
static tree dfs_build_secondary_vptr_vtt_inits (tree, void *);
static tree dfs_fixup_binfo_vtbls (tree, void *);
static int record_subobject_offset (tree, tree, splay_tree);
static int check_subobject_offset (tree, tree, splay_tree);
static int walk_subobject_offsets (tree, subobject_offset_fn,
tree, splay_tree, tree, int);
static int layout_conflict_p (tree, tree, splay_tree, int);
static int splay_tree_compare_integer_csts (splay_tree_key k1,
splay_tree_key k2);
static void maybe_warn_about_inaccessible_bases (tree);
static bool type_requires_array_cookie (tree);
static bool base_derived_from (tree, tree);
static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree);
static tree end_of_base (tree);
static tree get_vcall_index (tree, tree);
static bool type_maybe_constexpr_default_constructor (tree);
static bool type_maybe_constexpr_destructor (tree);
static bool field_poverlapping_p (tree);
/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */
void
set_current_access_from_decl (tree decl)
{
if (TREE_PRIVATE (decl))
current_access_specifier = access_private_node;
else if (TREE_PROTECTED (decl))
current_access_specifier = access_protected_node;
else
current_access_specifier = access_public_node;
}
/* Return a COND_EXPR that executes TRUE_STMT if this execution of the
'structor is in charge of 'structing virtual bases, or FALSE_STMT
otherwise. */
tree
build_if_in_charge (tree true_stmt, tree false_stmt)
{
gcc_assert (DECL_HAS_IN_CHARGE_PARM_P (current_function_decl));
tree cmp = build2 (NE_EXPR, boolean_type_node,
current_in_charge_parm, integer_zero_node);
tree type = unlowered_expr_type (true_stmt);
if (VOID_TYPE_P (type))
type = unlowered_expr_type (false_stmt);
tree cond = build3 (COND_EXPR, type,
cmp, true_stmt, false_stmt);
return cond;
}
/* Convert to or from a base subobject. EXPR is an expression of type
`A' or `A*', an expression of type `B' or `B*' is returned. To
convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for
the B base instance within A. To convert base A to derived B, CODE
is MINUS_EXPR and BINFO is the binfo for the A instance within B.
In this latter case, A must not be a morally virtual base of B.
NONNULL is true if EXPR is known to be non-NULL (this is only
needed when EXPR is of pointer type). CV qualifiers are preserved
from EXPR. */
tree
build_base_path (enum tree_code code,
tree expr,
tree binfo,
int nonnull,
tsubst_flags_t complain)
{
tree v_binfo = NULL_TREE;
tree d_binfo = NULL_TREE;
tree probe;
tree offset;
tree target_type;
tree null_test = NULL;
tree ptr_target_type;
int fixed_type_p;
int want_pointer = TYPE_PTR_P (TREE_TYPE (expr));
bool has_empty = false;
bool virtual_access;
bool rvalue = false;
if (expr == error_mark_node || binfo == error_mark_node || !binfo)
return error_mark_node;
for (probe = binfo; probe; probe = BINFO_INHERITANCE_CHAIN (probe))
{
d_binfo = probe;
if (is_empty_class (BINFO_TYPE (probe)))
has_empty = true;
if (!v_binfo && BINFO_VIRTUAL_P (probe))
v_binfo = probe;
}
probe = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
if (want_pointer)
probe = TYPE_MAIN_VARIANT (TREE_TYPE (probe));
if (dependent_type_p (probe))
if (tree open = currently_open_class (probe))
probe = open;
if (code == PLUS_EXPR
&& !SAME_BINFO_TYPE_P (BINFO_TYPE (d_binfo), probe))
{
/* This can happen when adjust_result_of_qualified_name_lookup can't
find a unique base binfo in a call to a member function. We
couldn't give the diagnostic then since we might have been calling
a static member function, so we do it now. In other cases, eg.
during error recovery (c++/71979), we may not have a base at all. */
if (complain & tf_error)
{
tree base = lookup_base (probe, BINFO_TYPE (d_binfo),
ba_unique, NULL, complain);
gcc_assert (base == error_mark_node || !base);
}
return error_mark_node;
}
gcc_assert ((code == MINUS_EXPR
&& SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), probe))
|| code == PLUS_EXPR);
if (binfo == d_binfo)
/* Nothing to do. */
return expr;
if (code == MINUS_EXPR && v_binfo)
{
if (complain & tf_error)
{
if (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), BINFO_TYPE (v_binfo)))
{
if (want_pointer)
error ("cannot convert from pointer to base class %qT to "
"pointer to derived class %qT because the base is "
"virtual", BINFO_TYPE (binfo), BINFO_TYPE (d_binfo));
else
error ("cannot convert from base class %qT to derived "
"class %qT because the base is virtual",
BINFO_TYPE (binfo), BINFO_TYPE (d_binfo));
}
else
{
if (want_pointer)
error ("cannot convert from pointer to base class %qT to "
"pointer to derived class %qT via virtual base %qT",
BINFO_TYPE (binfo), BINFO_TYPE (d_binfo),
BINFO_TYPE (v_binfo));
else
error ("cannot convert from base class %qT to derived "
"class %qT via virtual base %qT", BINFO_TYPE (binfo),
BINFO_TYPE (d_binfo), BINFO_TYPE (v_binfo));
}
}
return error_mark_node;
}
bool uneval = (cp_unevaluated_operand != 0
|| processing_template_decl
|| in_template_function ());
/* For a non-pointer simple base reference, express it as a COMPONENT_REF
without taking its address (and so causing lambda capture, 91933). */
if (code == PLUS_EXPR && !v_binfo && !want_pointer && !has_empty && !uneval)
return build_simple_base_path (expr, binfo);
if (!want_pointer)
{
rvalue = !lvalue_p (expr);
/* This must happen before the call to save_expr. */
expr = cp_build_addr_expr (expr, complain);
}
else
expr = mark_rvalue_use (expr);
offset = BINFO_OFFSET (binfo);
fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);
/* 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. */
target_type = cp_build_qualified_type
(target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr))));
ptr_target_type = build_pointer_type (target_type);
/* Do we need to look in the vtable for the real offset? */
virtual_access = (v_binfo && fixed_type_p <= 0);
/* Don't bother with the calculations inside sizeof; they'll ICE if the
source type is incomplete and the pointer value doesn't matter. In a
template (even in instantiate_non_dependent_expr), we don't have vtables
set up properly yet, and the value doesn't matter there either; we're
just interested in the result of overload resolution. */
if (uneval)
{
expr = build_nop (ptr_target_type, expr);
goto indout;
}
if (!COMPLETE_TYPE_P (probe))
{
if (complain & tf_error)
error ("cannot convert from %qT to base class %qT because %qT is "
"incomplete", BINFO_TYPE (d_binfo), BINFO_TYPE (binfo),
BINFO_TYPE (d_binfo));
return error_mark_node;
}
/* If we're in an NSDMI, we don't have the full constructor context yet
that we need for converting to a virtual base, so just build a stub
CONVERT_EXPR and expand it later in bot_replace. */
if (virtual_access && fixed_type_p < 0
&& current_scope () != current_function_decl)
{
expr = build1 (CONVERT_EXPR, ptr_target_type, expr);
CONVERT_EXPR_VBASE_PATH (expr) = true;
goto indout;
}
/* Do we need to check for a null pointer? */
if (want_pointer && !nonnull)
{
/* If we know the conversion will not actually change the value
of EXPR, then we can avoid testing the expression for NULL.
We have to avoid generating a COMPONENT_REF for a base class
field, because other parts of the compiler know that such
expressions are always non-NULL. */
if (!virtual_access && integer_zerop (offset))
return build_nop (ptr_target_type, expr);
null_test = error_mark_node;
}
/* Protect against multiple evaluation if necessary. */
if (TREE_SIDE_EFFECTS (expr) && (null_test || virtual_access))
expr = save_expr (expr);
/* Store EXPR and build the real null test just before returning. */
if (null_test)
null_test = expr;
/* If this is a simple base reference, express it as a COMPONENT_REF. */
if (code == PLUS_EXPR && !virtual_access
/* We don't build base fields for empty bases, and they aren't very
interesting to the optimizers anyway. */
&& !has_empty)
{
expr = cp_build_fold_indirect_ref (expr);
expr = build_simple_base_path (expr, binfo);
if (rvalue && lvalue_p (expr))
expr = move (expr);
if (want_pointer)
expr = build_address (expr);
target_type = TREE_TYPE (expr);
goto out;
}
if (virtual_access)
{
/* Going via virtual base V_BINFO. We need the static offset
from V_BINFO to BINFO, and the dynamic offset from D_BINFO to
V_BINFO. That offset is an entry in D_BINFO's vtable. */
tree v_offset;
if (fixed_type_p < 0 && in_base_initializer)
{
/* In a base member initializer, we cannot rely on the
vtable being set up. We have to indirect via the
vtt_parm. */
tree t;
t = TREE_TYPE (TYPE_VFIELD (current_class_type));
t = build_pointer_type (t);
v_offset = fold_convert (t, current_vtt_parm);
v_offset = cp_build_fold_indirect_ref (v_offset);
}
else
{
tree t = expr;
if (sanitize_flags_p (SANITIZE_VPTR)
&& fixed_type_p == 0)
{
t = cp_ubsan_maybe_instrument_cast_to_vbase (input_location,
probe, expr);
if (t == NULL_TREE)
t = expr;
}
v_offset = build_vfield_ref (cp_build_fold_indirect_ref (t),
TREE_TYPE (TREE_TYPE (expr)));
}
if (v_offset == error_mark_node)
return error_mark_node;
v_offset = fold_build_pointer_plus (v_offset, BINFO_VPTR_FIELD (v_binfo));
v_offset = build1 (NOP_EXPR,
build_pointer_type (ptrdiff_type_node),
v_offset);
v_offset = cp_build_fold_indirect_ref (v_offset);
TREE_CONSTANT (v_offset) = 1;
offset = convert_to_integer (ptrdiff_type_node,
size_diffop_loc (input_location, offset,
BINFO_OFFSET (v_binfo)));
if (!integer_zerop (offset))
v_offset = build2 (code, ptrdiff_type_node, v_offset, offset);
if (fixed_type_p < 0)
/* Negative fixed_type_p means this is a constructor or destructor;
virtual base layout is fixed in in-charge [cd]tors, but not in
base [cd]tors. */
offset = build_if_in_charge
(convert_to_integer (ptrdiff_type_node, BINFO_OFFSET (binfo)),
v_offset);
else
offset = v_offset;
}
if (want_pointer)
target_type = ptr_target_type;
if (!integer_zerop (offset))
{
offset = fold_convert (sizetype, offset);
if (code == MINUS_EXPR)
offset = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, offset);
expr = fold_build_pointer_plus (expr, offset);
}
else
null_test = NULL;
expr = build1 (NOP_EXPR, ptr_target_type, expr);
indout:
if (!want_pointer)
{
expr = cp_build_fold_indirect_ref (expr);
if (rvalue)
expr = move (expr);
}
out:
if (null_test)
/* Wrap EXPR in a null test. */
expr = build_if_nonnull (null_test, expr, complain);
return expr;
}
/* Subroutine of build_base_path; EXPR and BINFO are as in that function.
Perform a derived-to-base conversion by recursively building up a
sequence of COMPONENT_REFs to the appropriate base fields. */
static tree
build_simple_base_path (tree expr, tree binfo)
{
tree type = BINFO_TYPE (binfo);
tree d_binfo = BINFO_INHERITANCE_CHAIN (binfo);
tree field;
if (d_binfo == NULL_TREE)
{
tree temp;
gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type);
/* 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 front end; only _DECLs and _REFs are lvalues
in the back end. */
temp = unary_complex_lvalue (ADDR_EXPR, expr);
if (temp)
expr = cp_build_fold_indirect_ref (temp);
return expr;
}
/* Recurse. */
expr = build_simple_base_path (expr, d_binfo);
for (field = TYPE_FIELDS (BINFO_TYPE (d_binfo));
field; field = DECL_CHAIN (field))
/* Is this the base field created by build_base_field? */
if (TREE_CODE (field) == FIELD_DECL
&& DECL_FIELD_IS_BASE (field)
&& TREE_TYPE (field) == type
/* If we're looking for a field in the most-derived class,
also check the field offset; we can have two base fields
of the same type if one is an indirect virtual base and one
is a direct non-virtual base. */
&& (BINFO_INHERITANCE_CHAIN (d_binfo)
|| tree_int_cst_equal (byte_position (field),
BINFO_OFFSET (binfo))))
{
/* We don't use build_class_member_access_expr here, as that
has unnecessary checks, and more importantly results in
recursive calls to dfs_walk_once. */
int type_quals = cp_type_quals (TREE_TYPE (expr));
expr = build3 (COMPONENT_REF,
cp_build_qualified_type (type, type_quals),
expr, field, NULL_TREE);
/* Mark the expression const or volatile, as appropriate.
Even though we've dealt with the type above, we still have
to mark the expression itself. */
if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (expr) = 1;
if (type_quals & TYPE_QUAL_VOLATILE)
TREE_THIS_VOLATILE (expr) = 1;
return expr;
}
/* Didn't find the base field?!? */
gcc_unreachable ();
}
/* Convert OBJECT to the base TYPE. OBJECT is an expression whose
type is a class type or a pointer to a class type. In the former
case, TYPE is also a class type; in the latter it is another
pointer type. If CHECK_ACCESS is true, an error message is emitted
if TYPE is inaccessible. If OBJECT has pointer type, the value is
assumed to be non-NULL. */
tree
convert_to_base (tree object, tree type, bool check_access, bool nonnull,
tsubst_flags_t complain)
{
tree binfo;
tree object_type;
if (TYPE_PTR_P (TREE_TYPE (object)))
{
object_type = TREE_TYPE (TREE_TYPE (object));
type = TREE_TYPE (type);
}
else
object_type = TREE_TYPE (object);
binfo = lookup_base (object_type, type, check_access ? ba_check : ba_unique,
NULL, complain);
if (!binfo || binfo == error_mark_node)
return error_mark_node;
return build_base_path (PLUS_EXPR, object, binfo, nonnull, complain);
}
/* EXPR is an expression with unqualified class type. BASE is a base
binfo of that class type. Returns EXPR, converted to the BASE
type. This function assumes that EXPR is the most derived class;
therefore virtual bases can be found at their static offsets. */
tree
convert_to_base_statically (tree expr, tree base)
{
tree expr_type;
expr_type = TREE_TYPE (expr);
if (!SAME_BINFO_TYPE_P (BINFO_TYPE (base), expr_type))
{
/* If this is a non-empty base, use a COMPONENT_REF. */
if (!is_empty_class (BINFO_TYPE (base)))
return build_simple_base_path (expr, base);
/* 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 = cp_build_addr_expr (expr, tf_warning_or_error);
if (!integer_zerop (BINFO_OFFSET (base)))
expr = fold_build_pointer_plus_loc (input_location,
expr, BINFO_OFFSET (base));
expr = fold_convert (build_pointer_type (BINFO_TYPE (base)), expr);
expr = build_fold_indirect_ref_loc (input_location, expr);
}
return expr;
}
/* True IFF EXPR is a reference to an empty base class "subobject", as built in
convert_to_base_statically. We look for the result of the fold_convert
call, a NOP_EXPR from one pointer type to another, where the target is an
empty base of the original type. */
bool
is_empty_base_ref (tree expr)
{
if (TREE_CODE (expr) == INDIRECT_REF)
expr = TREE_OPERAND (expr, 0);
if (TREE_CODE (expr) != NOP_EXPR)
return false;
tree type = TREE_TYPE (expr);
if (!POINTER_TYPE_P (type))
return false;
type = TREE_TYPE (type);
if (!is_empty_class (type))
return false;
STRIP_NOPS (expr);
tree fromtype = TREE_TYPE (expr);
if (!POINTER_TYPE_P (fromtype))
return false;
fromtype = TREE_TYPE (fromtype);
return (CLASS_TYPE_P (fromtype)
&& !same_type_ignoring_top_level_qualifiers_p (fromtype, type)
&& DERIVED_FROM_P (type, fromtype));
}
tree
build_vfield_ref (tree datum, tree type)
{
tree vfield, vcontext;
if (datum == error_mark_node
/* Can happen in case of duplicate base types (c++/59082). */
|| !TYPE_VFIELD (type))
return error_mark_node;
/* First, convert to the requested type. */
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (datum), type))
datum = convert_to_base (datum, type, /*check_access=*/false,
/*nonnull=*/true, tf_warning_or_error);
/* Second, the requested type may not be the owner of its own vptr.
If not, convert to the base class that owns it. We cannot use
convert_to_base here, because VCONTEXT may appear more than once
in the inheritance hierarchy of TYPE, and thus direct conversion
between the types may be ambiguous. Following the path back up
one step at a time via primary bases avoids the problem. */
vfield = TYPE_VFIELD (type);
vcontext = DECL_CONTEXT (vfield);
while (!same_type_ignoring_top_level_qualifiers_p (vcontext, type))
{
datum = build_simple_base_path (datum, CLASSTYPE_PRIMARY_BINFO (type));
type = TREE_TYPE (datum);
}
return build3 (COMPONENT_REF, TREE_TYPE (vfield), datum, vfield, NULL_TREE);
}
/* Given an object INSTANCE, return an expression which yields the
vtable element corresponding to INDEX. There are many special
cases for INSTANCE which we take care of here, mainly to avoid
creating extra tree nodes when we don't have to. */
tree
build_vtbl_ref (tree instance, tree idx)
{
tree aref;
tree vtbl = NULL_TREE;
/* Try to figure out what a reference refers to, and
access its virtual function table directly. */
int cdtorp = 0;
tree fixed_type = fixed_type_or_null (instance, NULL, &cdtorp);
tree basetype = non_reference (TREE_TYPE (instance));
if (fixed_type && !cdtorp)
{
tree binfo = lookup_base (fixed_type, basetype,
ba_unique, NULL, tf_none);
if (binfo && binfo != error_mark_node)
vtbl = unshare_expr (BINFO_VTABLE (binfo));
}
if (!vtbl)
vtbl = build_vfield_ref (instance, basetype);
aref = build_array_ref (input_location, vtbl, idx);
TREE_CONSTANT (aref) |= TREE_CONSTANT (vtbl) && TREE_CONSTANT (idx);
return aref;
}
/* Given a stable object pointer INSTANCE_PTR, return an expression which
yields a function pointer corresponding to vtable element INDEX. */
tree
build_vfn_ref (tree instance_ptr, tree idx)
{
tree aref;
aref = build_vtbl_ref (cp_build_fold_indirect_ref (instance_ptr), idx);
/* When using function descriptors, the address of the
vtable entry is treated as a function pointer. */
if (TARGET_VTABLE_USES_DESCRIPTORS)
aref = build1 (NOP_EXPR, TREE_TYPE (aref),
cp_build_addr_expr (aref, tf_warning_or_error));
/* Remember this as a method reference, for later devirtualization. */
aref = build3 (OBJ_TYPE_REF, TREE_TYPE (aref), aref, instance_ptr, idx);
return aref;
}
/* Return the name of the virtual function table (as an IDENTIFIER_NODE)
for the given TYPE. */
static tree
get_vtable_name (tree type)
{
return mangle_vtbl_for_type (type);
}
/* DECL is an entity associated with TYPE, like a virtual table or an
implicitly generated constructor. Determine whether or not DECL
should have external or internal linkage at the object file
level. This routine does not deal with COMDAT linkage and other
similar complexities; it simply sets TREE_PUBLIC if it possible for
entities in other translation units to contain copies of DECL, in
the abstract. */
void
set_linkage_according_to_type (tree /*type*/, tree decl)
{
TREE_PUBLIC (decl) = 1;
determine_visibility (decl);
}
/* Create a VAR_DECL for a primary or secondary vtable for CLASS_TYPE.
(For a secondary vtable for B-in-D, CLASS_TYPE should be D, not B.)
Use NAME for the name of the vtable, and VTABLE_TYPE for its type. */
static tree
build_vtable (tree class_type, tree name, tree vtable_type)
{
tree decl;
decl = build_lang_decl (VAR_DECL, name, vtable_type);
/* vtable names are already mangled; give them their DECL_ASSEMBLER_NAME
now to avoid confusion in mangle_decl. */
SET_DECL_ASSEMBLER_NAME (decl, name);
DECL_CONTEXT (decl) = class_type;
DECL_ARTIFICIAL (decl) = 1;
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_VIRTUAL_P (decl) = 1;
SET_DECL_ALIGN (decl, TARGET_VTABLE_ENTRY_ALIGN);
DECL_USER_ALIGN (decl) = true;
DECL_VTABLE_OR_VTT_P (decl) = 1;
set_linkage_according_to_type (class_type, decl);
/* The vtable has not been defined -- yet. */
DECL_EXTERNAL (decl) = 1;
DECL_NOT_REALLY_EXTERN (decl) = 1;
/* Mark the VAR_DECL node representing the vtable itself as a
"gratuitous" one, thereby forcing dwarfout.c to ignore it. It
is rather important that such things be ignored because any
effort to actually generate DWARF for them will run into
trouble when/if we encounter code like:
#pragma interface
struct S { virtual void member (); };
because the artificial declaration of the vtable itself (as
manufactured by the g++ front end) will say that the vtable is
a static member of `S' but only *after* the debug output for
the definition of `S' has already been output. This causes
grief because the DWARF entry for the definition of the vtable
will try to refer back to an earlier *declaration* of the
vtable as a static member of `S' and there won't be one. We
might be able to arrange to have the "vtable static member"
attached to the member list for `S' before the debug info for
`S' get written (which would solve the problem) but that would
require more intrusive changes to the g++ front end. */
DECL_IGNORED_P (decl) = 1;
return decl;
}
/* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
or even complete. If this does not exist, create it. If COMPLETE is
nonzero, then complete the definition of it -- that will render it
impossible to actually build the vtable, but is useful to get at those
which are known to exist in the runtime. */
tree
get_vtable_decl (tree type, int complete)
{
tree decl;
if (CLASSTYPE_VTABLES (type))
return CLASSTYPE_VTABLES (type);
decl = build_vtable (type, get_vtable_name (type), vtbl_type_node);
CLASSTYPE_VTABLES (type) = decl;
if (complete)
{
DECL_EXTERNAL (decl) = 1;
cp_finish_decl (decl, NULL_TREE, false, NULL_TREE, 0);
}
return decl;
}
/* Build the primary virtual function table for TYPE. If BINFO is
non-NULL, build the vtable starting with the initial approximation
that it is the same as the one which is the head of the association
list. Returns a nonzero value if a new vtable is actually
created. */
static int
build_primary_vtable (tree binfo, tree type)
{
tree decl;
tree virtuals;
decl = get_vtable_decl (type, /*complete=*/0);
if (binfo)
{
if (BINFO_NEW_VTABLE_MARKED (binfo))
/* We have already created a vtable for this base, so there's
no need to do it again. */
return 0;
virtuals = copy_list (BINFO_VIRTUALS (binfo));
TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));
DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));
DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
}
else
{
gcc_assert (TREE_TYPE (decl) == vtbl_type_node);
virtuals = NULL_TREE;
}
/* Initialize the association list for this type, based
on our first approximation. */
BINFO_VTABLE (TYPE_BINFO (type)) = decl;
BINFO_VIRTUALS (TYPE_BINFO (type)) = virtuals;
SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type));
return 1;
}
/* Give BINFO a new virtual function table which is initialized
with a skeleton-copy of its original initialization. The only
entry that changes is the `delta' entry, so we can really
share a lot of structure.
FOR_TYPE is the most derived type which caused this table to
be needed.
Returns nonzero if we haven't met BINFO before.
The order in which vtables are built (by calling this function) for
an object must remain the same, otherwise a binary incompatibility
can result. */
static int
build_secondary_vtable (tree binfo)
{
if (BINFO_NEW_VTABLE_MARKED (binfo))
/* We already created a vtable for this base. There's no need to
do it again. */
return 0;
/* Remember that we've created a vtable for this BINFO, so that we
don't try to do so again. */
SET_BINFO_NEW_VTABLE_MARKED (binfo);
/* Make fresh virtual list, so we can smash it later. */
BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
/* Secondary vtables are laid out as part of the same structure as
the primary vtable. */
BINFO_VTABLE (binfo) = NULL_TREE;
return 1;
}
/* Create a new vtable for BINFO which is the hierarchy dominated by
T. Return nonzero if we actually created a new vtable. */
static int
make_new_vtable (tree t, tree binfo)
{
if (binfo == TYPE_BINFO (t))
/* In this case, it is *type*'s vtable we are modifying. We start
with the approximation that its vtable is that of the
immediate base class. */
return build_primary_vtable (binfo, t);
else
/* This is our very own copy of `basetype' to play with. Later,
we will fill in all the virtual functions that override the
virtual functions in these base classes which are not defined
by the current type. */
return build_secondary_vtable (binfo);
}
/* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
(which is in the hierarchy dominated by T) list FNDECL as its
BV_FN. DELTA is the required constant adjustment from the `this'
pointer where the vtable entry appears to the `this' required when
the function is actually called. */
static void
modify_vtable_entry (tree t,
tree binfo,
tree fndecl,
tree delta,
tree *virtuals)
{
tree v;
v = *virtuals;
if (fndecl != BV_FN (v)
|| !tree_int_cst_equal (delta, BV_DELTA (v)))
{
/* We need a new vtable for BINFO. */
if (make_new_vtable (t, binfo))
{
/* If we really did make a new vtable, we also made a copy
of the BINFO_VIRTUALS list. Now, we have to find the
corresponding entry in that list. */
*virtuals = BINFO_VIRTUALS (binfo);
while (BV_FN (*virtuals) != BV_FN (v))
*virtuals = TREE_CHAIN (*virtuals);
v = *virtuals;
}
BV_DELTA (v) = delta;
BV_VCALL_INDEX (v) = NULL_TREE;
BV_FN (v) = fndecl;
}
}
/* Add method METHOD to class TYPE. If VIA_USING indicates whether
METHOD is being injected via a using_decl. Returns true if the
method could be added to the method vec. */
bool
add_method (tree type, tree method, bool via_using)
{
if (method == error_mark_node)
return false;
gcc_assert (!DECL_EXTERN_C_P (method));
tree *slot = find_member_slot (type, DECL_NAME (method));
tree current_fns = slot ? *slot : NULL_TREE;
/* See below. */
int losem = -1;
/* Check to see if we've already got this method. */
for (ovl_iterator iter (current_fns); iter; ++iter)
{
tree fn = *iter;
if (TREE_CODE (fn) != TREE_CODE (method))
continue;
/* Two using-declarations can coexist, we'll complain about ambiguity in
overload resolution. */
if (via_using && iter.using_p ()
/* Except handle inherited constructors specially. */
&& ! DECL_CONSTRUCTOR_P (fn))
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.
[over.load] Member function declarations with the same name and
the same parameter-type-list as well as member function template
declarations with the same name, the same parameter-type-list, and
the same template parameter lists cannot be overloaded if any of
them, but not all, have a ref-qualifier.
[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). */
tree fn_type = TREE_TYPE (fn);
tree method_type = TREE_TYPE (method);
/* 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)
/* Either both or neither need to be ref-qualified for
differing quals to allow overloading. */
&& (FUNCTION_REF_QUALIFIED (fn_type)
== FUNCTION_REF_QUALIFIED (method_type))
&& (type_memfn_quals (fn_type) != type_memfn_quals (method_type)
|| type_memfn_rqual (fn_type) != type_memfn_rqual (method_type)))
continue;
tree real_fn = fn;
tree real_method = method;
/* Templates and conversion ops must match return types. */
if ((DECL_CONV_FN_P (fn) || TREE_CODE (fn) == TEMPLATE_DECL)
&& !same_type_p (TREE_TYPE (fn_type), TREE_TYPE (method_type)))
continue;
/* For templates, the template parameters must be identical. */
if (TREE_CODE (fn) == TEMPLATE_DECL)
{
if (!comp_template_parms (DECL_TEMPLATE_PARMS (fn),
DECL_TEMPLATE_PARMS (method)))
continue;
real_fn = DECL_TEMPLATE_RESULT (fn);
real_method = DECL_TEMPLATE_RESULT (method);
}
tree parms1 = TYPE_ARG_TYPES (fn_type);
tree parms2 = TYPE_ARG_TYPES (method_type);
if (! DECL_STATIC_FUNCTION_P (real_fn))
parms1 = TREE_CHAIN (parms1);
if (! DECL_STATIC_FUNCTION_P (real_method))
parms2 = TREE_CHAIN (parms2);
/* Bring back parameters omitted from an inherited ctor. The
method and the function can have different omittedness. */
if (ctor_omit_inherited_parms (real_fn))
parms1 = FUNCTION_FIRST_USER_PARMTYPE (DECL_CLONED_FUNCTION (real_fn));
if (ctor_omit_inherited_parms (real_method))
parms2 = (FUNCTION_FIRST_USER_PARMTYPE
(DECL_CLONED_FUNCTION (real_method)));
if (!compparms (parms1, parms2))
continue;
if (!equivalently_constrained (fn, method))
{
if (processing_template_decl)
/* We can't check satisfaction in dependent context, wait until
the class is instantiated. */
continue;
special_function_kind sfk = special_memfn_p (method);
if (sfk == sfk_none
|| DECL_INHERITED_CTOR (fn)
|| TREE_CODE (fn) == TEMPLATE_DECL)
/* Member function templates and non-special member functions
coexist if they are not equivalently constrained. A member
function is not hidden by an inherited constructor. */
continue;
/* P0848: For special member functions, deleted, unsatisfied, or
less constrained overloads are ineligible. We implement this
by removing them from CLASSTYPE_MEMBER_VEC. Destructors don't
use the notion of eligibility, and the selected destructor can
be deleted, but removing unsatisfied or less constrained
overloads has the same effect as overload resolution. */
bool dtor = (sfk == sfk_destructor);
if (losem == -1)
losem = ((!dtor && DECL_DELETED_FN (method))
|| !constraints_satisfied_p (method));
bool losef = ((!dtor && DECL_DELETED_FN (fn))
|| !constraints_satisfied_p (fn));
int win;
if (losem || losef)
win = losem - losef;
else
win = more_constrained (fn, method);
if (win > 0)
/* Leave FN in the method vec, discard METHOD. */
return false;
else if (win < 0)
{
/* Remove FN, add METHOD. */
current_fns = iter.remove_node (current_fns);
continue;
}
else
/* Let them coexist for now. */
continue;
}
/* If these are versions of the same function, process and
move on. */
if (TREE_CODE (fn) == FUNCTION_DECL
&& maybe_version_functions (method, fn, true))
continue;
if (DECL_INHERITED_CTOR (method))
{
if (!DECL_INHERITED_CTOR (fn))
/* Defer to the other function. */
return false;
tree basem = DECL_INHERITED_CTOR_BASE (method);
tree basef = DECL_INHERITED_CTOR_BASE (fn);
if (flag_new_inheriting_ctors)
{
if (basem == basef)
{
/* Inheriting the same constructor along different
paths, combine them. */
SET_DECL_INHERITED_CTOR
(fn, ovl_make (DECL_INHERITED_CTOR (method),
DECL_INHERITED_CTOR (fn)));
/* And discard the new one. */
return false;
}
else
/* Inherited ctors can coexist until overload
resolution. */
continue;
}
error_at (DECL_SOURCE_LOCATION (method),
"%q#D conflicts with version inherited from %qT",
method, basef);
inform (DECL_SOURCE_LOCATION (fn),
"version inherited from %qT declared here",
basef);
return false;
}
if (via_using)
/* Defer to the local function. */
return false;
else if (flag_new_inheriting_ctors
&& DECL_INHERITED_CTOR (fn))
{
/* Remove the inherited constructor. */
current_fns = iter.remove_node (current_fns);
continue;
}
else
{
error_at (DECL_SOURCE_LOCATION (method),
"%q#D cannot be overloaded with %q#D", method, fn);
inform (DECL_SOURCE_LOCATION (fn),
"previous declaration %q#D", fn);
return false;
}
}
current_fns = ovl_insert (method, current_fns, via_using);
if (!COMPLETE_TYPE_P (type) && !DECL_CONV_FN_P (method)
&& !push_class_level_binding (DECL_NAME (method), current_fns))
return false;
if (!slot)
slot = add_member_slot (type, DECL_NAME (method));
/* Maintain TYPE_HAS_USER_CONSTRUCTOR, etc. */
grok_special_member_properties (method);
*slot = current_fns;
return true;
}
/* Subroutines of finish_struct. */
/* Change the access of FDECL to ACCESS in T. Return 1 if change was
legit, otherwise return 0. */
static int
alter_access (tree t, tree fdecl, tree access)
{
tree elem;
retrofit_lang_decl (fdecl);
gcc_assert (!DECL_DISCRIMINATOR_P (fdecl));
elem = purpose_member (t, DECL_ACCESS (fdecl));
if (elem)
{
if (TREE_VALUE (elem) != access)
{
if (TREE_CODE (TREE_TYPE (fdecl)) == FUNCTION_DECL)
error ("conflicting access specifications for method"
" %q+D, ignored", TREE_TYPE (fdecl));
else
error ("conflicting access specifications for field %qE, ignored",
DECL_NAME (fdecl));
}
else
{
/* They're changing the access to the same thing they changed
it to before. That's OK. */
;
}
}
else
{
perform_or_defer_access_check (TYPE_BINFO (t), fdecl, fdecl,
tf_warning_or_error);
DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
return 1;
}
return 0;
}
/* Return the access node for DECL's access in its enclosing class. */
tree
declared_access (tree decl)
{
return (TREE_PRIVATE (decl) ? access_private_node
: TREE_PROTECTED (decl) ? access_protected_node
: access_public_node);
}
/* Process the USING_DECL, which is a member of T. */
static void
handle_using_decl (tree using_decl, tree t)
{
tree decl = USING_DECL_DECLS (using_decl);
tree name = DECL_NAME (using_decl);
tree access = declared_access (using_decl);
tree flist = NULL_TREE;
tree old_value;
gcc_assert (!processing_template_decl && decl);
old_value = lookup_member (t, name, /*protect=*/0, /*want_type=*/false,
tf_warning_or_error);
if (old_value)
{
old_value = OVL_FIRST (old_value);
if (DECL_P (old_value) && DECL_CONTEXT (old_value) == t)
/* OK */;
else
old_value = NULL_TREE;
}
cp_emit_debug_info_for_using (decl, t);
if (is_overloaded_fn (decl))
flist = decl;
if (! old_value)
;
else if (is_overloaded_fn (old_value))
{
if (flist)
/* It's OK to use functions from a base when there are functions with
the same name already present in the current class. */;
else
{
error_at (DECL_SOURCE_LOCATION (using_decl), "%qD invalid in %q#T "
"because of local method %q#D with same name",
using_decl, t, old_value);
inform (DECL_SOURCE_LOCATION (old_value),
"local method %q#D declared here", old_value);
return;
}
}
else if (!DECL_ARTIFICIAL (old_value))
{
error_at (DECL_SOURCE_LOCATION (using_decl), "%qD invalid in %q#T "
"because of local member %q#D with same name",
using_decl, t, old_value);
inform (DECL_SOURCE_LOCATION (old_value),
"local member %q#D declared here", old_value);
return;
}
iloc_sentinel ils (DECL_SOURCE_LOCATION (using_decl));
/* Make type T see field decl FDECL with access ACCESS. */
if (flist)
for (tree f : ovl_range (flist))
{
add_method (t, f, true);
alter_access (t, f, access);
}
else if (USING_DECL_UNRELATED_P (using_decl))
{
/* C++20 using enum can import non-inherited enumerators into class
scope. We implement that by making a copy of the CONST_DECL for which
CONST_DECL_USING_P is true. */
gcc_assert (TREE_CODE (decl) == CONST_DECL);
auto cas = make_temp_override (current_access_specifier);
set_current_access_from_decl (using_decl);
tree copy = copy_decl (decl);
DECL_CONTEXT (copy) = t;
DECL_ARTIFICIAL (copy) = true;
/* We emitted debug info for the USING_DECL above; make sure we don't
also emit anything for this clone. */
DECL_IGNORED_P (copy) = true;
DECL_SOURCE_LOCATION (copy) = DECL_SOURCE_LOCATION (using_decl);
finish_member_declaration (copy);
DECL_ABSTRACT_ORIGIN (copy) = decl;
}
else
alter_access (t, decl, access);
}
/* Data structure for find_abi_tags_r, below. */
struct abi_tag_data
{
tree t; // The type that we're checking for missing tags.
tree subob; // The subobject of T that we're getting tags from.
tree tags; // error_mark_node for diagnostics, or a list of missing tags.
};
/* Subroutine of find_abi_tags_r. Handle a single TAG found on the class TP
in the context of P. TAG can be either an identifier (the DECL_NAME of
a tag NAMESPACE_DECL) or a STRING_CST (a tag attribute). */
static void
check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
{
if (!IDENTIFIER_MARKED (id))
{
if (p->tags != error_mark_node)
{
/* We're collecting tags from template arguments or from
the type of a variable or function return type. */
p->tags = tree_cons (NULL_TREE, tag, p->tags);
/* Don't inherit this tag multiple times. */
IDENTIFIER_MARKED (id) = true;
if (TYPE_P (p->t))
{
/* Tags inherited from type template arguments are only used
to avoid warnings. */
ABI_TAG_IMPLICIT (p->tags) = true;
return;
}
/* For functions and variables we want to warn, too. */
}
/* Otherwise we're diagnosing missing tags. */
if (TREE_CODE (p->t) == FUNCTION_DECL)
{
auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
"that %qT (used in its return type) has",
p->t, tag, *tp))
inform (location_of (*tp), "%qT declared here", *tp);
}
else if (VAR_P (p->t))
{
auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
"that %qT (used in its type) has", p->t, tag, *tp))
inform (location_of (*tp), "%qT declared here", *tp);
}
else if (TYPE_P (p->subob))
{
auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
"that base %qT has", p->t, tag, p->subob))
inform (location_of (p->subob), "%qT declared here",
p->subob);
}
else
{
auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
"that %qT (used in the type of %qD) has",
p->t, tag, *tp, p->subob))
{
inform (location_of (p->subob), "%qD declared here",
p->subob);
inform (location_of (*tp), "%qT declared here", *tp);
}
}
}
}
/* Find all the ABI tags in the attribute list ATTR and either call
check_tag (if TP is non-null) or set IDENTIFIER_MARKED to val. */
static void
mark_or_check_attr_tags (tree attr, tree *tp, abi_tag_data *p, bool val)
{
if (!attr)
return;
for (; (attr = lookup_attribute ("abi_tag", attr));
attr = TREE_CHAIN (attr))
for (tree list = TREE_VALUE (attr); list;
list = TREE_CHAIN (list))
{
tree tag = TREE_VALUE (list);
tree id = get_identifier (TREE_STRING_POINTER (tag));
if (tp)
check_tag (tag, id, tp, p);
else
IDENTIFIER_MARKED (id) = val;
}
}
/* Find all the ABI tags on T and its enclosing scopes and either call
check_tag (if TP is non-null) or set IDENTIFIER_MARKED to val. */
static void
mark_or_check_tags (tree t, tree *tp, abi_tag_data *p, bool val)
{
while (t != global_namespace)
{
tree attr;
if (TYPE_P (t))
{
attr = TYPE_ATTRIBUTES (t);
t = CP_TYPE_CONTEXT (t);
}
else
{
attr = DECL_ATTRIBUTES (t);
t = CP_DECL_CONTEXT (t);
}
mark_or_check_attr_tags (attr, tp, p, val);
}
}
/* walk_tree callback for check_abi_tags: if the type at *TP involves any
types with ABI tags, add the corresponding identifiers to the VEC in
*DATA and set IDENTIFIER_MARKED. */
static tree
find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
{
if (TYPE_P (*tp) && *walk_subtrees == 1 && flag_abi_version != 14)
/* Tell cp_walk_subtrees to look though typedefs. [PR98481] */
*walk_subtrees = 2;
if (!OVERLOAD_TYPE_P (*tp))
return NULL_TREE;
/* walk_tree shouldn't be walking into any subtrees of a RECORD_TYPE
anyway, but let's make sure of it. */
*walk_subtrees = false;
abi_tag_data *p = static_cast<struct abi_tag_data*>(data);
mark_or_check_tags (*tp, tp, p, false);
return NULL_TREE;
}
/* walk_tree callback for mark_abi_tags: if *TP is a class, set
IDENTIFIER_MARKED on its ABI tags. */
static tree
mark_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
{
if (TYPE_P (*tp) && *walk_subtrees == 1 && flag_abi_version != 14)
/* Tell cp_walk_subtrees to look though typedefs. */
*walk_subtrees = 2;
if (!OVERLOAD_TYPE_P (*tp))
return NULL_TREE;
/* walk_tree shouldn't be walking into any subtrees of a RECORD_TYPE
anyway, but let's make sure of it. */
*walk_subtrees = false;
bool *valp = static_cast<bool*>(data);
mark_or_check_tags (*tp, NULL, NULL, *valp);
return NULL_TREE;
}
/* Set IDENTIFIER_MARKED on all the ABI tags on T and its enclosing
scopes. */
static void
mark_abi_tags (tree t, bool val)
{
mark_or_check_tags (t, NULL, NULL, val);
if (DECL_P (t))
{
if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t)
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)))
{
/* Template arguments are part of the signature. */
tree level = INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (t));
for (int j = 0; j < TREE_VEC_LENGTH (level); ++j)
{
tree arg = TREE_VEC_ELT (level, j);
cp_walk_tree_without_duplicates (&arg, mark_abi_tags_r, &val);
}
}
if (TREE_CODE (t) == FUNCTION_DECL)
/* A function's parameter types are part of the signature, so
we don't need to inherit any tags that are also in them. */
for (tree arg = FUNCTION_FIRST_USER_PARMTYPE (t); arg;
arg = TREE_CHAIN (arg))
cp_walk_tree_without_duplicates (&TREE_VALUE (arg),
mark_abi_tags_r, &val);
}
}
/* Check that T has all the ABI tags that subobject SUBOB has, or
warn if not. If T is a (variable or function) declaration, also
return any missing tags, and add them to T if JUST_CHECKING is false. */
static tree
check_abi_tags (tree t, tree subob, bool just_checking = false)
{
bool inherit = DECL_P (t);
if (!inherit && !warn_abi_tag)
return NULL_TREE;
tree decl = TYPE_P (t) ? TYPE_NAME (t) : t;
if (!TREE_PUBLIC (decl))
/* No need to worry about things local to this TU. */
return NULL_TREE;
mark_abi_tags (t, true);
tree subtype = TYPE_P (subob) ? subob : TREE_TYPE (subob);
struct abi_tag_data data = { t, subob, error_mark_node };
if (inherit)
data.tags = NULL_TREE;
cp_walk_tree_without_duplicates (&subtype, find_abi_tags_r, &data);
if (!(inherit && data.tags))
/* We don't need to do anything with data.tags. */;
else if (just_checking)
for (tree t = data.tags; t; t = TREE_CHAIN (t))
{
tree id = get_identifier (TREE_STRING_POINTER (TREE_VALUE (t)));
IDENTIFIER_MARKED (id) = false;
}
else
{
tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
if (attr)
TREE_VALUE (attr) = chainon (data.tags, TREE_VALUE (attr));
else
DECL_ATTRIBUTES (t)
= tree_cons (abi_tag_identifier, data.tags, DECL_ATTRIBUTES (t));
}
mark_abi_tags (t, false);
return data.tags;
}
/* Check that DECL has all the ABI tags that are used in parts of its type
that are not reflected in its mangled name. */
void
check_abi_tags (tree decl)
{
if (VAR_P (decl))
check_abi_tags (decl, TREE_TYPE (decl));
else if (TREE_CODE (decl) == FUNCTION_DECL
&& !DECL_CONV_FN_P (decl)
&& !mangle_return_type_p (decl))
check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)));
}
/* Return any ABI tags that are used in parts of the type of DECL
that are not reflected in its mangled name. This function is only
used in backward-compatible mangling for ABI <11. */
tree
missing_abi_tags (tree decl)
{
if (VAR_P (decl))
return check_abi_tags (decl, TREE_TYPE (decl), true);
else if (TREE_CODE (decl) == FUNCTION_DECL
/* Don't check DECL_CONV_FN_P here like we do in check_abi_tags, so
that we can use this function for setting need_abi_warning
regardless of the current flag_abi_version. */
&& !mangle_return_type_p (decl))
return check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)), true);
else
return NULL_TREE;
}
void
inherit_targ_abi_tags (tree t)
{
if (!CLASS_TYPE_P (t)
|| CLASSTYPE_TEMPLATE_INFO (t) == NULL_TREE)
return;
mark_abi_tags (t, true);
tree args = CLASSTYPE_TI_ARGS (t);
struct abi_tag_data data = { t, NULL_TREE, NULL_TREE };
for (int i = 0; i < TMPL_ARGS_DEPTH (args); ++i)
{
tree level = TMPL_ARGS_LEVEL (args, i+1);
for (int j = 0; j < TREE_VEC_LENGTH (level); ++j)
{
tree arg = TREE_VEC_ELT (level, j);
data.subob = arg;
cp_walk_tree_without_duplicates (&arg, find_abi_tags_r, &data);
}
}
// If we found some tags on our template arguments, add them to our
// abi_tag attribute.
if (data.tags)
{
tree attr = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t));
if (attr)
TREE_VALUE (attr) = chainon (data.tags, TREE_VALUE (attr));
else
TYPE_ATTRIBUTES (t)
= tree_cons (abi_tag_identifier, data.tags, TYPE_ATTRIBUTES (t));
}
mark_abi_tags (t, false);
}
/* Return true, iff class T has a non-virtual destructor that is
accessible from outside the class heirarchy (i.e. is public, or
there's a suitable friend. */
static bool
accessible_nvdtor_p (tree t)
{
tree dtor = CLASSTYPE_DESTRUCTOR (t);
/* An implicitly declared destructor is always public. And,
if it were virtual, we would have created it by now. */
if (!dtor)
return true;
if (DECL_VINDEX (dtor))
return false; /* Virtual */
if (!TREE_PRIVATE (dtor) && !TREE_PROTECTED (dtor))
return true; /* Public */
if (CLASSTYPE_FRIEND_CLASSES (t)
|| DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))
return true; /* Has friends */
return false;
}
/* Run through the base classes of T, updating CANT_HAVE_CONST_CTOR_P,
and NO_CONST_ASN_REF_P. Also set flag bits in T based on
properties of the bases. */
static void
check_bases (tree t,
int* cant_have_const_ctor_p,
int* no_const_asn_ref_p)
{
int i;
bool seen_non_virtual_nearly_empty_base_p = 0;
int seen_tm_mask = 0;
tree base_binfo;
tree binfo;
tree field = NULL_TREE;
if (!CLASSTYPE_NON_STD_LAYOUT (t))
for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
break;
for (binfo = TYPE_BINFO (t), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
tree basetype = TREE_TYPE (base_binfo);
gcc_assert (COMPLETE_TYPE_P (basetype));
if (CLASSTYPE_FINAL (basetype))
error ("cannot derive from %<final%> base %qT in derived type %qT",
basetype, t);
/* If any base class is non-literal, so is the derived class. */
if (!CLASSTYPE_LITERAL_P (basetype))
CLASSTYPE_LITERAL_P (t) = false;
/* If the base class doesn't have copy constructors or
assignment operators that take const references, then the
derived class cannot have such a member automatically
generated. */
if (TYPE_HAS_COPY_CTOR (basetype)
&& ! TYPE_HAS_CONST_COPY_CTOR (basetype))
*cant_have_const_ctor_p = 1;
if (TYPE_HAS_COPY_ASSIGN (basetype)
&& !TYPE_HAS_CONST_COPY_ASSIGN (basetype))
*no_const_asn_ref_p = 1;
if (BINFO_VIRTUAL_P (base_binfo))
/* A virtual base does not effect nearly emptiness. */
;
else if (CLASSTYPE_NEARLY_EMPTY_P (basetype))
{
if (seen_non_virtual_nearly_empty_base_p)
/* And if there is more than one nearly empty base, then the
derived class is not nearly empty either. */
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
else
/* Remember we've seen one. */
seen_non_virtual_nearly_empty_base_p = 1;
}
else if (!is_empty_class (basetype))
/* If the base class is not empty or nearly empty, then this
class cannot be nearly empty. */
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
/* A lot of properties from the bases also apply to the derived
class. */
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
|= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype);
TYPE_HAS_COMPLEX_COPY_ASSIGN (t)
|= (TYPE_HAS_COMPLEX_COPY_ASSIGN (basetype)
|| !TYPE_HAS_COPY_ASSIGN (basetype));
TYPE_HAS_COMPLEX_COPY_CTOR (t) |= (TYPE_HAS_COMPLEX_COPY_CTOR (basetype)
|| !TYPE_HAS_COPY_CTOR (basetype));
TYPE_HAS_COMPLEX_MOVE_ASSIGN (t)
|= TYPE_HAS_COMPLEX_MOVE_ASSIGN (basetype);
TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR (basetype);
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_DEFAULT_CONSTRUCTOR (basetype)
|| TYPE_HAS_COMPLEX_DFLT (basetype));
SET_CLASSTYPE_READONLY_FIELDS_NEED_INIT
(t, CLASSTYPE_READONLY_FIELDS_NEED_INIT (t)
| CLASSTYPE_READONLY_FIELDS_NEED_INIT (basetype));
SET_CLASSTYPE_REF_FIELDS_NEED_INIT
(t, CLASSTYPE_REF_FIELDS_NEED_INIT (t)
| CLASSTYPE_REF_FIELDS_NEED_INIT (basetype));
if (TYPE_HAS_MUTABLE_P (basetype))
CLASSTYPE_HAS_MUTABLE (t) = 1;
/* A standard-layout class is a class that:
...
* has no non-standard-layout base classes, */
CLASSTYPE_NON_STD_LAYOUT (t) |= CLASSTYPE_NON_STD_LAYOUT (basetype);
if (!CLASSTYPE_NON_STD_LAYOUT (t))
{
tree basefield;
/* ...has no base classes of the same type as the first non-static
data member... */
if (field && DECL_CONTEXT (field) == t
&& (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (field), basetype)))
CLASSTYPE_NON_STD_LAYOUT (t) = 1;
/* DR 1813:
...has at most one base class subobject of any given type... */
else if (CLASSTYPE_REPEATED_BASE_P (t))
CLASSTYPE_NON_STD_LAYOUT (t) = 1;
else
/* ...has all non-static data members and bit-fields in the class
and its base classes first declared in the same class. */
for (basefield = TYPE_FIELDS (basetype); basefield;
basefield = DECL_CHAIN (basefield))
if (TREE_CODE (basefield) == FIELD_DECL
&& !(DECL_FIELD_IS_BASE (basefield)
&& is_empty_field (basefield)))
{
if (field)
CLASSTYPE_NON_STD_LAYOUT (t) = 1;
else
field = basefield;
break;
}
}
/* Don't bother collecting tm attributes if transactional memory
support is not enabled. */
if (flag_tm)
{
tree tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (basetype));
if (tm_attr)
seen_tm_mask |= tm_attr_to_mask (tm_attr);
}
check_abi_tags (t, basetype);
}
/* If one of the base classes had TM attributes, and the current class
doesn't define its own, then the current class inherits one. */
if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t)))
{
tree tm_attr = tm_mask_to_attr (least_bit_hwi (seen_tm_mask));
TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t));
}
}
/* Determine all the primary bases within T. Sets BINFO_PRIMARY_BASE_P for
those that are primaries. Sets BINFO_LOST_PRIMARY_P for those
that have had a nearly-empty virtual primary base stolen by some
other base in the hierarchy. Determines CLASSTYPE_PRIMARY_BASE for
T. */
static void
determine_primary_bases (tree t)
{
unsigned i;
tree primary = NULL_TREE;
tree type_binfo = TYPE_BINFO (t);
tree base_binfo;
/* Determine the primary bases of our bases. */
for (base_binfo = TREE_CHAIN (type_binfo); base_binfo;
base_binfo = TREE_CHAIN (base_binfo))
{
tree primary = CLASSTYPE_PRIMARY_BINFO (BINFO_TYPE (base_binfo));
/* See if we're the non-virtual primary of our inheritance
chain. */
if (!BINFO_VIRTUAL_P (base_binfo))
{
tree parent = BINFO_INHERITANCE_CHAIN (base_binfo);
tree parent_primary = CLASSTYPE_PRIMARY_BINFO (BINFO_TYPE (parent));
if (parent_primary
&& SAME_BINFO_TYPE_P (BINFO_TYPE (base_binfo),
BINFO_TYPE (parent_primary)))
/* We are the primary binfo. */
BINFO_PRIMARY_P (base_binfo) = 1;
}
/* Determine if we have a virtual primary base, and mark it so.
*/
if (primary && BINFO_VIRTUAL_P (primary))
{
tree this_primary = copied_binfo (primary, base_binfo);
if (BINFO_PRIMARY_P (this_primary))
/* Someone already claimed this base. */
BINFO_LOST_PRIMARY_P (base_binfo) = 1;
else
{
tree delta;
BINFO_PRIMARY_P (this_primary) = 1;
BINFO_INHERITANCE_CHAIN (this_primary) = base_binfo;
/* A virtual binfo might have been copied from within
another hierarchy. As we're about to use it as a
primary base, make sure the offsets match. */
delta = size_diffop_loc (input_location,
fold_convert (ssizetype,
BINFO_OFFSET (base_binfo)),
fold_convert (ssizetype,
BINFO_OFFSET (this_primary)));
propagate_binfo_offsets (this_primary, delta);
}
}
}
/* First look for a dynamic direct non-virtual base. */
for (i = 0; BINFO_BASE_ITERATE (type_binfo, i, base_binfo); i++)
{
tree basetype = BINFO_TYPE (base_binfo);
if (TYPE_CONTAINS_VPTR_P (basetype) && !BINFO_VIRTUAL_P (base_binfo))
{
primary = base_binfo;
goto found;
}
}
/* A "nearly-empty" virtual base class can be the primary base
class, if no non-virtual polymorphic base can be found. Look for
a nearly-empty virtual dynamic base that is not already a primary
base of something in the hierarchy. If there is no such base,
just pick the first nearly-empty virtual base. */
for (base_binfo = TREE_CHAIN (type_binfo); base_binfo;
base_binfo = TREE_CHAIN (base_binfo))
if (BINFO_VIRTUAL_P (base_binfo)
&& CLASSTYPE_NEARLY_EMPTY_P (BINFO_TYPE (base_binfo)))
{
if (!BINFO_PRIMARY_P (base_binfo))
{
/* Found one that is not primary. */
primary = base_binfo;
goto found;
}
else if (!primary)
/* Remember the first candidate. */
primary = base_binfo;
}
found:
/* If we've got a primary base, use it. */
if (primary)
{
tree basetype = BINFO_TYPE (primary);
CLASSTYPE_PRIMARY_BINFO (t) = primary;
if (BINFO_PRIMARY_P (primary))
/* We are stealing a primary base. */
BINFO_LOST_PRIMARY_P (BINFO_INHERITANCE_CHAIN (primary)) = 1;
BINFO_PRIMARY_P (primary) = 1;
if (BINFO_VIRTUAL_P (primary))
{
tree delta;
BINFO_INHERITANCE_CHAIN (primary) = type_binfo;
/* A virtual binfo might have been copied from within
another hierarchy. As we're about to use it as a primary
base, make sure the offsets match. */
delta = size_diffop_loc (input_location, ssize_int (0),
fold_convert (ssizetype, BINFO_OFFSET (primary)));
propagate_binfo_offsets (primary, delta);
}
primary = TYPE_BINFO (basetype);
TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
BINFO_VTABLE (type_binfo) = BINFO_VTABLE (primary);
BINFO_VIRTUALS (type_binfo) = BINFO_VIRTUALS (primary);
}
}
/* Update the variant types of T. */
void
fixup_type_variants (tree type)
{
if (!type)
return;
for (tree variant = TYPE_NEXT_VARIANT (type);
variant;
variant = TYPE_NEXT_VARIANT (variant))
{
/* These fields are in the _TYPE part of the node, not in
the TYPE_LANG_SPECIFIC component, so they are not shared. */
TYPE_HAS_USER_CONSTRUCTOR (variant) = TYPE_HAS_USER_CONSTRUCTOR (type);
TYPE_NEEDS_CONSTRUCTING (variant) = TYPE_NEEDS_CONSTRUCTING (type);
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variant)
= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
TYPE_POLYMORPHIC_P (variant) = TYPE_POLYMORPHIC_P (type);
CLASSTYPE_FINAL (variant) = CLASSTYPE_FINAL (type);
TYPE_BINFO (variant) = TYPE_BINFO (type);
/* Copy whatever these are holding today. */
TYPE_VFIELD (variant) = TYPE_VFIELD (type);
TYPE_FIELDS (variant) = TYPE_FIELDS (type);
TYPE_SIZE (variant) = TYPE_SIZE (type);
TYPE_SIZE_UNIT (variant) = TYPE_SIZE_UNIT (type);
if (!TYPE_USER_ALIGN (variant)
|| TYPE_NAME (variant) == TYPE_NAME (type)
|| TYPE_ALIGN_RAW (variant) < TYPE_ALIGN_RAW (type))
{
TYPE_ALIGN_RAW (variant) = TYPE_ALIGN_RAW (type);
TYPE_USER_ALIGN (variant) = TYPE_USER_ALIGN (type);
}
TYPE_PRECISION (variant) = TYPE_PRECISION (type);
TYPE_MODE_RAW (variant) = TYPE_MODE_RAW (type);
TYPE_EMPTY_P (variant) = TYPE_EMPTY_P (type);
}
}
/* KLASS is a class that we're applying may_alias to after the body is
parsed. Fixup any POINTER_TO and REFERENCE_TO types. The
canonical type(s) will be implicitly updated. */
static void
fixup_may_alias (tree klass)
{
tree t, v;
for (t = TYPE_POINTER_TO (klass); t; t = TYPE_NEXT_PTR_TO (t))
for (v = TYPE_MAIN_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
TYPE_REF_CAN_ALIAS_ALL (v) = true;
for (t = TYPE_REFERENCE_TO (klass); t; t = TYPE_NEXT_REF_TO (t))
for (v = TYPE_MAIN_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
TYPE_REF_CAN_ALIAS_ALL (v) = true;
}
/* Early variant fixups: we apply attributes at the beginning of the class
definition, and we need to fix up any variants that have already been
made via elaborated-type-specifier so that check_qualified_type works. */
void
fixup_attribute_variants (tree t)
{
tree variants;
if (!t)
return;
tree attrs = TYPE_ATTRIBUTES (t);
unsigned align = TYPE_ALIGN (t);
bool user_align = TYPE_USER_ALIGN (t);
bool may_alias = lookup_attribute ("may_alias", attrs);
bool packed = TYPE_PACKED (t);
if (may_alias)
fixup_may_alias (t);
for (variants = TYPE_NEXT_VARIANT (t);
variants;
variants = TYPE_NEXT_VARIANT (variants))
{
/* These are the two fields that check_qualified_type looks at and
are affected by attributes. */
TYPE_ATTRIBUTES (variants) = attrs;
unsigned valign = align;
if (TYPE_USER_ALIGN (variants))
valign = MAX (valign, TYPE_ALIGN (variants));
else
TYPE_USER_ALIGN (variants) = user_align;
SET_TYPE_ALIGN (variants, valign);
TYPE_PACKED (variants) = packed;
if (may_alias)
fixup_may_alias (variants);
}
}
/* Set memoizing fields and bits of T (and its variants) for later
use. */
static void
finish_struct_bits (tree t)
{
/* Fix up variants (if any). */
fixup_type_variants (t);
if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) && TYPE_POLYMORPHIC_P (t))
/* For a class w/o baseclasses, 'finish_struct' has set
CLASSTYPE_PURE_VIRTUALS correctly (by definition).
Similarly for a class whose base classes do not have vtables.
When neither of these is true, we might have removed abstract
virtuals (by providing a definition), added some (by declaring
new ones), or redeclared ones from a base class. We need to
recalculate what's really an abstract virtual at this point (by
looking in the vtables). */
get_pure_virtuals (t);
/* If this type has a copy constructor or a destructor, force its
mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be
nonzero. This will cause it to be passed by invisible reference
and prevent it from being returned in a register. */
if (type_has_nontrivial_copy_init (t)
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
{
tree variants;
SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode);
for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))
{
SET_TYPE_MODE (variants, BLKmode);
TREE_ADDRESSABLE (variants) = 1;
}
}
}
/* Issue warnings about T having private constructors, but no friends,
and so forth.
HAS_NONPRIVATE_METHOD is nonzero if T has any non-private methods or
static members. HAS_NONPRIVATE_STATIC_FN is nonzero if T has any
non-private static member functions. */
static void
maybe_warn_about_overly_private_class (tree t)
{
int has_member_fn = 0;
int has_nonprivate_method = 0;
bool nonprivate_ctor = false;
if (!warn_ctor_dtor_privacy
/* If the class has friends, those entities might create and
access instances, so we should not warn. */
|| (CLASSTYPE_FRIEND_CLASSES (t)
|| DECL_FRIENDLIST (TYPE_MAIN_DECL (t)))
/* We will have warned when the template was declared; there's
no need to warn on every instantiation. */
|| CLASSTYPE_TEMPLATE_INSTANTIATION (t))
/* There's no reason to even consider warning about this
class. */
return;
/* We only issue one warning, if more than one applies, because
otherwise, on code like:
class A {
// Oops - forgot `public:'
A();
A(const A&);
~A();
};
we warn several times about essentially the same problem. */
/* Check to see if all (non-constructor, non-destructor) member
functions are private. (Since there are no friends or
non-private statics, we can't ever call any of the private member
functions.) */
for (tree fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn))
if (TREE_CODE (fn) == USING_DECL
&& DECL_NAME (fn) == ctor_identifier
&& !TREE_PRIVATE (fn))
nonprivate_ctor = true;
else if (!DECL_DECLARES_FUNCTION_P (fn))
/* Not a function. */;
else if (DECL_ARTIFICIAL (fn))
/* We're not interested in compiler-generated methods; they don't
provide any way to call private members. */;
else if (!TREE_PRIVATE (fn))
{
if (DECL_STATIC_FUNCTION_P (fn))
/* A non-private static member function is just like a
friend; it can create and invoke private member
functions, and be accessed without a class
instance. */
return;
has_nonprivate_method = 1;
/* Keep searching for a static member function. */
}
else if (!DECL_CONSTRUCTOR_P (fn) && !DECL_DESTRUCTOR_P (fn))
has_member_fn = 1;
if (!has_nonprivate_method && has_member_fn)
{
/* There are no non-private methods, and there's at least one
private member function that isn't a constructor or
destructor. (If all the private members are
constructors/destructors we want to use the code below that
issues error messages specifically referring to
constructors/destructors.) */
unsigned i;
tree binfo = TYPE_BINFO (t);
for (i = 0; i != BINFO_N_BASE_BINFOS (binfo); i++)
if (BINFO_BASE_ACCESS (binfo, i) != access_private_node)
{
has_nonprivate_method = 1;
break;
}
if (!has_nonprivate_method)
{
warning (OPT_Wctor_dtor_privacy,
"all member functions in class %qT are private", t);
return;
}
}
/* Even if some of the member functions are non-private, the class
won't be useful for much if all the constructors or destructors
are private: such an object can never be created or destroyed. */
if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
if (TREE_PRIVATE (dtor))
{
warning (OPT_Wctor_dtor_privacy,
"%q#T only defines a private destructor and has no friends",
t);
return;
}
/* Warn about classes that have private constructors and no friends. */
if (TYPE_HAS_USER_CONSTRUCTOR (t)
/* Implicitly generated constructors are always public. */
&& !CLASSTYPE_LAZY_DEFAULT_CTOR (t))
{
tree copy_or_move = NULL_TREE;
/* If a non-template class does not define a copy
constructor, one is defined for it, enabling it to avoid
this warning. For a template class, this does not
happen, and so we would normally get a warning on:
template <class T> class C { private: C(); };
To avoid this asymmetry, we check TYPE_HAS_COPY_CTOR. All
complete non-template or fully instantiated classes have this
flag set. */
if (!TYPE_HAS_COPY_CTOR (t))
nonprivate_ctor = true;
else
for (tree fn : ovl_range (CLASSTYPE_CONSTRUCTORS (t)))
if (TREE_PRIVATE (fn))
continue;
else if (copy_fn_p (fn) || move_fn_p (fn))
/* Ideally, we wouldn't count any constructor that takes
an argument of the class type as a parameter, because
such things cannot be used to construct an instance of
the class unless you already have one. */
copy_or_move = fn;
else
{
nonprivate_ctor = true;
break;
}
if (!nonprivate_ctor)
{
bool w = warning (OPT_Wctor_dtor_privacy,
"%q#T only defines private constructors and has "
"no friends", t);
if (w && copy_or_move)
inform (DECL_SOURCE_LOCATION (copy_or_move),
"%q#D is public, but requires an existing %q#T object",
copy_or_move, t);
return;
}
}
}
/* Make BINFO's vtable have N entries, including RTTI entries,
vbase and vcall offsets, etc. Set its type and call the back end
to lay it out. */
static void
layout_vtable_decl (tree binfo, int n)
{
tree atype;
tree vtable;
atype = build_array_of_n_type (vtable_entry_type, n);
layout_type (atype);
/* We may have to grow the vtable. */
vtable = get_vtbl_decl_for_binfo (binfo);
if (!same_type_p (TREE_TYPE (vtable), atype))
{
TREE_TYPE (vtable) = atype;
DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;
layout_decl (vtable, 0);
}
}
/* True iff FNDECL and BASE_FNDECL (both non-static member functions)
have the same signature. */
int
same_signature_p (const_tree fndecl, const_tree base_fndecl)
{
/* One destructor overrides another if they are the same kind of
destructor. */
if (DECL_DESTRUCTOR_P (base_fndecl) && DECL_DESTRUCTOR_P (fndecl)
&& special_function_p (base_fndecl) == special_function_p (fndecl))
return 1;
/* But a non-destructor never overrides a destructor, nor vice
versa, nor do different kinds of destructors override
one-another. For example, a complete object destructor does not
override a deleting destructor. */
if (DECL_DESTRUCTOR_P (base_fndecl) || DECL_DESTRUCTOR_P (fndecl))
return 0;
if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl)
|| (DECL_CONV_FN_P (fndecl)
&& DECL_CONV_FN_P (base_fndecl)
&& same_type_p (DECL_CONV_FN_TYPE (fndecl),
DECL_CONV_FN_TYPE (base_fndecl))))
{
tree fntype = TREE_TYPE (fndecl);
tree base_fntype = TREE_TYPE (base_fndecl);
if (type_memfn_quals (fntype) == type_memfn_quals (base_fntype)
&& type_memfn_rqual (fntype) == type_memfn_rqual (base_fntype)
&& compparms (FUNCTION_FIRST_USER_PARMTYPE (fndecl),
FUNCTION_FIRST_USER_PARMTYPE (base_fndecl)))
return 1;
}
return 0;
}
/* Returns TRUE if DERIVED is a binfo containing the binfo BASE as a
subobject. */
static bool
base_derived_from (tree derived, tree base)
{
tree probe;
for (probe = base; probe; probe = BINFO_INHERITANCE_CHAIN (probe))
{
if (probe == derived)
return true;
else if (BINFO_VIRTUAL_P (probe))
/* If we meet a virtual base, we can't follow the inheritance
any more. See if the complete type of DERIVED contains
such a virtual base. */
return (binfo_for_vbase (BINFO_TYPE (probe), BINFO_TYPE (derived))
!= NULL_TREE);
}
return false;
}
struct find_final_overrider_data {
/* The function for which we are trying to find a final overrider. */
tree fn;
/* The base class in which the function was declared. */
tree declaring_base;
/* The candidate overriders. */
tree candidates;
/* Path to most derived. */
auto_vec<tree> path;
};
/* Add the overrider along the current path to FFOD->CANDIDATES.
Returns true if an overrider was found; false otherwise. */
static bool
dfs_find_final_overrider_1 (tree binfo,
find_final_overrider_data *ffod,
unsigned depth)
{
tree method;
/* If BINFO is not the most derived type, try a more derived class.
A definition there will overrider a definition here. */
if (depth)
{
depth--;
if (dfs_find_final_overrider_1
(ffod->path[depth], ffod, depth))
return true;
}
method = look_for_overrides_here (BINFO_TYPE (binfo), ffod->fn);
if (method)
{
tree *candidate = &ffod->candidates;
/* Remove any candidates overridden by this new function. */
while (*candidate)
{
/* If *CANDIDATE overrides METHOD, then METHOD
cannot override anything else on the list. */
if (base_derived_from (TREE_VALUE (*candidate), binfo))
return true;
/* If METHOD overrides *CANDIDATE, remove *CANDIDATE. */
if (base_derived_from (binfo, TREE_VALUE (*candidate)))
*candidate = TREE_CHAIN (*candidate);
else
candidate = &TREE_CHAIN (*candidate);
}
/* Add the new function. */
ffod->candidates = tree_cons (method, binfo, ffod->candidates);
return true;
}
return false;
}
/* Called from find_final_overrider via dfs_walk. */
static tree
dfs_find_final_overrider_pre (tree binfo, void *data)
{
find_final_overrider_data *ffod = (find_final_overrider_data *) data;
if (binfo == ffod->declaring_base)
dfs_find_final_overrider_1 (binfo, ffod, ffod->path.length ());
ffod->path.safe_push (binfo);
return NULL_TREE;
}
static tree
dfs_find_final_overrider_post (tree /*binfo*/, void *data)
{
find_final_overrider_data *ffod = (find_final_overrider_data *) data;
ffod->path.pop ();
return NULL_TREE;
}
/* Returns a TREE_LIST whose TREE_PURPOSE is the final overrider for
FN and whose TREE_VALUE is the binfo for the base where the
overriding occurs. BINFO (in the hierarchy dominated by the binfo
DERIVED) is the base object in which FN is declared. */
static tree
find_final_overrider (tree derived, tree binfo, tree fn)
{
find_final_overrider_data ffod;
/* Getting this right is a little tricky. This is valid:
struct S { virtual void f (); };
struct T { virtual void f (); };
struct U : public S, public T { };
even though calling `f' in `U' is ambiguous. But,
struct R { virtual void f(); };
struct S : virtual public R { virtual void f (); };
struct T : virtual public R { virtual void f (); };
struct U : public S, public T { };
is not -- there's no way to decide whether to put `S::f' or
`T::f' in the vtable for `R'.
The solution is to look at all paths to BINFO. If we find
different overriders along any two, then there is a problem. */
if (DECL_THUNK_P (fn))
fn = THUNK_TARGET (fn);
/* Determine the depth of the hierarchy. */
ffod.fn = fn;
ffod.declaring_base = binfo;
ffod.candidates = NULL_TREE;
ffod.path.create (30);
dfs_walk_all (derived, dfs_find_final_overrider_pre,
dfs_find_final_overrider_post, &ffod);
/* If there was no winner, issue an error message. */
if (!ffod.candidates || TREE_CHAIN (ffod.candidates))
return error_mark_node;
return ffod.candidates;
}
/* Return the index of the vcall offset for FN when TYPE is used as a
virtual base. */
static tree
get_vcall_index (tree fn, tree type)
{
vec<tree_pair_s, va_gc> *indices = CLASSTYPE_VCALL_INDICES (type);
tree_pair_p p;
unsigned ix;
FOR_EACH_VEC_SAFE_ELT (indices, ix, p)
if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (p->purpose))
|| same_signature_p (fn, p->purpose))
return p->value;
/* There should always be an appropriate index. */
gcc_unreachable ();
}
/* Given a DECL_VINDEX of a virtual function found in BINFO, return the final
overrider at that index in the vtable. This should only be used when we
know that BINFO is correct for the dynamic type of the object. */
tree
lookup_vfn_in_binfo (tree idx, tree binfo)
{
int ix = tree_to_shwi (idx);
if (TARGET_VTABLE_USES_DESCRIPTORS)
ix /= MAX (TARGET_VTABLE_USES_DESCRIPTORS, 1);
while (BINFO_PRIMARY_P (binfo))
/* BINFO_VIRTUALS in a primary base isn't accurate, find the derived
class that actually owns the vtable. */
binfo = BINFO_INHERITANCE_CHAIN (binfo);
tree virtuals = BINFO_VIRTUALS (binfo);
return TREE_VALUE (chain_index (ix, virtuals));
}
/* Update an entry in the vtable for BINFO, which is in the hierarchy
dominated by T. FN is the old function; VIRTUALS points to the
corresponding position in the new BINFO_VIRTUALS list. IX is the index
of that entry in the list. */
static void
update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
unsigned ix)
{
tree b;
tree overrider;
tree delta;
tree virtual_base;
tree first_defn;
tree overrider_fn, overrider_target;
tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;
tree over_return, base_return;
bool lost = false;
/* Find the nearest primary base (possibly binfo itself) which defines
this function; this is the class the caller will convert to when
calling FN through BINFO. */
for (b = binfo; ; b = get_primary_binfo (b))
{
gcc_assert (b);
if (look_for_overrides_here (BINFO_TYPE (b), target_fn))
break;
/* The nearest definition is from a lost primary. */
if (BINFO_LOST_PRIMARY_P (b))
lost = true;
}
first_defn = b;
/* Find the final overrider. */
overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);
if (overrider == error_mark_node)
{
error ("no unique final overrider for %qD in %qT", target_fn, t);
return;
}
overrider_target = overrider_fn = TREE_PURPOSE (overrider);
/* Check for adjusting covariant return types. */
over_return = TREE_TYPE (TREE_TYPE (overrider_target));
base_return = TREE_TYPE (TREE_TYPE (target_fn));
if (INDIRECT_TYPE_P (over_return)
&& TREE_CODE (over_return) == TREE_CODE (base_return)
&& CLASS_TYPE_P (TREE_TYPE (over_return))
&& CLASS_TYPE_P (TREE_TYPE (base_return))
/* If the overrider is invalid, don't even try. */
&& !DECL_INVALID_OVERRIDER_P (overrider_target))
{
/* If FN is a covariant thunk, we must figure out the adjustment
to the final base FN was converting to. As OVERRIDER_TARGET might
also be converting to the return type of FN, we have to
combine the two conversions here. */
tree fixed_offset, virtual_offset;
over_return = TREE_TYPE (over_return);
base_return = TREE_TYPE (base_return);
if (DECL_THUNK_P (fn))
{
gcc_assert (DECL_RESULT_THUNK_P (fn));
fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
}
else
fixed_offset = virtual_offset = NULL_TREE;
if (virtual_offset)
/* Find the equivalent binfo within the return type of the
overriding function. We will want the vbase offset from
there. */
virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset),
over_return);
else if (!same_type_ignoring_top_level_qualifiers_p
(over_return, base_return))
{
/* There was no existing virtual thunk (which takes
precedence). So find the binfo of the base function's
return type within the overriding function's return type.
Fortunately we know the covariancy is valid (it
has already been checked), so we can just iterate along
the binfos, which have been chained in inheritance graph
order. Of course it is lame that we have to repeat the
search here anyway -- we should really be caching pieces
of the vtable and avoiding this repeated work. */
tree thunk_binfo = NULL_TREE;
tree base_binfo = TYPE_BINFO (base_return);
/* Find the base binfo within the overriding function's
return type. We will always find a thunk_binfo, except
when the covariancy is invalid (which we will have
already diagnosed). */
if (base_binfo)
for (thunk_binfo = TYPE_BINFO (over_return); thunk_binfo;
thunk_binfo = TREE_CHAIN (thunk_binfo))
if (SAME_BINFO_TYPE_P (BINFO_TYPE (thunk_binfo),
BINFO_TYPE (base_binfo)))
break;
gcc_assert (thunk_binfo || errorcount);
/* See if virtual inheritance is involved. */
for (virtual_offset = thunk_binfo;
virtual_offset;
virtual_offset = BINFO_INHERITANCE_CHAIN (virtual_offset))
if (BINFO_VIRTUAL_P (virtual_offset))
break;
if (virtual_offset
|| (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
{
tree offset = fold_convert (ssizetype, BINFO_OFFSET (thunk_binfo));
if (virtual_offset)
{
/* We convert via virtual base. Adjust the fixed
offset to be from there. */
offset =
size_diffop (offset,
fold_convert (ssizetype,
BINFO_OFFSET (virtual_offset)));
}
if (fixed_offset)
/* There was an existing fixed offset, this must be
from the base just converted to, and the base the
FN was thunking to. */
fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);
else
fixed_offset = offset;
}
}
if (fixed_offset || virtual_offset)
/* Replace the overriding function with a covariant thunk. We
will emit the overriding function in its own slot as
well. */
overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/0,
fixed_offset, virtual_offset);
}
else
gcc_assert (DECL_INVALID_OVERRIDER_P (overrider_target) ||
!DECL_THUNK_P (fn));
/* If we need a covariant thunk, then we may need to adjust first_defn.
The ABI specifies that the thunks emitted with a function are
determined by which bases the function overrides, so we need to be
sure that we're using a thunk for some overridden base; even if we
know that the necessary this adjustment is zero, there may not be an
appropriate zero-this-adjustment thunk for us to use since thunks for
overriding virtual bases always use the vcall offset.
Furthermore, just choosing any base that overrides this function isn't
quite right, as this slot won't be used for calls through a type that
puts a covariant thunk here. Calling the function through such a type
will use a different slot, and that slot is the one that determines
the thunk emitted for that base.
So, keep looking until we find the base that we're really overriding
in this slot: the nearest primary base that doesn't use a covariant
thunk in this slot. */
if (overrider_target != overrider_fn)
{
if (BINFO_TYPE (b) == DECL_CONTEXT (overrider_target))
/* We already know that the overrider needs a covariant thunk. */
b = get_primary_binfo (b);
for (; ; b = get_primary_binfo (b))
{
tree main_binfo = TYPE_BINFO (BINFO_TYPE (b));
tree bv = chain_index (ix, BINFO_VIRTUALS (main_binfo));
if (!DECL_THUNK_P (TREE_VALUE (bv)))
break;
if (BINFO_LOST_PRIMARY_P (b))
lost = true;
}
first_defn = b;
}
/* Assume that we will produce a thunk that convert all the way to
the final overrider, and not to an intermediate virtual base. */
virtual_base = NULL_TREE;
/* See if we can convert to an intermediate virtual base first, and then
use the vcall offset located there to finish the conversion. */
for (; b; b = BINFO_INHERITANCE_CHAIN (b))
{
/* If we find the final overrider, then we can stop
walking. */
if (SAME_BINFO_TYPE_P (BINFO_TYPE (b),
BINFO_TYPE (TREE_VALUE (overrider))))
break;
/* If we find a virtual base, and we haven't yet found the
overrider, then there is a virtual base between the
declaring base (first_defn) and the final overrider. */
if (BINFO_VIRTUAL_P (b))
{
virtual_base = b;
break;
}
}
/* Compute the constant adjustment to the `this' pointer. The
`this' pointer, when this function is called, will point at BINFO
(or one of its primary bases, which are at the same offset). */
if (virtual_base)
/* The `this' pointer needs to be adjusted from the declaration to
the nearest virtual base. */
delta = size_diffop_loc (input_location,
fold_convert (ssizetype, BINFO_OFFSET (virtual_base)),
fold_convert (ssizetype, BINFO_OFFSET (first_defn)));
else if (lost)
/* If the nearest definition is in a lost primary, we don't need an
entry in our vtable. Except possibly in a constructor vtable,
if we happen to get our primary back. In that case, the offset
will be zero, as it will be a primary base. */
delta = size_zero_node;
else
/* The `this' pointer needs to be adjusted from pointing to
BINFO to pointing at the base where the final overrider
appears. */
delta = size_diffop_loc (input_location,
fold_convert (ssizetype,
BINFO_OFFSET (TREE_VALUE (overrider))),
fold_convert (ssizetype, BINFO_OFFSET (binfo)));
modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
if (virtual_base)
BV_VCALL_INDEX (*virtuals)
= get_vcall_index (overrider_target, BINFO_TYPE (virtual_base));
else
BV_VCALL_INDEX (*virtuals) = NULL_TREE;
BV_LOST_PRIMARY (*virtuals) = lost;
}
/* Called from modify_all_vtables via dfs_walk. */
static tree
dfs_modify_vtables (tree binfo, void* data)
{
tree t = (tree) data;
tree virtuals;
tree old_virtuals;
unsigned ix;
if (!TYPE_CONTAINS_VPTR_P (BINFO_TYPE (binfo)))
/* A base without a vtable needs no modification, and its bases
are uninteresting. */
return dfs_skip_bases;
if (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), t)
&& !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
/* Don't do the primary vtable, if it's new. */
return NULL_TREE;
if (BINFO_PRIMARY_P (binfo) && !BINFO_VIRTUAL_P (binfo))
/* There's no need to modify the vtable for a non-virtual primary
base; we're not going to use that vtable anyhow. We do still
need to do this for virtual primary bases, as they could become
non-primary in a construction vtable. */
return NULL_TREE;
make_new_vtable (t, binfo);
/* Now, go through each of the virtual functions in the virtual
function table for BINFO. Find the final overrider, and update
the BINFO_VIRTUALS list appropriately. */
for (ix = 0, virtuals = BINFO_VIRTUALS (binfo),
old_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
virtuals;
ix++, virtuals = TREE_CHAIN (virtuals),
old_virtuals = TREE_CHAIN (old_virtuals))
update_vtable_entry_for_fn (t,
binfo,
BV_FN (old_virtuals),
&virtuals, ix);
return NULL_TREE;
}
/* Update all of the primary and secondary vtables for T. Create new
vtables as required, and initialize their RTTI information. Each
of the functions in VIRTUALS is declared in T and may override a
virtual function from a base class; find and modify the appropriate
entries to point to the overriding functions. Returns a list, in
declaration order, of the virtual functions that are declared in T,
but do not appear in the primary base class vtable, and which
should therefore be appended to the end of the vtable for T. */
static tree
modify_all_vtables (tree t, tree virtuals)
{
tree binfo = TYPE_BINFO (t);
tree *fnsp;
/* Mangle the vtable name before entering dfs_walk (c++/51884). */
if (TYPE_CONTAINS_VPTR_P (t))
get_vtable_decl (t, false);
/* Update all of the vtables. */
dfs_walk_once (binfo, dfs_modify_vtables, NULL, t);
/* Add virtual functions not already in our primary vtable. These
will be both those introduced by this class, and those overridden
from secondary bases. It does not include virtuals merely
inherited from secondary bases. */
for (fnsp = &virtuals; *fnsp; )
{
tree fn = TREE_VALUE (*fnsp);
if (!value_member (fn, BINFO_VIRTUALS (binfo))
|| DECL_VINDEX (fn) == error_mark_node)
{
/* We don't need to adjust the `this' pointer when
calling this function. */
BV_DELTA (*fnsp) = integer_zero_node;
BV_VCALL_INDEX (*fnsp) = NULL_TREE;
/* This is a function not already in our vtable. Keep it. */
fnsp = &TREE_CHAIN (*fnsp);
}
else
/* We've already got an entry for this function. Skip it. */
*fnsp = TREE_CHAIN (*fnsp);
}
return virtuals;
}
/* Get the base virtual function declarations in T that have the
indicated NAME. */
static void
get_basefndecls (tree name, tree t, vec<tree> *base_fndecls)
{
bool found_decls = false;
/* Find virtual functions in T with the indicated NAME. */
for (tree method : ovl_range (get_class_binding (t, name)))
{
if (TREE_CODE (method) == FUNCTION_DECL && DECL_VINDEX (method))
{
base_fndecls->safe_push (method);
found_decls = true;