Skip to content

Commit

Permalink
Move MSVC workarounds for future<Error>/future<Expected<T>> out of OR…
Browse files Browse the repository at this point in the history
…C and into

a header in support.

MSVC's std::future implementation requires types to be default constructible,
but Error and Expected are not. This issue came up once before in ORC's
RPCUtils.h header and was worked around there but came up again in r342939, so
I am moving the workaround to Support to make it available to other clients.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@343011 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
lhames committed Sep 25, 2018
1 parent b0c4f7e commit 2096ec5
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 71 deletions.
75 changes: 4 additions & 71 deletions include/llvm/ExecutionEngine/Orc/RPCUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,73 +207,6 @@ class RPCFunctionIdAllocator<

namespace detail {

// FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future implementation
// supports classes without default constructors.
#ifdef _MSC_VER

namespace msvc_hacks {

// Work around MSVC's future implementation's use of default constructors:
// A default constructed value in the promise will be overwritten when the
// real error is set - so the default constructed Error has to be checked
// already.
class MSVCPError : public Error {
public:
MSVCPError() { (void)!!*this; }

MSVCPError(MSVCPError &&Other) : Error(std::move(Other)) {}

MSVCPError &operator=(MSVCPError Other) {
Error::operator=(std::move(Other));
return *this;
}

MSVCPError(Error Err) : Error(std::move(Err)) {}
};

// Work around MSVC's future implementation, similar to MSVCPError.
template <typename T> class MSVCPExpected : public Expected<T> {
public:
MSVCPExpected()
: Expected<T>(make_error<StringError>("", inconvertibleErrorCode())) {
consumeError(this->takeError());
}

MSVCPExpected(MSVCPExpected &&Other) : Expected<T>(std::move(Other)) {}

MSVCPExpected &operator=(MSVCPExpected &&Other) {
Expected<T>::operator=(std::move(Other));
return *this;
}

MSVCPExpected(Error Err) : Expected<T>(std::move(Err)) {}

template <typename OtherT>
MSVCPExpected(
OtherT &&Val,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
nullptr)
: Expected<T>(std::move(Val)) {}

template <class OtherT>
MSVCPExpected(
Expected<OtherT> &&Other,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
nullptr)
: Expected<T>(std::move(Other)) {}

template <class OtherT>
explicit MSVCPExpected(
Expected<OtherT> &&Other,
typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
nullptr)
: Expected<T>(std::move(Other)) {}
};

} // end namespace msvc_hacks

#endif // _MSC_VER

/// Provides a typedef for a tuple containing the decayed argument types.
template <typename T> class FunctionArgsTuple;

Expand All @@ -293,10 +226,10 @@ template <typename RetT> class ResultTraits {

#ifdef _MSC_VER
// The ErrorReturnType wrapped in a std::promise.
using ReturnPromiseType = std::promise<msvc_hacks::MSVCPExpected<RetT>>;
using ReturnPromiseType = std::promise<MSVCPExpected<RetT>>;

// The ErrorReturnType wrapped in a std::future.
using ReturnFutureType = std::future<msvc_hacks::MSVCPExpected<RetT>>;
using ReturnFutureType = std::future<MSVCPExpected<RetT>>;
#else
// The ErrorReturnType wrapped in a std::promise.
using ReturnPromiseType = std::promise<ErrorReturnType>;
Expand Down Expand Up @@ -325,10 +258,10 @@ template <> class ResultTraits<void> {

#ifdef _MSC_VER
// The ErrorReturnType wrapped in a std::promise.
using ReturnPromiseType = std::promise<msvc_hacks::MSVCPError>;
using ReturnPromiseType = std::promise<MSVCPError>;

// The ErrorReturnType wrapped in a std::future.
using ReturnFutureType = std::future<msvc_hacks::MSVCPError>;
using ReturnFutureType = std::future<MSVCPError>;
#else
// The ErrorReturnType wrapped in a std::promise.
using ReturnPromiseType = std::promise<ErrorReturnType>;
Expand Down
86 changes: 86 additions & 0 deletions include/llvm/Support/MSVCErrorWorkarounds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//===--- MSVCErrorWorkarounds.h - Enable future<Error> in MSVC --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// MSVC's promise/future implementation requires types to be default
// constructible, so this header provides analogues of Error an Expected
// that are default constructed in a safely destructible state.
//
// FIXME: Kill off this header and migrate all users to Error/Expected once we
// move to MSVC versions that support non-default-constructible types.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_MSVCERRORWORKAROUNDS_H
#define LLVM_SUPPORT_MSVCERRORWORKAROUNDS_H

#include "llvm/Support/Error.h"

namespace llvm {
namespace orc {

// A default-constructible llvm::Error that is suitable for use with MSVC's
// std::future implementation which requires default constructible types.
class MSVCPError : public Error {
public:
MSVCPError() { (void)!!*this; }

MSVCPError(MSVCPError &&Other) : Error(std::move(Other)) {}

MSVCPError &operator=(MSVCPError Other) {
Error::operator=(std::move(Other));
return *this;
}

MSVCPError(Error Err) : Error(std::move(Err)) {}
};

// A default-constructible llvm::Expected that is suitable for use with MSVC's
// std::future implementation, which requires default constructible types.
template <typename T> class MSVCPExpected : public Expected<T> {
public:
MSVCPExpected()
: Expected<T>(make_error<StringError>("", inconvertibleErrorCode())) {
consumeError(this->takeError());
}

MSVCPExpected(MSVCPExpected &&Other) : Expected<T>(std::move(Other)) {}

MSVCPExpected &operator=(MSVCPExpected &&Other) {
Expected<T>::operator=(std::move(Other));
return *this;
}

MSVCPExpected(Error Err) : Expected<T>(std::move(Err)) {}

template <typename OtherT>
MSVCPExpected(
OtherT &&Val,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
nullptr)
: Expected<T>(std::move(Val)) {}

template <class OtherT>
MSVCPExpected(
Expected<OtherT> &&Other,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
nullptr)
: Expected<T>(std::move(Other)) {}

template <class OtherT>
explicit MSVCPExpected(
Expected<OtherT> &&Other,
typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
nullptr)
: Expected<T>(std::move(Other)) {}
};

} // end namespace orc
} // end namespace llvm

#endif // LLVM_SUPPORT_MSVCERRORWORKAROUNDS_H

0 comments on commit 2096ec5

Please sign in to comment.