From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 4D9773858C74 for ; Thu, 8 Sep 2022 16:13:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4D9773858C74 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662653583; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IXHPmuMiaQtpDL/pooNUEcLcgF9gCCed+5jYKF8SgLg=; b=PZX62OU068GybURv4sBDVkI6L7cxbnPQ1dYhkvDhO63qVHw1WICE70IU7y4v0amFEWHOD4 l18X1AOUQp9pHihQuhFi4EMeqt8lDuAxLt/qerLHrQlDOdqsnQB/kH/auuVy+lvCF+OPnq p8A71Sgkce4pitShpXnCrYQ4yJb4KOU= Received: from mail-qv1-f72.google.com (mail-qv1-f72.google.com [209.85.219.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-588-82RVMmCzPy6mxUHIjXRDyg-1; Thu, 08 Sep 2022 12:12:31 -0400 X-MC-Unique: 82RVMmCzPy6mxUHIjXRDyg-1 Received: by mail-qv1-f72.google.com with SMTP id i10-20020ad45c6a000000b004a25d0fea96so9421771qvh.3 for ; Thu, 08 Sep 2022 09:12:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date; bh=IXHPmuMiaQtpDL/pooNUEcLcgF9gCCed+5jYKF8SgLg=; b=4vpsxuQgj41L3ojmQVR3JxjxgbPqWpsbhLwJ6xIl6xZ4QY0Ootys29Fkr+faRY0vZ3 QqtQTLo2z8B8ORkarvGw/00dtBUszXW6UnbvviIBjw10CVxBY+FztL5MrTzchDRzXU9v wjsPPLZiez+r5hUEl0yQD4OCpSm5DGN3za5ny8Bhd74AJKVgMT8uFo/zMUyqqvCzCOWk WnC6AofDBlJVn3GsdgBJ4LciQTRWDtDmfBWDNKwDUCIZoxAJ9JN5iegS9kH6K3MpuDlH G3vaT9apq/w7qhdJLadKUiZjx725MI+kQHm9JNFuleLFcZaILyWer5XpuEPk/42QF30G tnOg== X-Gm-Message-State: ACgBeo3qhU/Dkj0x/nNhxfypdSiyM/mXmuJxYunk+/2cYOMbSweoutgx Be0QKUVbrCGtS6yM/j57pFlKA6f4vw2fII3IqUlt4A2fufw0lXoDFw5nrMd0hBgEf2sxDVsG1mL LfPExDB7q/IHsV18= X-Received: by 2002:ac8:7c4e:0:b0:344:7101:9455 with SMTP id o14-20020ac87c4e000000b0034471019455mr8674434qtv.182.1662653550059; Thu, 08 Sep 2022 09:12:30 -0700 (PDT) X-Google-Smtp-Source: AA6agR4/IRmt4eyuUoQI7lZO6UilKDti4hDf2EVKw4KhjTnsJu8w2+TYhx+mTpqoheE0gKXhT764og== X-Received: by 2002:ac8:7c4e:0:b0:344:7101:9455 with SMTP id o14-20020ac87c4e000000b0034471019455mr8674380qtv.182.1662653549442; Thu, 08 Sep 2022 09:12:29 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id z20-20020ac87cb4000000b0031f36cd1958sm14272451qtv.81.2022.09.08.09.12.28 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 08 Sep 2022 09:12:28 -0700 (PDT) Message-ID: <65658c39-e0fb-6ad3-9136-fac36d763f4a@redhat.com> Date: Thu, 8 Sep 2022 12:12:27 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.0 Subject: Re: [PATCH v2] c++: Fix type completeness checks for type traits [PR106838] To: Jonathan Wakely , gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org References: <20220908125606.3272086-1-jwakely@redhat.com> From: Jason Merrill In-Reply-To: <20220908125606.3272086-1-jwakely@redhat.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-14.5 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,NICE_REPLY_A,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 9/8/22 08:56, Jonathan Wakely wrote: > On Wed, 7 Sept 2022 at 16:11, Jason Merrill wrote: >> >> On 9/7/22 08:18, Jonathan Wakely wrote: >>> @@ -12080,23 +12098,37 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) >>> case CPTK_HAS_TRIVIAL_COPY: >>> case CPTK_HAS_TRIVIAL_DESTRUCTOR: >>> case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: >>> - case CPTK_HAS_VIRTUAL_DESTRUCTOR: >>> - case CPTK_IS_ABSTRACT: >>> + if (!check_trait_type (type1)) >>> + return error_mark_node; >>> + break; >>> + >>> case CPTK_IS_AGGREGATE: >> >> Hmm, why does std::is_aggregate require a complete array element type? >> An array is an aggregate regardless of its element type. I'd think it >> should be kind 4 instead. > > That makes sense. It doesn't match the precondition for the library > trait in the standard, but violating that library precondition is > undefined, not ill-formed, so it seems harmless for libstdc++ to also > relax that precondition and allow arrays of incomplete type. > >> >>> - case CPTK_IS_EMPTY: >>> - case CPTK_IS_FINAL: >>> case CPTK_IS_LITERAL_TYPE: >>> case CPTK_IS_POD: >>> - case CPTK_IS_POLYMORPHIC: >>> case CPTK_IS_STD_LAYOUT: >>> case CPTK_IS_TRIVIAL: >>> case CPTK_IS_TRIVIALLY_COPYABLE: >>> - if (!check_trait_type (type1)) >>> + if (!check_trait_type (type1, /* kind = */ 2)) >>> + return error_mark_node; >>> + break; >>> + >>> + case CPTK_IS_EMPTY: >> >> I also wonder why std::is_empty excludes unions, since there can now be >> an empty field of union type with the addition of [[no_unique_address]]? > > True, although the main purpose of is_empty is to decide whether to > derive from it to get the EBO. With [[no_unique_address]] there's no > reason to do that, you can just add the attribute unconditionally and if > it's not empty, the attribute is a no-op. So I find it hard to care > about this case :-) > > If the FE trait requires unions to be complete, then the library trait > would need to special-case unions to not use the FE trait, so that it > can still give the same answer (i.e. false) for incomplete union types. > I don't think changing this one has any advantage. > >> >>> + case CPTK_IS_POLYMORPHIC: >>> + case CPTK_IS_ABSTRACT: >>> + case CPTK_HAS_VIRTUAL_DESTRUCTOR: >>> + if (!check_trait_type (type1, /* kind = */ 3)) >>> + return error_mark_node; >>> + break; >>> + >>> + case CPTK_IS_FINAL: >> >> And I wonder a bit why std::is_final cares about the completeness of >> unions, which can't be (or have) base classes, but I guess you can still >> ask about whether the keyword was present, even though it has no effect. > > Yes, as currently specified, it tells you whether the specifier was > present, nothing more. > > Thanks for the review, here's an updated patch that moves __is_aggregate > to kind 4. I didn't change __is_empty or __is_final though, did you want > those changed? > > Tested x86_64-linux. That's fine, the patch is OK with the typo fix below: > -- >8 -- > > The check_trait_type function is used for a number of different type > traits that have different requirements on their arguments. For example, > __is_constructible allows arrays of unknown bound even if the array > element is an incomplete type, but __is_aggregate does not, it always > requires the array element type to be complete. Other traits have > different requirements again, e.g. __is_empty allows incomplete unions, > and arrays (of known or unknown bound) of incomplete types. > > This alters the check_trait_type function to take an additional KIND > parameter which indicates which set of type trait requirements to check. > > As noted in a comment, the requirements for __is_aggregate deviate from > the ones for std::is_aggregate in the standard. It's not necessary for > the elements of an array to be complete types, because arrays are always > aggregates. > > The type_has_virtual_destructor change is needed to avoid an ICE. > Previously it could never be called for incomplete union types as they > were (incorrectly) rejected by check_trait_type. > > This change causes some additional diagnostics in some libstdc++ tests, > where the front end was not previously complaining about invalid types > that the library assertions diagnosed. We should consider removing the > library assertions from traits where the front end implements the > correct checks now. > > PR c++/106838 > > gcc/cp/ChangeLog: > > * class.cc (type_has_virtual_destructor): Return false for > union types. > * semantics.cc (check_trait_type): Add KIND parameter to support > different sets of requirements. > (finish_trait_expr): Pass KIND argument for relevant traits. > > gcc/ChangeLog: > > * doc/extend.texi (Type Traits): Fix requirements. Document > __is_aggregate and __is_final. > > gcc/testsuite/ChangeLog: > > * g++.dg/ext/array4.C: Fix invalid use of __is_constructible. > * g++.dg/ext/unary_trait_incomplete.C: Fix tests for traits with > different requirements. > > libstdc++-v3/ChangeLog: > > * testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc: > Prune additional errors from front-end. > * testsuite/20_util/is_move_constructible/incomplete_neg.cc: > Likewise. > * testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc: > Likewise. > * testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc: > Likewise. > * testsuite/20_util/is_swappable_with/incomplete_neg.cc: > Likewise. > --- > gcc/cp/class.cc | 2 +- > gcc/cp/semantics.cc | 58 +++++++-- > gcc/doc/extend.texi | 30 +++-- > gcc/testsuite/g++.dg/ext/array4.C | 3 +- > .../g++.dg/ext/unary_trait_incomplete.C | 116 ++++++++++++++---- > .../memoization_neg.cc | 2 + > .../is_move_constructible/incomplete_neg.cc | 1 + > .../is_nothrow_swappable/incomplete_neg.cc | 1 + > .../incomplete_neg.cc | 1 + > .../is_swappable_with/incomplete_neg.cc | 1 + > 10 files changed, 164 insertions(+), 51 deletions(-) > > diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc > index a12d3673b96..b84f4227e7e 100644 > --- a/gcc/cp/class.cc > +++ b/gcc/cp/class.cc > @@ -5620,7 +5620,7 @@ type_has_virtual_destructor (tree type) > { > tree dtor; > > - if (!CLASS_TYPE_P (type)) > + if (!NON_UNION_CLASS_TYPE_P (type)) > return false; > > gcc_assert (COMPLETE_TYPE_P (type)); > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index 3d58d67ec11..aa3bfc457c1 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -12028,11 +12028,23 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) > } > } > > -/* If TYPE is an array of unknown bound, or (possibly cv-qualified) > - void, or a complete type, returns true, otherwise false. */ > +/* Returns true if TYPE meets the requirements for the specified KIND, > + false otherwise. > + > + When KIND == 1, TYPE must be an array of unknown bound, > + or (possibly cv-qualified) void, or a complete type. > + > + When KIND == 2, TYPE must be a complete type, or array of complete type, > + or (possibly cv-qualified) void. > + > + When KIND == 3: > + If TYPE is a non-union class type, it must be complete. > + > + When KIND == 4: > + If TYPE is a class type, it must be complete. */ > > static bool > -check_trait_type (tree type) > +check_trait_type (tree type, int kind = 1) > { > if (type == NULL_TREE) > return true; > @@ -12041,8 +12053,14 @@ check_trait_type (tree type) > return (check_trait_type (TREE_VALUE (type)) > && check_trait_type (TREE_CHAIN (type))); > > - if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)) > - return true; > + if (kind == 1 && TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)) > + return true; // Array of unknown bound. Don't care about completeness. > + > + if (kind == 3 && !NON_UNION_CLASS_TYPE_P (type)) > + return true; // Not a non-union class type. Don't care about completeness. > + > + if (kind == 4 && TREE_CODE (type) == ARRAY_TYPE) > + return true; // Not a class type. Don't care about completeness. > > if (VOID_TYPE_P (type)) > return true; > @@ -12080,23 +12098,39 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) > case CPTK_HAS_TRIVIAL_COPY: > case CPTK_HAS_TRIVIAL_DESTRUCTOR: > case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: > - case CPTK_HAS_VIRTUAL_DESTRUCTOR: > - case CPTK_IS_ABSTRACT: > - case CPTK_IS_AGGREGATE: > - case CPTK_IS_EMPTY: > - case CPTK_IS_FINAL: > + if (!check_trait_type (type1)) > + return error_mark_node; > + break; > + > case CPTK_IS_LITERAL_TYPE: > case CPTK_IS_POD: > - case CPTK_IS_POLYMORPHIC: > case CPTK_IS_STD_LAYOUT: > case CPTK_IS_TRIVIAL: > case CPTK_IS_TRIVIALLY_COPYABLE: > - if (!check_trait_type (type1)) > + if (!check_trait_type (type1, /* kind = */ 2)) > + return error_mark_node; > + break; > + > + case CPTK_IS_EMPTY: > + case CPTK_IS_POLYMORPHIC: > + case CPTK_IS_ABSTRACT: > + case CPTK_HAS_VIRTUAL_DESTRUCTOR: > + if (!check_trait_type (type1, /* kind = */ 3)) > + return error_mark_node; > + break; > + > + /* N.B. std::is_aggregate is kind=2 but we don't need a complete element > + type to know whether an array is an aggregate, so use kind=2 here. */ *kind=4 > + case CPTK_IS_AGGREGATE: > + case CPTK_IS_FINAL: > + if (!check_trait_type (type1, /* kind = */ 4)) > return error_mark_node; > break; > > case CPTK_IS_ASSIGNABLE: > case CPTK_IS_CONSTRUCTIBLE: > + if (!check_trait_type (type1)) > + return error_mark_node; > break; > > case CPTK_IS_TRIVIALLY_ASSIGNABLE: > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 0fedab96610..be3ea890c47 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -25174,14 +25174,17 @@ Requires: @code{type} shall be a complete type, (possibly cv-qualified) > @item __has_virtual_destructor (type) > If @code{type} is a class type with a virtual destructor > ([class.dtor]) then the trait is @code{true}, else it is @code{false}. > -Requires: @code{type} shall be a complete type, (possibly cv-qualified) > -@code{void}, or an array of unknown bound. > +Requires: If @code{type} is a non-union class type, it shall be a complete type. > > @item __is_abstract (type) > If @code{type} is an abstract class ([class.abstract]) then the trait > is @code{true}, else it is @code{false}. > -Requires: @code{type} shall be a complete type, (possibly cv-qualified) > -@code{void}, or an array of unknown bound. > +Requires: If @code{type} is a non-union class type, it shall be a complete type. > + > +@item __is_aggregate (type) > +If @code{type} is an aggregate type ([dcl.init.aggr]) the trait is > +@code{true}, else it is @code{false}. > +Requires: If @code{type} is a class type, it shall be a complete type. > > @item __is_base_of (base_type, derived_type) > If @code{base_type} is a base class of @code{derived_type} > @@ -25206,13 +25209,17 @@ any, are bit-fields of length 0, and @code{type} has no virtual > members, and @code{type} has no virtual base classes, and @code{type} > has no base classes @code{base_type} for which > @code{__is_empty (base_type)} is @code{false}. > -Requires: @code{type} shall be a complete type, (possibly cv-qualified) > -@code{void}, or an array of unknown bound. > +Requires: If @code{type} is a non-union class type, it shall be a complete type. > > @item __is_enum (type) > If @code{type} is a cv enumeration type ([basic.compound]) the trait is > @code{true}, else it is @code{false}. > > +@item __is_final (type) > +If @code{type} is a class or union type marked @code{final}, then the trait > +is @code{true}, else it is @code{false}. > +Requires: If @code{type} is a class type, it shall be a complete type. > + > @item __is_literal_type (type) > If @code{type} is a literal type ([basic.types]) the trait is > @code{true}, else it is @code{false}. > @@ -25228,20 +25235,19 @@ Requires: @code{type} shall be a complete type, (possibly cv-qualified) > @item __is_polymorphic (type) > If @code{type} is a polymorphic class ([class.virtual]) then the trait > is @code{true}, else it is @code{false}. > -Requires: @code{type} shall be a complete type, (possibly cv-qualified) > -@code{void}, or an array of unknown bound. > +Requires: If @code{type} is a non-union class type, it shall be a complete type. > > @item __is_standard_layout (type) > If @code{type} is a standard-layout type ([basic.types]) the trait is > @code{true}, else it is @code{false}. > -Requires: @code{type} shall be a complete type, (possibly cv-qualified) > -@code{void}, or an array of unknown bound. > +Requires: @code{type} shall be a complete type, an array of complete types, > +or (possibly cv-qualified) @code{void}. > > @item __is_trivial (type) > If @code{type} is a trivial type ([basic.types]) the trait is > @code{true}, else it is @code{false}. > -Requires: @code{type} shall be a complete type, (possibly cv-qualified) > -@code{void}, or an array of unknown bound. > +Requires: @code{type} shall be a complete type, an array of complete types, > +or (possibly cv-qualified) @code{void}. > > @item __is_union (type) > If @code{type} is a cv union type ([basic.compound]) the trait is > diff --git a/gcc/testsuite/g++.dg/ext/array4.C b/gcc/testsuite/g++.dg/ext/array4.C > index 0068ea854e1..6adf9a3b0ee 100644 > --- a/gcc/testsuite/g++.dg/ext/array4.C > +++ b/gcc/testsuite/g++.dg/ext/array4.C > @@ -16,7 +16,6 @@ template > constexpr integral_constant __is_complete_or_unbounded(_Tp) { > return {}; > } > -struct Trans_NS_std_formatter; > template > struct is_default_constructible : integral_constant { > static_assert(__is_complete_or_unbounded(_Tp{}), ""); > @@ -53,7 +52,7 @@ template struct basic_string_view { basic_string_view(int, int); }; > template struct formatter; > template > using has_formatter = > - __bool_constant<__is_constructible(Trans_NS_std_formatter)>; > + __bool_constant<__is_constructible(void)>; > struct fallback_formatter; > template struct custom_value { > using parse_context = typename Context::parse_context_type; > diff --git a/gcc/testsuite/g++.dg/ext/unary_trait_incomplete.C b/gcc/testsuite/g++.dg/ext/unary_trait_incomplete.C > index 6c83279c030..1dfa449a8d2 100644 > --- a/gcc/testsuite/g++.dg/ext/unary_trait_incomplete.C > +++ b/gcc/testsuite/g++.dg/ext/unary_trait_incomplete.C > @@ -2,6 +2,7 @@ > > struct I; // { dg-message "forward declaration" } > struct C { }; > +union U; // { dg-message "forward declaration" } > > bool nas1 = __has_nothrow_assign(I); // { dg-error "incomplete type" } > bool nas2 = __has_nothrow_assign(C[]); > @@ -39,38 +40,105 @@ bool tcp3 = __has_trivial_copy(I[]); > bool tcp4 = __has_trivial_copy(void); > bool tcp5 = __has_trivial_copy(const void); > > -bool vde1 = __has_virtual_destructor(I); // { dg-error "incomplete type" } > -bool vde2 = __has_virtual_destructor(C[]); > -bool vde3 = __has_virtual_destructor(I[]); > -bool vde4 = __has_virtual_destructor(void); > -bool vde5 = __has_virtual_destructor(const void); > - > bool tde1 = __has_trivial_destructor(I); // { dg-error "incomplete type" } > bool tde2 = __has_trivial_destructor(C[]); > bool tde3 = __has_trivial_destructor(I[]); > bool tde4 = __has_trivial_destructor(void); > bool tde5 = __has_trivial_destructor(const void); > > -bool abs1 = __is_abstract(I); // { dg-error "incomplete type" } > -bool abs2 = __is_abstract(C[]); > -bool abs3 = __is_abstract(I[]); > -bool abs4 = __is_abstract(void); > -bool abs5 = __is_abstract(const void); > +// T shall be a complete type, cv void, or an array of unknown bound. > > -bool pod1 = __is_pod(I); // { dg-error "incomplete type" } > -bool pod2 = __is_pod(C[]); > -bool pod3 = __is_pod(I[]); > -bool pod4 = __is_pod(void); > -bool pod5 = __is_pod(const void); > +bool con1 = __is_constructible(C); > +bool con2 = __is_constructible(I); // { dg-error "incomplete type" } > +bool con3 = __is_constructible(U); // { dg-error "incomplete type" } > +bool con4 = __is_constructible(C[]); > +bool con5 = __is_constructible(I[]); > +bool con6 = __is_constructible(U[]); > +bool con7 = __is_constructible(C[1]); > +bool con8 = __is_constructible(I[1]); // { dg-error "incomplete type" } > +bool con9 = __is_constructible(U[1]); // { dg-error "incomplete type" } > +bool con10 = __is_constructible(void); > +bool con11 = __is_constructible(const void); > + > +// If T is a non-union class type, T shall be a complete type. > + > +bool vde1 = __has_virtual_destructor(I); // { dg-error "incomplete type" } > +bool vde2 = __has_virtual_destructor(U); > +bool vde3 = __has_virtual_destructor(C[]); > +bool vde4 = __has_virtual_destructor(I[]); > +bool vde5 = __has_virtual_destructor(U[]); > +bool vde6 = __has_virtual_destructor(C[1]); > +bool vde7 = __has_virtual_destructor(I[1]); > +bool vde8 = __has_virtual_destructor(U[1]); > +bool vde9 = __has_virtual_destructor(void); > +bool vde10 = __has_virtual_destructor(const void); > + > +bool abs1 = __is_abstract(I); // { dg-error "incomplete type" } > +bool abs2 = __is_abstract(U); > +bool abs3 = __is_abstract(C[]); > +bool abs4 = __is_abstract(I[]); > +bool abs5 = __is_abstract(U[]); > +bool abs6 = __is_abstract(C[1]); > +bool abs7 = __is_abstract(I[1]); > +bool abs8 = __is_abstract(U[1]); > +bool abs9 = __is_abstract(void); > +bool abs10 = __is_abstract(const void); > > bool emp1 = __is_empty(I); // { dg-error "incomplete type" } > -bool emp2 = __is_empty(C[]); > -bool emp3 = __is_empty(I[]); > -bool emp4 = __is_empty(void); > -bool emp5 = __is_empty(const void); > +bool emp2 = __is_empty(U); > +bool emp3 = __is_empty(C[]); > +bool emp4 = __is_empty(I[]); > +bool emp5 = __is_empty(U[]); > +bool emp6 = __is_empty(C[1]); > +bool emp7 = __is_empty(I[1]); > +bool emp8 = __is_empty(U[1]); > +bool emp9 = __is_empty(void); > +bool emp10 = __is_empty(const void); > > bool pol1 = __is_polymorphic(I); // { dg-error "incomplete type" } > -bool pol2 = __is_polymorphic(C[]); > -bool pol3 = __is_polymorphic(I[]); > -bool pol4 = __is_polymorphic(void); > -bool pol5 = __is_polymorphic(const void); > +bool pol2 = __is_polymorphic(U); > +bool pol3 = __is_polymorphic(C[]); > +bool pol4 = __is_polymorphic(I[]); > +bool pol5 = __is_polymorphic(U[]); > +bool pol6 = __is_polymorphic(C[1]); > +bool pol7 = __is_polymorphic(I[1]); > +bool pol8 = __is_polymorphic(U[1]); > +bool pol9 = __is_polymorphic(void); > +bool pol10 = __is_polymorphic(const void); > + > +// If T is a class type, T shall be a complete type. > + > +bool agg1 = __is_aggregate(I); // { dg-error "incomplete type" } > +bool agg2 = __is_aggregate(U); // { dg-error "incomplete type" } > +bool agg3 = __is_aggregate(C[]); > +bool agg4 = __is_aggregate(I[]); > +bool agg5 = __is_aggregate(U[]); > +bool agg6 = __is_aggregate(C[1]); > +bool agg7 = __is_aggregate(I[1]); > +bool agg8 = __is_aggregate(U[1]); > +bool agg9 = __is_aggregate(void); > +bool agg10 = __is_aggregate(const void); > + > +bool fin1 = __is_final(I); // { dg-error "incomplete type" } > +bool fin2 = __is_final(U); // { dg-error "incomplete type" } > +bool fin3 = __is_final(C[]); > +bool fin4 = __is_final(I[]); > +bool fin5 = __is_final(U[]); > +bool fin6 = __is_final(C[1]); > +bool fin7 = __is_final(I[1]); > +bool fin8 = __is_final(U[1]); > +bool fin9 = __is_final(void); > +bool fin10 = __is_final(const void); > + > +// remove_all_extents_t shall be a complete type or cv void. > + > +bool pod1 = __is_pod(I); // { dg-error "incomplete type" } > +bool pod2 = __is_pod(U); // { dg-error "incomplete type" } > +bool pod3 = __is_pod(C[]); > +bool pod4 = __is_pod(I[]); // { dg-error "incomplete type" } > +bool pod5 = __is_pod(U[]); // { dg-error "incomplete type" } > +bool pod6 = __is_pod(C[1]); > +bool pod7 = __is_pod(I[1]); // { dg-error "incomplete type" } > +bool pod8 = __is_pod(U[1]); // { dg-error "incomplete type" } > +bool pod9 = __is_pod(void); > +bool pod10 = __is_pod(const void); > 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 > index 1870e501723..fc0b70b319c 100644 > --- 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 > @@ -1,5 +1,7 @@ > // { dg-do compile { target c++11 } } > // { dg-prune-output "must be a complete" } > +// { dg-prune-output "'value' is not a member of 'std::is_move_cons" } > +// { dg-prune-output "invalid use of incomplete type" } > > // Copyright (C) 2019-2022 Free Software Foundation, Inc. > // > 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 > index 7bd453d7851..7c34b5f1224 100644 > --- a/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc > +++ b/libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc > @@ -18,6 +18,7 @@ > // . > > // { dg-error "must be a complete class" "" { target *-*-* } 0 } > +// { dg-prune-output "invalid use of incomplete type" } > > #include > > diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc > index 88c9c01f37c..d3a34cca7a7 100644 > --- a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc > +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc > @@ -18,6 +18,7 @@ > // . > > // { dg-error "must be a complete class" "" { target *-*-* } 0 } > +// { dg-prune-output "invalid use of incomplete type" } > > #include > > diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc > index da0f7713659..6dfa3363d88 100644 > --- a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc > +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc > @@ -18,6 +18,7 @@ > // . > > // { dg-error "must be a complete class" "" { target *-*-* } 0 } > +// { dg-prune-output "invalid use of incomplete type" } > > #include > > diff --git a/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc > index 74ad291a931..d5fa42256ea 100644 > --- a/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc > +++ b/libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc > @@ -18,6 +18,7 @@ > // . > > // { dg-error "must be a complete class" "" { target *-*-* } 0 } > +// { dg-prune-output "invalid use of incomplete type" } > > #include >