Skip to content
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

[flang][runtime] Added Fortran::common::optional for use on device. #85177

Conversation

vzakhari
Copy link
Contributor

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.

Created using spr 1.3.4
@llvmbot llvmbot added flang:runtime flang Flang issues not falling into any other category labels Mar 14, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 14, 2024

@llvm/pr-subscribers-flang-runtime

Author: Slava Zakharin (vzakhari)

Changes

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 --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]

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

// methods were added).
//
// The implementation defines optional in Fortran::common namespace.
// This standalone implementation may beused if the target
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This standalone implementation may beused if the target
// This standalone implementation may be used if the target

Created using spr 1.3.4
@vzakhari vzakhari merged commit 71e0261 into main Mar 15, 2024
4 checks passed
@vzakhari vzakhari deleted the users/vzakhari/spr/flangruntime-added-fortrancommonoptional-for-use-on-device branch March 15, 2024 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:runtime flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants