diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 8c11cf6d18d..d678c6b56dc 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1199,6 +1199,9 @@ gfc_formal_arglist; #define gfc_get_formal_arglist() XCNEW (gfc_formal_arglist) +struct gfc_dummy_arg; + + /* The gfc_actual_arglist structure is for actual arguments and for type parameter specification lists. */ typedef struct gfc_actual_arglist @@ -1215,6 +1218,11 @@ typedef struct gfc_actual_arglist gfc_param_spec_type spec_type; struct gfc_expr *expr; + + /* The dummy arg this actual arg is associated with, if the interface + is explicit. NULL otherwise. */ + gfc_dummy_arg *associated_dummy; + struct gfc_actual_arglist *next; } gfc_actual_arglist; @@ -2298,14 +2306,33 @@ typedef struct gfc_intrinsic_arg gfc_typespec ts; unsigned optional:1, value:1; ENUM_BITFIELD (sym_intent) intent:2; - gfc_actual_arglist *actual; struct gfc_intrinsic_arg *next; - } gfc_intrinsic_arg; +typedef enum { + GFC_UNDEFINED_DUMMY_ARG = 0, + GFC_INTRINSIC_DUMMY_ARG, + GFC_NON_INTRINSIC_DUMMY_ARG +} +gfc_dummy_arg_intrinsicness; + +/* dummy arg of either an intrinsic or a user-defined procedure. */ +struct gfc_dummy_arg +{ + gfc_dummy_arg_intrinsicness intrinsicness; + + union { + gfc_intrinsic_arg *intrinsic; + gfc_formal_arglist *non_intrinsic; + } u; +}; + +#define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) + + /* Specifies the various kinds of check functions used to verify the argument lists of intrinsic functions. fX with X an integer refer to check functions of intrinsics with X arguments. f1m is used for diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 24698be8364..c4ec0d89a58 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -3043,6 +3043,18 @@ lookup_arg_fuzzy (const char *arg, gfc_formal_arglist *arguments) } +static gfc_dummy_arg * +get_nonintrinsic_dummy_arg (gfc_formal_arglist *formal) +{ + gfc_dummy_arg * const dummy_arg = gfc_get_dummy_arg (); + + dummy_arg->intrinsicness = GFC_NON_INTRINSIC_DUMMY_ARG; + dummy_arg->u.non_intrinsic = formal; + + return dummy_arg; +} + + /* Given formal and actual argument lists, see if they are compatible. If they are compatible, the actual argument list is sorted to correspond with the formal list, and elements for missing optional @@ -3150,6 +3162,8 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, "call at %L", where); return false; } + else + a->associated_dummy = get_nonintrinsic_dummy_arg (f); if (a->expr == NULL) { @@ -3646,9 +3660,12 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, /* The argument lists are compatible. We now relink a new actual argument list with null arguments in the right places. The head of the list remains the head. */ - for (i = 0; i < n; i++) + for (f = formal, i = 0; f; f = f->next, i++) if (new_arg[i] == NULL) - new_arg[i] = gfc_get_actual_arglist (); + { + new_arg[i] = gfc_get_actual_arglist (); + new_arg[i]->associated_dummy = get_nonintrinsic_dummy_arg (f); + } if (na != 0) { diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index 49ef3b2a3d2..f6d061a847c 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4236,6 +4236,18 @@ remove_nullargs (gfc_actual_arglist **ap) } +static gfc_dummy_arg * +get_intrinsic_dummy_arg (gfc_intrinsic_arg *intrinsic) +{ + gfc_dummy_arg * const dummy_arg = gfc_get_dummy_arg (); + + dummy_arg->intrinsicness = GFC_INTRINSIC_DUMMY_ARG; + dummy_arg->u.intrinsic = intrinsic; + + return dummy_arg; +} + + /* Given an actual arglist and a formal arglist, sort the actual arglist so that its arguments are in a one-to-one correspondence with the format arglist. Arguments that are not present are given @@ -4253,8 +4265,14 @@ sort_actual (const char *name, gfc_actual_arglist **ap, remove_nullargs (ap); actual = *ap; + auto_vec dummy_args; + auto_vec ordered_actual_args; + for (f = formal; f; f = f->next) - f->actual = NULL; + dummy_args.safe_push (f); + + ordered_actual_args.safe_grow_cleared (dummy_args.length (), + /* exact = */true); f = formal; a = actual; @@ -4306,7 +4324,7 @@ sort_actual (const char *name, gfc_actual_arglist **ap, } } - for (;;) + for (int i = 0;; i++) { /* Put the nonkeyword arguments in a 1:1 correspondence */ if (f == NULL) break; @@ -4316,7 +4334,7 @@ sort_actual (const char *name, gfc_actual_arglist **ap, if (a->name != NULL) goto keywords; - f->actual = a; + ordered_actual_args[i] = a; f = f->next; a = a->next; @@ -4334,7 +4352,8 @@ keywords: to be keyword arguments. */ for (; a; a = a->next) { - for (f = formal; f; f = f->next) + int idx; + FOR_EACH_VEC_ELT (dummy_args, idx, f) if (strcmp (a->name, f->name) == 0) break; @@ -4349,21 +4368,21 @@ keywords: return false; } - if (f->actual != NULL) + if (ordered_actual_args[idx] != NULL) { gfc_error ("Argument %qs appears twice in call to %qs at %L", f->name, name, where); return false; } - - f->actual = a; + ordered_actual_args[idx] = a; } optional: /* At this point, all unmatched formal args must be optional. */ - for (f = formal; f; f = f->next) + int idx; + FOR_EACH_VEC_ELT (dummy_args, idx, f) { - if (f->actual == NULL && f->optional == 0) + if (ordered_actual_args[idx] == NULL && f->optional == 0) { gfc_error ("Missing actual argument %qs in call to %qs at %L", f->name, name, where); @@ -4376,9 +4395,9 @@ do_sort: together in a way that corresponds with the formal list. */ actual = NULL; - for (f = formal; f; f = f->next) + FOR_EACH_VEC_ELT (dummy_args, idx, f) { - a = f->actual; + a = ordered_actual_args[idx]; if (a && a->label != NULL && f->ts.type) { gfc_error ("ALTERNATE RETURN not permitted at %L", where); @@ -4391,6 +4410,8 @@ do_sort: a->missing_arg_type = f->ts.type; } + a->associated_dummy = get_intrinsic_dummy_arg (f); + if (actual == NULL) *ap = a; else