diff --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h --- a/flang/runtime/format-implementation.h +++ b/flang/runtime/format-implementation.h @@ -225,6 +225,7 @@ while (true) { std::optional repeat; bool unlimited{false}; + auto maybeReversionPoint{offset_}; CharType ch{GetNextChar(context)}; while (ch == ',' || ch == ':') { // Skip commas, and don't complain if they're missing; the format @@ -254,6 +255,7 @@ return 0; } stack_[height_].start = offset_ - 1; // the '(' + RUNTIME_CHECK(context, format_[stack_[height_].start] == '('); if (unlimited || height_ == 0) { stack_[height_].remaining = Iteration::unlimited; unlimitedLoopCheck = offset_ - 1; @@ -265,6 +267,12 @@ } else { stack_[height_].remaining = 0; } + if (height_ == 1) { + // Subtle point (F'2018 13.4 para 9): tha last parenthesized group + // at height 1 becomes the restart point after control reaches the + // end of the format, including its repeat count. + stack_[0].start = maybeReversionPoint - 1; + } ++height_; } else if (height_ == 0) { context.SignalError(IostatErrorInFormat, "FORMAT lacks initial '('"); @@ -276,14 +284,15 @@ } context.AdvanceRecord(); // implied / before rightmost ) } + auto restart{stack_[height_ - 1].start + 1}; if (stack_[height_ - 1].remaining == Iteration::unlimited) { - offset_ = stack_[height_ - 1].start + 1; + offset_ = restart; if (offset_ == unlimitedLoopCheck) { context.SignalError(IostatErrorInFormat, "Unlimited repetition in FORMAT lacks data edit descriptors"); } } else if (stack_[height_ - 1].remaining-- > 0) { - offset_ = stack_[height_ - 1].start + 1; + offset_ = restart; } else { --height_; } @@ -396,7 +405,7 @@ ++height_; } edit.repeat = 1; - if (height_ > 1) { + if (height_ > 1) { // Subtle: stack_[0].start doesn't necessarily point to '(' int start{stack_[height_ - 1].start}; if (format_[start] != '(') { if (stack_[height_ - 1].remaining > maxRepeat) { diff --git a/flang/unittests/Runtime/hello.cpp b/flang/unittests/Runtime/hello.cpp --- a/flang/unittests/Runtime/hello.cpp +++ b/flang/unittests/Runtime/hello.cpp @@ -38,16 +38,16 @@ } static void multiline() { - char buffer[4][32]; + char buffer[5][32]; StaticDescriptor<1> staticDescriptor[2]; Descriptor &whole{staticDescriptor[0].descriptor()}; - SubscriptValue extent[]{4}; + SubscriptValue extent[]{5}; whole.Establish(TypeCode{CFI_type_char}, sizeof buffer[0], &buffer, 1, extent, CFI_attribute_pointer); whole.Dump(); whole.Check(); Descriptor §ion{staticDescriptor[1].descriptor()}; - SubscriptValue lowers[]{0}, uppers[]{3}, strides[]{1}; + SubscriptValue lowers[]{0}, uppers[]{4}, strides[]{1}; section.Establish(whole.type(), whole.ElementBytes(), nullptr, 1, extent, CFI_attribute_pointer); if (auto error{ @@ -57,12 +57,16 @@ } section.Dump(); section.Check(); - const char *format{"('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,25X,'done')"}; + const char *format{ + "('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,17X,'abcd',1(2I4))"}; auto cookie{IONAME(BeginInternalArrayFormattedOutput)( section, format, std::strlen(format))}; IONAME(OutputAscii)(cookie, "WORLD", 5); IONAME(OutputAscii)(cookie, "HELLO", 5); IONAME(OutputInteger64)(cookie, 789); + for (int j{666}; j <= 999; j += 111) { + IONAME(OutputInteger64)(cookie, j); + } if (auto status{IONAME(EndIoStatement)(cookie)}) { Fail() << "multiline: '" << format << "' failed, status " << static_cast(status) << '\n'; @@ -70,7 +74,8 @@ test(format, ">HELLO, WORLD <" " " - "789 done" + "789 abcd 666 777" + " 888 999 " " ", std::string{buffer[0], sizeof buffer}); }