From patchwork Mon May 6 11:19:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Antony Polukhin X-Patchwork-Id: 1095796 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-500144-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="fBLVJg4V"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ueq1JW/5"; 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 44yKzC1Fllz9s00 for ; Mon, 6 May 2019 21:20:22 +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 :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=TJhffbE/j01RQ/Dx7lneqr3Y/qwOO4QD7QM13L6koli+QR CmEzUqqbpgtWn6ctNnlj5EAdDlRMhJ4YubSuiYPQF46vYUZGeiyWDrlKgeHC4x+x ImkLjwyyajdcXG73ePNIkoM5TQ9ApShMJpTdCO9ymid9SsALk3vX5rSFFftYA= 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=e4pL7zdI+RznPPWuyZhfi15cjlI=; b=fBLVJg4VLYHMiPh1CjVv AefTki5Qvdh0JKaS92550WicqdrjOXtvG1Pc0Ncb0rxkOK6D1eVdNL3RklhMqao9 3oBKp66+981O1pDqHtWO+6LWjoPwpHLeUmWdK07Qf9RFDakER7KXnbRf7mzEpbiP Z1TLKi8n9eY6ryjKwcIJRVo= Received: (qmail 32452 invoked by alias); 6 May 2019 11:20:14 -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 32102 invoked by uid 89); 6 May 2019 11:20:13 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.4 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=queries, type_traits, them!, __and_ X-HELO: mail-lf1-f67.google.com Received: from mail-lf1-f67.google.com (HELO mail-lf1-f67.google.com) (209.85.167.67) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 06 May 2019 11:20:08 +0000 Received: by mail-lf1-f67.google.com with SMTP id j20so8864965lfh.2; Mon, 06 May 2019 04:20:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=GqctzZQpKC3yTO2srV9qyc5LcfwzPCW7alLGsFgXPN0=; b=ueq1JW/530lGS2CySHEL93It5f4kfLhcStasONqi/9vPBLP01Xa71bpsD0FX+fG2vq hSZzCjnqNTGH7Rj3lzr4le4Egi9nJuTxY6KVnjHhVt3Btbj4akqPUZjsv+O1Fp/ChiGU j8RcsdgSuxzneez6m+0VYas7sk2zZFR9YLl+XwaES7NuNoEwnJmMTMYMF8ukspYLAxqT Cob/XpM4DHSMmTbMKNijal8inOtxwoJmXs585EmndNRtuYyz81eTgVcB4fG66wgEr1O3 NMHYkTlRbmqcJU27i+GEQ0QQrEUow3OVa+n3WCvJ6B+R5WsoqL9I7RUGQ3mnyZ6QpcOD 20Jw== MIME-Version: 1.0 From: Antony Polukhin Date: Mon, 6 May 2019 14:19:53 +0300 Message-ID: Subject: [PATCH] PR libstdc++/71579 assert that type traits are not misused with an incomplete type To: "libstdc++" , gcc-patches List This patch adds static asserts for type traits misuse with incomplete classes and unions. This gives a nice readable error message instead of an UB and odr-violations. Some features of the patch: * each type trait has it's own static_assert inside. This gives better diagnostics than the approach with putting the assert into a helper structure and using it in each trait. * the result of completeness check is not memorized by the compiler. This gives no false positive after the first failed check. * some of the compiler builtins already implement the check. But not all of them! So the asserts are in all the type_traits that may benefit from the check. This also makes the behavior of libstdc++ more consistent across different (non GCC) compilers. * std::is_base_of does not have the assert as it works well in many cases with incomplete types PR libstdc++/71579 * include/std/type_traits: Add static_asserts to make sure that type traits are not misused with an incomplete type. * testsuite/20_util/__is_complete_or_unbounded/memoization.cc: New test. * testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc: Likewise. * testsuite/20_util/__is_complete_or_unbounded/value.cc: Likewise. * testsuite/20_util/is_abstract/incomplete_neg.cc: Likewise. * testsuite/20_util/is_aggregate/incomplete_neg.cc: Likewise. * testsuite/20_util/is_class/value.cc: Likewise. * testsuite/20_util/is_function/value.cc: Likewise. * testsuite/20_util/is_move_constructible/incomplete_neg.cc: Likewise. * testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc: Likewise. * testsuite/20_util/is_polymorphic/incomplete_neg.cc: Likewise. * testsuite/20_util/is_reference/value.cc: Likewise. * testsuite/20_util/is_unbounded_array/value.cc: Likewise. * testsuite/20_util/is_union/value.cc: Likewise. * testsuite/20_util/is_void/value.cc: Likewise. * testsuite/util/testsuite_tr1.h: Add incomplete union type. diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 411eff1..3a0cf44 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,27 @@ +2019-05-06 Antony Polukhin + + PR libstdc++/71579 + * include/std/type_traits: Add static_asserts to make sure that + type traits are not misused with an incomplete type. + * testsuite/20_util/__is_complete_or_unbounded/memoization.cc: + New test. + * testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc: + Likewise. + * testsuite/20_util/__is_complete_or_unbounded/value.cc: Likewise. + * testsuite/20_util/is_abstract/incomplete_neg.cc: Likewise. + * testsuite/20_util/is_aggregate/incomplete_neg.cc: Likewise. + * testsuite/20_util/is_class/value.cc: Likewise. + * testsuite/20_util/is_function/value.cc: Likewise. + * testsuite/20_util/is_move_constructible/incomplete_neg.cc: Likewise. + * testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc: + Likewise. + * testsuite/20_util/is_polymorphic/incomplete_neg.cc: Likewise. + * testsuite/20_util/is_reference/value.cc: Likewise. + * testsuite/20_util/is_unbounded_array/value.cc: Likewise. + * testsuite/20_util/is_union/value.cc: Likewise. + * testsuite/20_util/is_void/value.cc: Likewise. + * testsuite/util/testsuite_tr1.h: Add incomplete union type. + 2019-05-06 François Dumont * python/libstdcxx/v6/printers.py (add_one_template_type_printer): diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 1d14c75..6fdb534 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -91,6 +91,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct conditional; + template + struct __type_identity { + using type = _Type; + }; + template struct __or_; @@ -177,6 +182,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // C++17 + // Forward declarations + template + struct is_reference; + template + struct is_function; + template + struct is_void; + template + struct __is_array_unknown_bounds; + + // Helper functions that return false_type for incomplete classes, + // incomplete unions and arrays of known bound from those. + + template + constexpr true_type __is_complete_or_unbounded(__type_identity<_T>) + { return {}; } + + template + constexpr typename __or_< + is_reference<_NestedType>, + is_function<_NestedType>, + is_void<_NestedType>, + __is_array_unknown_bounds<_NestedType> + >::type __is_complete_or_unbounded(_TypeIdentity) + { return {}; } + // For several sfinae-friendly trait implementations we transport both the // result information (as the member type) and the failure information (no // member type). This is very similar to std::enable_if, but we cannot use @@ -399,9 +431,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public true_type { }; template - struct is_function; - - template struct __is_member_object_pointer_helper : public false_type { }; @@ -671,44 +700,65 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_trivial : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; // is_trivially_copyable template struct is_trivially_copyable : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_standard_layout template struct is_standard_layout : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_pod // Could use is_standard_layout && is_trivial instead of the builtin. template struct is_pod : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_literal_type template struct is_literal_type : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_empty template struct is_empty : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_polymorphic template struct is_polymorphic : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; #if __cplusplus >= 201402L #define __cpp_lib_is_final 201402L @@ -716,14 +766,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_final : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; #endif /// is_abstract template struct is_abstract : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template::value> @@ -828,7 +884,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_destructible : public __is_destructible_safe<_Tp>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; // is_nothrow_destructible requires that is_destructible is // satisfied as well. We realize that by mimicing the @@ -876,7 +935,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_nothrow_destructible : public __is_nt_destructible_safe<_Tp>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; struct __do_is_default_constructible_impl { @@ -889,10 +951,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_default_constructible_impl - : public __do_is_default_constructible_impl - { - typedef decltype(__test<_Tp>(0)) type; - }; + : public decltype(__do_is_default_constructible_impl::__test<_Tp>(0)) + { }; template struct __is_default_constructible_atom @@ -924,14 +984,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_default_constructible : public __is_default_constructible_safe<_Tp>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_constructible - template - struct is_constructible + template + struct __is_constructible_impl : public __bool_constant<__is_constructible(_Tp, _Args...)> { }; + template + struct is_constructible + : public __is_constructible_impl<_Tp, _Args...> + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; + template::value> struct __is_copy_constructible_impl; @@ -941,14 +1012,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_copy_constructible_impl<_Tp, true> - : public is_constructible<_Tp, const _Tp&> + : public __is_constructible_impl<_Tp, const _Tp&> { }; /// is_copy_constructible template struct is_copy_constructible : public __is_copy_constructible_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template::value> struct __is_move_constructible_impl; @@ -959,14 +1033,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_move_constructible_impl<_Tp, true> - : public is_constructible<_Tp, _Tp&&> + : public __is_constructible_impl<_Tp, _Tp&&> { }; /// is_move_constructible template struct is_move_constructible : public __is_move_constructible_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template struct __is_nt_default_constructible_atom @@ -989,12 +1066,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; /// is_nothrow_default_constructible - template - struct is_nothrow_default_constructible - : public __and_, + template + struct __is_nothrow_default_constructible_impl + : public __and_<__is_default_constructible_safe<_Tp>, __is_nt_default_constructible_impl<_Tp>> { }; + template + struct is_nothrow_default_constructible + : public __is_nothrow_default_constructible_impl<_Tp> + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; + template struct __is_nt_constructible_impl : public integral_constant()...))> @@ -1008,16 +1093,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_nt_constructible_impl<_Tp> - : public is_nothrow_default_constructible<_Tp> + : public __is_nothrow_default_constructible_impl<_Tp> { }; /// is_nothrow_constructible template - struct is_nothrow_constructible - : public __and_, + struct __is_nothrow_constructible_impl + : public __and_<__is_constructible_impl<_Tp, _Args...>, __is_nt_constructible_impl<_Tp, _Args...>> { }; + template + struct is_nothrow_constructible + : public __is_nothrow_constructible_impl<_Tp, _Args...> + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; + template::value> struct __is_nothrow_copy_constructible_impl; @@ -1027,14 +1120,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_nothrow_copy_constructible_impl<_Tp, true> - : public is_nothrow_constructible<_Tp, const _Tp&> + : public __is_nothrow_constructible_impl<_Tp, const _Tp&> { }; /// is_nothrow_copy_constructible template struct is_nothrow_copy_constructible : public __is_nothrow_copy_constructible_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template::value> struct __is_nothrow_move_constructible_impl; @@ -1045,20 +1141,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_nothrow_move_constructible_impl<_Tp, true> - : public is_nothrow_constructible<_Tp, _Tp&&> + : public __is_nothrow_constructible_impl<_Tp, _Tp&&> { }; /// is_nothrow_move_constructible template struct is_nothrow_move_constructible : public __is_nothrow_move_constructible_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_assignable template struct is_assignable : public __bool_constant<__is_assignable(_Tp, _Up)> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template::value> struct __is_copy_assignable_impl; @@ -1069,14 +1171,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_copy_assignable_impl<_Tp, true> - : public is_assignable<_Tp&, const _Tp&> + : public __bool_constant<__is_assignable(_Tp&, const _Tp&)> { }; /// is_copy_assignable template struct is_copy_assignable : public __is_copy_assignable_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template::value> struct __is_move_assignable_impl; @@ -1087,14 +1192,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_move_assignable_impl<_Tp, true> - : public is_assignable<_Tp&, _Tp&&> + : public __bool_constant<__is_assignable(_Tp&, _Tp&&)> { }; /// is_move_assignable template struct is_move_assignable : public __is_move_assignable_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template struct __is_nt_assignable_impl @@ -1102,12 +1210,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; /// is_nothrow_assignable - template - struct is_nothrow_assignable - : public __and_, + template + struct __is_nothrow_assignable_impl + : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>, __is_nt_assignable_impl<_Tp, _Up>> { }; + template + struct is_nothrow_assignable + : public __is_nothrow_assignable_impl<_Tp, _Up> + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; + template::value> struct __is_nt_copy_assignable_impl; @@ -1117,14 +1233,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_nt_copy_assignable_impl<_Tp, true> - : public is_nothrow_assignable<_Tp&, const _Tp&> + : public __is_nothrow_assignable_impl<_Tp&, const _Tp&> { }; /// is_nothrow_copy_assignable template struct is_nothrow_copy_assignable : public __is_nt_copy_assignable_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template::value> struct __is_nt_move_assignable_impl; @@ -1135,26 +1254,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_nt_move_assignable_impl<_Tp, true> - : public is_nothrow_assignable<_Tp&, _Tp&&> + : public __is_nothrow_assignable_impl<_Tp&, _Tp&&> { }; /// is_nothrow_move_assignable template struct is_nothrow_move_assignable : public __is_nt_move_assignable_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_constructible template struct is_trivially_constructible : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_default_constructible template struct is_trivially_default_constructible - : public is_trivially_constructible<_Tp>::type - { }; + : public __bool_constant<__is_trivially_constructible(_Tp)> + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; struct __do_is_implicitly_default_constructible_impl { @@ -1182,7 +1310,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_implicitly_default_constructible - : public __and_, + : public __and_<__is_default_constructible_safe<_Tp>, __is_implicitly_default_constructible_safe<_Tp>> { }; @@ -1197,7 +1325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_trivially_copy_constructible_impl<_Tp, true> - : public __and_, + : public __and_<__is_copy_constructible_impl<_Tp>, integral_constant> { }; @@ -1205,7 +1333,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_trivially_copy_constructible : public __is_trivially_copy_constructible_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_move_constructible @@ -1218,7 +1349,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __is_trivially_move_constructible_impl<_Tp, true> - : public __and_, + : public __and_<__is_move_constructible_impl<_Tp>, integral_constant> { }; @@ -1226,13 +1357,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_trivially_move_constructible : public __is_trivially_move_constructible_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_assignable template struct is_trivially_assignable : public __bool_constant<__is_trivially_assignable(_Tp, _Up)> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_copy_assignable @@ -1251,7 +1388,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_trivially_copy_assignable : public __is_trivially_copy_assignable_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_move_assignable @@ -1270,21 +1410,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_trivially_move_assignable : public __is_trivially_move_assignable_impl<_Tp> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_trivially_destructible template struct is_trivially_destructible - : public __and_, + : public __and_<__is_destructible_safe<_Tp>, __bool_constant<__has_trivial_destructor(_Tp)>> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// has_virtual_destructor template struct has_virtual_destructor : public integral_constant - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; // type property queries. @@ -1292,7 +1441,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// alignment_of template struct alignment_of - : public integral_constant { }; + : public integral_constant + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// rank template @@ -2596,13 +2749,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_swappable : public __is_swappable_impl<_Tp>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_nothrow_swappable template struct is_nothrow_swappable : public __is_nothrow_swappable_impl<_Tp>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; #if __cplusplus >= 201402L /// is_swappable_v @@ -2793,20 +2952,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct is_invocable : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), + "_Fn must be a complete class or an unbounded array"); + }; /// std::is_invocable_r template struct is_invocable_r : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), + "_Fn must be a complete class or an unbounded array"); + }; /// std::is_nothrow_invocable template struct is_nothrow_invocable : __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>, - __call_is_nothrow_<_Fn, _ArgTypes...>>::type - { }; + __call_is_nothrow_<_Fn, _ArgTypes...>>::type + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), + "_Fn must be a complete class or an unbounded array"); + }; template struct __is_nt_invocable_impl : false_type { }; @@ -3013,7 +3181,10 @@ template : bool_constant<__has_unique_object_representations( remove_cv_t> )> - { }; + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; template inline constexpr bool has_unique_object_representations_v @@ -3025,7 +3196,11 @@ template /// is_aggregate template struct is_aggregate - : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> { }; + : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> + { + static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), + "template argument must be a complete class or an unbounded array"); + }; /// is_aggregate_v template @@ -3084,7 +3259,7 @@ template : public __is_array_known_bounds<_Tp> { }; - /// True for a type that is an array of unknown bound. + /// True for a type that is an unbounded array. template struct is_unbounded_array : public __is_array_unknown_bounds<_Tp> diff --git a/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization.cc b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization.cc new file mode 100644 index 0000000..83afb40 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization.cc @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } + +// 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 +// . + +#include + +struct X; +static_assert( + !std::__is_complete_or_unbounded(std::__type_identity{}), "error"); + +struct X{}; +static_assert( + std::__is_complete_or_unbounded(std::__type_identity{}), + "Result memoized. This leads to worse diagnostics"); diff --git a/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc new file mode 100644 index 0000000..04b83a2 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/memoization_neg.cc @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } +// { dg-prune-output "must be a complete" } + +// 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 +// . + +#include + +struct X; +constexpr bool res_incomplete = std::is_move_constructible::value; // { dg-error "required from here" } + +struct X{}; +constexpr bool res_complete = std::is_default_constructible::value; // { dg-bogus "required from here" } diff --git a/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/value.cc b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/value.cc new file mode 100644 index 0000000..5a03ad6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/__is_complete_or_unbounded/value.cc @@ -0,0 +1,100 @@ +// { dg-do compile { target c++11 } } + +// 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 +// . + +#include + + +struct incomplete_type; +class incomplete_type2; +union incomplete_union; +enum class incomplete_enum: int; +enum incomplete_enum2: int; +static_assert(!std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(!std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(!std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(!std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(!std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(!std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + + +struct complete_type{ ~complete_type() = delete; }; +class complete_type2{ int i; }; +union complete_union{}; +enum class complete_enum: int {}; +enum complete_enum2: int {}; +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); + +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity{}), ""); diff --git a/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc new file mode 100644 index 0000000..94f4ecd --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_abstract/incomplete_neg.cc @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } +// { dg-prune-output "invalid use of incomplete type" } +// { dg-prune-output "must be a complete" } +// +// 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 +// . + +#include + +class X; + +void test01() +{ + std::is_abstract(); // { dg-error "required from here" } +} diff --git a/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc new file mode 100644 index 0000000..8a3dd55 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_aggregate/incomplete_neg.cc @@ -0,0 +1,29 @@ +// { dg-do compile { target c++17 } } +// +// 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 +// . + +// { dg-error "must be a complete class" "" { target *-*-* } 0 } + +#include + +class X; + +void test01() +{ + std::is_aggregate(); // { dg-error "required from here" } +} diff --git a/libstdc++-v3/testsuite/20_util/is_class/value.cc b/libstdc++-v3/testsuite/20_util/is_class/value.cc index 6391e28..801dc67 100644 --- a/libstdc++-v3/testsuite/20_util/is_class/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_class/value.cc @@ -27,6 +27,7 @@ void test01() // Positive tests. static_assert(test_category(true), ""); + static_assert(test_category(true), ""); static_assert(test_category(true), ""); static_assert(test_category(true), ""); static_assert(test_category(true), ""); @@ -47,4 +48,5 @@ void test01() static_assert(test_category(false), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); + static_assert(test_category(false), ""); } diff --git a/libstdc++-v3/testsuite/20_util/is_function/value.cc b/libstdc++-v3/testsuite/20_util/is_function/value.cc index cef2e3d..7b94b58 100644 --- a/libstdc++-v3/testsuite/20_util/is_function/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_function/value.cc @@ -46,4 +46,6 @@ void test01() // Sanity check. static_assert(test_category(false), ""); + static_assert(test_category(false), ""); + static_assert(test_category(false), ""); } diff --git a/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc new file mode 100644 index 0000000..d6a08d7 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } +// +// 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 +// . + +// { dg-error "must be a complete class" "" { target *-*-* } 0 } + +#include + +class X; + +void test01() +{ + std::is_move_constructible(); // { dg-error "required from here" } +} diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc new file mode 100644 index 0000000..ebceec5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_move_assignable/incomplete_neg.cc @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } +// +// 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 +// . + +// { dg-error "must be a complete class" "" { target *-*-* } 0 } + +#include + +class X; + +void test01() +{ + std::is_nothrow_move_assignable(); // { dg-error "required from here" } +} diff --git a/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc new file mode 100644 index 0000000..8cd1b40 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_polymorphic/incomplete_neg.cc @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } +// { dg-prune-output "invalid use of incomplete type" } +// { dg-prune-output "must be a complete" } +// +// 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 +// . + +#include + +class X; + +void test01() +{ + std::is_polymorphic(); // { dg-error "required from here" } +} diff --git a/libstdc++-v3/testsuite/20_util/is_reference/value.cc b/libstdc++-v3/testsuite/20_util/is_reference/value.cc index 79a9973..4676894 100644 --- a/libstdc++-v3/testsuite/20_util/is_reference/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_reference/value.cc @@ -33,8 +33,11 @@ void test01() static_assert(test_category(true), ""); static_assert(test_category(true), ""); static_assert(test_category(true), ""); + static_assert(test_category(true), ""); + static_assert(test_category(true), ""); // Sanity check. static_assert(test_category(false), ""); + static_assert(test_category(false), ""); } diff --git a/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc b/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc index 19fb052..bca0e3c 100644 --- a/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_unbounded_array/value.cc @@ -44,6 +44,8 @@ void test01() static_assert(test_category(true), ""); static_assert(test_category(false), ""); static_assert(test_category(true), ""); + static_assert(test_category(false), ""); + static_assert(test_category(true), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); @@ -51,6 +53,8 @@ void test01() // Sanity check. static_assert(test_category(false), ""); + static_assert(test_category(false), ""); + static_assert(test_category(false), ""); } template void pos() diff --git a/libstdc++-v3/testsuite/20_util/is_union/value.cc b/libstdc++-v3/testsuite/20_util/is_union/value.cc index 7d0f201..54df151 100644 --- a/libstdc++-v3/testsuite/20_util/is_union/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_union/value.cc @@ -27,6 +27,7 @@ void test01() // Positive tests. static_assert(test_category(true), ""); + static_assert(test_category(true), ""); // Negative tests. static_assert(test_category(false), ""); @@ -47,4 +48,5 @@ void test01() static_assert(test_category(false), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); + static_assert(test_category(false), ""); } diff --git a/libstdc++-v3/testsuite/20_util/is_void/value.cc b/libstdc++-v3/testsuite/20_util/is_void/value.cc index f04cdd6..dc116f7 100644 --- a/libstdc++-v3/testsuite/20_util/is_void/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_void/value.cc @@ -47,4 +47,6 @@ void test01() // Sanity check. static_assert(test_category(false), ""); + static_assert(test_category(false), ""); + static_assert(test_category(false), ""); } diff --git a/libstdc++-v3/testsuite/util/testsuite_tr1.h b/libstdc++-v3/testsuite/util/testsuite_tr1.h index b431682..2e1cbb0 100644 --- a/libstdc++-v3/testsuite/util/testsuite_tr1.h +++ b/libstdc++-v3/testsuite/util/testsuite_tr1.h @@ -126,6 +126,8 @@ namespace __gnu_test union UnionType { }; + union IncompleteUnion; + class IncompleteClass; struct ExplicitClass