diff mbox series

DR 2586 fix value category in uses-allocator checks

Message ID 20190214150830.GA17361@redhat.com
State New
Headers show
Series DR 2586 fix value category in uses-allocator checks | expand

Commit Message

Jonathan Wakely Feb. 14, 2019, 3:08 p.m. UTC
Because uses-allocator construction is invariably done with a const
lvalue the __uses_alloc helper should use a const lvalue for the
is_constructible checks. Otherwise, it can detect that the type can be
constructed from an rvalue, and then an error happens when a const
lvalue is passed to the constructor instead.

Prior to LWG DR 2586 scoped_allocator_adaptor incorrectly used an rvalue
type in the is_constructible check and then used a non-const lvalue for
the actual construction. The other components using uses-allocator
construction (tuple and polymorphic_allocator) have always done so with
a const lvalue allocator, although the use of __use_alloc in our
implementation meant they behaved the same as scoped_allocator_adaptor
and incorrectly used rvalues for the is_constructible checks.

In C++20 the P0591R4 changes mean that all uses-allocator construction
is defined in terms of the new uses_allocator_construction_args
functions, which always use a const lvalue allocator.

The changes in this patch ensure that the __use_alloc helper correctly
matches the requirements in the standard, consistently using a const
lvalue allocator for the is_constructible checks and the actual
constructor arguments.

	* doc/xml/manual/intro.xml: Document LWG 2586 status.
	* include/bits/uses_allocator.h (__uses_alloc): Use const lvalue
	allocator type in is_constructible checks.
	* testsuite/20_util/scoped_allocator/69293_neg.cc: Adjust dg-error.
	* testsuite/20_util/scoped_allocator/dr2586.cc: New test.
	* testsuite/20_util/tuple/cons/allocators.cc: Add test using
	problematic type from LWG 2586 discussion.
	* testsuite/20_util/uses_allocator/69293_neg.cc: Adjust dg-error.
	* testsuite/20_util/uses_allocator/cons_neg.cc: Likewise.

Tested powerpc64le-linux, committed to trunk.
commit 4e3200491f4cde4ae884a28bb11ece782ca17997
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Feb 14 11:17:22 2019 +0000

    DR 2586 fix value category in uses-allocator checks
    
    Because uses-allocator construction is invariably done with a const
    lvalue the __uses_alloc helper should use a const lvalue for the
    is_constructible checks. Otherwise, it can detect that the type can be
    constructed from an rvalue, and then an error happens when a const
    lvalue is passed to the constructor instead.
    
    Prior to LWG DR 2586 scoped_allocator_adaptor incorrectly used an rvalue
    type in the is_constructible check and then used a non-const lvalue for
    the actual construction. The other components using uses-allocator
    construction (tuple and polymorphic_allocator) have always done so with
    a const lvalue allocator, although the use of __use_alloc in our
    implementation meant they behaved the same as scoped_allocator_adaptor
    and incorrectly used rvalues for the is_constructible checks.
    
    In C++20 the P0591R4 changes mean that all uses-allocator construction
    is defined in terms of the new uses_allocator_construction_args
    functions, which always use a const lvalue allocator.
    
    The changes in this patch ensure that the __use_alloc helper correctly
    matches the requirements in the standard, consistently using a const
    lvalue allocator for the is_constructible checks and the actual
    constructor arguments.
    
            * doc/xml/manual/intro.xml: Document LWG 2586 status.
            * include/bits/uses_allocator.h (__uses_alloc): Use const lvalue
            allocator type in is_constructible checks.
            * testsuite/20_util/scoped_allocator/69293_neg.cc: Adjust dg-error.
            * testsuite/20_util/scoped_allocator/dr2586.cc: New test.
            * testsuite/20_util/tuple/cons/allocators.cc: Add test using
            problematic type from LWG 2586 discussion.
            * testsuite/20_util/uses_allocator/69293_neg.cc: Adjust dg-error.
            * testsuite/20_util/uses_allocator/cons_neg.cc: Likewise.
diff mbox series

Patch

diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml
index 656e32b00aa..9761b82fd65 100644
--- a/libstdc++-v3/doc/xml/manual/intro.xml
+++ b/libstdc++-v3/doc/xml/manual/intro.xml
@@ -1142,6 +1142,14 @@  requirements of the license of GCC.
     <listitem><para>Add new constructor.
     </para></listitem></varlistentry>
 
+    <varlistentry xml:id="manual.bugs.dr2586"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2586">2586</link>:
+       <emphasis>Wrong value category used in <code>scoped_allocator_adaptor::construct()</code>
+       </emphasis>
+    </term>
+    <listitem><para>Change internal helper for uses-allocator construction
+      to always check using const lvalue allocators.
+    </para></listitem></varlistentry>
+
     <varlistentry xml:id="manual.bugs.dr2684"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2684">2684</link>:
        <emphasis><code>priority_queue</code> lacking comparator typedef
        </emphasis>
diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h
index a118f695535..015828bee18 100644
--- a/libstdc++-v3/include/bits/uses_allocator.h
+++ b/libstdc++-v3/include/bits/uses_allocator.h
@@ -87,14 +87,17 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Alloc, typename... _Args>
     struct __uses_alloc<true, _Tp, _Alloc, _Args...>
     : conditional<
-        is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value,
+        is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value,
         __uses_alloc1<_Alloc>,
        	__uses_alloc2<_Alloc>>::type
     {
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 2586. Wrong value category used in scoped_allocator_adaptor::construct
       static_assert(__or_<
-	  is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>,
-	  is_constructible<_Tp, _Args..., _Alloc>>::value, "construction with"
-	  " an allocator must be possible if uses_allocator is true");
+	  is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>,
+	  is_constructible<_Tp, _Args..., const _Alloc&>>::value,
+	  "construction with an allocator must be possible"
+	  " if uses_allocator is true");
     };
 
   template<typename _Tp, typename _Alloc, typename... _Args>
diff --git a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
index bdd14de6a75..69f7280a3de 100644
--- a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
@@ -46,5 +46,5 @@  test01()
   scoped_alloc sa;
   auto p = sa.allocate(1);
   sa.construct(p);  // this is required to be ill-formed
-  // { dg-error "static assertion failed" "" { target *-*-* } 96 }
+  // { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 }
 }
diff --git a/libstdc++-v3/testsuite/20_util/scoped_allocator/dr2586.cc b/libstdc++-v3/testsuite/20_util/scoped_allocator/dr2586.cc
new file mode 100644
index 00000000000..11aab8a420b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/scoped_allocator/dr2586.cc
@@ -0,0 +1,34 @@ 
+// Copyright (C) 2019 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/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <memory>
+#include <scoped_allocator>
+
+// DR 2586. Wrong value category used in scoped_allocator_adaptor::construct()
+
+struct X {
+  using allocator_type = std::allocator<X>;
+  X(std::allocator_arg_t, allocator_type&&) { }
+  X(const allocator_type&) { }
+};
+
+int main() {
+  std::scoped_allocator_adaptor<std::allocator<X>> sa;
+  sa.construct(sa.allocate(1));
+}
diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc
index 2951de0d922..92938ecb450 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc
@@ -181,9 +181,23 @@  void test02()
   test_type empty = make_tuple();
 }
 
+void test03()
+{
+  struct dr2586
+  {
+    using allocator_type = std::allocator<int>;
+    dr2586(std::allocator_arg_t, allocator_type&&) { }
+    dr2586(const allocator_type&) { }
+  };
+
+  const dr2586::allocator_type a;
+  std::tuple<dr2586> t{std::allocator_arg, a};
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/20_util/uses_allocator/69293_neg.cc b/libstdc++-v3/testsuite/20_util/uses_allocator/69293_neg.cc
index 575fe546135..8f2d4b16a16 100644
--- a/libstdc++-v3/testsuite/20_util/uses_allocator/69293_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/uses_allocator/69293_neg.cc
@@ -44,5 +44,5 @@  test01()
 {
   alloc_type a;
   std::tuple<X> t(std::allocator_arg, a); // this is required to be ill-formed
-  // { dg-error "static assertion failed" "" { target *-*-* } 96 }
+  // { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 }
 }
diff --git a/libstdc++-v3/testsuite/20_util/uses_allocator/cons_neg.cc b/libstdc++-v3/testsuite/20_util/uses_allocator/cons_neg.cc
index 021d56c9fcd..abad4ec6a3a 100644
--- a/libstdc++-v3/testsuite/20_util/uses_allocator/cons_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/uses_allocator/cons_neg.cc
@@ -43,4 +43,4 @@  void test01()
 
   tuple<Type> t(allocator_arg, a, 1);
 }
-// { dg-error "static assertion failed" "" { target *-*-* } 96 }
+// { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 }