diff mbox

[RFC,fortran] PR fortran/60255 Deferred character length

Message ID 20141208183840.45364899@gmx.de
State New
Headers show

Commit Message

Andre Vehreschild Dec. 8, 2014, 5:38 p.m. UTC
Hi all,

please find attached a more elaborate patch for pr60255. I totally agree that
my first attempt was just scratching the surface of the work needed.

This patch also is *not* complete, but because I am really new to gfortran
patching, I don't want to present a final patch only to learn then, that I have
violated design rules, common practice or the like. Therefore please comment
and direct me to any sources/ideas to improve the patch.

Topic: 
The pr 60255 is about assigning a char array to an unlimited polymorphic
entity. In the comments the concern about the lost length information is
raised. The patch adds a _len component to the unlimited polymorphic entity
(after _data and _vtab) and adds an assignment of the string length to _len
when a string is pointer assigned to the unlimited poly entity. Furthermore is
the intrinsic len(unlimited poly pointing to a string) resolved to give the
_len component.

Yet missing:
- assign _len component back to deferred char array length component
- transport length along chains of unlimited poly entities, i.e., a => b; c =>
  a where all objects are unlimited poly and b is a string.
- allocate() in this context

Patch dependencies:
none

Comments, concerns, candy welcome!

Regards,
	Andre

On Sun, 17 Aug 2014 14:32:21 +0200
dominiq@lps.ens.fr (Dominique Dhumieres) wrote:

> > the testcase should check that the code generated is actually working,
> > not just that the ICE disappeared.
> 
> I agree. Note that there is a test in the comment 3 of PR60255 that
> can be used to check the run time behavior (and possibly check the
> vtab issue).
> 
> Dominique

Comments

Dominique d'Humières Dec. 9, 2014, 12:12 a.m. UTC | #1
Dear Paul,

The problem for oo.f90 is pr 55901.

I am updating my working tree with Andre’s patch.

Cheers,

Dominique

> Le 8 déc. 2014 à 21:20, Paul Richard Thomas <paul.richard.thomas@gmail.com> a écrit :
> 
> Dear Andre,
> 
> s/furure/future/ :-)
> 
> Why are you using a double underscore in get__len_component?
> 
> More seriously, I think that the len field should be added unconditionally to unlimited polymorphic variables. Otherwise, you might find unlimited polymorphic variables that are created in an already compiled module/subprogramme arriving without the requisite field.
> 
> Michael Metcalf has posted an example that makes use of unlimited polymorphism at ftp://ftp.numerical.rl.ac.uk/pub/MRandC/oo.f90 . gfortran does not work correctly with it at the moment because of the lack of a len field. Removing all the string input allows it to run correctly. I think that you should ensure that your patch fixes the problem.
> 
> A slight obstacle is that the substring at line 216 causes the emission of:
>     type is (character(*))
>                           1
> Error: Associate-name '__tmp_CHARACTER_0_1' at (1) is used as array
> 
> Just retaining print *, 'character = "', v, '"' allows the example to compile
> 
> ifort compiles and runs it successfully and so I think that it would be nice if gfortran catches up on this one.
> 
> Parenthetically, I wonder if this is not the time to implement PR53971... including responding to Mikael's comment?
> 
> Anyway, this is a good start in the right direction. Please persist!
> 
> Thanks
> 
> Paul
> 
> 
> On 8 December 2014 at 18:38, Andre Vehreschild <vehre@gmx.de> wrote:
> Hi all,
> 
> please find attached a more elaborate patch for pr60255. I totally agree that
> my first attempt was just scratching the surface of the work needed.
> 
> This patch also is *not* complete, but because I am really new to gfortran
> patching, I don't want to present a final patch only to learn then, that I have
> violated design rules, common practice or the like. Therefore please comment
> and direct me to any sources/ideas to improve the patch.
> 
> Topic:
> The pr 60255 is about assigning a char array to an unlimited polymorphic
> entity. In the comments the concern about the lost length information is
> raised. The patch adds a _len component to the unlimited polymorphic entity
> (after _data and _vtab) and adds an assignment of the string length to _len
> when a string is pointer assigned to the unlimited poly entity. Furthermore is
> the intrinsic len(unlimited poly pointing to a string) resolved to give the
> _len component.
> 
> Yet missing:
> - assign _len component back to deferred char array length component
> - transport length along chains of unlimited poly entities, i.e., a => b; c =>
>   a where all objects are unlimited poly and b is a string.
> - allocate() in this context
> 
> Patch dependencies:
> none
> 
> Comments, concerns, candy welcome!
> 
> Regards,
>         Andre
> 
> On Sun, 17 Aug 2014 14:32:21 +0200
> dominiq@lps.ens.fr (Dominique Dhumieres) wrote:
> 
> > > the testcase should check that the code generated is actually working,
> > > not just that the ICE disappeared.
> >
> > I agree. Note that there is a test in the comment 3 of PR60255 that
> > can be used to check the run time behavior (and possibly check the
> > vtab issue).
> >
> > Dominique
> 
> 
> --
> Andre Vehreschild * Email: vehre ad gmx dot de
> 
> 
> 
> -- 
> The knack of flying is learning how to throw yourself at the ground and miss.
>        --Hitchhikers Guide to the Galaxy
Andre Vehreschild Dec. 9, 2014, 9:42 a.m. UTC | #2
Hi Paul,

> s/furure/future/ :-)

Hups, fixed.

> Why are you using a double underscore in get__len_component?

Because the component is called _len. The routine should be called "get _len
component", but spaces aren't allowed :-) Anyways, does this violate some style
guide? Should I remove one of underscores?

> More seriously, I think that the len field should be added unconditionally
> to unlimited polymorphic variables. Otherwise, you might find unlimited
> polymorphic variables that are created in an already compiled
> module/subprogramme arriving without the requisite field.

I was thinking about that, too. For a start I just wanted to give an idea of
where this is going. When more gfortran gurus vote for the unconditional add to
u-poly variables, then I will change it. 

> Michael Metcalf has posted an example that makes use of unlimited
> polymorphism at ftp://ftp.numerical.rl.ac.uk/pub/MRandC/oo.f90 . gfortran
> does not work correctly with it at the moment because of the lack of a len
> field. Removing all the string input allows it to run correctly. I think
> that you should ensure that your patch fixes the problem.
> 
> A slight obstacle is that the substring at line 216 causes the emission of:
>     type is (character(*))
>                           1
> Error: Associate-name '__tmp_CHARACTER_0_1' at (1) is used as array
> 
> Just retaining print *, 'character = "', v, '"' allows the example to
> compile

Ok, I take a look at it. As I am paid to fix certain bugs that prevent
compiling another software, I will not prioritize working on 55901 as long as
it is not needed in the software I focus on. Sorry for not being more
enthusiastic, but there are more than 8 prs (and only one down yet) I have to
fix and time is limited.

What I did not mention in the previous mail is that I also plan to implement
this fixes in the fortran-dev branch with the new array descriptor. Given that
there is no other volunteer. :-)

Please continue commenting.

Regards,
	Andre

> ifort compiles and runs it successfully and so I think that it would be
> nice if gfortran catches up on this one.
> 
> Parenthetically, I wonder if this is not the time to implement PR53971...
> including responding to Mikael's comment?
> 
> Anyway, this is a good start in the right direction. Please persist!
> 
> Thanks
> 
> Paul
> 
> 
> On 8 December 2014 at 18:38, Andre Vehreschild <vehre@gmx.de> wrote:
> 
> > Hi all,
> >
> > please find attached a more elaborate patch for pr60255. I totally agree
> > that
> > my first attempt was just scratching the surface of the work needed.
> >
> > This patch also is *not* complete, but because I am really new to gfortran
> > patching, I don't want to present a final patch only to learn then, that I
> > have
> > violated design rules, common practice or the like. Therefore please
> > comment
> > and direct me to any sources/ideas to improve the patch.
> >
> > Topic:
> > The pr 60255 is about assigning a char array to an unlimited polymorphic
> > entity. In the comments the concern about the lost length information is
> > raised. The patch adds a _len component to the unlimited polymorphic entity
> > (after _data and _vtab) and adds an assignment of the string length to _len
> > when a string is pointer assigned to the unlimited poly entity.
> > Furthermore is
> > the intrinsic len(unlimited poly pointing to a string) resolved to give the
> > _len component.
> >
> > Yet missing:
> > - assign _len component back to deferred char array length component
> > - transport length along chains of unlimited poly entities, i.e., a => b;
> > c =>
> >   a where all objects are unlimited poly and b is a string.
> > - allocate() in this context
> >
> > Patch dependencies:
> > none
> >
> > Comments, concerns, candy welcome!
> >
> > Regards,
> >         Andre
> >
> > On Sun, 17 Aug 2014 14:32:21 +0200
> > dominiq@lps.ens.fr (Dominique Dhumieres) wrote:
> >
> > > > the testcase should check that the code generated is actually working,
> > > > not just that the ICE disappeared.
> > >
> > > I agree. Note that there is a test in the comment 3 of PR60255 that
> > > can be used to check the run time behavior (and possibly check the
> > > vtab issue).
> > >
> > > Dominique
> >
> >
> > --
> > Andre Vehreschild * Email: vehre ad gmx dot de
> >
> 
> 
>
Dominique d'Humières Dec. 9, 2014, 1:16 p.m. UTC | #3
Dear Andre,

The patch causes an ICE for the test gfortran.dg/unlimited_polymorphic_1.f03:

f951: internal compiler error: in gfc_add_component_ref, at fortran/class.c:236

f951: internal compiler error: Abort trap: 6
gfc: internal compiler error: Abort trap: 6 (program f951)
Abort

Reduced test for which the ICE is triggered by ‘len(w)'

MODULE m

contains
  subroutine bar (arg, res)
    class(*) :: arg
    character(100) :: res
    select type (w => arg)
      type is (character(*))
        write (res, '(I2)') len(w)
    end select
  end subroutine

END MODULE

Note that with your patch at https://gcc.gnu.org/ml/fortran/2014-08/msg00022.html, I get the same ICE for the Mikael’s test at https://gcc.gnu.org/ml/fortran/2014-08/msg00055.html (before your patch for pr60255, it used to give a wrong length: 80 instead of 20 AFAICR).

Note that the assert at fortran/class.c:236 is also triggered for pr61115.

Thanks for working on these issues,

Dominique

>> On 8 December 2014 at 18:38, Andre Vehreschild <vehre@gmx.de> wrote:
>> Hi all,
>> 
>> please find attached a more elaborate patch for pr60255. I totally agree that
>> my first attempt was just scratching the surface of the work needed.
>> 
>> This patch also is *not* complete, but because I am really new to gfortran
>> patching, I don't want to present a final patch only to learn then, that I have
>> violated design rules, common practice or the like. Therefore please comment
>> and direct me to any sources/ideas to improve the patch.
>> 
>> Topic:
>> The pr 60255 is about assigning a char array to an unlimited polymorphic
>> entity. In the comments the concern about the lost length information is
>> raised. The patch adds a _len component to the unlimited polymorphic entity
>> (after _data and _vtab) and adds an assignment of the string length to _len
>> when a string is pointer assigned to the unlimited poly entity. Furthermore is
>> the intrinsic len(unlimited poly pointing to a string) resolved to give the
>> _len component.
>> 
>> Yet missing:
>> - assign _len component back to deferred char array length component
>> - transport length along chains of unlimited poly entities, i.e., a => b; c =>
>>  a where all objects are unlimited poly and b is a string.
>> - allocate() in this context
>> 
>> Patch dependencies:
>> none
>> 
>> Comments, concerns, candy welcome!
>> 
>> Regards,
>>        Andre
diff mbox

Patch

diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c
index 0286c9e..29e31e1 100644
--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -2403,6 +2403,38 @@  yes:
   return true;
 }
 
+/* Add the component _len to the class-type variable in c->expr1.  */
+
+void
+gfc_add_len_component (gfc_code *c)
+{
+  /* Just make sure input is correct. This is already at the calling site,
+     but may be this routine is called from somewhere else in the furure.  */
+  gcc_assert (UNLIMITED_POLY(c->expr1)
+              && c->expr2
+              && c->expr2->ts.type== BT_CHARACTER);
+
+  gfc_component *len;
+  gfc_expr *e;
+  /* Check that _len is not present already.  */
+  if ((len= gfc_find_component (c->expr1->ts.u.derived, "_len", true, true)))
+    return;
+  /* Create the new component.  */
+  if (!gfc_add_component (c->expr1->ts.u.derived, "_len", &len))
+    // Possible errors are already reported in add_component
+    return;
+  len->ts.type = BT_INTEGER;
+  len->ts.kind = 4;
+  len->attr.access = ACCESS_PRIVATE;
+
+  /* Build minimal expression to initialize component with zero. */
+  e = gfc_get_expr();
+  e->ts = c->expr1->ts;
+  e->expr_type = EXPR_VARIABLE;
+  len->initializer = gfc_get_int_expr (gfc_default_integer_kind,
+                                       NULL, 0);
+  gfc_free_expr (e);
+}
 
 /* Find (or generate) the symbol for an intrinsic type's vtab.  This is
    needed to support unlimited polymorphism.  */
@@ -2415,18 +2447,9 @@  find_intrinsic_vtab (gfc_typespec *ts)
   gfc_symbol *copy = NULL, *src = NULL, *dst = NULL;
   int charlen = 0;
 
-  if (ts->type == BT_CHARACTER)
-    {
-      if (ts->deferred)
-	{
-	  gfc_error ("TODO: Deferred character length variable at %C cannot "
-		     "yet be associated with unlimited polymorphic entities");
-	  return NULL;
-	}
-      else if (ts->u.cl && ts->u.cl->length
-	       && ts->u.cl->length->expr_type == EXPR_CONSTANT)
-	charlen = mpz_get_si (ts->u.cl->length->value.integer);
-    }
+  if (ts->type == BT_CHARACTER && !ts->deferred && ts->u.cl && ts->u.cl->length
+      && ts->u.cl->length->expr_type == EXPR_CONSTANT)
+    charlen = mpz_get_si (ts->u.cl->length->value.integer);
 
   /* Find the top-level namespace.  */
   for (ns = gfc_current_ns; ns; ns = ns->parent)
@@ -2437,10 +2460,16 @@  find_intrinsic_vtab (gfc_typespec *ts)
     {
       char name[GFC_MAX_SYMBOL_LEN+1], tname[GFC_MAX_SYMBOL_LEN+1];
 
-      if (ts->type == BT_CHARACTER)
-	sprintf (tname, "%s_%d_%d", gfc_basic_typename (ts->type),
-		 charlen, ts->kind);
-      else
+      if (ts->type == BT_CHARACTER) {
+        if (!ts->deferred)
+          sprintf (tname, "%s_%d_%d", gfc_basic_typename (ts->type),
+                   charlen, ts->kind);
+        else
+          /* The type is deferred here. Ensure that this is easily seen in the 
+             vtable. */
+          sprintf (tname, "%s_DEFERRED_%d", gfc_basic_typename (ts->type),
+                   ts->kind);
+      } else
 	sprintf (tname, "%s_%d_", gfc_basic_typename (ts->type), ts->kind);
 
       sprintf (name, "__vtab_%s", tname);
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 1058502..f99c3f8 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3192,6 +3192,8 @@  gfc_expr *gfc_class_initializer (gfc_typespec *, gfc_expr *);
 unsigned int gfc_hash_value (gfc_symbol *);
 bool gfc_build_class_symbol (gfc_typespec *, symbol_attribute *,
 			     gfc_array_spec **);
+void gfc_add_len_component(gfc_code *);
+void gfc_assign_charlen_to_unlimited_poly(gfc_code *c);
 gfc_symbol *gfc_find_derived_vtab (gfc_symbol *);
 gfc_symbol *gfc_find_vtab (gfc_typespec *);
 gfc_symtree* gfc_find_typebound_proc (gfc_symbol*, bool*,
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 9d7d3c2..6e14e74 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -10081,7 +10081,11 @@  gfc_resolve_code (gfc_code *code, gfc_namespace *ns)
 	    if (!t)
 	      break;
 
-	    gfc_check_pointer_assign (code->expr1, code->expr2);
+	    if (gfc_check_pointer_assign (code->expr1, code->expr2)
+		&& UNLIMITED_POLY(code->expr1)
+		&& code->expr2->ts.type== BT_CHARACTER)
+	      gfc_add_len_component (code);
+
 	    break;
 	  }
 
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c
index 7ccabc7..88cd8e7 100644
--- a/gcc/fortran/simplify.c
+++ b/gcc/fortran/simplify.c
@@ -3687,6 +3687,31 @@  gfc_simplify_leadz (gfc_expr *e)
   return gfc_get_int_expr (gfc_default_integer_kind, &e->where, lz);
 }
 
+static gfc_expr *
+get__len_component (gfc_expr *e)
+{
+  gfc_expr *len_comp;
+  gfc_ref *ref, **last;
+  len_comp = gfc_copy_expr(e->symtree->n.sym->assoc->target);
+  /* We need to remove the last _data component ref from ptr.  */
+  last = &(len_comp->ref);
+  ref = len_comp->ref;
+  while (ref)
+    {
+      if (!ref->next
+          && ref->type == REF_COMPONENT
+          && strcmp("_data", ref->u.c.component->name)== 0)
+        {
+          gfc_free_ref_list(ref);
+          *last = NULL;
+          break;
+        }
+      last = &(ref->next);
+      ref = ref->next;
+    }
+  gfc_add_component_ref(len_comp, "_len");
+  return len_comp;
+}
 
 gfc_expr *
 gfc_simplify_len (gfc_expr *e, gfc_expr *kind)
@@ -3711,6 +3736,13 @@  gfc_simplify_len (gfc_expr *e, gfc_expr *kind)
       mpz_set (result->value.integer, e->ts.u.cl->length->value.integer);
       return range_check (result, "LEN");
     }
+  else if (e->expr_type == EXPR_VARIABLE && e->ts.type == BT_CHARACTER
+           && e->symtree->n.sym
+           && e->symtree->n.sym->assoc && e->symtree->n.sym->assoc->target
+           && e->symtree->n.sym->assoc->target->ts.type == BT_DERIVED)
+    {
+      return get__len_component (e);
+    }
   else
     return NULL;
 }
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index f8e4df8..9a08bde 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -1034,11 +1034,11 @@  gfc_trans_class_assign (gfc_expr *expr1, gfc_expr *expr2, gfc_exec_op op)
       gfc_add_vptr_component (lhs);
 
       if (UNLIMITED_POLY (expr1)
-	  && expr2->expr_type == EXPR_NULL && expr2->ts.type == BT_UNKNOWN)
-	{
-	  rhs = gfc_get_null_expr (&expr2->where);
- 	  goto assign_vptr;
-	}
+          && expr2->expr_type == EXPR_NULL && expr2->ts.type == BT_UNKNOWN)
+        {
+          rhs = gfc_get_null_expr (&expr2->where);
+          goto assign_vptr;
+        }
 
       if (expr2->expr_type == EXPR_NULL)
 	vtab = gfc_find_vtab (&expr1->ts);
@@ -6695,6 +6695,43 @@  gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)
 }
 
 
+/* Create the character length assignment to the _len component.  */
+
+void
+add_assignment_of_string_len_to_len_component (stmtblock_t *block,
+                                               gfc_expr *ptr, gfc_se *ptr_se,
+                                               gfc_se *str)
+{
+  gfc_expr *len_comp;
+  gfc_ref *ref, **last;
+  gfc_se lse;
+  len_comp = gfc_copy_expr(ptr);
+  /* We need to remove the last _data component ref from ptr.  */
+  last = &(len_comp->ref);
+  ref = len_comp->ref;
+  while (ref)
+    {
+      if (!ref->next
+          && ref->type == REF_COMPONENT
+          && strcmp("_data", ref->u.c.component->name)== 0)
+        {
+          gfc_free_ref_list(ref);
+          *last = NULL;
+          break;
+        }
+      last = &(ref->next);
+      ref = ref->next;
+    }
+  gfc_add_component_ref(len_comp, "_len");
+  gfc_init_se (&lse, NULL);
+  gfc_conv_expr (&lse, len_comp);
+
+  /* ptr % _len = len (str)  */
+  gfc_add_modify (block, lse.expr, str->string_length);
+  ptr_se->string_length = lse.expr;
+  gfc_free_expr (len_comp);
+}
+
 tree
 gfc_trans_pointer_assign (gfc_code * code)
 {
@@ -6759,6 +6796,15 @@  gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
       gfc_add_block_to_block (&block, &lse.pre);
       gfc_add_block_to_block (&block, &rse.pre);
 
+      /* For string assignments to unlimited polymorphic pointers add an
+         assignment of the string_length to the _len component of the pointer.  */
+      if (expr1->ts.type == BT_DERIVED
+          && expr1->ts.u.derived->attr.unlimited_polymorphic
+          && expr2->ts.type == BT_CHARACTER)
+        {
+          add_assignment_of_string_len_to_len_component (&block, expr1, &lse, &rse);
+        }
+
       /* Check character lengths if character expression.  The test is only
 	 really added if -fbounds-check is enabled.  Exclude deferred
 	 character length lefthand sides.  */
diff --git a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_19.f03 b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_19.f03
new file mode 100644
index 0000000..6042882
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_19.f03
@@ -0,0 +1,57 @@ 
+! { dg-do run }
+! Testing fix for 
+! PR fortran/60255 
+!
+program test
+    implicit none
+    character(LEN=:), allocatable :: S
+    call subP(S)
+    call sub2()
+    call sub1("test")
+
+contains
+
+  subroutine sub1(dcl)
+    character(len=*), target :: dcl
+    class(*), pointer :: ucp
+!    character(len=:), allocatable ::def
+
+    ucp => dcl
+
+    select type (ucp)
+    type is (character(len=*))
+      if (len(ucp) .NE. 4) then
+        call abort()
+!      else
+!        def = ucp
+!        if (len(def) .NE. 4) then
+!          call abort()   ! This abort is expected currently           
+!        end if
+      end if
+    class default
+      call abort()
+    end select
+  end subroutine
+  
+  subroutine sub2 
+    character(len=:), allocatable, target :: dcl
+    class(*), pointer :: ucp
+
+    dcl = "ttt"
+    ucp => dcl
+
+    select type (ucp)
+    type is (character(len=*))
+      if (len(ucp) .NE. 3) then
+        call abort()
+      end if
+    class default
+      call abort()
+    end select
+  end subroutine
+
+  subroutine subP(P)
+        class(*) :: P
+  end subroutine
+ 
+end program
diff --git a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_2.f03 b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_2.f03
index 8e80386..30e4797 100644
--- a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_2.f03
+++ b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_2.f03
@@ -5,7 +5,7 @@ 
 ! Contributed by Paul Thomas  <pault@gcc.gnu.org>
 !            and Tobias Burnus <burnus@gcc.gnu.org>
 !
-  CHARACTER(:), allocatable, target :: chr ! { dg-error "TODO: Deferred character length variable" }
+  CHARACTER(:), allocatable, target :: chr 
 ! F2008: C5100
   integer :: i(2)
   logical :: flag