+Wed Jun 29 16:44:45 1994 Mike Stump (mrs@cygnus.com)
+
+ Fixes a problem of the this pointer being wrong in virtual calls to
+ methods that are not overridden in more derived classes.
+
+ * class.c (fixup_vtable_delta): New routine. It will fixup the
+ delta entries in vtables, wheever they need updating.
+ * class.c (finish_struct): Call the new routine for all virtual
+ bases, as they can have different offsets, than those used in base
+ classes that we derive our vtable from.
+
+Tue Jun 28 23:49:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * typeck.c (build_binary_op): Use the types before default
+ conversions in the error message.
+
+ * *.c: Use c_build_type_variant instead of build_type_variant where
+ the type might be an array.
+
+ * call.c (build_method_call): Call build_type_variant and
+ build_reference_type in the right order.
+ * decl.c (record_builtin_type): Ditto.
+
+Wed Jun 29 16:58:53 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * call.c (build_method_call): Call build_type_variant and
+ build_reference_type in the right order.
+ * decl.c (record_builtin_type): Ditto.
+
+Tue Jun 28 23:49:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * typeck.c (build_binary_op): Use the types before default
+ conversions in the error message.
+
+ * *.c: Use c_build_type_variant instead of build_type_variant where
+ the type might be an array.
+
+Sat Jun 25 11:50:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * cvt.c (convert_to_reference): Try UDC's before doing the
+ reinterpret_cast thang, though.
+
+Fri Jun 24 01:24:01 1994 Jason Merrill (jason@deneb.cygnus.com)
+
+ * typeck.c (c_expand_return): Don't USE the return value location
+ after we've expanded the jump.
+
+ * decl2.c (finish_file): Make sure DECL_SAVED_INSNS is not 0 before
+ trying to write out an inline.
+
+ * cvt.c (build_up_reference): Also do address adjustment when the
+ target type uses MI.
+ (convert_to_reference): Try UDCs only after built-in conversions.
+ (build_type_conversion_1): Don't play games with the argument to the
+ method.
+ (build_type_conversion): #if 0 out code for binding to reference.
+
Thu Jun 23 00:22:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (finish_file): Use TREE_SYMBOL_REFERENCED to decide
+ whether to emit inlines.
+
* decl.c (grokdeclarator): Set explicit_int for decls that just
specify, say, 'long'.
#endif
h = convert_harshness (TREE_VALUE (ttf),
- TREE_TYPE (TREE_VALUE (tta)),
- TREE_VALUE (tta));
+ TREE_TYPE (TREE_VALUE (tta)),
+ TREE_VALUE (tta));
#ifdef DEBUG_MATCHING
cp_error (" evaluated %s", print_harshness (&h));
{
tree new_type;
parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
- new_type = build_reference_type (TREE_TYPE (parm));
- /* It is possible that this should go down a layer. */
- new_type = build_type_variant (new_type, constp, volatilep);
+ new_type = c_build_type_variant (TREE_TYPE (parm), constp,
+ volatilep);
+ new_type = build_reference_type (new_type);
parm = convert (new_type, parm);
friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
}
}
}
+/* Fixup all the delta entries in this vtable that need updating.
+ This happens when we have non-overridden virtual functions from a
+ virtual base class, that are at a different offset, in the new
+ hierarchy, because the layout of the virtual bases has changed. */
+static void
+fixup_vtable_deltas (binfo, t)
+ tree binfo, t;
+{
+ tree virtuals = BINFO_VIRTUALS (binfo);
+ unsigned HOST_WIDE_INT n;
+
+ n = 0;
+ /* Skip initial vtable length field and RTTI fake object. */
+ for (; virtuals && n < 1 + flag_dossier; n++)
+ virtuals = TREE_CHAIN (virtuals);
+ while (virtuals)
+ {
+ tree fndecl = TREE_VALUE (virtuals);
+ tree pfn = FNADDR_FROM_VTABLE_ENTRY (fndecl);
+ tree delta = DELTA_FROM_VTABLE_ENTRY (fndecl);
+ fndecl = TREE_OPERAND (pfn, 0);
+ if (fndecl)
+ {
+ tree base_offset, offset;
+ tree context = DECL_CLASS_CONTEXT (fndecl);
+ tree vfield = CLASSTYPE_VFIELD (t);
+ tree this_offset;
+
+ offset = integer_zero_node;
+ if (context != t && TYPE_USES_COMPLEX_INHERITANCE (t))
+ {
+ offset = virtual_offset (context, CLASSTYPE_VBASECLASSES (t), offset);
+ if (offset == NULL_TREE)
+ {
+ tree binfo = get_binfo (context, t, 0);
+ offset = BINFO_OFFSET (binfo);
+ }
+ }
+
+ /* Find the right offset for the this pointer based on the
+ base class we just found. We have to take into
+ consideration the virtual base class pointers that we
+ stick in before the virtual function table pointer.
+
+ Also, we want just the delta bewteen the most base class
+ that we derived this vfield from and us. */
+ base_offset = size_binop (PLUS_EXPR,
+ get_derived_offset (binfo),
+ BINFO_OFFSET (binfo));
+ this_offset = size_binop (MINUS_EXPR, offset, base_offset);
+
+ if (! tree_int_cst_equal (this_offset, delta))
+ {
+ /* Make sure we can modify the derived association with immunity. */
+ if (TREE_USED (binfo))
+ my_friendly_assert (0, 999);
+
+ if (binfo == TYPE_BINFO (t))
+ {
+ /* In this case, it is *type*'s vtable we are modifying.
+ We start with the approximation that it's vtable is that
+ of the immediate base class. */
+ if (! BINFO_NEW_VTABLE_MARKED (binfo))
+ build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), 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. */
+ if (! BINFO_NEW_VTABLE_MARKED (binfo))
+ prepare_fresh_vtable (binfo, t);
+ }
+
+ modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
+ build_vtable_entry (this_offset, pfn),
+ fndecl);
+ }
+ }
+ ++n;
+ virtuals = TREE_CHAIN (virtuals);
+ }
+}
+
/* These are the ones that are through virtual base classes. */
static void
modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
}
}
}
+
+ /* Now fixup any virtual function entries from virtual bases
+ that have different deltas. */
+ vbases = CLASSTYPE_VBASECLASSES (t);
+ while (vbases)
+ {
+ /* We might be able to shorten the ammount of work we do by
+ only doing this for vtables that come from virtual bases
+ that have differing offsets, but don't want to miss any
+ entries. */
+ fixup_vtable_deltas (vbases, t);
+ vbases = TREE_CHAIN (vbases);
+ }
}
/* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we
/* Macros which might want to be replaced by function calls. */
+#define DELTA_FROM_VTABLE_ENTRY(ENTRY) \
+ (!flag_vtable_thunks ? \
+ TREE_VALUE (CONSTRUCTOR_ELTS (ENTRY)) \
+ : TREE_CODE (TREE_OPERAND ((ENTRY), 0)) != THUNK_DECL ? integer_zero_node \
+ : build_int_2 (THUNK_DELTA (TREE_OPERAND ((ENTRY), 0)), 0))
#if 1
/* Virtual function addresses can be gotten from a virtual function
table entry using this macro. */
/* Pass along const and volatile down into the type. */
if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
- target_type = build_type_variant (target_type, TYPE_READONLY (type),
- TYPE_VOLATILE (type));
+ target_type = c_build_type_variant (target_type, TYPE_READONLY (type),
+ TYPE_VOLATILE (type));
targ = arg;
if (TREE_CODE (targ) == SAVE_EXPR)
targ = TREE_OPERAND (targ, 0);
TREE_READONLY (arg) = 0;
}
-#if 0
- if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
- {
- rval = copy_node (arg);
- TREE_TYPE (rval) = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
- }
- else
- rval = arg;
-
- rval = convert (build_pointer_type (TREE_TYPE (type)), rval);
- TREE_TYPE (rval) = type;
-#else
rval = build1 (CONVERT_EXPR, type, arg);
-#endif
TREE_REFERENCE_EXPR (rval) = 1;
/* propagate the const flag on something like:
rval = build1 (ADDR_EXPR, type, arg);
done:
- if (TYPE_USES_COMPLEX_INHERITANCE (argtype))
+ if (TYPE_USES_COMPLEX_INHERITANCE (argtype)
+ || TYPE_USES_COMPLEX_INHERITANCE (target_type))
{
TREE_TYPE (rval) = build_pointer_type (argtype);
if (flags & LOOKUP_PROTECT)
intype = TREE_TYPE (intype);
intype = TYPE_MAIN_VARIANT (intype);
- if (IS_AGGR_TYPE (intype)
- && ! (flags & LOOKUP_NO_CONVERSION)
- && (rval = build_type_conversion (CONVERT_EXPR, reftype, expr, 1)))
- {
- if (rval == error_mark_node)
- cp_error ("conversion from `%T' to `%T' is ambiguous",
- intype, reftype);
- return rval;
- }
-
if (((convtype & CONV_STATIC) && comptypes (type, intype, -1))
|| ((convtype & CONV_IMPLICIT) && comptypes (type, intype, 0)))
{
! (convtype & CONV_CONST));
}
- if ((convtype & CONV_REINTERPRET) && lvalue_p (expr))
+ if ((convtype & CONV_IMPLICIT)
+ && IS_AGGR_TYPE (intype)
+ && ! (flags & LOOKUP_NO_CONVERSION)
+ && (rval = build_type_conversion (CONVERT_EXPR, reftype, expr, 1)))
+ {
+ if (rval == error_mark_node)
+ cp_error ("conversion from `%T' to `%T' is ambiguous",
+ intype, reftype);
+ return rval;
+ }
+ else if ((convtype & CONV_REINTERPRET) && lvalue_p (expr))
{
/* When casting an lvalue to a reference type, just convert into
a pointer to the new type and deference it. This is allowed
tree typename;
int for_sure;
{
- tree first_arg = expr;
tree rval;
int flags;
if (for_sure == 0)
- {
- if (! lvalue_p (expr))
- first_arg = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node);
- flags = LOOKUP_PROTECT;
- }
+ flags = LOOKUP_PROTECT;
else
flags = LOOKUP_NORMAL;
- rval = build_method_call (first_arg, typename, NULL_TREE, NULL_TREE, flags);
+ rval = build_method_call (expr, typename, NULL_TREE, NULL_TREE, flags);
if (rval == error_mark_node)
{
if (for_sure == 0)
return NULL_TREE;
return error_mark_node;
}
- if (first_arg != expr)
- {
- expr = build_up_reference (build_reference_type (TREE_TYPE (expr)), expr,
- LOOKUP_COMPLAIN, 1);
- TREE_VALUE (TREE_OPERAND (rval, 1)) = build_unary_op (ADDR_EXPR, expr, 0);
- }
if (TREE_CODE (TREE_TYPE (rval)) == REFERENCE_TYPE
&& TREE_CODE (xtype) != REFERENCE_TYPE)
rval = default_conversion (rval);
if (TREE_CODE (type) == REFERENCE_TYPE)
{
- tree first_arg = expr;
+#if 0
+ /* Only reference variable initializations can use a temporary; this
+ must be handled elsewhere (like convert_to_reference and
+ compute_conversion_costs). */
+
type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ typename = build_typename_overload (type);
basetype = save_basetype;
/* May need to build a temporary for this. */
int flags;
if (for_sure == 0)
- {
- if (! lvalue_p (expr))
- first_arg = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node);
- flags = LOOKUP_PROTECT;
- }
+ flags = LOOKUP_PROTECT;
else
flags = LOOKUP_NORMAL;
- rval = build_method_call (first_arg, constructor_name_full (typename),
+ rval = build_method_call (expr,
+ constructor_name_full (typename),
NULL_TREE, NULL_TREE, flags);
if (rval == error_mark_node)
{
return NULL_TREE;
return error_mark_node;
}
- TREE_VALUE (TREE_OPERAND (rval, 1)) = expr;
- if (IS_AGGR_TYPE (type))
- {
- tree init = build_method_call (NULL_TREE,
- constructor_name_full (type),
- build_tree_list (NULL_TREE, rval), NULL_TREE, LOOKUP_NORMAL);
- tree temp = build_cplus_new (type, init, 1);
- return build_up_reference (TYPE_REFERENCE_TO (type), temp,
- LOOKUP_COMPLAIN, 1);
- }
return convert (xtype, rval);
}
if (TYPE_BINFO_BASETYPES (basetype))
else
break;
}
+#endif
/* No free conversions for reference types, right?. */
return NULL_TREE;
}
else if (type == float_type_node)
type = double_type_node;
- return build_type_variant (type, constp, volatilep);
+ return c_build_type_variant (type, constp, volatilep);
}
builtin_type_tdescs_arr[builtin_type_tdescs_len++]
= build_pointer_type (type);
builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_type_variant (TYPE_POINTER_TO (type), 1, 0);
+ = build_pointer_type (build_type_variant (type, 1, 0));
}
if (TREE_CODE (type) != VOID_TYPE)
{
builtin_type_tdescs_arr[builtin_type_tdescs_len++]
= build_reference_type (type);
builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_type_variant (TYPE_REFERENCE_TO (type), 1, 0);
+ = build_reference_type (build_type_variant (type, 1, 0));
}
}
}
vtbl_type_node
= build_array_type (vtable_entry_type, NULL_TREE);
layout_type (vtbl_type_node);
- vtbl_type_node = build_type_variant (vtbl_type_node, 1, 0);
+ vtbl_type_node = c_build_type_variant (vtbl_type_node, 1, 0);
record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node);
/* Simplify life by making a "sigtable_entry_type". Give its
if (pedantic && (constp || volatilep))
pedwarn ("function declared to return const or volatile result");
#else
- /* Merge any constancy or volatility into the target type
- for the pointer. */
+ /* Merge any constancy or volatility into the function return
+ type. */
if (constp || volatilep)
{
- type = build_type_variant (type, constp, volatilep);
+ type = c_build_type_variant (type, constp, volatilep);
if (IS_AGGR_TYPE (type))
build_pointer_type (type);
constp = 0;
signature pointer/reference itself. */
if (! IS_SIGNATURE (type))
{
- type = build_type_variant (type, constp, volatilep);
+ type = c_build_type_variant (type, constp, volatilep);
if (IS_AGGR_TYPE (type))
build_pointer_type (type);
constp = 0;
/* Note that the grammar rejects storage classes
in typenames, fields or parameters. */
if (constp || volatilep)
- type = build_type_variant (type, constp, volatilep);
+ type = c_build_type_variant (type, constp, volatilep);
/* If the user declares "struct {...} foo" then `foo' will have
an anonymous name. Fill that name in now. Nothing can
if (IS_SIGNATURE (type))
error ("`const' or `volatile' specified with signature type");
else
- type = build_type_variant (type, constp, volatilep);
+ type = c_build_type_variant (type, constp, volatilep);
/* Special case: "friend class foo" looks like a TYPENAME context. */
if (friendp)
{
/* Transfer const-ness of array into that of type pointed to. */
type = build_pointer_type
- (build_type_variant (TREE_TYPE (type), constp, volatilep));
+ (c_build_type_variant (TREE_TYPE (type), constp, volatilep));
volatilep = constp = 0;
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
warn_conversion = setting;
else if (!strcmp (p, "parentheses"))
warn_parentheses = setting;
+ else if (!strcmp (p, "non-virtual-dtor"))
+ warn_nonvdtor = setting;
else if (!strcmp (p, "extern-inline"))
warn_extern_inline = setting;
else if (!strcmp (p, "comment"))
{
tree decl = TREE_VALUE (saved_inlines);
saved_inlines = TREE_CHAIN (saved_inlines);
- if (TREE_ASM_WRITTEN (decl))
+ /* Redefinition of a member function can cause DECL_SAVED_INSNS to be
+ 0; don't crash. */
+ if (TREE_ASM_WRITTEN (decl) || DECL_SAVED_INSNS (decl) == 0)
continue;
if (DECL_FUNCTION_MEMBER_P (decl) && !TREE_PUBLIC (decl))
{
|| (DECL_INLINE (decl) && ! flag_implement_inlines));
}
}
- if (TREE_PUBLIC (decl) || TREE_ADDRESSABLE (decl)
+ if (TREE_PUBLIC (decl)
+ || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
|| flag_keep_inline_functions)
{
if (DECL_EXTERNAL (decl)
{
/* we are here for cases like const T* etc. */
grok_template_type (tvec, &TYPE_MAIN_VARIANT (*type));
- *type = build_type_variant (TYPE_MAIN_VARIANT (*type),
- TYPE_READONLY (*type),
- TYPE_VOLATILE (*type));
+ *type = c_build_type_variant (TYPE_MAIN_VARIANT (*type),
+ TYPE_READONLY (*type),
+ TYPE_VOLATILE (*type));
}
else
*type = TREE_VEC_ELT (tvec, TEMPLATE_TYPE_IDX (*type));
&& type != integer_type_node
&& type != void_type_node
&& type != char_type_node)
- type = build_type_variant (tsubst (type, args, nargs, in_decl),
- TYPE_READONLY (type),
- TYPE_VOLATILE (type));
+ type = c_build_type_variant (tsubst (type, args, nargs, in_decl),
+ TYPE_READONLY (type),
+ TYPE_VOLATILE (type));
switch (TREE_CODE (t))
{
case RECORD_TYPE:
tsubst (TYPE_MAX_VALUE (t), args, nargs, in_decl));
case TEMPLATE_TYPE_PARM:
- return build_type_variant (args[TEMPLATE_TYPE_IDX (t)],
- TYPE_READONLY (t),
- TYPE_VOLATILE (t));
+ return c_build_type_variant (args[TEMPLATE_TYPE_IDX (t)],
+ TYPE_READONLY (t),
+ TYPE_VOLATILE (t));
case TEMPLATE_CONST_PARM:
return args[TEMPLATE_CONST_IDX (t)];
r = build_pointer_type (type);
else
r = build_reference_type (type);
- r = build_type_variant (r, TYPE_READONLY (t), TYPE_VOLATILE (t));
+ r = c_build_type_variant (r, TYPE_READONLY (t), TYPE_VOLATILE (t));
/* Will this ever be needed for TYPE_..._TO values? */
layout_type (r);
return r;
}
else
{
- tree sig_tbl_type = build_type_variant (to_type, 1, 0);
+ tree sig_tbl_type = c_build_type_variant (to_type, 1, 0);
sptr = build_lang_field_decl (FIELD_DECL,
get_identifier (SIGNATURE_SPTR_NAME),
int constflag = TYPE_READONLY (type) || TYPE_READONLY (like);
int volflag = TYPE_VOLATILE (type) || TYPE_VOLATILE (like);
/* @@ Must do member pointers here. */
- return build_type_variant (type, constflag, volflag);
+ return c_build_type_variant (type, constflag, volflag);
}
\f
/* Return the common type of two parameter lists.
= TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2));
int volatilep
= TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
- target = build_type_variant (target, constp, volatilep);
+ target = c_build_type_variant (target, constp, volatilep);
if (code1 == POINTER_TYPE)
t1 = build_pointer_type (target);
else
restype = TREE_TYPE (type);
if (TYPE_READONLY (type) || TYPE_VOLATILE (type)
|| constp || volatilep)
- restype = build_type_variant (restype,
- TYPE_READONLY (type) || constp,
- TYPE_VOLATILE (type) || volatilep);
+ restype = c_build_type_variant (restype,
+ TYPE_READONLY (type) || constp,
+ TYPE_VOLATILE (type) || volatilep);
ptrtype = build_pointer_type (restype);
if (TREE_CODE (exp) == VAR_DECL)
if (try == 0)
{
cp_error ("no match for `%O(%#T, %#T)'", code,
- types[convert_index], types[convert_index ^ 1]);
+ TREE_TYPE (arg1), TREE_TYPE (arg2));
return error_mark_node;
}
if (try == error_mark_node)
|| TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
{
if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
- argtype = build_type_variant (argtype,
- TREE_READONLY (arg),
- TREE_THIS_VOLATILE (arg));
+ argtype = c_build_type_variant (argtype,
+ TREE_READONLY (arg),
+ TREE_THIS_VOLATILE (arg));
}
argtype = build_pointer_type (argtype);
else if (TREE_READONLY_DECL_P (op2))
op2 = decl_constant_value (op2);
if (type1 != type2)
- type1 = build_type_variant
+ type1 = c_build_type_variant
(type1,
TREE_READONLY (op1) || TREE_READONLY (op2),
TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
if (type1 == type2)
result_type = type1;
else
- result_type = build_type_variant
+ result_type = c_build_type_variant
(type1,
TREE_READONLY (op1) || TREE_READONLY (op2),
TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
}
current_function_returns_value = returns_value;
+#if 0
+ /* These wind up after the BARRIER, which causes problems for
+ expand_end_binding. What purpose were they supposed to serve? */
if (original_result_rtx)
use_variable (original_result_rtx);
if (use_temp)
use_variable (DECL_RTL (DECL_RESULT (current_function_decl)));
+#endif
/* One way to clear out cleanups that EXPR might
generate. Note that this code will really be