Index: llvm/include/llvm/ADT/SmallVector.h =================================================================== --- llvm/include/llvm/ADT/SmallVector.h +++ llvm/include/llvm/ADT/SmallVector.h @@ -220,6 +220,10 @@ std::is_trivially_destructible::value> class SmallVectorTemplateBase : public SmallVectorTemplateCommon { protected: + // Type used for taking in new values, which has to be const T & since this + // isn't trivially copyable. This has iterator invalidation gotchas. + using ValueParamT = const T &; + SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} static void destroy_range(T *S, T *E) { @@ -311,6 +315,11 @@ template class SmallVectorTemplateBase : public SmallVectorTemplateCommon { protected: + // Type used for taking in new values, T if it's small enough to be free, + // otherwise const T &. The latter has iterator invalidation gotchas. + using ValueParamT = + typename std::conditional::type; + SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} // No need to do a destroy loop for POD's. @@ -352,7 +361,7 @@ void grow(size_t MinSize = 0) { this->grow_pod(MinSize, sizeof(T)); } public: - void push_back(const T &Elt) { + void push_back(T Elt) { if (LLVM_UNLIKELY(this->size() >= this->capacity())) this->grow(); memcpy(reinterpret_cast(this->end()), &Elt, sizeof(T)); @@ -379,6 +388,9 @@ explicit SmallVectorImpl(unsigned N) : SmallVectorTemplateBase(N) {} + // Type used for taking in new values (either T or const T &). + using ValueParamT = typename SmallVectorTemplateBase::ValueParamT; + public: SmallVectorImpl(const SmallVectorImpl &) = delete; @@ -407,7 +419,7 @@ } } - void resize(size_type N, const T &NV) { + void resize(size_type N, ValueParamT NV) { if (N < this->size()) { this->destroy_range(this->begin()+N, this->end()); this->set_size(N); @@ -453,7 +465,7 @@ } /// Append \p NumInputs copies of \p Elt to the end. - void append(size_type NumInputs, const T &Elt) { + void append(size_type NumInputs, ValueParamT Elt) { if (NumInputs > this->capacity() - this->size()) this->grow(this->size()+NumInputs); @@ -468,7 +480,7 @@ // FIXME: Consider assigning over existing elements, rather than clearing & // re-initializing them - for all assign(...) variants. - void assign(size_type NumElts, const T &Elt) { + void assign(size_type NumElts, ValueParamT Elt) { clear(); if (this->capacity() < NumElts) this->grow(NumElts); @@ -523,7 +535,14 @@ return(N); } - iterator insert(iterator I, T &&Elt) { + // Use a template argument for the iterator so that enable_if can be used to + // disable when ValueParamT is the same as T. + template + iterator insert(IteratorT I1, T &&Elt, + typename std::enable_if_t< + std::is_convertible::value && + !std::is_same::value> * = 0) { + iterator I = I1; if (I == this->end()) { // Important special case for empty vector. this->push_back(::std::move(Elt)); return this->end()-1; @@ -553,7 +572,7 @@ return I; } - iterator insert(iterator I, const T &Elt) { + iterator insert(iterator I, ValueParamT Elt) { if (I == this->end()) { // Important special case for empty vector. this->push_back(Elt); return this->end()-1; @@ -582,7 +601,7 @@ return I; } - iterator insert(iterator I, size_type NumToInsert, const T &Elt) { + iterator insert(iterator I, size_type NumToInsert, ValueParamT Elt) { // Convert iterator to elt# to avoid invalidating iterator when we reserve() size_t InsertElt = I - this->begin(); @@ -895,6 +914,9 @@ template class LLVM_GSL_OWNER SmallVector : public SmallVectorImpl, SmallVectorStorage { + // Type used for taking in new values (either T or const T &). + using ValueParamT = typename SmallVectorTemplateBase::ValueParamT; + public: SmallVector() : SmallVectorImpl(N) {} @@ -903,7 +925,7 @@ this->destroy_range(this->begin(), this->end()); } - explicit SmallVector(size_t Size, const T &Value = T()) + explicit SmallVector(size_t Size, ValueParamT Value = T()) : SmallVectorImpl(N) { this->assign(Size, Value); }