diff mbox series

[v1] PR fortran/48958 - Add runtime diagnostics for SIZE intrinsic function

Message ID trinity-40b5eb30-1e93-481c-8dac-ba523821704c-1605392105473@3c-app-gmx-bs60
State New
Headers show
Series [v1] PR fortran/48958 - Add runtime diagnostics for SIZE intrinsic function | expand

Commit Message

Harald Anlauf Nov. 14, 2020, 10:15 p.m. UTC
Dear all,

here is a first version to check the status of ALLOCATABLE and POINTER
arguments to the SIZE intrinsic at runtime.

What it does not yet cover is situations like

  complex, allocatable :: z(:)
  print *, size (z% re)

Feedback, such as comments for improvement, are welcome.

As is, the patch regtests cleanly on x86_64-pc-linux-gnu.

Thanks,
Harald


PR fortran/48958 - Add runtime diagnostics for SIZE intrinsic function

Add code for runtime checking of status of ALLOCATABLE and POINTER
arguments to the SIZE intrinsic when -fcheck=pointer is specified.

gcc/fortran/ChangeLog:

	* trans-intrinsic.c (gfc_conv_intrinsic_size): Generate runtime
	checking code for status of argument.

gcc/testsuite/ChangeLog:

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

Comments

Thomas Koenig Nov. 15, 2020, 9:29 p.m. UTC | #1
Hi Harald,

> Feedback, such as comments for improvement, are welcome.
It feels a bit strange to have a check for an allocatable
behind -fcheck=pointer, but I'm not sure that introducing
a special check option would really be worth it.

Regarding pointers: They are usually not nullified (unless
they are global).  What do people think about adding a
NULL initializer to their data components when -fcheck=pointer is in
force?

On the other hand, for code like

module p
contains
   subroutine foo
   real, pointer, dimension(:) :: pp
     print *,pp
   end subroutine foo
end module p

we at least get a warning already.

Regarding size(x%re):  You would have to chase the refs to find
the allocatable components.

However, I think your patch already makes the situation better for
the user, so I'd say it is good for trunk already; later improvements
are always possible.

Best regards

	Thomas
Harald Anlauf Nov. 16, 2020, 8:57 p.m. UTC | #2
Hi Thomas,

thanks for the comments.

> It feels a bit strange to have a check for an allocatable
> behind -fcheck=pointer, but I'm not sure that introducing
> a special check option would really be worth it.

Yes, I thought about that.  There's already a discrepancy between
the GFC_RTCHECK_* in libgfortran.h, which has

#define GFC_RTCHECK_DO          (1<<3)
#define GFC_RTCHECK_POINTER     (1<<4)
#define GFC_RTCHECK_MEM         (1<<5)

without the latter being documented, and gfortran.texi, which has

[...] GFC_RTCHECK_DO (16), GFC_RTCHECK_POINTER (32), [...]

-fcheck=mem should be checking memory allocations for things
other than allocate (according to invoke.texi), like temporaries.

-fcheck=pointer says:
Enable generation of run-time checks for pointers and allocatables.

So that is at least consistent.

(Note to self: submit patch for obvious documentation fixes).

> Regarding pointers: They are usually not nullified (unless
> they are global).  What do people think about adding a
> NULL initializer to their data components when -fcheck=pointer is in
> force?

I was surprised when looking at the dump-tree difference of

  integer, pointer :: a(:)

vs.

  integer, pointer :: a(:) => NULL()

The latter has the expected:

  static struct array01_integer(kind=4) a = {.data=0B};

while the former has:

  struct array01_integer(kind=4) a;

  a.span = 0;

Why setting .span at all, and not setting a.data = 0B ?

> Regarding size(x%re):  You would have to chase the refs to find
> the allocatable components.

I was probably too tired and drifted off from the subject.
This is a more generic issue and not related to size().

> However, I think your patch already makes the situation better for
> the user, so I'd say it is good for trunk already; later improvements
> are always possible.

Yes.  Will commit soon.

Thanks again,
Harald
diff mbox series

Patch

diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index e0afc10d105..d17b623924c 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -7929,6 +7929,35 @@  gfc_conv_intrinsic_size (gfc_se * se, gfc_expr * expr)
       && strcmp (e->ref->u.c.component->name, "_data") == 0)
     sym = e->symtree->n.sym;

+  if ((gfc_option.rtcheck & GFC_RTCHECK_POINTER)
+      && e
+      && (e->expr_type == EXPR_VARIABLE || e->expr_type == EXPR_FUNCTION))
+    {
+      symbol_attribute attr;
+      char *msg;
+
+      attr = gfc_expr_attr (e);
+      if (attr.allocatable)
+	msg = xasprintf ("Allocatable argument '%s' is not allocated",
+			 e->symtree->n.sym->name);
+      else if (attr.pointer)
+	msg = xasprintf ("Pointer argument '%s' is not associated",
+			 e->symtree->n.sym->name);
+      else
+	goto end_arg_check;
+
+      argse.descriptor_only = 1;
+      gfc_conv_expr_descriptor (&argse, actual->expr);
+      tree temp = gfc_conv_descriptor_data_get (argse.expr);
+      tree cond = fold_build2_loc (input_location, EQ_EXPR,
+				   logical_type_node, temp,
+				   fold_convert (TREE_TYPE (temp),
+						 null_pointer_node));
+      gfc_trans_runtime_check (true, false, cond, &argse.pre, &e->where, msg);
+      free (msg);
+    }
+ end_arg_check:
+
   argse.data_not_needed = 1;
   if (gfc_is_class_array_function (e))
     {
diff --git a/gcc/testsuite/gfortran.dg/pr48958.f90 b/gcc/testsuite/gfortran.dg/pr48958.f90
new file mode 100644
index 00000000000..2b109374f40
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr48958.f90
@@ -0,0 +1,25 @@ 
+! { dg-do run }
+! { dg-options "-fcheck=pointer -fdump-tree-original" }
+! { dg-shouldfail "Fortran runtime error: Allocatable argument 'a' is not allocated" }
+! { dg-output "At line 13 .*" }
+! PR48958 - Add runtime diagnostics for SIZE intrinsic function
+
+program p
+  integer :: n
+  integer,  allocatable :: a(:)
+  integer,  pointer     :: b(:)
+  class(*), allocatable :: c(:)
+  integer               :: d(10)
+  print *, size (a)
+  print *, size (b)
+  print *, size (c)
+  print *, size (d)
+  print *, size (f(n))
+contains
+  function f (n)
+    integer, intent(in) :: n
+    real, allocatable   :: f(:)
+  end function f
+end
+
+! { dg-final { scan-tree-dump-times "_gfortran_runtime_error_at" 4 "original" } }