-/* Build a function call to function FUNCTION with parameters PARAMS.
- PARAMS is a list--a chain of TREE_LIST nodes--in which the
- TREE_VALUE of each node is a parameter-expression. The PARAMS do
- not include any object pointer that may be required. FUNCTION's
- data type may be a function type or a pointer-to-function.
-
- For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
- is the list of possible methods that FUNCTION could conceivably
- be. If the list of methods comes from a class, then it will be
- a list of lists (where each element is associated with the class
- that produced it), otherwise it will be a simple list (for
- functions overloaded in global scope).
-
- In the first case, TREE_VALUE (function) is the head of one of those
- lists, and TREE_PURPOSE is the name of the function.
-
- In the second case, TREE_PURPOSE (function) is the function's
- name directly.
-
- DECL is the class instance variable, usually CURRENT_CLASS_REF.
-
- When calling a TEMPLATE_DECL, we don't require a complete return
- type. */
-
-tree
-build_x_function_call (function, params, decl)
- tree function, params, decl;
-{
- tree type;
- tree template_id = NULL_TREE;
- int is_method;
-
- if (function == error_mark_node)
- return error_mark_node;
-
- if (processing_template_decl)
- return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
-
- /* Save explicit template arguments if found */
- if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
- {
- template_id = function;
- function = TREE_OPERAND (function, 0);
- }
-
- type = TREE_TYPE (function);
-
- if (TREE_CODE (type) == OFFSET_TYPE
- && TREE_TYPE (type) == unknown_type_node
- && TREE_CODE (function) == TREE_LIST
- && TREE_CHAIN (function) == NULL_TREE)
- {
- /* Undo (Foo:bar)()... */
- type = TYPE_OFFSET_BASETYPE (type);
- function = TREE_VALUE (function);
- my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999);
- my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999);
- function = TREE_VALUE (function);
- if (TREE_CODE (function) == OVERLOAD)
- function = OVL_FUNCTION (function);
- my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999);
- function = DECL_NAME (function);
- return build_method_call (decl, function, params,
- TYPE_BINFO (type), LOOKUP_NORMAL);
- }
-
- if (TREE_CODE (function) == OFFSET_REF
- && TREE_CODE (type) != METHOD_TYPE)
- function = resolve_offset_ref (function);
-
- if ((TREE_CODE (function) == FUNCTION_DECL
- && DECL_STATIC_FUNCTION_P (function))
- || (DECL_FUNCTION_TEMPLATE_P (function)
- && DECL_STATIC_FUNCTION_P (DECL_TEMPLATE_RESULT (function))))
- return build_member_call (DECL_CONTEXT (function),
- template_id
- ? template_id : DECL_NAME (function),
- params);
-
- is_method = ((TREE_CODE (function) == TREE_LIST
- && current_class_type != NULL_TREE
- && (IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function))
- == function))
- || (TREE_CODE (function) == OVERLOAD
- && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (function)))
- || TREE_CODE (function) == IDENTIFIER_NODE
- || TREE_CODE (type) == METHOD_TYPE
- || TYPE_PTRMEMFUNC_P (type));
-
- /* A friend template. Make it look like a toplevel declaration. */
- if (! is_method && TREE_CODE (function) == TEMPLATE_DECL)
- function = ovl_cons (function, NULL_TREE);
-
- /* Handle methods, friends, and overloaded functions, respectively. */
- if (is_method)
- {
- tree basetype = NULL_TREE;
-
- if (TREE_CODE (function) == OVERLOAD)
- function = OVL_CURRENT (function);
-
- if (TREE_CODE (function) == FUNCTION_DECL
- || DECL_FUNCTION_TEMPLATE_P (function))
- {
- basetype = DECL_CONTEXT (function);
-
- if (DECL_NAME (function))
- function = DECL_NAME (function);
- else
- function = TYPE_IDENTIFIER (DECL_CONTEXT (function));
- }
- else if (TREE_CODE (function) == TREE_LIST)
- {
- my_friendly_assert (TREE_CODE (TREE_VALUE (function))
- == FUNCTION_DECL, 312);
- basetype = DECL_CONTEXT (TREE_VALUE (function));
- function = TREE_PURPOSE (function);
- }
- else if (TREE_CODE (function) != IDENTIFIER_NODE)
- {
- if (TREE_CODE (function) == OFFSET_REF)
- {
- if (TREE_OPERAND (function, 0))
- decl = TREE_OPERAND (function, 0);
- }
- /* Call via a pointer to member function. */
- if (decl == NULL_TREE)
- {
- error ("pointer to member function called, but not in class scope");
- return error_mark_node;
- }
- /* What other type of POINTER_TYPE could this be? */
- if (TREE_CODE (TREE_TYPE (function)) != POINTER_TYPE
- && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (function))
- && TREE_CODE (function) != OFFSET_REF)
- function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE,
- function);
- goto do_x_function;
- }
-
- /* this is an abbreviated method call.
- must go through here in case it is a virtual function.
- @@ Perhaps this could be optimized. */
-
- if (basetype && (! current_class_type
- || ! DERIVED_FROM_P (basetype, current_class_type)))
- return build_member_call (basetype, function, params);
-
- if (decl == NULL_TREE)
- {
- if (current_class_type == NULL_TREE)
- {
- error ("object missing in call to method `%D'", function);
- return error_mark_node;
- }
- /* Yow: call from a static member function. */
- decl = build_dummy_object (current_class_type);
- }
-
- /* Put back explicit template arguments, if any. */
- if (template_id)
- function = template_id;
- return build_method_call (decl, function, params,
- NULL_TREE, LOOKUP_NORMAL);
- }
- else if (TREE_CODE (function) == COMPONENT_REF
- && type == unknown_type_node)
- {
- /* Undo what we did in build_component_ref. */
- decl = TREE_OPERAND (function, 0);
- function = TREE_OPERAND (function, 1);
-
- if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
- {
- my_friendly_assert (!template_id, 20011228);
-
- template_id = function;
- }
- else
- {
- function = DECL_NAME (OVL_CURRENT (function));
-
- if (template_id)
- {
- TREE_OPERAND (template_id, 0) = function;
- function = template_id;
- }
- }
-
- return build_method_call (decl, function, params,
- NULL_TREE, LOOKUP_NORMAL);
- }
- else if (really_overloaded_fn (function))
- {
- if (OVL_FUNCTION (function) == NULL_TREE)
- {
- error ("function `%D' declared overloaded, but no definitions appear with which to resolve it?!?",
- TREE_PURPOSE (function));
- return error_mark_node;
- }
- else
- {
- /* Put back explicit template arguments, if any. */
- if (template_id)
- function = template_id;
- return build_new_function_call (function, params);
- }
- }
- else
- /* Remove a potential OVERLOAD around it */
- function = OVL_CURRENT (function);
-
- do_x_function:
- if (TREE_CODE (function) == OFFSET_REF)
- {
- /* If the component is a data element (or a virtual function), we play
- games here to make things work. */
- tree decl_addr;
-
- if (TREE_OPERAND (function, 0))
- decl = TREE_OPERAND (function, 0);
- else
- decl = current_class_ref;
-
- decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
-
- /* Sigh. OFFSET_REFs are being used for too many things.
- They're being used both for -> and ->*, and we want to resolve
- the -> cases here, but leave the ->*. We could use
- resolve_offset_ref for those, too, but it would call
- get_member_function_from_ptrfunc and decl_addr wouldn't get
- updated properly. Nasty. */
- if (TREE_CODE (TREE_OPERAND (function, 1)) == FIELD_DECL)
- function = resolve_offset_ref (function);
- else
- function = TREE_OPERAND (function, 1);
-
- function = get_member_function_from_ptrfunc (&decl_addr, function);
- params = tree_cons (NULL_TREE, decl_addr, params);
- return build_function_call (function, params);
- }
-
- type = TREE_TYPE (function);
- if (type != error_mark_node)
- {
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
-
- if (IS_AGGR_TYPE (type))
- return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
- }
-
- if (is_method)
- {
- tree fntype = TREE_TYPE (function);
- tree ctypeptr = NULL_TREE;
-
- /* Explicitly named method? */
- if (TREE_CODE (function) == FUNCTION_DECL)
- ctypeptr = build_pointer_type (DECL_CLASS_CONTEXT (function));
- /* Expression with ptr-to-method type? It could either be a plain
- usage, or it might be a case where the ptr-to-method is being
- passed in as an argument. */
- else if (TYPE_PTRMEMFUNC_P (fntype))
- {
- tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE
- (TYPE_PTRMEMFUNC_FN_TYPE (fntype)));
- ctypeptr = build_pointer_type (rec);
- }
- /* Unexpected node type? */
- else
- abort ();
- if (decl == NULL_TREE)
- {
- if (current_function_decl
- && DECL_STATIC_FUNCTION_P (current_function_decl))
- error ("invalid call to member function needing `this' in static member function scope");
- else
- error ("pointer to member function called, but not in class scope");
- return error_mark_node;
- }
- if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
- && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
- {
- tree binfo = lookup_base (TREE_TYPE (decl), TREE_TYPE (ctypeptr),
- ba_check, NULL);
-
- decl = build_unary_op (ADDR_EXPR, decl, 0);
- decl = build_base_path (PLUS_EXPR, decl, binfo, 1);
- }
- else
- decl = build_c_cast (ctypeptr, decl);
- params = tree_cons (NULL_TREE, decl, params);
- }
-
- return build_function_call (function, params);
-}
-