From d1462b0782555354b4480e1f46498586d5882972 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 24 Apr 2020 00:54:20 +0100 Subject: [PATCH] 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 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 Jonathan Wakely 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, Args&&...)) (any::any(in_place_type_t, initializer_list, Args&&...)) (any::emplace(Args&&...)) (any::emplace(initializer_list, 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. --- libstdc++-v3/ChangeLog | 21 ++++ libstdc++-v3/include/std/any | 115 ++++++++---------- .../testsuite/20_util/any/cons/90415.cc | 64 ++++++++++ .../testsuite/20_util/any/cons/92156.cc | 53 ++++++++ .../20_util/any/misc/any_cast_neg.cc | 16 +-- .../testsuite/20_util/any/modifiers/92156.cc | 57 +++++++++ 6 files changed, 255 insertions(+), 71 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/any/cons/90415.cc create mode 100644 libstdc++-v3/testsuite/20_util/any/cons/92156.cc create mode 100644 libstdc++-v3/testsuite/20_util/any/modifiers/92156.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index ecb8617d02a..7b92ba7eebf 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,24 @@ +2020-04-24 Kamlesh Kumar + Jonathan Wakely + + 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, Args&&...)) + (any::any(in_place_type_t, initializer_list, Args&&...)) + (any::emplace(Args&&...)) + (any::emplace(initializer_list, 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. + 2020-04-23 Jonathan Wakely * doc/xml/manual/status_cxx2020.xml: Update C++20 status table. diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any index 6b7e68f0e63..e13292296d3 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> - using _Decay = enable_if_t::value, _Decayed>; + template> + using _Decay_if_not_any = enable_if_t, _VTp>; /// Emplace with an object created from @p __args as the contained object. template __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 + using __any_constructible + = enable_if<__and_, + is_constructible<_Tp, _Args...>>::value, + _Res>; + + template + using __any_constructible_t + = typename __any_constructible::type; + + template + using __emplace_t + = typename __any_constructible<_VTp&, _VTp, _Args...>::type; + public: // construct/destruct @@ -165,65 +179,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } - template - using __any_constructible = - enable_if<__and_, - is_constructible<_Tp, _Args...>>::value, - _Res>; - - template - using __any_constructible_t = - typename __any_constructible::type; - /// Construct with a copy of @p __value as the contained object. - template , - typename _Mgr = _Manager<_Tp>, - __any_constructible_t<_Tp, _ValueType&&> = true, - enable_if_t::value, bool> = true> - any(_ValueType&& __value) + template , + typename _Mgr = _Manager<_VTp>, + enable_if_t::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 _Mgr = _Manager<_Tp>, - enable_if_t<__and_v, - __not_>, - __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 _Mgr = _Manager<_Tp>, - __any_constructible_t<_Tp, _Args&&...> = false> + template , + 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 _Mgr = _Manager<_Tp>, - __any_constructible_t<_Tp, initializer_list<_Up>, + template , 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 - enable_if_t>::value, any&> - operator=(_ValueType&& __rhs) + template + enable_if_t>::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 __any_constructible<_Decay<_ValueType>&, - _Decay<_ValueType>, _Args&&...>::type + template + __emplace_t, _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 __any_constructible<_Decay<_ValueType>&, - _Decay<_ValueType>, - initializer_list<_Up>, - _Args&&...>::type + template + __emplace_t, 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 +// . + +#include +#include +#include +#include + +void +test01() +{ + // PR libstdc++/90415 + static_assert( std::is_copy_constructible>::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 +// . + +#include +#include +#include +#include + +void +test01() +{ + auto a = std::any(std::in_place_type, 5); + VERIFY( std::any_cast(std::any_cast(a)) == 5 ); + + auto b = std::any(std::in_place_type, {1}); + (void) std::any_cast>(std::any_cast(b)); +} + +void +test02() +{ + std::any p = std::pair(1, 1); + auto pt = std::any_cast>(p); + VERIFY( std::any_cast(pt.first) == 1 ); + VERIFY( std::any_cast(pt.second) == 1 ); + + std::any t = std::tuple(1); + auto tt = std::any_cast>(t); + VERIFY( std::any_cast(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 6a271e8faab..049815a0c1f 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-2020 Free Software Foundation, Inc. // @@ -26,20 +26,22 @@ using std::any_cast; void test01() { const any y(1); - any_cast(y); // { dg-error "invalid 'static_cast'" "" { target { *-*-* } } 461 } - // { dg-error "Template argument must be constructible from a const value" "" { target { *-*-* } } 457 } + any_cast(y); // { dg-error "here" } + // { dg-error "Template argument must be constructible from a const value" "" { target { *-*-* } } 0 } } void test02() { any y(1); - any_cast(y); - // { dg-error "Template argument must be constructible from an lvalue" "" { target { *-*-* } } 483 } + any_cast(y); // { dg-error "here" } + // { dg-error "Template argument must be constructible from an lvalue" "" { target { *-*-* } } 0 } } void test03() { any y(1); - any_cast(std::move(y)); // { dg-error "invalid 'static_cast'" "" { target { *-*-* } } 501 } - // { dg-error "Template argument must be constructible from an rvalue" "" { target { *-*-* } } 497 } + any_cast(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 +// . + +#include +#include +#include +#include + +void +test01() +{ + std::any a; + a.emplace(5); + VERIFY( std::any_cast(std::any_cast(a)) == 5 ); + + std::any b; + b.emplace({1}); + (void) std::any_cast>(std::any_cast(b)); +} + +void +test02() +{ + std::any p; + p.emplace>(1, 1); + auto pt = std::any_cast>(p); + VERIFY( std::any_cast(pt.first) == 1 ); + VERIFY( std::any_cast(pt.second) == 1 ); + + std::any t; + t.emplace>(1); + auto tt = std::any_cast>(t); + VERIFY( std::any_cast(std::get<0>(tt)) == 1 ); +} + +int main() +{ + test01(); + test02(); +} -- 2.30.2