diff mbox

Improve diagnostics for invalid std::allocator specializations

Message ID CAH6eHdTkW068CwALjKYf+9LW_KsiKskY7gZG3bwMsziERXD0AQ@mail.gmail.com
State New
Headers show

Commit Message

Jonathan Wakely Nov. 10, 2013, 6:24 p.m. UTC
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.gcc@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 mbox

Patch

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" }