From patchwork Thu May 23 13:39:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1104134 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-501546-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="bBun+ryO"; dkim-atps=neutral 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 458rFx41FPz9s4V for ; Thu, 23 May 2019 23:39:33 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=lyxCPJaRBKkpTkErG0nIDrnkVYBgC7ruV1dn/3PozVkIukBiyoffb LVDMn170HKxkpjkCfICzvTvl6NGTvGxpLne3LZIyB7peht1vXcwIAqgASrPtFl3v Am1JaaPZSP9g6PyK65wyNEQVfQjQA060JNpFIb7JP40+RYRS3jtc90= 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:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=jJ2wify4NhO8zNk9ntoEZbfDFJU=; b=bBun+ryOefEsKnFgmEQH oRNZfvufEMYtZY8+mkPTaV/fKD3JcNLio4tj78rNfTQXx2aH9sYh2yMoqTosajR/ xkuhFH184gfA56u0QpA+Xn427X+6iGooaJ99FFfQCEL/juR03c7FwFqvmCFXIgCe Pd7v2oi8+w0q8DPcv3TG1y8= Received: (qmail 68394 invoked by alias); 23 May 2019 13:39:18 -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 68376 invoked by uid 89); 23 May 2019 13:39:18 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 23 May 2019 13:39:17 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id F2AE6859FF; Thu, 23 May 2019 13:39:10 +0000 (UTC) Received: from localhost (unknown [10.33.36.15]) by smtp.corp.redhat.com (Postfix) with ESMTP id A2C6E6090E; Thu, 23 May 2019 13:39:10 +0000 (UTC) Date: Thu, 23 May 2019 14:39:09 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/90220 fix experimental::any_cast for non-object types Message-ID: <20190523133909.GA11223@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.11.3 (2019-02-01) This corresponds to the fixes done for std::any_cast, but has to be done without if-constexpr. The dummy specialization of _Manager_internal<_Op> is used to avoid instantiating the real _Manager_internal::_S_manage function just to compare its address. PR libstdc++/90220 * include/experimental/any (__any_caster): Constrain to only be callable for object types. Use remove_cv_t instead of decay_t. If the type decays or isn't copy constructible, compare the manager function to a dummy specialization. (__any_caster): Add overload constrained for non-object types. (any::_Manager_internal<_Op>): Add dummy specialization. * testsuite/experimental/any/misc/any_cast.cc: Test function types and array types. Tested powerpc64le-linux, committed to trunk. commit a05a99ecd0ef3a2d187f1f14a7ef2ed7de0cd7a5 Author: Jonathan Wakely Date: Thu May 23 14:19:04 2019 +0100 PR libstdc++/90220 fix experimental::any_cast for non-object types This corresponds to the fixes done for std::any_cast, but has to be done without if-constexpr. The dummy specialization of _Manager_internal<_Op> is used to avoid instantiating the real _Manager_internal::_S_manage function just to compare its address. PR libstdc++/90220 * include/experimental/any (__any_caster): Constrain to only be callable for object types. Use remove_cv_t instead of decay_t. If the type decays or isn't copy constructible, compare the manager function to a dummy specialization. (__any_caster): Add overload constrained for non-object types. (any::_Manager_internal<_Op>): Add dummy specialization. * testsuite/experimental/any/misc/any_cast.cc: Test function types and array types. diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index a6e0fc683d9..f1d4bbf788c 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -303,7 +303,8 @@ inline namespace fundamentals_v1 _Storage _M_storage; template - friend void* __any_caster(const any* __any); + friend enable_if_t::value, void*> + __any_caster(const any* __any); // Manage in-place contained object. template @@ -415,17 +416,34 @@ inline namespace fundamentals_v1 /// @cond undocumented template - void* __any_caster(const any* __any) + enable_if_t::value, void*> + __any_caster(const any* __any) { - struct _None { }; - using _Up = decay_t<_Tp>; - using _Vp = conditional_t::value, _Up, _None>; + // any_cast returns non-null if __any->type() == typeid(T) and + // typeid(T) ignores cv-qualifiers so remove them: + using _Up = remove_cv_t<_Tp>; + // The contained value has a decayed type, so if decay_t is not U, + // then it's not possible to have a contained value of type U. + using __does_not_decay = is_same, _Up>; + // Only copy constructible types can be used for contained values. + using __is_copyable = is_copy_constructible<_Up>; + // If the type _Tp could never be stored in an any we don't want to + // instantiate _Manager<_Tp>, so use _Manager instead, which + // is explicitly specialized and has a no-op _S_manage function. + using _Vp = conditional_t<__and_<__does_not_decay, __is_copyable>::value, + _Up, any::_Op>; if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage) return nullptr; any::_Arg __arg; __any->_M_manager(any::_Op_access, __any, &__arg); return __arg._M_obj; } + + // This overload exists so that std::any_cast(a) is well-formed. + template + enable_if_t::value, _Tp*> + __any_caster(const any*) noexcept + { return nullptr; } /// @endcond /** @@ -522,6 +540,14 @@ inline namespace fundamentals_v1 } } + // Dummy specialization used by __any_caster. + template<> + struct any::_Manager_internal + { + static void + _S_manage(_Op, const any*, _Arg*) { } + }; + // @} group any } // namespace fundamentals_v1 } // namespace experimental diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc index 1875d345c5e..be1e86e8c70 100644 --- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc @@ -24,6 +24,7 @@ using std::experimental::any; using std::experimental::any_cast; +using std::experimental::bad_any_cast; void test01() { @@ -56,7 +57,6 @@ void test01() void test02() { - using std::experimental::bad_any_cast; any x(1); auto p = any_cast(&x); VERIFY(p == nullptr); @@ -105,7 +105,7 @@ void test03() MoveDeleted&& md3 = any_cast(any(std::move(md))); } -void test04() +void test05() { // PR libstdc++/69321 struct noncopyable { @@ -117,10 +117,60 @@ void test04() VERIFY( p == nullptr ); } +void test06() +{ + // The contained value of a std::any is always an object type, + // but any_cast does not forbid checking for function types. + + any a(1); + void (*p1)() = any_cast(&a); + VERIFY( p1 == nullptr ); + int (*p2)(int) = any_cast(&a); + VERIFY( p2 == nullptr ); + int (*p3)() = any_cast(&const_cast(a)); + VERIFY( p3 == nullptr ); + + try { + any_cast(a); + VERIFY( false ); + } catch (const bad_any_cast&) { + } + + try { + any_cast(std::move(a)); + VERIFY( false ); + } catch (const bad_any_cast&) { + } + + try { + any_cast(const_cast(a)); + VERIFY( false ); + } catch (const bad_any_cast&) { + } +} + +void test07() +{ + int arr[3]; + any a(arr); + VERIFY( a.type() == typeid(int*) ); // contained value is decayed + + int (*p1)[3] = any_cast(&a); + VERIFY( a.type() != typeid(int[3]) ); // so any_cast should return nullptr + VERIFY( p1 == nullptr ); + int (*p2)[] = any_cast(&a); + VERIFY( a.type() != typeid(int[]) ); // so any_cast should return nullptr + VERIFY( p2 == nullptr ); + const int (*p3)[] = any_cast(&const_cast(a)); + VERIFY( p3 == nullptr ); +} + int main() { test01(); test02(); test03(); - test04(); + test05(); + test06(); + test07(); }