check.c (gfc_check_move_alloc): Prevent error that avoids aliasing between to and...
authorPaul Thomas <pault@gcc.gnu.org>
Wed, 9 Nov 2016 10:10:41 +0000 (10:10 +0000)
committerPaul Thomas <pault@gcc.gnu.org>
Wed, 9 Nov 2016 10:10:41 +0000 (10:10 +0000)
2016-11-09  Paul Thomas  <pault@gcc.gnu.org>

* check.c (gfc_check_move_alloc): Prevent error that avoids
aliasing between to and from arguments from rejecting valid
code.

2016-11-09  Paul Thomas  <pault@gcc.gnu.org>

* gfortran.dg/move_alloc_18.f90: New test.

From-SVN: r241995

gcc/fortran/ChangeLog
gcc/fortran/check.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/move_alloc_18.f90 [new file with mode: 0644]

index 6c39866487f8f614ff4c87face3ff0377607e8f4..bb0beb713e999201ae5496d600f56bfb2e7cace8 100644 (file)
@@ -1,3 +1,9 @@
+2016-11-09  Paul Thomas  <pault@gcc.gnu.org>
+
+       * check.c (gfc_check_move_alloc): Prevent error that avoids
+       aliasing between to and from arguments from rejecting valid
+       code.
+
 2016-11-09  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/71894
index 142cdac2e38e9dcaa0acae18a90bcde898aac1a5..265fe22594f4fe56b7184b74a908c5d0b3fe1eaf 100644 (file)
@@ -3342,14 +3342,44 @@ gfc_check_move_alloc (gfc_expr *from, gfc_expr *to)
       return false;
     }
 
-  /*  F2003 12.4.1.7  */
-  if (to->expr_type == EXPR_VARIABLE && from->expr_type ==EXPR_VARIABLE
+  /*  This is based losely on F2003 12.4.1.7. It is intended to prevent
+      the likes of to = sym->cmp1->cmp2 and from = sym->cmp1, where cmp1
+      and cmp2 are allocatable.  After the allocation is transferred,
+      the 'to' chain is broken by the nullification of the 'from'. A bit
+      of reflection reveals that this can only occur for derived types
+      with recursive allocatable components.  */
+  if (to->expr_type == EXPR_VARIABLE && from->expr_type == EXPR_VARIABLE
       && !strcmp (to->symtree->n.sym->name, from->symtree->n.sym->name))
     {
-      gfc_error ("The FROM and TO arguments at %L are either the same object "
-                "or subobjects thereof and so violate aliasing restrictions "
-                "(F2003 12.4.1.7)", &to->where);
-      return false;
+      gfc_ref *to_ref, *from_ref;
+      to_ref = to->ref;
+      from_ref = from->ref;
+      bool aliasing = true;
+
+      for (; from_ref && to_ref;
+          from_ref = from_ref->next, to_ref = to_ref->next)
+       {
+         if (to_ref->type != from->ref->type)
+           aliasing = false;
+         else if (to_ref->type == REF_ARRAY
+                  && to_ref->u.ar.type != AR_FULL
+                  && from_ref->u.ar.type != AR_FULL)
+           /* Play safe; assume sections and elements are different.  */
+           aliasing = false;
+         else if (to_ref->type == REF_COMPONENT
+                  && to_ref->u.c.component != from_ref->u.c.component)
+           aliasing = false;
+
+         if (!aliasing)
+           break;
+       }
+
+      if (aliasing)
+       {
+         gfc_error ("The FROM and TO arguments at %L violate aliasing "
+                    "restrictions (F2003 12.4.1.7)", &to->where);
+         return false;
+       }
     }
 
   /* CLASS arguments: Make sure the vtab of from is present.  */
index a7e0250e0c4b4394fee948f46acb896d4e1eb106..f3438bee74857c8a367c14dd4429f1c87d180d93 100644 (file)
@@ -1,3 +1,7 @@
+2016-11-09  Paul Thomas  <pault@gcc.gnu.org>
+
+       * gfortran.dg/move_alloc_18.f90: New test.
+
 2016-11-09  Prathamesh Kulkarni  <prathamesh.kulkarni@linaro.org>
 
        PR middle-end/78256
diff --git a/gcc/testsuite/gfortran.dg/move_alloc_18.f90 b/gcc/testsuite/gfortran.dg/move_alloc_18.f90
new file mode 100644 (file)
index 0000000..bc72d5d
--- /dev/null
@@ -0,0 +1,21 @@
+! { dg-do compile }
+!
+! Test that the anti-aliasing restriction does not knock out valid code.
+!
+! Contributed by  Andrew Balwin on
+! https://groups.google.com/forum/#!topic/comp.lang.fortran/oiXdl1LPb_s
+!
+      PROGRAM TEST
+        IMPLICIT NONE
+
+        TYPE FOOBAR
+          INTEGER, ALLOCATABLE :: COMP(:)
+        END TYPE
+
+        TYPE (FOOBAR) :: MY_ARRAY(6)
+
+        ALLOCATE (MY_ARRAY(1)%COMP(10))
+
+        CALL MOVE_ALLOC (MY_ARRAY(1)%COMP, MY_ARRAY(2)%COMP)
+
+      END PROGRAM TEST