+1998-10-19 Jason Merrill <jason@yorick.cygnus.com>
+
+ Revamp references to member functions.
+ * method.c (hack_identifier): Call build_component_ref for a
+ reference to a member function.
+ * typeck.c (build_component_ref): Only return a single function
+ if it's static. Otherwise, return a COMPONENT_REF.
+ (build_x_function_call): Handle a COMPONENT_REF.
+ (build_unary_op): Handle all unknown-type things.
+ * decl2.c (arg_assoc): Handle COMPONENT_REF.
+ * class.c (instantiate_type): Complain if the function we get is a
+ nonstatic member function. Remove code for finding "compatible"
+ functions.
+ * pt.c (tsubst_copy): Handle NOP_EXPR.
+ * tree.c (build_dummy_object): New fn.
+ (maybe_dummy_object): New fn.
+ (is_dummy_object): New fn.
+ * cp-tree.h: Declare them.
+ * cvt.c (cp_convert_to_pointer): Use maybe_dummy_object.
+ * error.c (dump_expr, case OFFSET_REF): Use is_dummy_object.
+ * init.c (build_member_call): Use maybe_dummy_object and
+ is_dummy_object.
+ (build_offset_ref): Use maybe_dummy_object.
+ (resolve_offset_ref): Use is_dummy_object.
+ * typeck.c (build_x_function_call): Call build_dummy_object.
+ (unary_complex_lvalue): Call is_dummy_object.
+
+ * typeck.c (build_component_addr): Make sure field is a field.
+
+ * call.c (build_new_op): Delete obsolete code.
+
+ * pt.c (tsubst, TEMPLATE*PARM*): Abort if we don't have any args.
+
1998-10-18 Martin von Löwis <loewis@informatik.hu-berlin.de>
* decl2.c (validate_nonmember_using_decl): Fix using-directives of
{
case NEW_EXPR:
case VEC_NEW_EXPR:
- {
- tree rval;
-
- arglist = scratch_tree_cons (NULL_TREE, arg2, arg3);
- if (flags & LOOKUP_GLOBAL)
- return build_new_function_call
- (lookup_function_nonclass (fnname, arglist), arglist);
-
- /* FIXME */
- rval = build_method_call
- (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node),
- "new"),
- fnname, arglist, NULL_TREE, flags);
- if (rval == error_mark_node)
- /* User might declare fancy operator new, but invoke it
- like standard one. */
- return rval;
-
- TREE_TYPE (rval) = arg1;
- return rval;
- }
-
case VEC_DELETE_EXPR:
case DELETE_EXPR:
- {
- tree rval;
-
- if (flags & LOOKUP_GLOBAL)
- {
- arglist = build_scratch_list (NULL_TREE, arg1);
- return build_new_function_call
- (lookup_function_nonclass (fnname, arglist), arglist);
- }
-
- arglist = scratch_tree_cons (NULL_TREE, arg1, build_scratch_list (NULL_TREE, arg2));
-
- arg1 = TREE_TYPE (arg1);
-
- /* This handles the case where we're trying to delete
- X (*a)[10];
- a=new X[5][10];
- delete[] a; */
-
- if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
- {
- /* Strip off the pointer and the array. */
- arg1 = TREE_TYPE (TREE_TYPE (arg1));
-
- while (TREE_CODE (arg1) == ARRAY_TYPE)
- arg1 = (TREE_TYPE (arg1));
-
- arg1 = build_pointer_type (arg1);
- }
-
- /* FIXME */
- rval = build_method_call
- (build_indirect_ref (build1 (NOP_EXPR, arg1,
- error_mark_node),
- NULL_PTR),
- fnname, arglist, NULL_TREE, flags);
-#if 0
- /* This can happen when operator delete is protected. */
- my_friendly_assert (rval != error_mark_node, 250);
- TREE_TYPE (rval) = void_type_node;
-#endif
- return rval;
- }
+ /* Use build_op_new_call and build_op_delete_call instead. */
+ my_friendly_abort (981018);
case CALL_EXPR:
return build_object_call (arg1, arg2);
if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL)
&& (TYPE_GETS_NEW (type) & (1 << (code == VEC_NEW_EXPR))))
{
- tree dummy = build1 (NOP_EXPR, build_pointer_type (type),
- error_mark_node);
- dummy = build_indirect_ref (dummy, "new");
- return build_method_call (dummy, fnname, args, NULL_TREE, flags);
+ return build_method_call (build_dummy_object (type),
+ fnname, args, NULL_TREE, flags);
}
else
return build_new_function_call
&& value_member (cand->fn, get_abstract_virtuals (basetype)))
cp_error ("abstract virtual `%#D' called from constructor", cand->fn);
if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
- && TREE_CODE (instance_ptr) == NOP_EXPR
- && TREE_OPERAND (instance_ptr, 0) == error_mark_node)
+ && is_dummy_object (instance_ptr))
cp_error ("cannot call member function `%D' without object", cand->fn);
if (DECL_VINDEX (cand->fn) && ! (flags & LOOKUP_NONVIRTUAL)
if (function == error_mark_node)
return error_mark_node;
my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 185);
- if (DECL_VINDEX (function))
- {
- tree base = TREE_OPERAND (rhs, 0);
- tree base_ptr = build_unary_op (ADDR_EXPR, base, 0);
- if (base_ptr == error_mark_node)
- return error_mark_node;
- base_ptr = convert_pointer_to (DECL_CONTEXT (function), base_ptr);
- if (base_ptr == error_mark_node)
- return error_mark_node;
- return build_vfn_ref (&base_ptr, base, DECL_VINDEX (function));
- }
+
+ if (! DECL_STATIC_FUNCTION_P (function))
+ cp_error ("reference to `%D' can only be used in a call",
+ function);
+
mark_used (function);
return function;
}
elem = OVL_NEXT (elem);
}
- /* No exact match found, look for a compatible method. */
- for (baselink = rhs; baselink;
- baselink = next_baselink (baselink))
- {
- elem = TREE_VALUE (baselink);
- for (; elem; elem = OVL_NEXT (elem))
- if (comp_target_types (lhstype,
- TREE_TYPE (OVL_CURRENT (elem)), 1) > 0)
- break;
- if (elem)
- {
- tree save_elem = OVL_CURRENT (elem);
- for (elem = OVL_NEXT (elem); elem; elem = OVL_NEXT (elem))
- if (comp_target_types (lhstype,
- TREE_TYPE (OVL_CURRENT (elem)), 0) > 0)
- break;
- if (elem)
- {
- if (complain)
- error ("ambiguous overload for overloaded method requested");
- return error_mark_node;
- }
- mark_used (save_elem);
- return save_elem;
- }
- name = rhs;
- while (TREE_CODE (name) == TREE_LIST)
- name = TREE_VALUE (name);
- name = DECL_NAME (OVL_CURRENT (name));
-#if 0
- if (TREE_CODE (lhstype) == FUNCTION_TYPE && globals < 0)
- {
- /* Try to instantiate from non-member functions. */
- rhs = lookup_name_nonclass (name);
- if (rhs && TREE_CODE (rhs) == TREE_LIST)
- {
- /* This code seems to be missing a `return'. */
- my_friendly_abort (4);
- instantiate_type (lhstype, rhs, complain);
- }
- }
-#endif
- }
+ name = rhs;
+ while (TREE_CODE (name) == TREE_LIST)
+ name = TREE_VALUE (name);
+ name = DECL_NAME (OVL_CURRENT (name));
+
if (complain)
cp_error ("no compatible member functions named `%D'", name);
return error_mark_node;
extern tree no_linkage_check PROTO((tree));
extern void debug_binfo PROTO((tree));
extern void push_expression_obstack PROTO((void));
+extern tree build_dummy_object PROTO((tree));
+extern tree maybe_dummy_object PROTO((tree, tree *));
+extern int is_dummy_object PROTO((tree));
#define scratchalloc expralloc
#define scratch_tree_cons expr_tree_cons
#define build_scratch_list build_expr_list
functions. */
if (TYPE_PTRMEMFUNC_P (intype))
{
- tree decl, basebinfo;
tree fntype = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (intype));
- tree t = TYPE_METHOD_BASETYPE (fntype);
-
- if (current_class_type == 0
- || get_base_distance (t, current_class_type, 0, &basebinfo)
- == -1)
- {
- decl = build1 (NOP_EXPR, t, error_mark_node);
- }
- else if (current_class_ptr == 0)
- decl = build1 (NOP_EXPR, t, error_mark_node);
- else
- decl = current_class_ref;
-
+ tree decl = maybe_dummy_object (TYPE_METHOD_BASETYPE (fntype), 0);
expr = build (OFFSET_REF, fntype, decl, expr);
}
if (TREE_CODE (n) == ADDR_EXPR)
n = TREE_OPERAND (n, 0);
+ if (TREE_CODE (n) == COMPONENT_REF)
+ n = TREE_OPERAND (n, 1);
while (TREE_CODE (n) == TREE_LIST)
n = TREE_VALUE (n);
+ if (TREE_CODE (n) == FUNCTION_DECL)
+ return arg_assoc_type (k, TREE_TYPE (n));
if (TREE_CODE (n) == TEMPLATE_ID_EXPR)
{
/* [basic.lookup.koenig]
my_friendly_assert (TREE_CODE (n) == OVERLOAD, 980715);
for (; n; n = OVL_CHAIN (n))
- if (arg_assoc (k, OVL_FUNCTION (n)))
+ if (arg_assoc_type (k, TREE_TYPE (OVL_FUNCTION (n))))
return 1;
}
case OFFSET_REF:
{
tree ob = TREE_OPERAND (t, 0);
- if (TREE_CODE (ob) == NOP_EXPR
- && TREE_OPERAND (ob, 0) == error_mark_node)
+ if (is_dummy_object (ob))
{
if (TREE_CODE (TREE_OPERAND (t, 1)) == FUNCTION_DECL)
/* A::f */
tree t;
tree method_name;
int dtor = 0;
- int dont_use_this = 0;
tree basetype_path, decl;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR
return error_mark_node;
}
- /* No object? Then just fake one up, and let build_method_call
- figure out what to do. */
- if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basetype_path) == -1)
- dont_use_this = 1;
+ decl = maybe_dummy_object (type, &basetype_path);
- if (dont_use_this)
- {
- basetype_path = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
- }
- else if (current_class_ptr == 0)
- {
- dont_use_this = 1;
- decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
- }
- else
+ /* Convert 'this' to the specified type to disambiguate conversion
+ to the function's context. */
+ if (decl == current_class_ref)
{
tree olddecl = current_class_ptr;
tree oldtype = TREE_TYPE (TREE_TYPE (olddecl));
tree newtype = build_type_variant (type, TYPE_READONLY (oldtype),
TYPE_VOLATILE (oldtype));
decl = convert_force (build_pointer_type (newtype), olddecl, 0);
+ decl = build_indirect_ref (decl, NULL_PTR);
}
- else
- decl = olddecl;
}
- decl = build_indirect_ref (decl, NULL_PTR);
-
if (method_name == constructor_name (type)
|| method_name == constructor_name_full (type))
return build_functional_cast (type, parmlist);
return error_mark_node;
if (TREE_CODE (t) == FIELD_DECL)
{
- if (dont_use_this)
+ if (is_dummy_object (decl))
{
cp_error ("invalid use of non-static field `%D'", t);
return error_mark_node;
return error_mark_node;
}
- if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basebinfo) == -1)
- {
- basebinfo = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR, type, error_mark_node);
- }
- else if (current_class_ptr == 0)
- decl = build1 (NOP_EXPR, type, error_mark_node);
- else
- decl = current_class_ref;
+ decl = maybe_dummy_object (type, &basebinfo);
fnfields = lookup_fnfields (basebinfo, name, 1);
fields = lookup_field (basebinfo, name, 0, 0);
/* The first case is really just a reference to a member of `this'. */
if (TREE_CODE (member) == FIELD_DECL
- && (base == current_class_ref
- || (TREE_CODE (base) == NOP_EXPR
- && TREE_OPERAND (base, 0) == error_mark_node)))
+ && (base == current_class_ref || is_dummy_object (base)))
{
tree basetype_path;
tree access;
}
/* Ensure that we have an object. */
- if (TREE_CODE (base) == NOP_EXPR
- && TREE_OPERAND (base, 0) == error_mark_node)
+ if (is_dummy_object (base))
addr = error_mark_node;
else
/* If this is a reference to a member function, then return the
TREE_USED (value) = 1;
value = build_component_ref (current_class_ref, name, NULL_TREE, 1);
}
+ else if (TREE_CODE (value) == FUNCTION_DECL
+ && DECL_FUNCTION_MEMBER_P (value))
+ {
+ tree decl;
+
+ if (IS_SIGNATURE (DECL_CLASS_CONTEXT (value)))
+ return value;
+
+ decl = maybe_dummy_object (DECL_CLASS_CONTEXT (value), 0);
+ value = build_component_ref (decl, name, NULL_TREE, 1);
+ }
else if (really_overloaded_fn (value))
{
#if 0
return arg;
}
}
+ else
+ my_friendly_abort (981018);
if (level == 1)
/* This can happen during the attempted tsubst'ing in
case CONST_CAST_EXPR:
case STATIC_CAST_EXPR:
case DYNAMIC_CAST_EXPR:
+ case NOP_EXPR:
return build1
(code, tsubst (TREE_TYPE (t), args, in_decl),
tsubst_copy (TREE_OPERAND (t, 0), args, in_decl));
tree ctx = DECL_CONTEXT (decl);
return (ctx && TREE_CODE_CLASS (TREE_CODE (ctx)) == 't');
}
+
+/* Create a placeholder for member access where we don't actually have an
+ object that the access is against. */
+
+tree
+build_dummy_object (type)
+ tree type;
+{
+ tree decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
+ return build_indirect_ref (decl, NULL_PTR);
+}
+
+/* We've gotten a reference to a member of TYPE. Return *this if appropriate,
+ or a dummy object otherwise. If BINFOP is non-0, it is filled with the
+ binfo path from current_class_type to TYPE, or 0. */
+
+tree
+maybe_dummy_object (type, binfop)
+ tree type;
+ tree *binfop;
+{
+ tree decl, context;
+
+ if (current_class_type
+ && get_base_distance (type, current_class_type, 0, binfop) != -1)
+ context = current_class_type;
+ else
+ {
+ /* Reference from a nested class member function. */
+ context = type;
+ if (binfop)
+ *binfop = TYPE_BINFO (type);
+ }
+
+ if (current_class_ref && context == current_class_type)
+ decl = current_class_ref;
+ else
+ decl = build_dummy_object (context);
+
+ return decl;
+}
+
+/* Returns 1 if OB is a placeholder object, or a pointer to one. */
+
+int
+is_dummy_object (ob)
+ tree ob;
+{
+ if (TREE_CODE (ob) == INDIRECT_REF)
+ ob = TREE_OPERAND (ob, 0);
+ return (TREE_CODE (ob) == NOP_EXPR
+ && TREE_OPERAND (ob, 0) == error_mark_node);
+}
return error_mark_node;
if (fndecls)
{
+ /* If the function is unique and static, we can resolve it
+ now. Otherwise, we have to wait and see what context it is
+ used in; a component_ref involving a non-static member
+ function can only be used in a call (expr.ref). */
if (TREE_CHAIN (fndecls) == NULL_TREE
- && TREE_CODE (TREE_VALUE (fndecls)) != OVERLOAD)
+ && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (TREE_VALUE (fndecls)))
{
- tree access, fndecl;
+ tree fndecl;
- /* Unique, so use this one now. */
basetype = TYPE_MAIN_VARIANT (TREE_PURPOSE (fndecls));
fndecl = TREE_VALUE (fndecls);
- access = compute_access (TREE_PURPOSE (fndecls), fndecl);
- if (access == access_public_node)
- {
- if (DECL_VINDEX (fndecl)
- && ! resolves_to_fixed_type_p (datum, 0))
- {
- tree addr = build_unary_op (ADDR_EXPR, datum, 0);
- tree fntype = TREE_TYPE (fndecl);
-
- addr = convert_pointer_to (DECL_CONTEXT (fndecl),
- addr);
- datum = build_indirect_ref (addr, NULL_PTR);
- my_friendly_assert (datum != error_mark_node, 310);
- fndecl = build_vfn_ref (&addr, datum,
- DECL_VINDEX (fndecl));
- /* The type of fndecl is a function type,
- not a pointer-to-function type, since
- build_vfn_ref returns not the correct
- vtable slot, but the indirection of the
- correct vtable slot. */
- TREE_TYPE (fndecl) = fntype;
- }
- else
- mark_used (fndecl);
- return build (OFFSET_REF, TREE_TYPE (fndecl),
- datum, fndecl);
- }
- if (access == access_protected_node)
- cp_error ("member function `%D' is protected", fndecl);
- else
- cp_error ("member function `%D' is private", fndecl);
- return error_mark_node;
+ enforce_access (TREE_PURPOSE (fndecls), fndecl);
+ mark_used (fndecl);
+ return fndecl;
}
else
{
- /* Just act like build_offset_ref, since the object does
- not matter unless we're actually calling the function. */
- tree t;
-
- t = build_tree_list (error_mark_node, fndecls);
- TREE_TYPE (t) = build_offset_type (basetype,
- unknown_type_node);
- return t;
+ ref = build (COMPONENT_REF, unknown_type_node,
+ datum, fndecls);
+ return ref;
}
}
return error_mark_node;
}
/* Yow: call from a static member function. */
- decl = build1 (NOP_EXPR, build_pointer_type (current_class_type),
- error_mark_node);
- decl = build_indirect_ref (decl, NULL_PTR);
+ decl = build_dummy_object (current_class_type);
}
/* Put back explicit template arguments, if any. */
else if (TREE_CODE (function) == COMPONENT_REF
&& type == unknown_type_node)
{
- /* Should we undo what was done in build_component_ref? */
- if (TREE_CODE (TREE_PURPOSE (TREE_OPERAND (function, 1))) == TREE_VEC)
- /* Get the name that build_component_ref hid. */
- function = DECL_NAME (TREE_VALUE (TREE_OPERAND (function, 1)));
- else
- function = TREE_PURPOSE (TREE_OPERAND (function, 1));
+ /* Undo what we did in build_component_ref. */
+ decl = TREE_OPERAND (function, 0);
+ function = TREE_OPERAND (function, 1);
+ function = DECL_NAME (OVL_CURRENT (TREE_VALUE (function)));
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
tree basetype = decl_type_context (field);
tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+ my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 981018);
+
if (DECL_C_BIT_FIELD (field))
{
error (msg, IDENTIFIER_POINTER (DECL_NAME (field)));
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
- if (TREE_CODE (arg) == OVERLOAD
- || (TREE_CODE (arg) == OFFSET_REF
- && TREE_CODE (TREE_OPERAND (arg, 1)) == TEMPLATE_ID_EXPR))
- return build1 (ADDR_EXPR, unknown_type_node, arg);
- else if (TREE_CODE (arg) == TREE_LIST)
- {
- if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL)
- /* Unique overloaded non-member function. */
- return build_unary_op (ADDR_EXPR, TREE_VALUE (arg), 0);
- if (TREE_CHAIN (arg) == NULL_TREE
- && TREE_CODE (TREE_VALUE (arg)) == TREE_LIST
- && TREE_CODE (TREE_VALUE (TREE_VALUE (arg))) != OVERLOAD)
- /* Unique overloaded member function. */
- return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)),
- 0);
- return build1 (ADDR_EXPR, unknown_type_node, arg);
- }
- else if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
+ if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
{
tree targs;
tree fn;
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
+ else if (type_unknown_p (arg))
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
tree type;
if (TREE_OPERAND (arg, 0)
- && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
- || (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)
- != error_mark_node))
+ && ! is_dummy_object (TREE_OPERAND (arg, 0))
&& TREE_CODE (t) != FIELD_DECL)
{
cp_error ("taking address of bound pointer-to-member expression");
if (TREE_CODE (type) == VOID_TYPE)
value = build1 (CONVERT_EXPR, type, value);
else if (TREE_TYPE (value) == NULL_TREE
- || type_unknown_p (value))
+ || type_unknown_p (value))
{
value = instantiate_type (type, value, 1);
/* Did we lose? */
59 is, so they can understand how to work around it, should they
ever run into it.
- Note, there will be no more calls in the C++ front end to abort,
- because the C++ front end is so unreliable still. The C front end
- can get away with calling abort, because for most of the calls to
- abort on most machines, it, I suspect, can be proven that it is
- impossible to ever call abort. The same is not yet true for C++,
- one day, maybe it will be.
-
We used to tell people to "fix the above error[s] and try recompiling
the program" via a call to fatal, but that message tended to look
silly. So instead, we just do the equivalent of a call to fatal in the
- same situation (call exit). */
+ same situation (call exit).
-/* First used: 0 (reserved), Last used: 369. Free: */
+ We used to assign sequential numbers for the aborts; now we use an
+ encoding of the date the abort was added, since that has more meaning
+ when we only see the error message. */
static int abortcount = 0;