Bug 49213 - [OOP] gfortran rejects structure constructor expression
Summary: [OOP] gfortran rejects structure constructor expression
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.7.0
: P3 major
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on: 64757
Blocks:
  Show dependency treegraph
 
Reported: 2011-05-28 18:04 UTC by neil.n.carlson
Modified: 2015-01-24 19:37 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-06-16 19:43:45


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description neil.n.carlson 2011-05-28 18:04:56 UTC
In the following program type-compatible variables are used as an expression in a structure constructor for an allocatable CLASS(S) component.  In the first case a TYPE(S) variable is used, and in the second a TYPE(S2), where S2 extends S.

The program compiles with nagfor 5.2 and (reportedly) with the cray compiler,
but gfortran rejects the code with the error messages:

  Tobj = T(Sobj)
           1
Error: Can't convert TYPE(s) to CLASS(s) at (1)

  Tobj = T(S2obj)
           1
Error: Can't convert TYPE(s2) to CLASS(s) at (1)

===============

From the F2008 standard:

"For a nonpointer component, the declared type and type parameters of the component and expr shall conform in the same way as for a variable and expr in an intrinsic assignment statement (7.2.1.2) [...]" (4.5.10p2)

"if the variable is polymorphic it shall be type compatible with expr; [...]" (7.2.1.2p1(4))

Also 4.5.10 p6 applies to allocatable components.

===============

program main

  type :: S
    integer :: n
  end type
  type(S) :: Sobj
  
  type, extends(S) :: S2
    integer :: m
  end type
  type(S2) :: S2obj
  
  type :: T
    class(S), allocatable :: x
  end type
  type(T) :: Tobj
  
  Sobj = S(1)
  Tobj = T(Sobj)
  
  S2obj = S2(1,2)
  Tobj = T(S2obj)
  
end program
Comment 1 janus 2011-06-16 19:43:45 UTC
Note: Intrinsic assignments to polymorphic variables are forbidden in the Fortran 2003 standard, and currently not supported by gfortran, cf. PR 43366.

F03:7.4.1.2:
"In an intrinsic assignment statement, variable shall not be polymorphic, and ..."
Comment 2 janus 2011-06-16 19:49:33 UTC
(In reply to comment #1)
> Note: Intrinsic assignments to polymorphic variables are forbidden in the
> Fortran 2003 standard, and currently not supported by gfortran, cf. PR 43366.


However, the same error message appears for the following variant (with a defined assignment), which is valid according to F03:


module m

  type :: S
    integer :: n
  contains
    generic :: assignment (=) => assgn
    procedure :: assgn
  end type

  type :: T
    class(S), allocatable :: x
  end type

contains

  subroutine assgn (a, b)
    class (S), intent (inout) :: a
    class (S), intent (in) :: b
  end subroutine

end module


  use m
  type(S) :: Sobj
  type(T) :: Tobj

  Sobj = S(1)
  Tobj = T(Sobj)

end program 



  Tobj = T(Sobj)
           1
Error: Can't convert TYPE(s) to CLASS(s) at (1)
Comment 3 neil.n.carlson 2011-06-16 20:35:48 UTC
(In reply to comment #1)
> Note: Intrinsic assignments to polymorphic variables are forbidden [...]

This was really about the structure constructor; the assignment was
just to do something with the value, so the example was poor.  Here's
a slightly different version that gets to the heart of what I intended:

program main

  type :: S
    integer :: n
  end type
  type(S) :: Sobj
  
  type, extends(S) :: S2
    integer :: m
  end type
  type(S2) :: S2obj
  
  type :: T
    class(S), allocatable :: x
  end type
  
  Sobj = S(1)
  call pass_it (T(Sobj))
  
  S2obj = S2(1,2)
  call pass_it (T(S2obj))
  
contains

  subroutine pass_it (foo)
    type(T), intent(in) :: foo
  end subroutine
  
end program

This gives the same errors:

  call pass_it (T(Sobj))
                  1
Error: Can't convert TYPE(s) to CLASS(s) at (1)

  call pass_it (T(S2obj))
                  1
Error: Can't convert TYPE(s2) to CLASS(s) at (1)
Comment 4 neil.n.carlson 2011-06-16 20:49:32 UTC
An intuitive way of viewing (and maybe even implementing I guess) the process triggered by a structure constructor is as a sequence of assignment statements for the components of the structure.  But that's not how the (2008) standard describes what takes place, and so constraints that apply to assignments (like assigning to a polymorphic) don't apply in this context.
Comment 5 janus 2011-06-16 21:29:07 UTC
(In reply to comment #4)
> An intuitive way of viewing (and maybe even implementing I guess) the process
> triggered by a structure constructor is as a sequence of assignment statements
> for the components of the structure.  But that's not how the (2008) standard
> describes what takes place, and so constraints that apply to assignments (like
> assigning to a polymorphic) don't apply in this context.

I think you are wrong here.

F08:7.2.1.3p13:

"An intrinsic assignment where the variable is of derived type is performed as if each component of the variable were assigned from the corresponding component of expr using pointer assignment (7.2.2) for each pointer component, defined assignment for each nonpointer nonallocatable component of a type that has a type-bound defined assignment consistent with the component, intrinsic assignment for each other nonpointer nonallocatable component, and intrinsic assignment for each allocated coarray component. For unallocated coarray components, the corresponding component of the variable shall be unallocated. For a noncoarray allocatable component the following sequence of operations is applied."

In essence this means that a derived type assignment *is* viewed as a sequence of component assignments. Therefore I think that the corresponding restrictions *do* apply.
Comment 6 neil.n.carlson 2011-06-16 22:12:17 UTC
(In reply to comment #5)
> (In reply to comment #4)
> > An intuitive way of viewing (and maybe even implementing I guess) the process
> > triggered by a structure constructor [...]
> 
> I think you are wrong here.
> 
> F08:7.2.1.3p13:
> 
> "An intrinsic assignment where the variable is of derived type [...]

Sorry, I wasn't talking about intrinsic assignment.  I was (unsuccessfully)
trying to talk about what happens when a structure constructor expression,
like T(Sobj) is encountered.  The compiler has to generate a temporary
object of type T and define its components, and what I was trying to say
(and I might be wrong about this) is that this process of defining the
components using the expressions given to the constructor is not like
normal assignment (intrinsic or defined) of derived type objects.
The reason for raising this was that the error messages suggest that
that is how the compiler is viewing it.

Sorry for the confusion.
Comment 7 neil.n.carlson 2011-06-16 22:18:14 UTC
I want to emphasize again that the error I wanted to report was that gfortran is rejecting valid structure constructor expressions (see comment 3).  It looks from you example that there is also an error with assignment, but that's orthogonal to the constructor error.
Comment 8 janus 2013-01-10 15:46:12 UTC
(In reply to comment #7)
> I want to emphasize again that the error I wanted to report was that gfortran
> is rejecting valid structure constructor expressions (see comment 3).

Here is a slightly reduced version of comment 3:

  type :: S
    integer :: n
  end type
  type(S) :: Sobj

  type :: T
    class(S), allocatable :: x
  end type

  Sobj = S(1)
  call pass_it (T(Sobj))

contains

  subroutine pass_it (foo)
    type(T) :: foo
  end subroutine

end



One can get past the error message with the following patch:

Index: gcc/fortran/resolve.c
===================================================================
--- gcc/fortran/resolve.c	(revision 194927)
+++ gcc/fortran/resolve.c	(working copy)
@@ -1103,7 +1103,7 @@ resolve_structure_cons (gfc_expr *expr, int init)
       /* If we don't have the right type, try to convert it.  */
 
       if (!comp->attr.proc_pointer &&
-	  !gfc_compare_types (&cons->expr->ts, &comp->ts))
+	  !gfc_compare_types (&comp->ts, &cons->expr->ts))
 	{
 	  t = FAILURE;
 	  if (strcmp (comp->name, "_extends") == 0)


but the one runs into an ICE:

internal compiler error: in fold_convert_loc, at fold-const.c:1986
   call pass_it (T(Sobj))
 ^
0x845634 fold_convert_loc(unsigned int, tree_node*, tree_node*)
        /home/jweil/gcc48/trunk/gcc/fold-const.c:1986
0x671aa9 gfc_trans_subcomponent_assign
        /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:6001
0x671e10 gfc_trans_structure_assign
        /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:6068
0x671f46 gfc_conv_structure(gfc_se*, gfc_expr*, int)
        /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:6095
Comment 9 janus 2013-01-10 16:06:51 UTC
In fact one also gets an ICE when replacing "class(S)" with "type(S)" in comment 8 (already with an unpatched gfortran):


  type :: S
    integer :: n
  end type
  type(S) :: Sobj

  type :: T
    type(S), allocatable :: x
  end type

  Sobj = S(1)
  call pass_it (T(Sobj))

contains

  subroutine pass_it (foo)
    type(T) :: foo
  end subroutine

end



internal compiler error: in fold_convert_loc, at fold-const.c:1864
   call pass_it (T(Sobj))
 ^
0x844efe fold_convert_loc(unsigned int, tree_node*, tree_node*)
        /home/jweil/gcc48/trunk/gcc/fold-const.c:1863
0x671aa9 gfc_trans_subcomponent_assign
        /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:6001
0x671e10 gfc_trans_structure_assign
        /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:6068
0x671f46 gfc_conv_structure(gfc_se*, gfc_expr*, int)
        /home/jweil/gcc48/trunk/gcc/fortran/trans-expr.c:6095


This is similar, but not identical, to the ICE in comment 8.
Comment 10 janus 2013-01-10 20:39:58 UTC
The following patch makes comment 8 and 9 compile, but I'm not sure if the generated code is correct:

Index: gcc/fortran/trans-expr.c
===================================================================
--- gcc/fortran/trans-expr.c	(revision 194927)
+++ gcc/fortran/trans-expr.c	(working copy)
@@ -5990,23 +5990,11 @@ gfc_trans_subcomponent_assign (tree dest, gfc_comp
 	  gfc_add_expr_to_block (&block, tmp);
 	}
     }
-  else if (expr->ts.type == BT_DERIVED)
+  else if (expr->ts.type == BT_DERIVED && expr->expr_type == EXPR_STRUCTURE)
     {
-      if (expr->expr_type != EXPR_STRUCTURE)
-	{
-	  gfc_init_se (&se, NULL);
-	  gfc_conv_expr (&se, expr);
-	  gfc_add_block_to_block (&block, &se.pre);
-	  gfc_add_modify (&block, dest,
-			       fold_convert (TREE_TYPE (dest), se.expr));
-	  gfc_add_block_to_block (&block, &se.post);
-	}
-      else
-	{
-	  /* Nested constructors.  */
-	  tmp = gfc_trans_structure_assign (dest, expr);
-	  gfc_add_expr_to_block (&block, tmp);
-	}
+      /* Nested constructors.  */
+      tmp = gfc_trans_structure_assign (dest, expr);
+      gfc_add_expr_to_block (&block, tmp);
     }
   else
     {
Comment 11 janus 2013-01-11 12:04:26 UTC
Note: Neither of the patches in comment 8 and 10 shows any testsuite regressions.
Comment 12 janus 2013-08-05 09:08:41 UTC
Related test case (using unlimited polymorphism) from http://gcc.gnu.org/ml/fortran/2013-08/msg00011.html:

type t
  class(*), pointer :: x
end type t
type(t), target :: y
integer,target :: z
type(t) :: x = t(y)
type(t) :: x = t(z)
class(*), pointer :: a => y 
end


Unpatched gfortran trunk yields:

tobias2.f90:7.17:

type(t) :: x = t(y)
                 1
Error: Can't convert TYPE(t) to CLASS(*) at (1)
tobias2.f90:8.17:

type(t) :: x = t(z)
                 1
Error: Can't convert INTEGER(4) to CLASS(*) at (1)
Comment 13 janus 2013-08-05 09:21:56 UTC
(In reply to janus from comment #12)
> 
> type(t) :: x = t(y)
>                  1
> Error: Can't convert TYPE(t) to CLASS(*) at (1)

The patch in comment 8 turns this error into:

type(t) :: x = t(y)
                 1
Error: Parameter 'y' at (1) has not been declared or is a variable, which does not reduce to a constant expression
Comment 14 janus 2013-08-05 11:14:54 UTC
(In reply to janus from comment #13)
> type(t) :: x = t(y)
>                  1
> Error: Parameter 'y' at (1) has not been declared or is a variable, which
> does not reduce to a constant expression

This error also occurs for the following non-polymorphic version ...

type t
  integer, pointer :: j
end type t
integer, target :: i = 0
type(t) :: x = t(i)
end

... which should be valid at least in F08.
Comment 15 janus 2013-08-06 08:42:37 UTC
Another test case related to comment 12 (from http://gcc.gnu.org/ml/fortran/2013-08/msg00015.html):


integer, target :: tgt
type t2
end type t2
type(t2), target :: tgt2
type t
  class(*), pointer :: a => tgt
  class(*), pointer :: b => tgt2
end type t
type(t) :: x
type(t), SAVE :: y
end


Unpatched gfortran gives:


tobias3.f90:1.22:

integer, target :: tgt
                      1
Internal Error at (1):
tobias3.f90:6.31:

  class(*), pointer :: a => tgt
                               1
Can't convert INTEGER(4) to CLASS(*) at (1)


and also the patches from comment 8 and 10 don't help here.
Comment 16 janus 2013-08-06 09:13:07 UTC
(In reply to janus from comment #15)
> and also the patches from comment 8 and 10 don't help here.

... but the following does:


Index: gcc/fortran/expr.c
===================================================================
--- gcc/fortran/expr.c	(revision 201520)
+++ gcc/fortran/expr.c	(working copy)
@@ -3936,8 +3936,7 @@ gfc_default_initializer (gfc_typespec *ts)
       if (comp->initializer)
 	{
 	  ctor->expr = gfc_copy_expr (comp->initializer);
-	  if ((comp->ts.type != comp->initializer->ts.type
-	       || comp->ts.kind != comp->initializer->ts.kind)
+	  if (!gfc_compare_types (&comp->ts, &comp->initializer->ts)
 	      && !comp->attr.pointer && !comp->attr.proc_pointer)
 	    gfc_convert_type_warn (ctor->expr, &comp->ts, 2, false);
 	}
Comment 17 janus 2013-08-06 10:50:38 UTC
(In reply to janus from comment #16)
> > and also the patches from comment 8 and 10 don't help here.
> 
> ... but the following does:

... without any testsuite failures, btw.
Comment 18 Dominique d'Humieres 2013-08-08 16:54:18 UTC
With the patch in comment #16 the 'Internal Error' when compiling the code in comment #15 disappears, but appears when compiling the test in pr51945 with the type-declaration line 'type(my_t) :: a' is uncommented.
Comment 19 Dominique d'Humieres 2013-08-11 17:03:22 UTC
Note that the patch in comment #10 no longer applies cleanly due to revision 197053:

@@ -6013,7 +5786,7 @@
 	  gfc_add_expr_to_block (&block, tmp);
 	}
     }
-  else if (expr->ts.type == BT_DERIVED)
+  else if (expr->ts.type == BT_DERIVED && expr->ts.f90_type != BT_VOID)
     {
       if (expr->expr_type != EXPR_STRUCTURE)
 	{
Comment 20 Dominique d'Humieres 2015-01-24 11:52:00 UTC
*** Bug 64757 has been marked as a duplicate of this bug. ***
Comment 21 Dominique d'Humieres 2015-01-24 16:31:52 UTC
The ICE for the test in comment 8 is now handled by PR64757.
Comment 22 janus 2015-01-24 19:05:50 UTC
The ICE on comment 9 does not occur any more with current trunk:

gcc-Version 5.0.0 20150124 (experimental) [trunk revision 220084] (GCC)
Comment 23 Dominique d'Humieres 2015-01-24 19:37:20 UTC
> The ICE on comment 9 does not occur any more with current trunk:
>
> gcc-Version 5.0.0 20150124 (experimental) [trunk revision 220084] (GCC)

Confirmed. I get the ICE with r219763 (2015-01-16), but not with r219772 (2015-01-16, with Andre's patch for pr60357: https://gcc.gnu.org/ml/fortran/2015-01/msg00094.html).

Since there is no fortran commit in the range, it is likely fixed by the Andre's patch.