aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog376
-rw-r--r--gcc/fortran/arith.cc35
-rw-r--r--gcc/fortran/array.cc110
-rw-r--r--gcc/fortran/class.cc25
-rw-r--r--gcc/fortran/decl.cc170
-rw-r--r--gcc/fortran/dump-parse-tree.cc18
-rw-r--r--gcc/fortran/expr.cc11
-rw-r--r--gcc/fortran/frontend-passes.cc1
-rw-r--r--gcc/fortran/gfortran.h23
-rw-r--r--gcc/fortran/gfortran.texi292
-rw-r--r--gcc/fortran/intrinsic.texi3
-rw-r--r--gcc/fortran/lang.opt.urls7
-rw-r--r--gcc/fortran/match.cc95
-rw-r--r--gcc/fortran/match.h1
-rw-r--r--gcc/fortran/module.cc34
-rw-r--r--gcc/fortran/openmp.cc411
-rw-r--r--gcc/fortran/parse.cc86
-rw-r--r--gcc/fortran/parse.h3
-rw-r--r--gcc/fortran/primary.cc100
-rw-r--r--gcc/fortran/resolve.cc350
-rw-r--r--gcc/fortran/symbol.cc159
-rw-r--r--gcc/fortran/trans-array.cc199
-rw-r--r--gcc/fortran/trans-common.cc31
-rw-r--r--gcc/fortran/trans-decl.cc77
-rw-r--r--gcc/fortran/trans-expr.cc71
-rw-r--r--gcc/fortran/trans-intrinsic.cc18
-rw-r--r--gcc/fortran/trans-openmp.cc35
-rw-r--r--gcc/fortran/trans.h6
28 files changed, 2321 insertions, 426 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 5501bca..4fd2183 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,379 @@
+2025-12-08 Harald Anlauf <anlauf@gmx.de>
+ Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/123025
+ * decl.cc (match_char_length): Add a check for the
+ obsolete '*' style of character declarations in the
+ alternate branch of checking so we dont miss two
+ use cases:
+
+2025-12-06 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122693
+ * array.cc (gfc_match_array_constructor): Stash and restore
+ gfc_current_ns after the call to 'gfc_match_type_spec'.
+
+2025-12-06 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122670
+ * decl.cc (gfc_get_pdt_instance): Ensure that, in an interface
+ body, PDT instances imported implicitly if the template has
+ been explicitly imported.
+ * module.cc (read_module): If a PDT template appears in a use
+ only statement, implicitly add the instances as well.
+
+2025-12-06 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122669
+ * resolve.cc (resolve_allocate_deallocate): Mold expressions
+ with an array reference and a constant size must be resolved
+ for each allocate object.
+
+2025-12-06 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122578
+ * primary.cc (gfc_match_varspec): Try to resolve a typebound
+ generic procedure selector expression to provide the associate
+ name with a type. Also, resolve component calls. In both cases,
+ make a copy of the selector expression to guard against changes
+ made by gfc_resolve_expr.
+
+2025-12-05 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/122977
+ * expr.cc (gfc_is_simply_contiguous): For an associate variable
+ check whether the associate target is contiguous.
+ * resolve.cc (resolve_symbol): Skip array type check for an
+ associate variable when the target has the contiguous attribute.
+
+2025-12-05 Tobias Burnus <tburnus@baylibre.com>
+
+ * openmp.cc (resolve_omp_clauses): Permit zero with
+ DYN_GROUPPRIVATE clause.
+ * trans-openmp.cc (fallback): Generate TREE code
+ for DYN_GROUPPRIVATE and remove 'sorry'.
+
+2025-12-03 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/103371
+ * decl.cc (gfc_get_pdt_instance): Remove the requirement that
+ PDT components be of the same type as the enclosing type. Apply
+ initializers other than the default to PDT components.
+ * primary.cc (gfc_match_rvalue): Make combination of the two
+ actual_arglists conditional on 'type_spec_list' having been
+ seen as well together with applying component names to all the
+ arguments.
+ * trans-decl.cc (gfc_init_default_dt): Add 'pdt_ok' to the args
+ and use it to signal that a PDT can be default initialized.
+ (gfc_init_default_pdt): New function to check that a pdt is OK
+ for default intialization before calling gfc_init_default_dt.
+ (gfc_trans_deferred_vars): Use gfc_init_default_pdt.
+ * trans.h: Add bool 'pdt_ok' to prototype with defaul value of
+ false.
+
+2025-12-01 Christopher Albert <albert@tugraz.at>
+ Harald Anlauf <anlauf@gcc.gnu.org>
+
+ PR fortran/107721
+ PR fortran/102417
+ * arith.cc (eval_intrinsic): Call gfc_check_constructor_type on
+ array constructor operands with explicit type-spec to ensure
+ element type conversion before operations. Resolve character
+ array constructors before CONCAT operations.
+ (reduce_binary_ac, reduce_binary_ca, reduce_binary_aa): Preserve
+ character length info in result arrays.
+ * array.cc (check_constructor_type): Simplify non-constant
+ expressions before type checking to handle parenthesized elements.
+ Handle nested character array constructors with explicit type-spec
+ when outer constructor has no type-spec.
+ (gfc_resolve_character_array_constructor): Recursively propagate
+ type-spec to nested array constructors. If the nested constructor
+ has an explicit type-spec, resolve it first before propagating
+ the outer type-spec.
+
+2025-12-01 Tobias Burnus <tburnus@baylibre.com>
+
+ * gfortran.texi (Default exponents): Remove spurious @menu entry.
+
+2025-11-30 Andrew Pinski <andrew.pinski@oss.qualcomm.com>
+
+ * lang.opt.urls: Regenerate.
+
+2025-11-28 Tobias Burnus <tburnus@baylibre.com>
+
+ PR c/122892
+ * openmp.cc (gfc_resolve_omp_allocate): Reject non-local
+ static variables with cgroup/pteam/thread allocators.
+ * parse.cc: Permit OMP ALLOCATE in BLOCK DATA.
+
+2025-11-26 Tobias Burnus <tburnus@baylibre.com>
+
+ * dump-parse-tree.cc (show_attr): Handle OpenMP's 'local' clause
+ and the 'groupprivate' directive.
+ (show_omp_clauses): Handle dyn_groupprivate.
+ * frontend-passes.cc (gfc_code_walker): Walk dyn_groupprivate.
+ * gfortran.h (enum gfc_statement): Add ST_OMP_GROUPPRIVATE.
+ (enum gfc_omp_fallback, gfc_add_omp_groupprivate,
+ gfc_add_omp_declare_target_local): New.
+ * match.h (gfc_match_omp_groupprivate): New.
+ * module.cc (enum ab_attribute, mio_symbol_attribute, load_commons,
+ write_common_0): Handle 'groupprivate' + declare target's 'local'.
+ * openmp.cc (gfc_omp_directives): Add 'groupprivate'.
+ (gfc_free_omp_clauses): Free dyn_groupprivate.
+ (enum omp_mask2): Add OMP_CLAUSE_LOCAL and OMP_CLAUSE_DYN_GROUPPRIVATE.
+ (gfc_match_omp_clauses): Match them.
+ (OMP_TARGET_CLAUSES): Add OMP_CLAUSE_DYN_GROUPPRIVATE.
+ (OMP_DECLARE_TARGET_CLAUSES): Add OMP_CLAUSE_LOCAL.
+ (gfc_match_omp_declare_target): Handle groupprivate + fixes.
+ (gfc_match_omp_threadprivate): Code move to and calling now ...
+ (gfc_match_omp_thread_group_private): ... this new function.
+ Also handle groupprivate.
+ (gfc_match_omp_groupprivate): New.
+ (resolve_omp_clauses): Resolve dyn_groupprivate.
+ * parse.cc (decode_omp_directive): Match groupprivate.
+ (case_omp_decl, parse_spec, gfc_ascii_statement): Handle it.
+ * resolve.cc (resolve_symbol): Handle groupprivate.
+ * symbol.cc (gfc_check_conflict, gfc_copy_attr): Handle 'local'
+ and 'groupprivate'.
+ (gfc_add_omp_groupprivate, gfc_add_omp_declare_target_local): New.
+ * trans-common.cc (build_common_decl,
+ accumulate_equivalence_attributes): Print 'sorry' for
+ groupprivate and declare target's local.
+ * trans-decl.cc (add_attributes_to_decl): Likewise..
+ * trans-openmp.cc (gfc_trans_omp_clauses): Print 'sorry' for
+ dyn_groupprivate.
+ (fallback): Process declare target with link/local as
+ done for 'enter'.
+
+2025-11-26 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/104650
+ * decl.cc (gfc_get_pdt_instance): If the PDT template has
+ finalizers, make a new f2k_derived namespace for this intance
+ and copy the template namespace into it. Set the instance
+ template_sym field to point to the template.
+ * expr.cc (gfc_check_pointer_assign): Allow array value pointer
+ lvalues to point to scalar null expressions in initialization.
+ * gfortran.h : Add the template_sym field to gfc_symbol.
+ * resolve.cc (gfc_resolve_finalizers): For a pdt_type, copy the
+ final subroutines with the same type argument into the pdt_type
+ finalizer list. Prevent final subroutine type checking and
+ creation of the vtab for pdt_templates.
+ * symbol.cc (gfc_free_symbol): Do not call gfc_free_namespace
+ for pdt_type with finalizers. Instead, free the finalizers and
+ the namespace.
+
+2025-11-24 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122766
+ * decl.cc (gfc_match_decl_type_spec): A pdt_type found while
+ parsing a contains section can only arise from the typespec of
+ a function declaration. This can be retained in the typespec.
+ Once we are parsing the function, the first reference to this
+ derived type will find that it has no symtree. Provide it with
+ one so that gfc_use_derived does not complain and, again,retain
+ it in the typespec.
+
+2025-11-18 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/32365
+ * parse.cc (parse_executable): Reject declaration/OpenMP
+ specification statements seen after executable code
+ unconditionally, keeping the legacy DATA diagnostic as
+ a warning.
+
+2025-11-17 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/122709
+ * resolve.cc (resolve_assoc_var): If the associate target is a
+ contiguous pointer, so is the associate variable.
+
+2025-11-17 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * gfortran.texi: Remove section "Experimental features for future
+ Fortran revisions". Move documentation of UNSIGNED into Extensions.
+ Mention flang compatibility.
+
+2025-11-17 Jakub Jelinek <jakub@redhat.com>
+
+ * parse.cc (gfc_parse_file): Avoid arithmetics or
+ bitwise operations between enumerators from different enums.
+
+2025-11-14 Yuao Ma <c8ef@outlook.com>
+
+ * trans-expr.cc (conv_dummy_value): Add check for NULL allocatable.
+
+2025-11-14 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/117070
+ * array.cc (check_constructor): Allow procedures as potential
+ target of a procedure pointer.
+
+2025-11-13 Andrew Stubbs <ams@codesourcery.com>
+ Kwok Cheung Yeung <kcyeung@baylibre.com>
+ Thomas Schwinge <tschwinge@baylibre.com>
+
+ * openmp.cc (is_predefined_allocator): Use GOMP_OMP_PREDEF_ALLOC_MAX
+ and GOMP_OMPX_PREDEF_ALLOC_MIN/MAX instead of hardcoded values in the
+ comment.
+
+2025-11-13 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR other/122638
+ * gfortran.texi (OpenMP): Fix syntax.
+ * intrinsic.texi (UINT): Fix syntax.
+
+2025-11-13 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/96255
+ * match.cc (apply_typespec_to_iterator): Call gfc_set_sym_referenced
+ for both new and shadow iterator symbols.
+
+2025-11-12 Tobias Burnus <tburnus@baylibre.com>
+
+ PR libgomp/119677
+ * intrinsic.texi (OpenMP Modules): Add omp_default_device.
+ * openmp.cc (gfc_resolve_omp_context_selector): Accept
+ omp_default_device as conforming device number.
+
+2025-11-11 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/96255
+ * resolve.cc (gfc_resolve_forall): Delete outer_sym
+
+2025-11-11 Christopher Albert <albert@tugraz.at>
+
+ PR fortran/90519
+ * trans-expr.cc (strip_parentheses): New helper function to strip
+ INTRINSIC_PARENTHESES operators from expressions.
+ (is_runtime_conformable): Use strip_parentheses to handle cases
+ like a = (a) when checking for self-assignment.
+ (gfc_trans_assignment_1): Strip parentheses before checking if
+ expr2 is a variable, ensuring deep_copy is enabled for cases like
+ a = (a). Also strip parentheses when checking for self-assignment
+ to avoid use-after-free in finalization.
+ (gfc_trans_scalar_assign): Add comment about parentheses handling.
+ * class.cc (generate_finalization_wrapper): Create separate result
+ symbol for finalizer wrapper functions instead of self-referencing
+ the procedure symbol, avoiding ICE in gimplify_call_expr.
+
+2025-11-11 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+ Steve Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/96255
+ * gfortran.h (gfc_forall_iterator): Add bool shadow field.
+ * match.cc (apply_typespec_to_iterator): New helper function to
+ consolidate shadow variable creation logic.
+ (match_forall_header): Add type-spec parsing for DO CONCURRENT
+ and FORALL. Create shadow variables when type-spec differs from
+ outer scope. Replace duplicated code with apply_typespec_to_iterator.
+ * resolve.cc (replace_in_expr_recursive): New function to recursively
+ walk expressions and replace symbol references.
+ (replace_in_code_recursive): New function to recursively walk code
+ blocks and replace symbol references.
+ (gfc_replace_forall_variable): New entry point for shadow variable
+ substitution.
+ (gfc_resolve_assign_in_forall): Skip many-to-one assignment warning
+ for DO CONCURRENT.
+ (gfc_count_forall_iterators): Handle both EXEC_FORALL and
+ EXEC_DO_CONCURRENT with assertion.
+ (gfc_resolve_forall): Skip F2018 obsolescence warning for DO
+ CONCURRENT. Fix memory allocation check. Add NULL checks for shadow
+ variables. Implement shadow variable walker.
+ (gfc_resolve_code): Set gfc_do_concurrent_flag for DO CONCURRENT
+ constructs to enable constraint checking.
+
+2025-11-10 Sandra Loosemore <sloosemore@baylibre.com>
+
+ PR other/122243
+ * lang.opt.urls: Regenerated.
+
+2025-11-08 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/113338
+ * decl.cc (gfc_verify_c_interop_param): Allow further types of
+ dummy argument without the VALUE attribute as specified in
+ F2018 18.3.6 item (5).
+
+2025-11-08 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/121628
+ * trans-array.cc (seen_derived_types): Move to file scope and
+ preserve/restore around generate_element_copy_wrapper.
+ * trans-intrinsic.cc (conv_intrinsic_atomic_op): Reuse
+ gfc_trans_force_lval when forcing addressable CAF temps.
+
+2025-11-06 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/121628
+ * trans-array.cc (get_copy_helper_function_type): New function to
+ create function type for element copy helpers.
+ (get_copy_helper_pointer_type): New function to create pointer type
+ for element copy helpers.
+ (generate_element_copy_wrapper): New function to generate runtime
+ helper for element-wise deep copying of recursive types.
+ (structure_alloc_comps): Detect recursive allocatable array
+ components and use runtime helper instead of inline recursion.
+ Add includes for cgraph.h and function.h.
+ * trans-decl.cc (gfor_fndecl_cfi_deep_copy_array): New declaration
+ for runtime deep copy helper.
+ (gfc_build_builtin_function_decls): Initialize the runtime helper
+ declaration.
+ * trans-intrinsic.cc (conv_intrinsic_atomic_op): Enhance handling of
+ constant values in coarray atomic operations by detecting and
+ materializing address-of-constant expressions.
+ * trans.h (gfor_fndecl_cfi_deep_copy_array): Add external declaration.
+
+2025-11-05 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122566
+ * decl.cc (gfc_get_pdt_instance): Add non-PDT type exstention.
+
+2025-11-05 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/122501
+ PR fortran/122524
+ * primary.cc (gfc_convert_to_structure_constructor): Correct
+ whitespace issue.
+ (gfc_match_rvalue): Remove the attempt to match specific procs
+ before filling out PDT constructor. Instead, defer this until
+ resolution with the condition that there not be a following
+ arglist and more than one procedure in the generic interface.
+
+2025-11-05 Tobias Burnus <tburnus@baylibre.com>
+
+ PR fortran/122570
+ * openmp.cc (resolve_omp_metadirective): Fix 'skip' of
+ never matchable metadirective variants.
+
+2025-11-04 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/122564
+ * resolve.cc (resolve_locality_spec): Delete temporary hash_set.
+
+2025-11-04 Paul-Antoine Arras <parras@baylibre.com>
+
+ PR fortran/122369
+ PR fortran/122508
+ * gfortran.h (gfc_rebind_label): Declare new function.
+ * parse.cc (parse_omp_metadirective_body): Rebind labels to the outer
+ region. Maintain a vector of metadirective regions.
+ (gfc_parse_file): Initialise it.
+ * parse.h (GFC_PARSE_H): Declare it.
+ * symbol.cc (gfc_get_st_label): Look for existing labels in outer
+ metadirective regions.
+ (gfc_rebind_label): Define new function.
+ (gfc_define_st_label): Accept duplicate labels in metadirective body.
+ (gfc_reference_st_label): Accept shared DO termination labels in
+ metadirective body.
+
+2025-11-03 Steve Kargl <kargls@comcast.net>
+
+ PR fortran/122513
+ * resolve.cc (check_default_none_expr): Do not allow an
+ iterator in a locality spec. Allow a named constant to be
+ used within the loop.
+
2025-11-01 Harald Anlauf <anlauf@gmx.de>
PR fortran/78640
diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc
index 82a8b6f..142f1b0 100644
--- a/gcc/fortran/arith.cc
+++ b/gcc/fortran/arith.cc
@@ -1565,6 +1565,8 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
&op1->where);
r->shape = gfc_copy_shape (op1->shape, op1->rank);
+ if (c->expr->ts.type == BT_CHARACTER)
+ r->ts.u.cl = c->expr->ts.u.cl;
}
else
{
@@ -1572,6 +1574,8 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
r = gfc_get_array_expr (op1->ts.type, op1->ts.kind,
&op1->where);
r->shape = gfc_get_shape (op1->rank);
+ if (op1->ts.type == BT_CHARACTER)
+ r->ts.u.cl = op1->ts.u.cl;
}
r->rank = op1->rank;
r->corank = op1->corank;
@@ -1629,6 +1633,8 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
&op2->where);
r->shape = gfc_copy_shape (op2->shape, op2->rank);
+ if (c->expr->ts.type == BT_CHARACTER)
+ r->ts.u.cl = c->expr->ts.u.cl;
}
else
{
@@ -1636,6 +1642,8 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
r = gfc_get_array_expr (op2->ts.type, op2->ts.kind,
&op2->where);
r->shape = gfc_get_shape (op2->rank);
+ if (op2->ts.type == BT_CHARACTER)
+ r->ts.u.cl = op2->ts.u.cl;
}
r->rank = op2->rank;
r->corank = op2->corank;
@@ -1697,11 +1705,15 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
{
/* Handle zero-sized arrays. */
r = gfc_get_array_expr (op1->ts.type, op1->ts.kind, &op1->where);
+ if (op1->ts.type == BT_CHARACTER)
+ r->ts.u.cl = op1->ts.u.cl;
}
else
{
r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
&op1->where);
+ if (c->expr->ts.type == BT_CHARACTER)
+ r->ts.u.cl = c->expr->ts.u.cl;
}
r->shape = gfc_copy_shape (op1->shape, op1->rank);
r->rank = op1->rank;
@@ -1921,6 +1933,29 @@ eval_intrinsic (gfc_intrinsic_op op,
|| !gfc_is_constant_expr (op2) || !gfc_expanded_ac (op2)))
goto runtime;
+ /* For array constructors with explicit type-spec, ensure elements are
+ converted to the specified type before any operations. This handles
+ cases like [integer :: ([1.0])] ** 2 where parentheses would otherwise
+ cause the type-spec to be lost during constant folding. */
+ if (op1->expr_type == EXPR_ARRAY && op1->ts.type != BT_UNKNOWN)
+ gfc_check_constructor_type (op1);
+ if (op2 != NULL && op2->expr_type == EXPR_ARRAY && op2->ts.type != BT_UNKNOWN)
+ gfc_check_constructor_type (op2);
+
+ /* For CONCAT operations, also resolve character array constructors to
+ ensure elements are padded to the specified length before concatenation.
+ This ensures [character(16):: 'a','b'] // '|' pads to 16 chars first. */
+ if (op == INTRINSIC_CONCAT)
+ {
+ if (op1->expr_type == EXPR_ARRAY && op1->ts.type == BT_CHARACTER
+ && op1->ts.u.cl && op1->ts.u.cl->length_from_typespec)
+ gfc_resolve_character_array_constructor (op1);
+ if (op2 != NULL && op2->expr_type == EXPR_ARRAY
+ && op2->ts.type == BT_CHARACTER
+ && op2->ts.u.cl && op2->ts.u.cl->length_from_typespec)
+ gfc_resolve_character_array_constructor (op2);
+ }
+
if (unary)
rc = reduce_unary (eval.f2, op1, &result);
else
diff --git a/gcc/fortran/array.cc b/gcc/fortran/array.cc
index 8f00049..471f0cb 100644
--- a/gcc/fortran/array.cc
+++ b/gcc/fortran/array.cc
@@ -1344,6 +1344,7 @@ gfc_match_array_constructor (gfc_expr **result)
match m;
const char *end_delim;
bool seen_ts;
+ gfc_namespace *old_ns = gfc_current_ns;
head = NULL;
seen_ts = false;
@@ -1368,6 +1369,8 @@ gfc_match_array_constructor (gfc_expr **result)
/* Try to match an optional "type-spec ::" */
gfc_clear_ts (&ts);
m = gfc_match_type_spec (&ts);
+ gfc_current_ns = old_ns;
+
if (m == MATCH_YES)
{
seen_ts = (gfc_match (" ::") == MATCH_YES);
@@ -1549,10 +1552,37 @@ check_constructor_type (gfc_constructor_base base, bool convert)
{
e = c->expr;
+ /* Simplify non-constant expressions (like parenthesized arrays) so type
+ conversion can work on the simplified result. This handles cases like
+ [integer :: ([1.0])] where ([1.0]) is an EXPR_OP that needs to be
+ simplified to an EXPR_ARRAY before type conversion. */
+ if (convert && e->expr_type != EXPR_CONSTANT
+ && e->expr_type != EXPR_ARRAY)
+ gfc_simplify_expr (e, 0);
+
if (e->expr_type == EXPR_ARRAY)
{
- if (!check_constructor_type (e->value.constructor, convert))
- return false;
+ /* If the outer constructor has no type-spec (convert=false) and
+ the nested array has an explicit type-spec, process it separately
+ so its elements get converted according to its type-spec. This
+ handles cases like [[character(16) :: ['a','b']]] where the outer
+ constructor has no type-spec but the inner one does.
+ gfc_check_constructor_type will also update the global
+ constructor_ts and cons_state which propagates the type info
+ to the outer constructor.
+ For character types, length_from_typespec indicates an explicit
+ type-spec was provided. */
+ if (!convert && e->ts.type == BT_CHARACTER
+ && e->ts.u.cl && e->ts.u.cl->length_from_typespec)
+ {
+ if (!gfc_check_constructor_type (e))
+ return false;
+ }
+ else
+ {
+ if (!check_constructor_type (e->value.constructor, convert))
+ return false;
+ }
continue;
}
@@ -1644,6 +1674,12 @@ check_constructor (gfc_constructor_base ctor, bool (*check_function) (gfc_expr *
if (!e)
continue;
+ /* Allow procedures as potential target of a procedure pointer. */
+ if (e->expr_type == EXPR_VARIABLE
+ && e->ts.type == BT_PROCEDURE
+ && e->symtree->n.sym->attr.flavor == FL_PROCEDURE)
+ continue;
+
if (e->expr_type != EXPR_ARRAY)
{
if (!(*check_function)(e))
@@ -2255,10 +2291,14 @@ gfc_resolve_character_array_constructor (gfc_expr *expr)
{
gfc_constructor *p;
HOST_WIDE_INT found_length;
+ bool has_ts;
gcc_assert (expr->expr_type == EXPR_ARRAY);
gcc_assert (expr->ts.type == BT_CHARACTER);
+ /* Check if we have an explicit type-spec with length. */
+ has_ts = expr->ts.u.cl && expr->ts.u.cl->length_from_typespec;
+
if (expr->ts.u.cl == NULL)
{
for (p = gfc_constructor_first (expr->value.constructor);
@@ -2361,28 +2401,56 @@ got_charlen:
if (found_length != -1)
for (p = gfc_constructor_first (expr->value.constructor);
p; p = gfc_constructor_next (p))
- if (p->expr->expr_type == EXPR_CONSTANT)
- {
- gfc_expr *cl = NULL;
- HOST_WIDE_INT current_length = -1;
- bool has_ts;
+ {
+ /* For non-constant expressions (like EXPR_OP from concatenation),
+ try to simplify them first so we can then pad/truncate. */
+ if (p->expr->expr_type != EXPR_CONSTANT
+ && p->expr->ts.type == BT_CHARACTER)
+ gfc_simplify_expr (p->expr, 0);
- if (p->expr->ts.u.cl && p->expr->ts.u.cl->length)
+ if (p->expr->expr_type == EXPR_CONSTANT)
{
- cl = p->expr->ts.u.cl->length;
- gfc_extract_hwi (cl, &current_length);
+ gfc_expr *cl = NULL;
+ HOST_WIDE_INT current_length = -1;
+
+ if (p->expr->ts.u.cl && p->expr->ts.u.cl->length)
+ {
+ cl = p->expr->ts.u.cl->length;
+ gfc_extract_hwi (cl, &current_length);
+ }
+
+ /* If gfc_extract_int above set current_length, we implicitly
+ know the type is BT_INTEGER and it's EXPR_CONSTANT. */
+
+ if (! cl
+ || (current_length != -1 && current_length != found_length))
+ gfc_set_constant_character_len (found_length, p->expr,
+ has_ts ? -1 : found_length);
}
-
- /* If gfc_extract_int above set current_length, we implicitly
- know the type is BT_INTEGER and it's EXPR_CONSTANT. */
-
- has_ts = expr->ts.u.cl->length_from_typespec;
-
- if (! cl
- || (current_length != -1 && current_length != found_length))
- gfc_set_constant_character_len (found_length, p->expr,
- has_ts ? -1 : found_length);
- }
+ else if (p->expr->expr_type == EXPR_ARRAY)
+ {
+ /* For nested array constructors, propagate the type-spec and
+ recursively resolve. This handles cases like
+ [character(16) :: ['a','b']] // "|". The inner constructor
+ may have BT_UNKNOWN type initially. */
+ if (p->expr->ts.type == BT_UNKNOWN
+ || p->expr->ts.type == BT_CHARACTER)
+ {
+ if (p->expr->ts.type == BT_CHARACTER
+ && p->expr->ts.u.cl
+ && p->expr->ts.u.cl->length_from_typespec)
+ {
+ /* If the inner array has an explicit type-spec, we must
+ honor it first (e.g. truncate/pad to its length),
+ before coercing it to the outer length. */
+ gfc_resolve_character_array_constructor (p->expr);
+ }
+
+ p->expr->ts = expr->ts;
+ gfc_resolve_character_array_constructor (p->expr);
+ }
+ }
+ }
}
return true;
diff --git a/gcc/fortran/class.cc b/gcc/fortran/class.cc
index a1c6faf..079240c 100644
--- a/gcc/fortran/class.cc
+++ b/gcc/fortran/class.cc
@@ -1733,10 +1733,12 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
{
gfc_symbol *final, *array, *fini_coarray, *byte_stride, *sizes, *strides;
gfc_symbol *ptr = NULL, *idx, *idx2, *is_contiguous, *offset, *nelem;
+ gfc_symbol *result = NULL;
gfc_component *comp;
gfc_namespace *sub_ns;
gfc_code *last_code, *block;
char *name;
+ char *result_name;
bool finalizable_comp = false;
gfc_expr *ancestor_wrapper = NULL, *rank;
gfc_iterator *iter;
@@ -1824,7 +1826,6 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
final->attr.function = 1;
final->attr.pure = 0;
final->attr.recursive = 1;
- final->result = final;
final->ts.type = BT_INTEGER;
final->ts.kind = 4;
final->attr.artificial = 1;
@@ -1832,6 +1833,26 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
final->attr.if_source = IFSRC_DECL;
if (ns->proc_name->attr.flavor == FL_MODULE)
final->module = ns->proc_name->name;
+
+ /* Create a separate result symbol instead of using final->result = final.
+ Self-referencing result symbols (final->result = final) create a cycle
+ in the symbol structure that causes an ICE in gimplify_call_expr when
+ the finalizer wrapper is used as a procedure pointer initializer. */
+ result_name = xasprintf ("__result_%s", tname);
+ if (gfc_get_symbol (result_name, sub_ns, &result) != 0)
+ gfc_internal_error ("Failed to create finalizer result symbol");
+ free (result_name);
+
+ if (!gfc_add_flavor (&result->attr, FL_VARIABLE, result->name,
+ &gfc_current_locus)
+ || !gfc_add_result (&result->attr, result->name, &gfc_current_locus))
+ gfc_internal_error ("Failed to set finalizer result attributes");
+
+ result->ts = final->ts;
+ result->attr.artificial = 1;
+ gfc_set_sym_referenced (result);
+ gfc_commit_symbol (result);
+ final->result = result;
gfc_set_sym_referenced (final);
gfc_commit_symbol (final);
@@ -1959,7 +1980,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
/* Set return value to 0. */
last_code = gfc_get_code (EXEC_ASSIGN);
- last_code->expr1 = gfc_lval_expr_from_sym (final);
+ last_code->expr1 = gfc_lval_expr_from_sym (result);
last_code->expr2 = gfc_get_int_expr (4, NULL, 0);
sub_ns->code = last_code;
diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 5b222cd..0e55171 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -1217,6 +1217,10 @@ match_char_length (gfc_expr **expr, bool *deferred, bool obsolescent_check)
goto syntax;
}
+ if (obsolescent_check
+ && !gfc_notify_std (GFC_STD_F95_OBS, "Old-style character length at %C"))
+ return MATCH_ERROR;
+
return MATCH_YES;
syntax:
@@ -1537,9 +1541,47 @@ gfc_verify_c_interop_param (gfc_symbol *sym)
{
if (sym->ns->proc_name->attr.is_bind_c == 1)
{
+ bool f2018_allowed = gfc_option.allow_std & ~GFC_STD_OPT_F08;
+ bool f2018_added = false;
+
is_c_interop = (gfc_verify_c_interop(&(sym->ts)) ? 1 : 0);
- if (is_c_interop != 1)
+ /* F2018:18.3.6 has the following text:
+ "(5) any dummy argument without the VALUE attribute corresponds to
+ a formal parameter of the prototype that is of a pointer type, and
+ either
+ • the dummy argument is interoperable with an entity of the
+ referenced type (ISO/IEC 9899:2011, 6.2.5, 7.19, and 7.20.1) of
+ the formal parameter (this is equivalent to the F2008 text),
+ • the dummy argument is a nonallocatable nonpointer variable of
+ type CHARACTER with assumed character length and the formal
+ parameter is a pointer to CFI_cdesc_t,
+ • the dummy argument is allocatable, assumed-shape, assumed-rank,
+ or a pointer without the CONTIGUOUS attribute, and the formal
+ parameter is a pointer to CFI_cdesc_t, or
+ • the dummy argument is assumed-type and not allocatable,
+ assumed-shape, assumed-rank, or a pointer, and the formal
+ parameter is a pointer to void," */
+ if (is_c_interop == 0 && !sym->attr.value && f2018_allowed)
+ {
+ bool as_ar = (sym->as
+ && (sym->as->type == AS_ASSUMED_SHAPE
+ || sym->as->type == AS_ASSUMED_RANK));
+ bool cond1 = (sym->ts.type == BT_CHARACTER
+ && !(sym->ts.u.cl && sym->ts.u.cl->length)
+ && !sym->attr.allocatable
+ && !sym->attr.pointer);
+ bool cond2 = (sym->attr.allocatable
+ || as_ar
+ || (IS_POINTER (sym) && !sym->attr.contiguous));
+ bool cond3 = (sym->ts.type == BT_ASSUMED
+ && !sym->attr.allocatable
+ && !sym->attr.pointer
+ && !as_ar);
+ f2018_added = cond1 || cond2 || cond3;
+ }
+
+ if (is_c_interop != 1 && !f2018_added)
{
/* Make personalized messages to give better feedback. */
if (sym->ts.type == BT_DERIVED)
@@ -3931,6 +3973,7 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
gfc_expr *kind_expr;
gfc_component *c1, *c2;
match m;
+ gfc_symtree *s = NULL;
type_param_spec_list = NULL;
@@ -3944,8 +3987,7 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
if (gfc_current_state () == COMP_DERIVED
&& !(gfc_state_stack->previous
&& gfc_state_stack->previous->state == COMP_DERIVED)
- && gfc_current_block ()->attr.pdt_template
- && !strcmp (gfc_current_block ()->name, (*sym)->name))
+ && gfc_current_block ()->attr.pdt_template)
{
if (ext_param_list)
*ext_param_list = gfc_copy_actual_arglist (param_list);
@@ -4141,10 +4183,29 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
goto error_return;
}
+ /* If we are in an interface body, the instance will not have been imported.
+ Make sure that it is imported implicitly. */
+ s = gfc_find_symtree (gfc_current_ns->sym_root, pdt->name);
+ if (gfc_current_ns->proc_name
+ && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY
+ && s && s->import_only && pdt->attr.imported)
+ {
+ s = gfc_find_symtree (gfc_current_ns->sym_root, instance->name);
+ if (!s)
+ {
+ gfc_get_sym_tree (instance->name, gfc_current_ns, &s, false,
+ &gfc_current_locus);
+ s->n.sym = instance;
+ }
+ s->n.sym->attr.imported = 1;
+ s->import_only = 1;
+ }
+
m = MATCH_YES;
if (instance->attr.flavor == FL_DERIVED
- && instance->attr.pdt_type)
+ && instance->attr.pdt_type
+ && instance->components)
{
instance->refs++;
if (ext_param_list)
@@ -4162,6 +4223,16 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
instance->attr.pdt_type = 1;
instance->declared_at = gfc_current_locus;
+ /* In resolution, the finalizers are copied, according to the type of the
+ argument, to the instance finalizers. However, they are retained by the
+ template and procedures are freed there. */
+ if (pdt->f2k_derived && pdt->f2k_derived->finalizers)
+ {
+ instance->f2k_derived = gfc_get_namespace (NULL, 0);
+ instance->template_sym = pdt;
+ *instance->f2k_derived = *pdt->f2k_derived;
+ }
+
/* Add the components, replacing the parameters in all expressions
with the expressions for their values in 'type_param_spec_list'. */
c1 = pdt->components;
@@ -4191,30 +4262,36 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
to obtain the instance of the extended type. */
if (gfc_current_state () != COMP_DERIVED
&& c1 == pdt->components
- && (c1->ts.type == BT_DERIVED || c1->ts.type == BT_CLASS)
- && c1->ts.u.derived && c1->ts.u.derived->attr.pdt_template
+ && c1->ts.type == BT_DERIVED
+ && c1->ts.u.derived
&& gfc_get_derived_super_type (*sym) == c2->ts.u.derived)
{
- gfc_formal_arglist *f;
+ if (c1->ts.u.derived->attr.pdt_template)
+ {
+ gfc_formal_arglist *f;
- old_param_spec_list = type_param_spec_list;
+ old_param_spec_list = type_param_spec_list;
- /* Obtain a spec list appropriate to the extended type..*/
- actual_param = gfc_copy_actual_arglist (type_param_spec_list);
- type_param_spec_list = actual_param;
- for (f = c1->ts.u.derived->formal; f && f->next; f = f->next)
- actual_param = actual_param->next;
- if (actual_param)
- {
- gfc_free_actual_arglist (actual_param->next);
- actual_param->next = NULL;
- }
+ /* Obtain a spec list appropriate to the extended type..*/
+ actual_param = gfc_copy_actual_arglist (type_param_spec_list);
+ type_param_spec_list = actual_param;
+ for (f = c1->ts.u.derived->formal; f && f->next; f = f->next)
+ actual_param = actual_param->next;
+ if (actual_param)
+ {
+ gfc_free_actual_arglist (actual_param->next);
+ actual_param->next = NULL;
+ }
- /* Now obtain the PDT instance for the extended type. */
- c2->param_list = type_param_spec_list;
- m = gfc_get_pdt_instance (type_param_spec_list, &c2->ts.u.derived,
- &c2->param_list);
- type_param_spec_list = old_param_spec_list;
+ /* Now obtain the PDT instance for the extended type. */
+ c2->param_list = type_param_spec_list;
+ m = gfc_get_pdt_instance (type_param_spec_list,
+ &c2->ts.u.derived,
+ &c2->param_list);
+ type_param_spec_list = old_param_spec_list;
+ }
+ else
+ c2->ts = c1->ts;
c2->ts.u.derived->refs++;
gfc_set_sym_referenced (c2->ts.u.derived);
@@ -4393,7 +4470,25 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
type_param_spec_list = old_param_spec_list;
if (!(c2->attr.pointer || c2->attr.allocatable))
- c2->initializer = gfc_default_initializer (&c2->ts);
+ {
+ if (!c1->initializer
+ || c1->initializer->expr_type != EXPR_FUNCTION)
+ c2->initializer = gfc_default_initializer (&c2->ts);
+ else
+ {
+ gfc_symtree *s;
+ c2->initializer = gfc_copy_expr (c1->initializer);
+ s = gfc_find_symtree (pdt->ns->sym_root,
+ gfc_dt_lower_string (c2->ts.u.derived->name));
+ if (s)
+ c2->initializer->symtree = s;
+ c2->initializer->ts = c2->ts;
+ if (!s)
+ gfc_insert_parameter_exprs (c2->initializer,
+ type_param_spec_list);
+ gfc_simplify_expr (params->expr, 1);
+ }
+ }
if (c2->attr.allocatable)
instance->attr.alloc_comp = 1;
@@ -4780,6 +4875,31 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
return m;
}
+ /* This picks up function declarations with a PDT typespec. Since a
+ pdt_type has been generated, there is no more to do. Within the
+ function body, this type must be used for the typespec so that
+ the "being used before it is defined warning" does not arise. */
+ if (ts->type == BT_DERIVED
+ && sym && sym->attr.pdt_type
+ && (gfc_current_state () == COMP_CONTAINS
+ || (gfc_current_state () == COMP_FUNCTION
+ && gfc_current_block ()->ts.type == BT_DERIVED
+ && gfc_current_block ()->ts.u.derived == sym
+ && !gfc_find_symtree (gfc_current_ns->sym_root,
+ sym->name))))
+ {
+ if (gfc_current_state () == COMP_FUNCTION)
+ {
+ gfc_symtree *pdt_st;
+ pdt_st = gfc_new_symtree (&gfc_current_ns->sym_root,
+ sym->name);
+ pdt_st->n.sym = sym;
+ sym->refs++;
+ }
+ ts->u.derived = sym;
+ return MATCH_YES;
+ }
+
/* Defer association of the derived type until the end of the
specification block. However, if the derived type can be
found, add it to the typespec. */
@@ -4816,7 +4936,7 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
dt_sym = gfc_find_dt_in_generic (sym);
/* Host associated PDTs can get confused with their constructors
- because they ar instantiated in the template's namespace. */
+ because they are instantiated in the template's namespace. */
if (!dt_sym)
{
if (gfc_find_symbol (dt_name, NULL, 1, &dt_sym))
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index eda0659..2a4ebb0 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -843,6 +843,8 @@ show_attr (symbol_attribute *attr, const char * module)
fputs (" VALUE", dumpfile);
if (attr->volatile_)
fputs (" VOLATILE", dumpfile);
+ if (attr->omp_groupprivate)
+ fputs (" GROUPPRIVATE", dumpfile);
if (attr->threadprivate)
fputs (" THREADPRIVATE", dumpfile);
if (attr->temporary)
@@ -938,6 +940,8 @@ show_attr (symbol_attribute *attr, const char * module)
fputs (" OMP-DECLARE-TARGET", dumpfile);
if (attr->omp_declare_target_link)
fputs (" OMP-DECLARE-TARGET-LINK", dumpfile);
+ if (attr->omp_declare_target_local)
+ fputs (" OMP-DECLARE-TARGET-LOCAL", dumpfile);
if (attr->omp_declare_target_indirect)
fputs (" OMP-DECLARE-TARGET-INDIRECT", dumpfile);
if (attr->omp_device_type == OMP_DEVICE_TYPE_HOST)
@@ -2211,6 +2215,20 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
fputs (" DEPEND(source)", dumpfile);
if (omp_clauses->doacross_source)
fputs (" DOACROSS(source:)", dumpfile);
+ if (omp_clauses->dyn_groupprivate)
+ {
+ fputs (" DYN_GROUPPRIVATE(", dumpfile);
+ if (omp_clauses->fallback != OMP_FALLBACK_NONE)
+ fputs ("FALLBACK(", dumpfile);
+ if (omp_clauses->fallback == OMP_FALLBACK_ABORT)
+ fputs ("ABORT):", dumpfile);
+ else if (omp_clauses->fallback == OMP_FALLBACK_DEFAULT_MEM)
+ fputs ("DEFAULT_MEM):", dumpfile);
+ else if (omp_clauses->fallback == OMP_FALLBACK_NULL)
+ fputs ("NULL):", dumpfile);
+ show_expr (omp_clauses->dyn_groupprivate);
+ fputc (')', dumpfile);
+ }
if (omp_clauses->capture)
fputs (" CAPTURE", dumpfile);
if (omp_clauses->depobj_update != OMP_DEPEND_UNSET)
diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index a11ff79..054276e 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -4577,7 +4577,8 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue,
return false;
}
- if (lvalue->rank != rvalue->rank && !rank_remap)
+ if (lvalue->rank != rvalue->rank && !rank_remap
+ && !(rvalue->expr_type == EXPR_NULL && is_init_expr))
{
gfc_error ("Different ranks in pointer assignment at %L", &lvalue->where);
return false;
@@ -6405,6 +6406,14 @@ gfc_is_simply_contiguous (gfc_expr *expr, bool strict, bool permit_element)
|| (sym->as && sym->as->type == AS_ASSUMED_SHAPE))))
return false;
+ /* An associate variable may point to a non-contiguous target. */
+ if (ar && ar->type == AR_FULL
+ && sym->attr.associate_var && !sym->attr.contiguous
+ && sym->assoc
+ && sym->assoc->target)
+ return gfc_is_simply_contiguous (sym->assoc->target, strict,
+ permit_element);
+
if (!ar || ar->type == AR_FULL)
return true;
diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 595c509..b699231 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5645,6 +5645,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
WALK_SUBEXPR (co->ext.omp_clauses->num_tasks);
WALK_SUBEXPR (co->ext.omp_clauses->priority);
WALK_SUBEXPR (co->ext.omp_clauses->detach);
+ WALK_SUBEXPR (co->ext.omp_clauses->dyn_groupprivate);
WALK_SUBEXPR (co->ext.omp_clauses->novariants);
WALK_SUBEXPR (co->ext.omp_clauses->nocontext);
for (idx = 0; idx < ARRAY_SIZE (list_types); idx++)
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 19473df..72aecfb 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -311,6 +311,7 @@ enum gfc_statement
ST_OMP_TASKLOOP, ST_OMP_END_TASKLOOP, ST_OMP_SCAN, ST_OMP_DEPOBJ,
ST_OMP_TASKLOOP_SIMD, ST_OMP_END_TASKLOOP_SIMD, ST_OMP_ORDERED_DEPEND,
ST_OMP_REQUIRES, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL, ST_END_CRITICAL,
+ ST_OMP_GROUPPRIVATE,
ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_EVENT_POST,
ST_EVENT_WAIT, ST_FAIL_IMAGE, ST_FORM_TEAM, ST_CHANGE_TEAM,
ST_END_TEAM, ST_SYNC_TEAM, ST_OMP_PARALLEL_MASTER,
@@ -1042,8 +1043,10 @@ typedef struct
/* Mentioned in OMP DECLARE TARGET. */
unsigned omp_declare_target:1;
unsigned omp_declare_target_link:1;
+ unsigned omp_declare_target_local:1;
unsigned omp_declare_target_indirect:1;
ENUM_BITFIELD (gfc_omp_device_type) omp_device_type:2;
+ unsigned omp_groupprivate:1;
unsigned omp_allocate:1;
/* Mentioned in OACC DECLARE. */
@@ -1488,6 +1491,7 @@ enum
OMP_LIST_TASK_REDUCTION,
OMP_LIST_DEVICE_RESIDENT,
OMP_LIST_LINK,
+ OMP_LIST_LOCAL,
OMP_LIST_USE_DEVICE,
OMP_LIST_CACHE,
OMP_LIST_IS_DEVICE_PTR,
@@ -1614,6 +1618,14 @@ enum gfc_omp_bind_type
OMP_BIND_THREAD
};
+enum gfc_omp_fallback
+{
+ OMP_FALLBACK_NONE,
+ OMP_FALLBACK_ABORT,
+ OMP_FALLBACK_DEFAULT_MEM,
+ OMP_FALLBACK_NULL
+};
+
typedef struct gfc_omp_assumptions
{
int n_absent, n_contains;
@@ -1649,6 +1661,7 @@ typedef struct gfc_omp_clauses
struct gfc_expr *detach;
struct gfc_expr *depobj;
struct gfc_expr *dist_chunk_size;
+ struct gfc_expr *dyn_groupprivate;
struct gfc_expr *message;
struct gfc_expr *novariants;
struct gfc_expr *nocontext;
@@ -1681,6 +1694,7 @@ typedef struct gfc_omp_clauses
ENUM_BITFIELD (gfc_omp_at_type) at:2;
ENUM_BITFIELD (gfc_omp_severity_type) severity:2;
ENUM_BITFIELD (gfc_omp_sched_kind) dist_sched_kind:3;
+ ENUM_BITFIELD (gfc_omp_fallback) fallback:2;
/* OpenACC. */
struct gfc_expr *async_expr;
@@ -1958,6 +1972,7 @@ typedef struct gfc_symbol
/* List of PDT parameter expressions */
struct gfc_actual_arglist *param_list;
+ struct gfc_symbol *template_sym;
struct gfc_expr *value; /* Parameter/Initializer value */
gfc_array_spec *as;
@@ -2117,6 +2132,8 @@ typedef struct gfc_common_head
char use_assoc, saved, threadprivate;
unsigned char omp_declare_target : 1;
unsigned char omp_declare_target_link : 1;
+ unsigned char omp_declare_target_local : 1;
+ unsigned char omp_groupprivate : 1;
ENUM_BITFIELD (gfc_omp_device_type) omp_device_type:2;
/* Provide sufficient space to hold "symbol.symbol.eq.1234567890". */
char name[2*GFC_MAX_SYMBOL_LEN + 1 + 14 + 1];
@@ -3101,6 +3118,8 @@ typedef struct gfc_forall_iterator
{
gfc_expr *var, *start, *end, *stride;
gfc_loop_annot annot;
+ /* index-name shadows a variable from outer scope. */
+ bool shadow;
struct gfc_forall_iterator *next;
}
gfc_forall_iterator;
@@ -3714,6 +3733,9 @@ bool gfc_add_threadprivate (symbol_attribute *, const char *, locus *);
bool gfc_add_omp_declare_target (symbol_attribute *, const char *, locus *);
bool gfc_add_omp_declare_target_link (symbol_attribute *, const char *,
locus *);
+bool gfc_add_omp_declare_target_local (symbol_attribute *, const char *,
+ locus *);
+bool gfc_add_omp_groupprivate (symbol_attribute *, const char *, locus *);
bool gfc_add_target (symbol_attribute *, locus *);
bool gfc_add_dummy (symbol_attribute *, const char *, locus *);
bool gfc_add_generic (symbol_attribute *, const char *, locus *);
@@ -3760,6 +3782,7 @@ gfc_st_label *gfc_get_st_label (int);
void gfc_free_st_label (gfc_st_label *);
void gfc_define_st_label (gfc_st_label *, gfc_sl_type, locus *);
bool gfc_reference_st_label (gfc_st_label *, gfc_sl_type);
+gfc_st_label *gfc_rebind_label (gfc_st_label *, int);
gfc_namespace *gfc_get_namespace (gfc_namespace *, int);
gfc_symtree *gfc_new_symtree (gfc_symtree **, const char *);
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 841f613..0f7572b 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -1186,7 +1186,6 @@ extensions.
@menu
* Extensions implemented in GNU Fortran::
* Extensions not implemented in GNU Fortran::
-* Experimental features for future Fortran versions::
@end menu
@@ -1242,6 +1241,7 @@ additional compatibility extensions along with those enabled by
* Extended I/O specifiers::
* Legacy PARAMETER statements::
* Default exponents::
+* Unsigned integers::
@end menu
@node Old-style kind specifications
@@ -1839,7 +1839,7 @@ in free form; and the @code{c$}, @code{*$} and @code{!$} sentinels
in fixed form, @command{gfortran} needs to be invoked with the
@option{-fopenmp} option. This option also arranges for automatic linking
of the OpenMP runtime library.
-@xref{,,,libgomp,GNU Offloading and Multi Processing Runtime Library}.
+@xref{Top,,,libgomp,GNU Offloading and Multi Processing Runtime Library}.
The OpenMP Fortran runtime library routines are provided both in a
form of a Fortran 90 module named @code{omp_lib} and in a form of
@@ -1900,7 +1900,7 @@ sentinels in free form; and the @code{c$}, @code{*$} and @code{!$}
sentinels in fixed form, @command{gfortran} needs to be invoked with
the @option{-fopenacc} option. This option also arranges for automatic
linking of the OpenACC runtime library.
-@xref{,,,libgomp,GNU Offloading and Multi Processing Runtime Library}.
+@xref{Top,,,libgomp,GNU Offloading and Multi Processing Runtime Library}.
The OpenACC Fortran runtime library routines are provided both in a
form of a Fortran 90 module named @code{openacc} and in a form of a
@@ -2535,6 +2535,141 @@ For compatibility, GNU Fortran supports a default exponent of zero in real
constants with @option{-fdec}. For example, @code{9e} would be
interpreted as @code{9e0}, rather than an error.
+@node Unsigned integers
+@subsection Unsigned integers
+@cindex Unsigned integers
+If the @option{-funsigned} option is given, GNU Fortran supports
+unsigned integers according to
+@uref{https://j3-fortran.org/doc/year/24/24-116.txt, J3/24-116}. The
+data type is called @code{UNSIGNED}. For an unsigned type with @code{n}
+bits, it implements integer arithmetic modulo @code{2**n}, comparable
+to the @code{unsigned} data type in C.
+
+The data type has @code{KIND} numbers comparable to other Fortran data
+types, which can be selected via the @code{SELECTED_UNSIGNED_KIND}
+function.
+
+Mixed arithmetic, comparisons and assignment between @code{UNSIGNED}
+and other types are only possible via explicit conversion. Conversion
+from @code{UNSIGNED} to other types is done via type conversion
+functions like @code{INT} or @code{REAL}. Conversion from other types
+to @code{UNSIGNED} is done via @code{UINT}. Unsigned variables cannot be
+used as index variables in @code{DO} loops or as array indices.
+
+Unsigned numbers have a trailing @code{u} as suffix, optionally followed
+by a @code{KIND} number separated by an underscore.
+
+Input and output can be done using the @samp{I}, @samp{B}, @samp{O}
+and @samp{Z} descriptors, plus unformatted I/O.
+
+Unsigned integers as implemented in gfortran are compatible with flang.
+
+Here is a small, somewhat contrived example of their use:
+@smallexample
+program main
+ use iso_fortran_env, only : uint64
+ unsigned(kind=uint64) :: v
+ v = huge(v) - 32u_uint64
+ print *,v
+end program main
+@end smallexample
+@noindent
+which outputs the number 18446744073709551583.
+
+Arithmetic operations work on unsigned integers, also for
+exponentiation. As an extension to J3/24-116.txt, unary minus
+and exponentiation of unsigned integers are permitted unless
+@code{-pedantic} is in force.
+
+In intrinsic procedures, unsigned arguments are typically permitted
+for arguments for the data to be processed, analogous to the
+use of @code{REAL} arguments. Unsigned values are prohibited
+as index variables in @code{DO} loops and as array indices.
+
+Unsigned numbers can be read and written using list-directed,
+formatted and unformatted I/O. For formatted I/O, the @samp{B},
+@samp{I}, @samp{O} and @samp{Z} descriptors are valid. Negative
+values and values that would overflow are rejected with
+@code{-pedantic}.
+
+@code{SELECT CASE} is supported for unsigned integers.
+
+The following intrinsics take unsigned arguments:
+@itemize @bullet
+@item @code{BGE}, @pxref{BGE}
+@item @code{BGT}, @pxref{BGT}
+@item @code{BIT_SIZE}, @pxref{BIT_SIZE}
+@item @code{BLE}, @pxref{BLE}
+@item @code{BLT}, @pxref{BLT}
+@item @code{CMPLX}, @pxref{CMPLX}
+@item @code{CSHIFT}, @pxref{CSHIFT}
+@item @code{DIGITS}, @pxref{DIGITS}
+@item @code{DOT_PRODUCT}, @pxref{DOT_PRODUCT}
+@item @code{DSHIFTL}, @pxref{DSHIFTL}
+@item @code{DSHIFTR}, @pxref{DSHIFTR}
+@item @code{EOSHIFT}, @pxref{EOSHIFT}
+@item @code{FINDLOC}, @pxref{FINDLOC}
+@item @code{HUGE}, @pxref{HUGE}
+@item @code{IALL}, @pxref{IALL}
+@item @code{IAND}, @pxref{IAND}
+@item @code{IANY}, @pxref{IANY}
+@item @code{IBCLR}, @pxref{IBCLR}
+@item @code{IBITS}, @pxref{IBITS}
+@item @code{IBSET}, @pxref{IBSET}
+@item @code{IEOR}, @pxref{IEOR}
+@item @code{INT}, @pxref{INT}
+@item @code{IOR}, @pxref{IOR}
+@item @code{IPARITY}, @pxref{IPARITY}
+@item @code{ISHFT}, @pxref{ISHFT}
+@item @code{ISHFTC}, @pxref{ISHFTC}
+@item @code{MATMUL}, @pxref{MATMUL}
+@item @code{MAX}, @pxref{MAX}
+@item @code{MAXLOC}, @pxref{MAXLOC}
+@item @code{MAXVAL}, @pxref{MAXVAL}
+@item @code{MERGE}, @pxref{MERGE}
+@item @code{MERGE_BITS}, @pxref{MERGE_BITS}
+@item @code{MIN}, @pxref{MIN}
+@item @code{MINLOC}, @pxref{MINLOC}
+@item @code{MINVAL}, @pxref{MINVAL}
+@item @code{MOD}, @pxref{MOD}
+@item @code{MODULO}, @pxref{MODULO}
+@item @code{MVBITS}, @pxref{MVBITS}
+@item @code{NOT}, @pxref{NOT}
+@item @code{OUT_OF_RANGE}, @pxref{OUT_OF_RANGE}
+@item @code{PRODUCT}, @pxref{PRODUCT}
+@item @code{RANDOM_NUMBER}, @pxref{RANDOM_NUMBER}
+@item @code{RANGE}, @pxref{RANGE}
+@item @code{REAL}, @pxref{REAL}
+@item @code{SHIFTA}, @pxref{SHIFTA}
+@item @code{SHIFTL}, @pxref{SHIFTL}
+@item @code{SHIFTR}, @pxref{SHIFTR}
+@item @code{SUM}, @pxref{SUM}
+@item @code{TRANSPOSE}, @pxref{TRANSPOSE}
+@item @code{TRANSFER}, @pxref{TRANSFER}
+@end itemize
+
+The following intrinsics are enabled with @option{-funsigned}:
+@itemize @bullet
+@item @code{UINT}, @pxref{UINT}
+@item @code{UMASKL}, @pxref{UMASKL}
+@item @code{UMASKR}, @pxref{UMASKR}
+@item @code{SELECTED_UNSIGNED_KIND}, @pxref{SELECTED_UNSIGNED_KIND}
+@end itemize
+
+The following constants have been added to the intrinsic
+@code{ISO_C_BINDING} module: @code{c_unsigned},
+@code{c_unsigned_short}, @code{c_unsigned_char},
+@code{c_unsigned_long}, @code{c_unsigned_long_long},
+@code{c_uintmax_t}, @code{c_uint8_t}, @code{c_uint16_t},
+@code{c_uint32_t}, @code{c_uint64_t}, @code{c_uint128_t},
+@code{c_uint_fast8_t}, @code{c_uint_fast16_t}, @code{c_uint_fast32_t},
+@code{c_uint_fast64_t}, @code{c_uint_fast128_t},
+@code{c_uint_least8_t}, @code{c_uint_least16_t}, @code{c_uint_least32_t},
+@code{c_uint_least64_t} and @code{c_uint_least128_t}.
+
+The following constants have been added to the intrinsic
+@code{ISO_FORTRAN_ENV} module: @code{uint8}, @code{uint16},
+@code{uint32} and @code{uint64}.
@node Extensions not implemented in GNU Fortran
@section Extensions not implemented in GNU Fortran
@@ -2715,157 +2850,6 @@ descriptor occurred, use @code{INQUIRE} to get the file position,
count the characters up to the next @code{NEW_LINE} and then start
reading from the position marked previously.
-@node Experimental features for future Fortran versions
-@section Experimental features future Fortran versions
-@cindex Future Fortran versions
-
-GNU Fortran supports some experimental features that have been
-proposed and accepted by the J3 standards committee. These
-exist to give users a chance to try them out, and to provide
-a reference implementation.
-
-As these features have not been included in the worklist for Fortran
-202Y by WG5, there is a chance that a version in any upcoming standard
-will differ from what GNU Fortran currently implements. These
-features are therefore currently classified as an extension.
-
-@menu
-* Unsigned integers::
-@end menu
-
-@node Unsigned integers
-@subsection Unsigned integers
-@cindex Unsigned integers
-If the @option{-funsigned} option is given, GNU Fortran supports
-unsigned integers according to
-@uref{https://j3-fortran.org/doc/year/24/24-116.txt, J3/24-116}. The
-data type is called @code{UNSIGNED}. For an unsigned type with @code{n}
-bits, it implements integer arithmetic modulo @code{2**n}, comparable
-to the @code{unsigned} data type in C.
-
-The data type has @code{KIND} numbers comparable to other Fortran data
-types, which can be selected via the @code{SELECTED_UNSIGNED_KIND}
-function.
-
-Mixed arithmetic, comparisons and assignment between @code{UNSIGNED}
-and other types are only possible via explicit conversion. Conversion
-from @code{UNSIGNED} to other types is done via type conversion
-functions like @code{INT} or @code{REAL}. Conversion from other types
-to @code{UNSIGNED} is done via @code{UINT}. Unsigned variables cannot be
-used as index variables in @code{DO} loops or as array indices.
-
-Unsigned numbers have a trailing @code{u} as suffix, optionally followed
-by a @code{KIND} number separated by an underscore.
-
-Input and output can be done using the @samp{I}, @samp{B}, @samp{O}
-and @samp{Z} descriptors, plus unformatted I/O.
-
-Here is a small, somewhat contrived example of their use:
-@smallexample
-program main
- use iso_fortran_env, only : uint64
- unsigned(kind=uint64) :: v
- v = huge(v) - 32u_uint64
- print *,v
-end program main
-@end smallexample
-@noindent
-which outputs the number 18446744073709551583.
-
-Arithmetic operations work on unsigned integers, also for
-exponentiation. As an extension to J3/24-116.txt, unary minus
-and exponentiation of unsigned integers are permitted unless
-@code{-pedantic} is in force.
-
-In intrinsic procedures, unsigned arguments are typically permitted
-for arguments for the data to be processed, analogous to the
-use of @code{REAL} arguments. Unsigned values are prohibited
-as index variables in @code{DO} loops and as array indices.
-
-Unsigned numbers can be read and written using list-directed,
-formatted and unformatted I/O. For formatted I/O, the @samp{B},
-@samp{I}, @samp{O} and @samp{Z} descriptors are valid. Negative
-values and values that would overflow are rejected with
-@code{-pedantic}.
-
-@code{SELECT CASE} is supported for unsigned integers.
-
-The following intrinsics take unsigned arguments:
-@itemize @bullet
-@item @code{BGE}, @pxref{BGE}
-@item @code{BGT}, @pxref{BGT}
-@item @code{BIT_SIZE}, @pxref{BIT_SIZE}
-@item @code{BLE}, @pxref{BLE}
-@item @code{BLT}, @pxref{BLT}
-@item @code{CMPLX}, @pxref{CMPLX}
-@item @code{CSHIFT}, @pxref{CSHIFT}
-@item @code{DIGITS}, @pxref{DIGITS}
-@item @code{DOT_PRODUCT}, @pxref{DOT_PRODUCT}
-@item @code{DSHIFTL}, @pxref{DSHIFTL}
-@item @code{DSHIFTR}, @pxref{DSHIFTR}
-@item @code{EOSHIFT}, @pxref{EOSHIFT}
-@item @code{FINDLOC}, @pxref{FINDLOC}
-@item @code{HUGE}, @pxref{HUGE}
-@item @code{IALL}, @pxref{IALL}
-@item @code{IAND}, @pxref{IAND}
-@item @code{IANY}, @pxref{IANY}
-@item @code{IBCLR}, @pxref{IBCLR}
-@item @code{IBITS}, @pxref{IBITS}
-@item @code{IBSET}, @pxref{IBSET}
-@item @code{IEOR}, @pxref{IEOR}
-@item @code{INT}, @pxref{INT}
-@item @code{IOR}, @pxref{IOR}
-@item @code{IPARITY}, @pxref{IPARITY}
-@item @code{ISHFT}, @pxref{ISHFT}
-@item @code{ISHFTC}, @pxref{ISHFTC}
-@item @code{MATMUL}, @pxref{MATMUL}
-@item @code{MAX}, @pxref{MAX}
-@item @code{MAXLOC}, @pxref{MAXLOC}
-@item @code{MAXVAL}, @pxref{MAXVAL}
-@item @code{MERGE}, @pxref{MERGE}
-@item @code{MERGE_BITS}, @pxref{MERGE_BITS}
-@item @code{MIN}, @pxref{MIN}
-@item @code{MINLOC}, @pxref{MINLOC}
-@item @code{MINVAL}, @pxref{MINVAL}
-@item @code{MOD}, @pxref{MOD}
-@item @code{MODULO}, @pxref{MODULO}
-@item @code{MVBITS}, @pxref{MVBITS}
-@item @code{NOT}, @pxref{NOT}
-@item @code{OUT_OF_RANGE}, @pxref{OUT_OF_RANGE}
-@item @code{PRODUCT}, @pxref{PRODUCT}
-@item @code{RANDOM_NUMBER}, @pxref{RANDOM_NUMBER}
-@item @code{RANGE}, @pxref{RANGE}
-@item @code{REAL}, @pxref{REAL}
-@item @code{SHIFTA}, @pxref{SHIFTA}
-@item @code{SHIFTL}, @pxref{SHIFTL}
-@item @code{SHIFTR}, @pxref{SHIFTR}
-@item @code{SUM}, @pxref{SUM}
-@item @code{TRANSPOSE}, @pxref{TRANSPOSE}
-@item @code{TRANSFER}, @pxref{TRANSFER}
-@end itemize
-
-The following intrinsics are enabled with @option{-funsigned}:
-@itemize @bullet
-@item @code{UINT}, @pxref{UINT}
-@item @code{UMASKL}, @pxref{UMASKL}
-@item @code{UMASKR}, @pxref{UMASKR}
-@item @code{SELECTED_UNSIGNED_KIND}, @pxref{SELECTED_UNSIGNED_KIND}
-@end itemize
-
-The following constants have been added to the intrinsic
-@code{ISO_C_BINDING} module: @code{c_unsigned},
-@code{c_unsigned_short}, @code{c_unsigned_char},
-@code{c_unsigned_long}, @code{c_unsigned_long_long},
-@code{c_uintmax_t}, @code{c_uint8_t}, @code{c_uint16_t},
-@code{c_uint32_t}, @code{c_uint64_t}, @code{c_uint128_t},
-@code{c_uint_fast8_t}, @code{c_uint_fast16_t}, @code{c_uint_fast32_t},
-@code{c_uint_fast64_t}, @code{c_uint_fast128_t},
-@code{c_uint_least8_t}, @code{c_uint_least16_t}, @code{c_uint_least32_t},
-@code{c_uint_least64_t} and @code{c_uint_least128_t}.
-
-The following constants have been added to the intrinsic
-@code{ISO_FORTRAN_ENV} module: @code{uint8}, @code{uint16},
-@code{uint32} and @code{uint64}.
@c ---------------------------------------------------------------------
@c ---------------------------------------------------------------------
diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi
index b2d1e45..c4c000b 100644
--- a/gcc/fortran/intrinsic.texi
+++ b/gcc/fortran/intrinsic.texi
@@ -15546,7 +15546,7 @@ Fortran 2008 and later
@node UINT
@section @code{UINT} -- Convert to @code{UNSIGNED} type
@fnindex UINT
-@cindex, conversion, to unsigned
+@cindex conversion, to unsigned
@table @asis
@item @emph{Synopsis}:
@@ -16250,6 +16250,7 @@ The following scalar default-integer named constants:
@table @asis
@item @code{omp_initial_device}
@item @code{omp_invalid_device}
+@item @code{omp_default_device}
@end table
diff --git a/gcc/fortran/lang.opt.urls b/gcc/fortran/lang.opt.urls
index 4a51f5a..cdb0ba8 100644
--- a/gcc/fortran/lang.opt.urls
+++ b/gcc/fortran/lang.opt.urls
@@ -1,8 +1,5 @@
; Autogenerated by regenerate-opt-urls.py from gcc/fortran/lang.opt and generated HTML
-A
-UrlSuffix(gcc/Preprocessor-Options.html#index-A)
-
C
UrlSuffix(gcc/Preprocessor-Options.html#index-C) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-C)
@@ -20,7 +17,7 @@ H
UrlSuffix(gcc/Preprocessor-Options.html#index-H) LangUrlSuffix_D(gdc/Code-Generation.html#index-H) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-H)
I
-UrlSuffix(gcc/Directory-Options.html#index-I) LangUrlSuffix_D(gdc/Directory-Options.html#index-I)
+UrlSuffix(gcc/Directory-Options.html#index-I) LangUrlSuffix_D(gdc/Directory-Options.html#index-I) LangUrlSuffix_Algol68(ga68/Directory-options.html#index-I)
J
LangUrlSuffix_D(gdc/Directory-Options.html#index-J)
@@ -428,7 +425,7 @@ fcoarray=
LangUrlSuffix_Fortran(gfortran/Code-Gen-Options.html#index-fcoarray)
fcheck=
-LangUrlSuffix_Fortran(gfortran/Code-Gen-Options.html#index-fcheck)
+LangUrlSuffix_Fortran(gfortran/Code-Gen-Options.html#index-fcheck) LangUrlSuffix_Algol68(ga68/Runtime-options.html#index-fcheck)
fsecond-underscore
LangUrlSuffix_Fortran(gfortran/Code-Gen-Options.html#index-fsecond-underscore)
diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc
index 8355a39..e009c82 100644
--- a/gcc/fortran/match.cc
+++ b/gcc/fortran/match.cc
@@ -2608,7 +2608,66 @@ cleanup:
}
-/* Match the header of a FORALL statement. */
+/* Apply type-spec to iterator and create shadow variable if needed. */
+
+static void
+apply_typespec_to_iterator (gfc_forall_iterator *iter, gfc_typespec *ts,
+ locus *loc)
+{
+ char *name;
+ gfc_expr *v;
+ gfc_symtree *st;
+
+ /* When a type-spec is provided in DO CONCURRENT/FORALL, F2018 19.4(6)
+ requires the index-name to have scope limited to the construct,
+ shadowing any variable with the same name from outer scope.
+ If the index-name was not previously declared, we can simply set its
+ type. Otherwise, create a shadow variable with "_" prefix. */
+ iter->shadow = false;
+ v = iter->var;
+ if (v->ts.type == BT_UNKNOWN)
+ {
+ /* Variable not declared in outer scope - just set the type. */
+ v->ts.type = v->symtree->n.sym->ts.type = BT_INTEGER;
+ v->ts.kind = v->symtree->n.sym->ts.kind = ts->kind;
+ gfc_set_sym_referenced (v->symtree->n.sym);
+ }
+ else
+ {
+ /* Variable exists in outer scope - must create shadow to comply
+ with F2018 19.4(6) scoping rules. */
+ name = (char *) alloca (strlen (v->symtree->name) + 2);
+ strcpy (name, "_");
+ strcat (name, v->symtree->name);
+ if (gfc_get_sym_tree (name, NULL, &st, false) != 0)
+ gfc_internal_error ("Failed to create shadow variable symtree for "
+ "DO CONCURRENT type-spec at %L", loc);
+
+ v = gfc_get_expr ();
+ v->where = gfc_current_locus;
+ v->expr_type = EXPR_VARIABLE;
+ v->ts.type = st->n.sym->ts.type = ts->type;
+ v->ts.kind = st->n.sym->ts.kind = ts->kind;
+ st->n.sym->forall_index = true;
+ v->symtree = st;
+ gfc_replace_expr (iter->var, v);
+ iter->shadow = true;
+ gfc_set_sym_referenced (st->n.sym);
+ }
+
+ /* Convert iterator bounds to the specified type. */
+ gfc_convert_type (iter->start, ts, 1);
+ gfc_convert_type (iter->end, ts, 1);
+ gfc_convert_type (iter->stride, ts, 1);
+}
+
+
+/* Match the header of a FORALL statement. In F2008 and F2018, the form of
+ the header is:
+
+ ([ type-spec :: ] concurrent-control-list [, scalar-mask-expr ] )
+
+ where type-spec is INTEGER. */
static match
match_forall_header (gfc_forall_iterator **phead, gfc_expr **mask)
@@ -2616,6 +2675,9 @@ match_forall_header (gfc_forall_iterator **phead, gfc_expr **mask)
gfc_forall_iterator *head, *tail, *new_iter;
gfc_expr *msk;
match m;
+ gfc_typespec ts;
+ bool seen_ts = false;
+ locus loc;
gfc_gobble_whitespace ();
@@ -2625,12 +2687,40 @@ match_forall_header (gfc_forall_iterator **phead, gfc_expr **mask)
if (gfc_match_char ('(') != MATCH_YES)
return MATCH_NO;
+ /* Check for an optional type-spec. */
+ gfc_clear_ts (&ts);
+ loc = gfc_current_locus;
+ m = gfc_match_type_spec (&ts);
+ if (m == MATCH_YES)
+ {
+ seen_ts = (gfc_match (" ::") == MATCH_YES);
+
+ if (seen_ts)
+ {
+ if (!gfc_notify_std (GFC_STD_F2008, "FORALL or DO CONCURRENT "
+ "construct includes type specification "
+ "at %L", &loc))
+ goto cleanup;
+
+ if (ts.type != BT_INTEGER)
+ {
+ gfc_error ("Type-spec at %L must be an INTEGER type", &loc);
+ goto cleanup;
+ }
+ }
+ }
+ else if (m == MATCH_ERROR)
+ goto syntax;
+
m = match_forall_iterator (&new_iter);
if (m == MATCH_ERROR)
goto cleanup;
if (m == MATCH_NO)
goto syntax;
+ if (seen_ts)
+ apply_typespec_to_iterator (new_iter, &ts, &loc);
+
head = tail = new_iter;
for (;;)
@@ -2644,6 +2734,9 @@ match_forall_header (gfc_forall_iterator **phead, gfc_expr **mask)
if (m == MATCH_YES)
{
+ if (seen_ts)
+ apply_typespec_to_iterator (new_iter, &ts, &loc);
+
tail->next = new_iter;
tail = new_iter;
continue;
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 410361c..314be6b 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -174,6 +174,7 @@ match gfc_match_omp_do_simd (void);
match gfc_match_omp_loop (void);
match gfc_match_omp_error (void);
match gfc_match_omp_flush (void);
+match gfc_match_omp_groupprivate (void);
match gfc_match_omp_interop (void);
match gfc_match_omp_masked (void);
match gfc_match_omp_masked_taskloop (void);
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index c489dec..9b845b5 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -2092,7 +2092,8 @@ enum ab_attribute
AB_ARRAY_OUTER_DEPENDENCY, AB_MODULE_PROCEDURE, AB_OACC_DECLARE_CREATE,
AB_OACC_DECLARE_COPYIN, AB_OACC_DECLARE_DEVICEPTR,
AB_OACC_DECLARE_DEVICE_RESIDENT, AB_OACC_DECLARE_LINK,
- AB_OMP_DECLARE_TARGET_LINK, AB_PDT_KIND, AB_PDT_LEN, AB_PDT_TYPE,
+ AB_OMP_DECLARE_TARGET_LINK, AB_OMP_DECLARE_TARGET_LOCAL,
+ AB_PDT_KIND, AB_PDT_LEN, AB_PDT_TYPE,
AB_PDT_COMP, AB_PDT_TEMPLATE, AB_PDT_ARRAY, AB_PDT_STRING,
AB_OACC_ROUTINE_LOP_GANG, AB_OACC_ROUTINE_LOP_WORKER,
AB_OACC_ROUTINE_LOP_VECTOR, AB_OACC_ROUTINE_LOP_SEQ,
@@ -2102,7 +2103,7 @@ enum ab_attribute
AB_OMP_REQ_MEM_ORDER_SEQ_CST, AB_OMP_REQ_MEM_ORDER_ACQ_REL,
AB_OMP_REQ_MEM_ORDER_ACQUIRE, AB_OMP_REQ_MEM_ORDER_RELEASE,
AB_OMP_REQ_MEM_ORDER_RELAXED, AB_OMP_DEVICE_TYPE_NOHOST,
- AB_OMP_DEVICE_TYPE_HOST, AB_OMP_DEVICE_TYPE_ANY
+ AB_OMP_DEVICE_TYPE_HOST, AB_OMP_DEVICE_TYPE_ANY, AB_OMP_GROUPPRIVATE
};
static const mstring attr_bits[] =
@@ -2166,6 +2167,8 @@ static const mstring attr_bits[] =
minit ("OACC_DECLARE_DEVICE_RESIDENT", AB_OACC_DECLARE_DEVICE_RESIDENT),
minit ("OACC_DECLARE_LINK", AB_OACC_DECLARE_LINK),
minit ("OMP_DECLARE_TARGET_LINK", AB_OMP_DECLARE_TARGET_LINK),
+ minit ("OMP_DECLARE_TARGET_LOCAL", AB_OMP_DECLARE_TARGET_LOCAL),
+ minit ("OMP_GROUPPRIVATE", AB_OMP_GROUPPRIVATE),
minit ("PDT_KIND", AB_PDT_KIND),
minit ("PDT_LEN", AB_PDT_LEN),
minit ("PDT_TYPE", AB_PDT_TYPE),
@@ -2399,6 +2402,10 @@ mio_symbol_attribute (symbol_attribute *attr)
MIO_NAME (ab_attribute) (AB_OACC_DECLARE_LINK, attr_bits);
if (attr->omp_declare_target_link)
MIO_NAME (ab_attribute) (AB_OMP_DECLARE_TARGET_LINK, attr_bits);
+ if (attr->omp_declare_target_local)
+ MIO_NAME (ab_attribute) (AB_OMP_DECLARE_TARGET_LOCAL, attr_bits);
+ if (attr->omp_groupprivate)
+ MIO_NAME (ab_attribute) (AB_OMP_GROUPPRIVATE, attr_bits);
if (attr->pdt_kind)
MIO_NAME (ab_attribute) (AB_PDT_KIND, attr_bits);
if (attr->pdt_len)
@@ -2654,6 +2661,12 @@ mio_symbol_attribute (symbol_attribute *attr)
case AB_OMP_DECLARE_TARGET_LINK:
attr->omp_declare_target_link = 1;
break;
+ case AB_OMP_DECLARE_TARGET_LOCAL:
+ attr->omp_declare_target_local = 1;
+ break;
+ case AB_OMP_GROUPPRIVATE:
+ attr->omp_groupprivate = 1;
+ break;
case AB_ARRAY_OUTER_DEPENDENCY:
attr->array_outer_dependency =1;
break;
@@ -5268,6 +5281,8 @@ load_commons (void)
if (flags & 2)
p->threadprivate = 1;
p->omp_device_type = (gfc_omp_device_type) ((flags >> 2) & 3);
+ if ((flags >> 4) & 1)
+ p->omp_groupprivate = 1;
p->use_assoc = 1;
/* Get whether this was a bind(c) common or not. */
@@ -5827,6 +5842,20 @@ read_module (void)
|| startswith (name, "__vtype_")))
p = name;
+ /* Include pdt_types if their associated pdt_template is in a
+ USE, ONLY list. */
+ if (p == NULL && name[0] == 'P'
+ && startswith (name, "Pdt")
+ && module_list)
+ {
+ gfc_use_list *ml = module_list;
+ for (; ml; ml = ml->next)
+ if (ml->rename
+ && !strncmp (&name[3], ml->rename->use_name,
+ strlen (ml->rename->use_name)))
+ p = name;
+ }
+
/* Skip symtree nodes not in an ONLY clause, unless there
is an existing symtree loaded from another USE statement. */
if (p == NULL)
@@ -6191,6 +6220,7 @@ write_common_0 (gfc_symtree *st, bool this_module)
if (p->threadprivate)
flags |= 2;
flags |= p->omp_device_type << 2;
+ flags |= p->omp_groupprivate << 4;
mio_integer (&flags);
/* Write out whether the common block is bind(c) or not. */
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index f5db9a8..abc27d5 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -84,6 +84,7 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
/* {"flatten", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLATTEN}, */
{"flush", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSH},
/* {"fuse", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSE}, */
+ {"groupprivate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_GROUPPRIVATE},
/* {"interchange", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTERCHANGE}, */
{"interop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTEROP},
{"loop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_LOOP},
@@ -195,6 +196,7 @@ gfc_free_omp_clauses (gfc_omp_clauses *c)
gfc_free_expr (c->num_teams_lower);
gfc_free_expr (c->num_teams_upper);
gfc_free_expr (c->device);
+ gfc_free_expr (c->dyn_groupprivate);
gfc_free_expr (c->thread_limit);
gfc_free_expr (c->dist_chunk_size);
gfc_free_expr (c->grainsize);
@@ -1172,6 +1174,8 @@ enum omp_mask2
OMP_CLAUSE_NOVARIANTS, /* OpenMP 5.1 */
OMP_CLAUSE_NOCONTEXT, /* OpenMP 5.1 */
OMP_CLAUSE_INTEROP, /* OpenMP 5.1 */
+ OMP_CLAUSE_LOCAL, /* OpenMP 6.0 */
+ OMP_CLAUSE_DYN_GROUPPRIVATE, /* OpenMP 6.1 */
/* This must come last. */
OMP_MASK2_LAST
};
@@ -3096,6 +3100,22 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
else
continue;
}
+ if ((mask & OMP_CLAUSE_DYN_GROUPPRIVATE)
+ && gfc_match_dupl_check (!c->dyn_groupprivate,
+ "dyn_groupprivate", true) == MATCH_YES)
+ {
+ if (gfc_match ("fallback ( abort ) : ") == MATCH_YES)
+ c->fallback = OMP_FALLBACK_ABORT;
+ else if (gfc_match ("fallback ( default_mem ) : ") == MATCH_YES)
+ c->fallback = OMP_FALLBACK_DEFAULT_MEM;
+ else if (gfc_match ("fallback ( null ) : ") == MATCH_YES)
+ c->fallback = OMP_FALLBACK_NULL;
+ if (gfc_match_expr (&c->dyn_groupprivate) != MATCH_YES)
+ return MATCH_ERROR;
+ if (gfc_match (" )") != MATCH_YES)
+ goto error;
+ continue;
+ }
break;
case 'e':
if ((mask & OMP_CLAUSE_ENTER))
@@ -3567,6 +3587,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
&c->lists[OMP_LIST_LINK])
== MATCH_YES))
continue;
+ if ((mask & OMP_CLAUSE_LOCAL)
+ && (gfc_match_omp_to_link ("local (", &c->lists[OMP_LIST_LOCAL])
+ == MATCH_YES))
+ continue;
break;
case 'm':
if ((mask & OMP_CLAUSE_MAP)
@@ -5064,7 +5088,8 @@ cleanup:
| OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULTMAP \
| OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION \
| OMP_CLAUSE_THREAD_LIMIT | OMP_CLAUSE_ALLOCATE \
- | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS)
+ | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS \
+ | OMP_CLAUSE_DYN_GROUPPRIVATE)
#define OMP_TARGET_DATA_CLAUSES \
(omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF \
| OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR)
@@ -5092,7 +5117,7 @@ cleanup:
(omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
#define OMP_DECLARE_TARGET_CLAUSES \
(omp_mask (OMP_CLAUSE_ENTER) | OMP_CLAUSE_LINK | OMP_CLAUSE_DEVICE_TYPE \
- | OMP_CLAUSE_TO | OMP_CLAUSE_INDIRECT)
+ | OMP_CLAUSE_TO | OMP_CLAUSE_INDIRECT | OMP_CLAUSE_LOCAL)
#define OMP_ATOMIC_CLAUSES \
(omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT \
| OMP_CLAUSE_MEMORDER | OMP_CLAUSE_COMPARE | OMP_CLAUSE_FAIL \
@@ -6113,7 +6138,7 @@ gfc_match_omp_declare_target (void)
gfc_buffer_error (false);
static const int to_enter_link_lists[]
- = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK };
+ = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK, OMP_LIST_LOCAL };
for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists)
&& (list = to_enter_link_lists[listn], true); ++listn)
for (n = c->lists[list]; n; n = n->next)
@@ -6122,6 +6147,8 @@ gfc_match_omp_declare_target (void)
else if (n->u.common->head)
n->u.common->head->mark = 0;
+ if (c->device_type == OMP_DEVICE_TYPE_UNSET)
+ c->device_type = OMP_DEVICE_TYPE_ANY;
for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists)
&& (list = to_enter_link_lists[listn], true); ++listn)
for (n = c->lists[list]; n; n = n->next)
@@ -6130,105 +6157,161 @@ gfc_match_omp_declare_target (void)
if (n->sym->attr.in_common)
gfc_error_now ("OMP DECLARE TARGET variable at %L is an "
"element of a COMMON block", &n->where);
+ else if (n->sym->attr.omp_groupprivate && list != OMP_LIST_LOCAL)
+ gfc_error_now ("List item %qs at %L not appear in the %qs clause "
+ "as it was previously specified in a GROUPPRIVATE "
+ "directive", n->sym->name, &n->where,
+ list == OMP_LIST_LINK
+ ? "link" : list == OMP_LIST_TO ? "to" : "enter");
else if (n->sym->mark)
gfc_error_now ("Variable at %L mentioned multiple times in "
"clauses of the same OMP DECLARE TARGET directive",
&n->where);
- else if (n->sym->attr.omp_declare_target
- && n->sym->attr.omp_declare_target_link
- && list != OMP_LIST_LINK)
+ else if ((n->sym->attr.omp_declare_target_link
+ || n->sym->attr.omp_declare_target_local)
+ && list != OMP_LIST_LINK
+ && list != OMP_LIST_LOCAL)
gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
- "mentioned in LINK clause and later in %s clause",
- &n->where, list == OMP_LIST_TO ? "TO" : "ENTER");
+ "mentioned in %s clause and later in %s clause",
+ &n->where,
+ n->sym->attr.omp_declare_target_link ? "LINK"
+ : "LOCAL",
+ list == OMP_LIST_TO ? "TO" : "ENTER");
else if (n->sym->attr.omp_declare_target
- && !n->sym->attr.omp_declare_target_link
- && list == OMP_LIST_LINK)
+ && (list == OMP_LIST_LINK || list == OMP_LIST_LOCAL))
gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
"mentioned in TO or ENTER clause and later in "
- "LINK clause", &n->where);
- else if (gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
- &n->sym->declared_at))
+ "%s clause", &n->where,
+ list == OMP_LIST_LINK ? "LINK" : "LOCAL");
+ else
{
+ if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+ gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
+ &n->sym->declared_at);
if (list == OMP_LIST_LINK)
gfc_add_omp_declare_target_link (&n->sym->attr, n->sym->name,
&n->sym->declared_at);
+ if (list == OMP_LIST_LOCAL)
+ gfc_add_omp_declare_target_local (&n->sym->attr, n->sym->name,
+ &n->sym->declared_at);
+ }
+ if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && n->sym->attr.omp_device_type != c->device_type)
+ {
+ const char *dt = "any";
+ if (n->sym->attr.omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ else if (n->sym->attr.omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ if (n->sym->attr.omp_groupprivate)
+ gfc_error_now ("List item %qs at %L set in previous OMP "
+ "GROUPPRIVATE directive to the different "
+ "DEVICE_TYPE %qs", n->sym->name, &n->where, dt);
+ else
+ gfc_error_now ("List item %qs at %L set in previous OMP "
+ "DECLARE TARGET directive to the different "
+ "DEVICE_TYPE %qs", n->sym->name, &n->where, dt);
}
- if (c->device_type != OMP_DEVICE_TYPE_UNSET)
- {
- if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && n->sym->attr.omp_device_type != c->device_type)
- gfc_error_now ("List item %qs at %L set in previous OMP DECLARE "
- "TARGET directive to a different DEVICE_TYPE",
- n->sym->name, &n->where);
- n->sym->attr.omp_device_type = c->device_type;
- }
- if (c->indirect)
+ n->sym->attr.omp_device_type = c->device_type;
+ if (c->indirect && c->device_type != OMP_DEVICE_TYPE_ANY)
{
- if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_ANY)
- gfc_error_now ("DEVICE_TYPE must be ANY when used with "
- "INDIRECT at %L", &n->where);
- n->sym->attr.omp_declare_target_indirect = c->indirect;
+ gfc_error_now ("DEVICE_TYPE must be ANY when used with INDIRECT "
+ "at %L", &n->where);
+ c->indirect = 0;
}
-
+ n->sym->attr.omp_declare_target_indirect = c->indirect;
+ if (list == OMP_LIST_LINK && c->device_type == OMP_DEVICE_TYPE_NOHOST)
+ gfc_error_now ("List item %qs at %L set with NOHOST specified may "
+ "not appear in a LINK clause", n->sym->name,
+ &n->where);
n->sym->mark = 1;
}
- else if (n->u.common->omp_declare_target
- && n->u.common->omp_declare_target_link
- && list != OMP_LIST_LINK)
- gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
- "mentioned in LINK clause and later in %s clause",
- &n->where, list == OMP_LIST_TO ? "TO" : "ENTER");
- else if (n->u.common->omp_declare_target
- && !n->u.common->omp_declare_target_link
- && list == OMP_LIST_LINK)
- gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
- "mentioned in TO or ENTER clause and later in "
- "LINK clause", &n->where);
- else if (n->u.common->head && n->u.common->head->mark)
- gfc_error_now ("COMMON at %L mentioned multiple times in "
- "clauses of the same OMP DECLARE TARGET directive",
- &n->where);
- else
- {
- n->u.common->omp_declare_target = 1;
- n->u.common->omp_declare_target_link = (list == OMP_LIST_LINK);
+ else /* common block */
+ {
+ if (n->u.common->omp_groupprivate && list != OMP_LIST_LOCAL)
+ gfc_error_now ("Common block %</%s/%> at %L not appear in the %qs "
+ "clause as it was previously specified in a "
+ "GROUPPRIVATE directive",
+ n->u.common->name, &n->where,
+ list == OMP_LIST_LINK
+ ? "link" : list == OMP_LIST_TO ? "to" : "enter");
+ else if (n->u.common->head && n->u.common->head->mark)
+ gfc_error_now ("Common block %</%s/%> at %L mentioned multiple "
+ "times in clauses of the same OMP DECLARE TARGET "
+ "directive", n->u.common->name, &n->where);
+ else if ((n->u.common->omp_declare_target_link
+ || n->u.common->omp_declare_target_local)
+ && list != OMP_LIST_LINK
+ && list != OMP_LIST_LOCAL)
+ gfc_error_now ("Common block %</%s/%> at %L previously mentioned "
+ "in %s clause and later in %s clause",
+ n->u.common->name, &n->where,
+ n->u.common->omp_declare_target_link ? "LINK"
+ : "LOCAL",
+ list == OMP_LIST_TO ? "TO" : "ENTER");
+ else if (n->u.common->omp_declare_target
+ && (list == OMP_LIST_LINK || list == OMP_LIST_LOCAL))
+ gfc_error_now ("Common block %</%s/%> at %L previously mentioned "
+ "in TO or ENTER clause and later in %s clause",
+ n->u.common->name, &n->where,
+ list == OMP_LIST_LINK ? "LINK" : "LOCAL");
if (n->u.common->omp_device_type != OMP_DEVICE_TYPE_UNSET
&& n->u.common->omp_device_type != c->device_type)
- gfc_error_now ("COMMON at %L set in previous OMP DECLARE "
- "TARGET directive to a different DEVICE_TYPE",
- &n->where);
+ {
+ const char *dt = "any";
+ if (n->u.common->omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ else if (n->u.common->omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ if (n->u.common->omp_groupprivate)
+ gfc_error_now ("Common block %</%s/%> at %L set in previous OMP "
+ "GROUPPRIVATE directive to the different "
+ "DEVICE_TYPE %qs", n->u.common->name, &n->where,
+ dt);
+ else
+ gfc_error_now ("Common block %</%s/%> at %L set in previous OMP "
+ "DECLARE TARGET directive to the different "
+ "DEVICE_TYPE %qs", n->u.common->name, &n->where,
+ dt);
+ }
n->u.common->omp_device_type = c->device_type;
+ if (c->indirect && c->device_type != OMP_DEVICE_TYPE_ANY)
+ {
+ gfc_error_now ("DEVICE_TYPE must be ANY when used with INDIRECT "
+ "at %L", &n->where);
+ c->indirect = 0;
+ }
+ if (list == OMP_LIST_LINK && c->device_type == OMP_DEVICE_TYPE_NOHOST)
+ gfc_error_now ("Common block %</%s/%> at %L set with NOHOST "
+ "specified may not appear in a LINK clause",
+ n->u.common->name, &n->where);
+
+ if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+ n->u.common->omp_declare_target = 1;
+ if (list == OMP_LIST_LINK)
+ n->u.common->omp_declare_target_link = 1;
+ if (list == OMP_LIST_LOCAL)
+ n->u.common->omp_declare_target_local = 1;
+
for (s = n->u.common->head; s; s = s->common_next)
{
s->mark = 1;
- if (gfc_add_omp_declare_target (&s->attr, s->name,
- &s->declared_at))
- {
- if (list == OMP_LIST_LINK)
- gfc_add_omp_declare_target_link (&s->attr, s->name,
- &s->declared_at);
- }
- if (s->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && s->attr.omp_device_type != c->device_type)
- gfc_error_now ("List item %qs at %L set in previous OMP DECLARE"
- " TARGET directive to a different DEVICE_TYPE",
- s->name, &n->where);
+ if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+ gfc_add_omp_declare_target (&s->attr, s->name, &n->where);
+ if (list == OMP_LIST_LINK)
+ gfc_add_omp_declare_target_link (&s->attr, s->name, &n->where);
+ if (list == OMP_LIST_LOCAL)
+ gfc_add_omp_declare_target_local (&s->attr, s->name, &n->where);
s->attr.omp_device_type = c->device_type;
-
- if (c->indirect
- && s->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && s->attr.omp_device_type != OMP_DEVICE_TYPE_ANY)
- gfc_error_now ("DEVICE_TYPE must be ANY when used with "
- "INDIRECT at %L", &n->where);
s->attr.omp_declare_target_indirect = c->indirect;
}
}
if ((c->device_type || c->indirect)
&& !c->lists[OMP_LIST_ENTER]
&& !c->lists[OMP_LIST_TO]
- && !c->lists[OMP_LIST_LINK])
+ && !c->lists[OMP_LIST_LINK]
+ && !c->lists[OMP_LIST_LOCAL])
gfc_warning_now (OPT_Wopenmp,
"OMP DECLARE TARGET directive at %L with only "
"DEVICE_TYPE or INDIRECT clauses is ignored",
@@ -7108,32 +7191,44 @@ gfc_match_omp_metadirective (void)
return match_omp_metadirective (false);
}
-match
-gfc_match_omp_threadprivate (void)
+/* Match 'omp threadprivate' or 'omp groupprivate'. */
+static match
+gfc_match_omp_thread_group_private (bool is_groupprivate)
{
locus old_loc;
char n[GFC_MAX_SYMBOL_LEN+1];
gfc_symbol *sym;
match m;
gfc_symtree *st;
+ struct sym_loc_t { gfc_symbol *sym; gfc_common_head *com; locus loc; };
+ auto_vec<sym_loc_t> syms;
old_loc = gfc_current_locus;
- m = gfc_match (" (");
+ m = gfc_match (" ( ");
if (m != MATCH_YES)
return m;
for (;;)
{
+ locus sym_loc = gfc_current_locus;
m = gfc_match_symbol (&sym, 0);
switch (m)
{
case MATCH_YES:
if (sym->attr.in_common)
- gfc_error_now ("Threadprivate variable at %C is an element of "
- "a COMMON block");
- else if (!gfc_add_threadprivate (&sym->attr, sym->name, &sym->declared_at))
+ gfc_error_now ("%qs variable at %L is an element of a COMMON block",
+ is_groupprivate ? "groupprivate" : "threadprivate",
+ &sym_loc);
+ else if (!is_groupprivate
+ && !gfc_add_threadprivate (&sym->attr, sym->name, &sym_loc))
goto cleanup;
+ else if (is_groupprivate)
+ {
+ if (!gfc_add_omp_groupprivate (&sym->attr, sym->name, &sym_loc))
+ goto cleanup;
+ syms.safe_push ({sym, nullptr, sym_loc});
+ }
goto next_item;
case MATCH_NO:
break;
@@ -7150,12 +7245,20 @@ gfc_match_omp_threadprivate (void)
st = gfc_find_symtree (gfc_current_ns->common_root, n);
if (st == NULL)
{
- gfc_error ("COMMON block /%s/ not found at %C", n);
+ gfc_error ("COMMON block /%s/ not found at %L", n, &sym_loc);
goto cleanup;
}
- st->n.common->threadprivate = 1;
+ syms.safe_push ({nullptr, st->n.common, sym_loc});
+ if (is_groupprivate)
+ st->n.common->omp_groupprivate = 1;
+ else
+ st->n.common->threadprivate = 1;
for (sym = st->n.common->head; sym; sym = sym->common_next)
- if (!gfc_add_threadprivate (&sym->attr, sym->name, &sym->declared_at))
+ if (!is_groupprivate
+ && !gfc_add_threadprivate (&sym->attr, sym->name, &sym_loc))
+ goto cleanup;
+ else if (is_groupprivate
+ && !gfc_add_omp_groupprivate (&sym->attr, sym->name, &sym_loc))
goto cleanup;
next_item:
@@ -7165,16 +7268,89 @@ gfc_match_omp_threadprivate (void)
goto syntax;
}
+ if (is_groupprivate)
+ {
+ gfc_omp_clauses *c;
+ m = gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_DEVICE_TYPE));
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+
+ if (c->device_type == OMP_DEVICE_TYPE_UNSET)
+ c->device_type = OMP_DEVICE_TYPE_ANY;
+
+ for (size_t i = 0; i < syms.length (); i++)
+ if (syms[i].sym)
+ {
+ sym_loc_t &n = syms[i];
+ if (n.sym->attr.in_common)
+ gfc_error_now ("Variable %qs at %L is an element of a COMMON "
+ "block", n.sym->name, &n.loc);
+ else if (n.sym->attr.omp_declare_target
+ || n.sym->attr.omp_declare_target_link)
+ gfc_error_now ("List item %qs at %L implies OMP DECLARE TARGET "
+ "with the LOCAL clause, but it has been specified"
+ " with a different clause before",
+ n.sym->name, &n.loc);
+ if (n.sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && n.sym->attr.omp_device_type != c->device_type)
+ {
+ const char *dt = "any";
+ if (n.sym->attr.omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ else if (n.sym->attr.omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ gfc_error_now ("List item %qs at %L set in previous OMP DECLARE "
+ "TARGET directive to the different DEVICE_TYPE %qs",
+ n.sym->name, &n.loc, dt);
+ }
+ gfc_add_omp_declare_target_local (&n.sym->attr, n.sym->name,
+ &n.loc);
+ n.sym->attr.omp_device_type = c->device_type;
+ }
+ else /* Common block. */
+ {
+ sym_loc_t &n = syms[i];
+ if (n.com->omp_declare_target
+ || n.com->omp_declare_target_link)
+ gfc_error_now ("List item %</%s/%> at %L implies OMP DECLARE "
+ "TARGET with the LOCAL clause, but it has been "
+ "specified with a different clause before",
+ n.com->name, &n.loc);
+ if (n.com->omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && n.com->omp_device_type != c->device_type)
+ {
+ const char *dt = "any";
+ if (n.com->omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ else if (n.com->omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ gfc_error_now ("List item %qs at %L set in previous OMP DECLARE"
+ " TARGET directive to the different DEVICE_TYPE "
+ "%qs", n.com->name, &n.loc, dt);
+ }
+ n.com->omp_declare_target_local = 1;
+ n.com->omp_device_type = c->device_type;
+ for (gfc_symbol *s = n.com->head; s; s = s->common_next)
+ {
+ gfc_add_omp_declare_target_local (&s->attr, s->name, &n.loc);
+ s->attr.omp_device_type = c->device_type;
+ }
+ }
+ free (c);
+ }
+
if (gfc_match_omp_eos () != MATCH_YES)
{
- gfc_error ("Unexpected junk after OMP THREADPRIVATE at %C");
+ gfc_error ("Unexpected junk after OMP %s at %C",
+ is_groupprivate ? "GROUPPRIVATE" : "THREADPRIVATE");
goto cleanup;
}
return MATCH_YES;
syntax:
- gfc_error ("Syntax error in !$OMP THREADPRIVATE list at %C");
+ gfc_error ("Syntax error in !$OMP %s list at %C",
+ is_groupprivate ? "GROUPPRIVATE" : "THREADPRIVATE");
cleanup:
gfc_current_locus = old_loc;
@@ -7183,6 +7359,20 @@ cleanup:
match
+gfc_match_omp_groupprivate (void)
+{
+ return gfc_match_omp_thread_group_private (true);
+}
+
+
+match
+gfc_match_omp_threadprivate (void)
+{
+ return gfc_match_omp_thread_group_private (false);
+}
+
+
+match
gfc_match_omp_parallel (void)
{
return match_omp (EXEC_OMP_PARALLEL, OMP_PARALLEL_CLAUSES);
@@ -8359,9 +8549,9 @@ resolve_omp_udr_clause (gfc_omp_namelist *n, gfc_namespace *ns,
}
/* Assume that a constant expression in the range 1 (omp_default_mem_alloc)
- to 8 (omp_thread_mem_alloc) range, or 200 (ompx_gnu_pinned_mem_alloc) is
- fine. The original symbol name is already lost during matching via
- gfc_match_expr. */
+ to GOMP_OMP_PREDEF_ALLOC_MAX, or GOMP_OMPX_PREDEF_ALLOC_MIN to
+ GOMP_OMPX_PREDEF_ALLOC_MAX is fine. The original symbol name is already
+ lost during matching via gfc_match_expr. */
static bool
is_predefined_allocator (gfc_expr *expr)
{
@@ -8492,7 +8682,8 @@ gfc_resolve_omp_allocate (gfc_namespace *ns, gfc_omp_namelist *list)
if (n->sym->attr.in_common || n->sym->attr.save || n->sym->ns->save_all
|| (n->sym->ns->proc_name
&& (n->sym->ns->proc_name->attr.flavor == FL_PROGRAM
- || n->sym->ns->proc_name->attr.flavor == FL_MODULE)))
+ || n->sym->ns->proc_name->attr.flavor == FL_MODULE
+ || n->sym->ns->proc_name->attr.flavor == FL_BLOCK_DATA)))
{
bool com = n->sym->attr.in_common;
if (!n->u2.allocator)
@@ -8506,6 +8697,30 @@ gfc_resolve_omp_allocate (gfc_namespace *ns, gfc_omp_namelist *list)
&n->u2.allocator->where, com ? "/" : "",
com ? n->sym->common_head->name : n->sym->name,
com ? "/" : "", &n->where);
+ /* Only local static variables might use omp_cgroup_mem_alloc (6),
+ omp_pteam_mem_alloc (7), or omp_thread_mem_alloc (8). */
+ else if ((!ns->proc_name
+ || ns->proc_name->attr.flavor == FL_PROGRAM
+ || ns->proc_name->attr.flavor == FL_BLOCK_DATA
+ || ns->proc_name->attr.flavor == FL_MODULE
+ || com)
+ && mpz_cmp_si (n->u2.allocator->value.integer,
+ 6 /* cgroup */) >= 0
+ && mpz_cmp_si (n->u2.allocator->value.integer,
+ 8 /* thread */) <= 0)
+ {
+ const char *alloc_name[] = {"omp_cgroup_mem_alloc",
+ "omp_pteam_mem_alloc",
+ "omp_thread_mem_alloc" };
+ gfc_error ("Predefined allocator %qs in ALLOCATOR clause at %L, "
+ "used for list item %<%s%s%s%> at %L, may only be used"
+ " for local static variables",
+ alloc_name[mpz_get_ui (n->u2.allocator->value.integer)
+ - 6 /* cgroup */], &n->u2.allocator->where,
+ com ? "/" : "",
+ com ? n->sym->common_head->name : n->sym->name,
+ com ? "/" : "", &n->where);
+ }
while (n->sym->attr.in_common && n->next && n->next->sym
&& n->sym->common_head == n->next->sym->common_head)
n = n->next;
@@ -8554,7 +8769,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
"TO", "FROM", "INCLUSIVE", "EXCLUSIVE",
"REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
"IN_REDUCTION", "TASK_REDUCTION",
- "DEVICE_RESIDENT", "LINK", "USE_DEVICE",
+ "DEVICE_RESIDENT", "LINK", "LOCAL", "USE_DEVICE",
"CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
"NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER",
"USES_ALLOCATORS", "INIT", "USE", "DESTROY", "INTEROP", "ADJUST_ARGS" };
@@ -8761,6 +8976,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
}
if (omp_clauses->num_threads)
resolve_positive_int_expr (omp_clauses->num_threads, "NUM_THREADS");
+ if (omp_clauses->dyn_groupprivate)
+ resolve_nonnegative_int_expr (omp_clauses->dyn_groupprivate,
+ "DYN_GROUPPRIVATE");
if (omp_clauses->chunk_size)
{
gfc_expr *expr = omp_clauses->chunk_size;
@@ -12290,12 +12508,14 @@ gfc_resolve_omp_context_selector (gfc_omp_set_selector *oss,
continue;
}
/* Device number must be conforming, which includes
- omp_initial_device (-1) and omp_invalid_device (-4). */
+ omp_initial_device (-1), omp_invalid_device (-4),
+ and omp_default_device (-5). */
if (property_kind == OMP_TRAIT_PROPERTY_DEV_NUM_EXPR
&& otp->expr->expr_type == EXPR_CONSTANT
&& mpz_sgn (otp->expr->value.integer) < 0
&& mpz_cmp_si (otp->expr->value.integer, -1) != 0
- && mpz_cmp_si (otp->expr->value.integer, -4) != 0)
+ && mpz_cmp_si (otp->expr->value.integer, -4) != 0
+ && mpz_cmp_si (otp->expr->value.integer, -5) != 0)
gfc_error ("property must be a conforming device number at %L",
&otp->expr->where);
break;
@@ -12320,6 +12540,7 @@ static void
resolve_omp_metadirective (gfc_code *code, gfc_namespace *ns)
{
gfc_omp_variant *variant = code->ext.omp_variants;
+ gfc_omp_variant *prev_variant = variant;
while (variant)
{
@@ -12333,15 +12554,19 @@ resolve_omp_metadirective (gfc_code *code, gfc_namespace *ns)
as the 'otherwise' clause should always match. */
if (variant == code->ext.omp_variants && !variant->next)
break;
- if (variant == code->ext.omp_variants)
- code->ext.omp_variants = variant->next;
gfc_omp_variant *tmp = variant;
- variant = variant->next;
+ if (variant == code->ext.omp_variants)
+ variant = prev_variant = code->ext.omp_variants = variant->next;
+ else
+ variant = prev_variant->next = variant->next;
gfc_free_omp_set_selector_list (tmp->selectors);
free (tmp);
}
else
- variant = variant->next;
+ {
+ prev_variant = variant;
+ variant = variant->next;
+ }
}
/* Replace metadirective by its body if only 'nothing' remains. */
if (!code->ext.omp_variants->next && code->ext.omp_variants->stmt == ST_NONE)
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index b29f690..df8570b 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -60,6 +60,7 @@ bool gfc_in_omp_metadirective_body;
/* Each metadirective body in the translation unit is given a unique
number, used to ensure that labels in the body have unique names. */
int gfc_omp_metadirective_region_count;
+vec<int> gfc_omp_metadirective_region_stack;
/* TODO: Re-order functions to kill these forward decls. */
static void check_statement_label (gfc_statement);
@@ -1194,6 +1195,9 @@ decode_omp_directive (void)
case 'f':
matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH);
break;
+ case 'g':
+ matchdo ("groupprivate", gfc_match_omp_groupprivate, ST_OMP_GROUPPRIVATE);
+ break;
case 'i':
matcho ("interop", gfc_match_omp_interop, ST_OMP_INTEROP);
break;
@@ -1989,7 +1993,8 @@ next_statement (void)
#define case_omp_decl case ST_OMP_THREADPRIVATE: case ST_OMP_DECLARE_SIMD: \
case ST_OMP_DECLARE_TARGET: case ST_OMP_DECLARE_REDUCTION: \
case ST_OMP_DECLARE_VARIANT: case ST_OMP_ALLOCATE: case ST_OMP_ASSUMES: \
- case ST_OMP_REQUIRES: case ST_OACC_ROUTINE: case ST_OACC_DECLARE
+ case ST_OMP_REQUIRES: case ST_OMP_GROUPPRIVATE: \
+ case ST_OACC_ROUTINE: case ST_OACC_DECLARE
/* OpenMP statements that are followed by a structured block. */
@@ -2908,6 +2913,9 @@ gfc_ascii_statement (gfc_statement st, bool strip_sentinel)
case ST_OMP_FLUSH:
p = "!$OMP FLUSH";
break;
+ case ST_OMP_GROUPPRIVATE:
+ p = "!$OMP GROUPPRIVATE";
+ break;
case ST_OMP_INTEROP:
p = "!$OMP INTEROP";
break;
@@ -4436,6 +4444,8 @@ loop:
case ST_EQUIVALENCE:
case ST_IMPLICIT:
case ST_IMPLICIT_NONE:
+ case ST_OMP_ALLOCATE:
+ case ST_OMP_GROUPPRIVATE:
case ST_OMP_THREADPRIVATE:
case ST_PARAMETER:
case ST_STRUCTURE_DECL:
@@ -6542,6 +6552,9 @@ parse_omp_metadirective_body (gfc_statement omp_st)
gfc_in_omp_metadirective_body = true;
gfc_omp_metadirective_region_count++;
+ gfc_omp_metadirective_region_stack.safe_push (
+ gfc_omp_metadirective_region_count);
+
switch (variant->stmt)
{
case_omp_structured_block:
@@ -6603,6 +6616,28 @@ parse_omp_metadirective_body (gfc_statement omp_st)
*variant->code = *gfc_state_stack->head;
pop_state ();
+ gfc_omp_metadirective_region_stack.pop ();
+ int outer_omp_metadirective_region
+ = gfc_omp_metadirective_region_stack.last ();
+
+ /* Rebind labels in the last statement -- which is the first statement
+ past the end of the metadirective body -- to the outer region. */
+ if (gfc_statement_label)
+ gfc_statement_label = gfc_rebind_label (gfc_statement_label,
+ outer_omp_metadirective_region);
+ if ((new_st.op == EXEC_READ || new_st.op == EXEC_WRITE)
+ && new_st.ext.dt->format_label
+ && new_st.ext.dt->format_label != &format_asterisk)
+ new_st.ext.dt->format_label
+ = gfc_rebind_label (new_st.ext.dt->format_label,
+ outer_omp_metadirective_region);
+ if (new_st.label1)
+ new_st.label1
+ = gfc_rebind_label (new_st.label1, outer_omp_metadirective_region);
+ if (new_st.here)
+ new_st.here
+ = gfc_rebind_label (new_st.here, outer_omp_metadirective_region);
+
gfc_commit_symbols ();
gfc_warning_check ();
if (variant->next)
@@ -7106,6 +7141,15 @@ loop:
accept_statement (st);
goto done;
+ /* Specification statements cannot appear after executable statements. */
+ case_decl:
+ case_omp_decl:
+ gfc_error ("%s statement at %C cannot appear after executable statements",
+ gfc_ascii_statement (st));
+ reject_statement ();
+ st = next_statement ();
+ continue;
+
default:
break;
}
@@ -7578,6 +7622,8 @@ gfc_parse_file (void)
gfc_statement_label = NULL;
gfc_omp_metadirective_region_count = 0;
+ gfc_omp_metadirective_region_stack.truncate (0);
+ gfc_omp_metadirective_region_stack.safe_push (0);
gfc_in_omp_metadirective_body = false;
gfc_matching_omp_context_selector = false;
@@ -7765,45 +7811,53 @@ done:
{
case OMP_REQ_ATOMIC_MEM_ORDER_SEQ_CST:
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_SEQ_CST);
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_MEMORY_ORDER_SEQ_CST));
break;
case OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL:
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_ACQ_REL);
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_MEMORY_ORDER_ACQ_REL));
break;
case OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE:
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_ACQUIRE);
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_MEMORY_ORDER_ACQUIRE));
break;
case OMP_REQ_ATOMIC_MEM_ORDER_RELAXED:
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_RELAXED);
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_MEMORY_ORDER_RELAXED));
break;
case OMP_REQ_ATOMIC_MEM_ORDER_RELEASE:
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_RELEASE);
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_MEMORY_ORDER_RELEASE));
break;
}
if (omp_target_seen)
omp_requires_mask = (enum omp_requires) (omp_requires_mask
- | OMP_REQUIRES_TARGET_USED);
+ | int (OMP_REQUIRES_TARGET_USED));
if (omp_requires & OMP_REQ_REVERSE_OFFLOAD)
- omp_requires_mask = (enum omp_requires) (omp_requires_mask
- | OMP_REQUIRES_REVERSE_OFFLOAD);
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_REQUIRES_REVERSE_OFFLOAD));
if (omp_requires & OMP_REQ_UNIFIED_ADDRESS)
- omp_requires_mask = (enum omp_requires) (omp_requires_mask
- | OMP_REQUIRES_UNIFIED_ADDRESS);
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_REQUIRES_UNIFIED_ADDRESS));
if (omp_requires & OMP_REQ_UNIFIED_SHARED_MEMORY)
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask
- | OMP_REQUIRES_UNIFIED_SHARED_MEMORY);
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_REQUIRES_UNIFIED_SHARED_MEMORY));
if (omp_requires & OMP_REQ_SELF_MAPS)
omp_requires_mask
- = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_SELF_MAPS);
+ = (enum omp_requires) (omp_requires_mask | int (OMP_REQUIRES_SELF_MAPS));
if (omp_requires & OMP_REQ_DYNAMIC_ALLOCATORS)
- omp_requires_mask = (enum omp_requires) (omp_requires_mask
- | OMP_REQUIRES_DYNAMIC_ALLOCATORS);
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask
+ | int (OMP_REQUIRES_DYNAMIC_ALLOCATORS));
/* Do the parse tree dump. */
gfc_current_ns = flag_dump_fortran_original ? gfc_global_ns_list : NULL;
diff --git a/gcc/fortran/parse.h b/gcc/fortran/parse.h
index 7bf0fa4..70ffcbd 100644
--- a/gcc/fortran/parse.h
+++ b/gcc/fortran/parse.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GFC_PARSE_H
#define GFC_PARSE_H
+#include "vec.h"
+
/* Enum for what the compiler is currently doing. */
enum gfc_compile_state
{
@@ -76,6 +78,7 @@ extern bool gfc_matching_function;
extern bool gfc_matching_omp_context_selector;
extern bool gfc_in_omp_metadirective_body;
extern int gfc_omp_metadirective_region_count;
+extern vec<int> gfc_omp_metadirective_region_stack;
match gfc_match_prefix (gfc_typespec *);
bool is_oacc (gfc_state_data *);
diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 1dcb1c3..e5e84e8 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -2261,6 +2261,32 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
&& !sym->attr.select_rank_temporary)
inferred_type = true;
+ /* Try to resolve a typebound generic procedure so that the associate name
+ has a chance to get a type before being used in a second, nested associate
+ statement. Note that a copy is used for resolution so that failure does
+ not result in a mutilated selector expression further down the line. */
+ if (tgt_expr && !sym->assoc->dangling
+ && tgt_expr->ts.type == BT_UNKNOWN
+ && tgt_expr->symtree
+ && tgt_expr->symtree->n.sym
+ && gfc_expr_attr (tgt_expr).generic
+ && ((sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.pdt_template)
+ || (sym->ts.type == BT_CLASS
+ && CLASS_DATA (sym)->ts.u.derived->attr.pdt_template)))
+ {
+ gfc_expr *cpy = gfc_copy_expr (tgt_expr);
+ if (gfc_resolve_expr (cpy)
+ && cpy->ts.type != BT_UNKNOWN)
+ {
+ gfc_replace_expr (tgt_expr, cpy);
+ sym->ts = tgt_expr->ts;
+ }
+ else
+ gfc_free_expr (cpy);
+ if (gfc_expr_attr (tgt_expr).generic)
+ inferred_type = true;
+ }
+
/* For associate names, we may not yet know whether they are arrays or not.
If the selector expression is unambiguously an array; eg. a full array
or an array section, then the associate name must be an array and we can
@@ -2493,6 +2519,20 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
&& !gfc_find_derived_types (sym, gfc_current_ns, name))
primary->ts.type = BT_UNKNOWN;
+ /* Otherwise try resolving a copy of a component call. If it succeeds,
+ use that for the selector expression. */
+ else if (tgt_expr && tgt_expr->expr_type == EXPR_COMPCALL)
+ {
+ gfc_expr *cpy = gfc_copy_expr (tgt_expr);
+ if (gfc_resolve_expr (cpy))
+ {
+ gfc_replace_expr (tgt_expr, cpy);
+ sym->ts = tgt_expr->ts;
+ }
+ else
+ gfc_free_expr (cpy);
+ }
+
/* An inquiry reference might determine the type, otherwise we have an
error. */
if (sym->ts.type == BT_UNKNOWN && !inquiry)
@@ -3543,7 +3583,7 @@ gfc_convert_to_structure_constructor (gfc_expr *e, gfc_symbol *sym, gfc_expr **c
}
/* Find the current component in the structure definition and check
- its access is not private. */
+ its access is not private. */
if (comp)
this_comp = gfc_find_component (sym, comp->name, false, false, NULL);
else
@@ -3836,8 +3876,6 @@ gfc_match_rvalue (gfc_expr **result)
bool implicit_char;
gfc_ref *ref;
gfc_symtree *pdt_st;
- gfc_symbol *found_specific = NULL;
-
m = gfc_match ("%%loc");
if (m == MATCH_YES)
@@ -4085,29 +4123,21 @@ gfc_match_rvalue (gfc_expr **result)
break;
}
- gfc_gobble_whitespace ();
- found_specific = NULL;
-
- /* Even if 'name' is that of a PDT template, priority has to be given to
- possible specific procedures in the generic interface. */
- gfc_find_sym_tree (gfc_dt_upper_string (name), NULL, 1, &pdt_st);
- if (sym->generic && sym->generic->next
- && gfc_peek_ascii_char() != '(')
- {
- gfc_actual_arglist *arg = actual_arglist;
- for (; arg && pdt_st; arg = arg->next)
- gfc_resolve_expr (arg->expr);
- found_specific = gfc_search_interface (sym->generic, 0,
- &actual_arglist);
- }
-
/* Check to see if this is a PDT constructor. The format of these
constructors is rather unusual:
name [(type_params)](component_values)
where, component_values excludes the type_params. With the present
gfortran representation this is rather awkward because the two are not
- distinguished, other than by their attributes. */
- if (sym->attr.generic && pdt_st != NULL && found_specific == NULL)
+ distinguished, other than by their attributes.
+
+ Even if 'name' is that of a PDT template, priority has to be given to
+ specific procedures, other than the constructor, in the generic
+ interface. */
+
+ gfc_gobble_whitespace ();
+ gfc_find_sym_tree (gfc_dt_upper_string (name), NULL, 1, &pdt_st);
+ if (sym->attr.generic && pdt_st != NULL
+ && !(sym->generic->next && gfc_peek_ascii_char() != '('))
{
gfc_symbol *pdt_sym;
gfc_actual_arglist *ctr_arglist = NULL, *tmp;
@@ -4172,12 +4202,8 @@ gfc_match_rvalue (gfc_expr **result)
tmp = tmp->next;
}
- if (found_specific)
- gfc_find_sym_tree (found_specific->name,
- NULL, 1, &symtree);
- else
- gfc_find_sym_tree (gfc_dt_lower_string (pdt_sym->name),
- NULL, 1, &symtree);
+ gfc_find_sym_tree (gfc_dt_lower_string (pdt_sym->name),
+ NULL, 1, &symtree);
if (!symtree)
{
gfc_get_ha_sym_tree (gfc_dt_lower_string (pdt_sym->name) ,
@@ -4187,11 +4213,21 @@ gfc_match_rvalue (gfc_expr **result)
symtree->n.sym->ts.type = BT_DERIVED;
}
- /* Append the type_params and the component_values. */
- for (tmp = ctr_arglist; tmp && tmp->next;)
- tmp = tmp->next;
- tmp->next = actual_arglist;
- actual_arglist = ctr_arglist;
+ if (type_spec_list)
+ {
+ /* Append the type_params and the component_values. */
+ for (tmp = ctr_arglist; tmp && tmp->next;)
+ tmp = tmp->next;
+ tmp->next = actual_arglist;
+ actual_arglist = ctr_arglist;
+ tmp = actual_arglist;
+ /* Can now add all the component names. */
+ for (c = pdt_sym->components; c && tmp; c = c->next)
+ {
+ tmp->name = c->name;
+ tmp = tmp->next;
+ }
+ }
}
}
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 03e26f0..db6b52f 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -6151,7 +6151,7 @@ gfc_resolve_ref (gfc_expr *expr)
}
/* The F08 standard requires(See R425, R431, R435, and in particular
- Note 6.7) that a PDT parameter reference be a scalar even if
+ Note 6.7) that a PDT parameter reference be a scalar even if
the designator is an array." */
if (array_ref && last_pdt && last_pdt->attr.pdt_type
&& (ref->u.c.component->attr.pdt_kind
@@ -8461,7 +8461,20 @@ check_default_none_expr (gfc_expr **e, int *, void *data)
break;
ns2 = ns2->parent;
}
- if (ns2 != NULL)
+
+ /* A DO CONCURRENT iterator cannot appear in a locality spec. */
+ if (sym->ns->code->ext.concur.forall_iterator)
+ {
+ gfc_forall_iterator *iter
+ = sym->ns->code->ext.concur.forall_iterator;
+ for (; iter; iter = iter->next)
+ if (iter->var->symtree
+ && strcmp(sym->name, iter->var->symtree->name) == 0)
+ return 0;
+ }
+
+ /* A named constant is not a variable, so skip test. */
+ if (ns2 != NULL && sym->attr.flavor != FL_PARAMETER)
{
gfc_error ("Variable %qs at %L not specified in a locality spec "
"of DO CONCURRENT at %L but required due to "
@@ -8741,6 +8754,8 @@ resolve_locality_spec (gfc_code *code, gfc_namespace *ns)
plist = &((*plist)->next);
}
}
+
+ delete data.sym_hash;
}
/* Resolve a list of FORALL iterators. The FORALL index-name is constrained
@@ -9784,8 +9799,10 @@ done_errmsg:
/* Resolving the expr3 in the loop over all objects to allocate would
execute loop invariant code for each loop item. Therefore do it just
once here. */
+ mpz_t nelem;
if (code->expr3 && code->expr3->mold
- && code->expr3->ts.type == BT_DERIVED)
+ && code->expr3->ts.type == BT_DERIVED
+ && !(code->expr3->ref && gfc_array_size (code->expr3, &nelem)))
{
/* Default initialization via MOLD (non-polymorphic). */
gfc_expr *rhs = gfc_default_initializer (&code->expr3->ts);
@@ -10775,6 +10792,10 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
/* If the target is a good class object, so is the associate variable. */
if (sym->ts.type == BT_CLASS && gfc_expr_attr (target).class_ok)
sym->attr.class_ok = 1;
+
+ /* If the target is a contiguous pointer, so is the associate variable. */
+ if (gfc_expr_attr (target).pointer && gfc_expr_attr (target).contiguous)
+ sym->attr.contiguous = 1;
}
@@ -12236,11 +12257,10 @@ static void
gfc_resolve_assign_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr)
{
int n;
+ gfc_symbol *forall_index;
for (n = 0; n < nvar; n++)
{
- gfc_symbol *forall_index;
-
forall_index = var_expr[n]->symtree->n.sym;
/* Check whether the assignment target is one of the FORALL index
@@ -12254,8 +12274,12 @@ gfc_resolve_assign_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr)
/* If one of the FORALL index variables doesn't appear in the
assignment variable, then there could be a many-to-one
assignment. Emit a warning rather than an error because the
- mask could be resolving this problem. */
- if (!find_forall_index (code->expr1, forall_index, 0))
+ mask could be resolving this problem.
+ DO NOT emit this warning for DO CONCURRENT - reduction-like
+ many-to-one assignments are semantically valid (formalized with
+ the REDUCE locality-spec in Fortran 2023). */
+ if (!find_forall_index (code->expr1, forall_index, 0)
+ && !gfc_do_concurrent_flag)
gfc_warning (0, "The FORALL with index %qs is not used on the "
"left side of the assignment at %L and so might "
"cause multiple assignment to this object",
@@ -12375,7 +12399,7 @@ gfc_count_forall_iterators (gfc_code *code)
int max_iters, sub_iters, current_iters;
gfc_forall_iterator *fa;
- gcc_assert(code->op == EXEC_FORALL);
+ gcc_assert (code->op == EXEC_FORALL || code->op == EXEC_DO_CONCURRENT);
max_iters = 0;
current_iters = 0;
@@ -12386,7 +12410,7 @@ gfc_count_forall_iterators (gfc_code *code)
while (code)
{
- if (code->op == EXEC_FORALL)
+ if (code->op == EXEC_FORALL || code->op == EXEC_DO_CONCURRENT)
{
sub_iters = gfc_count_forall_iterators (code);
if (sub_iters > max_iters)
@@ -12399,8 +12423,160 @@ gfc_count_forall_iterators (gfc_code *code)
}
-/* Given a FORALL construct, first resolve the FORALL iterator, then call
- gfc_resolve_forall_body to resolve the FORALL body. */
+/* Given a FORALL construct.
+ 1) Resolve the FORALL iterator.
+ 2) Check for shadow index-name(s) and update code block.
+ 3) call gfc_resolve_forall_body to resolve the FORALL body. */
+
+/* Custom recursive expression walker that replaces symbols.
+ This ensures we visit ALL expressions including those in array subscripts. */
+
+static void
+replace_in_expr_recursive (gfc_expr *expr, gfc_symbol *old_sym, gfc_symtree *new_st)
+{
+ if (!expr)
+ return;
+
+ /* Check if this is a variable reference to replace */
+ if (expr->expr_type == EXPR_VARIABLE && expr->symtree->n.sym == old_sym)
+ {
+ expr->symtree = new_st;
+ expr->ts = new_st->n.sym->ts;
+ }
+
+ /* Walk through reference chain (array subscripts, substrings, etc.) */
+ for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
+ {
+ if (ref->type == REF_ARRAY)
+ {
+ gfc_array_ref *ar = &ref->u.ar;
+ for (int i = 0; i < ar->dimen; i++)
+ {
+ replace_in_expr_recursive (ar->start[i], old_sym, new_st);
+ replace_in_expr_recursive (ar->end[i], old_sym, new_st);
+ replace_in_expr_recursive (ar->stride[i], old_sym, new_st);
+ }
+ }
+ else if (ref->type == REF_SUBSTRING)
+ {
+ replace_in_expr_recursive (ref->u.ss.start, old_sym, new_st);
+ replace_in_expr_recursive (ref->u.ss.end, old_sym, new_st);
+ }
+ }
+
+ /* Walk through sub-expressions based on expression type */
+ switch (expr->expr_type)
+ {
+ case EXPR_OP:
+ replace_in_expr_recursive (expr->value.op.op1, old_sym, new_st);
+ replace_in_expr_recursive (expr->value.op.op2, old_sym, new_st);
+ break;
+
+ case EXPR_FUNCTION:
+ for (gfc_actual_arglist *a = expr->value.function.actual; a; a = a->next)
+ replace_in_expr_recursive (a->expr, old_sym, new_st);
+ break;
+
+ case EXPR_ARRAY:
+ case EXPR_STRUCTURE:
+ for (gfc_constructor *c = gfc_constructor_first (expr->value.constructor);
+ c; c = gfc_constructor_next (c))
+ {
+ replace_in_expr_recursive (c->expr, old_sym, new_st);
+ if (c->iterator)
+ {
+ replace_in_expr_recursive (c->iterator->start, old_sym, new_st);
+ replace_in_expr_recursive (c->iterator->end, old_sym, new_st);
+ replace_in_expr_recursive (c->iterator->step, old_sym, new_st);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Walk code tree and replace all variable references */
+
+static void
+replace_in_code_recursive (gfc_code *code, gfc_symbol *old_sym, gfc_symtree *new_st)
+{
+ if (!code)
+ return;
+
+ for (gfc_code *c = code; c; c = c->next)
+ {
+ /* Replace in expressions associated with this code node */
+ replace_in_expr_recursive (c->expr1, old_sym, new_st);
+ replace_in_expr_recursive (c->expr2, old_sym, new_st);
+ replace_in_expr_recursive (c->expr3, old_sym, new_st);
+ replace_in_expr_recursive (c->expr4, old_sym, new_st);
+
+ /* Handle special code types with additional expressions */
+ switch (c->op)
+ {
+ case EXEC_DO:
+ if (c->ext.iterator)
+ {
+ replace_in_expr_recursive (c->ext.iterator->start, old_sym, new_st);
+ replace_in_expr_recursive (c->ext.iterator->end, old_sym, new_st);
+ replace_in_expr_recursive (c->ext.iterator->step, old_sym, new_st);
+ }
+ break;
+
+ case EXEC_CALL:
+ case EXEC_ASSIGN_CALL:
+ for (gfc_actual_arglist *a = c->ext.actual; a; a = a->next)
+ replace_in_expr_recursive (a->expr, old_sym, new_st);
+ break;
+
+ case EXEC_SELECT:
+ for (gfc_code *b = c->block; b; b = b->block)
+ {
+ for (gfc_case *cp = b->ext.block.case_list; cp; cp = cp->next)
+ {
+ replace_in_expr_recursive (cp->low, old_sym, new_st);
+ replace_in_expr_recursive (cp->high, old_sym, new_st);
+ }
+ replace_in_code_recursive (b->next, old_sym, new_st);
+ }
+ break;
+
+ case EXEC_FORALL:
+ case EXEC_DO_CONCURRENT:
+ for (gfc_forall_iterator *fa = c->ext.concur.forall_iterator; fa; fa = fa->next)
+ {
+ replace_in_expr_recursive (fa->start, old_sym, new_st);
+ replace_in_expr_recursive (fa->end, old_sym, new_st);
+ replace_in_expr_recursive (fa->stride, old_sym, new_st);
+ }
+ /* Don't recurse into nested FORALL/DO CONCURRENT bodies here,
+ they'll be handled separately */
+ break;
+
+ default:
+ break;
+ }
+
+ /* Recurse into blocks */
+ if (c->block)
+ replace_in_code_recursive (c->block->next, old_sym, new_st);
+ }
+}
+
+
+/* Replace all references to outer_sym with shadow_st in the given code. */
+
+static void
+gfc_replace_forall_variable (gfc_code **code_ptr, gfc_symbol *outer_sym,
+ gfc_symtree *shadow_st)
+{
+ /* Use custom recursive walker to ensure we visit ALL expressions */
+ replace_in_code_recursive (*code_ptr, outer_sym, shadow_st);
+}
+
static void
gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
@@ -12410,14 +12586,21 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
static int nvar = 0;
int i, old_nvar, tmp;
gfc_forall_iterator *fa;
+ bool shadow = false;
old_nvar = nvar;
- if (!gfc_notify_std (GFC_STD_F2018_OBS, "FORALL construct at %L", &code->loc))
+ /* Only warn about obsolescent FORALL, not DO CONCURRENT */
+ if (code->op == EXEC_FORALL
+ && !gfc_notify_std (GFC_STD_F2018_OBS, "FORALL construct at %L", &code->loc))
return;
/* Start to resolve a FORALL construct */
- if (forall_save == 0)
+ /* Allocate var_expr only at the truly outermost FORALL/DO CONCURRENT level.
+ forall_save==0 means we're not nested in a FORALL in the current scope,
+ but nvar==0 ensures we're not nested in a parent scope either (prevents
+ double allocation when FORALL is nested inside DO CONCURRENT). */
+ if (forall_save == 0 && nvar == 0)
{
/* Count the total number of FORALL indices in the nested FORALL
construct in order to allocate the VAR_EXPR with proper size. */
@@ -12427,11 +12610,12 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
var_expr = XCNEWVEC (gfc_expr *, total_var);
}
- /* The information about FORALL iterator, including FORALL indices start, end
- and stride. An outer FORALL indice cannot appear in start, end or stride. */
+ /* The information about FORALL iterator, including FORALL indices start,
+ end and stride. An outer FORALL indice cannot appear in start, end or
+ stride. Check for a shadow index-name. */
for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next)
{
- /* Fortran 20008: C738 (R753). */
+ /* Fortran 2008: C738 (R753). */
if (fa->var->ref && fa->var->ref->type == REF_ARRAY)
{
gfc_error ("FORALL index-name at %L must be a scalar variable "
@@ -12440,14 +12624,19 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
}
/* Check if any outer FORALL index name is the same as the current
- one. */
+ one. Skip this check if the iterator is a shadow variable (from
+ DO CONCURRENT type spec) which may not have a symtree yet. */
for (i = 0; i < nvar; i++)
{
- if (fa->var->symtree->n.sym == var_expr[i]->symtree->n.sym)
+ if (fa->var && fa->var->symtree && var_expr[i] && var_expr[i]->symtree
+ && fa->var->symtree->n.sym == var_expr[i]->symtree->n.sym)
gfc_error ("An outer FORALL construct already has an index "
"with this name %L", &fa->var->where);
}
+ if (fa->shadow)
+ shadow = true;
+
/* Record the current FORALL index. */
var_expr[nvar] = gfc_copy_expr (fa->var);
@@ -12457,6 +12646,47 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
gcc_assert (nvar <= total_var);
}
+ /* Need to walk the code and replace references to the index-name with
+ references to the shadow index-name. This must be done BEFORE resolving
+ the body so that resolution uses the correct shadow variables. */
+ if (shadow)
+ {
+ /* Walk the FORALL/DO CONCURRENT body and replace references to shadowed variables. */
+ for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next)
+ {
+ if (fa->shadow)
+ {
+ gfc_symtree *shadow_st;
+ const char *shadow_name_str;
+ char *outer_name;
+
+ /* fa->var now points to the shadow variable "_name". */
+ shadow_name_str = fa->var->symtree->name;
+ shadow_st = fa->var->symtree;
+
+ if (shadow_name_str[0] != '_')
+ gfc_internal_error ("Expected shadow variable name to start with _");
+
+ outer_name = (char *) alloca (strlen (shadow_name_str));
+ strcpy (outer_name, shadow_name_str + 1);
+
+ /* Find the ITERATOR symbol in the current namespace.
+ This is the local DO CONCURRENT variable that body expressions reference. */
+ gfc_symtree *iter_st = gfc_find_symtree (ns->sym_root, outer_name);
+
+ if (!iter_st)
+ /* No iterator variable found - this shouldn't happen */
+ continue;
+
+ gfc_symbol *iter_sym = iter_st->n.sym;
+
+ /* Walk the FORALL/DO CONCURRENT body and replace all references. */
+ if (code->block && code->block->next)
+ gfc_replace_forall_variable (&code->block->next, iter_sym, shadow_st);
+ }
+ }
+ }
+
/* Resolve the FORALL body. */
gfc_resolve_forall_body (code, nvar, var_expr);
@@ -13726,11 +13956,17 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns)
forall_save = forall_flag;
do_concurrent_save = gfc_do_concurrent_flag;
- if (code->op == EXEC_FORALL)
+ if (code->op == EXEC_FORALL || code->op == EXEC_DO_CONCURRENT)
{
- forall_flag = 1;
+ if (code->op == EXEC_FORALL)
+ forall_flag = 1;
+ else if (code->op == EXEC_DO_CONCURRENT)
+ gfc_do_concurrent_flag = 1;
gfc_resolve_forall (code, ns, forall_save);
- forall_flag = 2;
+ if (code->op == EXEC_FORALL)
+ forall_flag = 2;
+ else if (code->op == EXEC_DO_CONCURRENT)
+ gfc_do_concurrent_flag = 2;
}
else if (code->op == EXEC_OMP_METADIRECTIVE)
for (gfc_omp_variant *variant
@@ -15602,7 +15838,7 @@ check_formal:
static bool
gfc_resolve_finalizers (gfc_symbol* derived, bool *finalizable)
{
- gfc_finalizer* list;
+ gfc_finalizer *list, *pdt_finalizers = NULL;
gfc_finalizer** prev_link; /* For removing wrong entries from the list. */
bool result = true;
bool seen_scalar = false;
@@ -15632,6 +15868,41 @@ gfc_resolve_finalizers (gfc_symbol* derived, bool *finalizable)
return true;
}
+ /* If a PDT has finalizers, the pdt_type's f2k_derived is a copy of that of
+ the template. If the finalizers field has the same value, it needs to be
+ supplied with finalizers of the same pdt_type. */
+ if (derived->attr.pdt_type
+ && derived->template_sym
+ && derived->template_sym->f2k_derived
+ && (pdt_finalizers = derived->template_sym->f2k_derived->finalizers)
+ && derived->f2k_derived->finalizers == pdt_finalizers)
+ {
+ gfc_finalizer *tmp = NULL;
+ derived->f2k_derived->finalizers = NULL;
+ prev_link = &derived->f2k_derived->finalizers;
+ for (list = pdt_finalizers; list; list = list->next)
+ {
+ gfc_formal_arglist *args = gfc_sym_get_dummy_args (list->proc_sym);
+ if (args->sym
+ && args->sym->ts.type == BT_DERIVED
+ && args->sym->ts.u.derived
+ && !strcmp (args->sym->ts.u.derived->name, derived->name))
+ {
+ tmp = gfc_get_finalizer ();
+ *tmp = *list;
+ tmp->next = NULL;
+ if (*prev_link)
+ {
+ (*prev_link)->next = tmp;
+ prev_link = &tmp;
+ }
+ else
+ *prev_link = tmp;
+ list->proc_tree = gfc_find_sym_in_symtree (list->proc_sym);
+ }
+ }
+ }
+
/* Walk over the list of finalizer-procedures, check them, and if any one
does not fit in with the standard's definition, print an error and remove
it from the list. */
@@ -15688,7 +15959,8 @@ gfc_resolve_finalizers (gfc_symbol* derived, bool *finalizable)
}
/* This argument must be of our type. */
- if (arg->ts.type != BT_DERIVED || arg->ts.u.derived != derived)
+ if (!derived->attr.pdt_template
+ && (arg->ts.type != BT_DERIVED || arg->ts.u.derived != derived))
{
gfc_error ("Argument of FINAL procedure at %L must be of type %qs",
&arg->declared_at, derived->name);
@@ -15743,7 +16015,7 @@ gfc_resolve_finalizers (gfc_symbol* derived, bool *finalizable)
/* Argument list might be empty; that is an error signalled earlier,
but we nevertheless continued resolving. */
dummy_args = gfc_sym_get_dummy_args (i->proc_sym);
- if (dummy_args)
+ if (dummy_args && !derived->attr.pdt_template)
{
gfc_symbol* i_arg = dummy_args->sym;
const int i_rank = (i_arg->as ? i_arg->as->rank : 0);
@@ -15791,9 +16063,13 @@ error:
" rank finalizer has been declared",
derived->name, &derived->declared_at);
- vtab = gfc_find_derived_vtab (derived);
- c = vtab->ts.u.derived->components->next->next->next->next->next;
- gfc_set_sym_referenced (c->initializer->symtree->n.sym);
+ if (!derived->attr.pdt_template)
+ {
+ vtab = gfc_find_derived_vtab (derived);
+ c = vtab->ts.u.derived->components->next->next->next->next->next;
+ if (c && c->initializer && c->initializer->symtree && c->initializer->symtree->n.sym)
+ gfc_set_sym_referenced (c->initializer->symtree->n.sym);
+ }
if (finalizable)
*finalizable = true;
@@ -17869,6 +18145,7 @@ skip_interfaces:
/* F2008, C530. */
if (sym->attr.contiguous
+ && !sym->attr.associate_var
&& (!class_attr.dimension
|| (as->type != AS_ASSUMED_SHAPE && as->type != AS_ASSUMED_RANK
&& !class_attr.pointer)))
@@ -18440,17 +18717,30 @@ skip_interfaces:
}
/* Check threadprivate restrictions. */
- if (sym->attr.threadprivate
+ if ((sym->attr.threadprivate || sym->attr.omp_groupprivate)
&& !(sym->attr.save || sym->attr.data || sym->attr.in_common)
&& !(sym->ns->save_all && !sym->attr.automatic)
&& sym->module == NULL
&& (sym->ns->proc_name == NULL
|| (sym->ns->proc_name->attr.flavor != FL_MODULE
&& !sym->ns->proc_name->attr.is_main_program)))
- gfc_error ("Threadprivate at %L isn't SAVEd", &sym->declared_at);
+ {
+ if (sym->attr.threadprivate)
+ gfc_error ("Threadprivate at %L isn't SAVEd", &sym->declared_at);
+ else
+ gfc_error ("OpenMP groupprivate variable %qs at %L must have the SAVE "
+ "attribute", sym->name, &sym->declared_at);
+ }
+
+ if (sym->attr.omp_groupprivate && sym->value)
+ gfc_error ("!$OMP GROUPPRIVATE variable %qs at %L must not have an "
+ "initializer", sym->name, &sym->declared_at);
/* Check omp declare target restrictions. */
- if (sym->attr.omp_declare_target
+ if ((sym->attr.omp_declare_target
+ || sym->attr.omp_declare_target_link
+ || sym->attr.omp_declare_target_local)
+ && !sym->attr.omp_groupprivate /* already warned. */
&& sym->attr.flavor == FL_VARIABLE
&& !sym->attr.save
&& !(sym->ns->save_all && !sym->attr.automatic)
diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
index 8211d92..62925c0 100644
--- a/gcc/fortran/symbol.cc
+++ b/gcc/fortran/symbol.cc
@@ -458,8 +458,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
*contiguous = "CONTIGUOUS", *generic = "GENERIC", *automatic = "AUTOMATIC",
*pdt_len = "LEN", *pdt_kind = "KIND";
static const char *threadprivate = "THREADPRIVATE";
+ static const char *omp_groupprivate = "OpenMP GROUPPRIVATE";
static const char *omp_declare_target = "OMP DECLARE TARGET";
static const char *omp_declare_target_link = "OMP DECLARE TARGET LINK";
+ static const char *omp_declare_target_local = "OMP DECLARE TARGET LOCAL";
static const char *oacc_declare_copyin = "OACC DECLARE COPYIN";
static const char *oacc_declare_create = "OACC DECLARE CREATE";
static const char *oacc_declare_deviceptr = "OACC DECLARE DEVICEPTR";
@@ -553,8 +555,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (dummy, entry);
conf (dummy, intrinsic);
conf (dummy, threadprivate);
+ conf (dummy, omp_groupprivate);
conf (dummy, omp_declare_target);
conf (dummy, omp_declare_target_link);
+ conf (dummy, omp_declare_target_local);
conf (pointer, target);
conf (pointer, intrinsic);
conf (pointer, elemental);
@@ -604,8 +608,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (in_equivalence, entry);
conf (in_equivalence, allocatable);
conf (in_equivalence, threadprivate);
+ conf (in_equivalence, omp_groupprivate);
conf (in_equivalence, omp_declare_target);
conf (in_equivalence, omp_declare_target_link);
+ conf (in_equivalence, omp_declare_target_local);
conf (in_equivalence, oacc_declare_create);
conf (in_equivalence, oacc_declare_copyin);
conf (in_equivalence, oacc_declare_deviceptr);
@@ -616,6 +622,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (entry, result);
conf (generic, result);
conf (generic, omp_declare_target);
+ conf (generic, omp_declare_target_local);
conf (generic, omp_declare_target_link);
conf (function, subroutine);
@@ -661,8 +668,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (cray_pointee, in_common);
conf (cray_pointee, in_equivalence);
conf (cray_pointee, threadprivate);
+ conf (cray_pointee, omp_groupprivate);
conf (cray_pointee, omp_declare_target);
conf (cray_pointee, omp_declare_target_link);
+ conf (cray_pointee, omp_declare_target_local);
conf (cray_pointee, oacc_declare_create);
conf (cray_pointee, oacc_declare_copyin);
conf (cray_pointee, oacc_declare_deviceptr);
@@ -720,9 +729,11 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (proc_pointer, abstract)
conf (proc_pointer, omp_declare_target)
+ conf (proc_pointer, omp_declare_target_local)
conf (proc_pointer, omp_declare_target_link)
conf (entry, omp_declare_target)
+ conf (entry, omp_declare_target_local)
conf (entry, omp_declare_target_link)
conf (entry, oacc_declare_create)
conf (entry, oacc_declare_copyin)
@@ -782,8 +793,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf2 (function);
conf2 (subroutine);
conf2 (threadprivate);
+ conf2 (omp_groupprivate);
conf2 (omp_declare_target);
conf2 (omp_declare_target_link);
+ conf2 (omp_declare_target_local);
conf2 (oacc_declare_create);
conf2 (oacc_declare_copyin);
conf2 (oacc_declare_deviceptr);
@@ -828,7 +841,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf2 (dimension);
conf2 (function);
if (!attr->proc_pointer)
- conf2 (threadprivate);
+ {
+ conf2 (threadprivate);
+ conf2 (omp_groupprivate);
+ }
}
/* Procedure pointers in COMMON blocks are allowed in F03,
@@ -836,6 +852,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
if (!attr->proc_pointer || (gfc_option.allow_std & GFC_STD_F2008))
conf2 (in_common);
+ conf2 (omp_declare_target_local);
conf2 (omp_declare_target_link);
switch (attr->proc)
@@ -852,6 +869,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
case PROC_DUMMY:
conf2 (result);
conf2 (threadprivate);
+ conf2 (omp_groupprivate);
break;
default:
@@ -872,8 +890,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf2 (function);
conf2 (subroutine);
conf2 (threadprivate);
+ conf2 (omp_groupprivate);
conf2 (result);
conf2 (omp_declare_target);
+ conf2 (omp_declare_target_local);
conf2 (omp_declare_target_link);
conf2 (oacc_declare_create);
conf2 (oacc_declare_copyin);
@@ -905,6 +925,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf2 (volatile_);
conf2 (asynchronous);
conf2 (threadprivate);
+ conf2 (omp_groupprivate);
conf2 (value);
conf2 (codimension);
conf2 (result);
@@ -1407,6 +1428,25 @@ gfc_add_asynchronous (symbol_attribute *attr, const char *name, locus *where)
bool
+gfc_add_omp_groupprivate (symbol_attribute *attr, const char *name,
+ locus *where)
+{
+
+ if (check_used (attr, name, where))
+ return false;
+
+ if (attr->omp_groupprivate)
+ {
+ duplicate_attr ("OpenMP GROUPPRIVATE", where);
+ return false;
+ }
+
+ attr->omp_groupprivate = true;
+ return gfc_check_conflict (attr, name, where);
+}
+
+
+bool
gfc_add_threadprivate (symbol_attribute *attr, const char *name, locus *where)
{
@@ -1457,6 +1497,22 @@ gfc_add_omp_declare_target_link (symbol_attribute *attr, const char *name,
bool
+gfc_add_omp_declare_target_local (symbol_attribute *attr, const char *name,
+ locus *where)
+{
+
+ if (check_used (attr, name, where))
+ return false;
+
+ if (attr->omp_declare_target_local)
+ return true;
+
+ attr->omp_declare_target_local = 1;
+ return gfc_check_conflict (attr, name, where);
+}
+
+
+bool
gfc_add_oacc_declare_create (symbol_attribute *attr, const char *name,
locus *where)
{
@@ -2110,6 +2166,9 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
goto fail;
if (src->asynchronous && !gfc_add_asynchronous (dest, NULL, where))
goto fail;
+ if (src->omp_groupprivate
+ && !gfc_add_omp_groupprivate (dest, NULL, where))
+ goto fail;
if (src->threadprivate
&& !gfc_add_threadprivate (dest, NULL, where))
goto fail;
@@ -2119,6 +2178,9 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
if (src->omp_declare_target_link
&& !gfc_add_omp_declare_target_link (dest, NULL, where))
goto fail;
+ if (src->omp_declare_target_local
+ && !gfc_add_omp_declare_target_local (dest, NULL, where))
+ goto fail;
if (src->oacc_declare_create
&& !gfc_add_oacc_declare_create (dest, NULL, where))
goto fail;
@@ -2753,8 +2815,7 @@ gfc_get_st_label (int labelno)
{
gfc_st_label *lp;
gfc_namespace *ns;
- int omp_region = (gfc_in_omp_metadirective_body
- ? gfc_omp_metadirective_region_count : 0);
+ int omp_region = gfc_omp_metadirective_region_stack.last ();
if (gfc_current_state () == COMP_DERIVED)
ns = gfc_current_block ()->f2k_derived;
@@ -2768,22 +2829,28 @@ gfc_get_st_label (int labelno)
}
/* First see if the label is already in this namespace. */
- lp = ns->st_labels;
- while (lp)
+ gcc_checking_assert (gfc_omp_metadirective_region_stack.length () > 0);
+ for (int omp_region_idx = gfc_omp_metadirective_region_stack.length () - 1;
+ omp_region_idx >= 0; omp_region_idx--)
{
- if (lp->omp_region == omp_region)
+ int omp_region2 = gfc_omp_metadirective_region_stack[omp_region_idx];
+ lp = ns->st_labels;
+ while (lp)
{
- if (lp->value == labelno)
- return lp;
- if (lp->value < labelno)
+ if (lp->omp_region == omp_region2)
+ {
+ if (lp->value == labelno)
+ return lp;
+ if (lp->value < labelno)
+ lp = lp->left;
+ else
+ lp = lp->right;
+ }
+ else if (lp->omp_region < omp_region2)
lp = lp->left;
else
lp = lp->right;
}
- else if (lp->omp_region < omp_region)
- lp = lp->left;
- else
- lp = lp->right;
}
lp = XCNEW (gfc_st_label);
@@ -2799,6 +2866,53 @@ gfc_get_st_label (int labelno)
return lp;
}
+/* Rebind a statement label to a new OpenMP region. If a label with the same
+ value already exists in the new region, update it and return it. Otherwise,
+ move the label to the new region. */
+
+gfc_st_label *
+gfc_rebind_label (gfc_st_label *label, int new_omp_region)
+{
+ gfc_st_label *lp = label->ns->st_labels;
+ int labelno = label->value;
+
+ while (lp)
+ {
+ if (lp->omp_region == new_omp_region)
+ {
+ if (lp->value == labelno)
+ {
+ if (lp == label)
+ return label;
+ if (lp->defined == ST_LABEL_UNKNOWN
+ && label->defined != ST_LABEL_UNKNOWN)
+ lp->defined = label->defined;
+ if (lp->referenced == ST_LABEL_UNKNOWN
+ && label->referenced != ST_LABEL_UNKNOWN)
+ lp->referenced = label->referenced;
+ if (lp->format == NULL && label->format != NULL)
+ lp->format = label->format;
+ gfc_delete_bbt (&label->ns->st_labels, label, compare_st_labels);
+ return lp;
+ }
+ if (lp->value < labelno)
+ lp = lp->left;
+ else
+ lp = lp->right;
+ }
+ else if (lp->omp_region < new_omp_region)
+ lp = lp->left;
+ else
+ lp = lp->right;
+ }
+
+ gfc_delete_bbt (&label->ns->st_labels, label, compare_st_labels);
+ label->left = nullptr;
+ label->right = nullptr;
+ label->omp_region = new_omp_region;
+ gfc_insert_bbt (&label->ns->st_labels, label, compare_st_labels);
+ return label;
+}
/* Called when a statement with a statement label is about to be
accepted. We add the label to the list of the current namespace,
@@ -2812,7 +2926,7 @@ gfc_define_st_label (gfc_st_label *lp, gfc_sl_type type, locus *label_locus)
labelno = lp->value;
- if (lp->defined != ST_LABEL_UNKNOWN)
+ if (lp->defined != ST_LABEL_UNKNOWN && !gfc_in_omp_metadirective_body)
gfc_error ("Duplicate statement label %d at %L and %L", labelno,
&lp->where, label_locus);
else
@@ -2897,6 +3011,7 @@ gfc_reference_st_label (gfc_st_label *lp, gfc_sl_type type)
}
if (lp->referenced == ST_LABEL_DO_TARGET && type == ST_LABEL_DO_TARGET
+ && !gfc_in_omp_metadirective_body
&& !gfc_notify_std (GFC_STD_F95_OBS | GFC_STD_F2018_DEL,
"Shared DO termination label %d at %C", labelno))
return false;
@@ -3172,7 +3287,21 @@ gfc_free_symbol (gfc_symbol *&sym)
gfc_free_formal_arglist (sym->formal);
- gfc_free_namespace (sym->f2k_derived);
+ /* The pdt_type f2k_derived namespaces are copies of that of the pdt_template
+ and are only made if there are finalizers. The complete list of finalizers
+ is kept by the pdt_template and are freed with its f2k_derived. */
+ if (!sym->attr.pdt_type)
+ gfc_free_namespace (sym->f2k_derived);
+ else if (sym->f2k_derived && sym->f2k_derived->finalizers)
+ {
+ gfc_finalizer *p, *q = NULL;
+ for (p = sym->f2k_derived->finalizers; p; p = q)
+ {
+ q = p->next;
+ free (p);
+ }
+ free (sym->f2k_derived);
+ }
set_symbol_common_block (sym, NULL);
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index cb40816..cd13721 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -92,6 +92,8 @@ along with GCC; see the file COPYING3. If not see
#include "trans-array.h"
#include "trans-const.h"
#include "dependency.h"
+#include "cgraph.h" /* For cgraph_node::add_new_function. */
+#include "function.h" /* For push_struct_function. */
static bool gfc_get_array_constructor_size (mpz_t *, gfc_constructor_base);
@@ -10022,6 +10024,142 @@ enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP,
BCAST_ALLOC_COMP};
static gfc_actual_arglist *pdt_param_list;
+static bool generating_copy_helper;
+static hash_set<gfc_symbol *> seen_derived_types;
+
+/* Forward declaration of structure_alloc_comps for wrapper generator. */
+static tree structure_alloc_comps (gfc_symbol *, tree, tree, int, int, int,
+ gfc_co_subroutines_args *, bool);
+
+/* Generate a wrapper function that performs element-wise deep copy for
+ recursive allocatable array components. This wrapper is passed as a
+ function pointer to the runtime helper _gfortran_cfi_deep_copy_array,
+ allowing recursion to happen at runtime instead of compile time. */
+
+static tree
+get_copy_helper_function_type (void)
+{
+ static tree fn_type = NULL_TREE;
+ if (fn_type == NULL_TREE)
+ fn_type = build_function_type_list (void_type_node,
+ pvoid_type_node,
+ pvoid_type_node,
+ NULL_TREE);
+ return fn_type;
+}
+
+static tree
+get_copy_helper_pointer_type (void)
+{
+ static tree ptr_type = NULL_TREE;
+ if (ptr_type == NULL_TREE)
+ ptr_type = build_pointer_type (get_copy_helper_function_type ());
+ return ptr_type;
+}
+
+static tree
+generate_element_copy_wrapper (gfc_symbol *der_type, tree comp_type,
+ int purpose, int caf_mode)
+{
+ tree fndecl, fntype, result_decl;
+ tree dest_parm, src_parm, dest_typed, src_typed;
+ tree der_type_ptr;
+ stmtblock_t block;
+ tree decls;
+ tree body;
+
+ fntype = get_copy_helper_function_type ();
+
+ fndecl = build_decl (input_location, FUNCTION_DECL,
+ create_tmp_var_name ("copy_element"),
+ fntype);
+
+ TREE_STATIC (fndecl) = 1;
+ TREE_USED (fndecl) = 1;
+ DECL_ARTIFICIAL (fndecl) = 1;
+ DECL_IGNORED_P (fndecl) = 0;
+ TREE_PUBLIC (fndecl) = 0;
+ DECL_UNINLINABLE (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_CONTEXT (fndecl) = NULL_TREE;
+ DECL_INITIAL (fndecl) = make_node (BLOCK);
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+ result_decl = build_decl (input_location, RESULT_DECL, NULL_TREE,
+ void_type_node);
+ DECL_ARTIFICIAL (result_decl) = 1;
+ DECL_IGNORED_P (result_decl) = 1;
+ DECL_CONTEXT (result_decl) = fndecl;
+ DECL_RESULT (fndecl) = result_decl;
+
+ dest_parm = build_decl (input_location, PARM_DECL,
+ get_identifier ("dest"), pvoid_type_node);
+ src_parm = build_decl (input_location, PARM_DECL,
+ get_identifier ("src"), pvoid_type_node);
+
+ DECL_ARTIFICIAL (dest_parm) = 1;
+ DECL_ARTIFICIAL (src_parm) = 1;
+ DECL_ARG_TYPE (dest_parm) = pvoid_type_node;
+ DECL_ARG_TYPE (src_parm) = pvoid_type_node;
+ DECL_CONTEXT (dest_parm) = fndecl;
+ DECL_CONTEXT (src_parm) = fndecl;
+
+ DECL_ARGUMENTS (fndecl) = dest_parm;
+ TREE_CHAIN (dest_parm) = src_parm;
+
+ push_struct_function (fndecl);
+ cfun->function_end_locus = input_location;
+
+ pushlevel ();
+ gfc_init_block (&block);
+
+ bool saved_generating = generating_copy_helper;
+ generating_copy_helper = true;
+
+ /* When generating a wrapper, we need a fresh type tracking state to
+ avoid inheriting the parent context's seen_derived_types, which would
+ cause infinite recursion when the wrapper tries to handle the same
+ recursive type. Save elements, clear the set, generate wrapper, then
+ restore elements. */
+ vec<gfc_symbol *> saved_symbols = vNULL;
+ for (hash_set<gfc_symbol *>::iterator it = seen_derived_types.begin ();
+ it != seen_derived_types.end (); ++it)
+ saved_symbols.safe_push (*it);
+ seen_derived_types.empty ();
+
+ der_type_ptr = build_pointer_type (comp_type);
+ dest_typed = fold_convert (der_type_ptr, dest_parm);
+ src_typed = fold_convert (der_type_ptr, src_parm);
+
+ dest_typed = build_fold_indirect_ref (dest_typed);
+ src_typed = build_fold_indirect_ref (src_typed);
+
+ body = structure_alloc_comps (der_type, src_typed, dest_typed,
+ 0, purpose, caf_mode, NULL, false);
+ gfc_add_expr_to_block (&block, body);
+
+ /* Restore saved symbols. */
+ seen_derived_types.empty ();
+ for (unsigned i = 0; i < saved_symbols.length (); i++)
+ seen_derived_types.add (saved_symbols[i]);
+ saved_symbols.release ();
+ generating_copy_helper = saved_generating;
+
+ body = gfc_finish_block (&block);
+ decls = getdecls ();
+
+ poplevel (1, 1);
+
+ DECL_SAVED_TREE (fndecl)
+ = fold_build3_loc (DECL_SOURCE_LOCATION (fndecl), BIND_EXPR,
+ void_type_node, decls, body, DECL_INITIAL (fndecl));
+
+ pop_cfun ();
+
+ cgraph_node::add_new_function (fndecl, false);
+
+ return build1 (ADDR_EXPR, get_copy_helper_pointer_type (), fndecl);
+}
static tree
structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
@@ -10052,7 +10190,6 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
int caf_dereg_mode;
symbol_attribute *attr;
bool deallocate_called;
- static hash_set<gfc_symbol *> seen_derived_types;
gfc_init_block (&fnblock);
@@ -10186,6 +10323,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
&& seen_derived_types.contains (c->ts.u.derived))
|| (c->ts.type == BT_CLASS
&& seen_derived_types.contains (CLASS_DATA (c)->ts.u.derived));
+ bool inside_wrapper = generating_copy_helper;
bool is_pdt_type = c->ts.type == BT_DERIVED
&& c->ts.u.derived->attr.pdt_type;
@@ -10862,8 +11000,65 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
false, false, NULL_TREE, NULL_TREE);
gfc_add_expr_to_block (&fnblock, tmp);
}
+ /* Special case: recursive allocatable array components require
+ runtime helpers to avoid compile-time infinite recursion. Generate
+ a call to _gfortran_cfi_deep_copy_array with an element copy
+ wrapper. When inside a wrapper, reuse current_function_decl. */
+ else if (c->attr.allocatable && c->as && cmp_has_alloc_comps && same_type
+ && purpose == COPY_ALLOC_COMP && !c->attr.proc_pointer
+ && !c->attr.codimension && !caf_in_coarray (caf_mode)
+ && c->ts.type == BT_DERIVED && c->ts.u.derived != NULL)
+ {
+ tree copy_wrapper, call, dest_addr, src_addr, elem_type;
+ tree helper_ptr_type;
+ tree alloc_expr;
+ int comp_rank;
+
+ /* Get the element type from ctype (already the component
+ type). For arrays we need the element type, not the array
+ type. */
+ elem_type = ctype;
+ if (GFC_DESCRIPTOR_TYPE_P (ctype))
+ elem_type = gfc_get_element_type (ctype);
+ else if (TREE_CODE (ctype) == ARRAY_TYPE)
+ elem_type = TREE_TYPE (ctype);
+
+ helper_ptr_type = get_copy_helper_pointer_type ();
+
+ comp_rank = c->as ? c->as->rank : 0;
+ alloc_expr = gfc_duplicate_allocatable_nocopy (dcmp, comp, ctype,
+ comp_rank);
+ gfc_add_expr_to_block (&fnblock, alloc_expr);
+
+ /* Generate or reuse the element copy helper. Inside an
+ existing helper we can reuse the current function to
+ prevent recursive generation. */
+ if (inside_wrapper)
+ copy_wrapper
+ = gfc_build_addr_expr (NULL_TREE, current_function_decl);
+ else
+ copy_wrapper
+ = generate_element_copy_wrapper (c->ts.u.derived, elem_type,
+ purpose, caf_mode);
+ copy_wrapper = fold_convert (helper_ptr_type, copy_wrapper);
+
+ /* Build addresses of descriptors. */
+ dest_addr = gfc_build_addr_expr (pvoid_type_node, dcmp);
+ src_addr = gfc_build_addr_expr (pvoid_type_node, comp);
+
+ /* Build call: _gfortran_cfi_deep_copy_array (&dcmp, &comp,
+ wrapper). */
+ call = build_call_expr_loc (input_location,
+ gfor_fndecl_cfi_deep_copy_array, 3,
+ dest_addr, src_addr,
+ copy_wrapper);
+ gfc_add_expr_to_block (&fnblock, call);
+ }
else if (c->attr.allocatable && !c->attr.proc_pointer
- && (!(cmp_has_alloc_comps && c->as) || c->attr.codimension
+ && (add_when_allocated != NULL_TREE
+ || !cmp_has_alloc_comps
+ || !c->as
+ || c->attr.codimension
|| caf_in_coarray (caf_mode)))
{
rank = c->as ? c->as->rank : 0;
diff --git a/gcc/fortran/trans-common.cc b/gcc/fortran/trans-common.cc
index 135d304..6439a15 100644
--- a/gcc/fortran/trans-common.cc
+++ b/gcc/fortran/trans-common.cc
@@ -488,6 +488,27 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
}
omp_clauses = c;
}
+ /* Also check trans-decl.cc when updating/removing the following;
+ also update f95.c's gfc_gnu_attributes.
+ For the warning, see also OpenMP spec issue 4663. */
+ if (com->omp_groupprivate && com->threadprivate)
+ {
+ /* Unset this flag; implicit 'declare target local(...)' remains. */
+ com->omp_groupprivate = 0;
+ gfc_warning (OPT_Wopenmp,
+ "Ignoring the %<groupprivate%> attribute for "
+ "%<threadprivate%> common block %</%s/%> declared at %L",
+ com->name, &com->where);
+ }
+ if (com->omp_groupprivate)
+ gfc_error ("Sorry, OMP GROUPPRIVATE not implemented, used by common "
+ "block %</%s/%> declared at %L", com->name, &com->where);
+ else if (com->omp_declare_target_local)
+ /* Use 'else if' as groupprivate implies 'local'. */
+ gfc_error ("Sorry, OMP DECLARE TARGET with LOCAL clause not implemented"
+ ", used by common block %</%s/%> declared at %L",
+ com->name, &com->where);
+
if (com->omp_declare_target_link)
DECL_ATTRIBUTES (decl)
= tree_cons (get_identifier ("omp declare target link"),
@@ -497,10 +518,12 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
= tree_cons (get_identifier ("omp declare target"),
omp_clauses, DECL_ATTRIBUTES (decl));
- if (com->omp_declare_target_link || com->omp_declare_target)
+ if (com->omp_declare_target_link || com->omp_declare_target
+ /* FIXME: || com->omp_declare_target_local */)
{
- /* Add to offload_vars; get_create does so for omp_declare_target,
- omp_declare_target_link requires manual work. */
+ /* Add to offload_vars; get_create does so for omp_declare_target
+ and omp_declare_target_local, omp_declare_target_link requires
+ manual work. */
gcc_assert (symtab_node::get (decl) == 0);
symtab_node *node = symtab_node::get_create (decl);
if (node != NULL && com->omp_declare_target_link)
@@ -1045,8 +1068,10 @@ accumulate_equivalence_attributes (symbol_attribute *dummy_symbol, gfc_equiv *e)
dummy_symbol->generic |= attr.generic;
dummy_symbol->automatic |= attr.automatic;
dummy_symbol->threadprivate |= attr.threadprivate;
+ dummy_symbol->omp_groupprivate |= attr.omp_groupprivate;
dummy_symbol->omp_declare_target |= attr.omp_declare_target;
dummy_symbol->omp_declare_target_link |= attr.omp_declare_target_link;
+ dummy_symbol->omp_declare_target_local |= attr.omp_declare_target_local;
dummy_symbol->oacc_declare_copyin |= attr.oacc_declare_copyin;
dummy_symbol->oacc_declare_create |= attr.oacc_declare_create;
dummy_symbol->oacc_declare_deviceptr |= attr.oacc_declare_deviceptr;
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index c31c756..06edc99 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -248,6 +248,9 @@ tree gfor_fndecl_zgemm;
/* RANDOM_INIT function. */
tree gfor_fndecl_random_init; /* libgfortran, 1 image only. */
+/* Deep copy helper for recursive allocatable array components. */
+tree gfor_fndecl_cfi_deep_copy_array;
+
static void
gfc_add_decl_to_parent_function (tree decl)
{
@@ -1557,7 +1560,11 @@ add_attributes_to_decl (tree *decl_p, const gfc_symbol *sym)
clauses = c;
}
- if (sym_attr.omp_device_type != OMP_DEVICE_TYPE_UNSET)
+ /* FIXME: 'declare_target_link' permits both any and host, but
+ will fail if one sets OMP_CLAUSE_DEVICE_TYPE_KIND. */
+ if (sym_attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && !sym_attr.omp_declare_target_link
+ && !sym_attr.omp_declare_target_indirect /* implies 'any' */)
{
tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEVICE_TYPE);
switch (sym_attr.omp_device_type)
@@ -1578,6 +1585,26 @@ add_attributes_to_decl (tree *decl_p, const gfc_symbol *sym)
clauses = c;
}
+ /* Also check trans-common.cc when updating/removing the following;
+ also update f95.c's gfc_gnu_attributes.
+ For the warning, see also OpenMP spec issue 4663. */
+ if (sym_attr.omp_groupprivate && sym_attr.threadprivate)
+ {
+ /* Unset this flag; implicit 'declare target local(...)' remains. */
+ sym_attr.omp_groupprivate = 0;
+ gfc_warning (OPT_Wopenmp,
+ "Ignoring the %<groupprivate%> attribute for "
+ "%<threadprivate%> variable %qs declared at %L",
+ sym->name, &sym->declared_at);
+ }
+ if (sym_attr.omp_groupprivate)
+ gfc_error ("Sorry, OMP GROUPPRIVATE not implemented, "
+ "used by %qs declared at %L", sym->name, &sym->declared_at);
+ else if (sym_attr.omp_declare_target_local)
+ /* Use 'else if' as groupprivate implies 'local'. */
+ gfc_error ("Sorry, OMP DECLARE TARGET with LOCAL clause not implemented, "
+ "used by %qs declared at %L", sym->name, &sym->declared_at);
+
bool has_declare = true;
if (sym_attr.omp_declare_target_link
|| sym_attr.oacc_declare_link)
@@ -3588,6 +3615,23 @@ gfc_build_intrinsic_function_decls (void)
gfc_charlen_type_node, pchar1_type_node, gfc_charlen_type_node,
gfc_logical4_type_node);
+ {
+ tree copy_helper_ptr_type;
+ tree copy_helper_fn_type;
+
+ copy_helper_fn_type = build_function_type_list (void_type_node,
+ pvoid_type_node,
+ pvoid_type_node,
+ NULL_TREE);
+ copy_helper_ptr_type = build_pointer_type (copy_helper_fn_type);
+
+ gfor_fndecl_cfi_deep_copy_array
+ = gfc_build_library_function_decl_with_spec (
+ get_identifier (PREFIX ("cfi_deep_copy_array")), ". R R . ",
+ void_type_node, 3, pvoid_type_node, pvoid_type_node,
+ copy_helper_ptr_type);
+ }
+
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,
@@ -4522,7 +4566,8 @@ gfc_trans_vla_type_sizes (gfc_symbol *sym, stmtblock_t *body)
and using trans_assignment to do the work. Set dealloc to false
if no deallocation prior the assignment is needed. */
void
-gfc_init_default_dt (gfc_symbol * sym, stmtblock_t * block, bool dealloc)
+gfc_init_default_dt (gfc_symbol * sym, stmtblock_t * block, bool dealloc,
+ bool pdt_ok)
{
gfc_expr *e;
tree tmp;
@@ -4531,7 +4576,8 @@ gfc_init_default_dt (gfc_symbol * sym, stmtblock_t * block, bool dealloc)
gcc_assert (block);
/* Initialization of PDTs is done elsewhere. */
- if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.pdt_type)
+ if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.pdt_type
+ && !pdt_ok)
return;
gcc_assert (!sym->attr.allocatable);
@@ -4550,6 +4596,28 @@ gfc_init_default_dt (gfc_symbol * sym, stmtblock_t * block, bool dealloc)
}
+/* Initialize a PDT, when all the components have an initializer. */
+static void
+gfc_init_default_pdt (gfc_symbol *sym, stmtblock_t *block, bool dealloc)
+{
+ /* Allowed in the case where all the components have initializers and
+ there are no LEN components. */
+ if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.pdt_type)
+ {
+ gfc_component *c = sym->ts.u.derived->components;
+ if (!dealloc || !sym->value || sym->value->expr_type != EXPR_STRUCTURE)
+ return;
+ for (; c; c = c->next)
+ if (c->attr.pdt_len || !c->initializer)
+ return;
+ }
+ else
+ return;
+ gfc_init_default_dt (sym, block, dealloc, true);
+ return;
+}
+
+
/* Initialize INTENT(OUT) derived type dummies. As well as giving
them their default initializer, if they have allocatable
components, they have their allocatable components deallocated. */
@@ -4941,6 +5009,9 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
gfc_add_expr_to_block (&tmpblock, tmp);
}
+ if (is_pdt_type)
+ gfc_init_default_pdt (sym, &tmpblock, true);
+
if (!sym->attr.result && !sym->ts.u.derived->attr.alloc_comp)
tmp = gfc_deallocate_pdt_comp (sym->ts.u.derived,
sym->backend_decl,
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 2e88e65..ac85b76 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6696,11 +6696,14 @@ conv_dummy_value (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym,
argse.want_pointer = 1;
gfc_conv_expr (&argse, e);
cond = fold_convert (TREE_TYPE (argse.expr), null_pointer_node);
- cond = fold_build2_loc (input_location, NE_EXPR,
- logical_type_node,
+ cond = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
argse.expr, cond);
- vec_safe_push (optionalargs,
- fold_convert (boolean_type_node, cond));
+ if (e->symtree->n.sym->attr.dummy)
+ cond = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR,
+ logical_type_node,
+ gfc_conv_expr_present (e->symtree->n.sym),
+ cond);
+ vec_safe_push (optionalargs, fold_convert (boolean_type_node, cond));
/* Create "conditional temporary". */
conv_cond_temp (parmse, e, cond);
}
@@ -11697,7 +11700,17 @@ gfc_trans_scalar_assign (gfc_se *lse, gfc_se *rse, gfc_typespec ts,
}
gfc_add_block_to_block (&block, &rse->pre);
- gfc_add_block_to_block (&block, &lse->finalblock);
+
+ /* Skip finalization for self-assignment. */
+ if (deep_copy && lse->finalblock.head)
+ {
+ tmp = build3_v (COND_EXPR, cond, build_empty_stmt (input_location),
+ gfc_finish_block (&lse->finalblock));
+ gfc_add_expr_to_block (&block, tmp);
+ }
+ else
+ gfc_add_block_to_block (&block, &lse->finalblock);
+
gfc_add_block_to_block (&block, &lse->pre);
gfc_add_modify (&block, lse->expr,
@@ -12683,12 +12696,30 @@ alloc_scalar_allocatable_for_assignment (stmtblock_t *block,
to make sure we do not check for reallocation unneccessarily. */
+/* Strip parentheses from an expression to get the underlying variable.
+ This is needed for self-assignment detection since (a) creates a
+ parentheses operator node. */
+
+static gfc_expr *
+strip_parentheses (gfc_expr *expr)
+{
+ while (expr->expr_type == EXPR_OP
+ && expr->value.op.op == INTRINSIC_PARENTHESES)
+ expr = expr->value.op.op1;
+ return expr;
+}
+
+
static bool
is_runtime_conformable (gfc_expr *expr1, gfc_expr *expr2)
{
gfc_actual_arglist *a;
gfc_expr *e1, *e2;
+ /* Strip parentheses to handle cases like a = (a). */
+ expr1 = strip_parentheses (expr1);
+ expr2 = strip_parentheses (expr2);
+
switch (expr2->expr_type)
{
case EXPR_VARIABLE:
@@ -13390,10 +13421,15 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
}
/* Comply with F2018 (7.5.6.3). Make sure that any finalization code is added
- after evaluation of the rhs and before reallocation. */
+ after evaluation of the rhs and before reallocation.
+ Skip finalization for self-assignment to avoid use-after-free.
+ Strip parentheses from both sides to handle cases like a = (a). */
final_expr = gfc_assignment_finalizer_call (&lse, expr1, init_flag);
- if (final_expr && !(expr2->expr_type == EXPR_VARIABLE
- && expr2->symtree->n.sym->attr.artificial))
+ if (final_expr
+ && gfc_dep_compare_expr (strip_parentheses (expr1),
+ strip_parentheses (expr2)) != 0
+ && !(strip_parentheses (expr2)->expr_type == EXPR_VARIABLE
+ && strip_parentheses (expr2)->symtree->n.sym->attr.artificial))
{
if (lss == gfc_ss_terminator)
{
@@ -13416,13 +13452,18 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
/* If nothing else works, do it the old fashioned way! */
if (tmp == NULL_TREE)
- tmp
- = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
- gfc_expr_is_variable (expr2) || scalar_to_array
- || expr2->expr_type == EXPR_ARRAY,
- !(l_is_temp || init_flag) && dealloc,
- expr1->symtree->n.sym->attr.codimension,
- assoc_assign);
+ {
+ /* Strip parentheses to detect cases like a = (a) which need deep_copy. */
+ gfc_expr *expr2_stripped = strip_parentheses (expr2);
+ tmp
+ = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
+ gfc_expr_is_variable (expr2_stripped)
+ || scalar_to_array
+ || expr2->expr_type == EXPR_ARRAY,
+ !(l_is_temp || init_flag) && dealloc,
+ expr1->symtree->n.sym->attr.codimension,
+ assoc_assign);
+ }
/* Add the lse pre block to the body */
gfc_add_block_to_block (&body, &lse.pre);
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 5b9111d3..91c0301 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -12559,11 +12559,23 @@ conv_intrinsic_atomic_op (gfc_code *code)
else
image_index = integer_zero_node;
+ /* Ensure VALUE names addressable storage: taking the address of a
+ constant is invalid in C, and scalars need a temporary as well. */
if (!POINTER_TYPE_P (TREE_TYPE (value)))
{
- tmp = gfc_create_var (TREE_TYPE (TREE_TYPE (atom)), "value");
- gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), value));
- value = gfc_build_addr_expr (NULL_TREE, tmp);
+ tree elem
+ = fold_convert (TREE_TYPE (TREE_TYPE (atom)), value);
+ elem = gfc_trans_force_lval (&block, elem);
+ value = gfc_build_addr_expr (NULL_TREE, elem);
+ }
+ else if (TREE_CODE (value) == ADDR_EXPR
+ && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+ {
+ tree elem
+ = fold_convert (TREE_TYPE (TREE_TYPE (atom)),
+ build_fold_indirect_ref (value));
+ elem = gfc_trans_force_lval (&block, elem);
+ value = gfc_build_addr_expr (NULL_TREE, elem);
}
gfc_init_se (&argse, NULL);
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 69a70d7..8eb4fc4 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -4180,7 +4180,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
tree type = TREE_TYPE (decl);
if (n->sym->ts.type == BT_CHARACTER
&& n->sym->ts.deferred
- && n->sym->attr.omp_declare_target
+ && (n->sym->attr.omp_declare_target
+ || n->sym->attr.omp_declare_target_link
+ || n->sym->attr.omp_declare_target_local)
&& (always_modifier || n->sym->attr.pointer)
&& op != EXEC_OMP_TARGET_EXIT_DATA
&& n->u.map.op != OMP_MAP_DELETE
@@ -5263,6 +5265,37 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
}
+ if (clauses->dyn_groupprivate)
+ {
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr (&se, clauses->dyn_groupprivate);
+ gfc_add_block_to_block (block, &se.pre);
+ tree expr = (CONSTANT_CLASS_P (se.expr) || DECL_P (se.expr)
+ ? se.expr : gfc_evaluate_now (se.expr, block));
+ gfc_add_block_to_block (block, &se.post);
+
+ enum omp_clause_fallback_kind kind = OMP_CLAUSE_FALLBACK_UNSPECIFIED;
+ switch (clauses->fallback)
+ {
+ case OMP_FALLBACK_ABORT:
+ kind = OMP_CLAUSE_FALLBACK_ABORT;
+ break;
+ case OMP_FALLBACK_DEFAULT_MEM:
+ kind = OMP_CLAUSE_FALLBACK_DEFAULT_MEM;
+ break;
+ case OMP_FALLBACK_NULL:
+ kind = OMP_CLAUSE_FALLBACK_NULL;
+ break;
+ case OMP_FALLBACK_NONE:
+ break;
+ }
+ c = build_omp_clause (gfc_get_location (&where),
+ OMP_CLAUSE_DYN_GROUPPRIVATE);
+ OMP_CLAUSE_DYN_GROUPPRIVATE_KIND (c) = kind;
+ OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR (c) = expr;
+ omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+ }
+
chunk_size = NULL_TREE;
if (clauses->chunk_size)
{
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 1d04b22..52cebf5 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -666,7 +666,8 @@ tree gfc_get_symbol_decl (gfc_symbol *);
tree gfc_conv_initializer (gfc_expr *, gfc_typespec *, tree, bool, bool, bool);
/* Assign a default initializer to a derived type. */
-void gfc_init_default_dt (gfc_symbol *, stmtblock_t *, bool);
+void gfc_init_default_dt (gfc_symbol *, stmtblock_t *, bool,
+ bool pdt_ok = false);
/* Substitute a temporary variable in place of the real one. */
void gfc_shadow_sym (gfc_symbol *, tree, gfc_saved_var *);
@@ -1004,6 +1005,9 @@ extern GTY(()) tree gfor_fndecl_ieee_procedure_exit;
extern GTY(()) tree gfor_fndecl_random_init;
extern GTY(()) tree gfor_fndecl_caf_random_init;
+/* Deep copy helper for recursive allocatable array components. */
+extern GTY(()) tree gfor_fndecl_cfi_deep_copy_array;
+
/* True if node is an integer constant. */
#define INTEGER_CST_P(node) (TREE_CODE(node) == INTEGER_CST)