re PR fortran/78737 ([OOP] linking error with deferred, undefined user-defined derive...
authorJanus Weil <janus@gcc.gnu.org>
Tue, 13 Dec 2016 14:28:17 +0000 (15:28 +0100)
committerJanus Weil <janus@gcc.gnu.org>
Tue, 13 Dec 2016 14:28:17 +0000 (15:28 +0100)
2016-12-13  Janus Weil  <janus@gcc.gnu.org>
    Paul Thomas  <pault@gcc.gnu.org>

PR fortran/78737
* gfortran.h (gfc_find_typebound_dtio_proc): New prototype.
* interface.c (gfc_compare_interfaces): Whitespace fix.
(gfc_find_typebound_dtio_proc): New function.
(gfc_find_specific_dtio_proc): Use it. Improve error recovery.
* trans-io.c (get_dtio_proc): Implement polymorphic calls to DTIO
procedures.

2016-12-13  Janus Weil  <janus@gcc.gnu.org>
    Paul Thomas  <pault@gcc.gnu.org>

PR fortran/78737
* gfortran.dg/dtio_19.f90: New test case.

Co-Authored-By: Paul Thomas <pault@gcc.gnu.org>
From-SVN: r243609

gcc/fortran/ChangeLog
gcc/fortran/gfortran.h
gcc/fortran/interface.c
gcc/fortran/trans-io.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/dtio_19.f90 [new file with mode: 0644]

index 7a47db2e9995f8e958146eab7ea731f056c4795c..2a4b69dabc7872466bb0d338e420221876c013c0 100644 (file)
@@ -1,3 +1,14 @@
+2016-12-13  Janus Weil  <janus@gcc.gnu.org>
+           Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/78737
+       * gfortran.h (gfc_find_typebound_dtio_proc): New prototype.
+       * interface.c (gfc_compare_interfaces): Whitespace fix.
+       (gfc_find_typebound_dtio_proc): New function.
+       (gfc_find_specific_dtio_proc): Use it. Improve error recovery.
+       * trans-io.c (get_dtio_proc): Implement polymorphic calls to DTIO
+       procedures.
+
 2016-12-12  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/78392
index 24dadf26a12a0c2d1fc50012099e1d3716f2f596..f0189840f274753b966d75c083986b60118d434e 100644 (file)
@@ -3252,6 +3252,7 @@ int gfc_has_vector_subscript (gfc_expr*);
 gfc_intrinsic_op gfc_equivalent_op (gfc_intrinsic_op);
 bool gfc_check_typebound_override (gfc_symtree*, gfc_symtree*);
 void gfc_check_dtio_interfaces (gfc_symbol*);
+gfc_symtree* gfc_find_typebound_dtio_proc (gfc_symbol *, bool, bool);
 gfc_symbol* gfc_find_specific_dtio_proc (gfc_symbol*, bool, bool);
 
 
index 8afba84a697f5bc38fb66dfff0646edfffed05a6..90f46e56e4d3b54615ccb548df41d569a3476bba 100644 (file)
@@ -1712,8 +1712,8 @@ gfc_compare_interfaces (gfc_symbol *s1, gfc_symbol *s2, const char *name2,
        return 0;
 
       /* Special case: alternate returns.  If both f1->sym and f2->sym are
-        NULL, then the leading formal arguments are alternate returns.  
-        The previous conditional should catch argument lists with 
+        NULL, then the leading formal arguments are alternate returns.
+        The previous conditional should catch argument lists with
         different number of argument.  */
       if (f1 && f1->sym == NULL && f2 && f2->sym == NULL)
        return 1;
@@ -4826,13 +4826,10 @@ gfc_check_dtio_interfaces (gfc_symbol *derived)
 }
 
 
-gfc_symbol *
-gfc_find_specific_dtio_proc (gfc_symbol *derived, bool write, bool formatted)
+gfc_symtree*
+gfc_find_typebound_dtio_proc (gfc_symbol *derived, bool write, bool formatted)
 {
   gfc_symtree *tb_io_st = NULL;
-  gfc_symbol *dtio_sub = NULL;
-  gfc_symbol *extended;
-  gfc_typebound_proc *tb_io_proc, *specific_proc;
   bool t = false;
 
   if (!derived || derived->attr.flavor != FL_DERIVED)
@@ -4869,6 +4866,19 @@ gfc_find_specific_dtio_proc (gfc_symbol *derived, bool write, bool formatted)
                                            true,
                                            &derived->declared_at);
     }
+  return tb_io_st;
+}
+
+
+gfc_symbol *
+gfc_find_specific_dtio_proc (gfc_symbol *derived, bool write, bool formatted)
+{
+  gfc_symtree *tb_io_st = NULL;
+  gfc_symbol *dtio_sub = NULL;
+  gfc_symbol *extended;
+  gfc_typebound_proc *tb_io_proc, *specific_proc;
+
+  tb_io_st = gfc_find_typebound_dtio_proc (derived, write, formatted);
 
   if (tb_io_st != NULL)
     {
@@ -4893,17 +4903,17 @@ gfc_find_specific_dtio_proc (gfc_symbol *derived, bool write, bool formatted)
        dtio_sub = st->n.tb->u.specific->n.sym;
       else
        dtio_sub = specific_proc->u.specific->n.sym;
-    }
 
-  if (tb_io_st != NULL)
-    goto finish;
+      goto finish;
+    }
 
   /* If there is not a typebound binding, look for a generic
      DTIO interface.  */
   for (extended = derived; extended;
        extended = gfc_get_derived_super_type (extended))
     {
-      if (extended == NULL || extended->ns == NULL)
+      if (extended == NULL || extended->ns == NULL
+         || extended->attr.flavor == FL_UNKNOWN)
        return NULL;
 
       if (formatted == true)
index 253a5ac70a90cfed7079388f0b417574b066f076..b60685ee1572053f6b0097224b3f4a091c60c911 100644 (file)
@@ -2181,15 +2181,37 @@ get_dtio_proc (gfc_typespec * ts, gfc_code * code, gfc_symbol **dtio_sub)
     }
 
   if (ts->type == BT_DERIVED)
-    derived = ts->u.derived;
-  else
-    derived = ts->u.derived->components->ts.u.derived;
+    {
+      derived = ts->u.derived;
+      *dtio_sub = gfc_find_specific_dtio_proc (derived, last_dt == WRITE,
+                                             formatted);
+
+      if (*dtio_sub)
+       return gfc_build_addr_expr (NULL, gfc_get_symbol_decl (*dtio_sub));
+    }
+  else if (ts->type == BT_CLASS)
+    {
+      gfc_symtree *tb_io_st;
 
-  *dtio_sub = gfc_find_specific_dtio_proc (derived, last_dt == WRITE,
-                                          formatted);
+      derived = ts->u.derived->components->ts.u.derived;
+      tb_io_st = gfc_find_typebound_dtio_proc (derived,
+                                              last_dt == WRITE, formatted);
+      if (tb_io_st)
+       {
+         gfc_se se;
+         gfc_expr *expr = gfc_find_and_cut_at_last_class_ref (code->expr1);
+         gfc_add_vptr_component (expr);
+         gfc_add_component_ref (expr,
+                                tb_io_st->n.tb->u.generic->specific_st->name);
+         *dtio_sub = tb_io_st->n.tb->u.generic->specific->u.specific->n.sym;
+         gfc_init_se (&se, NULL);
+         se.want_pointer = 1;
+         gfc_conv_expr (&se, expr);
+         gfc_free_expr (expr);
+         return se.expr;
+       }
+    }
 
-  if (*dtio_sub)
-    return gfc_build_addr_expr (NULL, gfc_get_symbol_decl (*dtio_sub));
 
   return NULL_TREE;
 
index 118d01e2f583d2138179aa1aa4d1b09ea3d95ac3..fa954e539ff74726924aa845e6f7aeb98d190e29 100644 (file)
@@ -1,3 +1,9 @@
+2016-12-13  Janus Weil  <janus@gcc.gnu.org>
+           Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/78737
+       * gfortran.dg/dtio_19.f90: New test case.
+
 2016-12-13  Michael Matz  <matz@suse.de>
 
        PR tree-optimization/78725
diff --git a/gcc/testsuite/gfortran.dg/dtio_19.f90 b/gcc/testsuite/gfortran.dg/dtio_19.f90
new file mode 100644 (file)
index 0000000..f4d3757
--- /dev/null
@@ -0,0 +1,68 @@
+! { dg-do run }
+!
+! PR78737: [OOP] linking error with deferred, undefined user-defined derived-type I/O
+!
+! Contributed by Damian Rouson  <damian@sourceryinstitute.org>
+
+module object_interface
+  character(30) :: buffer(2)
+  type, abstract :: object
+  contains
+    procedure(write_formatted_interface), deferred :: write_formatted
+    generic :: write(formatted) => write_formatted
+  end type
+  abstract interface
+    subroutine write_formatted_interface(this,unit,iotype,vlist,iostat,iomsg)
+      import object
+      class(object), intent(in) :: this
+      integer, intent(in) :: unit
+      character (len=*), intent(in) :: iotype
+      integer, intent(in) :: vlist(:)
+      integer, intent(out) :: iostat
+      character (len=*), intent(inout) :: iomsg
+    end subroutine
+  end interface
+  type, extends(object) :: non_abstract_child1
+    integer :: i
+  contains
+    procedure :: write_formatted => write_formatted1
+  end type
+  type, extends(object) :: non_abstract_child2
+    real :: r
+  contains
+    procedure :: write_formatted => write_formatted2
+  end type
+contains
+  subroutine write_formatted1(this,unit,iotype,vlist,iostat,iomsg)
+    class(non_abstract_child1), intent(in) :: this
+    integer, intent(in) :: unit
+    character (len=*), intent(in) :: iotype
+    integer, intent(in) :: vlist(:)
+    integer, intent(out) :: iostat
+    character (len=*), intent(inout) :: iomsg
+    write(unit,'(a,i2/)') "write_formatted1 => ", this%i
+  end subroutine
+  subroutine write_formatted2(this,unit,iotype,vlist,iostat,iomsg)
+    class(non_abstract_child2), intent(in) :: this
+    integer, intent(in) :: unit
+    character (len=*), intent(in) :: iotype
+    integer, intent(in) :: vlist(:)
+    integer, intent(out) :: iostat
+    character (len=*), intent(inout) :: iomsg
+    write(unit,'(a,f4.1/)') "write_formatted2 => ", this%r
+  end subroutine
+  subroutine assert(a)
+    class(object):: a
+    write(buffer,'(DT)') a
+  end subroutine
+end module
+
+program p
+  use object_interface
+
+  call assert (non_abstract_child1 (99))
+  if (trim (buffer(1)) .ne. "write_formatted1 => 99") call abort
+
+  call assert (non_abstract_child2 (42.0))
+  if (trim (buffer(1)) .ne. "write_formatted2 => 42.0") call abort
+end