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

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon Nov 20 10:56:39 PST 2023


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/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.

>From 554ff3e2b057b4863a5b71b6d9f20503b6bfd8bb Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 20 Nov 2023 10:39:50 -0800
Subject: [PATCH] [flang][runtime] Allow already-documented missing 'w' on edit
 descriptor

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.
---
 flang/runtime/format-implementation.h | 73 ++++++++++++++-------------
 flang/unittests/Runtime/Format.cpp    |  3 +-
 2 files changed, 39 insertions(+), 37 deletions(-)

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