[flang-commits] [flang] [flang][runtime] Added Fortran::common::optional for use on device. (PR #85177)
via flang-commits
flang-commits at lists.llvm.org
Wed Mar 13 22:32:27 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-runtime
Author: Slava Zakharin (vzakhari)
<details>
<summary>Changes</summary>
This is a simplified implementation of std::optional that can be used
in the offload builds for the device code. The methods are properly
marked with RT_API_ATTRS so that the device compilation succedes.
---
Patch is 63.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/85177.diff
31 Files Affected:
- (added) flang/include/flang/Common/optional.h (+243)
- (modified) flang/include/flang/Runtime/type-code.h (+2-1)
- (modified) flang/runtime/connection.h (+8-7)
- (modified) flang/runtime/descriptor-io.cpp (+5-4)
- (modified) flang/runtime/descriptor-io.h (+7-6)
- (modified) flang/runtime/edit-input.cpp (+15-12)
- (modified) flang/runtime/environment.cpp (+3-2)
- (modified) flang/runtime/environment.h (+3-3)
- (modified) flang/runtime/extrema.cpp (-1)
- (modified) flang/runtime/file.cpp (+2-2)
- (modified) flang/runtime/file.h (+7-5)
- (modified) flang/runtime/format-implementation.h (+6-6)
- (modified) flang/runtime/format.h (+6-5)
- (modified) flang/runtime/io-api.cpp (+7-6)
- (modified) flang/runtime/io-stmt.cpp (+17-17)
- (modified) flang/runtime/io-stmt.h (+24-22)
- (modified) flang/runtime/matmul-transpose.cpp (+6-5)
- (modified) flang/runtime/matmul.cpp (+7-6)
- (modified) flang/runtime/misc-intrinsic.cpp (+3-3)
- (modified) flang/runtime/namelist.cpp (+11-9)
- (modified) flang/runtime/random-templates.h (+2-1)
- (modified) flang/runtime/random.cpp (+1-1)
- (modified) flang/runtime/tools.h (+8-6)
- (modified) flang/runtime/type-code.cpp (+2-2)
- (modified) flang/runtime/type-info.cpp (+3-3)
- (modified) flang/runtime/type-info.h (+2-2)
- (modified) flang/runtime/unit-map.cpp (+2-1)
- (modified) flang/runtime/unit.cpp (+9-7)
- (modified) flang/runtime/unit.h (+9-9)
- (modified) flang/runtime/utf.cpp (+3-3)
- (modified) flang/runtime/utf.h (+2-2)
``````````diff
diff --git a/flang/include/flang/Common/optional.h b/flang/include/flang/Common/optional.h
new file mode 100644
index 00000000000000..8903321e2baeb9
--- /dev/null
+++ b/flang/include/flang/Common/optional.h
@@ -0,0 +1,243 @@
+//===-- include/flang/Common/optional.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of std::optional borrowed from LLVM's
+// libc/src/__support/CPP/optional.h with modifications (e.g. value_or, emplace
+// methods were added).
+//
+// The implementation defines optional in Fortran::common namespace.
+// This standalone implementation may beused if the target
+// does not support std::optional implementation (e.g. CUDA device env),
+// otherwise, Fortran::common::optional is an alias for std::optional.
+//
+// TODO: using libcu++ is the best option for CUDA, but there is a couple
+// of issues:
+// * Older CUDA toolkits' libcu++ implementations do not support optional.
+// * The include paths need to be set up such that all STD header files
+// are taken from libcu++.
+// * cuda:: namespace need to be forced for all std:: references.
+//
+//===----------------------------------------------------------------------===//
+#ifndef FORTRAN_COMMON_OPTIONAL_H
+#define FORTRAN_COMMON_OPTIONAL_H
+
+#include "flang/Runtime/api-attrs.h"
+#include <optional>
+#include <type_traits>
+
+#if !defined(STD_OPTIONAL_UNSUPPORTED) && \
+ (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
+#define STD_OPTIONAL_UNSUPPORTED 1
+#endif
+
+#define FORTRAN_OPTIONAL_INLINE_WITH_ATTRS inline RT_API_ATTRS
+#define FORTRAN_OPTIONAL_INLINE inline
+#define FORTRAN_OPTIONAL_INLINE_VAR inline
+
+namespace Fortran::common {
+
+#if STD_OPTIONAL_UNSUPPORTED
+// Trivial nullopt_t struct.
+struct nullopt_t {
+ constexpr explicit nullopt_t() = default;
+};
+
+// nullopt that can be used and returned.
+FORTRAN_OPTIONAL_INLINE_VAR constexpr nullopt_t nullopt{};
+
+// This is very simple implementation of the std::optional class. It makes
+// several assumptions that the underlying type is trivially constructible,
+// copyable, or movable.
+template <typename T> class optional {
+ template <typename U, bool = !std::is_trivially_destructible<U>::value>
+ struct OptionalStorage {
+ union {
+ char empty;
+ U stored_value;
+ };
+
+ bool in_use = false;
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS ~OptionalStorage() { reset(); }
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr OptionalStorage() : empty() {}
+
+ template <typename... Args>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr explicit OptionalStorage(
+ std::in_place_t, Args &&...args)
+ : stored_value(std::forward<Args>(args)...) {}
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr void reset() {
+ if (in_use)
+ stored_value.~U();
+ in_use = false;
+ }
+ };
+
+ // The only difference is that this type U doesn't have a nontrivial
+ // destructor.
+ template <typename U> struct OptionalStorage<U, false> {
+ union {
+ char empty;
+ U stored_value;
+ };
+
+ bool in_use = false;
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr OptionalStorage() : empty() {}
+
+ template <typename... Args>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr explicit OptionalStorage(
+ std::in_place_t, Args &&...args)
+ : stored_value(std::forward<Args>(args)...) {}
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr void reset() {
+ in_use = false;
+ }
+ };
+
+ OptionalStorage<T> storage;
+
+public:
+ // The default methods do not use RT_API_ATTRS, which causes
+ // warnings in CUDA compilation of form:
+ // __device__/__host__ annotation is ignored on a function .* that is
+ // explicitly defaulted on its first declaration
+ FORTRAN_OPTIONAL_INLINE constexpr optional() = default;
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(nullopt_t) {}
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(const T &t)
+ : storage(std::in_place, t) {
+ storage.in_use = true;
+ }
+ FORTRAN_OPTIONAL_INLINE constexpr optional(const optional &) = default;
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(T &&t)
+ : storage(std::in_place, std::move(t)) {
+ storage.in_use = true;
+ }
+ FORTRAN_OPTIONAL_INLINE constexpr optional(optional &&O) = default;
+
+ template <typename... ArgTypes>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(
+ std::in_place_t, ArgTypes &&...Args)
+ : storage(std::in_place, std::forward<ArgTypes>(Args)...) {
+ storage.in_use = true;
+ }
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional &operator=(T &&t) {
+ storage.stored_value = std::move(t);
+ storage.in_use = true;
+ return *this;
+ }
+
+ FORTRAN_OPTIONAL_INLINE constexpr optional &operator=(optional &&) = default;
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional &operator=(const T &t) {
+ storage.stored_value = t;
+ storage.in_use = true;
+ return *this;
+ }
+
+ FORTRAN_OPTIONAL_INLINE constexpr optional &operator=(
+ const optional &) = default;
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr void reset() { storage.reset(); }
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr const T &value() const & {
+ return storage.stored_value;
+ }
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &value() & {
+ return storage.stored_value;
+ }
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr explicit operator bool() const {
+ return storage.in_use;
+ }
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr bool has_value() const {
+ return storage.in_use;
+ }
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr const T *operator->() const {
+ return &storage.stored_value;
+ }
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T *operator->() {
+ return &storage.stored_value;
+ }
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr const T &operator*() const & {
+ return storage.stored_value;
+ }
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &operator*() & {
+ return storage.stored_value;
+ }
+
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &&value() && {
+ return std::move(storage.stored_value);
+ }
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &&operator*() && {
+ return std::move(storage.stored_value);
+ }
+
+ template <typename VT>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T value_or(
+ VT &&default_value) const & {
+ return storage.in_use ? storage.stored_value
+ : static_cast<T>(std::forward<VT>(default_value));
+ }
+
+ template <typename VT>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T value_or(
+ VT &&default_value) && {
+ return storage.in_use ? std::move(storage.stored_value)
+ : static_cast<T>(std::forward<VT>(default_value));
+ }
+
+ template <typename... ArgTypes>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS
+ std::enable_if_t<std::is_constructible_v<T, ArgTypes &&...>, T &>
+ emplace(ArgTypes &&...args) {
+ reset();
+ new (reinterpret_cast<void *>(std::addressof(storage.stored_value)))
+ T(std::forward<ArgTypes>(args)...);
+ storage.in_use = true;
+ return value();
+ }
+
+ template <typename U = T,
+ std::enable_if_t<(std::is_constructible_v<T, U &&> &&
+ !std::is_same_v<std::decay_t<U>, std::in_place_t> &&
+ !std::is_same_v<std::decay_t<U>, optional> &&
+ std::is_convertible_v<U &&, T>),
+ bool> = true>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(U &&value) {
+ new (reinterpret_cast<void *>(std::addressof(storage.stored_value)))
+ T(std::forward<U>(value));
+ storage.in_use = true;
+ }
+
+ template <typename U = T,
+ std::enable_if_t<(std::is_constructible_v<T, U &&> &&
+ !std::is_same_v<std::decay_t<U>, std::in_place_t> &&
+ !std::is_same_v<std::decay_t<U>, optional> &&
+ !std::is_convertible_v<U &&, T>),
+ bool> = false>
+ FORTRAN_OPTIONAL_INLINE_WITH_ATTRS explicit constexpr optional(U &&value) {
+ new (reinterpret_cast<void *>(std::addressof(storage.stored_value)))
+ T(std::forward<U>(value));
+ storage.in_use = true;
+ }
+};
+#else // !STD_OPTIONAL_UNSUPPORTED
+using std::nullopt;
+using std::nullopt_t;
+using std::optional;
+#endif // !STD_OPTIONAL_UNSUPPORTED
+
+} // namespace Fortran::common
+
+#endif // FORTRAN_COMMON_OPTIONAL_H
diff --git a/flang/include/flang/Runtime/type-code.h b/flang/include/flang/Runtime/type-code.h
index 3757840cfdef96..f7419249c2ba9c 100644
--- a/flang/include/flang/Runtime/type-code.h
+++ b/flang/include/flang/Runtime/type-code.h
@@ -10,6 +10,7 @@
#define FORTRAN_RUNTIME_TYPE_CODE_H_
#include "flang/Common/Fortran.h"
+#include "flang/Common/optional.h"
#include "flang/ISO_Fortran_binding_wrapper.h"
#include <optional>
#include <utility>
@@ -54,7 +55,7 @@ class TypeCode {
return IsValid() && !IsDerived();
}
- RT_API_ATTRS std::optional<std::pair<TypeCategory, int>>
+ RT_API_ATTRS Fortran::common::optional<std::pair<TypeCategory, int>>
GetCategoryAndKind() const;
RT_API_ATTRS bool operator==(TypeCode that) const {
diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h
index c9a7566f209881..c41970d47e7b09 100644
--- a/flang/runtime/connection.h
+++ b/flang/runtime/connection.h
@@ -12,8 +12,8 @@
#define FORTRAN_RUNTIME_IO_CONNECTION_H_
#include "format.h"
+#include "flang/Common/optional.h"
#include <cinttypes>
-#include <optional>
namespace Fortran::runtime::io {
@@ -26,10 +26,10 @@ enum class Access { Sequential, Direct, Stream };
// established in an OPEN statement.
struct ConnectionAttributes {
Access access{Access::Sequential}; // ACCESS='SEQUENTIAL', 'DIRECT', 'STREAM'
- std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true
+ Fortran::common::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true
bool isUTF8{false}; // ENCODING='UTF-8'
unsigned char internalIoCharKind{0}; // 0->external, 1/2/4->internal
- std::optional<std::int64_t> openRecl; // RECL= on OPEN
+ Fortran::common::optional<std::int64_t> openRecl; // RECL= on OPEN
bool IsRecordFile() const {
// Formatted stream files are viewed as having records, at least on input
@@ -63,14 +63,14 @@ struct ConnectionState : public ConnectionAttributes {
unterminatedRecord = false;
}
- std::optional<std::int64_t> EffectiveRecordLength() const {
+ Fortran::common::optional<std::int64_t> EffectiveRecordLength() const {
// When an input record is longer than an explicit RECL= from OPEN
// it is effectively truncated on input.
return openRecl && recordLength && *openRecl < *recordLength ? openRecl
: recordLength;
}
- std::optional<std::int64_t> recordLength;
+ Fortran::common::optional<std::int64_t> recordLength;
std::int64_t currentRecordNumber{1}; // 1 is first
@@ -86,11 +86,12 @@ struct ConnectionState : public ConnectionAttributes {
std::int64_t furthestPositionInRecord{0}; // max(position+bytes)
// Set at end of non-advancing I/O data transfer
- std::optional<std::int64_t> leftTabLimit; // offset in current record
+ Fortran::common::optional<std::int64_t>
+ leftTabLimit; // offset in current record
// currentRecordNumber value captured after ENDFILE/REWIND/BACKSPACE statement
// or an end-of-file READ condition on a sequential access file
- std::optional<std::int64_t> endfileRecordNumber;
+ Fortran::common::optional<std::int64_t> endfileRecordNumber;
// Mutable modes set at OPEN() that can be overridden in READ/WRITE & FORMAT
MutableModes modes; // BLANK=, DECIMAL=, SIGN=, ROUND=, PAD=, DELIM=, kP
diff --git a/flang/runtime/descriptor-io.cpp b/flang/runtime/descriptor-io.cpp
index 6041104773cc49..7c7323b719adf8 100644
--- a/flang/runtime/descriptor-io.cpp
+++ b/flang/runtime/descriptor-io.cpp
@@ -12,11 +12,12 @@
namespace Fortran::runtime::io::descr {
// Defined formatted I/O (maybe)
-std::optional<bool> DefinedFormattedIo(IoStatementState &io,
+Fortran::common::optional<bool> DefinedFormattedIo(IoStatementState &io,
const Descriptor &descriptor, const typeInfo::DerivedType &derived,
const typeInfo::SpecialBinding &special,
const SubscriptValue subscripts[]) {
- std::optional<DataEdit> peek{io.GetNextDataEdit(0 /*to peek at it*/)};
+ Fortran::common::optional<DataEdit> peek{
+ io.GetNextDataEdit(0 /*to peek at it*/)};
if (peek &&
(peek->descriptor == DataEdit::DefinedDerivedType ||
peek->descriptor == DataEdit::ListDirected)) {
@@ -55,7 +56,7 @@ std::optional<bool> DefinedFormattedIo(IoStatementState &io,
int unit{external->unitNumber()};
int ioStat{IostatOk};
char ioMsg[100];
- std::optional<std::int64_t> startPos;
+ Fortran::common::optional<std::int64_t> startPos;
if (edit.descriptor == DataEdit::DefinedDerivedType &&
special.which() == typeInfo::SpecialBinding::Which::ReadFormatted) {
// DT is an edit descriptor so everything that the child
@@ -96,7 +97,7 @@ std::optional<bool> DefinedFormattedIo(IoStatementState &io,
// There's a defined I/O subroutine, but there's a FORMAT present and
// it does not have a DT data edit descriptor, so apply default formatting
// to the components of the derived type as usual.
- return std::nullopt;
+ return Fortran::common::nullopt;
}
}
diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h
index 394578796faa79..b6b0fefcff870b 100644
--- a/flang/runtime/descriptor-io.h
+++ b/flang/runtime/descriptor-io.h
@@ -21,6 +21,7 @@
#include "terminator.h"
#include "type-info.h"
#include "unit.h"
+#include "flang/Common/optional.h"
#include "flang/Common/uint128.h"
#include "flang/Runtime/cpp-type.h"
#include "flang/Runtime/descriptor.h"
@@ -321,9 +322,9 @@ static bool DefaultComponentwiseUnformattedIO(IoStatementState &io,
return true;
}
-std::optional<bool> DefinedFormattedIo(IoStatementState &, const Descriptor &,
- const typeInfo::DerivedType &, const typeInfo::SpecialBinding &,
- const SubscriptValue[]);
+Fortran::common::optional<bool> DefinedFormattedIo(IoStatementState &,
+ const Descriptor &, const typeInfo::DerivedType &,
+ const typeInfo::SpecialBinding &, const SubscriptValue[]);
template <Direction DIR>
static bool FormattedDerivedTypeIO(IoStatementState &io,
@@ -334,7 +335,7 @@ static bool FormattedDerivedTypeIO(IoStatementState &io,
RUNTIME_CHECK(handler, addendum != nullptr);
const typeInfo::DerivedType *type{addendum->derivedType()};
RUNTIME_CHECK(handler, type != nullptr);
- std::optional<typeInfo::SpecialBinding> nonTbpSpecial;
+ Fortran::common::optional<typeInfo::SpecialBinding> nonTbpSpecial;
const typeInfo::SpecialBinding *special{nullptr};
if (table) {
if (const auto *definedIo{table->Find(*type,
@@ -365,7 +366,7 @@ static bool FormattedDerivedTypeIO(IoStatementState &io,
std::size_t numElements{descriptor.Elements()};
for (std::size_t j{0}; j < numElements;
++j, descriptor.IncrementSubscripts(subscripts)) {
- std::optional<bool> result;
+ Fortran::common::optional<bool> result;
if (special) {
result = DefinedFormattedIo(io, descriptor, *type, *special, subscripts);
}
@@ -406,7 +407,7 @@ static bool UnformattedDescriptorIO(IoStatementState &io,
: typeInfo::SpecialBinding::Which::WriteUnformatted,
definedIo->subroutine, definedIo->isDtvArgPolymorphic, false,
false};
- if (std::optional<bool> wasDefined{
+ if (Fortran::common::optional<bool> wasDefined{
DefinedUnformattedIo(io, descriptor, *type, special)}) {
return *wasDefined;
}
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 85cce2f1a16623..f7cbbc21e5956e 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -9,6 +9,7 @@
#include "edit-input.h"
#include "namelist.h"
#include "utf.h"
+#include "flang/Common/optional.h"
#include "flang/Common/real.h"
#include "flang/Common/uint128.h"
#include <algorithm>
@@ -54,9 +55,9 @@ template <int LOG2_BASE>
static bool EditBOZInput(
IoStatementState &io, const DataEdit &edit, void *n, std::size_t bytes) {
// Skip leading white space & zeroes
- std::optional<int> remaining{io.CueUpInput(edit)};
+ Fortran::common::optional<int> remaining{io.CueUpInput(edit)};
auto start{io.GetConnectionState().positionInRecord};
- std::optional<char32_t> next{io.NextInField(remaining, edit)};
+ Fortran::common::optional<char32_t> next{io.NextInField(remaining, edit)};
if (next.value_or('?') == '0') {
do {
start = io.GetConnectionState().positionInRecord;
@@ -156,7 +157,8 @@ static inline char32_t GetRadixPointChar(const DataEdit &edit) {
// Prepares input from a field, and returns the sign, if any, else '\0'.
static char ScanNumericPrefix(IoStatementState &io, const DataEdit &edit,
- std::optional<char32_t> &next, std::optional<int> &remaining) {
+ Fortran::common::optional<char32_t> &next,
+ Fortran::common::optional<int> &remaining) {
remaining = io.CueUpInput(edit);
next = io.NextInField(remaining, edit);
char sign{'\0'};
@@ -198,8 +200,8 @@ bool EditIntegerInput(
edit.descriptor);
return false;
}
- std::optional<int> remaining;
- std::optional<char32_t> next;
+ Fortran::common::optional<int> remaining;
+ Fortran::common::optional<char32_t> next;
char sign{ScanNumericPrefix(io, edit, next, remaining)};
common::UnsignedInt128 value{0};
bool any{!!sign};
@@ -279,10 +281,10 @@ struct ScannedRealInput {
};
static ScannedRealInput ScanRealInput(
char *buffer, int bufferSize, IoStatementState &io, const DataEdit &edit) {
- std::optional<int> remaining;
- std::optional<char32_t> next;
+ Fortran::common::optional<int> remaining;
+ Fortran::common::optional<char32_t> next;
int got{0};
- std::optional<int> radixPointOffset;
+ Fortran::common::optional<int> radixPointOffset;
auto Put{[&](char ch) -> void {
if (got < bufferSize) {
buffer[got] = ch;
@@ -833,8 +835,8 @@ bool EditLogicalInput(IoStatementState &io, const DataEdit &edit, bool &x) {
edit.descriptor);
return false;
}
- std::optional<int> remaining{io.CueUpInput(edit)};
- std::optional<char32_t> next{io.NextInField(remaining, edit)};
+ Fortran::common::optional<int> remaining{io.CueUpInput(edit)};
+ Fortran::common::optional<char32_t> next{io.NextInField(remaining, edit)};
if (next && *next == '.') { // skip optional period
next = io.NextInField(remaining, edit);
}
@@ -916,8 +918,9 @@ static bool EditListDirectedCharacterInput(
// or the end of the current record. Subtlety: the "remaining" count
// here is a dummy that's used to avoid the interpretation of separators
// in NextInField.
- std::optional<int> remaining{length > 0 ? maxUTF8Bytes : 0};
- while (std::optional<char32_t> next{io.NextInField(remaining, edit)}) {
+ Fortran::common::optional<int> remaining{length > 0 ? maxUTF8Bytes : 0};
+ while (Fortran::common::optional<char32_t> next{
+ io.NextInField(remaining, edit)}) {
bool isSep{false};
switch (*next) {
case ' ':
diff --git a/flang/runtime/environment.cpp b/flang/runtime/environment.cpp
index fe6701d72c9ff5..b74067a377774b 100644
--- a/flang/runtime/environment.cpp
+++ b/flang/runtime/environment.cpp
@@ -49,7 +49,8 @@ static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) {
}
}
-std::optional<Convert> GetConvertFromString(const char *x, std::size_t n) {
+Fortran::common::optional<Convert> GetConvertFromString(
+ const char *x, std::size_t n) {
static const char *keywords[]{
"UNKNOWN", "NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN", "SWAP", nullptr};
switch (IdentifyValue(x, n, keywords)) {
@@ -64,7 +65,7 @@ std::optional<Convert> GetConvertFromString(const char *x, std::size_t n)...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/85177
More information about the flang-commits
mailing list