aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/class.cc2
-rw-r--r--gcc/cp/semantics.cc58
-rw-r--r--gcc/doc/extend.texi30
-rw-r--r--gcc/testsuite/g++.dg/ext/array4.C3
-rw-r--r--gcc/testsuite/g++.dg/ext/unary_trait_incomplete.C116
-rw-r--r--libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_move_constructible/incomplete_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/is_nothrow_swappable/incomplete_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/is_nothrow_swappable_with/incomplete_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/is_swappable_with/incomplete_neg.cc1
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>