public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jonathan Wakely <jwakely@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
Subject: Re: [PATCH v2] c++: Fix type completeness checks for type traits [PR106838]
Date: Thu, 8 Sep 2022 17:38:36 +0100	[thread overview]
Message-ID: <CACb0b4kiw-4TD9VdJ=W8W-u6oJxOM0_7CTeP_Qqm-vrJm0dZvw@mail.gmail.com> (raw)
In-Reply-To: <65658c39-e0fb-6ad3-9136-fac36d763f4a@redhat.com>

On Thu, 8 Sept 2022 at 17:12, Jason Merrill <jason@redhat.com> 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 <typename _Tp>
> >   constexpr integral_constant<true> __is_complete_or_unbounded(_Tp) {
> >     return {};
> >   }
> > -struct Trans_NS_std_formatter;
> >   template <typename _Tp>
> >   struct is_default_constructible : integral_constant<false> {
> >     static_assert(__is_complete_or_unbounded(_Tp{}), "");
> > @@ -53,7 +52,7 @@ template <typename> struct basic_string_view { basic_string_view(int, int); };
> >   template <typename, typename> struct formatter;
> >   template <typename, typename>
> >   using has_formatter =
> > -    __bool_constant<__is_constructible(Trans_NS_std_formatter)>;
> > +    __bool_constant<__is_constructible(void)>;
> >   struct fallback_formatter;
> >   template <typename Context> 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<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 @@
> >   // <http://www.gnu.org/licenses/>.
> >
> >   // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> > +// { dg-prune-output "invalid use of incomplete type" }
> >
> >   #include <type_traits>
> >
> > 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 @@
> >   // <http://www.gnu.org/licenses/>.
> >
> >   // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> > +// { dg-prune-output "invalid use of incomplete type" }
> >
> >   #include <type_traits>
> >
> > 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 @@
> >   // <http://www.gnu.org/licenses/>.
> >
> >   // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> > +// { dg-prune-output "invalid use of incomplete type" }
> >
> >   #include <type_traits>
> >
> > 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 @@
> >   // <http://www.gnu.org/licenses/>.
> >
> >   // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> > +// { dg-prune-output "invalid use of incomplete type" }
> >
> >   #include <type_traits>
> >
>


      reply	other threads:[~2022-09-08 16:38 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-07 12:18 [PATCH] " Jonathan Wakely
2022-09-07 15:11 ` Jason Merrill
2022-09-08 12:56   ` [PATCH v2] " Jonathan Wakely
2022-09-08 16:12     ` Jason Merrill
2022-09-08 16:38       ` Jonathan Wakely [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CACb0b4kiw-4TD9VdJ=W8W-u6oJxOM0_7CTeP_Qqm-vrJm0dZvw@mail.gmail.com' \
    --to=jwakely@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).