[gcc r9-9638] libstdc++: Fix constructor constraints for std::any (PR 90415)

Jonathan Wakely redi@gcc.gnu.org
Thu Jul 22 21:28:56 GMT 2021


https://gcc.gnu.org/g:14597b680a24b6f7375e4470dea935da9c369feb

commit r9-9638-g14597b680a24b6f7375e4470dea935da9c369feb
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Apr 24 00:54:20 2020 +0100

    libstdc++: Fix constructor constraints for std::any  (PR 90415)
    
    This removes a non-standard extension to std::any which causes errors
    for valid code, due to recursive instantiation of a trait that isn't
    supposed to be in the constraints.
    
    It also removes some incorrect constraints on the in_place_type<T>
    constructors and emplace members, which were preventing creating a
    std::any object with another std::any as the contained value.
    
    2020-04-24  Kamlesh Kumar  <kamleshbhalui@gmail.com>
                Jonathan Wakely  <jwakely@redhat.com>
    
            PR libstdc++/90415
            PR libstdc++/92156
            * include/std/any (any): Rename template parameters for consistency
            with the standard.
            (any::_Decay): Rename to _Decay_if_not_any.
            (any::any(T&&)): Remove is_constructible from constraints. Remove
            non-standard overload.
            (any::any(in_place_type_t<T>, Args&&...))
            (any::any(in_place_type_t<T>, initializer_list<U>, Args&&...))
            (any::emplace(Args&&...))
            (any::emplace(initializer_list<U>, Args&&...)):
            Use decay_t instead of _Decay.
            * testsuite/20_util/any/cons/90415.cc: New test.
            * testsuite/20_util/any/cons/92156.cc: New Test.
            * testsuite/20_util/any/misc/any_cast_neg.cc: Make dg-error directives
            more robust.
            * testsuite/20_util/any/modifiers/92156.cc: New test.
    
    (cherry picked from commit d1462b0782555354b4480e1f46498586d5882972)

Diff:
---
 libstdc++-v3/include/std/any                       | 115 +++++++++------------
 libstdc++-v3/testsuite/20_util/any/cons/90415.cc   |  64 ++++++++++++
 libstdc++-v3/testsuite/20_util/any/cons/92156.cc   |  53 ++++++++++
 .../testsuite/20_util/any/misc/any_cast_neg.cc     |  16 +--
 .../testsuite/20_util/any/modifiers/92156.cc       |  57 ++++++++++
 5 files changed, 234 insertions(+), 71 deletions(-)

diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any
index 91c4c1a7cf1..796949c7d4a 100644
--- a/libstdc++-v3/include/std/any
+++ b/libstdc++-v3/include/std/any
@@ -105,8 +105,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				     _Manager_internal<_Tp>,
 				     _Manager_external<_Tp>>;
 
-    template<typename _Tp, typename _Decayed = decay_t<_Tp>>
-      using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>;
+    template<typename _Tp, typename _VTp = decay_t<_Tp>>
+      using _Decay_if_not_any = enable_if_t<!is_same_v<_VTp, any>, _VTp>;
 
     /// Emplace with an object created from @p __args as the contained object.
     template <typename _Tp, typename... _Args,
@@ -125,10 +125,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       void __do_emplace(initializer_list<_Up> __il, _Args&&... __args)
       {
 	reset();
-        _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...);
+	_Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...);
 	_M_manager = &_Mgr::_S_manage;
       }
 
+    template <typename _Res, typename _Tp, typename... _Args>
+      using __any_constructible
+	= enable_if<__and_<is_copy_constructible<_Tp>,
+			   is_constructible<_Tp, _Args...>>::value,
+		    _Res>;
+
+    template <typename _Tp, typename... _Args>
+      using __any_constructible_t
+	= typename __any_constructible<bool, _Tp, _Args...>::type;
+
+    template<typename _VTp, typename... _Args>
+      using __emplace_t
+	= typename __any_constructible<_VTp&, _VTp, _Args...>::type;
+
   public:
     // construct/destruct
 
@@ -165,65 +179,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
     }
 
-    template <typename _Res, typename _Tp, typename... _Args>
-    using __any_constructible =
-      enable_if<__and_<is_copy_constructible<_Tp>,
-			 is_constructible<_Tp, _Args...>>::value,
-		  _Res>;
-
-    template <typename _Tp, typename... _Args>
-    using __any_constructible_t =
-      typename __any_constructible<bool, _Tp, _Args...>::type;
-
     /// Construct with a copy of @p __value as the contained object.
-    template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
-	      typename _Mgr = _Manager<_Tp>,
-              __any_constructible_t<_Tp, _ValueType&&> = true,
-	      enable_if_t<!__is_in_place_type<_Tp>::value, bool> = true>
-      any(_ValueType&& __value)
+    template <typename _Tp, typename _VTp = _Decay_if_not_any<_Tp>,
+	      typename _Mgr = _Manager<_VTp>,
+	      enable_if_t<is_copy_constructible<_VTp>::value
+			  && !__is_in_place_type<_VTp>::value, bool> = true>
+      any(_Tp&& __value)
       : _M_manager(&_Mgr::_S_manage)
       {
-        _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value));
-      }
-
-    /// Construct with a copy of @p __value as the contained object.
-    template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
-	      typename _Mgr = _Manager<_Tp>,
-              enable_if_t<__and_v<is_copy_constructible<_Tp>,
-				  __not_<is_constructible<_Tp, _ValueType&&>>,
-				  __not_<__is_in_place_type<_Tp>>>,
-			  bool> = false>
-      any(_ValueType&& __value)
-      : _M_manager(&_Mgr::_S_manage)
-      {
-        _Mgr::_S_create(_M_storage, __value);
+	_Mgr::_S_create(_M_storage, std::forward<_Tp>(__value));
       }
 
     /// Construct with an object created from @p __args as the contained object.
-    template <typename _ValueType, typename... _Args,
-	      typename _Tp = _Decay<_ValueType>,
-	      typename _Mgr = _Manager<_Tp>,
-              __any_constructible_t<_Tp, _Args&&...> = false>
+    template <typename _Tp, typename... _Args, typename _VTp = decay_t<_Tp>,
+	      typename _Mgr = _Manager<_VTp>,
+	      __any_constructible_t<_VTp, _Args&&...> = false>
       explicit
-      any(in_place_type_t<_ValueType>, _Args&&... __args)
+      any(in_place_type_t<_Tp>, _Args&&... __args)
       : _M_manager(&_Mgr::_S_manage)
       {
-        _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...);
+	_Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...);
       }
 
     /// Construct with an object created from @p __il and @p __args as
     /// the contained object.
-    template <typename _ValueType, typename _Up, typename... _Args,
-	      typename _Tp = _Decay<_ValueType>,
-	      typename _Mgr = _Manager<_Tp>,
-              __any_constructible_t<_Tp, initializer_list<_Up>,
+    template <typename _Tp, typename _Up, typename... _Args,
+	      typename _VTp = decay_t<_Tp>, typename _Mgr = _Manager<_VTp>,
+	      __any_constructible_t<_VTp, initializer_list<_Up>,
 				    _Args&&...> = false>
       explicit
-      any(in_place_type_t<_ValueType>,
-	  initializer_list<_Up> __il, _Args&&... __args)
+      any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args)
       : _M_manager(&_Mgr::_S_manage)
       {
-        _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...);
+	_Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...);
       }
 
     /// Destructor, calls @c reset()
@@ -232,7 +220,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     // assignments
 
     /// Copy the state of another object.
-    any& operator=(const any& __rhs)
+    any&
+    operator=(const any& __rhs)
     {
       *this = any(__rhs);
       return *this;
@@ -243,7 +232,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      *
      * @post @c !__rhs.has_value() (not guaranteed for other implementations)
      */
-    any& operator=(any&& __rhs) noexcept
+    any&
+    operator=(any&& __rhs) noexcept
     {
       if (!__rhs.has_value())
 	reset();
@@ -258,40 +248,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
     /// Store a copy of @p __rhs as the contained object.
-    template<typename _ValueType>
-      enable_if_t<is_copy_constructible<_Decay<_ValueType>>::value, any&>
-      operator=(_ValueType&& __rhs)
+    template<typename _Tp>
+      enable_if_t<is_copy_constructible<_Decay_if_not_any<_Tp>>::value, any&>
+      operator=(_Tp&& __rhs)
       {
-	*this = any(std::forward<_ValueType>(__rhs));
+	*this = any(std::forward<_Tp>(__rhs));
 	return *this;
       }
 
     /// Emplace with an object created from @p __args as the contained object.
-    template <typename _ValueType, typename... _Args>
-      typename __any_constructible<_Decay<_ValueType>&,
-				   _Decay<_ValueType>, _Args&&...>::type
+    template <typename _Tp, typename... _Args>
+      __emplace_t<decay_t<_Tp>, _Args...>
       emplace(_Args&&... __args)
       {
-	__do_emplace<_Decay<_ValueType>>(std::forward<_Args>(__args)...);
+	using _VTp = decay_t<_Tp>;
+	__do_emplace<_VTp>(std::forward<_Args>(__args)...);
 	any::_Arg __arg;
 	this->_M_manager(any::_Op_access, this, &__arg);
-	return *static_cast<_Decay<_ValueType>*>(__arg._M_obj);
+	return *static_cast<_VTp*>(__arg._M_obj);
       }
 
     /// Emplace with an object created from @p __il and @p __args as
     /// the contained object.
-    template <typename _ValueType, typename _Up, typename... _Args>
-      typename __any_constructible<_Decay<_ValueType>&,
-				   _Decay<_ValueType>,
-				   initializer_list<_Up>,
-				   _Args&&...>::type
+    template <typename _Tp, typename _Up, typename... _Args>
+      __emplace_t<decay_t<_Tp>, initializer_list<_Up>, _Args&&...>
       emplace(initializer_list<_Up> __il, _Args&&... __args)
       {
-	__do_emplace<_Decay<_ValueType>, _Up>(__il,
-					      std::forward<_Args>(__args)...);
+	using _VTp = decay_t<_Tp>;
+	__do_emplace<_VTp, _Up>(__il, std::forward<_Args>(__args)...);
 	any::_Arg __arg;
 	this->_M_manager(any::_Op_access, this, &__arg);
-	return *static_cast<_Decay<_ValueType>*>(__arg._M_obj);
+	return *static_cast<_VTp*>(__arg._M_obj);
       }
 
     // modifiers
diff --git a/libstdc++-v3/testsuite/20_util/any/cons/90415.cc b/libstdc++-v3/testsuite/20_util/any/cons/90415.cc
new file mode 100644
index 00000000000..122262386d3
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/any/cons/90415.cc
@@ -0,0 +1,64 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// Copyright (C) 2020 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/>.
+
+#include <any>
+#include <utility>
+#include <tuple>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  // PR libstdc++/90415
+  static_assert( std::is_copy_constructible<std::tuple<std::any>>::value );
+}
+
+struct wrapper
+{
+  wrapper() = default;
+
+  wrapper(const std::any& t);
+
+  wrapper(const wrapper& w);
+
+  auto& operator=(const std::any& t);
+
+  auto& operator=(const wrapper& w)
+  {
+    value = w.value;
+    return *this;
+  }
+
+  std::any value;
+};
+
+void
+test02()
+{
+  // PR libstdc++/91630
+  wrapper a, b;
+  a = b;
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/any/cons/92156.cc b/libstdc++-v3/testsuite/20_util/any/cons/92156.cc
new file mode 100644
index 00000000000..d797473716d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/any/cons/92156.cc
@@ -0,0 +1,53 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// Copyright (C) 2020 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/>.
+
+#include <any>
+#include <utility>
+#include <tuple>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto a = std::any(std::in_place_type<std::any>, 5);
+  VERIFY( std::any_cast<int>(std::any_cast<std::any>(a)) == 5 );
+
+  auto b = std::any(std::in_place_type<std::any>, {1});
+  (void) std::any_cast<std::initializer_list<int>>(std::any_cast<std::any>(b));
+}
+
+void
+test02()
+{
+  std::any p = std::pair<std::any, std::any>(1, 1);
+  auto pt = std::any_cast<std::pair<std::any, std::any>>(p);
+  VERIFY( std::any_cast<int>(pt.first) == 1 );
+  VERIFY( std::any_cast<int>(pt.second) == 1 );
+
+  std::any t = std::tuple<std::any>(1);
+  auto tt = std::any_cast<std::tuple<std::any>>(t);
+  VERIFY( std::any_cast<int>(std::get<0>(tt)) == 1 );
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
index d8a52d719db..0c56fce963f 100644
--- a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
@@ -1,5 +1,5 @@
 // { dg-options "-std=gnu++17" }
-// { dg-do compile }
+// { dg-do compile { target c++17 } }
 
 // Copyright (C) 2014-2019 Free Software Foundation, Inc.
 //
@@ -26,20 +26,22 @@ using std::any_cast;
 void test01()
 {
   const any y(1);
-  any_cast<int&>(y); // { dg-error "invalid static_cast" "" { target { *-*-* } } 461 }
-  // { dg-error "Template argument must be constructible from a const value" "" { target { *-*-* } } 457 }
+  any_cast<int&>(y); // { dg-error "here" }
+  // { dg-error "Template argument must be constructible from a const value" "" { target { *-*-* } } 0 }
 }
 
 void test02()
 {
   any y(1);
-  any_cast<int&&>(y);
-  // { dg-error "Template argument must be constructible from an lvalue" "" { target { *-*-* } } 483 }
+  any_cast<int&&>(y); // { dg-error "here" }
+  // { dg-error "Template argument must be constructible from an lvalue" "" { target { *-*-* } } 0 }
 }
 
 void test03()
 {
   any y(1);
-  any_cast<int&>(std::move(y));  // { dg-error "invalid static_cast" "" { target { *-*-* } } 501 }
-  // { dg-error "Template argument must be constructible from an rvalue" "" { target { *-*-* } } 497 }
+  any_cast<int&>(std::move(y)); // { dg-error "here" }
+  // { dg-error "Template argument must be constructible from an rvalue" "" { target { *-*-* } } 0 }
 }
+
+// { dg-prune-output "invalid static_cast" }
diff --git a/libstdc++-v3/testsuite/20_util/any/modifiers/92156.cc b/libstdc++-v3/testsuite/20_util/any/modifiers/92156.cc
new file mode 100644
index 00000000000..4a7bc97bb83
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/any/modifiers/92156.cc
@@ -0,0 +1,57 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// Copyright (C) 2020 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/>.
+
+#include <any>
+#include <utility>
+#include <tuple>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::any a;
+  a.emplace<std::any>(5);
+  VERIFY( std::any_cast<int>(std::any_cast<std::any>(a)) == 5 );
+
+  std::any b;
+  b.emplace<std::any>({1});
+  (void) std::any_cast<std::initializer_list<int>>(std::any_cast<std::any>(b));
+}
+
+void
+test02()
+{
+  std::any p;
+  p.emplace<std::pair<std::any, std::any>>(1, 1);
+  auto pt = std::any_cast<std::pair<std::any, std::any>>(p);
+  VERIFY( std::any_cast<int>(pt.first) == 1 );
+  VERIFY( std::any_cast<int>(pt.second) == 1 );
+
+  std::any t;
+  t.emplace<std::tuple<std::any>>(1);
+  auto tt = std::any_cast<std::tuple<std::any>>(t);
+  VERIFY( std::any_cast<int>(std::get<0>(tt)) == 1 );
+}
+
+int main()
+{
+  test01();
+  test02();
+}


More information about the Libstdc++-cvs mailing list