Index: docs/ProgrammersManual.rst =================================================================== --- docs/ProgrammersManual.rst +++ docs/ProgrammersManual.rst @@ -1456,7 +1456,7 @@ #. std::vector is exception-safe, and some implementations have pessimizations that copy elements when SmallVector would move them. -#. SmallVector understands ``isPodLike`` and uses realloc aggressively. +#. SmallVector understands ``is_trivially_copyable`` and uses realloc aggressively. #. Many LLVM APIs take a SmallVectorImpl as an out parameter (see the note below). Index: include/llvm/ADT/ArrayRef.h =================================================================== --- include/llvm/ADT/ArrayRef.h +++ include/llvm/ADT/ArrayRef.h @@ -526,12 +526,6 @@ /// @} - // ArrayRefs can be treated like a POD type. - template struct isPodLike; - template struct isPodLike> { - static const bool value = true; - }; - template hash_code hash_value(ArrayRef S) { return hash_combine_range(S.begin(), S.end()); } Index: include/llvm/ADT/DenseMap.h =================================================================== --- include/llvm/ADT/DenseMap.h +++ include/llvm/ADT/DenseMap.h @@ -146,7 +146,8 @@ } const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); - if (isPodLike::value && isPodLike::value) { + if (is_trivially_copyable::value && + is_trivially_copyable::value) { // Use a simpler loop when these are trivial types. for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) P->getFirst() = EmptyKey; @@ -422,7 +423,8 @@ setNumEntries(other.getNumEntries()); setNumTombstones(other.getNumTombstones()); - if (isPodLike::value && isPodLike::value) + if (is_trivially_copyable::value && + is_trivially_copyable::value) memcpy(reinterpret_cast(getBuckets()), other.getBuckets(), getNumBuckets() * sizeof(BucketT)); else Index: include/llvm/ADT/ImmutableList.h =================================================================== --- include/llvm/ADT/ImmutableList.h +++ include/llvm/ADT/ImmutableList.h @@ -242,10 +242,6 @@ } }; -template struct isPodLike; -template -struct isPodLike> { static const bool value = true; }; - } // end namespace llvm #endif // LLVM_ADT_IMMUTABLELIST_H Index: include/llvm/ADT/Optional.h =================================================================== --- include/llvm/ADT/Optional.h +++ include/llvm/ADT/Optional.h @@ -29,7 +29,9 @@ namespace optional_detail { /// Storage for any type. -template struct OptionalStorage { +template struct OptionalStorage; + +template struct OptionalStorage { AlignedCharArrayUnion storage; bool hasVal = false; @@ -108,15 +110,37 @@ } }; +// Trivially copyable types have trivial destructors, which makes specialization +// simpler and trivially copyable itself +template struct OptionalStorage { + AlignedCharArrayUnion storage = {}; + bool hasVal = false; + + OptionalStorage() = default; + + OptionalStorage(const T &y) : storage{}, hasVal(true) { + new (storage.buffer) T(y); + } + OptionalStorage(const OptionalStorage &O) = default; + OptionalStorage &operator=(const T &y) { + hasVal = true; + new (storage.buffer) T(y); + return *this; + } + OptionalStorage &operator=(const OptionalStorage &O) = default; + ~OptionalStorage() = default; + void reset() { hasVal = false; } +}; + } // namespace optional_detail template class Optional { - optional_detail::OptionalStorage::value> Storage; + optional_detail::OptionalStorage::value> Storage; public: using value_type = T; - constexpr Optional() {} + constexpr Optional() = default; constexpr Optional(NoneType) {} Optional(const T &y) : Storage(y) {} @@ -184,11 +208,6 @@ #endif }; -template struct isPodLike> { - // An Optional is pod-like if T is. - static const bool value = isPodLike::value; -}; - template bool operator==(const Optional &X, const Optional &Y) { if (X && Y) Index: include/llvm/ADT/PointerIntPair.h =================================================================== --- include/llvm/ADT/PointerIntPair.h +++ include/llvm/ADT/PointerIntPair.h @@ -174,12 +174,6 @@ } }; -template struct isPodLike; -template -struct isPodLike> { - static const bool value = true; -}; - // Provide specialization of DenseMapInfo for PointerIntPair. template struct DenseMapInfo> { Index: include/llvm/ADT/SmallVector.h =================================================================== --- include/llvm/ADT/SmallVector.h +++ include/llvm/ADT/SmallVector.h @@ -180,9 +180,9 @@ } }; -/// SmallVectorTemplateBase - This is where we put method -/// implementations that are designed to work with non-POD-like T's. -template +/// SmallVectorTemplateBase - This is where we +/// put method implementations that are designed to work with non-POD-like T's. +template class SmallVectorTemplateBase : public SmallVectorTemplateCommon { protected: SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} @@ -236,8 +236,8 @@ }; // Define this out-of-line to dissuade the C++ compiler from inlining it. -template -void SmallVectorTemplateBase::grow(size_t MinSize) { +template +void SmallVectorTemplateBase::grow(size_t MinSize) { if (MinSize > UINT32_MAX) report_bad_alloc_error("SmallVector capacity overflow during allocation"); @@ -260,9 +260,8 @@ this->Capacity = NewCapacity; } - -/// SmallVectorTemplateBase - This is where we put method -/// implementations that are designed to work with POD-like T's. +/// SmallVectorTemplateBase - This is where we put +/// method implementations that are designed to work with POD-like T's. template class SmallVectorTemplateBase : public SmallVectorTemplateCommon { protected: @@ -320,8 +319,10 @@ /// This class consists of common code factored out of the SmallVector class to /// reduce code duplication based on the SmallVector 'N' template parameter. template -class SmallVectorImpl : public SmallVectorTemplateBase::value> { - using SuperClass = SmallVectorTemplateBase::value>; +class SmallVectorImpl + : public SmallVectorTemplateBase::value> { + using SuperClass = + SmallVectorTemplateBase::value>; public: using iterator = typename SuperClass::iterator; @@ -331,7 +332,7 @@ protected: // Default ctor - Initialize to empty. explicit SmallVectorImpl(unsigned N) - : SmallVectorTemplateBase::value>(N) {} + : SmallVectorTemplateBase::value>(N) {} public: SmallVectorImpl(const SmallVectorImpl &) = delete; Index: include/llvm/ADT/StringRef.h =================================================================== --- include/llvm/ADT/StringRef.h +++ include/llvm/ADT/StringRef.h @@ -928,10 +928,6 @@ LLVM_NODISCARD hash_code hash_value(StringRef S); - // StringRefs can be treated like a POD type. - template struct isPodLike; - template <> struct isPodLike { static const bool value = true; }; - } // end namespace llvm #endif // LLVM_ADT_STRINGREF_H Index: include/llvm/ADT/bit.h =================================================================== --- include/llvm/ADT/bit.h +++ include/llvm/ADT/bit.h @@ -41,11 +41,11 @@ , typename = typename std::enable_if<__is_trivially_copyable(To)>::type , typename = typename std::enable_if<__is_trivially_copyable(From)>::type #else - // This case is GCC 4.x. clang with libc++ or libstdc++ never get here. Unlike - // llvm/Support/type_traits.h's isPodLike we don't want to provide a - // good-enough answer here: developers in that configuration will hit - // compilation failures on the bots instead of locally. That's acceptable - // because it's very few developers, and only until we move past C++11. +// This case is GCC 4.x. clang with libc++ or libstdc++ never get here. Unlike +// llvm/Support/type_traits.h's is_trivially_constructible we don't want to +// provide a good-enough answer here: developers in that configuration will hit +// compilation failures on the bots instead of locally. That's acceptable +// because it's very few developers, and only until we move past C++11. #endif > inline To bit_cast(const From &from) noexcept { Index: include/llvm/Analysis/BlockFrequencyInfoImpl.h =================================================================== --- include/llvm/Analysis/BlockFrequencyInfoImpl.h +++ include/llvm/Analysis/BlockFrequencyInfoImpl.h @@ -160,10 +160,6 @@ } // end namespace bfi_detail -template <> struct isPodLike { - static const bool value = true; -}; - /// Base class for BlockFrequencyInfoImpl /// /// BlockFrequencyInfoImplBase has supporting data structures and some Index: include/llvm/Bitcode/BitCodes.h =================================================================== --- include/llvm/Bitcode/BitCodes.h +++ include/llvm/Bitcode/BitCodes.h @@ -160,8 +160,6 @@ }; -template <> struct isPodLike { static const bool value=true; }; - /// BitCodeAbbrev - This class represents an abbreviation record. An /// abbreviation allows a complex record that has redundancy to be stored in a /// specialized format instead of the fully-general, fully-vbr, format. Index: include/llvm/CodeGen/RegisterPressure.h =================================================================== --- include/llvm/CodeGen/RegisterPressure.h +++ include/llvm/CodeGen/RegisterPressure.h @@ -132,10 +132,6 @@ } }; -template <> struct isPodLike { - static const bool value = true; -}; - /// List of PressureChanges in order of increasing, unique PSetID. /// /// Use a small fixed number, because we can fit more PressureChanges in an Index: include/llvm/CodeGen/ScheduleDAG.h =================================================================== --- include/llvm/CodeGen/ScheduleDAG.h +++ include/llvm/CodeGen/ScheduleDAG.h @@ -239,9 +239,6 @@ void dump(const TargetRegisterInfo *TRI = nullptr) const; }; - template <> - struct isPodLike { static const bool value = true; }; - /// Scheduling unit. This is a node in the scheduling DAG. class SUnit { private: Index: include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- include/llvm/CodeGen/SelectionDAGNodes.h +++ include/llvm/CodeGen/SelectionDAGNodes.h @@ -232,7 +232,6 @@ return LHS == RHS; } }; -template <> struct isPodLike { static const bool value = true; }; /// Allow casting operators to work directly on /// SDValues as if they were SDNode*'s. Index: include/llvm/CodeGen/SlotIndexes.h =================================================================== --- include/llvm/CodeGen/SlotIndexes.h +++ include/llvm/CodeGen/SlotIndexes.h @@ -302,8 +302,6 @@ } }; - template <> struct isPodLike { static const bool value = true; }; - inline raw_ostream& operator<<(raw_ostream &os, SlotIndex li) { li.print(os); return os; Index: include/llvm/CodeGen/TargetPassConfig.h =================================================================== --- include/llvm/CodeGen/TargetPassConfig.h +++ include/llvm/CodeGen/TargetPassConfig.h @@ -75,9 +75,6 @@ } }; -template <> struct isPodLike { - static const bool value = true; -}; /// Target-Independent Code Generator Pass Configuration Options. /// Index: include/llvm/IR/CFG.h =================================================================== --- include/llvm/IR/CFG.h +++ include/llvm/IR/CFG.h @@ -236,10 +236,6 @@ } }; -template struct isPodLike> { - static const bool value = isPodLike::value; -}; - using succ_iterator = SuccIterator; using succ_const_iterator = SuccIterator; using succ_range = iterator_range; Index: include/llvm/IR/ValueHandle.h =================================================================== --- include/llvm/IR/ValueHandle.h +++ include/llvm/IR/ValueHandle.h @@ -309,15 +309,6 @@ } }; -template -struct isPodLike> { -#ifdef NDEBUG - static const bool value = true; -#else - static const bool value = false; -#endif -}; - /// Value handle that tracks a Value across RAUW. /// /// TrackingVH is designed for situations where a client needs to hold a handle @@ -549,14 +540,6 @@ } }; -template struct isPodLike> { -#ifdef NDEBUG - static const bool value = true; -#else - static const bool value = false; -#endif -}; - } // end namespace llvm #endif // LLVM_IR_VALUEHANDLE_H Index: include/llvm/MC/MCInst.h =================================================================== --- include/llvm/MC/MCInst.h +++ include/llvm/MC/MCInst.h @@ -154,8 +154,6 @@ bool evaluateAsConstantImm(int64_t &Imm) const; }; -template <> struct isPodLike { static const bool value = true; }; - /// Instances of this class represent a single low-level machine /// instruction. class MCInst { Index: include/llvm/Support/ScaledNumber.h =================================================================== --- include/llvm/Support/ScaledNumber.h +++ include/llvm/Support/ScaledNumber.h @@ -887,10 +887,6 @@ Digits >>= Shift; } -template struct isPodLike; -template struct isPodLike> { - static const bool value = true; -}; } // end namespace llvm Index: include/llvm/Support/type_traits.h =================================================================== --- include/llvm/Support/type_traits.h +++ include/llvm/Support/type_traits.h @@ -25,34 +25,27 @@ namespace llvm { -/// isPodLike - This is a type trait that is used to determine whether a given -/// type can be copied around with memcpy instead of running ctors etc. template -struct isPodLike { - // std::is_trivially_copyable is available in libc++ with clang, libstdc++ - // that comes with GCC 5. +using is_trivially_copyable = +// std::is_trivially_copyable is available in libc++ with clang, libstdc++ +// that comes with GCC 5. #if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \ (defined(__GNUC__) && __GNUC__ >= 5) - // If the compiler supports the is_trivially_copyable trait use it, as it - // matches the definition of isPodLike closely. - static const bool value = std::is_trivially_copyable::value; + + // If the compiler supports the is_trivially_copyable trait use it + std::is_trivially_copyable; #elif __has_feature(is_trivially_copyable) - // Use the internal name if the compiler supports is_trivially_copyable but we - // don't know if the standard library does. This is the case for clang in - // conjunction with libstdc++ from GCC 4.x. - static const bool value = __is_trivially_copyable(T); + // Use the internal name if the compiler supports is_trivially_copyable but + // we don't know if the standard library does. This is the case for clang in + // conjunction with libstdc++ from GCC 4.x. + std::integral_constant; +#elif (defined(__GNUC__) && __GNUC__ >= 4) + std::is_trivial; #else - // If we don't know anything else, we can (at least) assume that all non-class - // types are PODs. - static const bool value = !std::is_class::value; + // If we don't know anything else, we can (at least) assume that all + // non-class types are PODs. + std::integral_constant::value>; #endif -}; - -// std::pair's are pod-like if their elements are. -template -struct isPodLike> { - static const bool value = isPodLike::value && isPodLike::value; -}; /// Metafunction that determines whether the given type is either an /// integral type or an enumeration type, including enum classes. Index: lib/Transforms/Scalar/SROA.cpp =================================================================== --- lib/Transforms/Scalar/SROA.cpp +++ lib/Transforms/Scalar/SROA.cpp @@ -222,13 +222,6 @@ } // end anonymous namespace -namespace llvm { - -template struct isPodLike; -template <> struct isPodLike { static const bool value = true; }; - -} // end namespace llvm - /// Representation of the alloca slices. /// /// This class represents the slices of an alloca which are formed by its Index: tools/llvm-diff/DifferenceEngine.cpp =================================================================== --- tools/llvm-diff/DifferenceEngine.cpp +++ tools/llvm-diff/DifferenceEngine.cpp @@ -68,7 +68,7 @@ unsigned NewSize = Storage.size() - 1; if (NewSize) { // Move the slot at the end to the beginning. - if (isPodLike::value) + if (is_trivially_copyable::value) Storage[0] = Storage[NewSize]; else std::swap(Storage[0], Storage[NewSize]); Index: unittests/ADT/ArrayRefTest.cpp =================================================================== --- unittests/ADT/ArrayRefTest.cpp +++ unittests/ADT/ArrayRefTest.cpp @@ -249,4 +249,9 @@ EXPECT_TRUE(AR2.equals(AR2Ref)); } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable>::value, + "trivially copyable"); +#endif + } // end anonymous namespace Index: unittests/ADT/ImmutableListTest.cpp =================================================================== --- unittests/ADT/ImmutableListTest.cpp +++ unittests/ADT/ImmutableListTest.cpp @@ -268,4 +268,9 @@ ASSERT_EQ(6, i); } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable>>::value, + "trivially copyable"); +#endif + } // namespace Index: unittests/ADT/OptionalTest.cpp =================================================================== --- unittests/ADT/OptionalTest.cpp +++ unittests/ADT/OptionalTest.cpp @@ -14,6 +14,11 @@ namespace { +template constexpr bool is_optional_trivially_copyable_consistent() { + return !(is_trivially_copyable::value ^ + is_trivially_copyable>::value); +} + struct NonDefaultConstructible { static unsigned CopyConstructions; static unsigned Destructions; @@ -36,6 +41,9 @@ CopyAssignments = 0; } }; +static_assert( + is_optional_trivially_copyable_consistent(), + "consistent is_trivially_copyable"); unsigned NonDefaultConstructible::CopyConstructions = 0; unsigned NonDefaultConstructible::Destructions = 0; @@ -198,6 +206,8 @@ } }; unsigned MultiArgConstructor::Destructions = 0; +static_assert(is_optional_trivially_copyable_consistent(), + "consistent is_trivially_copyable"); TEST_F(OptionalTest, Emplace) { MultiArgConstructor::ResetCounts(); @@ -246,6 +256,9 @@ unsigned MoveOnly::Destructions = 0; unsigned MoveOnly::MoveAssignments = 0; +static_assert(is_optional_trivially_copyable_consistent(), + "consistent is_trivially_copyable"); + TEST_F(OptionalTest, MoveOnlyNull) { MoveOnly::ResetCounts(); Optional O; @@ -347,6 +360,9 @@ unsigned Immovable::Constructions = 0; unsigned Immovable::Destructions = 0; +static_assert(is_optional_trivially_copyable_consistent(), + "consistent is_trivially_copyable"); + TEST_F(OptionalTest, ImmovableEmplace) { Optional A; Immovable::ResetCounts(); @@ -384,6 +400,9 @@ } }; +static_assert(is_optional_trivially_copyable_consistent(), + "consistent is_trivially_copyable"); + struct NotEqualTo { template static bool apply(const T &X, const U &Y) { return X != Y; @@ -518,5 +537,9 @@ CheckRelation(InequalityLhs, InequalityRhs, !IsLess); } +// extra tests of the is_trivially_copyable trait for Optional +static_assert(is_optional_trivially_copyable_consistent(), + "consistent is_trivially_copyable"); + } // end anonymous namespace Index: unittests/ADT/PointerIntPairTest.cpp =================================================================== --- unittests/ADT/PointerIntPairTest.cpp +++ unittests/ADT/PointerIntPairTest.cpp @@ -62,6 +62,11 @@ Pair2.setPointerAndInt(&s, E::Case3); EXPECT_EQ(&s, Pair2.getPointer()); EXPECT_EQ(E::Case3, Pair2.getInt()); + +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) + static_assert(is_trivially_copyable>::value, + "trivially copyable"); +#endif } TEST(PointerIntPairTest, DefaultInitialize) { @@ -97,6 +102,13 @@ EXPECT_EQ(FixnumPointerTraits::NumLowBitsAvailable - 1, PointerLikeTypeTraits::NumLowBitsAvailable); + +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) + static_assert( + is_trivially_copyable< + PointerIntPair>::value, + "trivially copyable"); +#endif } } // end anonymous namespace Index: unittests/ADT/StringRefTest.cpp =================================================================== --- unittests/ADT/StringRefTest.cpp +++ unittests/ADT/StringRefTest.cpp @@ -1062,4 +1062,8 @@ EXPECT_EQ(StringRef("Bar"), Strings[1]); } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable::value, "trivially copyable"); +#endif + } // end anonymous namespace Index: unittests/Analysis/BlockFrequencyInfoTest.cpp =================================================================== --- unittests/Analysis/BlockFrequencyInfoTest.cpp +++ unittests/Analysis/BlockFrequencyInfoTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BlockFrequencyInfoImpl.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/AsmParser/Parser.h" @@ -91,5 +92,10 @@ EXPECT_EQ(BFI.getBlockFreq(BB3).getFrequency(), BB3Freq); } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable::value, + "trivially copyable"); +#endif + } // end anonymous namespace } // end namespace llvm Index: unittests/Bitcode/BitstreamReaderTest.cpp =================================================================== --- unittests/Bitcode/BitstreamReaderTest.cpp +++ unittests/Bitcode/BitstreamReaderTest.cpp @@ -148,4 +148,9 @@ } } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable::value, + "trivially copyable"); +#endif + } // end anonymous namespace Index: unittests/CodeGen/CMakeLists.txt =================================================================== --- unittests/CodeGen/CMakeLists.txt +++ unittests/CodeGen/CMakeLists.txt @@ -19,6 +19,7 @@ MachineInstrTest.cpp MachineOperandTest.cpp ScalableVectorMVTsTest.cpp + TypeTraitsTest.cpp ) add_subdirectory(GlobalISel) Index: unittests/CodeGen/MachineInstrTest.cpp =================================================================== --- unittests/CodeGen/MachineInstrTest.cpp +++ unittests/CodeGen/MachineInstrTest.cpp @@ -273,4 +273,8 @@ StringRef(OS.str()).endswith("filename:1:5")); } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable::value, "trivially copyable"); +#endif + } // end namespace Index: unittests/IR/CFGBuilder.cpp =================================================================== --- unittests/IR/CFGBuilder.cpp +++ unittests/IR/CFGBuilder.cpp @@ -9,6 +9,7 @@ #include "CFGBuilder.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/TypeBuilder.h" @@ -267,3 +268,13 @@ EXPECT_TRUE(isa(B.getOrAddBlock("c")->getTerminator())); EXPECT_TRUE(isa(B.getOrAddBlock("d")->getTerminator())); } + +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable::value, + "trivially copyable"); +static_assert(is_trivially_copyable::value, + "trivially copyable"); +static_assert(is_trivially_copyable::value, "trivially copyable"); +static_assert(is_trivially_copyable::value, + "trivially copyable"); +#endif Index: unittests/IR/ValueHandleTest.cpp =================================================================== --- unittests/IR/ValueHandleTest.cpp +++ unittests/IR/ValueHandleTest.cpp @@ -548,5 +548,14 @@ #endif // GTEST_HAS_DEATH_TEST +#ifdef NDEBUG +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable>::value, + "trivially copyable"); +static_assert(is_trivially_copyable>::value, + "trivially copyable"); +#endif +#endif + #endif // NDEBUG } Index: unittests/Support/ScaledNumberTest.cpp =================================================================== --- unittests/Support/ScaledNumberTest.cpp +++ unittests/Support/ScaledNumberTest.cpp @@ -563,4 +563,9 @@ EXPECT_EQ(1u, (n * n).toInt()); } +#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5) +static_assert(is_trivially_copyable>::value, + "trivially copyable"); +#endif + } // end namespace