From patchwork Wed Mar 15 22:21:04 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ville Voutilainen X-Patchwork-Id: 739455 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vk5fv0SMNz9s03 for ; Thu, 16 Mar 2017 09:21:25 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="okw0+fQC"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=v+tSZtOiCpPbS+iuHC/24nWd9DiOpPUiKp4zuiTPH0Q4rF qZvRZJjGAig83jVLOYrejnFdipLgB0CcO99RzOxIH3ee6OmDC8NVRrujqX6KC91R EXIwXB1HS28iSah9e3RX0zOXQvPG9ssjsFW6nqXArs0/Gf3V+oyQ9Om4qIJFo= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=JXLV8Kgr3XuzFnUp3yrQwN7rbCQ=; b=okw0+fQCCPfwZRZIkl4j pP2FuQnUAs/YPyVoCI3+NVPWPN8bfxPmU3UvAWuoMtf1IP11BEhOETEhH4ar4VAM K26RgLmXEaLO7XBEF3B8Vss+fazfvaynFBhXzCzaeGESH698e3Q3PCadBftg5XLd hi9pL0J0ilNFseBtZ3lPwNc= Received: (qmail 107076 invoked by alias); 15 Mar 2017 22:21:08 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 107007 invoked by uid 89); 15 Mar 2017 22:21:07 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.7 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy= X-Spam-User: qpsmtpd, 2 recipients X-HELO: mail-ot0-f173.google.com Received: from mail-ot0-f173.google.com (HELO mail-ot0-f173.google.com) (74.125.82.173) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 15 Mar 2017 22:21:06 +0000 Received: by mail-ot0-f173.google.com with SMTP id x37so35733652ota.2; Wed, 15 Mar 2017 15:21:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=Nw51UfHXYG44EM7PwoD0Fbly/f5zCafliuwO/yae6Zo=; b=DfjvWZGGV/TCyXrBBXWixkhFMJjFxqaw7RPG0Jnnr8Sdo4UPAGrRyfLoYtSsXVHPRR FfxZs//fAX782GxrMRabxBG2Yfxr8guSBaTK1bcqpCF4Ff8wheMd/wRu5zKrSyuQi18D 6ZruZ4Kj5NOg7XZouFjhZa6jfbnZkTpH4Lx80Ey5SwH+d5hVLgt0BzFAKo0VzCu4Rou3 STIGtjWR2BjjJapFSwoox2CqAne4Cb8B4ZYsOaZVk18ZttxOt5odlKvZjfWnUhA9vDDI PksFmo0ZxcVrt0aYMtGqPoEVffOO4Inwy82d0gESsBt0j3u7e73YfibRBW/koKXItnD1 Wk3A== X-Gm-Message-State: AFeK/H3LKsQm8x4xyJmNTnf7MjYwfb/bZJZnGUSsBzv/l9tSGMwOi9eupqUdlZhsCbem2WymIiT93kLXlqvBYg== X-Received: by 10.157.6.164 with SMTP id 33mr2730014otx.43.1489616465111; Wed, 15 Mar 2017 15:21:05 -0700 (PDT) MIME-Version: 1.0 Received: by 10.157.5.225 with HTTP; Wed, 15 Mar 2017 15:21:04 -0700 (PDT) From: Ville Voutilainen Date: Thu, 16 Mar 2017 00:21:04 +0200 Message-ID: Subject: [v3 PATCH] Implement LWG 2857, {variant, optional, any}::emplace should return the constructed value. To: "libstdc++" , "gcc-patches@gcc.gnu.org" Tested on Linux-x64. 2017-03-16 Ville Voutilainen Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value. * include/std/any (any_cast(any*)): Forward-declare. (emplace(_Args&&...)): Change the return type and return a reference to the constructed value. (emplace(initializer_list<_Up>, _Args&&...)): Likewise. * include/std/optional (emplace(_Args&&...)): Likewise. (emplace(initializer_list<_Up>, _Args&&...)): Likewise. * include/std/variant (emplace<_Tp>(_Args&&...)): Likewise. (emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise. (emplace<_Np>(_Args&&...)): Likewise. (emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise. * testsuite/20_util/any/assign/emplace.cc: Add tests for checking the return value of emplace. * testsuite/20_util/any/misc/any_cast_neg.cc: Adjust. * testsuite/20_util/optional/assignment/6.cc: Add tests for checking the return value of emplace. * testsuite/20_util/variant/run.cc: Likewise. diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any index e807617..fff13d9 100644 --- a/libstdc++-v3/include/std/any +++ b/libstdc++-v3/include/std/any @@ -74,6 +74,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * An @c any object's state is either empty or it stores a contained object * of CopyConstructible type. */ + class any; + template + inline _ValueType* any_cast(any* __any) noexcept; + class any { // Holds either pointer to a heap object or the contained object itself. @@ -268,18 +272,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Emplace with an object created from @p __args as the contained object. template - typename __any_constructible&, _Decay<_ValueType>, _Args&&...>::type emplace(_Args&&... __args) { __do_emplace<_Decay<_ValueType>> (std::forward<_Args>(__args)...); + return *(std::any_cast<_Decay<_ValueType>>(this)); } /// Emplace with an object created from @p __il and @p __args as /// the contained object. template - typename __any_constructible&, _Decay<_ValueType>, initializer_list<_Up>, _Args&&...>::type @@ -287,6 +292,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __do_emplace<_Decay<_ValueType>, _Up> (__il, std::forward<_Args>(__args)...); + return *(std::any_cast<_Decay<_ValueType>>(this)); } // modifiers diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 5e796ac..3f540ec 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -592,20 +592,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - enable_if_t::value> + enable_if_t::value, _Tp&> emplace(_Args&&... __args) { this->_M_reset(); this->_M_construct(std::forward<_Args>(__args)...); + return this->_M_get(); } template enable_if_t&, - _Args&&...>::value> + _Args&&...>::value, _Tp&> emplace(initializer_list<_Up> __il, _Args&&... __args) { this->_M_reset(); this->_M_construct(__il, std::forward<_Args>(__args)...); + return this->_M_get(); } // Destructor is implicit, implemented in _Optional_base. diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 46d7b92..58bf8c7 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1007,25 +1007,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - enable_if_t && __exactly_once<_Tp>> + enable_if_t && __exactly_once<_Tp>, + _Tp&> emplace(_Args&&... __args) { - this->emplace<__index_of<_Tp>>(std::forward<_Args>(__args)...); + auto& ret = + this->emplace<__index_of<_Tp>>(std::forward<_Args>(__args)...); __glibcxx_assert(holds_alternative<_Tp>(*this)); + return ret; } template enable_if_t&, _Args...> - && __exactly_once<_Tp>> + && __exactly_once<_Tp>, + _Tp&> emplace(initializer_list<_Up> __il, _Args&&... __args) { - this->emplace<__index_of<_Tp>>(__il, std::forward<_Args>(__args)...); + auto& ret = + this->emplace<__index_of<_Tp>>(__il, + std::forward<_Args>(__args)...); __glibcxx_assert(holds_alternative<_Tp>(*this)); + return ret; } template enable_if_t, - _Args...>> + _Args...>, + variant_alternative_t<_Np, variant>&> emplace(_Args&&... __args) { static_assert(_Np < sizeof...(_Types), @@ -1042,11 +1050,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __throw_exception_again; } __glibcxx_assert(index() == _Np); + return std::get<_Np>(*this); } template enable_if_t, - initializer_list<_Up>&, _Args...>> + initializer_list<_Up>&, _Args...>, + variant_alternative_t<_Np, variant>&> emplace(initializer_list<_Up> __il, _Args&&... __args) { static_assert(_Np < sizeof...(_Types), @@ -1063,6 +1073,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __throw_exception_again; } __glibcxx_assert(index() == _Np); + return std::get<_Np>(*this); } constexpr bool valueless_by_exception() const noexcept diff --git a/libstdc++-v3/testsuite/20_util/any/assign/emplace.cc b/libstdc++-v3/testsuite/20_util/any/assign/emplace.cc index 07cbdde..119104b 100644 --- a/libstdc++-v3/testsuite/20_util/any/assign/emplace.cc +++ b/libstdc++-v3/testsuite/20_util/any/assign/emplace.cc @@ -72,4 +72,8 @@ int main() std::any o10; o10.emplace(nullptr); VERIFY(o9.type() == o10.type()); + std::any o11; + VERIFY(&o11.emplace(42) == &std::any_cast(o11)); + VERIFY(&o11.emplace>({1,2,3}) == + &std::any_cast&>(o11)); } 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 61f0bc4..2d2b3d3 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 @@ -26,5 +26,5 @@ void test01() using std::any_cast; const any y(1); - any_cast(y); // { dg-error "invalid static_cast" "" { target { *-*-* } } 455 } + any_cast(y); // { dg-error "invalid static_cast" "" { target { *-*-* } } 461 } } diff --git a/libstdc++-v3/testsuite/20_util/optional/assignment/6.cc b/libstdc++-v3/testsuite/20_util/optional/assignment/6.cc index 4d754c1..40a537a 100644 --- a/libstdc++-v3/testsuite/20_util/optional/assignment/6.cc +++ b/libstdc++-v3/testsuite/20_util/optional/assignment/6.cc @@ -76,6 +76,11 @@ int main() o.emplace({ 'a' }, ""); VERIFY( o && o->state == 2 ); } + { + O o; + VERIFY(&o.emplace(0) == &*o); + VERIFY(&o.emplace({ 'a' }, "") == &*o); + } static_assert( !std::is_constructible, int>(), "" ); diff --git a/libstdc++-v3/testsuite/20_util/variant/run.cc b/libstdc++-v3/testsuite/20_util/variant/run.cc index db4529e..c6c2bc9 100644 --- a/libstdc++-v3/testsuite/20_util/variant/run.cc +++ b/libstdc++-v3/testsuite/20_util/variant/run.cc @@ -189,6 +189,15 @@ void emplace() try { v.emplace<1>(AlwaysThrow{}); } catch (nullptr_t) { } VERIFY(v.valueless_by_exception()); } + VERIFY(&v.emplace<0>(1) == &std::get<0>(v)); + VERIFY(&v.emplace(1) == &std::get(v)); + VERIFY(&v.emplace<1>("a") == &std::get<1>(v)); + VERIFY(&v.emplace("a") == &std::get(v)); + { + variant> v; + VERIFY(&v.emplace<0>({1,2,3}) == &std::get<0>(v)); + VERIFY(&v.emplace>({1,2,3}) == &std::get>(v)); + } } void test_get()