https://gcc.gnu.org/g:1be1970f97d05a07851cd826132fcf466827ebe5
commit r16-74-g1be1970f97d05a07851cd826132fcf466827ebe5 Author: Andre Vehreschild <ve...@gcc.gnu.org> Date: Fri Mar 14 14:20:18 2025 +0100 Fortran: Unify handling of STAT= and ERRMSG= optional arguments [PR87939] In preparing F2018 Teams handling improvements, unify handling of STAT= and ERRMSG= optional arguments. Handling of stat and errmsg in most teams statements is corrected in the next patch. Implement stat and errmsg for move_alloc () to comply with F2018. PR fortran/87939 gcc/fortran/ChangeLog: * check.cc (gfc_check_move_alloc): Add stat and errmsg to move_alloc. * dump-parse-tree.cc (show_sync_stat): New helper function. (show_code_node): Use show_sync_stat to print stat and errmsg. * gfortran.h (struct sync_stat): New struct to unify stat and errmsg handling. * intrinsic.cc (add_subroutines): Correct signature of move_alloc. * intrinsic.h (gfc_check_move_alloc): Correct signature of check_move_alloc. * match.cc (match_named_arg): Match an optional argument to a statement. (match_stat_errmsg): Match a stat= or errmsg= named argument. (gfc_match_critical): Use match_stat_errmsg to match the named arguments. (gfc_match_sync_team): Same. * resolve.cc (resolve_team_argument): Resolve an expr to have type TEAM_TYPE from iso_fortran_env. (resolve_scalar_variable_as_arg): Resolve an argument as a scalar type. (resolve_sync_stat): Resolve stat and errmsg expressions. (resolve_sync_team): Resolve a sync team statement using sync_stat helper. (resolve_end_team): Same. (resolve_critical): Same. * trans-decl.cc (gfc_build_builtin_function_decls): Correct sync_team signature. * trans-intrinsic.cc (conv_intrinsic_move_alloc): Store stat an errmsg optional arguments in helper struct and use helper to translate. * trans-stmt.cc (trans_exit): Implement DRY pattern for generating an _exit(). (gfc_trans_sync_stat): Translate stat and errmsg contents. (gfc_trans_end_team): Use helper to translate stat and errmsg. (gfc_trans_sync_team): Same. (gfc_trans_critical): Same. * trans-stmt.h (gfc_trans_sync_stat): New function. * trans.cc (gfc_deallocate_with_status): Parameterize check at runtime to allow unallocated (co-)array when freeing a structure. (gfc_deallocate_scalar_with_status): Same and also add errmsg. * trans.h (gfc_deallocate_with_status): Signature changes. (gfc_deallocate_scalar_with_status): Same. libgfortran/ChangeLog: * caf/single.c (_gfortran_caf_lock): Correct stat value, if lock is already locked by current image. (_gfortran_caf_unlock): Correct stat value, if lock is not locked. gcc/testsuite/ChangeLog: * gfortran.dg/coarray_critical_2.f90: New test. * gfortran.dg/coarray_critical_3.f90: New test. * gfortran.dg/team_sync_1.f90: New test. * gfortran.dg/move_alloc_11.f90: New test. Diff: --- gcc/fortran/check.cc | 12 +- gcc/fortran/dump-parse-tree.cc | 23 ++- gcc/fortran/gfortran.h | 9 ++ gcc/fortran/intrinsic.cc | 10 +- gcc/fortran/intrinsic.h | 3 +- gcc/fortran/match.cc | 121 +++++++++++++-- gcc/fortran/resolve.cc | 52 ++++++- gcc/fortran/trans-decl.cc | 8 +- gcc/fortran/trans-intrinsic.cc | 61 ++++++-- gcc/fortran/trans-stmt.cc | 186 +++++++++++++++-------- gcc/fortran/trans-stmt.h | 1 + gcc/fortran/trans.cc | 46 +++--- gcc/fortran/trans.h | 11 +- gcc/testsuite/gfortran.dg/coarray_critical_2.f90 | 30 ++++ gcc/testsuite/gfortran.dg/coarray_critical_3.f90 | 32 ++++ gcc/testsuite/gfortran.dg/move_alloc_11.f90 | 23 +++ gcc/testsuite/gfortran.dg/team_sync_1.f90 | 24 +++ libgfortran/caf/single.c | 8 +- 18 files changed, 532 insertions(+), 128 deletions(-) diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc index 9c66c25e0596..00342787a518 100644 --- a/gcc/fortran/check.cc +++ b/gcc/fortran/check.cc @@ -4683,8 +4683,18 @@ gfc_check_merge_bits (gfc_expr *i, gfc_expr *j, gfc_expr *mask) bool -gfc_check_move_alloc (gfc_expr *from, gfc_expr *to) +gfc_check_move_alloc (gfc_expr *from, gfc_expr *to, gfc_expr *stat, + gfc_expr *errmsg) { + struct sync_stat sync_stat = {stat, errmsg}; + + if ((stat || errmsg) + && !gfc_notify_std (GFC_STD_F2008, "STAT= or ERRMSG= at %L not supported", + &to->where)) + return false; + + gfc_resolve_sync_stat (&sync_stat); + if (!variable_check (from, 0, false)) return false; if (!allocatable_check (from, 0)) diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc index 9501bccb803b..4ace093738ca 100644 --- a/gcc/fortran/dump-parse-tree.cc +++ b/gcc/fortran/dump-parse-tree.cc @@ -2607,6 +2607,20 @@ show_omp_node (int level, gfc_code *c) fprintf (dumpfile, " (%s)", c->ext.omp_clauses->critical_name); } +static void +show_sync_stat (struct sync_stat *sync_stat) +{ + if (sync_stat->stat) + { + fputs (" stat=", dumpfile); + show_expr (sync_stat->stat); + } + if (sync_stat->errmsg) + { + fputs (" errmsg=", dumpfile); + show_expr (sync_stat->errmsg); + } +} /* Show a single code node and everything underneath it if necessary. */ @@ -2761,6 +2775,7 @@ show_code_node (int level, gfc_code *c) case EXEC_END_TEAM: fputs ("END TEAM", dumpfile); + show_sync_stat (&c->ext.sync_stat); break; case EXEC_FORM_TEAM: @@ -2768,7 +2783,9 @@ show_code_node (int level, gfc_code *c) break; case EXEC_SYNC_TEAM: - fputs ("SYNC TEAM", dumpfile); + fputs ("SYNC TEAM ", dumpfile); + show_expr (c->expr1); + show_sync_stat (&c->ext.sync_stat); break; case EXEC_SYNC_ALL: @@ -3048,7 +3065,9 @@ show_code_node (int level, gfc_code *c) break; case EXEC_CRITICAL: - fputs ("CRITICAL\n", dumpfile); + fputs ("CRITICAL", dumpfile); + show_sync_stat (&c->ext.sync_stat); + fputc ('\n', dumpfile); show_code (level + 1, c->block->next); code_indent (level, 0); fputs ("END CRITICAL", dumpfile); diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 5ef70378b1b5..46310a088f26 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3162,6 +3162,11 @@ enum locality_type LOCALITY_NUM }; +struct sync_stat +{ + gfc_expr *stat, *errmsg; +}; + typedef struct gfc_code { gfc_exec_op op; @@ -3197,6 +3202,7 @@ typedef struct gfc_code gfc_omp_variant *omp_variants; bool omp_bool; int stop_code; + struct sync_stat sync_stat; struct { @@ -3207,6 +3213,7 @@ typedef struct gfc_code unsigned arr_spec_from_expr3:1; /* expr3 is not explicit */ unsigned expr3_not_explicit:1; + struct sync_stat sync_stat; } alloc; @@ -3215,6 +3222,7 @@ typedef struct gfc_code gfc_namespace *ns; gfc_association_list *assoc; gfc_case *case_list; + struct sync_stat sync_stat; } block; @@ -3985,6 +3993,7 @@ bool gfc_resolve_index (gfc_expr *, int); bool gfc_resolve_dim_arg (gfc_expr *); bool gfc_resolve_substring (gfc_ref *, bool *); void gfc_resolve_substring_charlen (gfc_expr *); +void gfc_resolve_sync_stat (struct sync_stat *); gfc_expr *gfc_expr_to_initialize (gfc_expr *); bool gfc_type_is_extensible (gfc_symbol *); bool gfc_resolve_intrinsic (gfc_symbol *, locus *); diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc index d2ce74f16eb5..91f16c7f35f9 100644 --- a/gcc/fortran/intrinsic.cc +++ b/gcc/fortran/intrinsic.cc @@ -3835,11 +3835,11 @@ add_subroutines (void) st, BT_INTEGER, di, OPTIONAL, INTENT_OUT, trim_name, BT_LOGICAL, dl, OPTIONAL, INTENT_IN); - add_sym_2s ("move_alloc", GFC_ISYM_MOVE_ALLOC, CLASS_PURE, BT_UNKNOWN, 0, - GFC_STD_F2003, - gfc_check_move_alloc, NULL, NULL, - f, BT_UNKNOWN, 0, REQUIRED, INTENT_INOUT, - t, BT_UNKNOWN, 0, REQUIRED, INTENT_OUT); + add_sym_4s ("move_alloc", GFC_ISYM_MOVE_ALLOC, CLASS_PURE, BT_UNKNOWN, 0, + GFC_STD_F2003, gfc_check_move_alloc, NULL, NULL, f, BT_UNKNOWN, 0, + REQUIRED, INTENT_INOUT, t, BT_UNKNOWN, 0, REQUIRED, INTENT_OUT, + stat, BT_INTEGER, di, OPTIONAL, INTENT_OUT, errmsg, BT_CHARACTER, + dc, OPTIONAL, INTENT_INOUT); add_sym_5s ("mvbits", GFC_ISYM_MVBITS, CLASS_ELEMENTAL, BT_UNKNOWN, 0, GFC_STD_F95, gfc_check_mvbits, NULL, gfc_resolve_mvbits, diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h index fec1c24a0995..70e14c4098b1 100644 --- a/gcc/fortran/intrinsic.h +++ b/gcc/fortran/intrinsic.h @@ -208,7 +208,8 @@ bool gfc_check_fstat_sub (gfc_expr *, gfc_expr *, gfc_expr *); bool gfc_check_gerror (gfc_expr *); bool gfc_check_getarg (gfc_expr *, gfc_expr *); bool gfc_check_getlog (gfc_expr *); -bool gfc_check_move_alloc (gfc_expr *, gfc_expr *); +bool gfc_check_move_alloc (gfc_expr *, gfc_expr *, gfc_expr *stat, + gfc_expr *errmsg); bool gfc_check_mvbits (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); bool gfc_check_random_init (gfc_expr *, gfc_expr *); diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index ec9e5873204a..4d77e094ab9f 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -1814,12 +1814,53 @@ gfc_free_iterator (gfc_iterator *iter, int flag) free (iter); } +static match +match_named_arg (const char *pat, const char *name, gfc_expr **e, + gfc_statement st_code) +{ + match m; + gfc_expr *tmp; + + m = gfc_match (pat, &tmp); + if (m == MATCH_ERROR) + { + gfc_syntax_error (st_code); + return m; + } + if (m == MATCH_YES) + { + if (*e) + { + gfc_error ("Duplicate %s attribute in %C", name); + gfc_free_expr (tmp); + return MATCH_ERROR; + } + *e = tmp; + + return MATCH_YES; + } + return MATCH_NO; +} + +static match +match_stat_errmsg (struct sync_stat *sync_stat, gfc_statement st_code) +{ + match m; + + m = match_named_arg (" stat = %v", "STAT", &sync_stat->stat, st_code); + if (m != MATCH_NO) + return m; + + m = match_named_arg (" errmsg = %v", "ERRMSG", &sync_stat->errmsg, st_code); + return m; +} /* Match a CRITICAL statement. */ match gfc_match_critical (void) { gfc_st_label *label = NULL; + match m; if (gfc_match_label () == MATCH_ERROR) return MATCH_ERROR; @@ -1830,12 +1871,29 @@ gfc_match_critical (void) if (gfc_match_st_label (&label) == MATCH_ERROR) return MATCH_ERROR; - if (gfc_match_eos () != MATCH_YES) + if (gfc_match_eos () == MATCH_YES) + goto done; + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + for (;;) { - gfc_syntax_error (ST_CRITICAL); - return MATCH_ERROR; + m = match_stat_errmsg (&new_st.ext.sync_stat, ST_CRITICAL); + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (',') == MATCH_YES) + continue; + + break; } + if (gfc_match (" )%t") != MATCH_YES) + goto syntax; + +done: + if (gfc_pure (NULL)) { gfc_error ("Image control statement CRITICAL at %C in PURE procedure"); @@ -1856,9 +1914,9 @@ gfc_match_critical (void) if (flag_coarray == GFC_FCOARRAY_NONE) { - gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to " - "enable"); - return MATCH_ERROR; + gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to " + "enable"); + return MATCH_ERROR; } if (gfc_find_state (COMP_CRITICAL)) @@ -1869,13 +1927,21 @@ gfc_match_critical (void) new_st.op = EXEC_CRITICAL; - if (label != NULL - && !gfc_reference_st_label (label, ST_LABEL_TARGET)) - return MATCH_ERROR; + if (label != NULL && !gfc_reference_st_label (label, ST_LABEL_TARGET)) + goto cleanup; return MATCH_YES; -} +syntax: + gfc_syntax_error (ST_CRITICAL); + +cleanup: + gfc_free_expr (new_st.ext.sync_stat.stat); + gfc_free_expr (new_st.ext.sync_stat.errmsg); + new_st.ext.sync_stat = {NULL, NULL}; + + return MATCH_ERROR; +} /* Match a BLOCK statement. */ @@ -3941,7 +4007,7 @@ match gfc_match_sync_team (void) { match m; - gfc_expr *team; + gfc_expr *team = NULL; if (!gfc_notify_std (GFC_STD_F2018, "SYNC TEAM statement at %C")) return MATCH_ERROR; @@ -3954,10 +4020,34 @@ gfc_match_sync_team (void) if (gfc_match ("%e", &team) != MATCH_YES) goto syntax; - m = gfc_match_char (')'); + m = gfc_match_char (','); + if (m == MATCH_ERROR) + goto syntax; if (m == MATCH_NO) + { + m = gfc_match_char (')'); + if (m == MATCH_YES) + goto done; + goto syntax; + } + + for (;;) + { + m = match_stat_errmsg (&new_st.ext.sync_stat, ST_SYNC_TEAM); + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (',') == MATCH_YES) + continue; + + break; + } + + if (gfc_match (" )%t") != MATCH_YES) goto syntax; +done: + new_st.expr1 = team; return MATCH_YES; @@ -3965,6 +4055,13 @@ gfc_match_sync_team (void) syntax: gfc_syntax_error (ST_SYNC_TEAM); +cleanup: + gfc_free_expr (new_st.ext.sync_stat.stat); + gfc_free_expr (new_st.ext.sync_stat.errmsg); + new_st.ext.sync_stat = {NULL, NULL}; + + gfc_free_expr (team); + return MATCH_ERROR; } diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index f03708efef78..e9053b49392b 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -11484,6 +11484,53 @@ resolve_lock_unlock_event (gfc_code *code) } } +static void +resolve_team_argument (gfc_expr *team) +{ + gfc_resolve_expr (team); + if (team->rank != 0 || team->ts.type != BT_DERIVED + || team->ts.u.derived->from_intmod != INTMOD_ISO_FORTRAN_ENV + || team->ts.u.derived->intmod_sym_id != ISOFORTRAN_TEAM_TYPE) + { + gfc_error ("TEAM argument at %L must be a scalar expression " + "of type TEAM_TYPE from the intrinsic module ISO_FORTRAN_ENV", + &team->where); + } +} + +static void +resolve_scalar_variable_as_arg (const char *name, bt exp_type, int exp_kind, + gfc_expr *e) +{ + gfc_resolve_expr (e); + if (e + && (e->ts.type != exp_type || e->ts.kind < exp_kind || e->rank != 0 + || e->expr_type != EXPR_VARIABLE)) + gfc_error ("%s argument at %L must be a scalar %s variable of at least " + "kind %d", name, &e->where, gfc_basic_typename (exp_type), + exp_kind); +} + +void +gfc_resolve_sync_stat (struct sync_stat *sync_stat) +{ + resolve_scalar_variable_as_arg ("STAT=", BT_INTEGER, 2, sync_stat->stat); + resolve_scalar_variable_as_arg ("ERRMSG=", BT_CHARACTER, + gfc_default_character_kind, + sync_stat->errmsg); +} +static void +resolve_sync_team (gfc_code *code) +{ + resolve_team_argument (code->expr1); + gfc_resolve_sync_stat (&code->ext.sync_stat); +} + +static void +resolve_end_team (gfc_code *code) +{ + gfc_resolve_sync_stat (&code->ext.sync_stat); +} static void resolve_critical (gfc_code *code) @@ -11493,6 +11540,8 @@ resolve_critical (gfc_code *code) char name[GFC_MAX_SYMBOL_LEN]; static int serial = 0; + gfc_resolve_sync_stat (&code->ext.sync_stat); + if (flag_coarray != GFC_FCOARRAY_LIB) return; @@ -13493,10 +13542,11 @@ start: break; case EXEC_END_TEAM: + resolve_end_team (code); break; case EXEC_SYNC_TEAM: - check_team (code->expr1, "SYNC TEAM"); + resolve_sync_team (code); break; case EXEC_ENTRY: diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index ddc4960b6fff..5e5311e4f0c2 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -4222,11 +4222,9 @@ gfc_build_builtin_function_decls (void) get_identifier (PREFIX("caf_get_team")), void_type_node, 1, integer_type_node); - gfor_fndecl_caf_sync_team - = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("caf_sync_team")), ". r . ", - void_type_node, 2, ppvoid_type_node, - integer_type_node); + gfor_fndecl_caf_sync_team = gfc_build_library_function_decl_with_spec ( + get_identifier (PREFIX ("caf_sync_team")), ". r w w w ", void_type_node, + 4, pvoid_type_node, pint_type, pchar_type_node, size_type_node); gfor_fndecl_caf_team_number = gfc_build_library_function_decl_with_spec ( diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc index 6ffc3e0261e5..16ade8d4d552 100644 --- a/gcc/fortran/trans-intrinsic.cc +++ b/gcc/fortran/trans-intrinsic.cc @@ -12970,6 +12970,9 @@ gfc_conv_intrinsic_mvbits (gfc_se *se, gfc_actual_arglist *actual_args, void_type_node, to, se->expr); } +/* Comes from trans-stmt.cc, but we don't want the whole header included. */ +extern void gfc_trans_sync_stat (struct sync_stat *sync_stat, gfc_se *se, + tree *stat, tree *errmsg, tree *errmsg_len); static tree conv_intrinsic_move_alloc (gfc_code *code) @@ -12977,17 +12980,37 @@ conv_intrinsic_move_alloc (gfc_code *code) stmtblock_t block; gfc_expr *from_expr, *to_expr; gfc_se from_se, to_se; - tree tmp, to_tree, from_tree; + tree tmp, to_tree, from_tree, stat, errmsg, errmsg_len, fin_label = NULL_TREE; bool coarray, from_is_class, from_is_scalar; + gfc_actual_arglist *arg = code->ext.actual; + sync_stat tmp_sync_stat = {nullptr, nullptr}; gfc_start_block (&block); - from_expr = code->ext.actual->expr; - to_expr = code->ext.actual->next->expr; + from_expr = arg->expr; + arg = arg->next; + to_expr = arg->expr; + arg = arg->next; + + while (arg) + { + if (arg->expr) + { + if (!strcmp ("stat", arg->name)) + tmp_sync_stat.stat = arg->expr; + else if (!strcmp ("errmsg", arg->name)) + tmp_sync_stat.errmsg = arg->expr; + } + arg = arg->next; + } gfc_init_se (&from_se, NULL); gfc_init_se (&to_se, NULL); + gfc_trans_sync_stat (&tmp_sync_stat, &from_se, &stat, &errmsg, &errmsg_len); + if (stat != null_pointer_node) + fin_label = gfc_build_label_decl (NULL_TREE); + gcc_assert (from_expr->ts.type != BT_CLASS || to_expr->ts.type == BT_CLASS); coarray = from_expr->corank != 0; @@ -13030,9 +13053,10 @@ conv_intrinsic_move_alloc (gfc_code *code) /* Deallocate "to". */ if (to_expr->rank == 0) { - tmp - = gfc_deallocate_scalar_with_status (to_tree, NULL_TREE, NULL_TREE, - true, to_expr, to_expr->ts); + tmp = gfc_deallocate_scalar_with_status (to_tree, stat, fin_label, + true, to_expr, to_expr->ts, + NULL_TREE, false, true, + errmsg, errmsg_len); gfc_add_expr_to_block (&block, tmp); } @@ -13105,9 +13129,12 @@ conv_intrinsic_move_alloc (gfc_code *code) { tree cond; - tmp = gfc_deallocate_with_status (to_se.expr, NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE, true, to_expr, - GFC_CAF_COARRAY_DEALLOCATE_ONLY); + tmp = gfc_deallocate_with_status (to_se.expr, stat, errmsg, errmsg_len, + fin_label, true, to_expr, + GFC_CAF_COARRAY_DEALLOCATE_ONLY, + NULL_TREE, NULL_TREE, + gfc_conv_descriptor_token (to_se.expr), + true); gfc_add_expr_to_block (&block, tmp); tmp = gfc_conv_descriptor_data_get (to_se.expr); @@ -13133,9 +13160,10 @@ conv_intrinsic_move_alloc (gfc_code *code) gfc_add_expr_to_block (&block, tmp); } - tmp = gfc_deallocate_with_status (to_se.expr, NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE, true, to_expr, - GFC_CAF_COARRAY_NOCOARRAY); + tmp = gfc_deallocate_with_status (to_se.expr, stat, errmsg, errmsg_len, + fin_label, true, to_expr, + GFC_CAF_COARRAY_NOCOARRAY, NULL_TREE, + NULL_TREE, NULL_TREE, true); gfc_add_expr_to_block (&block, tmp); } @@ -13147,6 +13175,13 @@ conv_intrinsic_move_alloc (gfc_code *code) gfc_add_modify_loc (input_location, &block, tmp, fold_convert (TREE_TYPE (tmp), null_pointer_node)); + if (coarray && flag_coarray == GFC_FCOARRAY_LIB) + { + /* Copy the array descriptor data has overwritten the to-token and cleared + from.data. Now also clear the from.token. */ + gfc_add_modify (&block, gfc_conv_descriptor_token (from_se.expr), + null_pointer_node); + } if (to_expr->ts.type == BT_CHARACTER && to_expr->ts.deferred) { @@ -13157,6 +13192,8 @@ conv_intrinsic_move_alloc (gfc_code *code) gfc_add_modify_loc (input_location, &block, from_se.string_length, build_int_cst (TREE_TYPE (from_se.string_length), 0)); } + if (fin_label) + gfc_add_expr_to_block (&block, build1_v (LABEL_EXPR, fin_label)); return gfc_finish_block (&block); } diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc index 37f8acaea3f6..e79209e94aa0 100644 --- a/gcc/fortran/trans-stmt.cc +++ b/gcc/fortran/trans-stmt.cc @@ -721,6 +721,15 @@ gfc_trans_stop (gfc_code *code, bool error_stop) return gfc_finish_block (&se.pre); } +tree +trans_exit () +{ + const char *name = gfc_get_string (PREFIX ("exit_i%d"), 4); + gfc_symbol *exsym = gfc_get_intrinsic_sub_symbol (name); + tree tmp = gfc_get_symbol_decl (exsym); + return build_call_expr_loc (input_location, tmp, 1, integer_zero_node); +} + /* Translate the FAIL IMAGE statement. */ tree @@ -730,11 +739,49 @@ gfc_trans_fail_image (gfc_code *code ATTRIBUTE_UNUSED) return build_call_expr_loc (input_location, gfor_fndecl_caf_fail_image, 0); else + return trans_exit (); +} + +void +gfc_trans_sync_stat (struct sync_stat *sync_stat, gfc_se *se, tree *stat, + tree *errmsg, tree *errmsg_len) +{ + gfc_se argse; + + if (sync_stat->stat) { - const char *name = gfc_get_string (PREFIX ("exit_i%d"), 4); - gfc_symbol *exsym = gfc_get_intrinsic_sub_symbol (name); - tree tmp = gfc_get_symbol_decl (exsym); - return build_call_expr_loc (input_location, tmp, 1, integer_zero_node); + gfc_init_se (&argse, NULL); + gfc_conv_expr (&argse, sync_stat->stat); + gfc_add_block_to_block (&se->pre, &argse.pre); + + if (TREE_TYPE (argse.expr) != integer_type_node) + { + tree tstat = gfc_create_var (integer_type_node, "stat"); + TREE_THIS_VOLATILE (tstat) = 1; + gfc_add_modify (&se->pre, tstat, + fold_convert (integer_type_node, argse.expr)); + gfc_add_modify (&se->post, argse.expr, + fold_convert (TREE_TYPE (argse.expr), tstat)); + *stat = build_fold_addr_expr (tstat); + } + else + *stat = build_fold_addr_expr (argse.expr); + } + else + *stat = null_pointer_node; + + if (sync_stat->errmsg) + { + gfc_init_se (&argse, NULL); + gfc_conv_expr_reference (&argse, sync_stat->errmsg); + gfc_add_block_to_block (&se->pre, &argse.pre); + *errmsg = argse.expr; + *errmsg_len = fold_convert (size_type_node, argse.string_length); + } + else + { + *errmsg = null_pointer_node; + *errmsg_len = build_zero_cst (size_type_node); } } @@ -812,21 +859,27 @@ gfc_trans_change_team (gfc_code *code) /* Translate the END TEAM statement. */ tree -gfc_trans_end_team (gfc_code *code ATTRIBUTE_UNUSED) +gfc_trans_end_team (gfc_code *code) { if (flag_coarray == GFC_FCOARRAY_LIB) { - return build_call_expr_loc (input_location, - gfor_fndecl_caf_end_team, 1, - build_int_cst (pchar_type_node, 0)); + gfc_se se; + tree stat, errmsg, errmsg_len, tmp; + + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + gfc_trans_sync_stat (&code->ext.sync_stat, &se, &stat, &errmsg, + &errmsg_len); + + tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_end_team, 3, + stat, errmsg, errmsg_len); + gfc_add_expr_to_block (&se.pre, tmp); + gfc_add_block_to_block (&se.pre, &se.post); + return gfc_finish_block (&se.pre); } else - { - const char *name = gfc_get_string (PREFIX ("exit_i%d"), 4); - gfc_symbol *exsym = gfc_get_intrinsic_sub_symbol (name); - tree tmp = gfc_get_symbol_decl (exsym); - return build_call_expr_loc (input_location, tmp, 1, integer_zero_node); - } + return trans_exit (); } /* Translate the SYNC TEAM statement. */ @@ -836,28 +889,25 @@ gfc_trans_sync_team (gfc_code *code) { if (flag_coarray == GFC_FCOARRAY_LIB) { - gfc_se argse; - tree team_type, tmp; + gfc_se se; + tree team_type, stat, errmsg, errmsg_len, tmp; - gfc_init_se (&argse, NULL); - gfc_conv_expr_val (&argse, code->expr1); - team_type = gfc_build_addr_expr (ppvoid_type_node, argse.expr); + gfc_init_se (&se, NULL); - tmp = build_call_expr_loc (input_location, - gfor_fndecl_caf_sync_team, 2, - team_type, - integer_zero_node); - gfc_add_expr_to_block (&argse.pre, tmp); - gfc_add_block_to_block (&argse.pre, &argse.post); - return gfc_finish_block (&argse.pre); + gfc_conv_expr_val (&se, code->expr1); + team_type = se.expr; + + gfc_trans_sync_stat (&code->ext.sync_stat, &se, &stat, &errmsg, + &errmsg_len); + + tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_sync_team, 4, + team_type, stat, errmsg, errmsg_len); + gfc_add_expr_to_block (&se.pre, tmp); + gfc_add_block_to_block (&se.pre, &se.post); + return gfc_finish_block (&se.pre); } else - { - const char *name = gfc_get_string (PREFIX ("exit_i%d"), 4); - gfc_symbol *exsym = gfc_get_intrinsic_sub_symbol (name); - tree tmp = gfc_get_symbol_decl (exsym); - return build_call_expr_loc (input_location, tmp, 1, integer_zero_node); - } + return trans_exit (); } tree @@ -1609,35 +1659,41 @@ gfc_trans_arithmetic_if (gfc_code * code) /* Translate a CRITICAL block. */ + tree gfc_trans_critical (gfc_code *code) -{ - stmtblock_t block; - tree tmp, token = NULL_TREE; + { + stmtblock_t block; + tree tmp, token = NULL_TREE; + tree stat = NULL_TREE, errmsg, errmsg_len; - gfc_start_block (&block); + gfc_start_block (&block); - if (flag_coarray == GFC_FCOARRAY_LIB) - { - tree zero_size = build_zero_cst (size_type_node); - token = gfc_get_symbol_decl (code->resolved_sym); - token = GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE (token)); - tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_lock, 7, - token, zero_size, integer_one_node, - null_pointer_node, null_pointer_node, - null_pointer_node, zero_size); - gfc_add_expr_to_block (&block, tmp); + if (flag_coarray == GFC_FCOARRAY_LIB) + { + gfc_se se; - /* It guarantees memory consistency within the same segment */ - tmp = gfc_build_string_const (strlen ("memory")+1, "memory"), - tmp = build5_loc (input_location, ASM_EXPR, void_type_node, - gfc_build_string_const (1, ""), - NULL_TREE, NULL_TREE, - tree_cons (NULL_TREE, tmp, NULL_TREE), - NULL_TREE); - ASM_VOLATILE_P (tmp) = 1; + gfc_init_se (&se, NULL); + gfc_trans_sync_stat (&code->ext.sync_stat, &se, &stat, &errmsg, + &errmsg_len); + gfc_add_block_to_block (&block, &se.pre); - gfc_add_expr_to_block (&block, tmp); + token = gfc_get_symbol_decl (code->resolved_sym); + token = GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE (token)); + tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_lock, 7, + token, integer_zero_node, integer_one_node, + null_pointer_node, stat, errmsg, errmsg_len); + gfc_add_expr_to_block (&block, tmp); + gfc_add_block_to_block (&block, &se.post); + + /* It guarantees memory consistency within the same segment. */ + tmp = gfc_build_string_const (strlen ("memory") + 1, "memory"), + tmp = build5_loc (input_location, ASM_EXPR, void_type_node, + gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE, + tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE); + ASM_VOLATILE_P (tmp) = 1; + + gfc_add_expr_to_block (&block, tmp); } tmp = gfc_trans_code (code->block->next); @@ -1645,11 +1701,19 @@ gfc_trans_critical (gfc_code *code) if (flag_coarray == GFC_FCOARRAY_LIB) { - tree zero_size = build_zero_cst (size_type_node); - tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_unlock, 6, - token, zero_size, integer_one_node, - null_pointer_node, null_pointer_node, - zero_size); + /* END CRITICAL does not accept STAT or ERRMSG arguments. + * If STAT= is specified for CRITICAL, pass a stat argument to + * _gfortran_caf_lock_unlock to prevent termination in the event of an + * error, but ignore any value assigned to it. + */ + tmp = build_call_expr_loc ( + input_location, gfor_fndecl_caf_unlock, 6, token, integer_zero_node, + integer_one_node, + stat != NULL_TREE + ? gfc_build_addr_expr (NULL, + gfc_create_var (integer_type_node, "stat")) + : null_pointer_node, + null_pointer_node, integer_zero_node); gfc_add_expr_to_block (&block, tmp); /* It guarantees memory consistency within the same segment */ @@ -1981,7 +2045,7 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) GFC_DECL_PTR_ARRAY_P (sym->backend_decl) = 1; } - if (sym->attr.codimension && !sym->attr.dimension) + if (sym->attr.codimension) se.want_coarray = 1; gfc_conv_expr_descriptor (&se, e); diff --git a/gcc/fortran/trans-stmt.h b/gcc/fortran/trans-stmt.h index 67b1970776b9..8fbcdcba1f98 100644 --- a/gcc/fortran/trans-stmt.h +++ b/gcc/fortran/trans-stmt.h @@ -58,6 +58,7 @@ tree gfc_trans_sync (gfc_code *, gfc_exec_op); tree gfc_trans_lock_unlock (gfc_code *, gfc_exec_op); tree gfc_trans_event_post_wait (gfc_code *, gfc_exec_op); tree gfc_trans_fail_image (gfc_code *); +void gfc_trans_sync_stat (struct sync_stat *, gfc_se *, tree *, tree *, tree *); tree gfc_trans_forall (gfc_code *); tree gfc_trans_form_team (gfc_code *); tree gfc_trans_change_team (gfc_code *); diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc index b03dcc1fb1a4..fdeb1e89a765 100644 --- a/gcc/fortran/trans.cc +++ b/gcc/fortran/trans.cc @@ -1795,11 +1795,11 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, analyzed and set by this routine, and -2 to indicate that a non-coarray is to be deallocated. */ tree -gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, - tree errlen, tree label_finish, - bool can_fail, gfc_expr* expr, +gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, tree errlen, + tree label_finish, bool can_fail, gfc_expr *expr, int coarray_dealloc_mode, tree class_container, - tree add_when_allocated, tree caf_token) + tree add_when_allocated, tree caf_token, + bool unalloc_ok) { stmtblock_t null, non_null; tree cond, tmp, error; @@ -1891,7 +1891,7 @@ gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), - build_int_cst (status_type, 1)); + build_int_cst (status_type, unalloc_ok ? 0 : 1)); error = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2, tmp, error); } @@ -1975,10 +1975,10 @@ gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, token = gfc_build_addr_expr (NULL_TREE, token); gcc_assert (caf_dereg_type > GFC_CAF_COARRAY_ANALYZE); - tmp = build_call_expr_loc (input_location, - gfor_fndecl_caf_deregister, 5, - token, build_int_cst (integer_type_node, - caf_dereg_type), + tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_deregister, 5, + token, + build_int_cst (integer_type_node, + caf_dereg_type), pstat, errmsg, errlen); gfc_add_expr_to_block (&non_null, tmp); @@ -1990,7 +1990,7 @@ gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, ASM_VOLATILE_P (tmp) = 1; gfc_add_expr_to_block (&non_null, tmp); - if (status != NULL_TREE) + if (status != NULL_TREE && !integer_zerop (status)) { tree stat = build_fold_indirect_ref_loc (input_location, status); tree nullify = fold_build2_loc (input_location, MODIFY_EXPR, @@ -2024,9 +2024,10 @@ gfc_deallocate_with_status (tree pointer, tree status, tree errmsg, tree gfc_deallocate_scalar_with_status (tree pointer, tree status, tree label_finish, - bool can_fail, gfc_expr* expr, + bool can_fail, gfc_expr *expr, gfc_typespec ts, tree class_container, - bool coarray) + bool coarray, bool unalloc_ok, tree errmsg, + tree errmsg_len) { stmtblock_t null, non_null; tree cond, tmp, error; @@ -2069,7 +2070,7 @@ gfc_deallocate_scalar_with_status (tree pointer, tree status, tree label_finish, tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, fold_build1_loc (input_location, INDIRECT_REF, status_type, status), - build_int_cst (status_type, 1)); + build_int_cst (status_type, unalloc_ok ? 0 : 1)); error = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2, tmp, error); } @@ -2134,7 +2135,8 @@ gfc_deallocate_scalar_with_status (tree pointer, tree status, tree label_finish, else { tree token; - tree pstat = null_pointer_node; + tree pstat = null_pointer_node, perrmsg = null_pointer_node, + perrlen = size_zero_node; gfc_se se; gfc_init_se (&se, NULL); @@ -2147,11 +2149,17 @@ gfc_deallocate_scalar_with_status (tree pointer, tree status, tree label_finish, pstat = status; } - tmp = build_call_expr_loc (input_location, - gfor_fndecl_caf_deregister, 5, - token, build_int_cst (integer_type_node, - caf_dereg_type), - pstat, null_pointer_node, integer_zero_node); + if (errmsg != NULL_TREE) + { + perrmsg = errmsg; + perrlen = errmsg_len; + } + + tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_deregister, 5, + token, + build_int_cst (integer_type_node, + caf_dereg_type), + pstat, perrmsg, perrlen); gfc_add_expr_to_block (&non_null, tmp); /* It guarantees memory consistency within the same segment. */ diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index ae7be9f81a8c..13bb04af1d2c 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -774,12 +774,13 @@ void gfc_allocate_using_malloc (stmtblock_t *, tree, tree, tree, tree = NULL_TREE); /* Generate code to deallocate an array. */ -tree gfc_deallocate_with_status (tree, tree, tree, tree, tree, bool, - gfc_expr *, int, tree = NULL_TREE, - tree a = NULL_TREE, tree c = NULL_TREE); -tree gfc_deallocate_scalar_with_status (tree, tree, tree, bool, gfc_expr*, +tree gfc_deallocate_with_status (tree, tree, tree, tree, tree, bool, gfc_expr *, + int, tree = NULL_TREE, tree a = NULL_TREE, + tree c = NULL_TREE, bool u = false); +tree gfc_deallocate_scalar_with_status (tree, tree, tree, bool, gfc_expr *, gfc_typespec, tree = NULL_TREE, - bool c = false); + bool c = false, bool u = false, + tree = NULL_TREE, tree = NULL_TREE); /* Generate code to call realloc(). */ tree gfc_call_realloc (stmtblock_t *, tree, tree); diff --git a/gcc/testsuite/gfortran.dg/coarray_critical_2.f90 b/gcc/testsuite/gfortran.dg/coarray_critical_2.f90 new file mode 100644 index 000000000000..702611c35ab4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/coarray_critical_2.f90 @@ -0,0 +1,30 @@ +!{ dg-do compile } +!{ dg-additional-options "-fcoarray=lib" } + +! Test critical syntax errors with stat= and errmsg= specifiers + + implicit none + integer :: istat + character(len=30) :: err + integer(kind=1) :: too_small_stat + + critical (stat=err) !{ dg-error "must be a scalar INTEGER" } + continue + end critical + + critical (stat=istat, stat=istat) !{ dg-error "Duplicate STAT" } + continue + end critical !{ dg-error "Expecting END PROGRAM" } + + critical (stat=istat, errmsg=istat) !{ dg-error "must be a scalar CHARACTER variable" } + continue + end critical + + critical (stat=istat, errmsg=err, errmsg=err) !{ dg-error "Duplicate ERRMSG" } + continue + end critical !{ dg-error "Expecting END PROGRAM" } + + critical (stat=too_small_stat) !{ dg-error "scalar INTEGER variable of at least kind 2" } + continue + end critical +end diff --git a/gcc/testsuite/gfortran.dg/coarray_critical_3.f90 b/gcc/testsuite/gfortran.dg/coarray_critical_3.f90 new file mode 100644 index 000000000000..cd609bd249dd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/coarray_critical_3.f90 @@ -0,0 +1,32 @@ +! { dg-do run } +! { dg-options "-fcoarray=lib -fdump-tree-original -lcaf_single" } +! { dg-additional-options "-latomic" { target libatomic_available } } + +! PR 87939 +! Test critical construct with stat= and errmsg= specifiers +! + use, intrinsic :: iso_fortran_env, only: int16 + implicit none + integer :: istat = 42 + integer(kind=int16) :: istat16 = 42 + character(len=30) :: err = 'unchanged' + integer :: fail = 0 + + critical (stat=istat, errmsg=err) + if (istat /= 0) fail = 1 + if (trim(err) /= 'unchanged') fail = 2 + end critical + + if (fail /= 0) stop fail + + critical (stat=istat16, errmsg=err) + if (istat16 /= 0) fail = 3 + if (trim(err) /= 'unchanged') fail = 4 + end critical + + if (fail /= 0) stop fail +end + +! { dg-final { scan-tree-dump "_gfortran_caf_lock \\(caf_token\\.\[0-9\]+, 0, 1, 0B, &istat, &err, 30\\);" "original" } } +! { dg-final { scan-tree-dump "_gfortran_caf_lock \\(caf_token\\.\[0-9\]+, 0, 1, 0B, &stat\\.\[0-9\]+, &err, 30\\);" "original" } } +! { dg-final { scan-tree-dump-times "_gfortran_caf_unlock \\(caf_token\\.\[0-9\]+, 0, 1, &stat\\.\[0-9\]+, 0B, 0\\);" 2 "original" } } diff --git a/gcc/testsuite/gfortran.dg/move_alloc_11.f90 b/gcc/testsuite/gfortran.dg/move_alloc_11.f90 new file mode 100644 index 000000000000..d33e0ce7ed51 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/move_alloc_11.f90 @@ -0,0 +1,23 @@ +!{ dg-do compile } + +! General error checking for move_alloc parameter list. + +integer, allocatable :: i, o +integer :: st, s2 +character(30) :: e, e2 + + call move_alloc(i, o, STAT=st) + call move_alloc(i, o, STAT=st, STAT=s2) !{ dg-error "Keyword 'stat' at \\(1\\) has already appeared in the current argument list" } + call move_alloc(i, o, STAT=e) !{ dg-error "STAT= argument at \\(1\\) must be a scalar INTEGER variable of at least kind 2" } + call move_alloc(i, o, STAT=[st, s2]) !{ dg-error "STAT= argument at \\(1\\) must be a scalar INTEGER variable of at least kind 2" } + call move_alloc(i, o, STAT=.TRUE.) !{ dg-error "STAT= argument at \\(1\\) must be a scalar INTEGER variable of at least kind 2" } + + call move_alloc(i, o, STAT=st, ERRMSG=e) + call move_alloc(i, o, ERRMSG=e) + call move_alloc(i, o, ERRMSG=e, ERRMSG=e2) !{ dg-error "Keyword 'errmsg' at \\(1\\) has already appeared in the current argument list" } + call move_alloc(i, o, ERRMSG=st) !{ dg-error "ERRMSG= argument at \\(1\\) must be a scalar CHARACTER variable of at least kind 1" } + call move_alloc(i, o, ERRMSG=.TRUE.) !{ dg-error "ERRMSG= argument at \\(1\\) must be a scalar CHARACTER variable of at least kind 1" } + + +end + diff --git a/gcc/testsuite/gfortran.dg/team_sync_1.f90 b/gcc/testsuite/gfortran.dg/team_sync_1.f90 new file mode 100644 index 000000000000..5b28651b8be0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/team_sync_1.f90 @@ -0,0 +1,24 @@ +!{ dg-do compile } +!{ dg-additional-options "-fcoarray=lib" } + +! PR 87939 +! Test sync team syntax errors + + use iso_fortran_env, only : team_type + implicit none + integer :: istat + character(len=30) :: err + type(team_type) :: team + + form team (mod(this_image(),2)+1, team) + + change team (team) + sync team ! { dg-error "Syntax error in SYNC TEAM statement" } + sync team (err) ! { dg-error "must be a scalar expression of type TEAM_TYPE" } + sync team (team, istat) ! { dg-error "Syntax error in SYNC TEAM statement" } + sync team (team, stat=err) ! { dg-error "must be a scalar INTEGER" } + sync team (team, stat=istat, stat=istat) ! { dg-error "Duplicate STAT" } + sync team (team, stat=istat, errmsg=istat) ! { dg-error "must be a scalar CHARACTER variable" } + sync team (team, stat=istat, errmsg=err, errmsg=err) ! { dg-error "Duplicate ERRMSG" } + end team +end diff --git a/libgfortran/caf/single.c b/libgfortran/caf/single.c index 9c1c0c1bc8ca..1d7af6b89722 100644 --- a/libgfortran/caf/single.c +++ b/libgfortran/caf/single.c @@ -859,14 +859,14 @@ _gfortran_caf_lock (caf_token_t token, size_t index, { *acquired_lock = (int) false; if (stat) - *stat = 0; - return; + *stat = GFC_STAT_LOCKED; + return; } if (stat) { - *stat = 1; + *stat = GFC_STAT_LOCKED; if (errmsg_len > 0) { size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len @@ -899,7 +899,7 @@ _gfortran_caf_unlock (caf_token_t token, size_t index, if (stat) { - *stat = 1; + *stat = GFC_STAT_UNLOCKED; if (errmsg_len > 0) { size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len