[llvm-commits] [llvm] r172991 - in /llvm/trunk: include/llvm/Support/Compiler.h include/llvm/Support/ErrorOr.h include/llvm/Support/type_traits.h unittests/Support/CMakeLists.txt unittests/Support/ErrorOrTest.cpp
Galina Kistanova
gkistanova at gmail.com
Tue Jan 22 13:53:03 PST 2013
Hi Michael,
Seems this revision broke clang-X86_64-freebsd build.
The last successful build was for r 172988:
http://lab.llvm.org:8011/builders/clang-X86_64-freebsd/builds/6722
The next builded revision was 172992 and it failed:
http://lab.llvm.org:8011/builders/clang-X86_64-freebsd/builds/6723
Please have a look at this?
Let me know if you need more information on it.
Thanks
Galina
On Sun, Jan 20, 2013 at 12:32 PM, Michael J. Spencer
<bigcheesegs at gmail.com>wrote:
> Author: mspencer
> Date: Sun Jan 20 14:32:30 2013
> New Revision: 172991
>
> URL: http://llvm.org/viewvc/llvm-project?rev=172991&view=rev
> Log:
> [Support] Port ErrorOr<T> from lld to C++03.
>
> Added:
> llvm/trunk/include/llvm/Support/ErrorOr.h
> llvm/trunk/unittests/Support/ErrorOrTest.cpp
> Modified:
> llvm/trunk/include/llvm/Support/Compiler.h
> llvm/trunk/include/llvm/Support/type_traits.h
> llvm/trunk/unittests/Support/CMakeLists.txt
>
> Modified: llvm/trunk/include/llvm/Support/Compiler.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Compiler.h?rev=172991&r1=172990&r2=172991&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/Compiler.h (original)
> +++ llvm/trunk/include/llvm/Support/Compiler.h Sun Jan 20 14:32:30 2013
> @@ -42,6 +42,33 @@
> #define LLVM_HAS_RVALUE_REFERENCE_THIS 0
> #endif
>
> +/// \macro LLVM_HAS_CXX11_TYPETRAITS
> +/// \brief Does the compiler have the C++11 type traits.
> +///
> +/// #include <type_traits>
> +///
> +/// * enable_if
> +/// * {true,false}_type
> +/// * is_constructible
> +/// * etc...
> +#if defined(__GXX_EXPERIMENTAL_CXX0X__) \
> + || (defined(_MSC_VER) && _MSC_VER >= 1600)
> +#define LLVM_HAS_CXX11_TYPETRAITS 1
> +#else
> +#define LLVM_HAS_CXX11_TYPETRAITS 0
> +#endif
> +
> +/// \macro LLVM_HAS_CXX11_STDLIB
> +/// \brief Does the compiler have the C++11 standard library.
> +///
> +/// Implies LLVM_HAS_RVALUE_REFERENCES, LLVM_HAS_CXX11_TYPETRAITS
> +#if defined(__GXX_EXPERIMENTAL_CXX0X__) \
> + || (defined(_MSC_VER) && _MSC_VER >= 1600)
> +#define LLVM_HAS_CXX11_STDLIB 1
> +#else
> +#define LLVM_HAS_CXX11_STDLIB 0
> +#endif
> +
> /// llvm_move - Expands to ::std::move if the compiler supports
> /// r-value references; otherwise, expands to the argument.
> #if LLVM_HAS_RVALUE_REFERENCES
>
> Added: llvm/trunk/include/llvm/Support/ErrorOr.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ErrorOr.h?rev=172991&view=auto
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/ErrorOr.h (added)
> +++ llvm/trunk/include/llvm/Support/ErrorOr.h Sun Jan 20 14:32:30 2013
> @@ -0,0 +1,342 @@
> +//===- llvm/Support/ErrorOr.h - Error Smart Pointer
> -----------------------===//
> +//
> +// The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Provides ErrorOr<T> smart pointer.
> +///
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_SUPPORT_ERROR_OR_H
> +#define LLVM_SUPPORT_ERROR_OR_H
> +
> +#include "llvm/Support/AlignOf.h"
> +#include "llvm/Support/system_error.h"
> +#include "llvm/Support/type_traits.h"
> +
> +#include <cassert>
> +#if LLVM_HAS_CXX11_TYPETRAITS
> +#include <type_traits>
> +#endif
> +
> +namespace llvm {
> +struct ErrorHolderBase {
> + error_code Error;
> + uint16_t RefCount;
> + bool HasUserData;
> +
> + ErrorHolderBase() : RefCount(1) {}
> +
> + void aquire() {
> + ++RefCount;
> + }
> +
> + void release() {
> + if (--RefCount == 0)
> + delete this;
> + }
> +
> +protected:
> + virtual ~ErrorHolderBase() {}
> +};
> +
> +template<class T>
> +struct ErrorHolder : ErrorHolderBase {
> +#if LLVM_HAS_RVALUE_REFERENCES
> + ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
> +#else
> + ErrorHolder(T &UD) : UserData(UD) {}
> +#endif
> + T UserData;
> +};
> +
> +template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {};
> +
> +#if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
> +template<class T, class V>
> +typename std::enable_if< std::is_constructible<T, V>::value
> + , typename std::remove_reference<V>::type>::type &&
> + moveIfMoveConstructible(V &Val) {
> + return std::move(Val);
> +}
> +
> +template<class T, class V>
> +typename std::enable_if< !std::is_constructible<T, V>::value
> + , typename std::remove_reference<V>::type>::type &
> +moveIfMoveConstructible(V &Val) {
> + return Val;
> +}
> +#else
> +template<class T, class V>
> +V &moveIfMoveConstructible(V &Val) {
> + return Val;
> +}
> +#endif
> +
> +/// \brief Stores a reference that can be changed.
> +template <typename T>
> +class ReferenceStorage {
> + T *Storage;
> +
> +public:
> + ReferenceStorage(T &Ref) : Storage(&Ref) {}
> +
> + operator T &() const { return *Storage; }
> + T &get() const { return *Storage; }
> +};
> +
> +/// \brief Represents either an error or a value T.
> +///
> +/// ErrorOr<T> is a pointer-like class that represents the result of an
> +/// operation. The result is either an error, or a value of type T. This
> is
> +/// designed to emulate the usage of returning a pointer where nullptr
> indicates
> +/// failure. However instead of just knowing that the operation failed,
> we also
> +/// have an error_code and optional user data that describes why it
> failed.
> +///
> +/// It is used like the following.
> +/// \code
> +/// ErrorOr<Buffer> getBuffer();
> +/// void handleError(error_code ec);
> +///
> +/// auto buffer = getBuffer();
> +/// if (!buffer)
> +/// handleError(buffer);
> +/// buffer->write("adena");
> +/// \endcode
> +///
> +/// ErrorOr<T> also supports user defined data for specific error_codes.
> To use
> +/// this feature you must first add a template specialization of
> +/// ErrorOrUserDataTraits derived from std::true_type for your type in
> the lld
> +/// namespace. This specialization must have a static error_code error()
> +/// function that returns the error_code this data is used with.
> +///
> +/// getError<UserData>() may be called to get either the stored user
> data, or
> +/// a default constructed UserData if none was stored.
> +///
> +/// Example:
> +/// \code
> +/// struct InvalidArgError {
> +/// InvalidArgError() {}
> +/// InvalidArgError(std::string S) : ArgName(S) {}
> +/// std::string ArgName;
> +/// };
> +///
> +/// namespace llvm {
> +/// template<>
> +/// struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type {
> +/// static error_code error() {
> +/// return make_error_code(errc::invalid_argument);
> +/// }
> +/// };
> +/// } // end namespace llvm
> +///
> +/// using namespace llvm;
> +///
> +/// ErrorOr<int> foo() {
> +/// return InvalidArgError("adena");
> +/// }
> +///
> +/// int main() {
> +/// auto a = foo();
> +/// if (!a && error_code(a) == errc::invalid_argument)
> +/// llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n";
> +/// }
> +/// \endcode
> +///
> +/// An implicit conversion to bool provides a way to check if there was an
> +/// error. The unary * and -> operators provide pointer like access to the
> +/// value. Accessing the value when there is an error has undefined
> behavior.
> +///
> +/// When T is a reference type the behaivor is slightly different. The
> reference
> +/// is held in a std::reference_wrapper<std::remove_reference<T>::type>,
> and
> +/// there is special handling to make operator -> work as if T was not a
> +/// reference.
> +///
> +/// T cannot be a rvalue reference.
> +template<class T>
> +class ErrorOr {
> + static const bool isRef = is_reference<T>::value;
> + typedef ReferenceStorage<typename remove_reference<T>::type> wrap;
> +
> +public:
> + typedef typename
> + conditional< isRef
> + , wrap
> + , T
> + >::type storage_type;
> +
> +private:
> + typedef T &reference;
> + typedef typename remove_reference<T>::type *pointer;
> +
> +public:
> + ErrorOr() : IsValid(false) {}
> +
> + ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
> + Error = new ErrorHolderBase;
> + Error->Error = EC;
> + Error->HasUserData = false;
> + }
> +
> + template<class UserDataT>
> + ErrorOr(UserDataT UD, typename
> + enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0)
> + : HasError(true), IsValid(true) {
> + Error = new ErrorHolder<UserDataT>(llvm_move(UD));
> + Error->Error = ErrorOrUserDataTraits<UserDataT>::error();
> + Error->HasUserData = true;
> + }
> +
> + ErrorOr(T Val) : HasError(false), IsValid(true) {
> + new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val));
> + }
> +
> + ErrorOr(const ErrorOr &Other) : IsValid(false) {
> + // Construct an invalid ErrorOr if other is invalid.
> + if (!Other.IsValid)
> + return;
> + if (!Other.HasError) {
> + // Get the other value.
> + new (get()) storage_type(*Other.get());
> + HasError = false;
> + } else {
> + // Get other's error.
> + Error = Other.Error;
> + HasError = true;
> + Error->aquire();
> + }
> +
> + IsValid = true;
> + }
> +
> + ErrorOr &operator =(const ErrorOr &Other) {
> + if (this == &Other)
> + return *this;
> +
> + this->~ErrorOr();
> + new (this) ErrorOr(Other);
> +
> + return *this;
> + }
> +
> +#if LLVM_HAS_RVALUE_REFERENCES
> + ErrorOr(ErrorOr &&Other) : IsValid(false) {
> + // Construct an invalid ErrorOr if other is invalid.
> + if (!Other.IsValid)
> + return;
> + if (!Other.HasError) {
> + // Get the other value.
> + IsValid = true;
> + new (get()) storage_type(std::move(*Other.get()));
> + HasError = false;
> + // Tell other not to do any destruction.
> + Other.IsValid = false;
> + } else {
> + // Get other's error.
> + Error = Other.Error;
> + HasError = true;
> + // Tell other not to do any destruction.
> + Other.IsValid = false;
> + }
> +
> + IsValid = true;
> + }
> +
> + ErrorOr &operator =(ErrorOr &&Other) {
> + if (this == &Other)
> + return *this;
> +
> + this->~ErrorOr();
> + new (this) ErrorOr(std::move(Other));
> +
> + return *this;
> + }
> +
> + ~ErrorOr() {
> + if (!IsValid)
> + return;
> + if (HasError)
> + Error->release();
> + else
> + get()->~storage_type();
> + }
> +#endif
> +
> + template<class ET>
> + ET getError() const {
> + assert(IsValid && "Cannot get the error of a default constructed
> ErrorOr!");
> + assert(HasError && "Cannot get an error if none exists!");
> + assert(ErrorOrUserDataTraits<ET>::error() == Error->Error &&
> + "Incorrect user error data type for error!");
> + if (!Error->HasUserData)
> + return ET();
> + return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData;
> + }
> +
> + typedef void (*unspecified_bool_type)();
> + static void unspecified_bool_true() {}
> +
> + /// \brief Return false if there is an error.
> + operator unspecified_bool_type() const {
> + assert(IsValid && "Can't do anything on a default constructed
> ErrorOr!");
> + return HasError ? 0 : unspecified_bool_true;
> + }
> +
> + operator llvm::error_code() const {
> + assert(IsValid && "Can't do anything on a default constructed
> ErrorOr!");
> + return HasError ? Error->Error : llvm::error_code::success();
> + }
> +
> + pointer operator ->() {
> + return toPointer(get());
> + }
> +
> + reference operator *() {
> + return *get();
> + }
> +
> +private:
> + pointer toPointer(pointer Val) {
> + return Val;
> + }
> +
> + pointer toPointer(wrap *Val) {
> + return &Val->get();
> + }
> +
> +protected:
> + storage_type *get() {
> + assert(IsValid && "Can't do anything on a default constructed
> ErrorOr!");
> + assert(!HasError && "Cannot get value when an error exists!");
> + return reinterpret_cast<storage_type*>(TStorage.buffer);
> + }
> +
> + const storage_type *get() const {
> + assert(IsValid && "Can't do anything on a default constructed
> ErrorOr!");
> + assert(!HasError && "Cannot get value when an error exists!");
> + return reinterpret_cast<const storage_type*>(TStorage.buffer);
> + }
> +
> + union {
> + AlignedCharArrayUnion<storage_type> TStorage;
> + ErrorHolderBase *Error;
> + };
> + bool HasError : 1;
> + bool IsValid : 1;
> +};
> +
> +template<class T, class E>
> +typename enable_if_c<is_error_code_enum<E>::value ||
> + is_error_condition_enum<E>::value, bool>::type
> +operator ==(ErrorOr<T> &Err, E Code) {
> + return error_code(Err) == Code;
> +}
> +} // end namespace llvm
> +
> +#endif
>
> Modified: llvm/trunk/include/llvm/Support/type_traits.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/type_traits.h?rev=172991&r1=172990&r2=172991&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/type_traits.h (original)
> +++ llvm/trunk/include/llvm/Support/type_traits.h Sun Jan 20 14:32:30 2013
> @@ -145,6 +145,10 @@
> template <typename T> struct is_pointer<T* volatile> : true_type {};
> template <typename T> struct is_pointer<T* const volatile> : true_type {};
>
> +/// \brief Metafunction that determines wheather the given type is a
> reference.
> +template <typename T> struct is_reference : false_type {};
> +template <typename T> struct is_reference<T&> : true_type {};
> +
> /// \brief Metafunction that determines whether the given type is either
> an
> /// integral type or an enumeration type.
> ///
>
> Modified: llvm/trunk/unittests/Support/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CMakeLists.txt?rev=172991&r1=172990&r2=172991&view=diff
>
> ==============================================================================
> --- llvm/trunk/unittests/Support/CMakeLists.txt (original)
> +++ llvm/trunk/unittests/Support/CMakeLists.txt Sun Jan 20 14:32:30 2013
> @@ -13,6 +13,7 @@
> ConstantRangeTest.cpp
> DataExtractorTest.cpp
> EndianTest.cpp
> + ErrorOrTest.cpp
> FileOutputBufferTest.cpp
> IntegersSubsetTest.cpp
> LeakDetectorTest.cpp
>
> Added: llvm/trunk/unittests/Support/ErrorOrTest.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorOrTest.cpp?rev=172991&view=auto
>
> ==============================================================================
> --- llvm/trunk/unittests/Support/ErrorOrTest.cpp (added)
> +++ llvm/trunk/unittests/Support/ErrorOrTest.cpp Sun Jan 20 14:32:30 2013
> @@ -0,0 +1,78 @@
> +//===- unittests/ErrorOrTest.cpp - ErrorOr.h tests
> ------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Support/ErrorOr.h"
> +
> +#include "gtest/gtest.h"
> +
> +#include <memory>
> +
> +using namespace llvm;
> +
> +namespace {
> +
> +ErrorOr<int> t1() {return 1;}
> +ErrorOr<int> t2() {return make_error_code(errc::invalid_argument);}
> +
> +TEST(ErrorOr, SimpleValue) {
> + ErrorOr<int> a = t1();
> + EXPECT_TRUE(a);
> + EXPECT_EQ(1, *a);
> +
> + a = t2();
> + EXPECT_FALSE(a);
> + EXPECT_EQ(errc::invalid_argument, a);
> + EXPECT_DEBUG_DEATH(*a, "Cannot get value when an error exists");
> +}
> +
> +#if LLVM_HAS_CXX11_STDLIB
> +ErrorOr<std::unique_ptr<int> > t3() {
> + return std::unique_ptr<int>(new int(3));
> +}
> +#endif
> +
> +TEST(ErrorOr, Types) {
> + int x;
> + ErrorOr<int&> a(x);
> + *a = 42;
> + EXPECT_EQ(42, x);
> +
> +#if LLVM_HAS_CXX11_STDLIB
> + // Move only types.
> + EXPECT_EQ(3, **t3());
> +#endif
> +}
> +} // end anon namespace
> +
> +struct InvalidArgError {
> + InvalidArgError() {}
> + InvalidArgError(std::string S) : ArgName(S) {}
> + std::string ArgName;
> +};
> +
> +namespace llvm {
> +template<>
> +struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type {
> + static error_code error() {
> + return make_error_code(errc::invalid_argument);
> + }
> +};
> +} // end namespace lld
> +
> +ErrorOr<int> t4() {
> + return InvalidArgError("adena");
> +}
> +
> +namespace {
> +TEST(ErrorOr, UserErrorData) {
> + ErrorOr<int> a = t4();
> + EXPECT_EQ(errc::invalid_argument, a);
> + EXPECT_EQ("adena", t4().getError<InvalidArgError>().ArgName);
> +}
> +} // end anon namespace
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130122/b9291fd6/attachment.html>
More information about the llvm-commits
mailing list