[flang-commits] [flang] c13f7e1 - [flang][runtime] Allow already-documented missing 'w' on edit descriptor (#72901)

via flang-commits flang-commits at lists.llvm.org
Thu Nov 30 12:52:02 PST 2023


Author: Peter Klausler
Date: 2023-11-30T12:51:56-08:00
New Revision: c13f7e17409b6fed29696c2bbe59efc3af3a408b

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

LOG: [flang][runtime] Allow already-documented missing 'w' on edit descriptor (#72901)

As already documented in flang/docs/Extensions.md and implemented in the
compilation-time format validator, we want to support at execution time
the Intel (and presumably also Fujitsu) extension of allowing a missing
width on an edit descriptor in a formatted I/O statement.

Fixes https://github.com/llvm/llvm-project/issues/72597.

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h
index 57c176ea8d77cac..c54ac062c7beab9 100644
--- a/flang/runtime/format-implementation.h
+++ b/flang/runtime/format-implementation.h
@@ -416,14 +416,16 @@ std::optional<DataEdit> FormatControl<CONTEXT>::GetNextDataEdit(
   int repeat{CueUpNextDataEdit(context)};
   auto start{offset_};
   DataEdit edit;
+  edit.modes = context.mutableModes();
+  // Handle repeated nonparenthesized edit descriptors
+  edit.repeat = std::min(repeat, maxRepeat); // 0 if maxRepeat==0
+  if (repeat > maxRepeat) {
+    stack_[height_].start = start; // after repeat count
+    stack_[height_].remaining = repeat - edit.repeat;
+    ++height_;
+  }
   edit.descriptor = static_cast<char>(Capitalize(GetNextChar(context)));
-  if (edit.descriptor == 'E') {
-    if (auto next{static_cast<char>(Capitalize(PeekNext()))};
-        next == 'N' || next == 'S' || next == 'X') {
-      edit.variation = next;
-      ++offset_;
-    }
-  } else if (edit.descriptor == 'D' && Capitalize(PeekNext()) == 'T') {
+  if (edit.descriptor == 'D' && Capitalize(PeekNext()) == 'T') {
     // DT['iotype'][(v_list)] defined I/O
     edit.descriptor = DataEdit::DefinedDerivedType;
     ++offset_;
@@ -479,38 +481,37 @@ std::optional<DataEdit> FormatControl<CONTEXT>::GetNextDataEdit(
         return std::nullopt;
       }
     }
-  }
-  if (edit.descriptor == 'A' || edit.descriptor == 'L') {
-    // width is optional for A[w] or L[w]
-    auto ch{PeekNext()};
-    if (ch >= '0' && ch <= '9') {
-      edit.width = GetIntField(context);
-    }
-  } else if (edit.descriptor != DataEdit::DefinedDerivedType) {
-    edit.width = GetIntField(context);
-  }
-  if constexpr (std::is_base_of_v<InputStatementState, CONTEXT>) {
-    if (edit.width.value_or(-1) == 0) {
-      ReportBadFormat(context, "Input field width is zero", start);
+  } else { // not DT'iotype'
+    if (edit.descriptor == 'E') {
+      if (auto next{static_cast<char>(Capitalize(PeekNext()))};
+          next == 'N' || next == 'S' || next == 'X') {
+        edit.variation = next;
+        ++offset_;
+      }
     }
-  }
-  if (edit.descriptor != DataEdit::DefinedDerivedType && PeekNext() == '.') {
-    ++offset_;
-    edit.digits = GetIntField(context);
-    CharType ch{PeekNext()};
-    if (ch == 'e' || ch == 'E' || ch == 'd' || ch == 'D') {
-      ++offset_;
-      edit.expoDigits = GetIntField(context);
+    // Width is optional for A[w] in the standard and optional
+    // for Lw in most compilers.
+    // Intel & (presumably, from bug report) Fujitsu allow
+    // a missing 'w' & 'd'/'m' for other edit descriptors -- but not
+    // 'd'/'m' with a missing 'w' -- and so interpret "(E)" as "(E0)".
+    if (CharType ch{PeekNext()}; (ch >= '0' && ch <= '9') || ch == '.') {
+      edit.width = GetIntField(context);
+      if constexpr (std::is_base_of_v<InputStatementState, CONTEXT>) {
+        if (edit.width.value_or(-1) == 0) {
+          ReportBadFormat(context, "Input field width is zero", start);
+        }
+      }
+      if (PeekNext() == '.') {
+        ++offset_;
+        edit.digits = GetIntField(context);
+        if (CharType ch{PeekNext()};
+            ch == 'e' || ch == 'E' || ch == 'd' || ch == 'D') {
+          ++offset_;
+          edit.expoDigits = GetIntField(context);
+        }
+      }
     }
   }
-  edit.modes = context.mutableModes();
-  // Handle repeated nonparenthesized edit descriptors
-  edit.repeat = std::min(repeat, maxRepeat); // 0 if maxRepeat==0
-  if (repeat > maxRepeat) {
-    stack_[height_].start = start; // after repeat count
-    stack_[height_].remaining = repeat - edit.repeat;
-    ++height_;
-  }
   return edit;
 }
 

diff  --git a/flang/unittests/Runtime/Format.cpp b/flang/unittests/Runtime/Format.cpp
index e9004b7798f3613..01803c628de26ad 100644
--- a/flang/unittests/Runtime/Format.cpp
+++ b/flang/unittests/Runtime/Format.cpp
@@ -111,6 +111,7 @@ TEST(FormatTests, FormatStringTraversal) {
           ResultsTy{"I4", "E10.1", "E10.1", "/", "I4", "E10.1", "E10.1", "/",
               "I4", "E10.1", "E10.1"},
           1},
+      {1, "(F)", ResultsTy{"F"}, 1}, // missing 'w'
   };
 
   for (const auto &[n, format, expect, repeat] : params) {
@@ -170,7 +171,7 @@ TEST(InvalidFormatFailure, MissingPrecision) {
       R"(Invalid FORMAT: integer expected at '\)')");
 }
 
-TEST(InvalidFormatFailure, MissingFormatWidth) {
+TEST(InvalidFormatFailure, MissingFormatWidthWithDigits) {
   static constexpr const char *format{"(F.9)"};
   static constexpr int repeat{1};
 


        


More information about the flang-commits mailing list