Skip to content

Commit

Permalink
[flang] Relax the implementation of constraint C1302. (flang-compiler…
Browse files Browse the repository at this point in the history
…/f18#805)

* Relax the implementation of constraint C1302.

When a list of format items can be unambiguously partitioned into individual items even though one or more otherwise required comma separators are omitted, generate a warning rather than an error.

Fixes flang-compiler/f18#703

Original-commit: flang-compiler/f18@79c0731
Reviewed-on: flang-compiler/f18#805
  • Loading branch information
vdonaldson committed Nov 5, 2019
1 parent 9392f2a commit 65791b2
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 72 deletions.
74 changes: 25 additions & 49 deletions flang/lib/common/format.h
Expand Up @@ -16,6 +16,7 @@
#define FORTRAN_COMMON_FORMAT_H_

#include "Fortran.h"
#include "enum-set.h"
#include <cstring>

// Define a FormatValidator class template to validate a format expression
Expand All @@ -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<typename CHAR = char> class FormatValidator {
public:
using Reporter = std::function<bool(const FormatMessage &)>;
Expand All @@ -54,53 +65,11 @@ template<typename CHAR = char> class FormatValidator {
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<TokenKind, TokenKind_enumSize> 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) {
Expand Down Expand Up @@ -176,6 +145,7 @@ template<typename CHAR = char> class FormatValidator {
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};
Expand Down Expand Up @@ -213,6 +183,7 @@ template<typename CHAR> void FormatValidator<CHAR>::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_);
Expand Down Expand Up @@ -472,7 +443,7 @@ template<typename CHAR> bool FormatValidator<CHAR>::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
Expand Down Expand Up @@ -773,7 +744,12 @@ template<typename CHAR> bool FormatValidator<CHAR>::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);
}
}
}
}
Expand Down
18 changes: 6 additions & 12 deletions flang/test/semantics/io07.f90
Expand Up @@ -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')

Expand All @@ -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)))

Expand Down
17 changes: 6 additions & 11 deletions flang/test/semantics/io08.f90
Expand Up @@ -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(*,"")

Expand All @@ -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)')

Expand Down Expand Up @@ -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)")
Expand Down Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions flang/test/semantics/io10.f90
Expand Up @@ -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

0 comments on commit 65791b2

Please sign in to comment.