Hi all!
Proposed patch to Bug 93963 - Select rank mishandling allocatable and
pointer arguments with bind(c).
Patch tested only on x86_64-pc-linux-gnu.
cfi_desc_to_gfc_desc, in ISO_Fortran_binding.c, will likely store -1 (or
garbage) in the upper bound of the descriptor for unallocated, or
unassociated, allocatable, or pointer, arrays effectively marking them
as assumed size arrays.
gfc_trans_select_rank_cases, in trans-stmt.c, will check the upper bound
of arguments in order to check for assumed size arrays even if the array
is a pointer or an allocatable.
Thank you very much.
Best regards,
José Rui
2020-2-27 José Rui Faustino de Sousa <jrfso...@gmail.com>
PR fortran/93963
* trans-stmt.c (gfc_trans_select_rank_cases): Add if conditional
short circuiting the evaluation of rank for allocatable and pointer
arguments.
PR fortran/93963
* ISO_Fortran_binding.c (cfi_desc_to_gfc_desc): Add if conditional
guarding the calculation of dimensional bounds if the data pointer
is NULL.
2020-2-28 José Rui Faustino de Sousa <jrfso...@gmail.com>
PR fortran/93963
* PR93963.f90: New test.
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 4e9b5ad..6a39bda 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -3641,12 +3641,11 @@ gfc_trans_select_rank_cases (gfc_code * code)
tree low;
tree sexpr;
tree rank;
- tree rank_minus_one;
- tree minus_one;
gfc_se se;
gfc_se cse;
stmtblock_t block;
stmtblock_t body;
+ symbol_attribute attr;
bool def = false;
gfc_start_block (&block);
@@ -3655,25 +3654,35 @@ gfc_trans_select_rank_cases (gfc_code * code)
gfc_init_se (&se, NULL);
gfc_conv_expr_descriptor (&se, code->expr1);
rank = gfc_conv_descriptor_rank (se.expr);
- rank = gfc_evaluate_now (rank, &block);
- minus_one = build_int_cst (TREE_TYPE (rank), -1);
- tmp = fold_build2_loc (input_location, MINUS_EXPR,
- gfc_array_index_type,
- fold_convert (gfc_array_index_type, rank),
- build_int_cst (gfc_array_index_type, 1));
- rank_minus_one = gfc_evaluate_now (tmp, &block);
- tmp = gfc_conv_descriptor_ubound_get (se.expr, rank_minus_one);
- cond = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
- tmp, build_int_cst (TREE_TYPE (tmp), -1));
- tmp = fold_build3_loc (input_location, COND_EXPR,
- TREE_TYPE (rank), cond,
- rank, minus_one);
- cond = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
- rank, build_int_cst (TREE_TYPE (rank), 0));
- sexpr = fold_build3_loc (input_location, COND_EXPR,
- TREE_TYPE (rank), cond,
- rank, tmp);
- sexpr = gfc_evaluate_now (sexpr, &block);
+ attr = gfc_expr_attr (code->expr1);
+ if (attr.pointer || attr.allocatable)
+ sexpr = gfc_evaluate_now (rank, &block);
+ else
+ {
+ tree rank_minus_one;
+ tree minus_one;
+
+ rank = gfc_evaluate_now (rank, &block);
+ minus_one = build_int_cst (TREE_TYPE (rank), -1);
+ tmp = fold_build2_loc (input_location, MINUS_EXPR,
+ gfc_array_index_type,
+ fold_convert (gfc_array_index_type, rank),
+ build_int_cst (gfc_array_index_type, 1));
+ rank_minus_one = gfc_evaluate_now (tmp, &block);
+ tmp = gfc_conv_descriptor_ubound_get (se.expr, rank_minus_one);
+ cond = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
+ tmp, build_int_cst (TREE_TYPE (tmp), -1));
+ tmp = fold_build3_loc (input_location, COND_EXPR,
+ TREE_TYPE (rank), cond,
+ rank, minus_one);
+ cond = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
+ rank, build_int_cst (TREE_TYPE (rank), 0));
+ sexpr = fold_build3_loc (input_location, COND_EXPR,
+ TREE_TYPE (rank), cond,
+ rank, tmp);
+ sexpr = gfc_evaluate_now (sexpr, &block);
+ }
+
TREE_USED (code->exit_label) = 0;
repeat:
diff --git a/gcc/testsuite/gfortran.dg/PR93963.f90
b/gcc/testsuite/gfortran.dg/PR93963.f90
new file mode 100644
index 0000000..15ab59a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/PR93963.f90
@@ -0,0 +1,146 @@
+! { dg-do run }
+!
+! PR fortran/93963
+!
+
+function rank_p(this) result(rnk) bind(c)
+ use, intrinsic :: iso_c_binding, only: c_int
+
+ implicit none
+
+ integer(kind=c_int), pointer, intent(in) :: this(..)
+ integer(kind=c_int) :: rnk
+
+ select rank(this)
+ rank(0)
+ rnk = 0
+ rank(1)
+ rnk = 1
+ rank(2)
+ rnk = 2
+ rank(3)
+ rnk = 3
+ rank(4)
+ rnk = 4
+ rank(5)
+ rnk = 5
+ rank(6)
+ rnk = 6
+ rank(7)
+ rnk = 7
+ rank(8)
+ rnk = 8
+ rank(9)
+ rnk = 9
+ rank(10)
+ rnk = 10
+ rank(11)
+ rnk = 11
+ rank(12)
+ rnk = 12
+ rank(13)
+ rnk = 13
+ rank(14)
+ rnk = 14
+ rank(15)
+ rnk = 15
+ rank default
+ rnk = -1000
+ end select
+ return
+end function rank_p
+
+function rank_a(this) result(rnk) bind(c)
+ use, intrinsic :: iso_c_binding, only: c_int
+
+ implicit none
+
+ integer(kind=c_int), allocatable, intent(in) :: this(..)
+ integer(kind=c_int) :: rnk
+
+ select rank(this)
+ rank(0)
+ rnk = 0
+ rank(1)
+ rnk = 1
+ rank(2)
+ rnk = 2
+ rank(3)
+ rnk = 3
+ rank(4)
+ rnk = 4
+ rank(5)
+ rnk = 5
+ rank(6)
+ rnk = 6
+ rank(7)
+ rnk = 7
+ rank(8)
+ rnk = 8
+ rank(9)
+ rnk = 9
+ rank(10)
+ rnk = 10
+ rank(11)
+ rnk = 11
+ rank(12)
+ rnk = 12
+ rank(13)
+ rnk = 13
+ rank(14)
+ rnk = 14
+ rank(15)
+ rnk = 15
+ rank default
+ rnk = -1000
+ end select
+ return
+end function rank_a
+
+program selr_p
+
+ use, intrinsic :: iso_c_binding, only: c_int
+
+ implicit none
+
+ interface
+ function rank_p(this) result(rnk) bind(c)
+ use, intrinsic :: iso_c_binding, only: c_int
+ integer(kind=c_int), pointer, intent(in) :: this(..)
+ integer(kind=c_int) :: rnk
+ end function rank_p
+ end interface
+
+ interface
+ function rank_a(this) result(rnk) bind(c)
+ use, intrinsic :: iso_c_binding, only: c_int
+ integer(kind=c_int), allocatable, intent(in) :: this(..)
+ integer(kind=c_int) :: rnk
+ end function rank_a
+ end interface
+
+ integer(kind=c_int), parameter :: siz = 7
+ integer(kind=c_int), parameter :: rnk = 1
+
+ integer(kind=c_int), pointer :: intp(:)
+ integer(kind=c_int), allocatable :: inta(:)
+
+ nullify(intp)
+ if(rank(intp)/=rnk) stop 1
+ if(rank_p(intp)/=rnk) stop 2
+ !
+ if(rank(inta)/=rnk) stop 3
+ if(rank_a(inta)/=rnk) stop 4
+ !
+ allocate(intp(siz))
+ if(rank(intp)/=rnk) stop 5
+ if(rank_p(intp)/=rnk) stop 6
+ deallocate(intp)
+ nullify(intp)
+ !
+ allocate(inta(siz))
+ if(rank(inta)/=rnk) stop 7
+ if(rank_a(inta)/=rnk) stop 8
+ deallocate(inta)
+
+end program selr_p
diff --git a/libgfortran/runtime/ISO_Fortran_binding.c
b/libgfortran/runtime/ISO_Fortran_binding.c
index a546b04..cd304f6 100644
--- a/libgfortran/runtime/ISO_Fortran_binding.c
+++ b/libgfortran/runtime/ISO_Fortran_binding.c
@@ -74,14 +74,15 @@ cfi_desc_to_gfc_desc (gfc_array_void *d, CFI_cdesc_t
**s_ptr)
}
d->offset = 0;
- for (n = 0; n < GFC_DESCRIPTOR_RANK (d); n++)
- {
- GFC_DESCRIPTOR_LBOUND(d, n) = (index_type)s->dim[n].lower_bound;
- GFC_DESCRIPTOR_UBOUND(d, n) = (index_type)(s->dim[n].extent
- + s->dim[n].lower_bound - 1);
- GFC_DESCRIPTOR_STRIDE(d, n) = (index_type)(s->dim[n].sm /
s->elem_len);
- d->offset -= GFC_DESCRIPTOR_STRIDE(d, n) *
GFC_DESCRIPTOR_LBOUND(d, n);
- }
+ if (GFC_DESCRIPTOR_DATA (d))
+ for (n = 0; n < GFC_DESCRIPTOR_RANK (d); n++)
+ {
+ GFC_DESCRIPTOR_LBOUND(d, n) = (index_type)s->dim[n].lower_bound;
+ GFC_DESCRIPTOR_UBOUND(d, n) = (index_type)(s->dim[n].extent
+ + s->dim[n].lower_bound - 1);
+ GFC_DESCRIPTOR_STRIDE(d, n) = (index_type)(s->dim[n].sm / s->elem_len);
+ d->offset -= GFC_DESCRIPTOR_STRIDE(d, n) * GFC_DESCRIPTOR_LBOUND(d, n);
+ }
}
extern void gfc_desc_to_cfi_desc (CFI_cdesc_t **, const gfc_array_void *);