Hi Mikael,

On 7/17/2025 3:47 PM, Mikael Morin wrote:
How did you declare gfor_fndecl_string_split?
More exactly what is the declaration type for the POS argument?

For the POS argument type, I'm using build_pointer_type(gfc_charlen_type_node). I got this from string_minmax, but I'm unsure if it's the right fit here.

Also, I'm encountering an issue with pointer declarations. I've found two methods: gfc_build_addr_expr and se.want_pointer. Are these the same, or do they have different uses? I've tried both, and they give me the same errors in my tests.

I've attached a minimal patch below that reproduces the issue, even though it's incomplete. Hopefully, this helps with troubleshooting.

Thanks,
Yuao
diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 838d523f7c4..be323639e52 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -5560,6 +5560,25 @@ gfc_check_scan (gfc_expr *x, gfc_expr *y, gfc_expr *z, 
gfc_expr *kind)
 }
 
 
+bool gfc_check_split (gfc_expr *string, gfc_expr *set, gfc_expr *pos, gfc_expr 
*back) {
+  if (!type_check (string, 0, BT_CHARACTER))
+    return false;
+
+  if (!type_check (set, 1, BT_CHARACTER))
+    return false;
+
+  if (!type_check(pos, 2, BT_INTEGER) || !scalar_check(pos, 2))
+    return false;
+
+  if (back != NULL && !type_check (back, 3, BT_LOGICAL))
+    return false;
+
+  if (!same_type_check (string, 0, set, 1))
+    return false;
+
+  return true;
+}
+
 bool
 gfc_check_secnds (gfc_expr *r)
 {
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 4c85548bc30..7233ea277ca 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -729,6 +729,8 @@ enum gfc_isym_id
   GFC_ISYM_COSPI,
   GFC_ISYM_SINPI,
   GFC_ISYM_TANPI,
+
+  GFC_ISYM_SPLIT,
 };
 
 enum init_local_logical
diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc
index 9e07627503d..0ed2bd078bf 100644
--- a/gcc/fortran/intrinsic.cc
+++ b/gcc/fortran/intrinsic.cc
@@ -3933,6 +3933,14 @@ add_subroutines (void)
              pt, BT_INTEGER, di, OPTIONAL, INTENT_IN,
              gt, BT_INTEGER, di, OPTIONAL, INTENT_OUT);
 
+  add_sym_4s ("split", GFC_ISYM_SPLIT, CLASS_IMPURE, 
+             BT_UNKNOWN, 0, GFC_STD_F2023,
+             gfc_check_split, NULL, gfc_resolve_split,
+             "string", BT_CHARACTER, dc, REQUIRED, INTENT_IN,
+             "set", BT_CHARACTER, dc, REQUIRED, INTENT_IN,
+             "pos", BT_INTEGER, di, REQUIRED, INTENT_INOUT,
+             "back", BT_LOGICAL, dl, OPTIONAL, INTENT_IN);
+
   /* 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,
diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h
index fd54588054f..8a0ab935e1f 100644
--- a/gcc/fortran/intrinsic.h
+++ b/gcc/fortran/intrinsic.h
@@ -215,6 +215,7 @@ bool gfc_check_mvbits (gfc_expr *, gfc_expr *, gfc_expr *, 
gfc_expr *,
 bool gfc_check_random_init (gfc_expr *, gfc_expr *);
 bool gfc_check_random_number (gfc_expr *);
 bool gfc_check_random_seed (gfc_expr *, gfc_expr *, gfc_expr *);
+bool gfc_check_split (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *);
 bool gfc_check_dtime_etime_sub (gfc_expr *, gfc_expr *);
 bool gfc_check_fgetputc_sub (gfc_expr *, gfc_expr *, gfc_expr *);
 bool gfc_check_fgetput_sub (gfc_expr *, gfc_expr *);
@@ -693,6 +694,7 @@ void gfc_resolve_link_sub (gfc_code *);
 void gfc_resolve_symlnk_sub (gfc_code *);
 void gfc_resolve_signal_sub (gfc_code *);
 void gfc_resolve_sleep_sub (gfc_code *);
+void gfc_resolve_split (gfc_code *);
 void gfc_resolve_stat_sub (gfc_code *);
 void gfc_resolve_system_clock (gfc_code *);
 void gfc_resolve_system_sub (gfc_code *);
diff --git a/gcc/fortran/iresolve.cc b/gcc/fortran/iresolve.cc
index 10013096c70..1968bb8a325 100644
--- a/gcc/fortran/iresolve.cc
+++ b/gcc/fortran/iresolve.cc
@@ -3864,6 +3864,18 @@ gfc_resolve_sleep_sub (gfc_code *c)
 }
 
 
+void gfc_resolve_split (gfc_code *c) {
+  const char *name;
+  gfc_expr *string;
+
+  string = c->ext.actual->expr;
+  if(string->ts.type == BT_CHARACTER && string->ts.kind == 4)
+    name = "__split_char4";
+  else
+    name = "__split";
+  c->resolved_sym = gfc_get_intrinsic_sub_symbol(name);
+}
+
 /* G77 compatibility function srand().  */
 
 void
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 43bd7be54cb..e0475ab3859 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -197,6 +197,7 @@ tree gfor_fndecl_string_scan;
 tree gfor_fndecl_string_verify;
 tree gfor_fndecl_string_trim;
 tree gfor_fndecl_string_minmax;
+tree gfor_fndecl_string_split;
 tree gfor_fndecl_adjustl;
 tree gfor_fndecl_adjustr;
 tree gfor_fndecl_select_string;
@@ -208,6 +209,7 @@ tree gfor_fndecl_string_scan_char4;
 tree gfor_fndecl_string_verify_char4;
 tree gfor_fndecl_string_trim_char4;
 tree gfor_fndecl_string_minmax_char4;
+tree gfor_fndecl_string_split_char4;
 tree gfor_fndecl_adjustl_char4;
 tree gfor_fndecl_adjustr_char4;
 tree gfor_fndecl_select_string_char4;
@@ -3569,6 +3571,11 @@ gfc_build_intrinsic_function_decls (void)
        build_pointer_type (pchar1_type_node), integer_type_node,
        integer_type_node);
 
+  gfor_fndecl_string_split = gfc_build_library_function_decl_with_spec (
+       get_identifier (PREFIX("string_split")), ". . R . R . . ",
+       void_type_node, 6, gfc_charlen_type_node, pchar1_type_node,
+       gfc_charlen_type_node, pchar1_type_node, build_pointer_type 
(gfc_charlen_type_node),gfc_logical4_type_node);
+
   gfor_fndecl_adjustl = gfc_build_library_function_decl_with_spec (
        get_identifier (PREFIX("adjustl")), ". W . R ",
        void_type_node, 3, pchar1_type_node, gfc_charlen_type_node,
@@ -3641,6 +3648,11 @@ gfc_build_intrinsic_function_decls (void)
        build_pointer_type (pchar4_type_node), integer_type_node,
        integer_type_node);
 
+  gfor_fndecl_string_split_char4 = gfc_build_library_function_decl_with_spec (
+       get_identifier (PREFIX("string_split_char4")), ". . R . R . . ",
+       void_type_node, 6, gfc_charlen_type_node, pchar4_type_node,
+       gfc_charlen_type_node, pchar4_type_node, build_pointer_type 
(gfc_charlen_type_node),gfc_logical4_type_node);
+
   gfor_fndecl_adjustl_char4 = gfc_build_library_function_decl_with_spec (
        get_identifier (PREFIX("adjustl_char4")), ". W . R ",
        void_type_node, 3, pchar4_type_node, gfc_charlen_type_node,
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index be984271d6a..2d259d7fbaf 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -3466,6 +3466,48 @@ else
   return gfc_finish_block (&block);
 }
 
+static tree
+conv_intrinsic_split (gfc_code *code) {
+  stmtblock_t block;
+  gfc_se se;
+  tree stringlen, string;
+  tree setlen, set;
+  tree pos, back;
+  tree tmp;
+
+
+  gfc_start_block (&block);
+
+  gfc_init_se (&se, NULL);
+  gfc_conv_expr(&se, code->ext.actual->expr);
+  gfc_conv_string_parameter(&se);
+  stringlen = se.string_length;
+  gfc_add_block_to_block(&block, &se.pre);
+  gfc_add_block_to_block(&block, &se.post);
+  string = se.expr;
+
+  gfc_init_se (&se, NULL);
+  gfc_conv_expr(&se, code->ext.actual->next->expr);
+  gfc_conv_string_parameter(&se);
+  setlen = se.string_length;
+  gfc_add_block_to_block(&block, &se.pre);
+  gfc_add_block_to_block(&block, &se.post);
+  set = se.expr;
+
+  gfc_init_se (&se, NULL);
+
+  gfc_conv_expr(&se, code->ext.actual->next->next->expr);
+  gfc_add_block_to_block(&block, &se.pre);
+  gfc_add_block_to_block(&block, &se.post);
+  pos = se.expr;
+  pos = gfc_build_addr_expr(NULL_TREE, pos);
+
+  back = build_int_cst (gfc_get_logical_type (4), 0);
+
+  tmp = build_call_expr_loc (input_location, gfor_fndecl_string_split, 6, 
stringlen, string, setlen, set, pos, back);
+  gfc_add_expr_to_block (&block, tmp);
+  return gfc_finish_block (&block);
+}
 
 /* Return a character string containing the tty name.  */
 
@@ -13261,6 +13303,10 @@ gfc_conv_intrinsic_subroutine (gfc_code *code)
       res = conv_intrinsic_system_clock (code);
       break;
 
+    case GFC_ISYM_SPLIT:
+      res = conv_intrinsic_split (code);
+      break;
+
     default:
       res = NULL_TREE;
       break;
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 461b0cdac71..40680e97cbc 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -961,6 +961,7 @@ extern GTY(()) tree gfor_fndecl_string_scan;
 extern GTY(()) tree gfor_fndecl_string_verify;
 extern GTY(()) tree gfor_fndecl_string_trim;
 extern GTY(()) tree gfor_fndecl_string_minmax;
+extern GTY(()) tree gfor_fndecl_string_split;
 extern GTY(()) tree gfor_fndecl_adjustl;
 extern GTY(()) tree gfor_fndecl_adjustr;
 extern GTY(()) tree gfor_fndecl_select_string;
@@ -972,6 +973,7 @@ extern GTY(()) tree gfor_fndecl_string_scan_char4;
 extern GTY(()) tree gfor_fndecl_string_verify_char4;
 extern GTY(()) tree gfor_fndecl_string_trim_char4;
 extern GTY(()) tree gfor_fndecl_string_minmax_char4;
+extern GTY(()) tree gfor_fndecl_string_split_char4;
 extern GTY(()) tree gfor_fndecl_adjustl_char4;
 extern GTY(()) tree gfor_fndecl_adjustr_char4;
 extern GTY(()) tree gfor_fndecl_select_string_char4;
diff --git a/gcc/testsuite/gfortran.dg/split_1.f90 
b/gcc/testsuite/gfortran.dg/split_1.f90
new file mode 100644
index 00000000000..8f381a9e995
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/split_1.f90
@@ -0,0 +1,12 @@
+! { dg-do run }
+program b
+  CHARACTER (LEN=:), ALLOCATABLE :: INPUT
+  CHARACTER (LEN=2) :: SET = ', '
+  INTEGER P
+  INPUT = "one,last example"
+  P = 4
+  ISTART = P + 1
+  CALL SPLIT (INPUT, SET, P)
+  IEND = P - 1
+  PRINT '(T7,A)', INPUT (ISTART:IEND)
+end program b
diff --git a/libgfortran/gfortran.map b/libgfortran/gfortran.map
index 742dddfe559..0eb2cf6936e 100644
--- a/libgfortran/gfortran.map
+++ b/libgfortran/gfortran.map
@@ -1262,6 +1262,8 @@ GFORTRAN_8 {
     _gfortran_string_minmax_char4;
     _gfortran_string_scan;
     _gfortran_string_scan_char4;
+    _gfortran_string_split;
+    _gfortran_string_split_char4;
     _gfortran_string_trim;
     _gfortran_string_trim_char4;
     _gfortran_string_verify;
diff --git a/libgfortran/intrinsics/string_intrinsics_inc.c 
b/libgfortran/intrinsics/string_intrinsics_inc.c
index d86bb6c8833..0c2f326990d 100644
--- a/libgfortran/intrinsics/string_intrinsics_inc.c
+++ b/libgfortran/intrinsics/string_intrinsics_inc.c
@@ -33,6 +33,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If 
not, see
 #define string_verify SUFFIX(string_verify)
 #define string_trim SUFFIX(string_trim)
 #define string_minmax SUFFIX(string_minmax)
+#define string_split SUFFIX(string_split)
 #define zero_length_string SUFFIX(zero_length_string)
 #define compare_string SUFFIX(compare_string)
 
@@ -72,6 +73,9 @@ export_proto(string_trim);
 extern void string_minmax (gfc_charlen_type *, CHARTYPE **, int, int, ...);
 export_proto(string_minmax);
 
+extern void string_split (gfc_charlen_type, const CHARTYPE *, gfc_charlen_type,
+                         const CHARTYPE *, gfc_charlen_type *, GFC_LOGICAL_4);
+export_proto (string_split);
 
 /* Use for functions which can return a zero-length string.  */
 static CHARTYPE zero_length_string = 0;
@@ -459,3 +463,73 @@ string_minmax (gfc_charlen_type *rlen, CHARTYPE **dest, 
int op, int nargs, ...)
       *dest = tmp;
     }
 }
+
+void
+string_split (gfc_charlen_type stringlen, const CHARTYPE *string,
+             gfc_charlen_type setlen, const CHARTYPE *set,
+             gfc_charlen_type *pos, GFC_LOGICAL_4 back)
+{
+  // *pos = 4;
+  gfc_charlen_type i, j;
+
+  if (!back)
+    {
+      if (*pos < 0 || *pos > stringlen)
+       runtime_error ("If BACK is present with the value false, the value of "
+                      "POS shall be in the range [0, LEN (STRING)=%llu], 
*pos=%llu", stringlen, *pos);
+
+      if (stringlen == 0 || setlen == 0)
+       {
+         *pos = stringlen + 1;
+         return;
+       }
+
+      for (i = *pos + 1; i < stringlen; i++)
+       {
+         for (j = 0; j < setlen; j++)
+           {
+             if (string[i] == set[j])
+               {
+                 *pos = i + 1;
+                 return;
+               }
+           }
+       }
+
+      if (i == stringlen && j == setlen)
+       {
+         *pos = stringlen + 1;
+         return;
+       }
+    }
+  else
+    {
+      if (*pos < 1 || *pos > (stringlen + 1))
+       runtime_error ("If BACK is present with the value true, the value of "
+                      "POS shall be in the range [1, LEN (STRING) + 1]");
+
+      if (stringlen == 0 || setlen == 0)
+       {
+         *pos = 0;
+         return;
+       }
+
+      for (i = *pos; i != 0; i--)
+       {
+         for (j = 0; j < setlen; j++)
+           {
+             if (string[i - 1] == set[j])
+               {
+                 *pos = i;
+                 return;
+               }
+           }
+       }
+
+      if (i == 0 && j == setlen)
+       {
+         *pos = 0;
+         return;
+       }
+    }
+}

Reply via email to