aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpeter klausler <pklausler@nvidia.com>2020-07-21 17:10:14 -0700
committerpeter klausler <pklausler@nvidia.com>2020-07-21 18:59:49 -0700
commitc6cb726a8c60d97908016fe7fb76cdc88b543db2 (patch)
tree4b722914ae0484c2fbbce822e1e0ac3feb4cf033
parent320389e849f82403049c76ef06d11bfcef7b82e3 (diff)
downloadllvm-c6cb726a8c60d97908016fe7fb76cdc88b543db2.zip
llvm-c6cb726a8c60d97908016fe7fb76cdc88b543db2.tar.gz
llvm-c6cb726a8c60d97908016fe7fb76cdc88b543db2.tar.bz2
[flang] Replay a FORMAT at the right position
When FORMAT control reaches the final parenthesis and data items remain, we advance a record and revert to the beginning of the FORMAT for further items. But when the FORMAT contains any nested parenthesized group of editing descriptors, possibly repeated, reversion must be to the beginning of the last such top-level parenthesized group, including its repetition count. Reviewed By: sscalpone, PeteSteinfeld Differential Revision: https://reviews.llvm.org/D84281
-rw-r--r--flang/runtime/format-implementation.h15
-rw-r--r--flang/unittests/Runtime/hello.cpp15
2 files changed, 22 insertions, 8 deletions
diff --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h
index ce0e08b..a4453cd 100644
--- a/flang/runtime/format-implementation.h
+++ b/flang/runtime/format-implementation.h
@@ -225,6 +225,7 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
while (true) {
std::optional<int> 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 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
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 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
} 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 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
}
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 @@ DataEdit FormatControl<CONTEXT>::GetNextDataEdit(
++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
index 71d4943..0543571 100644
--- a/flang/unittests/Runtime/hello.cpp
+++ b/flang/unittests/Runtime/hello.cpp
@@ -38,16 +38,16 @@ static void hello() {
}
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 &section{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 @@ static void multiline() {
}
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<int>(status) << '\n';
@@ -70,7 +74,8 @@ static void multiline() {
test(format,
">HELLO, WORLD <"
" "
- "789 done"
+ "789 abcd 666 777"
+ " 888 999 "
" ",
std::string{buffer[0], sizeof buffer});
}