indicating a particular base class, and whose TREE_VALUE is a
(possibly overloaded) function from that base class. */
#define BASELINK_P(NODE) \
- (TREE_CODE ((NODE)) == TREE_LIST && TREE_LANG_FLAG_1 ((NODE)))
+ (TREE_CODE (NODE) == TREE_LIST && TREE_LANG_FLAG_1 (NODE))
#define SET_BASELINK_P(NODE) \
- (TREE_LANG_FLAG_1 ((NODE)) = 1)
+ (TREE_LANG_FLAG_1 (NODE) = 1)
-#define WRAPPER_PTR(NODE) (((struct tree_wrapper*)NODE)->u.ptr)
-#define WRAPPER_INT(NODE) (((struct tree_wrapper*)NODE)->u.i)
+#define WRAPPER_PTR(NODE) (((struct tree_wrapper*)(NODE))->u.ptr)
+#define WRAPPER_INT(NODE) (((struct tree_wrapper*)(NODE))->u.i)
struct tree_wrapper
{
(DECL_CONTEXT (NODE) ? DECL_CONTEXT (NODE) : global_namespace)
#define FROB_CONTEXT(NODE) ((NODE) == global_namespace ? NULL_TREE : (NODE))
+/* For a virtual function, the base where we find its vtable entry.
+ For a non-virtual function, the base where it is defined. */
+#define DECL_VIRTUAL_CONTEXT(NODE) DECL_CONTEXT (NODE)
+
/* 1 iff NODE has namespace scope, including the global namespace. */
#define DECL_NAMESPACE_SCOPE_P(NODE) \
(DECL_CONTEXT (NODE) == NULL_TREE \
\f
/* Get difference in deltas for different pointer to member function
types. Return integer_zero_node, if FROM cannot be converted to a
- TO type. If FORCE is true, then allow reverse conversions as well. */
+ TO type. If FORCE is true, then allow reverse conversions as well.
+
+ Note that the naming of FROM and TO is kind of backwards; the return
+ value is what we add to a TO in order to get a FROM. They are named
+ this way because we call this function to find out how to convert from
+ a pointer to member of FROM to a pointer to member of TO. */
static tree
get_delta_difference (from, to, force)
{
tree type = TREE_TYPE (cst);
tree fn = PTRMEM_CST_MEMBER (cst);
+ tree ptr_class, fn_class;
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
-
- *delta
- = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
- TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
- /*force=*/0);
+
+ /* The class that the function belongs to. */
+ fn_class = DECL_CLASS_CONTEXT (fn);
+
+ /* The class that we're creating a pointer to member of. */
+ ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
+
+ /* First, calculate the adjustment to the function's class. */
+ *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+
if (!DECL_VIRTUAL_P (fn))
{
- *idx = size_binop (MINUS_EXPR, integer_zero_node,
- integer_one_node);
- *pfn = build_addr_func (fn);
- if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
- TYPE_PTRMEMFUNC_OBJECT_TYPE (type)))
- *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
- *pfn);
+ *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+ *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
*delta2 = NULL_TREE;
}
else
{
- *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn),
- integer_one_node);
+ /* If we're dealing with a virtual function, we have to adjust 'this'
+ again, to point to the base which provides the vtable entry for
+ fn; the call will do the opposite adjustment. */
+ tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+ tree binfo = binfo_or_else (orig_class, fn_class);
+ *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
+
+ /* Map everything down one to make room for the null PMF. */
+ *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
*pfn = NULL_TREE;
- *delta2 = get_binfo (DECL_CONTEXT (fn),
- DECL_CLASS_CONTEXT (fn),
- 0);
- *delta2 = get_vfield_offset (*delta2);
- *delta2 = size_binop (PLUS_EXPR, *delta2,
- build_binary_op (PLUS_EXPR,
- *delta,
- integer_zero_node));
+
+ /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS. */
+ *delta2 = size_binop (PLUS_EXPR, *delta,
+ get_vfield_offset (TYPE_BINFO (orig_class)));
}
}