https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108619
Bug ID: 108619
Summary: Compilation error if the construct method of the
allocator isn't implemented and the detructor of
value_type is private
Product: gcc
Version: 12.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: gccbugzilla at thepirate42 dot org
Target Milestone: ---
When I try to compile this code:
#include <memory>
#include <vector>
#include <type_traits>
class a {
~a() = default;
friend class b;
};
class b {
template<typename C>
struct alloc : std::allocator<C> {
template<typename U>
void destroy(U* p){
if constexpr (std::is_array_v<U>){
for(auto& elem : *p){
(destroy)(std::addressof(elem));
}
} else {
p->~U();
}
}
};
std::vector<a,alloc<a>> v;
public:
void f(){
v.emplace_back();
}
};
with this command line
g++ -v -Wall -Wextra -Wpedantic -std=c++20 test.cpp
I get this output:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure
--enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --enable-bootstrap
--prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man
--infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/
--with-build-config=bootstrap-lto --with-linker-hash-style=gnu
--with-system-zlib --enable-__cxa_atexit --enable-cet=auto
--enable-checking=release --enable-clocale=gnu --enable-default-pie
--enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object
--enable-libstdcxx-backtrace --enable-link-serialization=1
--enable-linker-build-id --enable-lto --enable-multilib --enable-plugin
--enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch
--disable-werror
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 12.2.1 20230111 (GCC)
COLLECT_GCC_OPTIONS='-v' '-Wall' '-Wextra' '-Wpedantic' '-std=c++20'
'-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/cc1plus -quiet -v -D_GNU_SOURCE
test.cpp -quiet -dumpdir a- -dumpbase test.cpp -dumpbase-ext .cpp
-mtune=generic -march=x86-64 -Wall -Wextra -Wpedantic -std=c++20 -version -o
/tmp/ccZ8wizU.s
GNU C++20 (GCC) version 12.2.1 20230111 (x86_64-pc-linux-gnu)
compiled by GNU C version 12.2.1 20230111, GMP version 6.2.1, MPFR
version 4.2.0, MPC version 1.3.1, isl version isl-0.25-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory
"/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../include/c++/12.2.1
/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../include/c++/12.2.1/x86_64-pc-linux-gnu
/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/../../../../include/c++/12.2.1/backward
/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/include
/usr/local/include
/usr/lib/gcc/x86_64-pc-linux-gnu/12.2.1/include-fixed
/usr/include
End of search list.
GNU C++20 (GCC) version 12.2.1 20230111 (x86_64-pc-linux-gnu)
compiled by GNU C version 12.2.1 20230111, GMP version 6.2.1, MPFR
version 4.2.0, MPC version 1.3.1, isl version isl-0.25-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: d14869452663722b786a6617dcf7b0b2
In file included from /usr/include/c++/12.2.1/vector:70,
from test.cpp:2:
/usr/include/c++/12.2.1/bits/vector.tcc: In instantiation of ‘constexpr
std::vector<_Tp, _Alloc>::reference std::vector<_Tp,
_Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = a; _Alloc =
b::alloc<a>; reference = a&]’:
test.cpp:36:23: required from here
/usr/include/c++/12.2.1/bits/vector.tcc:117:37: error: no matching function for
call to ‘__gnu_cxx::__alloc_traits<b::alloc<a>,
a>::construct(std::_Vector_base<a, b::alloc<a> >::_Vector_impl&, a*&)’
117 | _Alloc_traits::construct(this->_M_impl,
this->_M_impl._M_finish,
|
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118 | std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/12.2.1/ext/alloc_traits.h:34,
from /usr/include/c++/12.2.1/bits/stl_uninitialized.h:64,
from /usr/include/c++/12.2.1/memory:65,
from test.cpp:1:
/usr/include/c++/12.2.1/bits/alloc_traits.h:360:9: note: candidate:
‘template<class _Tp, class ... _Args> static constexpr decltype
(std::allocator_traits< <template-parameter-1-1> >::_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits< <template-parameter-1-1>
>::construct::__args)...)) std::allocator_traits< <template-parameter-1-1>
>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Args = _Tp; _Alloc =
b::alloc<a>]’
360 | construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
| ^~~~~~~~~
/usr/include/c++/12.2.1/bits/alloc_traits.h:360:9: note: template argument
deduction/substitution failed:
/usr/include/c++/12.2.1/bits/alloc_traits.h: In substitution of ‘template<class
_Tp, class ... _Args> static constexpr decltype
(std::allocator_traits<b::alloc<a> >::_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits< <template-parameter-1-1>
>::construct::__args)...)) std::allocator_traits<b::alloc<a>
>::construct(b::alloc<a>&, _Tp*, _Args&& ...) [with _Tp = a; _Args = {}]’:
/usr/include/c++/12.2.1/bits/vector.tcc:117:30: required from ‘constexpr
std::vector<_Tp, _Alloc>::reference std::vector<_Tp,
_Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = a; _Alloc =
b::alloc<a>; reference = a&]’
test.cpp:36:23: required from here
/usr/include/c++/12.2.1/bits/alloc_traits.h:363:33: error: no matching function
for call to ‘std::allocator_traits<b::alloc<a> >::_S_construct(b::alloc<a>&,
a*&)’
363 | -> decltype(_S_construct(__a, __p,
std::forward<_Args>(__args)...))
|
~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/12.2.1/bits/alloc_traits.h:249:9: note: candidate:
‘template<class _Tp, class ... _Args> static constexpr std::_Require<typename
std::allocator_traits< <template-parameter-1-1> >::__construct_helper<_Tp,
_Args>::type> std::allocator_traits< <template-parameter-1-1>
>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Args = _Tp; _Alloc =
b::alloc<a>]’
249 | _S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
| ^~~~~~~~~~~~
/usr/include/c++/12.2.1/bits/alloc_traits.h:249:9: note: template argument
deduction/substitution failed:
In file included from /usr/include/c++/12.2.1/bits/move.h:57,
from /usr/include/c++/12.2.1/bits/new_allocator.h:36,
from
/usr/include/c++/12.2.1/x86_64-pc-linux-gnu/bits/c++allocator.h:33,
from /usr/include/c++/12.2.1/bits/allocator.h:46,
from /usr/include/c++/12.2.1/memory:63:
/usr/include/c++/12.2.1/type_traits: In substitution of ‘template<bool _Cond,
class _Tp> using __enable_if_t = typename std::enable_if::type [with bool _Cond
= false; _Tp = void]’:
/usr/include/c++/12.2.1/type_traits:2238:11: required by substitution of
‘template<class ... _Cond> using _Require = std::__enable_if_t<std::__and_<
<template-parameter-1-1> >::value> [with _Cond = {std::integral_constant<bool,
false>}]’
/usr/include/c++/12.2.1/bits/alloc_traits.h:249:2: required by substitution
of ‘template<class _Tp, class ... _Args> static constexpr
std::_Require<typename std::allocator_traits<b::alloc<a>
>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<b::alloc<a>
>::_S_construct(b::alloc<a>&, _Tp*, _Args&& ...) [with _Tp = a; _Args = {}]’
/usr/include/c++/12.2.1/bits/alloc_traits.h:363:26: required by substitution
of ‘template<class _Tp, class ... _Args> static constexpr decltype
(std::allocator_traits<b::alloc<a> >::_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits< <template-parameter-1-1>
>::construct::__args)...)) std::allocator_traits<b::alloc<a>
>::construct(b::alloc<a>&, _Tp*, _Args&& ...) [with _Tp = a; _Args = {}]’
/usr/include/c++/12.2.1/bits/vector.tcc:117:30: required from ‘constexpr
std::vector<_Tp, _Alloc>::reference std::vector<_Tp,
_Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = a; _Alloc =
b::alloc<a>; reference = a&]’
test.cpp:36:23: required from here
/usr/include/c++/12.2.1/type_traits:2234:11: error: no type named ‘type’ in
‘struct std::enable_if<false, void>’
2234 | using __enable_if_t = typename enable_if<_Cond, _Tp>::type;
| ^~~~~~~~~~~~~
/usr/include/c++/12.2.1/bits/alloc_traits.h: In substitution of ‘template<class
_Tp, class ... _Args> static constexpr decltype
(std::allocator_traits<b::alloc<a> >::_S_construct(__a, __p,
(forward<_Args>)(std::allocator_traits< <template-parameter-1-1>
>::construct::__args)...)) std::allocator_traits<b::alloc<a>
>::construct(b::alloc<a>&, _Tp*, _Args&& ...) [with _Tp = a; _Args = {}]’:
/usr/include/c++/12.2.1/bits/vector.tcc:117:30: required from ‘constexpr
std::vector<_Tp, _Alloc>::reference std::vector<_Tp,
_Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = a; _Alloc =
b::alloc<a>; reference = a&]’
test.cpp:36:23: required from here
/usr/include/c++/12.2.1/bits/alloc_traits.h:257:9: note: candidate:
‘template<class _Tp, class ... _Args> static constexpr
std::_Require<std::__and_<std::__not_<typename std::allocator_traits<
<template-parameter-1-1> >::__construct_helper<_Tp, _Args>::type>,
std::is_constructible<_Tp, _Args ...> > > std::allocator_traits<
<template-parameter-1-1> >::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with
_Args = _Tp; _Alloc = b::alloc<a>]’
257 | _S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
| ^~~~~~~~~~~~
/usr/include/c++/12.2.1/bits/alloc_traits.h:257:9: note: template argument
deduction/substitution failed:
/usr/include/c++/12.2.1/bits/vector.tcc: In instantiation of ‘constexpr
std::vector<_Tp, _Alloc>::reference std::vector<_Tp,
_Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = a; _Alloc =
b::alloc<a>; reference = a&]’:
test.cpp:36:23: required from here
/usr/include/c++/12.2.1/ext/alloc_traits.h:81:7: note: candidate:
‘template<class _Ptr, class ... _Args> static constexpr
std::__enable_if_t<std::__and_<std::is_same<typename
std::allocator_traits<_Alloc>::pointer, _Ptr>,
std::__not_<std::is_pointer<_Ptr> > >::value> __gnu_cxx::__alloc_traits<_Alloc,
<template-parameter-1-2> >::construct(_Alloc&, _Ptr, _Args&& ...) [with _Args =
_Ptr; _Alloc = b::alloc<a>; <template-parameter-1-2> = a]’
81 | construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
| ^~~~~~~~~
/usr/include/c++/12.2.1/ext/alloc_traits.h:81:7: note: template argument
deduction/substitution failed:
Here's a compiler explorer link for convenience:
https://godbolt.org/z/qK1nxhbnW
The code compiles if I add a dummy constructor method to the custom allocator,
that internally just calls std::construct_at (https://godbolt.org/z/bM7rzoWaK),
but I think this shouldn't be necessary; the construct method is optional, and
std::allocator_traits<alloc<a>>::construct should work as intended in both
cases. I suppose this is caused by some sort of check of the "constructability"
of a that fails because of the private destructor, but as far as I know
allocator_traits::construct in c++20 should just forward to std::construct_at
without doing additional checks, which makes this behavior wrong.
I don't know if it's relevant, but msvc compiles this without problems
(https://godbolt.org/z/oEb6Ej4sr).