diff options
-rw-r--r-- | gcc/cp/class.cc | 2 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 58 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 30 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/array4.C | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/unary_trait_incomplete.C | 116 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc | 2 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc | 1 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc | 1 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc | 1 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/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 a12d367..b84f422 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 3d58d67..6bda30e 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=4 here. */ + 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 0fedab9..be3ea89 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 0068ea8..6adf9a3 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 6c83279..1dfa449 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 1870e50..fc0b70b 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 7bd453d..7c34b5f 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 88c9c01..d3a34cc 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 da0f771..6dfa336 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 74ad291..d5fa4225 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> |