diff mbox

[fortran] Fix PR 38536

Message ID 4D317249.30509@netcologne.de
State New
Headers show

Commit Message

Thomas Koenig Jan. 15, 2011, 10:09 a.m. UTC
Hello world,

the attached patch fixes the PR by inserting additional checks in
resolve.c to catch the invalid array sections.

Regression-tested.  OK for trunk?

	Thomas

2011-01-15  Thomas Koenig  <tkoenig@gcc.gnu.org>

	PR fortran/38536
	* resolve.c (gfc_iso_c_func_interface):  For C_LOC,
	check for array sections which are illegal.

2011-01-15  Thomas Koenig  <tkoenig@gcc.gnu.org>

	PR fortran/38536
	* gfortran.dg/c_loc_tests_16.f90:  New test.
! { dg-do compile }
! PR 38536 - array sections as arguments to c_loc are illegal.
  use iso_c_binding
  type, bind(c) :: t1
          integer(c_int) :: i(5)
  end type t1
  type, bind(c):: t2
          type(t1) :: t(5)
  end type t2

  type(t2), target :: tt
  integer(c_int), target :: n(3)
  type(C_PTR) :: p
  p = c_loc(tt%t%i(1))  ! { dg-error "Array section not permitted" }
  p = c_loc(n(1:2))  ! { dg-error "Array section not permitted" }
  end

Comments

Tobias Burnus Jan. 15, 2011, 10:53 a.m. UTC | #1
Thomas Koenig wrote:
> the attached patch fixes the PR by inserting additional checks in
> resolve.c to catch the invalid array sections.
>
> 	PR fortran/38536
> 	* resolve.c (gfc_iso_c_func_interface):  For C_LOC,
> 	check for array sections which are illegal.
>
>    integer(c_int), target :: n(3)
>    p = c_loc(tt%t%i(1))  ! { dg-error "Array section not permitted" }
>    p = c_loc(n(1:2))  ! { dg-error "Array section not permitted" }

While I agree that "tt%t%i(1)" is invalid as "t" is an array (of size 
5), I fail to see why "n(1:2)" is invalid.

If I look at the Fortran 2008 standard I just find:

"15.2.3.6 C LOC (X)" [...]
"Argument. X shall have either the POINTER or TARGET attribute. It shall 
not be a coindexed object. It shall
either be a variable with interoperable type and kind type parameters, 
or be a scalar, nonpolymorphic variable
with no length type parameters. If it is allocatable, it shall be 
allocated. If it is a pointer, it shall be associated.
If it is an array, it shall be contiguous and have nonzero size. It 
shall not be a zero-length string."

"n" is a TARGET, it is not coindexed, has of an interoperable type/kind 
- and it is an array, which is not only contiguous but even simply 
contiguous. And it is not a zero-sized string.

Thus, I claim that "n(1:2)" is perfectly valid and thus the patch 
rejects too much.

In terms of Fortran 2003 it is more difficult to see. If one reads 
Richard Maine's answer at 
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/4b65b1cd206ce9fe 
one sees that the standard is rather unclear. While Richard deduces that 
array slices are not valid, it is by far not obvious and the reason 
"that array slices would not be interoperable is that an array slice 
might be noncontiguous" is not an issue in Fortran 2008. Fortran 2008 
defines when an array is contiguous (cf. "5.3.7 CONTIGUOUS attribute", 
paragraph 2 ["An object is contiguous if it is ..."]) - and then can 
uses the term for C_LOC.

Regarding the PR: The problem is that contiguity is not compile-time 
checkable. A subset is compile-time checkable, this set encompasses 
"simply contiguous" arrays, defined in Section 6.5.4. For very few 
additional arrays one can deduce at compile time their contiguity (e.g. 
"A([1,2])") - but in general, going beyond a simple contiguous check is 
not possible.

Thus, one can essentially do three things: (a) Keep the current status 
[accepts invalid, which is allowed according to the standard], (b) 
reject clearly invalid arrays such as "tt%t%i(1)", or (c) warn (or even 
give an error) if the argument is not simply contiguous ["Warning: 
Argument to C_LOC might be noncontiguous"].

I am happy with both (b) and (c) (warning) , but not with the current 
patch - even though "c_loc(n(1:2))" can be written as the equivalent 
"c_loc(n(1))". (With some trickery in defining "n", it could be also 
equivalent to "c_loc(n(2)).) Thus, the current patch would not really 
cause that functionality is lost.

Tobias
Thomas Koenig Jan. 15, 2011, 2:07 p.m. UTC | #2
Am 15.01.2011 11:52, schrieb Tobias Burnus:
> "n" is a TARGET, it is not coindexed, has of an interoperable type/kind
> - and it is an array,


Following Richard's explanation, I don't think it is an array, it is an
array section.

Should we ask on c.l.f?

	Thomas
Tobias Burnus Jan. 15, 2011, 4:13 p.m. UTC | #3
Thomas Koenig wrote:
> Am 15.01.2011 11:52, schrieb Tobias Burnus:
>> "n" is a TARGET, it is not coindexed, has of an interoperable type/kind
>> - and it is an array,
> Following Richard's explanation, I don't think it is an array, it is an
> array section.

I agree that it is an array section, but I maintain that it is also an 
array according to the following definition:

"1.3.4 array - set of scalar data, all of the same type and type 
parameters, whose individual elements are arranged in a
rectangular pattern"

> Should we ask on c.l.f?

Seemingly, you already did.* And it looks as if Fortran 2008 relaxed the 
requirements - but don't ask me for the details as I find Fortran 2003 
very unclear.

Tobias

* 
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/4b65b1cd206ce9fe
diff mbox

Patch

Index: resolve.c
===================================================================
--- resolve.c	(Revision 168614)
+++ resolve.c	(Arbeitskopie)
@@ -2709,6 +2709,8 @@  gfc_iso_c_func_interface (gfc_symbol *sym, gfc_act
         }
       else if (sym->intmod_sym_id == ISOCBINDING_LOC)
         {
+	  gfc_ref *ref;
+
           /* Make sure we have either the target or pointer attribute.  */
 	  if (!arg_attr.target && !arg_attr.pointer)
             {
@@ -2719,6 +2721,23 @@  gfc_iso_c_func_interface (gfc_symbol *sym, gfc_act
               retval = FAILURE;
             }
 
+	  /* Follow references to make sure there are no array
+	     slices.  */
+	  for (ref=args->expr->ref; ref; ref = ref->next)
+	    {
+	      if (ref->type == REF_ARRAY)
+		{
+		  if (ref->u.ar.type == AR_SECTION
+		      || (ref->u.ar.type != AR_ELEMENT &&
+			  ref->next && ref->next->type == REF_COMPONENT))
+		    {
+		      gfc_error_now ("Array section not permitted in '%s'"
+				     " call at %L", name, &(args->expr->where));
+		      retval = FAILURE;
+		    }
+		}
+	    }
+
           /* See if we have interoperable type and type param.  */
           if (verify_c_interop (arg_ts) == SUCCESS
               || gfc_check_any_c_kind (arg_ts) == SUCCESS)