diff --git a/flang/lib/common/format.h b/flang/lib/common/format.h index 2bf5384166b1..1688801fe53f 100644 --- a/flang/lib/common/format.h +++ b/flang/lib/common/format.h @@ -16,6 +16,7 @@ #define FORTRAN_COMMON_FORMAT_H_ #include "Fortran.h" +#include "enum-set.h" #include // Define a FormatValidator class template to validate a format expression @@ -41,6 +42,16 @@ struct FormatMessage { bool isError; // vs. warning }; +// This declaration is logically private to class FormatValidator. +// It is placed here to work around a clang compilation problem. +ENUM_CLASS(TokenKind, None, A, B, BN, BZ, D, DC, DP, DT, E, EN, ES, EX, F, G, I, + L, O, P, RC, RD, RN, RP, RU, RZ, S, SP, SS, T, TL, TR, X, Z, Colon, Slash, + Backslash, // nonstandard: inhibit newline on output + Dollar, // nonstandard: inhibit newline on output on terminals + Star, LParen, RParen, Comma, Point, Sign, + UnsignedInteger, // value in integerValue_ + String) // char-literal-constant or Hollerith constant + template class FormatValidator { public: using Reporter = std::function; @@ -54,53 +65,11 @@ public: bool Check(); private: - enum class TokenKind { - None, - A, - B, - BN, - BZ, - D, - DC, - DP, - DT, - E, - EN, - ES, - EX, - F, - G, - I, - L, - O, - P, - RC, - RD, - RN, - RP, - RU, - RZ, - S, - SP, - SS, - T, - TL, - TR, - X, - Z, - Colon, - Slash, - Backslash, // nonstandard: inhibit newline on output - Dollar, // nonstandard: inhibit newline on output on terminals - Star, - LParen, - RParen, - Comma, - Point, - Sign, - UnsignedInteger, // value in integerValue_ - String, // char-literal-constant or Hollerith constant - }; + common::EnumSet itemsWithLeadingInts_{ + TokenKind::A, TokenKind::B, TokenKind::D, TokenKind::DT, TokenKind::E, + TokenKind::EN, TokenKind::ES, TokenKind::EX, TokenKind::F, TokenKind::G, + TokenKind::I, TokenKind::L, TokenKind::O, TokenKind::P, TokenKind::X, + TokenKind::Z, TokenKind::Slash, TokenKind::LParen}; struct Token { Token &set_kind(TokenKind kind) { @@ -176,6 +145,7 @@ private: Token knrToken_{}; // k, n, or r UnsignedInteger token int64_t knrValue_{-1}; // -1 ==> not present int64_t wValue_{-1}; + bool previousTokenWasInt_{false}; char argString_[3]{}; // 1-2 character msg arg; usually edit descriptor name bool formatHasErrors_{false}; bool unterminatedFormatError_{false}; @@ -213,6 +183,7 @@ template void FormatValidator::NextToken() { // At entry, cursor_ points before the start of the next token. // At exit, cursor_ points to last CHAR of token_. + previousTokenWasInt_ = token_.kind() == TokenKind::UnsignedInteger; CHAR c{NextChar()}; token_.set_kind(TokenKind::None); token_.set_offset(cursor_ - format_); @@ -472,7 +443,7 @@ template bool FormatValidator::Check() { Token starToken{}; // unlimited format token bool hasDataEditDesc{false}; - // Subject to error recovery exceptions, a loop iteration processes an + // Subject to error recovery exceptions, a loop iteration processes one // edit descriptor or does list management. The loop terminates when // - a level-0 right paren is processed (format may be valid) // - the end of an incomplete format is reached @@ -773,7 +744,12 @@ template bool FormatValidator::Check() { default: // Possible first token of the next format item; token not yet processed. if (commaRequired) { - ReportError("Expected ',' or ')' in format expression"); // C1302 + const char *s{"Expected ',' or ')' in format expression"}; // C1302 + if (previousTokenWasInt_ && itemsWithLeadingInts_.test(token_.kind())) { + ReportError(s); + } else { + ReportWarning(s); + } } } } diff --git a/flang/test/semantics/io07.f90 b/flang/test/semantics/io07.f90 index 610790f1ebdc..8b97d9fa9f8b 100644 --- a/flang/test/semantics/io07.f90 +++ b/flang/test/semantics/io07.f90 @@ -30,6 +30,12 @@ 2011 format(:2L2) 2012 format(2L2 : 2L2) + ! C1302 warnings; no errors +2051 format(1X3/) +2052 format(1X003/) +2053 format(3P7I2) +2054 format(3PI2) + !ERROR: Expected ',' or ')' in format expression 2101 format(3I83Z8, 'abc') @@ -42,18 +48,6 @@ !ERROR: Expected ',' or ')' in format expression 2104 format(3I8 Z8) - !ERROR: Expected ',' or ')' in format expression -2105 format(1X3/) - - !ERROR: Expected ',' or ')' in format expression -2106 format(1X003/) - - !ERROR: Expected ',' or ')' in format expression -2107 format(3P7I2) - - !ERROR: Expected ',' or ')' in format expression -2108 format(3PI2) - 3001 format(*(I3)) 3002 format(5X,*(2(A))) diff --git a/flang/test/semantics/io08.f90 b/flang/test/semantics/io08.f90 index 2e3d2e01f64e..528d3bb90a3c 100644 --- a/flang/test/semantics/io08.f90 +++ b/flang/test/semantics/io08.f90 @@ -51,6 +51,11 @@ write(*,'(\)') write(*,'(RZ,RU,RP,RN,RD,RC,SS,SP,S,3G15.3e2)') + ! C1302 warnings; no errors + write(*,'(3P7I2)') + write(*,'(5X i3)') + write(*,'(XEN)') + !ERROR: Empty format expression write(*,"") @@ -72,12 +77,6 @@ !ERROR: 'P' edit descriptor must have a scale factor write(*,'(P7F' // '5.2)') - !ERROR: Expected ',' or ')' in format expression - write(*,'(3P7I2)') - - !ERROR: Expected ',' or ')' in format expression - write(*,'(5X i3)') - !ERROR: Unexpected integer constant write(*,'(X,3,3L4)') @@ -186,9 +185,6 @@ !ERROR: Unexpected 'M' in format expression write(*,'(MXY)') - !ERROR: Expected ',' or ')' in format expression - write(*,'(XEN)') - !ERROR: Unexpected 'R' in format expression !ERROR: Unexpected 'R' in format expression write(*,"(RR, RV)") @@ -265,9 +261,8 @@ !ERROR: Unterminated format expression write(*,'(X') - !ERROR: Expected ',' or ')' in format expression !ERROR: Unterminated format expression - write(*,'(XX') + write(*,'(XX') ! C1302 warning is not an error !ERROR: Unexpected '@' in format expression !ERROR: Unexpected '#' in format expression diff --git a/flang/test/semantics/io10.f90 b/flang/test/semantics/io10.f90 index 69a94950da6f..ef79c945e41d 100644 --- a/flang/test/semantics/io10.f90 +++ b/flang/test/semantics/io10.f90 @@ -35,4 +35,18 @@ !WARNING: Legacy 'H' edit descriptor write(*, '(3Habc)') + + !WARNING: 'X' edit descriptor must have a positive position value + !WARNING: Expected ',' or ')' in format expression + !WARNING: 'X' edit descriptor must have a positive position value + write(*,'(XX)') + + !WARNING: Expected ',' or ')' in format expression + write(*,'(RZEN8.2)') + + !WARNING: Expected ',' or ')' in format expression + write(*,'(3P7I2)') + + !WARNING: Expected ',' or ')' in format expression + write(*,'(5X i3)') end