[PATCH] D125611: DWARFVerifier: Change vector of IntervalMap to vector of unique_ptrs
David Blaikie via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue May 17 13:32:49 PDT 2022
dblaikie added a comment.
In D125611#3519571 <https://reviews.llvm.org/D125611#3519571>, @dim wrote:
> In D125611#3517574 <https://reviews.llvm.org/D125611#3517574>, @dblaikie wrote:
>
>> Some more details on the specifics in the patch description would be good - I'm still not 100% clear on the reproduction case to understand what we're working around, exactly. Do you have a godbolt reproduction/small example, by chance?
>
> Assuming there's a directory with llvm includes, this is enough to reproduce:
>
> #include "llvm/ADT/IntervalMap.h"
> #include <vector>
>
> void f(std::size_t size)
> {
> using namespace llvm;
>
> IntervalMap<uint32_t, uint64_t>::Allocator Alloc;
> std::vector<IntervalMap<uint32_t, uint64_t>> Sections(size, IntervalMap<uint32_t, uint64_t>(Alloc));
> }
>
> which will (on FreeBSD at least, where libc++ is the standard C++ library) result in something like:
>
> $ clang++ -I llvm/include -c intervalmap.cpp
> In file included from intervalmap.cpp:1:
> In file included from llvm/include/llvm/ADT/IntervalMap.h:108:
> In file included from llvm/include/llvm/ADT/SmallVector.h:19:
> In file included from /usr/include/c++/v1/algorithm:643:
> /usr/include/c++/v1/memory:1809:31: error: call to implicitly-deleted copy constructor of 'llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>'
> ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
> ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /usr/include/c++/v1/memory:1687:21: note: in instantiation of function template specialization 'std::__1::allocator<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>>::construct<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>, const llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>> &>' requested here
> __a.construct(__p, _VSTD::forward<_Args>(__args)...);
> ^
> /usr/include/c++/v1/memory:1538:14: note: in instantiation of function template specialization 'std::__1::allocator_traits<std::__1::allocator<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>>>::__construct<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>, const llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>> &>' requested here
> {__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
> ^
> /usr/include/c++/v1/vector:1066:25: note: in instantiation of function template specialization 'std::__1::allocator_traits<std::__1::allocator<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>>>::construct<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>, const llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>> &>' requested here
> __alloc_traits::construct(this->__alloc(), _VSTD::__to_address(__pos), __x);
> ^
> /usr/include/c++/v1/vector:1159:9: note: in instantiation of member function 'std::__1::vector<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>, std::__1::allocator<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>>>::__construct_at_end' requested here
> __construct_at_end(__n, __x);
> ^
> intervalmap.cpp:9:48: note: in instantiation of member function 'std::__1::vector<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>, std::__1::allocator<llvm::IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>>>::vector' requested here
> std::vector<IntervalMap<uint32_t, uint64_t>> Sections(size, IntervalMap<uint32_t, uint64_t>(Alloc));
> ^
> llvm/include/llvm/ADT/IntervalMap.h:970:14: note: copy constructor of 'IntervalMap<unsigned int, unsigned long, 12, llvm::IntervalMapInfo<unsigned int>>' is implicitly deleted because variant field 'leaf' has a non-trivial copy constructor
> RootLeaf leaf;
> ^
> 1 error generated.
>
> Ultimately, this is caused by `_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR` in `/usr/include/c++/v1/__config` (this was last modified by @EricWF, but a long time ago). If this setting is enabled (to preserve the old ABI), `std::pair` will always have a non-trivial copy constructor, and since `IntervalMap` contains a `std::pair` (via `RootLeaf` -> `IntervalMapImpl::LeafNode` -> `NodeBase<std::pair<KeyT, KeyT>, ValT, N>`), `IntervalMap` itself is also non-trivially copyable. `std::vector` in turn requires its value type to be copy-constructible (at least certainly when you use the constructor with a size).
I was hoping something I could reproduce without having FreeBSD myself - either on godbolt (though godbolt might not have different OS platforms as a primary feature) or something like that. Or a brief example that emulates the quirk of FreeBSD to better understand what we're working around here.
> I think this patch, using a unique_ptr sidesteps this issue by letting unique_ptr taking care of things. Another way would be to provide a hand-written copy constructor or move constructor for `IntervalMap`.
That seems likely to be a better solution - if that's closer to the root cause, less chance someone else will introduce a similarly problematic use of IntervalMap that way (since the use will be no longer problematic).
Oh, OK, so piecing this together from the various discussions: FreeBSD opted to not pickup an ABI-breaking fix to libc++'s std::pair that would've made std::pair of two trivially copyable types itself trivially copyable. And so without that fix, IntervalMap is not trivially copyable/implicitly copyable because it has a union over a non-trivial type (`RootLeaf` -> `LeafNode` -> `NodeBase<pair<KeyT, KeyT>...` -> which has a member of that `pair<KeyT, KeyT>` type (well, an array of them))
So, yeah, I guess adding a copy and/or move constructor to IntervalMap would be more suitable.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D125611/new/
https://reviews.llvm.org/D125611
More information about the llvm-commits
mailing list