https://gcc.gnu.org/g:37724f8a90f0b9ebc5d8883ea0af71edaef2cc35
commit r16-9106-g37724f8a90f0b9ebc5d8883ea0af71edaef2cc35 Author: Jerry DeLisle <[email protected]> Date: Wed May 27 21:00:19 2026 -0700 fortran: ICE in DO CONCURRENT with DEFAULT(NONE) inside ASSOCIATE Two bugs in check_default_none_expr caused a segfault when a DO CONCURRENT with inline type-spec iterators (e.g. "integer :: i = 1:10") contained an ASSOCIATE construct. Bug 1: sym->ns->code was used to locate the ext.concur.forall_iterator list. When a symbol's namespace is an ASSOCIATE body, sym->ns->code is an EXEC_BLOCK node, not the DO CONCURRENT node; reading ext.concur from it interprets the wrong union member and yields a garbage pointer. Fix: use d->code instead, the DO CONCURRENT gfc_code node passed through the walker's data parameter, which is always the correct node. Bug 2: inline type-spec iterators are shadow iterators, stored internally with a leading underscore prepended to the name. The comparison of the iterator's symtree name against the user-visible sym->name must skip that underscore by advancing iter_name one character when iter->shadow is set. Assisted by: Claude Sonnet 4.6 PR fortran/125529 gcc/fortran/ChangeLog: * resolve.cc (check_default_none_expr): Use d->code instead of sym->ns->code to locate the DO CONCURRENT forall_iterator list, avoiding a wrong-union-member read when the symbol's namespace is an ASSOCIATE body. Skip leading underscore when comparing iterator names for shadow iterators. gcc/testsuite/ChangeLog: * gfortran.dg/do_concurrent_assoc_default_none.f90: New test. (cherry picked from commit 7fd7fdfa4c228089277ddfbadda55dc8c3077726) Diff: --- gcc/fortran/resolve.cc | 24 ++++++++++----- .../do_concurrent_assoc_default_none.f90 | 35 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index eca35ef4b633..90fc7b1cfe78 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -8581,15 +8581,23 @@ check_default_none_expr (gfc_expr **e, int *, void *data) ns2 = ns2->parent; } - /* A DO CONCURRENT iterator cannot appear in a locality spec. */ - if (sym->ns->code->ext.concur.forall_iterator) + /* A DO CONCURRENT iterator cannot appear in a locality spec. + Use d->code (the DO CONCURRENT node) rather than sym->ns->code, + which may be a different code type (e.g. EXEC_ASSOCIATE) whose + ext union would be read incorrectly. */ + for (gfc_forall_iterator *iter = d->code->ext.concur.forall_iterator; + iter; iter = iter->next) { - 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; + if (!iter->var || !iter->var->symtree) + continue; + const char *iter_name = iter->var->symtree->name; + /* Shadow iterators (from inline type-spec: integer :: i = ...) + store the iterator with a leading underscore internally; the + user-visible name does not have the underscore. */ + if (iter->shadow) + iter_name++; + if (strcmp (sym->name, iter_name) == 0) + return 0; } /* A named constant is not a variable, so skip test. */ diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_assoc_default_none.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_assoc_default_none.f90 new file mode 100644 index 000000000000..97cf5ae37f42 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_assoc_default_none.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } +! +! PR fortran/125529 +! DO CONCURRENT with inline type-spec iterators and DEFAULT(NONE) inside an +! ASSOCIATE block used to ICE (segfault in check_default_none_expr). The +! bug was that sym->ns->code was used instead of d->code to locate the +! forall_iterator list; for symbols in an ASSOCIATE or enclosing procedure +! namespace the wrong union member was read, giving a garbage pointer. +! Additionally, shadow iterators store their name with a leading underscore +! internally, so the comparison against user-visible names must strip it. + +subroutine test_associate_default_none (a, b) + implicit none + integer, intent(in) :: a(10,10) + integer, intent(out) :: b(10,10) + do concurrent (integer :: i = 1:10, j = 1:10) & + default(none) shared(a, b) + associate (tmp => a(i,j)) + b(i,j) = tmp + 1 + end associate + end do +end subroutine + +! Verify that a genuinely missing variable still gets an error. +subroutine test_missing_var (a, b, c) + implicit none + integer, intent(in) :: a(10,10), c + integer, intent(out) :: b(10,10) + do concurrent (integer :: i = 1:10, j = 1:10) & + default(none) shared(a, b) + ! { dg-error "not specified in a locality spec" "" { target *-*-* } .-1 } + b(i,j) = a(i,j) + c ! { dg-error "not specified in a locality spec" } + end do +end subroutine
