Bug 52024 - [OOP] GENERIC operator cannot be resolved
Summary: [OOP] GENERIC operator cannot be resolved
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Tobias Burnus
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2012-01-27 21:55 UTC by Fran Martinez Fadrique
Modified: 2012-02-01 19:14 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-01-28 00:00:00


Attachments
Module with class operators for test (272 bytes, text/x-fortran)
2012-01-27 21:55 UTC, Fran Martinez Fadrique
Details
Test case driver (94 bytes, text/x-fortran)
2012-01-27 21:56 UTC, Fran Martinez Fadrique
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Fran Martinez Fadrique 2012-01-27 21:55:45 UTC
Created attachment 26483 [details]
Module with class operators for test

The attached example generates the compilation error:

m_test.f90:10.32:

      generic :: operator(==) => t_equal_i, i_equal_t
                                1
Error: 't_equal_i' and 'i_equal_t' for GENERIC '==' at (1) are ambiguous

Subroutines t_equal_i and i_equal_t for operator(==) have different signatures.

The module and est program compile and run correctly using Intel 12.1
Comment 1 Fran Martinez Fadrique 2012-01-27 21:56:34 UTC
Created attachment 26484 [details]
Test case driver
Comment 2 Tobias Burnus 2012-01-28 09:38:52 UTC
It works if one uses the very similar:

interface operator (==)
  module procedure t_equal_i
  module procedure i_equal_t
end interface


While for GENERIC, one calls in resolve.c's check_generic_tbp_ambiguity:
  if (gfc_compare_interfaces (sym1, sym2, sym2->name, 1, 0, NULL, 0))

The INTERFACE is checked via interface.c's "gfc_check_interfaces (gfc_namespace *ns)", which calls "check_interface1" for the actual check.


Note that the current ambiguity check fails to diagnose ambiguity between GENERIC and INTERFACE, cf. PR 41951. Which might be fixed at the same time.
Comment 3 Tobias Burnus 2012-01-28 09:51:55 UTC
(In reply to comment #2)
> While for GENERIC, one calls in resolve.c's check_generic_tbp_ambiguity:
>   if (gfc_compare_interfaces (sym1, sym2, sym2->name, 1, 0, NULL, 0))
> 
> The INTERFACE is checked via interface.c's "gfc_check_interfaces (gfc_namespace
> *ns)", which calls "check_interface1" for the actual check.

The latter uses:

	    && gfc_compare_interfaces (p->sym, q->sym, q->sym->name,
				       generic_flag, 0, NULL, 0))

while it looks the same, it turns out that "generic_flag" is 0. If one uses "0" also for the GENERIC version, everything works as expected (i.e. no error for this version, an error if one swaps the dummy argument order). The question is only: What does that "generic_flag" actually do?
Comment 4 Tobias Burnus 2012-01-28 12:38:56 UTC
(In reply to comment #3)
> The question is only: What does that "generic_flag" actually do?

Answer: For generic procedures which are not operators one can do:
   generic (i=4, t=x)
which matches both interfaces:
  function t_equal_i( t, i ) result(res)
  function i_equal_t( i, t ) result(res)

For operators, the "t=" syntax is not possible, the argument order is fixed and, thus, for operators the interface is not ambiguous.

Untested patch:

Index: gfortran.h
===================================================================
--- gfortran.h  (Revision 183664)
+++ gfortran.h
@@ -1118,2 +1118,3 @@ typedef struct gfc_tbp_generic
   struct gfc_tbp_generic* next;
+  bool is_operator;
 }
Index: resolve.c
===================================================================
--- resolve.c   (Revision 183664)
+++ resolve.c
@@ -10966,2 +10995,3 @@ check_generic_tbp_ambiguity (gfc_tbp_gen
   gcc_assert (!t2->specific->is_generic);
+  gcc_assert (t1->is_operator == t2->is_operator);
 
@@ -10984,3 +11014,4 @@ check_generic_tbp_ambiguity (gfc_tbp_gen
   /* Compare the interfaces.  */
-  if (gfc_compare_interfaces (sym1, sym2, sym2->name, 1, 0, NULL, 0))
+  if (gfc_compare_interfaces (sym1, sym2, sym2->name, !t1->is_operator, 0,
+                             NULL, 0))
     {
Index: decl.c
===================================================================
--- decl.c      (Revision 183664)
+++ decl.c
@@ -8394,2 +8394,4 @@ gfc_match_generic (void)
       target->next = tb->u.generic;
+      target->is_operator = ((op_type == INTERFACE_USER_OP)
+                            || (op_type == INTERFACE_INTRINSIC_OP));
       tb->u.generic = target;
Comment 5 Dominique d'Humieres 2012-01-28 20:41:28 UTC
With the patch in comment #4 I get

[macbook] f90/bug% gfc pr52024.f90 
pr52024.f90:46.6:

  use m_test
      1
Error: 'i_equal_t' and 't_equal_i' for GENERIC '==' at (1) are ambiguous
pr52024.f90:52.10:

  print *, t == i
          1
Error: Operands of comparison operator '==' at (1) are TYPE(t_test)/INTEGER(4)
pr52024.f90:53.10:

  print *, i == t
          1
Error: Operands of comparison operator '==' at (1) are INTEGER(4)/TYPE(t_test)

instead of

[macbook] f90/bug% gfcp pr52024.f90
pr52024.f90:10.32:

      generic :: operator(==) => t_equal_i, i_equal_t
                                1
Error: 't_equal_i' and 'i_equal_t' for GENERIC '==' at (1) are ambiguous
pr52024.f90:46.6:

  use m_test
      1
Fatal Error: Can't open module file 'm_test.mod' for reading at (1): No such file or directory

without it. However the following test


module m_sort
  implicit none
  type, abstract :: sort_t
  contains
    generic :: operator(.gt.) => gt_cmp
    procedure :: gt_cmp
    end type sort_t
contains
  logical function gt_cmp(a,b)
    class(sort_t), intent(in) :: a, b
    gt_cmp = .true.
  end function gt_cmp
end module

module test
  use m_sort
  implicit none
  type, extends(sort_t) :: sort_int_t
    integer :: i
  contains
    generic :: operator(.gt.) => gt_cmp_int
    procedure :: gt_cmp_int
  end type
contains
  logical function gt_cmp_int(a,b) result(cmp)
    class(sort_int_t), intent(in) :: a, b
    if (a%i > b%i) then
      cmp = .true.
     else
      cmp = .false.
     end if
  end function gt_cmp_int
end module

(related to pr41951, but I cannot find where I grabbed it) now gives an ICE

[macbook] f90/bug% gfc pr41951_3.f90
f951: internal compiler error: in check_generic_tbp_ambiguity, at fortran/resolve.c:10965
...

instead of the error

[macbook] f90/bug% gfcp pr41951_3.f90
pr41951_3.f90:21.32:

    generic :: operator(.gt.) => gt_cmp_int
                                1
Error: 'gt_cmp_int' and 'gt_cmp' for GENERIC '.gt.' at (1) are ambiguous

Note that AFAICT the other tests in pr41951 don't ICE.
Comment 6 Tobias Burnus 2012-01-31 18:41:57 UTC
Author: burnus
Date: Tue Jan 31 18:41:47 2012
New Revision: 183771

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=183771
Log:
2012-01-31  Tobias Burnus  <burnus@net-b.de>

        PR fortran/52024
        * gfortran.h (gfc_tbp_generic): Store whether the
        generic is an operator.
        * decl.c (gfc_match_generic): Set that flag.
        * resolve.c (check_generic_tbp_ambiguity): Use it in the
        gfc_compare_interfaces check.

2012-01-31  Tobias Burnus  <burnus@net-b.de>

        PR fortran/52024
        * gfortran.dg/typebound_generic_11.f90: New.


Added:
    trunk/gcc/testsuite/gfortran.dg/typebound_generic_11.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/decl.c
    trunk/gcc/fortran/gfortran.h
    trunk/gcc/fortran/resolve.c
    trunk/gcc/testsuite/ChangeLog
Comment 7 Tobias Burnus 2012-01-31 19:02:06 UTC
FIXED on the trunk (4.7).

Thanks for the bug report.
Comment 8 Tobias Burnus 2012-01-31 19:14:24 UTC
I somehow missed comment 5, which has an example which now gives an internal compiler error for:
  gcc_assert (t1->is_operator == t2->is_operator);

The problem is that in module.c's mio_typebound_proc, the gfc_tbp_generic's is_operator is not set.

Possible solutions:
- Check for whether the symtree starts with "OPERATOR"
- Save the "is_opterator" state to the file

TODO: Check whether ASSIGNMENT is currently correctly handled, it might have a similar issue.
Comment 9 Tobias Burnus 2012-01-31 22:27:02 UTC
(In reply to comment #8)
> I somehow missed comment 5

The ICE is fixed by the patch:
  http://gcc.gnu.org/ml/fortran/2012-01/msg00277.html

However, I believe that test case is valid (NAG 5.1 also compiles it), but GCC 4.6 and current 4.7 (before Rev. 183771 and with submitted patch) rejected it as ambiguous.


> TODO: Check whether ASSIGNMENT is currently correctly handled, it might have a
> similar issue.
Comment 10 Tobias Burnus 2012-02-01 19:06:11 UTC
Author: burnus
Date: Wed Feb  1 19:06:07 2012
New Revision: 183808

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=183808
Log:
2012-02-01  Tobias Burnus  <burnus@net-b.de>

        PR fortran/52024
        * module.c (MOD_VERSION): Bump.
        (mio_typebound_proc): Read/write is_operator from/to the
        .mod file.

2012-02-01  Tobias Burnus  <burnus@net-b.de>

        PR fortran/52024
        * gfortran.dg/typebound_operator_14.f90: New.


Added:
    trunk/gcc/testsuite/gfortran.dg/typebound_operator_14.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/module.c
    trunk/gcc/testsuite/ChangeLog
Comment 11 Tobias Burnus 2012-02-01 19:14:54 UTC
FIXED on the trunk (4.7).

Thanks Dominique for updated test case.

(In reply to comment #9)
> However, I believe that test case is valid.

Actually, I now think that it invalid and correctly rejected by gfortran, cf. http://gcc.gnu.org/ml/fortran/2012-01/msg00278.html