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.129.124]) by sourceware.org (Postfix) with ESMTPS id C302A3858285 for ; Thu, 8 Sep 2022 16:38:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C302A3858285 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=1662655129; 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: in-reply-to:in-reply-to:references:references; bh=F+IbSyLIg8Shw1aMA4OFolH81ml4FK61ik1Ogqnr9aY=; b=JX+Sn9JYtN7sjTDS2QhS7Ak80J+t3/L7OMcLxx6KO9iLFuXC0ATf1mKfo9ea3EJb/bLKqm 5waxe1W4uLP11OwaFSF+sXfp4IsY0zBd+EXxFrD5U41p86YO4NnoXzly4H45g+GCkrxi46 chc2IygfhH91O2gxBbwDFtQmaX+1IZU= Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-249--Dwj5-AGMYa_yfUGPUyAOA-1; Thu, 08 Sep 2022 12:38:48 -0400 X-MC-Unique: -Dwj5-AGMYa_yfUGPUyAOA-1 Received: by mail-qv1-f70.google.com with SMTP id n15-20020ad444af000000b004a2a341ad71so9526913qvt.15 for ; Thu, 08 Sep 2022 09:38:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date; bh=F+IbSyLIg8Shw1aMA4OFolH81ml4FK61ik1Ogqnr9aY=; b=gm+QFya4GZOmkXF/RmIL0GtyZVnJPzMdVi91iIfHIyKp/qTQTa+8AqGpSvXpwdmtKG XoFs8AsBtmhKh7/bHY06Sqd20rJtyC3kUxwEfnvSoZkfaQVcTWglv7CZOl0IWVmDABka 6a4QEr8X5U9JzLVbMytXZWuVhdWy10lL46Ww2mgmVTQ59RZRq7HqWIYYhrecPB1CcXKW fiUEphHsvoHkSlUxv46cPrdKrUiLoX05uG0Yfkx1dUdtv7Uvvl6vzOAK9Gj8vv35HsTx eQS+DurG3KgYJR8KVGDRn/mNrcnNxQfSGANCt/uj/IljEj3IerpOrfXzYexHJBPRUR9q oNYg== X-Gm-Message-State: ACgBeo0IZT/6scXVqlrTyQLclrssQmDRVs3PswFfhfUFgw8ODvEGteTv s2sAx6TC7OLQiuAaRUjPgq2lmLhoogMpzKyuWlSHMuH4zd7xtWbutLKrAayV0UryHTU57e2OydL qmv5lnAfkKbn4lkwYmLpSHdRAktUUEKI= X-Received: by 2002:a05:622a:11c2:b0:343:69d:65b2 with SMTP id n2-20020a05622a11c200b00343069d65b2mr8924517qtk.491.1662655127676; Thu, 08 Sep 2022 09:38:47 -0700 (PDT) X-Google-Smtp-Source: AA6agR70Cp2Sz6U+7vHMDCW/h00pmUsPdEkHJmM3+dAofhGlJrd1VpM1ebGDTj6Y/Tf7QS1b8lJ15tHQQk8R4Dw7NLg= X-Received: by 2002:a05:622a:11c2:b0:343:69d:65b2 with SMTP id n2-20020a05622a11c200b00343069d65b2mr8924486qtk.491.1662655127206; Thu, 08 Sep 2022 09:38:47 -0700 (PDT) MIME-Version: 1.0 References: <20220908125606.3272086-1-jwakely@redhat.com> <65658c39-e0fb-6ad3-9136-fac36d763f4a@redhat.com> In-Reply-To: <65658c39-e0fb-6ad3-9136-fac36d763f4a@redhat.com> From: Jonathan Wakely Date: Thu, 8 Sep 2022 17:38:36 +0100 Message-ID: Subject: Re: [PATCH v2] c++: Fix type completeness checks for type traits [PR106838] To: Jason Merrill Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,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 Thu, 8 Sept 2022 at 17:12, Jason Merrill wrote: > > 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: Oops, I'll fix that - thanks. > > > -- >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 > > >