[flang-commits] [flang] c6cb726 - [flang] Replay a FORMAT at the right position

peter klausler via flang-commits flang-commits at lists.llvm.org
Tue Jul 21 19:00:35 PDT 2020


Author: peter klausler
Date: 2020-07-21T18:59:49-07:00
New Revision: c6cb726a8c60d97908016fe7fb76cdc88b543db2

URL: https://github.com/llvm/llvm-project/commit/c6cb726a8c60d97908016fe7fb76cdc88b543db2
DIFF: https://github.com/llvm/llvm-project/commit/c6cb726a8c60d97908016fe7fb76cdc88b543db2.diff

LOG: [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

Added: 
    

Modified: 
    flang/runtime/format-implementation.h
    flang/unittests/Runtime/hello.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h
index ce0e08b99005..a4453cd172ea 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 71d49437bfcc..0543571bbb57 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});
   }


        


More information about the flang-commits mailing list