-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang][runtime] Accept some real input for integer NAMELIST #108268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
A few other Fortran compilers silently accept real values for integer variables in NAMELIST input. Handling an exponent would be difficult, but it's easy to skip and ignore a fractional part when one is present.
@llvm/pr-subscribers-flang-runtime Author: Peter Klausler (klausler) ChangesA few other Fortran compilers silently accept real values for integer variables in NAMELIST input. Handling an exponent would be difficult, but it's easy to skip and ignore a fractional part when one is present. Full diff: https://github.com/llvm/llvm-project/pull/108268.diff 2 Files Affected:
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 61b070bde80e6f..2cee35e23f31a3 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -54,6 +54,10 @@ static RT_API_ATTRS bool CheckCompleteListDirectedField(
}
}
+static inline RT_API_ATTRS char32_t GetSeparatorChar(const DataEdit &edit) {
+ return edit.modes.editingFlags & decimalComma ? char32_t{';'} : char32_t{','};
+}
+
template <int LOG2_BASE>
static RT_API_ATTRS bool EditBOZInput(
IoStatementState &io, const DataEdit &edit, void *n, std::size_t bytes) {
@@ -70,6 +74,7 @@ static RT_API_ATTRS bool EditBOZInput(
// Count significant digits after any leading white space & zeroes
int digits{0};
int significantBits{0};
+ const char32_t comma{GetSeparatorChar(edit)};
for (; next; next = io.NextInField(remaining, edit)) {
char32_t ch{*next};
if (ch == ' ' || ch == '\t') {
@@ -84,7 +89,7 @@ static RT_API_ATTRS bool EditBOZInput(
} else if (LOG2_BASE >= 4 && ch >= '8' && ch <= '9') {
} else if (LOG2_BASE >= 4 && ch >= 'A' && ch <= 'F') {
} else if (LOG2_BASE >= 4 && ch >= 'a' && ch <= 'f') {
- } else if (ch == ',') {
+ } else if (ch == comma) {
break; // end non-list-directed field early
} else {
io.GetIoErrorHandler().SignalError(
@@ -209,6 +214,7 @@ RT_API_ATTRS bool EditIntegerInput(
common::UnsignedInt128 value{0};
bool any{!!sign};
bool overflow{false};
+ const char32_t comma{GetSeparatorChar(edit)};
for (; next; next = io.NextInField(remaining, edit)) {
char32_t ch{*next};
if (ch == ' ' || ch == '\t') {
@@ -221,9 +227,23 @@ RT_API_ATTRS bool EditIntegerInput(
int digit{0};
if (ch >= '0' && ch <= '9') {
digit = ch - '0';
- } else if (ch == ',') {
+ } else if (ch == comma) {
break; // end non-list-directed field early
} else {
+ if (edit.modes.inNamelist && ch == GetRadixPointChar(edit)) {
+ // Ignore any fractional part that might appear in NAMELIST integer
+ // input, like a few other Fortran compilers do.
+ // TODO: also process exponents? Some compilers do, but they obviously
+ // can't just be ignored.
+ while ((next = io.NextInField(remaining, edit))) {
+ if (*next < '0' || *next > '9') {
+ break;
+ }
+ }
+ if (!next || *next == comma) {
+ break;
+ }
+ }
io.GetIoErrorHandler().SignalError(
"Bad character '%lc' in INTEGER input field", ch);
return false;
diff --git a/flang/unittests/Runtime/Namelist.cpp b/flang/unittests/Runtime/Namelist.cpp
index f95c5d2e553aa7..9037fa15a97cb3 100644
--- a/flang/unittests/Runtime/Namelist.cpp
+++ b/flang/unittests/Runtime/Namelist.cpp
@@ -305,4 +305,33 @@ TEST(NamelistTests, Comma) {
EXPECT_EQ(got, expect);
}
+// Tests REAL-looking input to integers
+TEST(NamelistTests, RealValueForInt) {
+ OwningPtr<Descriptor> scDesc{
+ MakeArray<TypeCategory::Integer, static_cast<int>(sizeof(int))>(
+ std::vector<int>{}, std::vector<int>{{}})};
+ const NamelistGroup::Item items[]{{"j", *scDesc}};
+ const NamelistGroup group{"nml", 1, items};
+ static char t1[]{"&nml j=123.456/"};
+ StaticDescriptor<1, true> statDesc;
+ Descriptor &internalDesc{statDesc.descriptor()};
+ internalDesc.Establish(TypeCode{CFI_type_char},
+ /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);
+ auto inCookie{IONAME(BeginInternalArrayListInput)(
+ internalDesc, nullptr, 0, __FILE__, __LINE__)};
+ ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
+ ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)
+ << "namelist real input for integer";
+ char out[16];
+ internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,
+ out, 0, nullptr, CFI_attribute_pointer);
+ auto outCookie{IONAME(BeginInternalArrayListOutput)(
+ internalDesc, nullptr, 0, __FILE__, __LINE__)};
+ ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));
+ ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";
+ std::string got{out, sizeof out};
+ static const std::string expect{" &NML J= 123/ "};
+ EXPECT_EQ(got, expect);
+}
+
// TODO: Internal NAMELIST error tests
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this also fixes some European bugs, that's good too!
A few other Fortran compilers silently accept real values for integer variables in NAMELIST input. Handling an exponent would be difficult, but it's easy to skip and ignore a fractional part when one is present.