Skip to content

Commit 7d61a84

Browse files
committed
[flang] Semantics limits on kP scale factors
When known at compile time, Ew.d and Dw.d output edit descriptors should respect limitations from the standard on the value of a kP scale factor with respect to the digit count (d), at least for values of k other than zero.
1 parent 16c93aa commit 7d61a84

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

flang/include/flang/Common/format.h

+54-8
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ template <typename CHAR = char> class FormatValidator {
125125
void check_r(bool allowed = true);
126126
bool check_w();
127127
void check_m();
128-
bool check_d();
128+
bool check_d(bool checkScaleFactor = false);
129+
void check_k();
129130
void check_e();
130131

131132
const CHAR *const format_; // format text
@@ -135,11 +136,13 @@ template <typename CHAR = char> class FormatValidator {
135136

136137
const CHAR *cursor_{}; // current location in format_
137138
const CHAR *laCursor_{}; // lookahead cursor
138-
Token token_{}; // current token
139139
TokenKind previousTokenKind_{TokenKind::None};
140-
int64_t integerValue_{-1}; // value of UnsignedInteger token
140+
Token token_{}; // current token
141141
Token knrToken_{}; // k, n, or r UnsignedInteger token
142+
Token scaleFactorToken_{}; // most recent scale factor token P
143+
int64_t integerValue_{-1}; // value of UnsignedInteger token
142144
int64_t knrValue_{-1}; // -1 ==> not present
145+
int64_t scaleFactorValue_{}; // signed k in kP
143146
int64_t wValue_{-1};
144147
char argString_[3]{}; // 1-2 character msg arg; usually edit descriptor name
145148
bool formatHasErrors_{false};
@@ -491,7 +494,8 @@ template <typename CHAR> void FormatValidator<CHAR>::check_m() {
491494
}
492495

493496
// Return the predicate "d value is present" to control further processing.
494-
template <typename CHAR> bool FormatValidator<CHAR>::check_d() {
497+
template <typename CHAR>
498+
bool FormatValidator<CHAR>::check_d(bool checkScaleFactor) {
495499
if (token_.kind() != TokenKind::Point) {
496500
ReportError("Expected '%s' edit descriptor '.d' value");
497501
return false;
@@ -501,10 +505,41 @@ template <typename CHAR> bool FormatValidator<CHAR>::check_d() {
501505
ReportError("Expected '%s' edit descriptor 'd' value after '.'");
502506
return false;
503507
}
508+
if (checkScaleFactor) {
509+
check_k();
510+
}
504511
NextToken();
505512
return true;
506513
}
507514

515+
// Check the value of scale factor k against a field width d.
516+
template <typename CHAR> void FormatValidator<CHAR>::check_k() {
517+
// Limit the check to D and E edit descriptors in output statements that
518+
// explicitly set the scale factor.
519+
if (stmt_ != IoStmtKind::Print && stmt_ != IoStmtKind::Write) {
520+
return;
521+
}
522+
if (!scaleFactorToken_.IsSet()) {
523+
return;
524+
}
525+
// 13.7.2.3.3p5 - The values of d and k must satisfy:
526+
// −d < k <= 0; or
527+
// 0 < k < d+2
528+
const int64_t d{integerValue_};
529+
const int64_t k{scaleFactorValue_};
530+
// Exception: d = k = 0 is nonstandard, but has a reasonable interpretation.
531+
if (d == 0 && k == 0) {
532+
return;
533+
}
534+
if (k <= 0 && !(-d < k)) {
535+
ReportError("Negative scale factor k (from kP) and width d in a '%s' "
536+
"edit descriptor must satisfy '-d < k'");
537+
} else if (k > 0 && !(k < d + 2)) {
538+
ReportError("Positive scale factor k (from kP) and width d in a '%s' "
539+
"edit descriptor must satisfy 'k < d+2'");
540+
}
541+
}
542+
508543
template <typename CHAR> void FormatValidator<CHAR>::check_e() {
509544
if (token_.kind() != TokenKind::E) {
510545
return;
@@ -584,28 +619,32 @@ template <typename CHAR> bool FormatValidator<CHAR>::Check() {
584619
}
585620
break;
586621
case TokenKind::D:
587-
case TokenKind::F:
622+
case TokenKind::F: {
588623
// R1307 data-edit-desc -> D w . d | F w . d
624+
bool isD{token_.kind() == TokenKind::D};
589625
hasDataEditDesc = true;
590626
check_r();
591627
NextToken();
592628
if (check_w()) {
593-
check_d();
629+
check_d(/*checkScaleFactor=*/isD);
594630
}
595631
break;
632+
}
596633
case TokenKind::E:
597634
case TokenKind::EN:
598635
case TokenKind::ES:
599-
case TokenKind::EX:
636+
case TokenKind::EX: {
600637
// R1307 data-edit-desc ->
601638
// E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e]
639+
bool isE{token_.kind() == TokenKind::E};
602640
hasDataEditDesc = true;
603641
check_r();
604642
NextToken();
605-
if (check_w() && check_d()) {
643+
if (check_w() && check_d(/*checkScaleFactor=*/isE)) {
606644
check_e();
607645
}
608646
break;
647+
}
609648
case TokenKind::G:
610649
// R1307 data-edit-desc -> G w [. d [E e]]
611650
hasDataEditDesc = true;
@@ -695,6 +734,13 @@ template <typename CHAR> bool FormatValidator<CHAR>::Check() {
695734
// R1313 control-edit-desc -> k P
696735
if (knrValue_ < 0) {
697736
ReportError("'P' edit descriptor must have a scale factor");
737+
} else {
738+
scaleFactorToken_ = knrToken_;
739+
if (signToken.IsSet() && format_[signToken.offset()] == '-') {
740+
scaleFactorValue_ = -knrValue_;
741+
} else {
742+
scaleFactorValue_ = knrValue_;
743+
}
698744
}
699745
// Diagnosing C1302 may require multiple token lookahead.
700746
// Save current cursor position to enable backup.

flang/test/Semantics/io08.f90

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
character(20), parameter :: kp_ok = "(4P,E20.5,E15.5)"
3+
character(20), parameter :: kp_xx = "(4P,E20.5,E15.2)"
4+
25
write(*,*)
36
write(*,'()')
47
write(*,'(A)')
@@ -40,6 +43,9 @@
4043
write(*, '(' // achar( 9) // ')') ! horizontal tab
4144
write(*, '(' // achar(11) // ')') ! vertical tab
4245
write(*, '(' // achar(32) // ')') ! space
46+
write(*, kp_ok)
47+
write(*, '(-4P,E20.5,E15.5)')
48+
write(*, '(D20.0)')
4349

4450
! C1302 warnings; no errors
4551
write(*,'(3P7I2)')
@@ -309,4 +315,10 @@
309315

310316
!ERROR: Repeat specifier before '$' edit descriptor
311317
write(*,'(7$)')
318+
319+
!ERROR: Positive scale factor k (from kP) and width d in a 'E' edit descriptor must satisfy 'k < d+2'
320+
write(*, kp_xx)
321+
322+
!ERROR: Negative scale factor k (from kP) and width d in a 'E' edit descriptor must satisfy '-d < k'
323+
write(*, '(-4P,E20.5,E15.2)')
312324
end

0 commit comments

Comments
 (0)