[flang-commits] [flang] e6873bf - [flang][runtime] Don't skip input spaces when they are significant

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Apr 14 21:30:56 PDT 2022


Author: Peter Klausler
Date: 2022-04-14T21:30:43-07:00
New Revision: e6873bfbcd356c6aeb0e0bc165326f9fc8f02cbd

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

LOG: [flang][runtime] Don't skip input spaces when they are significant

When formatted input (not list-directed or NAMELIST) is in "BZ" mode,
either because a BZ control edit descriptor appeared in a FORMAT or
BLANK="ZERO" appeared in OPEN or READ, input editing must not skip
over blanks before or within the input field.

Differential Revision: https://reviews.llvm.org/D123725

Added: 
    

Modified: 
    flang/include/flang/Runtime/iostat.h
    flang/runtime/edit-input.cpp
    flang/runtime/io-stmt.h
    flang/runtime/iostat.cpp
    flang/unittests/Runtime/NumericalFormatTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h
index 15985b74dd3ce..0303d3de16d09 100644
--- a/flang/include/flang/Runtime/iostat.h
+++ b/flang/include/flang/Runtime/iostat.h
@@ -68,6 +68,7 @@ enum Iostat {
   IostatBadUnformattedRecord,
   IostatUTF8Decoding,
   IostatUnitOverflow,
+  IostatBadRealInput,
 };
 
 const char *IostatErrorString(int);

diff  --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 73a3478fbbe31..d7cace7b34c3f 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -58,12 +58,15 @@ static inline char32_t GetDecimalPoint(const DataEdit &edit) {
 // Returns true if there's a '-' sign.
 static bool ScanNumericPrefix(IoStatementState &io, const DataEdit &edit,
     std::optional<char32_t> &next, std::optional<int> &remaining) {
-  next = io.PrepareInput(edit, remaining);
+  bool bzMode{(edit.modes.editingFlags & blankZero) != 0};
+  next = io.PrepareInput(edit, remaining, !bzMode);
   bool negative{false};
   if (next) {
     negative = *next == '-';
     if (negative || *next == '+') {
-      io.SkipSpaces(remaining);
+      if (!bzMode) {
+        io.SkipSpaces(remaining);
+      }
       next = io.NextInField(remaining, edit);
     }
   }
@@ -153,7 +156,8 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
   if (ScanNumericPrefix(io, edit, next, remaining)) {
     Put('-');
   }
-  if (next.value_or(' ') == ' ') { // empty/blank field means zero
+  bool bzMode{(edit.modes.editingFlags & blankZero) != 0};
+  if (!next || (!bzMode && *next == ' ')) { // empty/blank field means zero
     remaining.reset();
     if (!io.GetConnectionState().IsAtEOF()) {
       Put('0');
@@ -181,10 +185,11 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
     }
     exponent = 0;
   } else if (first == decimal || (first >= '0' && first <= '9') ||
-      first == 'E' || first == 'D' || first == 'Q') {
+      (bzMode && (first == ' ' || first == '\t')) || first == 'E' ||
+      first == 'D' || first == 'Q') {
     Put('.'); // input field is normalized to a fraction
     auto start{got};
-    bool bzMode{(edit.modes.editingFlags & blankZero) != 0};
+    bool anyDigit{false};
     for (; next; next = io.NextInField(remaining, edit)) {
       char32_t ch{*next};
       if (ch == ' ' || ch == '\t') {
@@ -195,8 +200,10 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
         }
       }
       if (ch == '0' && got == start && !decimalPoint) {
+        anyDigit = true;
         // omit leading zeroes before the decimal
       } else if (ch >= '0' && ch <= '9') {
+        anyDigit = true;
         Put(ch);
       } else if (ch == decimal && !decimalPoint) {
         // the decimal point is *not* copied to the buffer
@@ -206,7 +213,11 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
       }
     }
     if (got == start) {
-      Put('0'); // emit at least one digit
+      if (anyDigit) {
+        Put('0'); // emit at least one digit
+      } else {
+        return 0; // no digits, invalid input
+      }
     }
     if (next &&
         (*next == 'e' || *next == 'E' || *next == 'd' || *next == 'D' ||
@@ -372,7 +383,7 @@ bool EditCommonRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
     return false;
   }
   if (got == 0) {
-    io.GetIoErrorHandler().SignalError("Bad REAL input value");
+    io.GetIoErrorHandler().SignalError(IostatBadRealInput);
     return false;
   }
   bool hadExtra{got > maxDigits};

diff  --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 72d6bf6b3b629..41bcfa3bb217d 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -132,8 +132,8 @@ class IoStatementState {
   // For fixed-width fields, initialize the number of remaining characters.
   // Skip over leading blanks, then return the first non-blank character (if
   // any).
-  std::optional<char32_t> PrepareInput(
-      const DataEdit &edit, std::optional<int> &remaining) {
+  std::optional<char32_t> PrepareInput(const DataEdit &edit,
+      std::optional<int> &remaining, bool skipSpaces = true) {
     remaining.reset();
     if (edit.descriptor == DataEdit::ListDirected) {
       std::size_t byteCount{0};
@@ -142,7 +142,9 @@ class IoStatementState {
       if (edit.width.value_or(0) > 0) {
         remaining = *edit.width;
       }
-      SkipSpaces(remaining);
+      if (skipSpaces) {
+        SkipSpaces(remaining);
+      }
     }
     return NextInField(remaining, edit);
   }

diff  --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp
index 5b761369206cb..e31fb83678301 100644
--- a/flang/runtime/iostat.cpp
+++ b/flang/runtime/iostat.cpp
@@ -79,6 +79,8 @@ const char *IostatErrorString(int iostat) {
     return "UTF-8 decoding error";
   case IostatUnitOverflow:
     return "UNIT number is out of range";
+  case IostatBadRealInput:
+    return "Bad REAL input value";
   default:
     return nullptr;
   }

diff  --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang/unittests/Runtime/NumericalFormatTest.cpp
index 3bc7b6dbf4221..a0c9680977413 100644
--- a/flang/unittests/Runtime/NumericalFormatTest.cpp
+++ b/flang/unittests/Runtime/NumericalFormatTest.cpp
@@ -688,6 +688,8 @@ TEST(IOApiTests, FormatDoubleInputValues) {
       {"(1P,F18.0)", "               125", 0x4029000000000000}, // 12.5
       {"(BZ,F18.0)", "              125 ", 0x4093880000000000}, // 1250
       {"(BZ,F18.0)", "       125 . e +1 ", 0x42a6bcc41e900000}, // 1.25e13
+      {"(BZ,F18.0)", "           .      ", 0x0},
+      {"(BZ,F18.0)", "           . e +1 ", 0x0},
       {"(DC,F18.0)", "              12,5", 0x4029000000000000},
   };
   for (auto const &[format, data, want] : testCases) {


        


More information about the flang-commits mailing list