User account creation filtered due to spam.

Bug 43169 - [OOP] gfortran rejects pure procedure with select type construct
Summary: [OOP] gfortran rejects pure procedure with select type construct
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: janus
URL:
Keywords:
: 42912 (view as bug list)
Depends on:
Blocks:
 
Reported: 2010-02-24 20:13 UTC by Todd Hay
Modified: 2010-03-03 15:17 UTC (History)
3 users (show)

See Also:
Host: x86_64-pc-linux-gnu
Target: x86_64-pc-linux-gnu
Build: x86_64-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2010-02-25 13:40:15


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Todd Hay 2010-02-24 20:13:53 UTC
The following code fails to compile with gcc version 4.5.0-pre9999 20100224 (experimental) rev. 157053. However, if lines 22, 23 and 27 (i.e. 'select type(x)', 'class is (myType)', and 'end select') are removed it compiles fine and the executable gives the expected output '2.0000 1.0000'.

Source compiled with ifort v. 11.1 behaves as expected with 'select type' construct included. 

$ cat test.f90 && gfortran test.f90                             
program testPure
implicit none
type :: myType
    real :: a,b
end type myType
type(myType),target :: y
class(myType),pointer :: x

x=>y
x%a=1.
x%b=2.
call swap(x)
print *, x%a,x%b

contains

pure subroutine swap(x)
implicit none
class(myType), intent(inout) :: x
real :: work

select type(x)
class is (myType)
    work=x%a
    x%a=x%b
    x%b=work
end select
end subroutine swap
end program testPure
test.f90:25.4:

    x%a=x%b
    1
Error: Cannot assign to variable 'tmp$class$mytype' in PURE procedure at (1)
test.f90:26.4:

    x%b=work
    1
Error: Cannot assign to variable 'tmp$class$mytype' in PURE procedure at (1)

********************
Now with 'select type' construct removed


$ cat test.f90 && gfortran test.f90 && ./a.out                    --(Wed,Feb24)--
program testPure
implicit none
type :: myType
    real :: a,b
end type myType
type(myType),target :: y
class(myType),pointer :: x

x=>y
x%a=1.
x%b=2.
call swap(x)
print *, x%a,x%b

contains

pure subroutine swap(x)
implicit none
class(myType), intent(inout) :: x
real :: work

    work=x%a
    x%a=x%b
    x%b=work
end subroutine swap
end program testPure

   2.0000000       1.0000000


-------------------------------------
gcc configure options:
$ gcc -v
gcc -v                                                          
Using built-in specs.
COLLECT_GCC=/usr/x86_64-pc-linux-gnu/gcc-bin/4.5.0-pre9999/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/4.5.0-pre9999/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /var/tmp/portage/sys-devel/gcc-4.5.0_pre9999/work/gcc-4.5.0-9999/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/4.5.0-pre9999 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.0-pre9999/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.5.0-pre9999 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.5.0-pre9999/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.5.0-pre9999/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.0-pre9999/include/g++-v4 --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --with-ppl --with-cloog --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --enable-multilib --enable-libmudflap --disable-libssp --enable-libgomp --enable-cld --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/4.5.0-pre9999/python --disable-libgcj --enable-languages=c,c++,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo SVN' --enable-lto --disable-checking
Thread model: posix
gcc version 4.5.0-pre9999 20100224 (experimental) rev. 157053 (Gentoo SVN)
Comment 1 janus 2010-02-25 08:38:03 UTC
Confirmed. Here is a reduced test case:

  pure subroutine swap(x)
    implicit none
    type :: myType
      real :: a
    end type myType
    class(myType), intent(inout) :: x
    select type(x)
    class is (myType)
      x%a = 42.
    end select
  end subroutine

Thanks for the report!
Comment 2 janus 2010-02-25 09:08:51 UTC
The problem lies in gfc_impure_variable (resolve.c), where it is checked if the namespace of the variable equals the local namespace of the pure procedure. This check fails if the procedure has sub-namespaces.

We have sub-namespaces e.g. in the following cases:
1) BLOCK
2) SELECT TYPE
3) contained procedures
4) ...?

Comment #0 shows the failure for case (2), but the others may also be affected. I'll check this.
Comment 3 janus 2010-02-25 09:13:45 UTC
Regarding BLOCK, it seems there is an additional problem: Assignments inside a BLOCK are not checked at all, as the following case shows ...

  implicit none
  real :: glob

contains

  pure subroutine swap
    implicit none
    real :: r1
    r1 = 42.
    block
      real :: r2
      r2 = 43.
      glob = 0.
    end block
  end subroutine

end

The assignment to 'glob' is clearly invalid, but is not being caught. 'gfc_impure_variable' is only called for 'r1', the other two are left unchecked. Seems like statements inside a BLOCK are not being resolved at all?!?
Comment 4 janus 2010-02-25 09:19:30 UTC
Contained procedures are not affected by this bug, since a procedure contained in a pure procedure must itself be pure. Therefore something like this is invalid (as gfortran correctly detects):

module m

  implicit none

contains

  pure subroutine swap
    implicit none
    real :: r1

  contains

    pure subroutine cont
      real :: r2
      r1 = 42.
      r2 = 43.
    end subroutine

  end subroutine

end
Comment 5 janus 2010-02-25 12:16:42 UTC
(In reply to comment #3)
> Seems like statements inside a BLOCK are not being resolved at all?!?

Sorry, this is wrong. They are resolved alright. The problem is just that 'gfc_pure' does not work (checking if we're inside a pure function).
Comment 6 janus 2010-02-25 12:54:57 UTC
(In reply to comment #2)
> The problem lies in gfc_impure_variable (resolve.c), where it is checked if the
> namespace of the variable equals the local namespace of the pure procedure.
> This check fails if the procedure has sub-namespaces.

Actually it seems that 'gfc_impure_variable' works fine, but for SELECT TYPE the 'gfc_current_ns' is not set correctly.

Setting the namespace happens in 'resolve_codes', but the pureness check happens inside 'gfc_resolve_blocks'.
Comment 7 janus 2010-02-25 13:40:14 UTC
(In reply to comment #5)
> (In reply to comment #3)
> > Seems like statements inside a BLOCK are not being resolved at all?!?
> 
> Sorry, this is wrong. They are resolved alright. The problem is just that
> 'gfc_pure' does not work (checking if we're inside a pure function).

The BLOCK issue in comment #3 is fixed by the following patch:

Index: gcc/fortran/resolve.c
===================================================================
--- gcc/fortran/resolve.c	(revision 157055)
+++ gcc/fortran/resolve.c	(working copy)
@@ -11689,18 +11695,30 @@ gfc_impure_variable (gfc_symbol *sym)
 }
 
 
-/* Test whether a symbol is pure or not.  For a NULL pointer, checks the
-   symbol of the current procedure.  */
+/* Test whether a symbol is pure or not.  For a NULL pointer, checks if the
+   current namespace is inside a pure procedure.  */
 
 int
 gfc_pure (gfc_symbol *sym)
 {
   symbol_attribute attr;
+  gfc_namespace *ns;
 
   if (sym == NULL)
-    sym = gfc_current_ns->proc_name;
-  if (sym == NULL)
-    return 0;
+    {
+      /* Check if the current namespace or one of its parents
+	 belongs to a pure procedure.  */
+      for (ns = gfc_current_ns; ns; ns = ns->parent)
+	{
+	  sym = ns->proc_name;
+	  if (sym == NULL)
+	    return 0;
+	  attr = sym->attr;
+	  if (attr.flavor == FL_PROCEDURE && (attr.pure || attr.elemental))
+	    return 1;
+	}
+      return 0;
+    }
 
   attr = sym->attr;
Comment 8 Daniel Kraft 2010-02-28 15:07:54 UTC
*** Bug 42912 has been marked as a duplicate of this bug. ***
Comment 9 janus 2010-03-01 12:47:10 UTC
Even with the patch from comment #7, another thing goes wrong with BLOCK statements:

  pure subroutine swap
    implicit none
    real :: r1
    block
      real :: r2
      r1 = 42.
      r2 = 43.
    end block
  end subroutine


      r1 = 42.
      1
Error: Cannot assign to variable 'r1' in PURE procedure at (1)

This is rejected although it is valid.
Comment 10 janus 2010-03-03 15:13:10 UTC
Subject: Bug 43169

Author: janus
Date: Wed Mar  3 15:12:40 2010
New Revision: 157196

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=157196
Log:
2010-03-03  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/43169
	* resolve.c (resolve_code): Correctly set gfc_current_ns for
	EXEC_SELECT_TYPE.
	(gfc_impure_variable): Make it work with sub-namespaces (BLOCK etc).
	(gfc_pure): Ditto.


2010-03-03  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/43169
	* gfortran.dg/impure_assignment_3.f90: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/impure_assignment_3.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/resolve.c
    trunk/gcc/testsuite/ChangeLog

Comment 11 janus 2010-03-03 15:17:38 UTC
Fixed with r157196. Closing.