Skip to content

Commit

Permalink
[flang][runtime] Catch error on Ew.0 output editing (#78522)
Browse files Browse the repository at this point in the history
An Ew.0(Ee) or Ew.0(Ee) output edit descriptor with a scale factor of
zero is an error condition, unless the output edit descriptor was
originally Gw.0(Ee), list-directed, or just E0/D0 with no .d part.

Fixes #78390.
  • Loading branch information
klausler committed Jan 25, 2024
1 parent 3bca850 commit 033b491
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 4 deletions.
14 changes: 12 additions & 2 deletions flang/runtime/edit-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,11 @@ bool RealOutputEditing<KIND>::EditEorDOutput(const DataEdit &edit) {
}
++significantDigits;
scale = std::min(scale, significantDigits + 1);
} else if (edit.digits.value_or(1) == 0 && !edit.variation) {
// F'2023 13.7.2.3.3 p5; does not apply to Gw.0(Ee) or E0(no d)
io_.GetIoErrorHandler().SignalError(IostatErrorInFormat,
"Output edit descriptor %cw.d must have d>0", edit.descriptor);
return false;
}
// In EN editing, multiple attempts may be necessary, so this is a loop.
while (true) {
Expand Down Expand Up @@ -549,6 +554,7 @@ bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
template <int KIND>
DataEdit RealOutputEditing<KIND>::EditForGOutput(DataEdit edit) {
edit.descriptor = 'E';
edit.variation = 'G'; // to suppress error for Ew.0
int editWidth{edit.width.value_or(0)};
int significantDigits{
edit.digits.value_or(BinaryFloatingPoint::decimalPrecision)}; // 'd'
Expand Down Expand Up @@ -594,7 +600,9 @@ bool RealOutputEditing<KIND>::EditListDirectedOutput(const DataEdit &edit) {
decimal::ConversionToDecimalResult converted{
ConvertToDecimal(1, edit.modes.round)};
if (IsInfOrNaN(converted.str, static_cast<int>(converted.length))) {
return EditEorDOutput(edit);
DataEdit copy{edit};
copy.variation = DataEdit::ListDirected;
return EditEorDOutput(copy);
}
int expo{converted.decimalExponent};
// The decimal precision of 16-bit floating-point types is very low,
Expand All @@ -604,10 +612,12 @@ bool RealOutputEditing<KIND>::EditListDirectedOutput(const DataEdit &edit) {
std::max(6, BinaryFloatingPoint::decimalPrecision)};
if (expo < 0 || expo > maxExpo) {
DataEdit copy{edit};
copy.variation = DataEdit::ListDirected;
copy.modes.scale = 1; // 1P
return EditEorDOutput(copy);
} else {
return EditFOutput(edit);
}
return EditFOutput(edit);
}

// 13.7.2.3.6 in F'2023
Expand Down
2 changes: 1 addition & 1 deletion flang/runtime/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct DataEdit {

static constexpr char DefinedDerivedType{'d'}; // DT defined I/O

char variation{'\0'}; // N, S, or X for EN, ES, EX
char variation{'\0'}; // N, S, or X for EN, ES, EX; G/l for original G/list
std::optional<int> width; // the 'w' field; optional for A
std::optional<int> digits; // the 'm' or 'd' field
std::optional<int> expoDigits; // 'Ee' field
Expand Down
2 changes: 1 addition & 1 deletion flang/unittests/Runtime/NumericalFormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ TEST(IOApiTests, FormatDoubleValues) {
{"(E62.55,';')",
" 0.1000000000000000055511151231257827021181583404541015625E+"
"00;"},
{"(E0.0,';')", ".1E+00;"},
{"(E0.1,';')", ".1E+00;"},
{"(E0.55,';')",
".1000000000000000055511151231257827021181583404541015625E+"
"00;"},
Expand Down

0 comments on commit 033b491

Please sign in to comment.