For PR libstdc++/55963 I said I'd improve the diagnostics when you try to use std::vector<const T>, which is invalid because the C++ Allocator requirements require the value_type to be a non-const object type.
I tried adding static assertions to the primary std::allocator template, but the diagnostics are still not very clear, because const types cause ambiguous overloads and reference types cause invalid pointer-to-reference types to be formed. This patch adds std::allocator<const T> and std::allocator<T&> partial specializations instead, which inherit from std::allocator<T> so they can be used in limited ways (most importantly, you can rebind them to a valid specialization) but attempting to construct such an allocator will fail with a helpful message in C++11 mode (and just fail due to using a private constructor in C++03 mode.) The change passes testing, but I haven't committed yet as I'd like to hear other opinions on the approach, or if this is even worth doing at all. I think the better diagnostics are helpful, e.g. with this patch instantiating std::vector<const int> gives the following, rather than 33 far more cryptic lines: In file included from /home/jwakely/gcc/4.x/include/c++/4.9.0/vector:61:0, from a.cc:1: /home/jwakely/gcc/4.x/include/c++/4.9.0/bits/allocator.h: In instantiation of ‘std::allocator<const _Tp>::allocator() [with _Tp = int]’: a.cc:5:26: required from here /home/jwakely/gcc/4.x/include/c++/4.9.0/bits/allocator.h:134:2: error: static assertion failed: allocator's value_type must be non-const static_assert( !is_const<const _Tp>::value, ^
commit b63fee8ad1f7ee67dd68954272f73e02d3fa6e70 Author: Jonathan Wakely <jwakely....@gmail.com> Date: Sat Nov 9 13:23:46 2013 +0000 PR libstdc++/55963 * include/bits/allocator.h (allocator<const _Tp>, allocator<_Tp&>): Add partial specializations to improve diagnostics for invalid uses. * testsuite/20_util/allocator/55963.cc: New. diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index c72859b..451c3be 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -123,6 +123,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Inherit everything else. }; + /// Partial specialization for const types + template<typename _Tp> + class allocator<const _Tp> : public allocator<_Tp> + { +#if __cplusplus >= 201103L + public: + allocator() + { + static_assert( !is_const<const _Tp>::value, + "allocator's value_type must be non-const" ); + } +#else + private: + allocator(); +#endif + }; + + /// Partial specialization for reference types + template<typename _Tp> + class allocator<_Tp&> : public allocator<_Tp> + { +#if __cplusplus >= 201103L + public: + allocator() + { + static_assert( is_object<_Tp&>::value, + "allocator's value_type must be an object type" ); + } +#else + private: + allocator(); +#endif + }; + template<typename _T1, typename _T2> inline bool operator==(const allocator<_T1>&, const allocator<_T2>&) diff --git a/libstdc++-v3/testsuite/20_util/allocator/55963.cc b/libstdc++-v3/testsuite/20_util/allocator/55963.cc new file mode 100644 index 0000000..66f5472 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator/55963.cc @@ -0,0 +1,27 @@ +// Copyright (C) 2013 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 17.6.3.5 Allocator requirements +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +#include <memory> + +std::allocator<int&> a1; // { dg-error "here" } +// { dg-prune-output "must be an object type" } +std::allocator<const int> a2; // { dg-error "here" } +// { dg-prune-output "must be non-const" }