Hi all, here is another small patch for an accepts-invalid OOP problem: When overriding a type-bound procedure, we need to check that the intents of the formal args agree (or more general: their 'characteristics', as defined in chapter 12.3.2 of the F08 standard). For now I'm only checking type+rank as well as the INTENT and OPTIONAL attributes, but I added a FIXME for more comprehensive checking (which could be added in a follow-up patch).
On the technical side of things, I'm adding a new function 'check_dummy_characteristics', which is called in two places: * gfc_compare_interfaces and * gfc_check_typebound_override. A slight subtlety is given by the fact that for the PASS argument, the type of the argument does not have to agree when overriding. The improved checking also caught an invalid test case in the testsuite (dynamic_dispatch_5), for another one the error message changed slightly (typebound_proc_6). Regtested on x86_64-unknown-linux-gnu. Ok for trunk? Cheers, Janus 2011-09-09 Janus Weil <ja...@gcc.gnu.org> PR fortran/47978 * interface.c (check_dummy_characteristics): New function to check the characteristics of dummy arguments. (gfc_compare_interfaces,gfc_check_typebound_override): Call it here. 2011-09-09 Janus Weil <ja...@gcc.gnu.org> PR fortran/47978 * gfortran.dg/dynamic_dispatch_5.f03: Fix invalid test case. * gfortran.dg/typebound_proc_6.f03: Changed wording in error message. * gfortran.dg/typebound_override_1.f90: New.
Index: gcc/testsuite/gfortran.dg/dynamic_dispatch_5.f03 =================================================================== --- gcc/testsuite/gfortran.dg/dynamic_dispatch_5.f03 (revision 178722) +++ gcc/testsuite/gfortran.dg/dynamic_dispatch_5.f03 (working copy) @@ -56,7 +56,7 @@ module s_base_mat_mod contains subroutine s_scals(d,a,info) implicit none - class(s_base_sparse_mat), intent(in) :: a + class(s_base_sparse_mat), intent(inout) :: a real(spk_), intent(in) :: d integer, intent(out) :: info @@ -73,7 +73,7 @@ contains subroutine s_scal(d,a,info) implicit none - class(s_base_sparse_mat), intent(in) :: a + class(s_base_sparse_mat), intent(inout) :: a real(spk_), intent(in) :: d(:) integer, intent(out) :: info Index: gcc/testsuite/gfortran.dg/typebound_proc_6.f03 =================================================================== --- gcc/testsuite/gfortran.dg/typebound_proc_6.f03 (revision 178722) +++ gcc/testsuite/gfortran.dg/typebound_proc_6.f03 (working copy) @@ -89,7 +89,7 @@ MODULE testmod ! For corresponding dummy arguments. PROCEDURE, PASS :: corresp1 => proc_tmeint ! Ok. PROCEDURE, PASS :: corresp2 => proc_tmeintx ! { dg-error "should be named 'a'" } - PROCEDURE, PASS :: corresp3 => proc_tmereal ! { dg-error "Types mismatch for dummy argument 'a'" } + PROCEDURE, PASS :: corresp3 => proc_tmereal ! { dg-error "Type/rank mismatch in argument 'a'" } END TYPE t Index: gcc/fortran/interface.c =================================================================== --- gcc/fortran/interface.c (revision 178722) +++ gcc/fortran/interface.c (working copy) @@ -977,6 +977,45 @@ generic_correspondence (gfc_formal_arglist *f1, gf } +/* Check if the characteristics of two dummy arguments match, cf. F08:12.3.2. */ + +static gfc_try +check_dummy_characteristics (gfc_symbol *s1, gfc_symbol *s2, + bool type_must_agree, char *errmsg, int err_len) +{ + /* Check type and rank. */ + if (type_must_agree && !compare_type_rank (s2, s1)) + { + if (errmsg != NULL) + snprintf (errmsg, err_len, "Type/rank mismatch in argument '%s'", + s1->name); + return FAILURE; + } + + /* Check INTENT. */ + if (s1->attr.intent != s2->attr.intent) + { + snprintf (errmsg, err_len, "INTENT mismatch in argument '%s'", + s1->name); + return FAILURE; + } + + /* Check OPTIONAL. */ + if (s1->attr.optional != s2->attr.optional) + { + snprintf (errmsg, err_len, "OPTIONAL mismatch in argument '%s'", + s1->name); + return FAILURE; + } + + /* FIXME: Do more comprehensive testing of dummy characteristics, + e.g. array shape, string length and attributes like + ALLOCATABLE, POINTER, TARGET, etc. */ + + return SUCCESS; +} + + /* 'Compare' two formal interfaces associated with a pair of symbols. We return nonzero if there exists an actual argument list that would be ambiguous between the two interfaces, zero otherwise. @@ -1059,31 +1098,22 @@ gfc_compare_interfaces (gfc_symbol *s1, gfc_symbol return 0; } - /* Check type and rank. */ - if (!compare_type_rank (f2->sym, f1->sym)) + if (intent_flag) { + /* Check all characteristics. */ + if (check_dummy_characteristics (f1->sym, f2->sym, + true, errmsg, err_len) == FAILURE) + return 0; + } + else if (!compare_type_rank (f2->sym, f1->sym)) + { + /* Only check type and rank. */ if (errmsg != NULL) snprintf (errmsg, err_len, "Type/rank mismatch in argument '%s'", f1->sym->name); return 0; } - /* Check INTENT. */ - if (intent_flag && (f1->sym->attr.intent != f2->sym->attr.intent)) - { - snprintf (errmsg, err_len, "INTENT mismatch in argument '%s'", - f1->sym->name); - return 0; - } - - /* Check OPTIONAL. */ - if (intent_flag && (f1->sym->attr.optional != f2->sym->attr.optional)) - { - snprintf (errmsg, err_len, "OPTIONAL mismatch in argument '%s'", - f1->sym->name); - return 0; - } - f1 = f1->next; f2 = f2->next; } @@ -3468,18 +3498,18 @@ gfc_free_formal_arglist (gfc_formal_arglist *p) } -/* Check that it is ok for the typebound procedure proc to override the - procedure old. */ +/* Check that it is ok for the type-bound procedure 'proc' to override the + procedure 'old', cf. F08:4.5.7.3. */ gfc_try gfc_check_typebound_override (gfc_symtree* proc, gfc_symtree* old) { locus where; - const gfc_symbol* proc_target; - const gfc_symbol* old_target; + const gfc_symbol *proc_target, *old_target; unsigned proc_pass_arg, old_pass_arg, argpos; - gfc_formal_arglist* proc_formal; - gfc_formal_arglist* old_formal; + gfc_formal_arglist *proc_formal, *old_formal; + bool check_type; + char err[200]; /* This procedure should only be called for non-GENERIC proc. */ gcc_assert (!proc->n.tb->is_generic); @@ -3637,15 +3667,12 @@ gfc_check_typebound_override (gfc_symtree* proc, g return FAILURE; } - /* Check that the types correspond if neither is the passed-object - argument. */ - /* FIXME: Do more comprehensive testing here. */ - if (proc_pass_arg != argpos && old_pass_arg != argpos - && !gfc_compare_types (&proc_formal->sym->ts, &old_formal->sym->ts)) + check_type = proc_pass_arg != argpos && old_pass_arg != argpos; + if (check_dummy_characteristics (proc_formal->sym, old_formal->sym, + check_type, err, sizeof(err)) == FAILURE) { - gfc_error ("Types mismatch for dummy argument '%s' of '%s' %L " - "in respect to the overridden procedure", - proc_formal->sym->name, proc->name, &where); + gfc_error (strcat (err, " of '%s' at %L with respect to the " + "overridden procedure"), proc->name, &where); return FAILURE; }
! { dg-do compile } module foo_mod type foo contains procedure, pass(f) :: bar => base_bar end type foo contains subroutine base_bar(f,j) class(foo), intent(inout) :: f integer, intent(in) :: j end subroutine base_bar end module foo_mod module extfoo_mod use foo_mod type, extends(foo) :: extfoo contains procedure, pass(f) :: bar => ext_bar ! { dg-error "INTENT mismatch in argument" } end type extfoo contains subroutine ext_bar(f,j) class(extfoo), intent(inout) :: f integer, intent(inout) :: j end subroutine ext_bar end module extfoo_mod ! { dg-final { cleanup-modules "foo_mod extfoo_mod" } }