summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2000-05-27 02:43:50 +0000
committerobrien <obrien@FreeBSD.org>2000-05-27 02:43:50 +0000
commit797ccd6333f01cbf4e77f65a6400e825d04257cd (patch)
tree63fe65f03181fdf1e4e58df8070a9c2001b37e3d /contrib
parent2213994dde95f9976af97c2acabf8054049ba10a (diff)
downloadFreeBSD-src-797ccd6333f01cbf4e77f65a6400e825d04257cd.zip
FreeBSD-src-797ccd6333f01cbf4e77f65a6400e825d04257cd.tar.gz
Fix conflicts.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/gcc/cp/decl.c617
-rw-r--r--contrib/gcc/cp/gxxint.texi233
-rw-r--r--contrib/gcc/function.c59
-rw-r--r--contrib/gcc/invoke.texi18
4 files changed, 669 insertions, 258 deletions
diff --git a/contrib/gcc/cp/decl.c b/contrib/gcc/cp/decl.c
index 79e0d97..113d4b5 100644
--- a/contrib/gcc/cp/decl.c
+++ b/contrib/gcc/cp/decl.c
@@ -190,6 +190,8 @@ static tree record_builtin_java_type PROTO((const char *, int));
static const char *tag_name PROTO((enum tag_types code));
static void find_class_binding_level PROTO((void));
static struct binding_level *innermost_nonclass_level PROTO((void));
+static void finish_dtor PROTO((void));
+static void finish_ctor PROTO((int));
static tree poplevel_class PROTO((void));
static void warn_about_implicit_typename_lookup PROTO((tree, tree));
static int walk_namespaces_r PROTO((tree, walk_namespaces_fn, void *));
@@ -337,6 +339,15 @@ tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type;
tree __ptmf_desc_array_type, __ptmd_desc_array_type;
#endif
+/* This is the identifier __vlist. */
+tree vlist_identifier;
+
+/* This is the type _Vlist = vtable_entry_type**. */
+tree vlist_type_node;
+
+/* A null pointer of type _Vlist. */
+tree vlist_zero_node;
+
/* Indicates that there is a type value in some namespace, although
that is not necessarily in scope at the moment. */
@@ -6285,6 +6296,7 @@ init_decl_processing ()
this_identifier = get_identifier (THIS_NAME);
in_charge_identifier = get_identifier (IN_CHARGE_NAME);
+ vlist_identifier = get_identifier (VLIST_NAME);
ctor_identifier = get_identifier (CTOR_NAME);
dtor_identifier = get_identifier (DTOR_NAME);
pfn_identifier = get_identifier (VTABLE_PFN_NAME);
@@ -6512,6 +6524,7 @@ init_decl_processing ()
#if 0
record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
#endif
+
endlink = void_list_node;
int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
@@ -6851,6 +6864,16 @@ init_decl_processing ()
layout_type (vtbl_ptr_type_node);
record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_type_node);
+ if (flag_vtable_thunks)
+ {
+ /* We need vlists only when using thunks; otherwise leave them
+ as NULL_TREE. That way, it doesn't get into the way of the
+ mangling. */
+ vlist_type_node = build_pointer_type (vtbl_ptr_type_node);
+ vlist_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (vlist_zero_node) = vlist_type_node;
+ }
+
/* Simplify life by making a "sigtable_entry_type". Give its
fields names so that the debugger can use them. */
@@ -11388,6 +11411,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (decl)))
arg_types = TREE_CHAIN (arg_types);
+ /* And the `vlist' argument. */
+ if (TYPE_USES_PVBASES (DECL_CONTEXT (decl)))
+ arg_types = TREE_CHAIN (arg_types);
+
if (arg_types == void_list_node
|| (arg_types
&& TREE_CHAIN (arg_types)
@@ -12082,6 +12109,9 @@ replace_defarg (arg, init)
TREE_PURPOSE (arg) = init;
}
+/* Return 1 if D copies its arguments. This is used to test for copy
+ constructors and copy assignment operators. */
+
int
copy_args_p (d)
tree d;
@@ -12089,7 +12119,12 @@ copy_args_p (d)
tree t = FUNCTION_ARG_CHAIN (d);
if (DECL_CONSTRUCTOR_P (d)
&& TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d)))
- t = TREE_CHAIN (t);
+ {
+ t = TREE_CHAIN (t);
+ if (TYPE_USES_PVBASES (DECL_CONTEXT (d)))
+ t = TREE_CHAIN (t);
+ }
+
if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t)))
== DECL_CLASS_CONTEXT (d))
@@ -12119,7 +12154,8 @@ grok_ctor_properties (ctype, decl)
added to any ctor so we can tell if the class has been initialized
yet. This could screw things up in this function, so we deliberately
ignore the leading int if we're in that situation. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (ctype))
+ if (TYPE_USES_VIRTUAL_BASECLASSES (ctype)
+ && !CLASSTYPE_IS_TEMPLATE (ctype))
{
my_friendly_assert (parmtypes
&& TREE_VALUE (parmtypes) == integer_type_node,
@@ -12128,6 +12164,15 @@ grok_ctor_properties (ctype, decl)
parmtype = TREE_VALUE (parmtypes);
}
+ if (TYPE_USES_PVBASES (ctype))
+ {
+ my_friendly_assert (parmtypes
+ && TREE_VALUE (parmtypes) == vlist_type_node,
+ 980529);
+ parmtypes = TREE_CHAIN (parmtypes);
+ parmtype = TREE_VALUE (parmtypes);
+ }
+
/* [class.copy]
A non-template constructor for class X is a copy constructor if
@@ -12925,6 +12970,16 @@ xref_basetypes (code_type_node, name, ref, binfo)
{
TYPE_USES_VIRTUAL_BASECLASSES (ref) = 1;
TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
+ /* The PVBASES flag is never set for templates; we know
+ only for instantiations whether the virtual bases are
+ polymorphic. */
+ if (flag_vtable_thunks >= 2 && !CLASSTYPE_IS_TEMPLATE (ref))
+ {
+ if (via_virtual && TYPE_VIRTUAL_P (basetype))
+ TYPE_USES_PVBASES (ref) = 1;
+ else if (TYPE_USES_PVBASES (basetype))
+ TYPE_USES_PVBASES (ref) = 1;
+ }
}
if (CLASS_TYPE_P (basetype))
@@ -13930,6 +13985,313 @@ store_return_init (return_id, init)
}
+/* Emit implicit code for a destructor. This is a subroutine of
+ finish_function. */
+
+static void
+finish_dtor ()
+{
+ tree binfo = TYPE_BINFO (current_class_type);
+ tree cond = integer_one_node;
+ tree exprstmt;
+ tree in_charge_node = lookup_name (in_charge_identifier, 0);
+ tree virtual_size;
+ int ok_to_optimize_dtor = 0;
+ int empty_dtor = get_last_insn () == last_dtor_insn;
+ rtx insns, last_parm_insn;
+
+ if (current_function_assigns_this)
+ cond = build (NE_EXPR, boolean_type_node,
+ current_class_ptr, integer_zero_node);
+ else
+ {
+ int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
+
+ /* If this destructor is empty, then we don't need to check
+ whether `this' is NULL in some cases. */
+ if ((flag_this_is_variable & 1) == 0)
+ ok_to_optimize_dtor = 1;
+ else if (empty_dtor)
+ ok_to_optimize_dtor
+ = (n_baseclasses == 0
+ || (n_baseclasses == 1
+ && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
+ }
+
+ /* If this has a vlist1 parameter, allocate the corresponding vlist
+ parameter. */
+ if (DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl))
+ {
+ /* _Vlist __vlist; */
+ tree vlist;
+
+ mark_all_temps_used();
+ vlist = pushdecl (build_decl (VAR_DECL, vlist_identifier,
+ vlist_type_node));
+ TREE_USED (vlist) = 1;
+ DECL_ARTIFICIAL (vlist) = 1;
+ expand_decl (vlist);
+ expand_decl_init (vlist);
+ }
+
+ /* These initializations might go inline. Protect
+ the binding level of the parms. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ if (current_function_assigns_this)
+ {
+ current_function_assigns_this = 0;
+ current_function_just_assigned_this = 0;
+ }
+
+ /* Generate the code to call destructor on base class.
+ If this destructor belongs to a class with virtual
+ functions, then set the virtual function table
+ pointer to represent the type of our base class. */
+
+ /* This side-effect makes call to `build_delete' generate the
+ code we have to have at the end of this destructor.
+ `build_delete' will set the flag again. */
+ TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
+
+ /* These are two cases where we cannot delegate deletion. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
+ || TYPE_GETS_REG_DELETE (current_class_type))
+ exprstmt = build_delete
+ (current_class_type, current_class_ref, integer_zero_node,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
+ else
+ exprstmt = build_delete
+ (current_class_type, current_class_ref, in_charge_node,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
+
+ /* If we did not assign to this, then `this' is non-zero at
+ the end of a destructor. As a special optimization, don't
+ emit test if this is an empty destructor. If it does nothing,
+ it does nothing. If it calls a base destructor, the base
+ destructor will perform the test. */
+
+ if (exprstmt != error_mark_node
+ && (TREE_CODE (exprstmt) != NOP_EXPR
+ || TREE_OPERAND (exprstmt, 0) != integer_zero_node
+ || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
+ {
+ expand_label (dtor_label);
+ if (cond != integer_one_node)
+ expand_start_cond (cond, 0);
+ if (exprstmt != void_zero_node)
+ /* Don't call `expand_expr_stmt' if we're not going to do
+ anything, since -Wall will give a diagnostic. */
+ expand_expr_stmt (exprstmt);
+
+ /* Run destructor on all virtual baseclasses. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ {
+ tree vbases = nreverse
+ (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
+ expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
+ in_charge_node, integer_two_node), 0);
+ while (vbases)
+ {
+ if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
+ {
+ tree vb = get_vbase
+ (BINFO_TYPE (vbases),
+ TYPE_BINFO (current_class_type));
+
+ expand_expr_stmt
+ (build_base_dtor_call (current_class_ref,
+ vb, integer_zero_node));
+ }
+ vbases = TREE_CHAIN (vbases);
+ }
+ expand_end_cond ();
+ }
+
+ do_pending_stack_adjust ();
+ if (cond != integer_one_node)
+ expand_end_cond ();
+ }
+
+ virtual_size = c_sizeof (current_class_type);
+
+ /* At the end, call delete if that's what's requested. */
+
+ /* FDIS sez: At the point of definition of a virtual destructor
+ (including an implicit definition), non-placement operator
+ delete shall be looked up in the scope of the destructor's
+ class and if found shall be accessible and unambiguous.
+
+ This is somewhat unclear, but I take it to mean that if the
+ class only defines placement deletes we don't do anything here.
+ So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain
+ for us if they ever try to delete one of these. */
+
+ if (TYPE_GETS_REG_DELETE (current_class_type)
+ || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ exprstmt = build_op_delete_call
+ (DELETE_EXPR, current_class_ptr, virtual_size,
+ LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
+ else
+ exprstmt = NULL_TREE;
+
+ if (exprstmt)
+ {
+ cond = build (BIT_AND_EXPR, integer_type_node,
+ in_charge_node, integer_one_node);
+ expand_start_cond (cond, 0);
+ expand_expr_stmt (exprstmt);
+ expand_end_cond ();
+ }
+
+ /* End of destructor. */
+ expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
+ poplevel (getdecls () != NULL_TREE, 0, 0);
+
+ /* Back to the top of destructor. */
+ /* Don't execute destructor code if `this' is NULL. */
+
+ start_sequence ();
+
+ /* If we need thunk-style vlists, initialize them if the caller did
+ not pass them. This requires a new temporary. The generated code
+ looks like
+ if (!(__in_charge & 4))
+ __vlist = __vl.<type> + sizeof(__vl.<type>);
+ else
+ __vlist = __vlist1;
+ */
+ if (TYPE_USES_PVBASES (current_class_type))
+ {
+ tree vlist = lookup_name (vlist_identifier, 0);
+ tree vlist1 = lookup_name (get_identifier (VLIST1_NAME), 0);
+ cond = build (BIT_AND_EXPR, integer_type_node,
+ in_charge_node, build_int_2 (4, 0));
+ cond = build1 (TRUTH_NOT_EXPR, boolean_type_node, cond);
+ expand_start_cond (cond, 0);
+ init_vlist (current_class_type);
+ expand_start_else ();
+ expand_expr_stmt (build_modify_expr (vlist, NOP_EXPR, vlist1));
+ expand_end_cond ();
+ }
+
+ /* If the dtor is empty, and we know there is not possible way we
+ could use any vtable entries, before they are possibly set by
+ a base class dtor, we don't have to setup the vtables, as we
+ know that any base class dtoring will set up any vtables it
+ needs. We avoid MI, because one base class dtor can do a
+ virtual dispatch to an overridden function that would need to
+ have a non-related vtable set up, we cannot avoid setting up
+ vtables in that case. We could change this to see if there is
+ just one vtable. */
+ if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
+ {
+ /* Make all virtual function table pointers in non-virtual base
+ classes point to CURRENT_CLASS_TYPE's virtual function
+ tables. */
+ expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
+
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr);
+ }
+
+ if (! ok_to_optimize_dtor)
+ {
+ cond = build_binary_op (NE_EXPR,
+ current_class_ptr, integer_zero_node);
+ expand_start_cond (cond, 0);
+ }
+
+ insns = get_insns ();
+ end_sequence ();
+
+ last_parm_insn = get_first_nonparm_insn ();
+ if (last_parm_insn == NULL_RTX)
+ last_parm_insn = get_last_insn ();
+ else
+ last_parm_insn = previous_insn (last_parm_insn);
+
+ emit_insns_after (insns, last_parm_insn);
+
+ if (! ok_to_optimize_dtor)
+ expand_end_cond ();
+}
+
+/* Emit implicit code for a constructor. This is a subroutine of
+ finish_function. CALL_POPLEVEL is the same variable in
+ finish_function. */
+
+static void
+finish_ctor (call_poplevel)
+ int call_poplevel;
+{
+ register tree fndecl = current_function_decl;
+ tree cond = NULL_TREE, thenclause = NULL_TREE;
+ rtx insns;
+ tree decls;
+
+ /* Allow constructor for a type to get a new instance of the object
+ using `build_new'. */
+ tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
+ CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
+
+ if (flag_this_is_variable > 0)
+ {
+ cond = build_binary_op (EQ_EXPR, current_class_ptr, integer_zero_node);
+ thenclause =
+ build_modify_expr (current_class_ptr, NOP_EXPR,
+ build_new (NULL_TREE, current_class_type,
+ void_type_node, 0));
+ }
+
+ CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
+
+ start_sequence ();
+
+ if (flag_this_is_variable > 0)
+ {
+ expand_start_cond (cond, 0);
+ expand_expr_stmt (thenclause);
+ expand_end_cond ();
+ }
+
+ /* Emit insns from `emit_base_init' which sets up virtual
+ function table pointer(s). */
+ if (base_init_expr)
+ {
+ expand_expr_stmt (base_init_expr);
+ base_init_expr = NULL_TREE;
+ }
+
+ insns = get_insns ();
+ end_sequence ();
+
+ /* This is where the body of the constructor begins. */
+
+ emit_insns_after (insns, last_parm_cleanup_insn);
+
+ end_protect_partials ();
+
+ /* This is where the body of the constructor ends. */
+ expand_label (ctor_label);
+ ctor_label = NULL_TREE;
+
+ if (call_poplevel)
+ {
+ decls = getdecls ();
+ expand_end_bindings (decls, decls != NULL_TREE, 0);
+ poplevel (decls != NULL_TREE, 1, 0);
+ }
+
+ /* c_expand_return knows to return 'this' from a constructor. */
+ c_expand_return (NULL_TREE);
+
+ current_function_assigns_this = 0;
+ current_function_just_assigned_this = 0;
+}
+
+
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
for the function definition.
@@ -13958,7 +14320,6 @@ finish_function (lineno, flags, nested)
{
register tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
- rtx last_parm_insn, insns;
/* Label to use if this function is supposed to return a value. */
tree no_return_label = NULL_TREE;
tree decls = NULL_TREE;
@@ -14020,191 +14381,7 @@ finish_function (lineno, flags, nested)
do_pending_stack_adjust ();
if (dtor_label)
- {
- tree binfo = TYPE_BINFO (current_class_type);
- tree cond = integer_one_node;
- tree exprstmt;
- tree in_charge_node = lookup_name (in_charge_identifier, 0);
- tree virtual_size;
- int ok_to_optimize_dtor = 0;
- int empty_dtor = get_last_insn () == last_dtor_insn;
-
- if (current_function_assigns_this)
- cond = build (NE_EXPR, boolean_type_node,
- current_class_ptr, integer_zero_node);
- else
- {
- int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
-
- /* If this destructor is empty, then we don't need to check
- whether `this' is NULL in some cases. */
- if ((flag_this_is_variable & 1) == 0)
- ok_to_optimize_dtor = 1;
- else if (empty_dtor)
- ok_to_optimize_dtor
- = (n_baseclasses == 0
- || (n_baseclasses == 1
- && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
- }
-
- /* These initializations might go inline. Protect
- the binding level of the parms. */
- pushlevel (0);
- expand_start_bindings (0);
-
- if (current_function_assigns_this)
- {
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- }
-
- /* Generate the code to call destructor on base class.
- If this destructor belongs to a class with virtual
- functions, then set the virtual function table
- pointer to represent the type of our base class. */
-
- /* This side-effect makes call to `build_delete' generate the
- code we have to have at the end of this destructor.
- `build_delete' will set the flag again. */
- TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
-
- /* These are two cases where we cannot delegate deletion. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
- || TYPE_GETS_REG_DELETE (current_class_type))
- exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
- else
- exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
-
- /* If we did not assign to this, then `this' is non-zero at
- the end of a destructor. As a special optimization, don't
- emit test if this is an empty destructor. If it does nothing,
- it does nothing. If it calls a base destructor, the base
- destructor will perform the test. */
-
- if (exprstmt != error_mark_node
- && (TREE_CODE (exprstmt) != NOP_EXPR
- || TREE_OPERAND (exprstmt, 0) != integer_zero_node
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
- {
- expand_label (dtor_label);
- if (cond != integer_one_node)
- expand_start_cond (cond, 0);
- if (exprstmt != void_zero_node)
- /* Don't call `expand_expr_stmt' if we're not going to do
- anything, since -Wall will give a diagnostic. */
- expand_expr_stmt (exprstmt);
-
- /* Run destructor on all virtual baseclasses. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- {
- tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
- expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
- in_charge_node, integer_two_node), 0);
- while (vbases)
- {
- if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
- {
- tree vb = get_vbase
- (BINFO_TYPE (vbases),
- TYPE_BINFO (current_class_type));
- expand_expr_stmt
- (build_scoped_method_call
- (current_class_ref, vb, dtor_identifier,
- build_expr_list (NULL_TREE, integer_zero_node)));
- }
- vbases = TREE_CHAIN (vbases);
- }
- expand_end_cond ();
- }
-
- do_pending_stack_adjust ();
- if (cond != integer_one_node)
- expand_end_cond ();
- }
-
- virtual_size = c_sizeof (current_class_type);
-
- /* At the end, call delete if that's what's requested. */
-
- /* FDIS sez: At the point of definition of a virtual destructor
- (including an implicit definition), non-placement operator
- delete shall be looked up in the scope of the destructor's
- class and if found shall be accessible and unambiguous.
-
- This is somewhat unclear, but I take it to mean that if the
- class only defines placement deletes we don't do anything here.
- So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain
- for us if they ever try to delete one of these. */
-
- if (TYPE_GETS_REG_DELETE (current_class_type)
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- exprstmt = build_op_delete_call
- (DELETE_EXPR, current_class_ptr, virtual_size,
- LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
- else
- exprstmt = NULL_TREE;
-
- if (exprstmt)
- {
- cond = build (BIT_AND_EXPR, integer_type_node,
- in_charge_node, integer_one_node);
- expand_start_cond (cond, 0);
- expand_expr_stmt (exprstmt);
- expand_end_cond ();
- }
-
- /* End of destructor. */
- expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
- poplevel (getdecls () != NULL_TREE, 0, 0);
-
- /* Back to the top of destructor. */
- /* Don't execute destructor code if `this' is NULL. */
-
- start_sequence ();
-
- /* If the dtor is empty, and we know there is not possible way we
- could use any vtable entries, before they are possibly set by
- a base class dtor, we don't have to setup the vtables, as we
- know that any base class dtoring will set up any vtables it
- needs. We avoid MI, because one base class dtor can do a
- virtual dispatch to an overridden function that would need to
- have a non-related vtable set up, we cannot avoid setting up
- vtables in that case. We could change this to see if there is
- just one vtable. */
- if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
- {
- /* Make all virtual function table pointers in non-virtual base
- classes point to CURRENT_CLASS_TYPE's virtual function
- tables. */
- expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr);
- }
-
- if (! ok_to_optimize_dtor)
- {
- cond = build_binary_op (NE_EXPR,
- current_class_ptr, integer_zero_node);
- expand_start_cond (cond, 0);
- }
-
- insns = get_insns ();
- end_sequence ();
-
- last_parm_insn = get_first_nonparm_insn ();
- if (last_parm_insn == NULL_RTX)
- last_parm_insn = get_last_insn ();
- else
- last_parm_insn = previous_insn (last_parm_insn);
-
- emit_insns_after (insns, last_parm_insn);
-
- if (! ok_to_optimize_dtor)
- expand_end_cond ();
- }
+ finish_dtor ();
else if (current_function_assigns_this)
{
/* Does not need to call emit_base_init, because
@@ -14234,67 +14411,9 @@ finish_function (lineno, flags, nested)
current_function_just_assigned_this = 0;
base_init_expr = NULL_TREE;
}
- else if (DECL_CONSTRUCTOR_P (fndecl))
- {
- tree cond = NULL_TREE, thenclause = NULL_TREE;
- /* Allow constructor for a type to get a new instance of the object
- using `build_new'. */
- tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
- CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
-
- if (flag_this_is_variable > 0)
- {
- cond = build_binary_op (EQ_EXPR,
- current_class_ptr, integer_zero_node);
- thenclause = build_modify_expr (current_class_ptr, NOP_EXPR,
- build_new (NULL_TREE, current_class_type, void_type_node, 0));
- }
-
- CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
-
- start_sequence ();
-
- if (flag_this_is_variable > 0)
- {
- expand_start_cond (cond, 0);
- expand_expr_stmt (thenclause);
- expand_end_cond ();
- }
-
- /* Emit insns from `emit_base_init' which sets up virtual
- function table pointer(s). */
- if (base_init_expr)
- {
- expand_expr_stmt (base_init_expr);
- base_init_expr = NULL_TREE;
- }
-
- insns = get_insns ();
- end_sequence ();
-
- /* This is where the body of the constructor begins. */
-
- emit_insns_after (insns, last_parm_cleanup_insn);
-
- end_protect_partials ();
-
- /* This is where the body of the constructor ends. */
- expand_label (ctor_label);
- ctor_label = NULL_TREE;
-
- if (call_poplevel)
- {
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
- poplevel (decls != NULL_TREE, 1, 0);
- }
-
- /* c_expand_return knows to return 'this' from a constructor. */
- c_expand_return (NULL_TREE);
-
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- }
+ else if (DECL_CONSTRUCTOR_P (fndecl)
+ && !DECL_VLIST_CTOR_WRAPPER_P (fndecl))
+ finish_ctor (call_poplevel);
else if (DECL_MAIN_P (fndecl))
{
/* Make it so that `main' always returns 0 by default. */
diff --git a/contrib/gcc/cp/gxxint.texi b/contrib/gcc/cp/gxxint.texi
index e3ba1aa..5a665c7 100644
--- a/contrib/gcc/cp/gxxint.texi
+++ b/contrib/gcc/cp/gxxint.texi
@@ -27,6 +27,7 @@ Questions and comments to Benjamin Kosnik @code{<bkoz@@cygnus.com>}.
* Exception Handling::
* Free Store::
* Mangling:: Function name mangling for C++ and Java
+* Vtables:: Two ways to do virtual functions
* Concept Index::
@end menu
@@ -191,7 +192,9 @@ accessed by the BINFO_ accessor macros.
The virtual function table holds information used in virtual function
dispatching. In the compiler, they are usually referred to as vtables,
or vtbls. The first index is not used in the normal way, I believe it
-is probably used for the virtual destructor.
+is probably used for the virtual destructor. There are two forms of
+virtual tables, one that has offsets in addition to pointers, and one
+using thunks. @xref{Vtables}.
@item vfield
@@ -1456,7 +1459,7 @@ To meet the first goal, we defer emission of inlines and vtables until
the end of the translation unit, where we can decide whether or not they
are needed, and how to emit them if they are.
-@node Mangling, Concept Index, Free Store, Top
+@node Mangling, Vtables, Free Store, Top
@section Function name mangling for C++ and Java
Both C++ and Jave provide overloaded function and methods,
@@ -1840,7 +1843,231 @@ Used for template type parameters.
The letters @samp{G}, @samp{M}, @samp{O}, and @samp{p}
also seem to be used for obscure purposes ...
-@node Concept Index, , Mangling, Top
+@node Vtables, Concept Index, Mangling, Top
+@section Virtual Tables
+
+In order to invoke virtual functions, GNU C++ uses virtual tables. Each
+virtual function gets an index, and the table entry points to the
+overridden function to call. Sometimes, and adjustment to the this
+pointer has to be made before calling a virtual function:
+
+@example
+struct A@{
+ int i;
+ virtual void foo();
+@};
+
+struct B@{
+ int j;
+ virtual void bar();
+@};
+
+struct C:A,B@{
+ virtual void bar();
+@};
+
+void C::bar()
+@{
+ i++;
+@}
+
+int main()
+@{
+ C *c = new C;
+ B *b = c;
+ c->bar();
+@}
+@end example
+
+Here, casting from @samp{c} to @samp{b} adds an offset. When @samp{bar}
+is called, this offset needs to be subtracted, so that @samp{C::bar} can
+properly access @samp{i}. One approach of achieving this is to use
+@emph{thunks}, which are small half-functions put into the virtual
+table. The modify the first argument (the @samp{this} pointer), and then
+jump into the real function.
+
+The other (traditional) approach is to have an additional integer in the
+virtual table which is added to this. This is an additional overhead
+both at the function call, and in the size of virtual tables: In the
+case of single inheritance (or for the first base class), these integers
+will always be zero.
+
+@subsection Virtual Base Classes with Virtual Tables
+
+In case of virtual bases, the code is even more
+complicated. Constructors and destructors need to know whether they are
+"in charge" of the virtual bases, and an implicit integer
+@samp{__in_chrg} for that purpose.
+
+@example
+struct A@{
+ int i;
+ virtual void bar();
+ void call_bar()@{bar();@}
+@};
+
+struct B:virtual A@{
+ B();
+ int j;
+ virtual void bar();
+@};
+
+B::B()@{
+ call_bar();
+@}
+
+struct C@{
+ int k;
+@};
+
+struct D:C,B@{
+ int l;
+ virtual void bar();
+@};
+
+@end example
+
+When constructing an instance of B, it will have the following layout:
+@samp{vbase pointer to A}, @samp{j}, @samp{A virtual table}, @samp{i}.
+On a 32-bit machine, downcasting from @samp{A*} to @samp{B*} would need
+to subtract 8, which would be the thunk executed when calling
+@samp{B::bar} inside @samp{call_bar}.
+
+When constructing an instance of D, it will have a different layout:
+@samp{k}, @samp{vbase pointer to A}, @samp{j}, @samp{l}, @samp{A virtual
+table}, @samp{i}. So, when downcasting from @samp{A*} to @samp{B*} in a
+@samp{D} object, the offset would be @samp{12}.
+
+This means that during construction of the @samp{B} base of a @samp{D}
+object, a virtual table is needed which has a @samp{-12} thunk to
+@samp{B::bar}. This is @emph{only} needed during construction and
+destruction, as the full object will use a @samp{-16} thunk to
+@samp{D::bar}.
+
+In order to implement this, the compiler generates an implicit argument
+(in addition to @code{__in_chrg}): the virtual list argument
+@code{__vlist}. This is a list of virtual tables needed during
+construction and destruction. The virtual pointers are ordered in the
+way they are used during construction; the destructors will process the
+array in reverse order. The ordering is as follows:
+@itemize @bullet
+@item
+If the class is in charge, the vlist starts with virtual table pointers
+for the virtual bases that have virtual bases themselves. Here, only
+@emph{polymorphic} virtual bases (pvbases) are interesting: if a vbase
+has no virtual functions, it doesn't have a virtual table.
+
+@item
+Next, the vlist has virtual tables for the initialization of the
+non-virtual bases. These bases are not in charge, so the layout is
+recursive, but ignores virtual bases during recursion.
+
+@item
+Next, there is a number of virtual tables for each virtual base. These
+are sorted in the order in which virtual bases are constructed. Each
+virtual base may have more than one @code{vfield}, and therefore require
+more than one @code{vtable}. The order of vtables is the same as used
+when initializing vfields of non-virtual bases in a constructor.
+@end itemize
+
+The compiler emits a virtual table list in a variable mangled as
+@code{__vl.classname}.
+
+Class with virtual bases, but without pvbases, only have the
+@code{__in_chrg} argument to their ctors and dtors: they don't have any
+vfields in the vbases to initialize.
+
+A further problem arises with virtual destructors: A destructor
+typically has only the @code{__in_chrg} argument, which also indicates
+whether the destructor should call @code{operator delete}. A dtor of a
+class with pvbases has an additional argument. Unfortunately, a caller
+of a virtual dtor might not know whether to pass that argument or not.
+Therefore, the dtor processes the @code{__vlist} argument in an
+automatic variable, which is initialized from the class' vlist if the
+__in_chrg flag has a zero value in bit 2 (bit mask 4), or from the
+argument @code{__vlist1} if bit 2 of the __in_chrg parameter is set to
+one.
+
+@subsection Specification of non-thunked vtables
+
+In the traditional implementation of vtables, each slot contains three
+fields: The offset to be added to the this pointer before invoking a
+virtual function, an unused field that is always zero, and the pointer
+to the virtual function. The first two fields are typically 16 bits
+wide. The unused field is called `index'; it may be non-zero in
+pointer-to-member-functions, which use the same layout.
+
+The virtual table then is an array of vtable slots. The first slot is
+always the virtual type info function, the other slots are in the order
+in which the virtual functions appear in the class declaration.
+
+If a class has base classes, it may inherit other bases' vfields. Each
+class may have a primary vfield; the primary vfield of the derived class
+is the primary vfield of the left-most non-virtual base class. If a
+class inherits a primary vfield, any new virtual functions in the
+derived class are appended to the virtual table of the primary
+vfield. If there are new virtual functions in the derived class, and no
+primary vfield is inherited, a new vfield is introduced which becomes
+primary. The redefined virtual functions fill the vtable slots inherited
+from the base; new virtual functions are put into the primary vtable in
+the order of declaration. If no new virtual functions are introduced, no
+primary vfield is allocated.
+
+In a base class that has pvbases, virtual tables are needed which are
+used only in the constructor (see example above). At run-time, the
+virtual tables of the base class are adjusted, to reflect the new offset
+of the pvbase. The compiler knows statically what offset the pvbase has
+for a complete object. At run-time, the offset of the pvbase can be
+extracted from the vbase pointer, which is set in the constructor of the
+complete object. These two offsets result in a delta, which is used to
+adjust the deltas in the vtable (the adjustment might be different for
+different vtable slots). To adjust the vtables, the compiler emits code
+that creates a vtable on the stack. This vtable is initialized with the
+vtable for the complete base type, and then adjusted.
+
+In order to call a virtual function, the compiler gets the offset field
+from the vtable entry, and adds it to the this pointer. It then
+indirectly calls the virtual function pointer, passing the adjusted this
+pointer, and any arguments the virtual function may have.
+
+To implement dynamic casting, the dynamic_cast function needs typeinfos
+for the complete type, and the pointer to the complete type. The
+typeinfo pointer is obtained by calling the virtual typeinfo function
+(which doesn't take a this parameter). The pointer to the complete
+object is obtained by adding the offset of the virtual typeinfo vtable
+slot, since this virtual function is always implemented in the complete
+object.
+
+@subsection Specification of thunked vtables
+
+For vtable thunks, each slot only consists of a pointer to the virtual
+function, which might be a thunk function. The first slot in the vtable
+is an offset of the this pointer to the complete object, which is needed
+as a parameter to __dynamic_cast. The second slot is the virtual
+typeinfo function. All other slots are allocated with the same procedure
+as in the non-thunked case. Allocation of vfields also uses the same
+procedure as described above.
+
+If the virtual function needs an adjusted this pointer, a thunk function
+is emitted. If supported by the target architecture, this is only a
+half-function. Such a thunk has no stack frame; it merely adjusts the
+first argument of the function, and then directly branches into the
+implementation of the virtual function. If the architecture does not
+support half-functions (i.e. if ASM_OUTPUT_MI_THUNK is not defined), the
+compiler emits a wrapper function, which copies all arguments, adjust
+the this pointer, and then calls the original function. Since objects of
+non-aggregate type are passed by invisible reference, this copies only
+POD arguments. The approach fails for virtual functions with a variable
+number of arguments.
+
+In order to support the vtables needed in base constructors with
+pvbases, the compiler passes an implicit __vlist argument as described
+above, if the version 2 thunks are used. For version 1 thunks, the base
+class constructor will fill in the vtables for the complete base class,
+which will incorrectly adjust the this pointer, leading to a dynamic
+error.
+
+@node Concept Index, , Vtables, Top
@section Concept Index
diff --git a/contrib/gcc/function.c b/contrib/gcc/function.c
index e597d33..cd8f249 100644
--- a/contrib/gcc/function.c
+++ b/contrib/gcc/function.c
@@ -6704,7 +6704,10 @@ void
thread_prologue_and_epilogue_insns (f)
rtx f ATTRIBUTE_UNUSED;
{
- int insertted = 0;
+ int inserted = 0;
+#ifdef HAVE_prologue
+ rtx prologue_end = NULL_RTX;
+#endif
prologue = 0;
#ifdef HAVE_prologue
@@ -6721,7 +6724,7 @@ thread_prologue_and_epilogue_insns (f)
seq = get_insns ();
prologue = record_insns (seq);
- emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+ prologue_end = emit_note (NULL, NOTE_INSN_PROLOGUE_END);
seq = gen_sequence ();
end_sequence ();
@@ -6734,7 +6737,7 @@ thread_prologue_and_epilogue_insns (f)
abort ();
insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
- insertted = 1;
+ inserted = 1;
}
else
emit_insn_after (seq, f);
@@ -6866,8 +6869,56 @@ thread_prologue_and_epilogue_insns (f)
}
#endif
- if (insertted)
+ if (inserted)
commit_edge_insertions ();
+
+#ifdef HAVE_prologue
+ if (prologue_end)
+ {
+ rtx insn, prev;
+
+ /* GDB handles `break f' by setting a breakpoint on the first
+ line note *after* the prologue. Which means (1) that if
+ there are line number notes before where we inserted the
+ prologue we should move them, and (2) if there is no such
+ note, then we should generate one at the prologue. */
+
+ for (insn = prologue_end; insn ; insn = prev)
+ {
+ prev = PREV_INSN (insn);
+ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ {
+ /* Note that we cannot reorder the first insn in the
+ chain, since rest_of_compilation relies on that
+ remaining constant. Do the next best thing. */
+ if (prev == NULL)
+ {
+ emit_line_note_after (NOTE_SOURCE_FILE (insn),
+ NOTE_LINE_NUMBER (insn),
+ prologue_end);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ }
+ else
+ reorder_insns (insn, insn, prologue_end);
+ }
+ }
+
+ insn = NEXT_INSN (prologue_end);
+ if (! insn || GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) <= 0)
+ {
+ for (insn = next_active_insn (f); insn ; insn = PREV_INSN (insn))
+ {
+ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ {
+ emit_line_note_after (NOTE_SOURCE_FILE (insn),
+ NOTE_LINE_NUMBER (insn),
+ prologue_end);
+ break;
+ }
+ }
+ }
+ }
+ #endif
}
/* Reposition the prologue-end and epilogue-begin notes after instruction
diff --git a/contrib/gcc/invoke.texi b/contrib/gcc/invoke.texi
index e10a9c6..962a707 100644
--- a/contrib/gcc/invoke.texi
+++ b/contrib/gcc/invoke.texi
@@ -1190,7 +1190,7 @@ anachronism. Therefore, by default it is invalid to assign to
type @samp{X *}. However, for backwards compatibility, you can make it
valid with @samp{-fthis-is-variable}.
-@item -fvtable-thunks
+@item -fvtable-thunks=@var{thunks-version}
Use @samp{thunks} to implement the virtual function dispatch table
(@samp{vtable}). The traditional (cfront-style) approach to
implementing vtables was to store a pointer to the function and two
@@ -1198,13 +1198,27 @@ offsets for adjusting the @samp{this} pointer at the call site. Newer
implementations store a single pointer to a @samp{thunk} function which
does any necessary adjustment and then calls the target function.
+The original implementation of thunks (version 1) had a bug regarding
+virtual base classes; this bug is fixed with version 2 of the thunks
+implementation. With setting the version to 2, compatibility to the
+version 1 thunks is provided, at the cost of extra machine code. Version
+3 does not include this compatibility.
+
This option also enables a heuristic for controlling emission of
vtables; if a class has any non-inline virtual functions, the vtable
will be emitted in the translation unit containing the first one of
those.
Like all options that change the ABI, all C++ code, @emph{including
-libgcc.a} must be built with the same setting of this option.
+libgcc.a} must be built with the same setting of this option. Since
+version 1 and version 2 are also incompatible (for classes with virtual
+bases defining virtual functions), all code must also be compiled with
+the same version.
+
+On some targets (e.g. Linux/GNU), version 2 thunks are the default. On these
+targets, no option or -fvtable-thunks will produce version 2 thunks. On
+all other targets, not giving the option will use the traditional
+implementation, and -fvtable-thunks will produce version 2 thunks.
@item -nostdinc++
Do not search for header files in the standard directories specific to
OpenPOWER on IntegriCloud