Hi all,This patch implements the optional lower argument for the c_f_pointer intrinsic, as specified in the Fortran 2023 standard. I've also included documentation and tests, and the regression tests on aarch64-linux passed.
Please take a look when you have a chance. Thanks, Yuao
From 74eba4dbd7601ca4c854b0e6138b6bffc727222a Mon Sep 17 00:00:00 2001 From: Yuao Ma <c...@outlook.com> Date: Tue, 5 Aug 2025 23:33:16 +0800 Subject: [PATCH] fortran: add optional lower arg to c_f_pointer This patch adds support for the optional lower argument in intrinsic c_f_pointer specified in Fortran 2023. Test cases and documentation have also been updated. gcc/fortran/ChangeLog: * check.cc (gfc_check_c_f_pointer): Check lower arg legitimacy. * intrinsic.cc (add_subroutines): Teach c_f_pointer about lower arg. * intrinsic.h (gfc_check_c_f_pointer): Add lower arg. * intrinsic.texi: Update lower arg for c_f_pointer. * trans-intrinsic.cc (conv_isocbinding_subroutine): Add logic handle lower. gcc/testsuite/ChangeLog: * gfortran.dg/c_f_pointer_shape_tests_3.f03: Check rank & type for lower. * gfortran.dg/c_f_pointer_shape_tests_7.f90: New test. Signed-off-by: Yuao Ma <c...@outlook.com> --- gcc/fortran/check.cc | 35 +++++- gcc/fortran/intrinsic.cc | 5 +- gcc/fortran/intrinsic.h | 2 +- gcc/fortran/intrinsic.texi | 12 ++- gcc/fortran/trans-intrinsic.cc | 100 ++++++++++++------ .../gfortran.dg/c_f_pointer_shape_tests_3.f03 | 29 +++-- .../gfortran.dg/c_f_pointer_shape_tests_7.f90 | 34 ++++++ 7 files changed, 171 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_7.f90 diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc index 862652683a7..3c4594be9e7 100644 --- a/gcc/fortran/check.cc +++ b/gcc/fortran/check.cc @@ -6081,7 +6081,8 @@ gfc_check_c_associated (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2) bool -gfc_check_c_f_pointer (gfc_expr *cptr, gfc_expr *fptr, gfc_expr *shape) +gfc_check_c_f_pointer (gfc_expr *cptr, gfc_expr *fptr, gfc_expr *shape, + gfc_expr *lower) { symbol_attribute attr; const char *msg; @@ -6156,6 +6157,38 @@ gfc_check_c_f_pointer (gfc_expr *cptr, gfc_expr *fptr, gfc_expr *shape) } } + if (!shape && lower) + { + gfc_error ("Unexpected LOWER argument at %L to C_F_POINTER " + "with scalar FPTR", + &fptr->where); + return false; + } + + if (lower && !rank_check (lower, 3, 1)) + return false; + + if (lower && !type_check (lower, 3, BT_INTEGER)) + return false; + + if (lower) + { + mpz_t size; + if (gfc_array_size (lower, &size)) + { + if (mpz_cmp_ui (size, fptr->rank) != 0) + { + mpz_clear (size); + gfc_error ( + "LOWER argument at %L to C_F_POINTER must have the same " + "size as the RANK of FPTR", + &lower->where); + return false; + } + mpz_clear (size); + } + } + if (fptr->ts.type == BT_CLASS) { gfc_error ("Polymorphic FPTR at %L to C_F_POINTER", &fptr->where); diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc index c99a7a86aea..e2847f08daa 100644 --- a/gcc/fortran/intrinsic.cc +++ b/gcc/fortran/intrinsic.cc @@ -3943,11 +3943,12 @@ add_subroutines (void) /* The following subroutines are part of ISO_C_BINDING. */ - add_sym_3s ("c_f_pointer", GFC_ISYM_C_F_POINTER, CLASS_IMPURE, BT_UNKNOWN, 0, + add_sym_4s ("c_f_pointer", GFC_ISYM_C_F_POINTER, CLASS_IMPURE, BT_UNKNOWN, 0, GFC_STD_F2003, gfc_check_c_f_pointer, NULL, NULL, "cptr", BT_VOID, 0, REQUIRED, INTENT_IN, "fptr", BT_UNKNOWN, 0, REQUIRED, INTENT_OUT, - "shape", BT_INTEGER, di, OPTIONAL, INTENT_IN); + "shape", BT_INTEGER, di, OPTIONAL, INTENT_IN, + "lower", BT_INTEGER, di, OPTIONAL, INTENT_IN); make_from_module(); add_sym_2s ("c_f_procpointer", GFC_ISYM_C_F_PROCPOINTER, CLASS_IMPURE, diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h index 8a0ab935e1f..048196d65c3 100644 --- a/gcc/fortran/intrinsic.h +++ b/gcc/fortran/intrinsic.h @@ -165,7 +165,7 @@ bool gfc_check_sign (gfc_expr *, gfc_expr *); bool gfc_check_signal (gfc_expr *, gfc_expr *); bool gfc_check_sizeof (gfc_expr *); bool gfc_check_c_associated (gfc_expr *, gfc_expr *); -bool gfc_check_c_f_pointer (gfc_expr *, gfc_expr *, gfc_expr *); +bool gfc_check_c_f_pointer (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); bool gfc_check_c_f_procpointer (gfc_expr *, gfc_expr *); bool gfc_check_c_funloc (gfc_expr *); bool gfc_check_c_loc (gfc_expr *); diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index a24b234316c..d06c9d9dadc 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -3368,10 +3368,10 @@ Fortran 2003 and later @table @asis @item @emph{Synopsis}: -@code{CALL C_F_POINTER(CPTR, FPTR[, SHAPE])} +@code{CALL C_F_POINTER(CPTR, FPTR[, SHAPE, LOWER])} @item @emph{Description}: -@code{C_F_POINTER(CPTR, FPTR[, SHAPE])} assigns the target of the C pointer +@code{C_F_POINTER(CPTR, FPTR[, SHAPE, LOWER])} assigns the target of the C pointer @var{CPTR} to the Fortran pointer @var{FPTR} and specifies its shape. @item @emph{Class}: @@ -3385,8 +3385,12 @@ Subroutine @code{INTENT(OUT)}. @item @var{SHAPE} @tab (Optional) Rank-one array of type @code{INTEGER} with @code{INTENT(IN)}. It shall be present -if and only if @var{fptr} is an array. The size -must be equal to the rank of @var{fptr}. +if and only if @var{FPTR} is an array. The size +must be equal to the rank of @var{FPTR}. +@item @var{LOWER} @tab (Optional) Rank-one array of type @code{INTEGER} +with @code{INTENT(IN)}. It shall not be present +if @var{SHAPE} is not present. The size +must be equal to the rank of @var{FPTR}. @end multitable @item @emph{Example}: diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc index f68ceb18820..7d874548b32 100644 --- a/gcc/fortran/trans-intrinsic.cc +++ b/gcc/fortran/trans-intrinsic.cc @@ -9918,38 +9918,40 @@ conv_isocbinding_function (gfc_se *se, gfc_expr *expr) static tree conv_isocbinding_subroutine (gfc_code *code) { - gfc_se se; - gfc_se cptrse; - gfc_se fptrse; - gfc_se shapese; - gfc_ss *shape_ss; - tree desc, dim, tmp, stride, offset; + gfc_expr *cptr, *fptr, *shape, *lower; + gfc_se se, cptrse, fptrse, shapese, lowerse; + gfc_ss *shape_ss, *lower_ss; + tree desc, dim, tmp, stride, offset, lbound, ubound; stmtblock_t body, block; gfc_loopinfo loop; - gfc_actual_arglist *arg = code->ext.actual; + gfc_actual_arglist *arg; + + arg = code->ext.actual; + cptr = arg->expr; + fptr = arg->next->expr; + shape = arg->next->next ? arg->next->next->expr : NULL; + lower = shape && arg->next->next->next ? arg->next->next->next->expr : NULL; gfc_init_se (&se, NULL); gfc_init_se (&cptrse, NULL); - gfc_conv_expr (&cptrse, arg->expr); + gfc_conv_expr (&cptrse, cptr); gfc_add_block_to_block (&se.pre, &cptrse.pre); gfc_add_block_to_block (&se.post, &cptrse.post); gfc_init_se (&fptrse, NULL); - if (arg->next->expr->rank == 0) + if (fptr->rank == 0) { fptrse.want_pointer = 1; - gfc_conv_expr (&fptrse, arg->next->expr); + gfc_conv_expr (&fptrse, fptr); gfc_add_block_to_block (&se.pre, &fptrse.pre); gfc_add_block_to_block (&se.post, &fptrse.post); - if (arg->next->expr->symtree->n.sym->attr.proc_pointer - && arg->next->expr->symtree->n.sym->attr.dummy) - fptrse.expr = build_fold_indirect_ref_loc (input_location, - fptrse.expr); - se.expr = fold_build2_loc (input_location, MODIFY_EXPR, - TREE_TYPE (fptrse.expr), - fptrse.expr, - fold_convert (TREE_TYPE (fptrse.expr), - cptrse.expr)); + if (fptr->symtree->n.sym->attr.proc_pointer + && fptr->symtree->n.sym->attr.dummy) + fptrse.expr = build_fold_indirect_ref_loc (input_location, fptrse.expr); + se.expr + = fold_build2_loc (input_location, MODIFY_EXPR, TREE_TYPE (fptrse.expr), + fptrse.expr, + fold_convert (TREE_TYPE (fptrse.expr), cptrse.expr)); gfc_add_expr_to_block (&se.pre, se.expr); gfc_add_block_to_block (&se.pre, &se.post); return gfc_finish_block (&se.pre); @@ -9959,7 +9961,7 @@ conv_isocbinding_subroutine (gfc_code *code) /* Get the descriptor of the Fortran pointer. */ fptrse.descriptor_only = 1; - gfc_conv_expr_descriptor (&fptrse, arg->next->expr); + gfc_conv_expr_descriptor (&fptrse, fptr); gfc_add_block_to_block (&block, &fptrse.pre); desc = fptrse.expr; @@ -9976,18 +9978,33 @@ conv_isocbinding_subroutine (gfc_code *code) /* Start scalarization of the bounds, using the shape argument. */ - shape_ss = gfc_walk_expr (arg->next->next->expr); + shape_ss = gfc_walk_expr (shape); gcc_assert (shape_ss != gfc_ss_terminator); gfc_init_se (&shapese, NULL); + if (lower) + { + lower_ss = gfc_walk_expr (lower); + gcc_assert (lower_ss != gfc_ss_terminator); + gfc_init_se (&lowerse, NULL); + } gfc_init_loopinfo (&loop); gfc_add_ss_to_loop (&loop, shape_ss); + if (lower) + gfc_add_ss_to_loop (&loop, lower_ss); gfc_conv_ss_startstride (&loop); - gfc_conv_loop_setup (&loop, &arg->next->expr->where); + gfc_conv_loop_setup (&loop, &fptr->where); gfc_mark_ss_chain_used (shape_ss, 1); + if (lower) + gfc_mark_ss_chain_used (lower_ss, 1); gfc_copy_loopinfo_to_se (&shapese, &loop); shapese.ss = shape_ss; + if (lower) + { + gfc_copy_loopinfo_to_se (&lowerse, &loop); + lowerse.ss = lower_ss; + } stride = gfc_create_var (gfc_array_index_type, "stride"); offset = gfc_create_var (gfc_array_index_type, "offset"); @@ -9998,27 +10015,46 @@ conv_isocbinding_subroutine (gfc_code *code) gfc_start_scalarized_body (&loop, &body); dim = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type, - loop.loopvar[0], loop.from[0]); + loop.loopvar[0], loop.from[0]); + + if (lower) + { + gfc_conv_expr (&lowerse, lower); + gfc_add_block_to_block (&body, &lowerse.pre); + lbound = fold_convert (gfc_array_index_type, lowerse.expr); + gfc_add_block_to_block (&body, &lowerse.post); + } + else + { + lbound = gfc_index_one_node; + } /* Set bounds and stride. */ - gfc_conv_descriptor_lbound_set (&body, desc, dim, gfc_index_one_node); + gfc_conv_descriptor_lbound_set (&body, desc, dim, lbound); gfc_conv_descriptor_stride_set (&body, desc, dim, stride); - gfc_conv_expr (&shapese, arg->next->next->expr); + gfc_conv_expr (&shapese, shape); gfc_add_block_to_block (&body, &shapese.pre); - gfc_conv_descriptor_ubound_set (&body, desc, dim, shapese.expr); + ubound = fold_build2_loc ( + input_location, MINUS_EXPR, gfc_array_index_type, + fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type, lbound, + fold_convert (gfc_array_index_type, shapese.expr)), + gfc_index_one_node); + gfc_conv_descriptor_ubound_set (&body, desc, dim, ubound); gfc_add_block_to_block (&body, &shapese.post); /* Calculate offset. */ + tmp = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type, + stride, lbound); gfc_add_modify (&body, offset, fold_build2_loc (input_location, PLUS_EXPR, - gfc_array_index_type, offset, stride)); + gfc_array_index_type, offset, tmp)); + /* Update stride. */ - gfc_add_modify (&body, stride, - fold_build2_loc (input_location, MULT_EXPR, - gfc_array_index_type, stride, - fold_convert (gfc_array_index_type, - shapese.expr))); + gfc_add_modify ( + &body, stride, + fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type, stride, + fold_convert (gfc_array_index_type, shapese.expr))); /* Finish scalarization loop. */ gfc_trans_scalarizing_loops (&loop, &body); gfc_add_block_to_block (&block, &loop.pre); diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_3.f03 b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_3.f03 index 632e4579ce8..67dc0f0a444 100644 --- a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_3.f03 +++ b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_3.f03 @@ -2,21 +2,38 @@ ! Verify that the type and rank of the SHAPE argument are enforced. module c_f_pointer_shape_tests_3 use, intrinsic :: iso_c_binding - + contains subroutine sub0(my_c_array) bind(c) type(c_ptr), value :: my_c_array - integer(c_int), dimension(:), pointer :: my_array_ptr - + integer(kind=c_int), dimension(:), pointer :: my_array_ptr + call c_f_pointer(my_c_array, my_array_ptr, (/ 10.0 /)) ! { dg-error "must be INTEGER" } end subroutine sub0 subroutine sub1(my_c_array) bind(c) type(c_ptr), value :: my_c_array - integer(c_int), dimension(:), pointer :: my_array_ptr - integer(c_int), dimension(1,1) :: shape + integer(kind=c_int), dimension(:), pointer :: my_array_ptr + integer(kind=c_int), dimension(1, 1) :: shape - shape(1,1) = 10 + shape(1, 1) = 10 call c_f_pointer(my_c_array, my_array_ptr, shape) ! { dg-error "must be of rank 1" } end subroutine sub1 + + subroutine sub2(my_c_array) bind(c) + type(c_ptr), value :: my_c_array + integer(kind=c_int), dimension(:), pointer :: my_array_ptr + + call c_f_pointer(my_c_array, my_array_ptr, (/ 10 /), (/ 10.0 /)) ! { dg-error "must be INTEGER" } + end subroutine sub2 + + subroutine sub3(my_c_array) bind(c) + type(c_ptr), value :: my_c_array + integer(kind=c_int), dimension(:), pointer :: my_array_ptr + integer(kind=c_int), dimension(1) :: shape + integer(kind=c_int), dimension(1, 1) :: lower + + lower(1, 1) = 10 + call c_f_pointer(my_c_array, my_array_ptr, shape, lower) ! { dg-error "must be of rank 1" } + end subroutine sub3 end module c_f_pointer_shape_tests_3 diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_7.f90 b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_7.f90 new file mode 100644 index 00000000000..7190961d0f3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_7.f90 @@ -0,0 +1,34 @@ +! { dg-do run } +program lower + use iso_c_binding + type(c_ptr) :: x + integer, target :: array_2d(12), array_3d(24) + integer, pointer :: ptr_2d(:, :), ptr_3d(:, :, :) + integer :: myshape_2d(2), myshape_3d(3) + integer :: mylower_2d(2), mylower_3d(3) + + array_2d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + x = c_loc(array_2d) + myshape_2d = [3, 4] + mylower_2d = [2, 2] + + call c_f_pointer(x, ptr_2d, shape=myshape_2d, lower=mylower_2d) + if (any(lbound(ptr_2d) /= [2, 2])) stop 1 + if (any(ubound(ptr_2d) /= [4, 5])) stop 2 + if (any(shape(ptr_2d) /= [3, 4])) stop 3 + if (ptr_2d(2, 2) /= 1) stop 4 + if (ptr_2d(3, 4) /= 8) stop 5 + if (ptr_2d(4, 5) /= 12) stop 6 + + array_3d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] + x = c_loc(array_3d) + myshape_3d = [2, 3, 4] + mylower_3d = [-1, -2, -3] + + call c_f_pointer(x, ptr_3d, shape=myshape_3d, lower=mylower_3d) + if (any(lbound(ptr_3d) /= [-1, -2, -3])) stop 7 + if (any(ubound(ptr_3d) /= [0, 0, 0])) stop 8 + if (any(shape(ptr_3d) /= [2, 3, 4])) stop 9 + if (ptr_3d(0, 0, 0) /= 24) stop 10 + +end program lower -- 2.43.0