Type-bound procedures are stored in the tb_sym_root
of the namespace
f2k_derived
associated with the derived-type symbol as gfc_symtree
nodes. The name and symbol of these symtrees corresponds to the binding-name
of the procedure, i.e. the name that is used to call it from the context of an
object of the derived-type.
In addition, this type of symtrees stores in n.tb
a struct of type
gfc_typebound_proc
containing the additional data needed: The
binding attributes (like PASS
and NOPASS
, NON_OVERRIDABLE
or the access-specifier), the binding’s target(s) and, if the current binding
overrides or extends an inherited binding of the same name, overridden
points to this binding’s gfc_typebound_proc
structure.
For specific bindings (declared with PROCEDURE
), if they have a
passed-object argument, the passed-object dummy argument is first saved by its
name, and later during resolution phase the corresponding argument is looked for
and its position remembered as pass_arg_num
in gfc_typebound_proc
.
The binding’s target procedure is pointed-to by u.specific
.
DEFERRED
bindings are just like ordinary specific bindings, except
that their deferred
flag is set of course and that u.specific
points to their “interface” defining symbol (might be an abstract interface)
instead of the target procedure.
At the moment, all type-bound procedure calls are statically dispatched and transformed into ordinary procedure calls at resolution time; their actual argument list is updated to include at the right position the passed-object argument, if applicable, and then a simple procedure call to the binding’s target procedure is built. To handle dynamic dispatch in the future, this will be extended to allow special code generation during the trans-phase to dispatch based on the object’s dynamic type.
Bindings declared as GENERIC
store the specific bindings they target as
a linked list using nodes of type gfc_tbp_generic
in u.generic
.
For each specific target, the parser records its symtree and during resolution
this symtree is bound to the corresponding gfc_typebound_proc
structure
of the specific target.
Calls to generic bindings are handled entirely in the resolution-phase, where
for the actual argument list present the matching specific binding is found
and the call’s target procedure (value.compcall.tbp
) is re-pointed to
the found specific binding and this call is subsequently handled by the logic
for specific binding calls.
Calls to type-bound procedures are stored in the parse-tree as gfc_expr
nodes of type EXPR_COMPCALL
. Their value.compcall.actual
saves
the actual argument list of the call and value.compcall.tbp
points to the
gfc_typebound_proc
structure of the binding to be called. The object
in whose context the procedure was called is saved by combination of
symtree
and ref
, as if the expression was of type
EXPR_VARIABLE
.
For code like this:
CALL myobj%procedure (arg1, arg2)
the CALL
is represented in the parse-tree as a gfc_code
node of
type EXEC_COMPCALL
. The expr
member of this node holds an
expression of type EXPR_COMPCALL
of the same structure as mentioned above
except that its target procedure is of course a SUBROUTINE
and not a
FUNCTION
.
Expressions that are generated internally (as expansion of a type-bound
operator call) may also use additional flags and members.
value.compcall.ignore_pass
signals that even though a PASS
attribute may be present the actual argument list should not be updated because
it already contains the passed-object.
value.compcall.base_object
overrides, if it is set, the base-object
(that is normally stored in symtree
and ref
as mentioned above);
this is needed because type-bound operators can be called on a base-object that
need not be of type EXPR_VARIABLE
and thus representable in this way.
Finally, if value.compcall.assign
is set, the call was produced in
expansion of a type-bound assignment; this means that proper dependency-checking
needs to be done when relevant.