Fortran: Add code gen for do,concurrent's LOCAL/LOCAL_INIT [PR101602]

Implement LOCAL and LOCAL_INIT; we locally replace the tree declaration by
a local declaration of the outer variable. The 'local_init' then assigns
the value at the beginning of each loop iteration from the outer
declaration.

Note that the current implementation does not handle LOCAL with types that
have a default initializer and LOCAL/LOCAL_INIT for assumed-shape arrays;
this is diagnosed with a sorry error.

	PR fortran/101602

gcc/fortran/ChangeLog:

	* resolve.cc (resolve_locality_spec): Remove 'sorry, unimplemented'.
	* trans-stmt.cc (struct symbol_and_tree_t): New.
	(gfc_trans_concurrent_locality_spec): New.
	(gfc_trans_forall_1): Call it; update to handle local and local_init.
	* trans-decl.cc (gfc_start_saved_local_decls,
	gfc_stop_saved_local_decls): New; moved code from ...
	(gfc_process_block_locals): ... here. Call it.
	* trans.h (gfc_start_saved_local_decls,
	gfc_stop_saved_local_decls): Declare.

gcc/testsuite/ChangeLog:

	* gfortran.dg/do_concurrent_8_f2023.f90: Update for removed 'sorry,
	unimplemented'.
	* gfortran.dg/do_concurrent_9.f90: Likewise.
	* gfortran.dg/do_concurrent_all_clauses.f90: Likewise.
	* gfortran.dg/do_concurrent_local_init.f90: Likewise.
	* gfortran.dg/do_concurrent_locality_specs.f90: Likewise.
	* gfortran.dg/do_concurrent_11.f90: New test.
	* gfortran.dg/do_concurrent_12.f90: New test.
	* gfortran.dg/do_concurrent_13.f90: New test.
	* gfortran.dg/do_concurrent_14.f90: New test.
	* gfortran.dg/do_concurrent_15.f90: New test.
This commit is contained in:
Tobias Burnus 2025-04-09 08:21:19 +02:00
parent 94438ca827
commit 2d7e1d6e40
14 changed files with 808 additions and 31 deletions

View file

@ -8422,13 +8422,6 @@ resolve_locality_spec (gfc_code *code, gfc_namespace *ns)
plist = &((*plist)->next);
}
}
if (code->ext.concur.locality[LOCALITY_LOCAL]
|| code->ext.concur.locality[LOCALITY_LOCAL_INIT])
{
gfc_error ("Sorry, LOCAL and LOCAL_INIT are not yet supported for "
"%<do concurrent%> constructs at %L", &code->loc);
}
}
/* Resolve a list of FORALL iterators. The FORALL index-name is constrained

View file

@ -8361,23 +8361,17 @@ gfc_generate_block_data (gfc_namespace * ns)
rest_of_decl_compilation (decl, 1, 0);
}
/* Process the local variables of a BLOCK construct. */
void
gfc_start_saved_local_decls ()
{
gcc_checking_assert (current_function_decl != NULL_TREE);
saved_local_decls = NULL_TREE;
}
void
gfc_process_block_locals (gfc_namespace* ns)
gfc_stop_saved_local_decls ()
{
tree decl;
saved_local_decls = NULL_TREE;
has_coarray_vars_or_accessors = caf_accessor_head != NULL;
generate_local_vars (ns);
if (flag_coarray == GFC_FCOARRAY_LIB && has_coarray_vars_or_accessors)
generate_coarray_init (ns);
decl = nreverse (saved_local_decls);
tree decl = nreverse (saved_local_decls);
while (decl)
{
tree next;
@ -8390,5 +8384,20 @@ gfc_process_block_locals (gfc_namespace* ns)
saved_local_decls = NULL_TREE;
}
/* Process the local variables of a BLOCK construct. */
void
gfc_process_block_locals (gfc_namespace* ns)
{
gfc_start_saved_local_decls ();
has_coarray_vars_or_accessors = caf_accessor_head != NULL;
generate_local_vars (ns);
if (flag_coarray == GFC_FCOARRAY_LIB && has_coarray_vars_or_accessors)
generate_coarray_init (ns);
gfc_stop_saved_local_decls ();
}
#include "gt-fortran-trans-decl.h"

View file

@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_VECTOR
#include "config.h"
#include "system.h"
#include "coretypes.h"
@ -5093,6 +5093,138 @@ gfc_trans_pointer_assign_need_temp (gfc_expr * expr1, gfc_expr * expr2,
}
}
/* For saving the outer-variable data when doing
LOCAL and LOCAL_INIT substitution. */
struct symbol_and_tree_t
{
gfc_symbol *sym;
gfc_expr *value;
tree decl;
symbol_attribute attr;
};
/* Handle the LOCAL and LOCAL_INIT locality specifiers. This has to be
called twice, once with after_body=false - and then after the loop
body has been processed with after_body=true.
Creates a copy of the variables that appear in the LOCAL and LOCAL_INIT
locality specifiers of 'do concurrent' - and use it in the original
gfc_symbol. The declaration is then reset by after_body=true.
Variables in LOCAL_INIT are set in every loop iteration. */
void
gfc_trans_concurrent_locality_spec (bool after_body, stmtblock_t *body,
std::vector<symbol_and_tree_t> *saved_decls,
gfc_expr_list **locality_list)
{
if (!locality_list[LOCALITY_LOCAL] && !locality_list[LOCALITY_LOCAL_INIT])
return;
if (after_body)
{
for (unsigned i = 0; i < saved_decls->size (); i++)
{
(*saved_decls)[i].sym->backend_decl = (*saved_decls)[i].decl;
(*saved_decls)[i].sym->attr = (*saved_decls)[i].attr;
(*saved_decls)[i].sym->value = (*saved_decls)[i].value;
}
return;
}
gfc_expr_list *el;
int cnt = 0;
for (int i = 0; i <= 1; i++)
for (el = locality_list[i == 0 ? LOCALITY_LOCAL : LOCALITY_LOCAL_INIT];
el; el = el->next)
{
gfc_symbol *outer_sym = el->expr->symtree->n.sym;
if (!outer_sym->backend_decl)
outer_sym->backend_decl = gfc_get_symbol_decl (outer_sym);
cnt++;
}
saved_decls->resize (cnt);
/* The variables have to be created in the scope of the loop body. */
if (!body->has_scope)
{
gcc_checking_assert (body->head == NULL_TREE);
gfc_start_block (body);
}
gfc_start_saved_local_decls ();
cnt = 0;
static_assert (LOCALITY_LOCAL_INIT - LOCALITY_LOCAL == 1);
for (int type = LOCALITY_LOCAL;
type <= LOCALITY_LOCAL_INIT; type++)
for (el = locality_list[type]; el; el = el->next)
{
gfc_symbol *sym = el->expr->symtree->n.sym;
(*saved_decls)[cnt].sym = sym;
(*saved_decls)[cnt].attr = sym->attr;
(*saved_decls)[cnt].value = sym->value;
(*saved_decls)[cnt].decl = sym->backend_decl;
if (sym->attr.dimension && sym->as->type == AS_ASSUMED_SHAPE)
{
gfc_error ("Sorry, %s specifier at %L for assumed-size array %qs "
"is not yet supported",
type == LOCALITY_LOCAL ? "LOCAL" : "LOCAL_INIT",
&el->expr->where, sym->name);
continue;
}
gfc_symbol outer_sym = *sym;
/* Create the inner local variable. */
sym->backend_decl = NULL;
sym->value = NULL;
sym->attr.save = SAVE_NONE;
sym->attr.value = 0;
sym->attr.dummy = 0;
sym->attr.optional = 0;
{
/* Slightly ugly hack for adding the decl via add_decl_as_local. */
gfc_symbol dummy_block_sym;
dummy_block_sym.attr.flavor = FL_LABEL;
gfc_symbol *saved_proc_name = sym->ns->proc_name;
sym->ns->proc_name = &dummy_block_sym;
gfc_get_symbol_decl (sym);
DECL_SOURCE_LOCATION (sym->backend_decl)
= gfc_get_location (&el->expr->where);
sym->ns->proc_name = saved_proc_name;
}
symbol_attribute attr = gfc_expr_attr (el->expr);
if (type == LOCALITY_LOCAL
&& !attr.pointer
&& sym->ts.type == BT_DERIVED
&& gfc_has_default_initializer (sym->ts.u.derived))
/* Cf. PR fortran/ */
gfc_error ("Sorry, LOCAL specifier at %L for %qs of derived type with"
" default initializer is not yet supported",
&el->expr->where, sym->name);
if (type == LOCALITY_LOCAL_INIT)
{
/* LOCAL_INIT: local_var = outer_var. */
gfc_symtree st = *el->expr->symtree;
st.n.sym = &outer_sym;
gfc_expr expr = *el->expr;
expr.symtree = &st;
tree t = (attr.pointer
? gfc_trans_pointer_assignment (el->expr, &expr)
: gfc_trans_assignment (el->expr, &expr, false, false,
false, false));
gfc_add_expr_to_block (body, t);
}
cnt++;
}
gfc_stop_saved_local_decls ();
}
/* FORALL and WHERE statements are really nasty, especially when you nest
them. All the rhs of a forall assignment must be evaluated before the
@ -5348,9 +5480,19 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info)
gfc_init_block (&body);
cycle_label = gfc_build_label_decl (NULL_TREE);
code->cycle_label = cycle_label;
/* Handle LOCAL and LOCAL_INIT. */
std::vector<symbol_and_tree_t> saved_decls;
gfc_trans_concurrent_locality_spec (false, &body, &saved_decls,
code->ext.concur.locality);
/* Translate the body. */
tmp = gfc_trans_code (code->block->next);
gfc_add_expr_to_block (&body, tmp);
/* Reset locality variables. */
gfc_trans_concurrent_locality_spec (true, &body, &saved_decls,
code->ext.concur.locality);
if (TREE_USED (cycle_label))
{
tmp = build1_v (LABEL_EXPR, cycle_label);

View file

@ -804,6 +804,8 @@ tree gfc_build_library_function_decl_with_spec (tree name, const char *spec,
tree rettype, int nargs, ...);
/* Process the local variable decls of a block construct. */
void gfc_start_saved_local_decls ();
void gfc_stop_saved_local_decls ();
void gfc_process_block_locals (gfc_namespace*);
/* Output initialization/clean-up code that was deferred. */

View file

@ -0,0 +1,53 @@
! { dg-do run }
! { dg-additional-options "-fdump-tree-original" }
module m
implicit none
contains
subroutine sub(y,str)
integer :: y, x, i
character(len=5) :: str
character(len=5) :: z = "abcde"
logical :: error = .false.
x = 5
z = "12345"
do concurrent (i = 1: 3) local_init(x) local_init(z) shared(error)default(none)
if (x /= 5) error = .true.
if (z /= "12345") error = .true.
x = 99
z = "XXXXX"
end do
if (x /= 5 .or. z /= "12345") stop 1
if (error) stop 2
do concurrent (i = 1: 3) local(y) local(str) shared(error) default(none)
y = 99
str = "XXXXX"
end do
if (y /= 42 .or. str /= "ABCDE") stop 3
end
end
use m
implicit none
character(len=5) :: chars = "ABCDE"
integer :: fourtytwo = 42
call sub(fourtytwo, chars)
end
! { dg-final { scan-tree-dump-times " integer\\(kind=4\\) x;" 2 "original" } }
! { dg-final { scan-tree-dump-times " static character\\(kind=1\\) z\\\[1:5\\\] = .abcde.;" 1 "original" } }
! { dg-final { scan-tree-dump-times " character\\(kind=1\\) z\\\[1:5\\\];" 1 "original" } }
! { dg-final { scan-tree-dump-times " integer\\(kind=4\\) y;" 1 "original" } }
! { dg-final { scan-tree-dump-times " character\\(kind=1\\) str\\\[1:5\\\];" 1 "original" } }
! { dg-final { scan-tree-dump-times " x = 5;" 1 "original" } }
! { dg-final { scan-tree-dump-times " __builtin_memmove \\(\\(void \\*\\) &z, \\(void \\*\\) &.12345.\\\[1\\\]\{lb: 1 sz: 1\}, 5\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times " x = x;" 1 "original" } }
! { dg-final { scan-tree-dump-times " __builtin_memmove \\(\\(void \\*\\) &z, \\(void \\*\\)\\ &z, 5\\);" 1 "original" } }
! { dg-final { scan-tree-dump-not " y = y;" "original" } }
! { dg-final { scan-tree-dump-times " __builtin_memmove \\(\\(void \\*\\) &str, \\(void \\*\\)\\ &.XXXXX.\\\[1\\\]\{lb: 1 sz: 1\}, 5\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times " __builtin_memmove \\(\\(void \\*\\) &str," 1 "original" } }

View file

@ -0,0 +1,175 @@
! { dg-do compile }
! Fails to compile because default initializers aren't supported.
! cf. do_concurrent_14.f90 and PR fortran/101602 (comment 6)
module m
implicit none
type t
integer :: y = 44
integer, pointer :: ptr(:) => null()
end type t
contains
subroutine sub(x, y)
integer :: i
type(t) :: x, y(4)
type(t) :: a, b(3)
logical :: error = .false.
integer, target :: tgt(6)
integer, target :: tgt2(7)
x%y = 100
x%ptr => tgt
y(1)%y = 101
y(2)%y = 102
y(3)%y = 103
y(4)%y = 104
y(1)%ptr => tgt
y(2)%ptr => tgt
y(3)%ptr => tgt
y(4)%ptr => tgt
a%y = 105
a%ptr => tgt
b(1)%y = 106
b(2)%y = 107
b(3)%y = 108
b(1)%ptr => tgt
b(2)%ptr => tgt
b(3)%ptr => tgt
do concurrent (i = 1: 3) local_init(x,y,a,b) shared(error,tgt,tgt2) default(none)
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
error = .true.
x%y = 900
x%ptr => tgt
y(1)%y = 901
y(2)%y = 902
y(3)%y = 903
y(4)%y = 904
y(1)%ptr => tgt2
y(2)%ptr => tgt2
y(3)%ptr => tgt2
y(4)%ptr => tgt2
a%y = 905
a%ptr => tgt
b(1)%y = 906
b(2)%y = 907
b(3)%y = 908
b(1)%ptr => tgt2
b(2)%ptr => tgt2
b(3)%ptr => tgt2
end do
if (error) stop 1
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
stop 2
do concurrent (i = 1: 3) local(x,y,a,b) shared(error,tgt,tgt2) default(none)
! { dg-error "34: Sorry, LOCAL specifier at .1. for 'x' of derived type with default initializer is not yet supported" "" { target *-*-* } .-1 }
! { dg-error "36: Sorry, LOCAL specifier at .1. for 'y' of derived type with default initializer is not yet supported" "" { target *-*-* } .-2 }
! { dg-error "38: Sorry, LOCAL specifier at .1. for 'a' of derived type with default initializer is not yet supported" "" { target *-*-* } .-3 }
! { dg-error "40: Sorry, LOCAL specifier at .1. for 'b' of derived type with default initializer is not yet supported" "" { target *-*-* } .-4 }
if (x%y /= 44) error = .true.
if (any(y(:)%y /= 44)) error = .true.
if (a%y /= 44) error = .true.
if (any (b(:)%y /= 44)) error = .true.
if (associated(x%ptr)) error = .true.
if (associated(y(1)%ptr)) error = .true.
if (associated(y(2)%ptr)) error = .true.
if (associated(y(3)%ptr)) error = .true.
if (associated(y(4)%ptr)) error = .true.
if (associated(a%ptr)) error = .true.
if (associated(b(1)%ptr)) error = .true.
if (associated(b(2)%ptr)) error = .true.
if (associated(b(3)%ptr)) error = .true.
x%y = 900
x%ptr => tgt
y(1)%y = 901
y(2)%y = 902
y(3)%y = 903
y(4)%y = 904
y(1)%ptr => tgt2
y(2)%ptr => tgt2
y(3)%ptr => tgt2
y(4)%ptr => tgt2
a%y = 905
a%ptr => tgt
b(1)%y = 906
b(2)%y = 907
b(3)%y = 908
b(1)%ptr => tgt2
b(2)%ptr => tgt2
b(3)%ptr => tgt2
end do
if (error) stop 3
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
stop 4
end
end
use m
implicit none
type(t) :: q, r(4)
call sub(q,r)
end

View file

@ -0,0 +1,211 @@
! { dg-do run }
! { dg-additional-options "-fdump-tree-original" }
module m
implicit none
type t
integer :: y = 44
integer, pointer :: ptr(:) => null()
end type t
contains
subroutine sub(x, y)
integer :: i
type(t), pointer :: x, y(:)
type(t), pointer :: a, b(:)
logical :: error = .false.
integer, target :: tgt(6)
integer, target :: tgt2(7)
type(t), pointer :: x_saved
type(t), pointer :: y_saved(:)
type(t), pointer :: a_saved
type(t), pointer :: b_saved(:)
allocate(a, b(3))
x_saved => x
y_saved => y
a_saved => a
b_saved => b
x%y = 100
x%ptr => tgt
y(1)%y = 101
y(2)%y = 102
y(3)%y = 103
y(4)%y = 104
y(1)%ptr => tgt
y(2)%ptr => tgt
y(3)%ptr => tgt
y(4)%ptr => tgt
a%y = 105
a%ptr => tgt
b(1)%y = 106
b(2)%y = 107
b(3)%y = 108
b(1)%ptr => tgt
b(2)%ptr => tgt
b(3)%ptr => tgt
do concurrent (i = 1: 3) local_init(x,y,a,b) shared(error,tgt,tgt2,x_saved,y_saved,a_saved,b_saved) default(none)
if (.not.associated(x,x_saved)) error = .true.
if (.not.associated(y,y_saved)) error = .true.
if (.not.associated(a,a_saved)) error = .true.
if (.not.associated(b,b_saved)) error = .true.
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
error = .true.
if (i == 3) then
! This is a hack - assuming no concurrency!
x%y = 900
y(1)%y = 901
a%y = 905
b(1)%y = 906
endif
x => null()
y => null()
a => null()
b => null()
end do
if (error) stop 1
if (.not.associated(x,x_saved)) stop 2
if (.not.associated(y,y_saved)) stop 3
if (.not.associated(a,a_saved)) stop 4
if (.not.associated(b,b_saved)) stop 5
! Value a bit changed because of the hack above!
if (x%y /= 900 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 901 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 905 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 906 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
stop 6
! Reset
x%y = 100
y(1)%y = 101
a%y = 105
b(1)%y = 106
do concurrent (i = 1: 3) local(x,y,a,b) shared(error) default(none)
x => null()
y => null()
a => null()
b => null()
end do
if (.not.associated(x,x_saved)) stop 7
if (.not.associated(y,y_saved)) stop 8
if (.not.associated(a,a_saved)) stop 9
if (.not.associated(b,b_saved)) stop 10
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
stop 11
do concurrent (i = 1: 3) local(x,y,a,b) shared(error,tgt,tgt2,x_saved,y_saved,a_saved,b_saved) default(none)
x => a_saved
y => b_saved
a => x_saved
b => y_saved
if (a%y /= 100 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 101 &
.or. b(2)%y /= 102 &
.or. b(3)%y /= 103 &
.or. b(4)%y /= 104 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt) &
.or. .not.associated (b(4)%ptr, tgt) &
.or. x%y /= 105 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 106 &
.or. y(2)%y /= 107 &
.or. y(3)%y /= 108 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt)) &
error = .true.
end do
if (.not.associated(x,x_saved)) stop 12
if (.not.associated(y,y_saved)) stop 13
if (.not.associated(a,a_saved)) stop 14
if (.not.associated(b,b_saved)) stop 15
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
stop 16
end
end
use m
implicit none
type(t), pointer :: q, r(:)
allocate(q, r(4))
call sub(q,r)
end

View file

@ -0,0 +1,176 @@
! { dg-do run }
module m
implicit none
type t
integer :: y = 44
integer, pointer :: ptr(:) => null()
end type t
! No default initializers, cf. do_concurrent_12.f90
! and PR fortran/101602 (comment 6)
type t2
integer :: y
integer, pointer :: ptr(:)
end type t2
contains
subroutine sub(x, y)
integer :: i
type(t) :: x, y(4)
type(t) :: a, b(3)
type(t2) :: x2, y2(4)
type(t2) :: a2, b2(3)
logical :: error = .false.
integer, target :: tgt(6)
integer, target :: tgt2(7)
x%y = 100
x%ptr => tgt
y(1)%y = 101
y(2)%y = 102
y(3)%y = 103
y(4)%y = 104
y(1)%ptr => tgt
y(2)%ptr => tgt
y(3)%ptr => tgt
y(4)%ptr => tgt
a%y = 105
a%ptr => tgt
b(1)%y = 106
b(2)%y = 107
b(3)%y = 108
b(1)%ptr => tgt
b(2)%ptr => tgt
b(3)%ptr => tgt
! Copy values from 't' to associated 't2' variables
x2%y = x%y
x2%ptr => x%ptr
a2%y = a%y
a2%ptr => a%ptr
y2(:)%y = y(:)%y
do i = 1, size(y)
y2(i)%ptr => y(i)%ptr
end do
b2(:)%y = b(:)%y
do i = 1, size(b)
b2(i)%ptr => b(i)%ptr
end do
do concurrent (i = 1: 3) local_init(x,y,a,b) shared(error,tgt,tgt2) default(none)
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
error = .true.
x%y = 900
x%ptr => tgt
y(1)%y = 901
y(2)%y = 902
y(3)%y = 903
y(4)%y = 904
y(1)%ptr => tgt2
y(2)%ptr => tgt2
y(3)%ptr => tgt2
y(4)%ptr => tgt2
a%y = 905
a%ptr => tgt
b(1)%y = 906
b(2)%y = 907
b(3)%y = 908
b(1)%ptr => tgt2
b(2)%ptr => tgt2
b(3)%ptr => tgt2
end do
if (error) stop 1
if (x%y /= 100 &
.or. .not.associated (x%ptr, tgt) &
.or. y(1)%y /= 101 &
.or. y(2)%y /= 102 &
.or. y(3)%y /= 103 &
.or. y(4)%y /= 104 &
.or. .not.associated (y(1)%ptr, tgt) &
.or. .not.associated (y(2)%ptr, tgt) &
.or. .not.associated (y(3)%ptr, tgt) &
.or. .not.associated (y(4)%ptr, tgt) &
.or. a%y /= 105 &
.or. .not.associated (a%ptr, tgt) &
.or. b(1)%y /= 106 &
.or. b(2)%y /= 107 &
.or. b(3)%y /= 108 &
.or. .not.associated (b(1)%ptr, tgt) &
.or. .not.associated (b(2)%ptr, tgt) &
.or. .not.associated (b(3)%ptr, tgt)) &
stop 2
! Use version without default initializers
do concurrent (i = 1: 3) local(x2,y2,a2,b2) shared(error,tgt,tgt2) default(none)
x2%y = 900
x2%ptr => tgt
y2(1)%y = 901
y2(2)%y = 902
y2(3)%y = 903
y2(4)%y = 904
y2(1)%ptr => tgt2
y2(2)%ptr => tgt2
y2(3)%ptr => tgt2
y2(4)%ptr => tgt2
a2%y = 905
a2%ptr => tgt
b2(1)%y = 906
b2(2)%y = 907
b2(3)%y = 908
b2(1)%ptr => tgt2
b2(2)%ptr => tgt2
b2(3)%ptr => tgt2
end do
if (error) stop 3
if (x2%y /= 100 &
.or. .not.associated (x2%ptr, tgt) &
.or. y2(1)%y /= 101 &
.or. y2(2)%y /= 102 &
.or. y2(3)%y /= 103 &
.or. y2(4)%y /= 104 &
.or. .not.associated (y2(1)%ptr, tgt) &
.or. .not.associated (y2(2)%ptr, tgt) &
.or. .not.associated (y2(3)%ptr, tgt) &
.or. .not.associated (y2(4)%ptr, tgt) &
.or. a2%y /= 105 &
.or. .not.associated (a2%ptr, tgt) &
.or. b2(1)%y /= 106 &
.or. b2(2)%y /= 107 &
.or. b2(3)%y /= 108 &
.or. .not.associated (b2(1)%ptr, tgt) &
.or. .not.associated (b2(2)%ptr, tgt) &
.or. .not.associated (b2(3)%ptr, tgt)) &
stop 4
end
end
use m
implicit none
type(t) :: q, r(4)
call sub(q,r)
end

View file

@ -0,0 +1,20 @@
! { dg-do compile }
! Fails to compile because assumed-size arrays are not yet
! handled with LOCAL / LOCAL_INIT, cf. PR fortran/101602 (comment 6)
subroutine test_it(xx, yy)
implicit none
integer :: xx(:), yy(:,:)
integer :: i, sz1, sz2
sz1 = size(xx)
do , concurrent (i = 1 : sz1) local(xx) ! { dg-error "39: Sorry, LOCAL specifier at .1. for assumed-size array 'xx' is not yet supported" }
xx(i) = 1
end do
sz2 = size(yy,dim=1)
do , concurrent (i=1:sz2) local_init(yy) ! { dg-error "40: Sorry, LOCAL_INIT specifier at .1. for assumed-size array 'yy' is not yet supported" }
yy(i,:) = 1
end do
end

View file

@ -8,10 +8,8 @@ program do_concurrent_complex
product = 1
do concurrent (i = 1:10) local(j) shared(sum) reduce(+:sum)
! { dg-error "Variable .sum. at .1. has already been specified in a locality-spec" "" { target *-*-* } .-1 }
! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" "" { target *-*-* } .-2 }
do concurrent (j = 1:10) local(k) shared(product) reduce(*:product)
! { dg-error "Variable .product. at .1. has already been specified in a locality-spec" "" { target *-*-* } .-1 }
! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" "" { target *-*-* } .-2 }
do concurrent (k = 1:10)
array(i,j,k) = i * j * k
sum = sum + array(i,j,k)
@ -20,4 +18,4 @@ program do_concurrent_complex
end do
end do
print *, sum, product
end program do_concurrent_complex
end program do_concurrent_complex

View file

@ -6,7 +6,7 @@ program do_concurrent_default_none
x = 0
y = 0
z = 0
do concurrent (i = 1:10) default(none) shared(x) local(y) ! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported" }
do concurrent (i = 1:10) default(none) shared(x) local(y)
! { dg-error "Variable 'z' .* not specified in a locality spec .* but required due to DEFAULT \\(NONE\\)" "" { target *-*-* } .-1 }
x = x + i
y = i * 2

View file

@ -11,7 +11,6 @@ program do_concurrent_all_clauses
shared(arr, squared, sum, max_val) &
reduce(+:sum) & ! { dg-error "Variable 'sum' at \\(1\\) has already been specified in a locality-spec" }
reduce(max:max_val) ! { dg-error "Variable 'max_val' at \\(1\\) has already been specified in a locality-spec" }
! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported*" "" { target *-*-* } .-1 }
block
integer :: temp2
temp = i * 2

View file

@ -3,9 +3,9 @@
program do_concurrent_local_init
implicit none
integer :: i, arr(10), temp
do concurrent (i = 1:10) local_init(temp) ! { dg-error "LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" }
do concurrent (i = 1:10) local_init(temp)
temp = i
arr(i) = temp
end do
print *, arr
end program do_concurrent_local_init
end program do_concurrent_local_init

View file

@ -6,9 +6,8 @@ do , concurrent (i = 1:5) shared(j,jj) local(k,kk) local_init(ll,lll)
! { dg-warning "Variable 'kk' in locality-spec at \\(1\\) is not used \\\[-Wunused-variable\\\]" "" { target *-*-* } .-1 }
! { dg-warning "Variable 'll' in locality-spec at \\(1\\) is not used \\\[-Wunused-variable\\\]" "" { target *-*-* } .-2 }
! { dg-warning "Variable 'jj' in locality-spec at \\(1\\) is not used \\\[-Wunused-variable\\\]" "" { target *-*-* } .-3 }
! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" "" { target *-*-* } .-4 }
j = 5
k = 7
lll = 8
end do
end
end