Skip to content

Commit dea30ac

Browse files
authored
[flang][runtime] NAMELIST input into storage sequence (llvm#76584)
Nearly every Fortran compiler supports the extension of NAMELIST input into a storage sequence identified by its initial scalar array element. For example, &GROUP A(1) = 1. 2. 3. / should be processed as if the input had been &GROUP A(1:) = 1. 2. 3. / Fixes llvm-test-suite/Fortran/gfortran/regression/namelist_24.f90.
1 parent 49ee8b5 commit dea30ac

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

flang/docs/Extensions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,7 @@ end
657657
but every Fortran compiler allows the encoding to be changed on an
658658
open unit.
659659

660+
* A `NAMELIST` input item that references a scalar element of a vector
661+
or contiguous array can be used as the initial element of a storage
662+
sequence. For example, "&GRP A(1)=1. 2. 3./" is treated as if had been
663+
"&GRP A(1:)=1. 2. 3./".

flang/runtime/namelist.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,28 @@ static bool HandleSubscripts(IoStatementState &io, Descriptor &desc,
247247
return false;
248248
}
249249

250+
static void StorageSequenceExtension(
251+
Descriptor &desc, const Descriptor &source) {
252+
// Support the near-universal extension of NAMELIST input into a
253+
// designatable storage sequence identified by its initial scalar array
254+
// element. For example, treat "A(1) = 1. 2. 3." as if it had been
255+
// "A(1:) = 1. 2. 3.".
256+
if (desc.rank() == 0 && (source.rank() == 1 || source.IsContiguous())) {
257+
if (auto stride{source.rank() == 1
258+
? source.GetDimension(0).ByteStride()
259+
: static_cast<SubscriptValue>(source.ElementBytes())};
260+
stride != 0) {
261+
desc.raw().attribute = CFI_attribute_pointer;
262+
desc.raw().rank = 1;
263+
desc.GetDimension(0)
264+
.SetBounds(1,
265+
source.Elements() -
266+
((source.OffsetElement() - desc.OffsetElement()) / stride))
267+
.SetByteStride(stride);
268+
}
269+
}
270+
}
271+
250272
static bool HandleSubstring(
251273
IoStatementState &io, Descriptor &desc, const char *name) {
252274
IoErrorHandler &handler{io.GetIoErrorHandler()};
@@ -480,10 +502,14 @@ bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
480502
bool hadSubscripts{false};
481503
bool hadSubstring{false};
482504
if (next && (*next == '(' || *next == '%')) {
505+
const Descriptor *lastSubscriptBase{nullptr};
506+
Descriptor *lastSubscriptDescriptor{nullptr};
483507
do {
484508
Descriptor &mutableDescriptor{staticDesc[whichStaticDesc].descriptor()};
485509
whichStaticDesc ^= 1;
486510
io.HandleRelativePosition(byteCount); // skip over '(' or '%'
511+
lastSubscriptDescriptor = nullptr;
512+
lastSubscriptBase = nullptr;
487513
if (*next == '(') {
488514
if (!hadSubstring && (hadSubscripts || useDescriptor->rank() == 0)) {
489515
mutableDescriptor = *useDescriptor;
@@ -497,11 +523,12 @@ bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
497523
"NAMELIST group '%s'",
498524
name, group.groupName);
499525
return false;
526+
} else if (HandleSubscripts(
527+
io, mutableDescriptor, *useDescriptor, name)) {
528+
lastSubscriptBase = useDescriptor;
529+
lastSubscriptDescriptor = &mutableDescriptor;
500530
} else {
501-
if (!HandleSubscripts(
502-
io, mutableDescriptor, *useDescriptor, name)) {
503-
return false;
504-
}
531+
return false;
505532
}
506533
hadSubscripts = true;
507534
} else {
@@ -514,6 +541,9 @@ bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
514541
useDescriptor = &mutableDescriptor;
515542
next = io.GetCurrentChar(byteCount);
516543
} while (next && (*next == '(' || *next == '%'));
544+
if (lastSubscriptDescriptor) {
545+
StorageSequenceExtension(*lastSubscriptDescriptor, *lastSubscriptBase);
546+
}
517547
}
518548
// Skip the '='
519549
next = io.GetNextNonBlank(byteCount);

0 commit comments

Comments
 (0)