On Thu, Jul 02, 2026 at 01:17:12PM -0400, Jason Merrill wrote:
> On 7/2/26 12:49 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > I'm not sure about backporting this. It might make future 16 backports
> > easier.
> >
> > -- >8 --
> > This PR laments that our meta::is_trivially_copyable_type gives the wrong
> > result when its argument is a reflection of an uninstantiated template,
> > because its TYPE_HAS_* flags haven't been properly set. They are set in
> > finish_struct_1, called while instantiating the template.
> >
> > This led to a much broader problem: we're not checking Preconditions in
> > [meta.unary.prop] and Comments in [meta.rel]. Jason pointed out to me
> > that check_trait_type and its KIND parameter already does this kind of
> > checking; our Reflection code just wasn't using it fully. With this patch
> > we give an error when finish_trait_expr returns an error node.
> > finish_trait_expr and check_trait_type need a complain parameter. Many
> > metafuncions weren't using the finish_trait_expr mechanism as they
> > should. The rest of the patch is adding the extra arguments.
> >
> > I found PR126073, XFAILd for now.
> >
> > +eval_type_trait (location_t loc, const constexpr_ctx *ctx, tree type1,
> > + tree type2, cp_trait_kind kind, bool *non_constant_p,
> > + tree fun)
> > {
> > - tree r = finish_trait_expr (loc, kind, type1, type2);
> > - gcc_checking_assert (r != error_mark_node);
> > + tree r = finish_trait_expr (loc, kind, type1, type2, tf_none);
> > + if (r == error_mark_node)
> > + {
> > + /* [meta.reflection.traits]/3.2: Otherwise, if the instantiation of S
> > + would result in undefined behavior due to dependence on an incomplete
> > + type, then the call is not a constant subexpression. */
> > + if (!cxx_constexpr_quiet_p (ctx))
> > + {
> > + auto_diagnostic_group d;
> > + error_at (loc, "type trait %qE preconditions not satisfied", fun);
> > + inform (loc, "argument has a type that cannot be completed");
>
> Since the type in question is probably type1 or type2, we should usually be
> able to identify it and cxx_incomplete_type_diagnostic.
I added a search for the incomplete type. Since a lot of the preconditions
talk about "complete type, cv void, or array of unknown bound", I'm using
COMPLETE_OR_VOID_TYPE_P + array_of_unknown_bound_p not to complain about
the wrong argument. The diagnostic now looks like this:
type_trait17.C:13:48: error: type trait 'std::meta::is_trivially_copyable_type'
preconditions not satisfied
13 | constexpr bool b0 = is_trivially_copyable_type (^^S<int>); // {
dg-error "invalid use of incomplete type" }
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
type_trait17.C:13:48: note: invalid use of incomplete type 'struct S<int>'
type_trait17.C:9:8: note: declaration of 'struct S<int>'
9 | struct S;
| ^
> > @@ -14286,10 +14286,13 @@ trait_expr_value (cp_trait_kind kind, tree type1,
> > tree type2)
> > 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. */
> > + If TYPE is a class type, it must be complete.
> > +
> > + If COMPLAIN is not tf_none, we emit error messages and return false only
> > + if -fpermissive wasn't specified. */
>
> I might phrase this as "we permerror and return false if that doesn't
> produce a hard error".
Done.
Tested dg.exp.
-- >8 --
This PR laments that our meta::is_trivially_copyable_type gives the wrong
result when its argument is a reflection of an uninstantiated template,
because its TYPE_HAS_* flags haven't been properly set. They are set in
finish_struct_1, called while instantiating the template.
This led to a much broader problem: we're not checking Preconditions in
[meta.unary.prop] and Comments in [meta.rel]. Jason pointed out to me
that check_trait_type and its KIND parameter already does this kind of
checking; our Reflection code just wasn't using it fully. With this patch
we give an error when finish_trait_expr returns an error node.
finish_trait_expr and check_trait_type need a complain parameter. Many
metafuncions weren't using the finish_trait_expr mechanism as they
should. The rest of the patch is adding the extra arguments.
I found PR126073, XFAILd for now.
PR c++/125901
gcc/cp/ChangeLog:
* cp-tree.h (finish_trait_expr): Adjust declaration.
* reflect.cc (eval_constant_of): Adjust the call to
eval_is_array_type.
(eval_reflect_object): Adjust the call to eval_is_object_type.
(eval_type_trait): Emit a diagnostic when finish_trait_expr
returns error_mark_node and set *non_constant_p. Adjust the
call to eval_type_trait.
(eval_is_array_type): Adjust the call to eval_type_trait.
(eval_is_pointer_type): Likewise.
(eval_is_member_object_pointer_type): Likewise.
(eval_is_member_function_pointer_type): Likewise.
(eval_is_enum_type): Likewise.
(eval_is_union_type): Likewise.
(eval_is_class_type): Likewise.
(eval_is_reference_type): Likewise.
(eval_is_member_pointer_type): Likewise.
(eval_is_object_type): Likewise.
(eval_is_trivially_copyable_type): Use eval_type_trait.
(eval_is_standard_layout_type): Likewise.
(eval_is_empty_type): Adjust the call to eval_type_trait.
(eval_is_polymorphic_type): Likewise.
(eval_is_abstract_type): Use eval_type_trait.
(eval_is_final_type): Adjust the call to eval_type_trait.
(eval_is_aggregate_type): Use eval_type_trait.
(eval_is_structural_type): Adjust the call to eval_type_trait.
(eval_is_bounded_array_type): Likewise.
(eval_is_constructible_type): Use eval_type_trait.
(eval_is_default_constructible_type): Likewise.
(eval_is_copy_constructible_type): Likewise.
(eval_is_move_constructible_type): Likewise.
(eval_is_assignable_type): Adjust the call to eval_type_trait.
(eval_is_copy_assignable_type): Use eval_type_trait.
(eval_is_move_assignable_type): Use eval_type_trait.
(eval_is_destructible_type): Adjust the call to eval_type_trait.
(eval_is_trivially_constructible_type): Use eval_type_trait.
(eval_is_trivially_default_constructible_type): Likewise.
(eval_is_trivially_copy_constructible_type): Likewise.
(eval_is_trivially_move_constructible_type): Likewise.
(eval_is_trivially_assignable_type): Adjust the call to
eval_type_trait.
(eval_is_trivially_copy_assignable_type): Use eval_type_trait.
(eval_is_trivially_move_assignable_type): Likewise.
(eval_is_trivially_destructible_type): Adjust the call to
eval_type_trait.
(eval_is_nothrow_constructible_type): Use eval_type_trait.
(eval_is_nothrow_default_constructible_type): Likewise.
(eval_is_nothrow_copy_constructible_type): Likewise.
(eval_is_nothrow_move_constructible_type): Likewise.
(eval_is_nothrow_assignable_type): Adjust the call to
eval_type_trait.
(eval_is_nothrow_copy_assignable_type): Use eval_type_trait.
(eval_is_nothrow_move_assignable_type): Likewise.
(eval_is_nothrow_destructible_type): Adjust the call to
eval_type_trait.
(eval_is_implicit_lifetime_type): Use eval_type_trait.
(eval_has_virtual_destructor): Likewise.
(eval_has_unique_object_representations): Likewise.
(eval_reference_constructs_from_temporary): Adjust the call to
eval_type_trait.
(eval_reference_converts_from_temporary): Likewise.
(eval_extent): Adjust the call to eval_is_bounded_array_type.
Check != boolean_true_node rather than == boolean_false_node when
checking eval_is_bounded_array_type.
(eval_is_same_type): Adjust the call to eval_type_trait.
(eval_is_base_of_type): Likewise.
(eval_is_virtual_base_of_type): Likewise.
(eval_is_convertible_type): Likewise.
(eval_is_nothrow_convertible_type): Likewise.
(eval_is_layout_compatible_type): Likewise.
(eval_is_pointer_interconvertible_base_of_type): Likewise.
(eval_is_invocable_type): Use eval_type_trait.
(eval_is_nothrow_invocable_type): Likewise.
(eval_data_member_spec): Adjust the calls to eval_is_array_type
and eval_is_object_type. Check != boolean_true_node rather than
== boolean_false_node when checking eval_is_object_type.
(eval_extract): Adjust the call to eval_is_reference_type.
(process_metafunction): Adjust the calls to various
metafunctions.
* semantics.cc (check_trait_type): Remove a default argument.
Add a complain parameter. If not emitting error messages, always
return false for incomplete types.
(finish_trait_expr): Add a complain parameter. Use it. Call
complete_type_or_maybe_complain instead of
complete_type_or_else.
gcc/testsuite/ChangeLog:
* g++.dg/reflect/type_trait16.C: New test.
* g++.dg/reflect/type_trait17.C: New test.
* g++.dg/reflect/type_trait18.C: New test.
---
gcc/cp/cp-tree.h | 4 +-
gcc/cp/reflect.cc | 697 ++++++++++++--------
gcc/cp/semantics.cc | 43 +-
gcc/testsuite/g++.dg/reflect/type_trait16.C | 37 ++
gcc/testsuite/g++.dg/reflect/type_trait17.C | 315 +++++++++
gcc/testsuite/g++.dg/reflect/type_trait18.C | 126 ++++
6 files changed, 935 insertions(+), 287 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/reflect/type_trait16.C
create mode 100644 gcc/testsuite/g++.dg/reflect/type_trait17.C
create mode 100644 gcc/testsuite/g++.dg/reflect/type_trait18.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a1b95b6f569..a0fa19a9c37 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8675,7 +8675,9 @@ extern bool pointer_interconvertible_base_of_p (tree,
tree, bool = false);
extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t,
int, tree *);
extern tree fold_builtin_is_string_literal (location_t, int, tree *);
extern tree finish_structured_binding_size (location_t, tree,
tsubst_flags_t);
-extern tree finish_trait_expr (location_t, enum
cp_trait_kind, tree, tree);
+extern tree finish_trait_expr (location_t, enum cp_trait_kind,
+ tree, tree,
+ tsubst_flags_t =
tf_warning_or_error);
extern tree finish_trait_type (enum cp_trait_kind, tree,
tree, tsubst_flags_t);
extern tree build_lambda_expr (void);
extern tree build_lambda_object (tree);
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 96f5de8481d..6d8db5bd95d 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -33,10 +33,12 @@ along with GCC; see the file COPYING3. If not see
#include "metafns.h"
static tree eval_is_function_type (tree);
-static tree eval_is_object_type (location_t, tree);
+static tree eval_is_object_type (location_t, const constexpr_ctx *, tree,
+ bool *, tree);
static tree eval_reflect_constant (location_t, const constexpr_ctx *, tree,
tree, bool *, tree *, tree);
-static tree eval_is_array_type (location_t, tree);
+static tree eval_is_array_type (location_t, const constexpr_ctx *, tree,
+ bool *, tree);
static tree eval_reflect_constant_array (location_t, const constexpr_ctx *,
tree, bool *, bool *, tree *, tree);
static tree eval_reflect_function (location_t, const constexpr_ctx *, tree,
@@ -2805,7 +2807,8 @@ eval_constant_of (location_t loc, const constexpr_ctx
*ctx, tree r,
if (eval_is_annotation (r, kind) == boolean_true_node)
r = tree_strip_any_location_wrapper (TREE_VALUE (TREE_VALUE (r)));
- else if (eval_is_array_type (loc, type) == boolean_true_node)
+ else if (eval_is_array_type (loc, ctx, type, non_constant_p, fun)
+ == boolean_true_node)
{
const tsubst_flags_t complain = complain_flags (ctx);
/* Create a call to reflect_constant_array so that we can simply
@@ -4087,7 +4090,8 @@ eval_reflect_object (location_t loc, const constexpr_ctx
*ctx, tree type,
tree expr, bool *non_constant_p, tree *jump_target,
tree fun)
{
- if (eval_is_object_type (loc, type) != boolean_true_node)
+ if (eval_is_object_type (loc, ctx, type, non_constant_p, fun)
+ != boolean_true_node)
{
error_at (loc, "%qT must be an object type", TREE_TYPE (type));
return error_mark_node;
@@ -4143,10 +4147,47 @@ eval_reflect_function (location_t loc, const
constexpr_ctx *ctx, tree type,
arguments to the trait. */
static tree
-eval_type_trait (location_t loc, tree type1, tree type2, cp_trait_kind kind)
+eval_type_trait (location_t loc, const constexpr_ctx *ctx, tree type1,
+ tree type2, cp_trait_kind kind, bool *non_constant_p,
+ tree fun)
{
- tree r = finish_trait_expr (loc, kind, type1, type2);
- gcc_checking_assert (r != error_mark_node);
+ tree r = finish_trait_expr (loc, kind, type1, type2, tf_none);
+ if (r == error_mark_node)
+ {
+ /* [meta.reflection.traits]/3.2: Otherwise, if the instantiation of S
+ would result in undefined behavior due to dependence on an incomplete
+ type, then the call is not a constant subexpression. */
+ if (!cxx_constexpr_quiet_p (ctx))
+ {
+ auto_diagnostic_group d;
+ error_at (loc, "type trait %qE preconditions not satisfied", fun);
+ /* See if we can figure out which argument was incomplete. */
+ tree inc = NULL_TREE;
+ if (!COMPLETE_OR_VOID_TYPE_P (type1)
+ && !array_of_unknown_bound_p (type1))
+ inc = type1;
+ else if (type2)
+ {
+ if (TYPE_P (type2)
+ && !COMPLETE_OR_VOID_TYPE_P (type2)
+ && !array_of_unknown_bound_p (type2))
+ inc = type2;
+ else if (TREE_CODE (type2) == TREE_VEC)
+ for (tree t : tree_vec_range (type2))
+ if (!COMPLETE_OR_VOID_TYPE_P (t)
+ && !array_of_unknown_bound_p (t))
+ {
+ inc = t;
+ break;
+ }
+ }
+ if (inc)
+ cxx_incomplete_type_diagnostic (loc, NULL_TREE, inc,
+ diagnostics::kind::note);
+ }
+ *non_constant_p = true;
+ return NULL_TREE;
+ }
STRIP_ANY_LOCATION_WRAPPER (r);
return r;
}
@@ -4154,9 +4195,11 @@ eval_type_trait (location_t loc, tree type1, tree type2,
cp_trait_kind kind)
/* Like above, but for type traits that take only one type. */
static tree
-eval_type_trait (location_t loc, tree type, cp_trait_kind kind)
+eval_type_trait (location_t loc, const constexpr_ctx *ctx, tree type,
+ cp_trait_kind kind, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, NULL_TREE, kind);
+ return eval_type_trait (loc, ctx, type, NULL_TREE, kind, non_constant_p,
+ fun);
}
/* Process std::meta::is_function_type. */
@@ -4217,17 +4260,21 @@ eval_is_floating_point_type (tree type)
/* Process std::meta::is_array_type. */
static tree
-eval_is_array_type (location_t loc, tree type)
+eval_is_array_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_ARRAY);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_ARRAY, non_constant_p,
+ fun);
}
/* Process std::meta::is_pointer_type. */
static tree
-eval_is_pointer_type (location_t loc, tree type)
+eval_is_pointer_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_POINTER);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_POINTER, non_constant_p,
+ fun);
}
/* Process std::meta::is_lvalue_reference_type. */
@@ -4255,41 +4302,51 @@ eval_is_rvalue_reference_type (tree type)
/* Process std::meta::is_member_object_pointer_type. */
static tree
-eval_is_member_object_pointer_type (location_t loc, tree type)
+eval_is_member_object_pointer_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_MEMBER_OBJECT_POINTER);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_MEMBER_OBJECT_POINTER,
+ non_constant_p, fun);
}
/* Process std::meta::is_member_function_pointer_type. */
static tree
-eval_is_member_function_pointer_type (location_t loc, tree type)
+eval_is_member_function_pointer_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_MEMBER_FUNCTION_POINTER);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_MEMBER_FUNCTION_POINTER,
+ non_constant_p, fun);
}
/* Process std::meta::is_enum_type. */
static tree
-eval_is_enum_type (location_t loc, tree type)
+eval_is_enum_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_ENUM);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_ENUM, non_constant_p,
+ fun);
}
/* Process std::meta::is_union_type. */
static tree
-eval_is_union_type (location_t loc, tree type)
+eval_is_union_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_UNION);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_UNION, non_constant_p,
+ fun);
}
/* Process std::meta::is_class_type. */
static tree
-eval_is_class_type (location_t loc, tree type)
+eval_is_class_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_CLASS);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_CLASS, non_constant_p,
+ fun);
}
/* Process std::meta::is_reflection_type. */
@@ -4306,9 +4363,11 @@ eval_is_reflection_type (tree type)
/* Process std::meta::is_reference_type. */
static tree
-eval_is_reference_type (location_t loc, tree type)
+eval_is_reference_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_REFERENCE);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_REFERENCE, non_constant_p,
+ fun);
}
/* Process std::meta::is_arithmetic_type. */
@@ -4325,9 +4384,11 @@ eval_is_arithmetic_type (tree type)
/* Process std::meta::is_object_type. */
static tree
-eval_is_object_type (location_t loc, tree type)
+eval_is_object_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_OBJECT);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_OBJECT, non_constant_p,
+ fun);
}
/* Process std::meta::is_scalar_type. */
@@ -4369,9 +4430,11 @@ eval_is_compound_type (tree type)
/* Process std::meta::is_member_pointer_type. */
static tree
-eval_is_member_pointer_type (location_t loc, tree type)
+eval_is_member_pointer_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_MEMBER_POINTER);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_MEMBER_POINTER,
+ non_constant_p, fun);
}
/* Process std::meta::is_const_type. */
@@ -4399,58 +4462,60 @@ eval_is_volatile_type (tree type)
/* Process std::meta::is_trivially_copyable_type. */
static tree
-eval_is_trivially_copyable_type (tree type)
+eval_is_trivially_copyable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (trivially_copyable_p (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_IS_TRIVIALLY_COPYABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_standard_layout_type. */
static tree
-eval_is_standard_layout_type (tree type)
+eval_is_standard_layout_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (std_layout_type_p (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_IS_STD_LAYOUT, non_constant_p,
+ fun);
}
/* Process std::meta::is_empty_type. */
static tree
-eval_is_empty_type (location_t loc, tree type)
+eval_is_empty_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_EMPTY);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_EMPTY, non_constant_p,
+ fun);
}
/* Process std::meta::is_polymorphic_type. */
static tree
-eval_is_polymorphic_type (location_t loc, tree type)
+eval_is_polymorphic_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_POLYMORPHIC);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_POLYMORPHIC, non_constant_p,
+ fun);
}
/* Process std::meta::is_abstract_type. */
static tree
-eval_is_abstract_type (tree type)
+eval_is_abstract_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (ABSTRACT_CLASS_TYPE_P (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_IS_ABSTRACT, non_constant_p,
+ fun);
}
/* Process std::meta::is_final_type. */
static tree
-eval_is_final_type (location_t loc, tree type)
+eval_is_final_type (location_t loc, const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_FINAL);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_FINAL, non_constant_p, fun);
}
/* Process std::meta::is_final.
@@ -4480,20 +4545,21 @@ eval_is_final (tree r)
/* Process std::meta::is_aggregate_type. */
static tree
-eval_is_aggregate_type (tree type)
+eval_is_aggregate_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (CP_AGGREGATE_TYPE_P (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_IS_AGGREGATE,
+ non_constant_p, fun);
}
/* Process std::meta::is_structural_type. */
static tree
-eval_is_structural_type (location_t loc, tree type)
+eval_is_structural_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_STRUCTURAL);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_STRUCTURAL,
+ non_constant_p, fun);
}
/* Process std::meta::is_signed_type. */
@@ -4521,9 +4587,11 @@ eval_is_unsigned_type (tree type)
/* Process std::meta::is_bounded_array_type. */
static tree
-eval_is_bounded_array_type (location_t loc, tree type)
+eval_is_bounded_array_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_BOUNDED_ARRAY);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_BOUNDED_ARRAY,
+ non_constant_p, fun);
}
/* Process std::meta::is_unbounded_array_type. */
@@ -4551,320 +4619,355 @@ eval_is_scoped_enum_type (tree type)
/* Process std::meta::is_constructible_type. */
static tree
-eval_is_constructible_type (tree type, tree tvec)
+eval_is_constructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, tree tvec, bool *non_constant_p,
+ tree fun)
{
- if (is_xible (INIT_EXPR, type, tvec))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, tvec, CPTK_IS_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_default_constructible_type. */
static tree
-eval_is_default_constructible_type (tree type)
+eval_is_default_constructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (is_xible (INIT_EXPR, type, make_tree_vec (0)))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, make_tree_vec (0),
+ CPTK_IS_CONSTRUCTIBLE, non_constant_p, fun);
}
/* Process std::meta::is_copy_constructible_type. */
static tree
-eval_is_copy_constructible_type (tree type)
+eval_is_copy_constructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
tree arg = make_tree_vec (1);
TREE_VEC_ELT (arg, 0) = build_const_lref (type);
- if (is_xible (INIT_EXPR, type, arg))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, arg, CPTK_IS_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_move_constructible_type. */
static tree
-eval_is_move_constructible_type (tree type)
+eval_is_move_constructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
tree arg = make_tree_vec (1);
TREE_VEC_ELT (arg, 0) = cp_build_reference_type (type, /*rval=*/true);
- if (is_xible (INIT_EXPR, type, arg))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, arg, CPTK_IS_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_assignable_type. */
static tree
-eval_is_assignable_type (location_t loc, tree type1, tree type2)
+eval_is_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_ASSIGNABLE);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_copy_assignable_type. */
static tree
-eval_is_copy_assignable_type (tree type)
+eval_is_copy_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
tree type1 = cp_build_reference_type (type, /*rval=*/false);
tree type2 = build_const_lref (type);
- if (is_xible (MODIFY_EXPR, type1, type2))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_move_assignable_type. */
static tree
-eval_is_move_assignable_type (tree type)
+eval_is_move_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
tree type1 = cp_build_reference_type (type, /*rval=*/false);
tree type2 = cp_build_reference_type (type, /*rval=*/true);
- if (is_xible (MODIFY_EXPR, type1, type2))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_destructible_type. */
static tree
-eval_is_destructible_type (location_t loc, tree type)
+eval_is_destructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_DESTRUCTIBLE);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_DESTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_constructible_type. */
static tree
-eval_is_trivially_constructible_type (tree type, tree tvec)
+eval_is_trivially_constructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, tree tvec,
+ bool *non_constant_p, tree fun)
{
- if (is_trivially_xible (INIT_EXPR, type, tvec))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, tvec,
+ CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_default_constructible_type. */
static tree
-eval_is_trivially_default_constructible_type (tree type)
+eval_is_trivially_default_constructible_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
- if (is_trivially_xible (INIT_EXPR, type, make_tree_vec (0)))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, make_tree_vec (0),
+ CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_copy_constructible_type. */
static tree
-eval_is_trivially_copy_constructible_type (tree type)
+eval_is_trivially_copy_constructible_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
- if (trivially_copy_constructible_p (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ tree arg = make_tree_vec (1);
+ TREE_VEC_ELT (arg, 0) = build_const_lref (type);
+ return eval_type_trait (loc, ctx, type, arg,
+ CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_move_constructible_type. */
static tree
-eval_is_trivially_move_constructible_type (tree type)
+eval_is_trivially_move_constructible_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
tree arg = make_tree_vec (1);
TREE_VEC_ELT (arg, 0) = cp_build_reference_type (type, /*rval=*/true);
- if (is_trivially_xible (INIT_EXPR, type, arg))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, arg,
+ CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_assignable_type. */
static tree
-eval_is_trivially_assignable_type (location_t loc, tree type1, tree type2)
+eval_is_trivially_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2,
+ bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_TRIVIALLY_ASSIGNABLE);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_TRIVIALLY_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_copy_assignable_type. */
static tree
-eval_is_trivially_copy_assignable_type (tree type)
+eval_is_trivially_copy_assignable_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
tree type1 = cp_build_reference_type (type, /*rval=*/false);
tree type2 = build_const_lref (type);
- if (is_trivially_xible (MODIFY_EXPR, type1, type2))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_TRIVIALLY_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_move_assignable_type. */
static tree
-eval_is_trivially_move_assignable_type (tree type)
+eval_is_trivially_move_assignable_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
tree type1 = cp_build_reference_type (type, /*rval=*/false);
tree type2 = cp_build_reference_type (type, /*rval=*/true);
- if (is_trivially_xible (MODIFY_EXPR, type1, type2))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_TRIVIALLY_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_trivially_destructible_type. */
static tree
-eval_is_trivially_destructible_type (location_t loc, tree type)
+eval_is_trivially_destructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_TRIVIALLY_DESTRUCTIBLE);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_TRIVIALLY_DESTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_constructible_type. */
static tree
-eval_is_nothrow_constructible_type (tree type, tree tvec)
+eval_is_nothrow_constructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, tree tvec, bool *non_constant_p,
+ tree fun)
{
- if (is_nothrow_xible (INIT_EXPR, type, tvec))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, tvec, CPTK_IS_NOTHROW_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_default_constructible_type. */
static tree
-eval_is_nothrow_default_constructible_type (tree type)
+eval_is_nothrow_default_constructible_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
- if (is_nothrow_xible (INIT_EXPR, type, make_tree_vec (0)))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, make_tree_vec (0),
+ CPTK_IS_NOTHROW_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_copy_constructible_type. */
static tree
-eval_is_nothrow_copy_constructible_type (tree type)
+eval_is_nothrow_copy_constructible_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
tree arg = make_tree_vec (1);
TREE_VEC_ELT (arg, 0) = build_const_lref (type);
- if (is_nothrow_xible (INIT_EXPR, type, arg))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, arg,
+ CPTK_IS_NOTHROW_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_move_constructible_type. */
static tree
-eval_is_nothrow_move_constructible_type (tree type)
+eval_is_nothrow_move_constructible_type (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
tree arg = make_tree_vec (1);
TREE_VEC_ELT (arg, 0) = cp_build_reference_type (type, /*rval=*/true);
- if (is_nothrow_xible (INIT_EXPR, type, arg))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, arg,
+ CPTK_IS_NOTHROW_CONSTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_assignable_type. */
static tree
-eval_is_nothrow_assignable_type (location_t loc, tree type1, tree type2)
+eval_is_nothrow_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_NOTHROW_ASSIGNABLE);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_NOTHROW_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_copy_assignable_type. */
static tree
-eval_is_nothrow_copy_assignable_type (tree type)
+eval_is_nothrow_copy_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
tree type1 = cp_build_reference_type (type, /*rval=*/false);
tree type2 = build_const_lref (type);
- if (is_nothrow_xible (MODIFY_EXPR, type1, type2))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_NOTHROW_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_move_assignable_type. */
static tree
-eval_is_nothrow_move_assignable_type (tree type)
+eval_is_nothrow_move_assignable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
tree type1 = cp_build_reference_type (type, /*rval=*/false);
tree type2 = cp_build_reference_type (type, /*rval=*/true);
- if (is_nothrow_xible (MODIFY_EXPR, type1, type2))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_NOTHROW_ASSIGNABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_destructible_type. */
static tree
-eval_is_nothrow_destructible_type (location_t loc, tree type)
+eval_is_nothrow_destructible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type, CPTK_IS_NOTHROW_DESTRUCTIBLE);
+ return eval_type_trait (loc, ctx, type, CPTK_IS_NOTHROW_DESTRUCTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_implicit_lifetime_type. */
static tree
-eval_is_implicit_lifetime_type (tree type)
+eval_is_implicit_lifetime_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (implicit_lifetime_type_p (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_IS_IMPLICIT_LIFETIME,
+ non_constant_p, fun);
}
/* Process std::meta::has_virtual_destructor. */
static tree
-eval_has_virtual_destructor (tree type)
+eval_has_virtual_destructor (location_t loc, const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p, tree fun)
{
- if (type_has_virtual_destructor (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_HAS_VIRTUAL_DESTRUCTOR,
+ non_constant_p, fun);
}
/* Process std::meta::has_unique_object_representations. */
static tree
-eval_has_unique_object_representations (tree type)
+eval_has_unique_object_representations (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type, bool *non_constant_p,
+ tree fun)
{
- if (type_has_unique_obj_representations (type))
- return boolean_true_node;
- else
- return boolean_false_node;
+ return eval_type_trait (loc, ctx, type, CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+ non_constant_p, fun);
}
/* Process std::meta::reference_constructs_from_temporary. */
static tree
-eval_reference_constructs_from_temporary (location_t loc, tree type1,
- tree type2)
+eval_reference_constructs_from_temporary (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type1, tree type2,
+ bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2,
- CPTK_REF_CONSTRUCTS_FROM_TEMPORARY);
+ return eval_type_trait (loc, ctx, type1, type2,
+ CPTK_REF_CONSTRUCTS_FROM_TEMPORARY,
+ non_constant_p, fun);
}
/* Process std::meta::reference_converts_from_temporary. */
static tree
-eval_reference_converts_from_temporary (location_t loc, tree type1, tree type2)
+eval_reference_converts_from_temporary (location_t loc,
+ const constexpr_ctx *ctx,
+ tree type1, tree type2,
+ bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_REF_CONVERTS_FROM_TEMPORARY);
+ return eval_type_trait (loc, ctx, type1, type2,
+ CPTK_REF_CONVERTS_FROM_TEMPORARY,
+ non_constant_p, fun);
}
/* Process std::meta::rank. */
@@ -4881,7 +4984,8 @@ eval_rank (tree type)
/* Process std::meta::extent. */
static tree
-eval_extent (location_t loc, tree type, tree i)
+eval_extent (location_t loc, const constexpr_ctx *ctx, tree type, tree i,
+ bool *non_constant_p, tree fun)
{
size_t rank = tree_to_uhwi (i);
while (rank && TREE_CODE (type) == ARRAY_TYPE)
@@ -4892,7 +4996,8 @@ eval_extent (location_t loc, tree type, tree i)
tree r;
if (rank
|| TREE_CODE (type) != ARRAY_TYPE
- || eval_is_bounded_array_type (loc, type) == boolean_false_node)
+ || eval_is_bounded_array_type (loc, ctx, type, non_constant_p,
+ fun) != boolean_true_node)
r = size_zero_node;
else
r = size_binop (PLUS_EXPR, TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
@@ -4904,69 +5009,90 @@ eval_extent (location_t loc, tree type, tree i)
/* Process std::meta::is_same_type. */
static tree
-eval_is_same_type (location_t loc, tree type1, tree type2)
+eval_is_same_type (location_t loc, const constexpr_ctx *ctx, tree type1,
+ tree type2, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_SAME);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_SAME,
+ non_constant_p, fun);
}
/* Process std::meta::is_base_of_type. */
static tree
-eval_is_base_of_type (location_t loc, tree type1, tree type2)
+eval_is_base_of_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p, tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_BASE_OF);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_BASE_OF,
+ non_constant_p, fun);
}
/* Process std::meta::is_virtual_base_of_type. */
static tree
-eval_is_virtual_base_of_type (location_t loc, tree type1, tree type2)
+eval_is_virtual_base_of_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_VIRTUAL_BASE_OF);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_VIRTUAL_BASE_OF,
+ non_constant_p, fun);
}
/* Process std::meta::is_convertible_type. */
static tree
-eval_is_convertible_type (location_t loc, tree type1, tree type2)
+eval_is_convertible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_CONVERTIBLE);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_CONVERTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_nothrow_convertible_type. */
static tree
-eval_is_nothrow_convertible_type (location_t loc, tree type1, tree type2)
+eval_is_nothrow_convertible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_NOTHROW_CONVERTIBLE);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_NOTHROW_CONVERTIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_layout_compatible_type. */
static tree
-eval_is_layout_compatible_type (location_t loc, tree type1, tree type2)
+eval_is_layout_compatible_type (location_t loc, const constexpr_ctx *ctx,
+ tree type1, tree type2, bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2, CPTK_IS_LAYOUT_COMPATIBLE);
+ return eval_type_trait (loc, ctx, type1, type2, CPTK_IS_LAYOUT_COMPATIBLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_pointer_interconvertible_base_of_type. */
static tree
eval_is_pointer_interconvertible_base_of_type (location_t loc,
- tree type1, tree type2)
+ const constexpr_ctx *ctx,
+ tree type1, tree type2,
+ bool *non_constant_p,
+ tree fun)
{
- return eval_type_trait (loc, type1, type2,
- CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF);
+ return eval_type_trait (loc, ctx, type1, type2,
+ CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF,
+ non_constant_p, fun);
}
/* Process std::meta::is_invocable_type. */
static tree
-eval_is_invocable_type (location_t loc, tree type, tree tvec)
+eval_is_invocable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, tree tvec, bool *non_constant_p,
+ tree fun)
{
- tree r = finish_trait_expr (loc, CPTK_IS_INVOCABLE, type, tvec);
- STRIP_ANY_LOCATION_WRAPPER (r);
- return r;
+ return eval_type_trait (loc, ctx, type, tvec, CPTK_IS_INVOCABLE,
+ non_constant_p, fun);
}
/* Helper for various eval_* type trait functions which can't use builtin
@@ -5039,11 +5165,12 @@ eval_is_invocable_r_type (location_t loc, const
constexpr_ctx *ctx,
/* Process std::meta::is_nothrow_invocable_type. */
static tree
-eval_is_nothrow_invocable_type (location_t loc, tree type, tree tvec)
+eval_is_nothrow_invocable_type (location_t loc, const constexpr_ctx *ctx,
+ tree type, tree tvec, bool *non_constant_p,
+ tree fun)
{
- tree r = finish_trait_expr (loc, CPTK_IS_NOTHROW_INVOCABLE, type, tvec);
- STRIP_ANY_LOCATION_WRAPPER (r);
- return r;
+ return eval_type_trait (loc, ctx, type, tvec, CPTK_IS_NOTHROW_INVOCABLE,
+ non_constant_p, fun);
}
/* Process std::meta::is_{,nothrow_}swappable_with_type. */
@@ -6087,8 +6214,10 @@ eval_data_member_spec (location_t loc, const
constexpr_ctx *ctx,
return throw_exception (loc, ctx, "reflection does not have a type",
fun, non_constant_p, jump_target);
tree type = type_of (r, kind);
- if (eval_is_array_type (loc, type) == boolean_true_node
- || eval_is_object_type (loc, type) == boolean_false_node)
+ if ((eval_is_array_type (loc, ctx, type, non_constant_p, fun)
+ == boolean_true_node)
+ || (eval_is_object_type (loc, ctx, type, non_constant_p, fun)
+ != boolean_true_node))
return throw_exception (loc, ctx, "reflection does not have "
"non-array object type",
fun, non_constant_p, jump_target);
@@ -7701,7 +7830,8 @@ eval_extract (location_t loc, const constexpr_ctx *ctx,
tree type, tree r,
reflect_kind kind, bool *non_constant_p, bool *overflow_p,
tree *jump_target, tree fun)
{
- if (eval_is_reference_type (loc, type) == boolean_true_node)
+ if (eval_is_reference_type (loc, ctx, type, non_constant_p, fun)
+ == boolean_true_node)
return extract_ref (loc, ctx, type, r, kind, non_constant_p, jump_target,
fun);
type = cv_unqualified (type);
@@ -8275,85 +8405,90 @@ process_metafunction (const constexpr_ctx *ctx, tree
fun, tree call,
case METAFN_IS_FLOATING_POINT_TYPE:
return eval_is_floating_point_type (h);
case METAFN_IS_ARRAY_TYPE:
- return eval_is_array_type (loc, h);
+ return eval_is_array_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_POINTER_TYPE:
- return eval_is_pointer_type (loc, h);
+ return eval_is_pointer_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_LVALUE_REFERENCE_TYPE:
return eval_is_lvalue_reference_type (h);
case METAFN_IS_RVALUE_REFERENCE_TYPE:
return eval_is_rvalue_reference_type (h);
case METAFN_IS_MEMBER_OBJECT_POINTER_TYPE:
- return eval_is_member_object_pointer_type (loc, h);
+ return eval_is_member_object_pointer_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_MEMBER_FUNCTION_POINTER_TYPE:
- return eval_is_member_function_pointer_type (loc, h);
+ return eval_is_member_function_pointer_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_ENUM_TYPE:
- return eval_is_enum_type (loc, h);
+ return eval_is_enum_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_UNION_TYPE:
- return eval_is_union_type (loc, h);
+ return eval_is_union_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_CLASS_TYPE:
- return eval_is_class_type (loc, h);
+ return eval_is_class_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_FUNCTION_TYPE:
return eval_is_function_type (h);
case METAFN_IS_REFLECTION_TYPE:
return eval_is_reflection_type (h);
case METAFN_IS_REFERENCE_TYPE:
- return eval_is_reference_type (loc, h);
+ return eval_is_reference_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_ARITHMETIC_TYPE:
return eval_is_arithmetic_type (h);
case METAFN_IS_FUNDAMENTAL_TYPE:
return eval_is_fundamental_type (h);
case METAFN_IS_OBJECT_TYPE:
- return eval_is_object_type (loc, h);
+ return eval_is_object_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_SCALAR_TYPE:
return eval_is_scalar_type (h);
case METAFN_IS_COMPOUND_TYPE:
return eval_is_compound_type (h);
case METAFN_IS_MEMBER_POINTER_TYPE:
- return eval_is_member_pointer_type (loc, h);
+ return eval_is_member_pointer_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_CONST_TYPE:
return eval_is_const_type (h);
case METAFN_IS_VOLATILE_TYPE:
return eval_is_volatile_type (h);
case METAFN_IS_TRIVIALLY_COPYABLE_TYPE:
- return eval_is_trivially_copyable_type (h);
+ return eval_is_trivially_copyable_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_STANDARD_LAYOUT_TYPE:
- return eval_is_standard_layout_type (h);
+ return eval_is_standard_layout_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_EMPTY_TYPE:
- return eval_is_empty_type (loc, h);
+ return eval_is_empty_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_POLYMORPHIC_TYPE:
- return eval_is_polymorphic_type (loc, h);
+ return eval_is_polymorphic_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_ABSTRACT_TYPE:
- return eval_is_abstract_type (h);
+ return eval_is_abstract_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_FINAL_TYPE:
- return eval_is_final_type (loc, h);
+ return eval_is_final_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_AGGREGATE_TYPE:
- return eval_is_aggregate_type (h);
+ return eval_is_aggregate_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_STRUCTURAL_TYPE:
- return eval_is_structural_type (loc, h);
+ return eval_is_structural_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_SIGNED_TYPE:
return eval_is_signed_type (h);
case METAFN_IS_UNSIGNED_TYPE:
return eval_is_unsigned_type (h);
case METAFN_IS_BOUNDED_ARRAY_TYPE:
- return eval_is_bounded_array_type (loc, h);
+ return eval_is_bounded_array_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_UNBOUNDED_ARRAY_TYPE:
return eval_is_unbounded_array_type (h);
case METAFN_IS_SCOPED_ENUM_TYPE:
return eval_is_scoped_enum_type (h);
case METAFN_IS_CONSTRUCTIBLE_TYPE:
- return eval_is_constructible_type (h, hvec);
+ return eval_is_constructible_type (loc, ctx, h, hvec, non_constant_p,
+ fun);
case METAFN_IS_DEFAULT_CONSTRUCTIBLE_TYPE:
- return eval_is_default_constructible_type (h);
+ return eval_is_default_constructible_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_COPY_CONSTRUCTIBLE_TYPE:
- return eval_is_copy_constructible_type (h);
+ return eval_is_copy_constructible_type (loc, ctx, h, non_constant_p,
fun);
case METAFN_IS_MOVE_CONSTRUCTIBLE_TYPE:
- return eval_is_move_constructible_type (h);
+ return eval_is_move_constructible_type (loc, ctx, h, non_constant_p,
fun);
case METAFN_IS_ASSIGNABLE_TYPE:
- return eval_is_assignable_type (loc, h, h1);
+ return eval_is_assignable_type (loc, ctx, h, h1, non_constant_p, fun);
case METAFN_IS_COPY_ASSIGNABLE_TYPE:
- return eval_is_copy_assignable_type (h);
+ return eval_is_copy_assignable_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_MOVE_ASSIGNABLE_TYPE:
- return eval_is_move_assignable_type (h);
+ return eval_is_move_assignable_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_SWAPPABLE_WITH_TYPE:
return eval_is_swappable_with_type (loc, ctx, h, h1, call,
non_constant_p, jump_target, fun,
@@ -8362,37 +8497,53 @@ process_metafunction (const constexpr_ctx *ctx, tree
fun, tree call,
return eval_is_swappable_type (loc, ctx, h, call, non_constant_p,
jump_target, fun, "is_swappable");
case METAFN_IS_DESTRUCTIBLE_TYPE:
- return eval_is_destructible_type (loc, h);
+ return eval_is_destructible_type (loc, ctx, h, non_constant_p, fun);
case METAFN_IS_TRIVIALLY_CONSTRUCTIBLE_TYPE:
- return eval_is_trivially_constructible_type (h, hvec);
+ return eval_is_trivially_constructible_type (loc, ctx, h, hvec,
+ non_constant_p, fun);
case METAFN_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_TYPE:
- return eval_is_trivially_default_constructible_type (h);
+ return eval_is_trivially_default_constructible_type (loc, ctx, h,
+ non_constant_p,
+ fun);
case METAFN_IS_TRIVIALLY_COPY_CONSTRUCTIBLE_TYPE:
- return eval_is_trivially_copy_constructible_type (h);
+ return eval_is_trivially_copy_constructible_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE_TYPE:
- return eval_is_trivially_move_constructible_type (h);
+ return eval_is_trivially_move_constructible_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_TRIVIALLY_ASSIGNABLE_TYPE:
- return eval_is_trivially_assignable_type (loc, h, h1);
+ return eval_is_trivially_assignable_type (loc, ctx, h, h1,
+ non_constant_p, fun);
case METAFN_IS_TRIVIALLY_COPY_ASSIGNABLE_TYPE:
- return eval_is_trivially_copy_assignable_type (h);
+ return eval_is_trivially_copy_assignable_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_TRIVIALLY_MOVE_ASSIGNABLE_TYPE:
- return eval_is_trivially_move_assignable_type (h);
+ return eval_is_trivially_move_assignable_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_TRIVIALLY_DESTRUCTIBLE_TYPE:
- return eval_is_trivially_destructible_type (loc, h);
+ return eval_is_trivially_destructible_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_NOTHROW_CONSTRUCTIBLE_TYPE:
- return eval_is_nothrow_constructible_type (h, hvec);
+ return eval_is_nothrow_constructible_type (loc, ctx, h, hvec,
+ non_constant_p, fun);
case METAFN_IS_NOTHROW_DEFAULT_CONSTRUCTIBLE_TYPE:
- return eval_is_nothrow_default_constructible_type (h);
+ return eval_is_nothrow_default_constructible_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_NOTHROW_COPY_CONSTRUCTIBLE_TYPE:
- return eval_is_nothrow_copy_constructible_type (h);
+ return eval_is_nothrow_copy_constructible_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_NOTHROW_MOVE_CONSTRUCTIBLE_TYPE:
- return eval_is_nothrow_move_constructible_type (h);
+ return eval_is_nothrow_move_constructible_type (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_IS_NOTHROW_ASSIGNABLE_TYPE:
- return eval_is_nothrow_assignable_type (loc, h, h1);
+ return eval_is_nothrow_assignable_type (loc, ctx, h, h1, non_constant_p,
+ fun);
case METAFN_IS_NOTHROW_COPY_ASSIGNABLE_TYPE:
- return eval_is_nothrow_copy_assignable_type (h);
+ return eval_is_nothrow_copy_assignable_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_NOTHROW_MOVE_ASSIGNABLE_TYPE:
- return eval_is_nothrow_move_assignable_type (h);
+ return eval_is_nothrow_move_assignable_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_NOTHROW_SWAPPABLE_WITH_TYPE:
return eval_is_swappable_with_type (loc, ctx, h, h1, call,
non_constant_p, jump_target, fun,
@@ -8401,43 +8552,53 @@ process_metafunction (const constexpr_ctx *ctx, tree
fun, tree call,
return eval_is_swappable_type (loc, ctx, h, call, non_constant_p,
jump_target, fun, "is_nothrow_swappable");
case METAFN_IS_NOTHROW_DESTRUCTIBLE_TYPE:
- return eval_is_nothrow_destructible_type (loc, h);
+ return eval_is_nothrow_destructible_type (loc, ctx, h, non_constant_p,
+ fun);
case METAFN_IS_IMPLICIT_LIFETIME_TYPE:
- return eval_is_implicit_lifetime_type (h);
+ return eval_is_implicit_lifetime_type (loc, ctx, h, non_constant_p, fun);
case METAFN_HAS_VIRTUAL_DESTRUCTOR:
- return eval_has_virtual_destructor (h);
+ return eval_has_virtual_destructor (loc, ctx, h, non_constant_p, fun);
case METAFN_HAS_UNIQUE_OBJECT_REPRESENTATIONS:
- return eval_has_unique_object_representations (h);
+ return eval_has_unique_object_representations (loc, ctx, h,
+ non_constant_p, fun);
case METAFN_REFERENCE_CONSTRUCTS_FROM_TEMPORARY:
- return eval_reference_constructs_from_temporary (loc, h, h1);
+ return eval_reference_constructs_from_temporary (loc, ctx, h, h1,
+ non_constant_p, fun);
case METAFN_REFERENCE_CONVERTS_FROM_TEMPORARY:
- return eval_reference_converts_from_temporary (loc, h, h1);
+ return eval_reference_converts_from_temporary (loc, ctx, h, h1,
+ non_constant_p, fun);
case METAFN_RANK:
return eval_rank (h);
case METAFN_EXTENT:
- return eval_extent (loc, h, expr);
+ return eval_extent (loc, ctx, h, expr, non_constant_p, fun);
case METAFN_IS_SAME_TYPE:
- return eval_is_same_type (loc, h, h1);
+ return eval_is_same_type (loc, ctx, h, h1, non_constant_p, fun);
case METAFN_IS_BASE_OF_TYPE:
- return eval_is_base_of_type (loc, h, h1);
+ return eval_is_base_of_type (loc, ctx, h, h1, non_constant_p, fun);
case METAFN_IS_VIRTUAL_BASE_OF_TYPE:
- return eval_is_virtual_base_of_type (loc, h, h1);
+ return eval_is_virtual_base_of_type (loc, ctx, h, h1, non_constant_p,
+ fun);
case METAFN_IS_CONVERTIBLE_TYPE:
- return eval_is_convertible_type (loc, h, h1);
+ return eval_is_convertible_type (loc, ctx, h, h1, non_constant_p, fun);
case METAFN_IS_NOTHROW_CONVERTIBLE_TYPE:
- return eval_is_nothrow_convertible_type (loc, h, h1);
+ return eval_is_nothrow_convertible_type (loc, ctx, h, h1, non_constant_p,
+ fun);
case METAFN_IS_LAYOUT_COMPATIBLE_TYPE:
- return eval_is_layout_compatible_type (loc, h, h1);
+ return eval_is_layout_compatible_type (loc, ctx, h, h1, non_constant_p,
+ fun);
case METAFN_IS_POINTER_INTERCONVERTIBLE_BASE_OF_TYPE:
- return eval_is_pointer_interconvertible_base_of_type (loc, h, h1);
+ return eval_is_pointer_interconvertible_base_of_type (loc, ctx, h, h1,
+ non_constant_p,
+ fun);
case METAFN_IS_INVOCABLE_TYPE:
- return eval_is_invocable_type (loc, h, hvec);
+ return eval_is_invocable_type (loc, ctx, h, hvec, non_constant_p, fun);
case METAFN_IS_INVOCABLE_R_TYPE:
return eval_is_invocable_r_type (loc, ctx, h, h1, hvec, call,
non_constant_p, jump_target, fun,
"is_invocable_r");
case METAFN_IS_NOTHROW_INVOCABLE_TYPE:
- return eval_is_nothrow_invocable_type (loc, h, hvec);
+ return eval_is_nothrow_invocable_type (loc, ctx, h, hvec, non_constant_p,
+ fun);
case METAFN_IS_NOTHROW_INVOCABLE_R_TYPE:
return eval_is_invocable_r_type (loc, ctx, h, h1, hvec, call,
non_constant_p, jump_target, fun,
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 3a7e19c190a..4806acbcdc6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -14286,10 +14286,13 @@ trait_expr_value (cp_trait_kind kind, tree type1,
tree type2)
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. */
+ If TYPE is a class type, it must be complete.
+
+ If COMPLAIN is not tf_none, we permerror and return false if that doesn't
+ produce a hard error. */
static bool
-check_trait_type (tree type, int kind = 1)
+check_trait_type (tree type, int kind, tsubst_flags_t complain)
{
if (type == NULL_TREE)
return true;
@@ -14297,7 +14300,7 @@ check_trait_type (tree type, int kind = 1)
if (TREE_CODE (type) == TREE_VEC)
{
for (tree arg : tree_vec_range (type))
- if (!check_trait_type (arg, kind))
+ if (!check_trait_type (arg, kind, complain))
return false;
return true;
}
@@ -14316,9 +14319,12 @@ check_trait_type (tree type, int kind = 1)
type = complete_type (strip_array_types (type));
if (!COMPLETE_TYPE_P (type)
- && cxx_incomplete_type_diagnostic (NULL_TREE, type,
- diagnostics::kind::permerror)
- && !flag_permissive)
+ /* If we're not emitting error messages, always return false for
+ incomplete types. */
+ && (complain == tf_none
+ || (cxx_incomplete_type_diagnostic (NULL_TREE, type,
+ diagnostics::kind::permerror)
+ && !flag_permissive)))
return false;
return true;
}
@@ -14388,7 +14394,8 @@ finish_structured_binding_size (location_t loc, tree
type,
/* Process a trait expression. */
tree
-finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
+finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2,
+ tsubst_flags_t complain/*=tf_warning_or_error*/)
{
if (type1 == error_mark_node
|| type2 == error_mark_node)
@@ -14426,7 +14433,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind,
tree type1, tree type2)
case CPTK_IS_DESTRUCTIBLE:
case CPTK_IS_NOTHROW_DESTRUCTIBLE:
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
- if (!check_trait_type (type1))
+ if (!check_trait_type (type1, /*kind=*/1, complain))
return error_mark_node;
break;
@@ -14437,7 +14444,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind,
tree type1, tree type2)
case CPTK_IS_TRIVIALLY_COPYABLE:
case CPTK_IS_STRUCTURAL:
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
- if (!check_trait_type (type1, /* kind = */ 2))
+ if (!check_trait_type (type1, /* kind = */ 2, complain))
return error_mark_node;
break;
@@ -14445,7 +14452,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind,
tree type1, tree type2)
case CPTK_IS_EMPTY:
case CPTK_IS_POLYMORPHIC:
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
- if (!check_trait_type (type1, /* kind = */ 3))
+ if (!check_trait_type (type1, /* kind = */ 3, complain))
return error_mark_node;
break;
@@ -14454,7 +14461,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind,
tree type1, tree type2)
case CPTK_IS_AGGREGATE:
case CPTK_IS_FINAL:
case CPTK_IS_IMPLICIT_LIFETIME:
- if (!check_trait_type (type1, /* kind = */ 4))
+ if (!check_trait_type (type1, /* kind = */ 4, complain))
return error_mark_node;
break;
@@ -14475,8 +14482,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind,
tree type1, tree type2)
case CPTK_IS_ASSIGNABLE:
case CPTK_IS_NOTHROW_ASSIGNABLE:
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
- if (!check_trait_type (type1)
- || !check_trait_type (type2))
+ if (!check_trait_type (type1, /*kind=*/1, complain)
+ || !check_trait_type (type2, /*kind=*/1, complain))
return error_mark_node;
break;
@@ -14484,14 +14491,14 @@ finish_trait_expr (location_t loc, cp_trait_kind
kind, tree type1, tree type2)
case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
&& !same_type_ignoring_top_level_qualifiers_p (type1, type2)
- && !complete_type_or_else (type2, NULL_TREE))
+ && !complete_type_or_maybe_complain (type2, NULL_TREE, complain))
/* We already issued an error. */
return error_mark_node;
break;
case CPTK_IS_VIRTUAL_BASE_OF:
if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
- && !complete_type_or_else (type2, NULL_TREE))
+ && !complete_type_or_maybe_complain (type2, NULL_TREE, complain))
/* We already issued an error. */
return error_mark_node;
break;
@@ -14528,17 +14535,17 @@ finish_trait_expr (location_t loc, cp_trait_kind
kind, tree type1, tree type2)
return maybe_wrap_with_location (type_order_value (type1, type2), loc);
case CPTK_STRUCTURED_BINDING_SIZE:
- return finish_structured_binding_size (loc, type1, tf_warning_or_error);
+ return finish_structured_binding_size (loc, type1, complain);
case CPTK_IS_LAYOUT_COMPATIBLE:
if (!array_of_unknown_bound_p (type1)
&& TREE_CODE (type1) != VOID_TYPE
- && !complete_type_or_else (type1, NULL_TREE))
+ && !complete_type_or_maybe_complain (type1, NULL_TREE, complain))
/* We already issued an error. */
return error_mark_node;
if (!array_of_unknown_bound_p (type2)
&& TREE_CODE (type2) != VOID_TYPE
- && !complete_type_or_else (type2, NULL_TREE))
+ && !complete_type_or_maybe_complain (type2, NULL_TREE, complain))
/* We already issued an error. */
return error_mark_node;
break;
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait16.C
b/gcc/testsuite/g++.dg/reflect/type_trait16.C
new file mode 100644
index 00000000000..5fca8658f1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/type_trait16.C
@@ -0,0 +1,37 @@
+// PR c++/125901
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template<typename T>
+struct S {
+ T t;
+};
+
+static_assert(is_trivially_copyable_type(^^S<int>));
+static_assert(!is_trivially_copyable_type(^^std::vector<int>));
+static_assert(is_standard_layout_type(^^std::vector<int>));
+static_assert(is_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_copy_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_move_constructible_type(^^std::vector<int>));
+static_assert(is_copy_assignable_type(^^std::vector<int>));
+static_assert(!is_implicit_lifetime_type(^^std::vector<int>));
+static_assert(!has_virtual_destructor(^^std::vector<int>));
+static_assert(!has_unique_object_representations(^^std::vector<int>));
+
+const std::vector<int> vec{};
+const S<int> s{};
+
+static_assert(is_trivially_copyable_type(^^S<int>));
+static_assert(!is_trivially_copyable_type(^^std::vector<int>));
+static_assert(is_standard_layout_type(^^std::vector<int>));
+static_assert(is_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_copy_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_move_constructible_type(^^std::vector<int>));
+static_assert(is_copy_assignable_type(^^std::vector<int>));
+static_assert(!is_implicit_lifetime_type(^^std::vector<int>));
+static_assert(!has_virtual_destructor(^^std::vector<int>));
+static_assert(!has_unique_object_representations(^^std::vector<int>));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait17.C
b/gcc/testsuite/g++.dg/reflect/type_trait17.C
new file mode 100644
index 00000000000..2a2c2ddeb78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/type_trait17.C
@@ -0,0 +1,315 @@
+// PR c++/125901
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// [meta.unary.prop]
+
+#include <meta>
+
+template<typename>
+struct S;
+union U;
+
+// remove_all_extents_t<T> shall be a complete type or cv void.
+constexpr bool b0 = is_trivially_copyable_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b1 = is_trivially_copyable_type (^^S<int>[1]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b0u = is_trivially_copyable_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b1u = is_trivially_copyable_type (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_trivially_copyable_type (^^void));
+
+constexpr bool b2 = is_standard_layout_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b3 = is_standard_layout_type (^^S<int>[1]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b2u = is_standard_layout_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b3u = is_standard_layout_type (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_standard_layout_type (^^void));
+
+constexpr bool b11 = is_structural_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b12 = is_structural_type (^^S<int>[1]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b11u = is_structural_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b12u = is_structural_type (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_structural_type (^^void));
+
+// If T is a non-union class type, T shall be a complete type.
+constexpr bool b4 = is_empty_type (^^S<int>); // { dg-error "preconditions
not satisfied" }
+static_assert (!is_empty_type (^^S<int>[1]));
+static_assert (!is_empty_type (^^U));
+static_assert (!is_empty_type (^^U[1]));
+static_assert (!is_empty_type (^^void));
+
+constexpr bool b5 = is_polymorphic_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_polymorphic_type (^^S<int>[1]));
+static_assert (!is_polymorphic_type (^^U));
+static_assert (!is_polymorphic_type (^^U[1]));
+static_assert (!is_polymorphic_type (^^void));
+
+constexpr bool b6 = is_abstract_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_abstract_type (^^S<int>[1]));
+static_assert (!is_abstract_type (^^U));
+static_assert (!is_abstract_type (^^U[1]));
+static_assert (!is_abstract_type (^^void));
+
+// If T is a class type, T shall be a complete type.
+constexpr bool b7 = is_final_type (^^S<int>); // { dg-error "preconditions
not satisfied" }
+constexpr bool b8 = is_final_type (^^U); // { dg-error "preconditions
not satisfied" }
+static_assert (!is_final_type (^^S<int>[1]));
+static_assert (!is_final_type (^^U[1]));
+static_assert (!is_final_type (^^void));
+
+// T shall be an array type, a complete type, or cv void.
+static_assert (is_aggregate_type (^^S<int>[1]));
+static_assert (is_aggregate_type (^^U[]));
+static_assert (is_aggregate_type (^^S<int>[]));
+static_assert (is_aggregate_type (^^U[1]));
+static_assert (!is_aggregate_type (^^void));
+constexpr bool b9 = is_aggregate_type (^^S<int>); // { dg-error "preconditions
not satisfied" }
+constexpr bool b10 = is_aggregate_type (^^U); // { dg-error "preconditions
not satisfied" }
+
+// T and all types in the template parameter pack Args shall be
+// complete types, cv void, or arrays of unknown bound.
+constexpr bool b13 = is_constructible_type (^^S<int>, { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b14 = is_constructible_type (^^int, { ^^S<int> }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b13a = is_constructible_type (^^S<int>[1], { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b14a = is_constructible_type (^^int, { ^^S<int>[1] }); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_constructible_type (^^S<int>[], { ^^int }));
+static_assert (!is_constructible_type (^^int, { ^^S<int>[] }));
+constexpr bool b15 = is_constructible_type (^^U, { ^^int }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b16 = is_constructible_type (^^int, { ^^U }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b15a = is_constructible_type (^^U[1], { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b16a = is_constructible_type (^^int, { ^^U[1] }); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_constructible_type (^^U[], { ^^int }));
+static_assert (!is_constructible_type (^^int, { ^^U[] }));
+static_assert (!is_constructible_type (^^int, { ^^void }));
+
+// T shall be a complete type, cv void, or an array of unknown bound.
+constexpr bool b17 = is_default_constructible_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b18 = is_default_constructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b19 = is_default_constructible_type (^^S<int>[1]); // {
dg-error "preconditions not satisfied" }
+constexpr bool b20 = is_default_constructible_type (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_default_constructible_type (^^S<int>[]));
+static_assert (!is_default_constructible_type (^^U[]));
+static_assert (!is_default_constructible_type (^^void));
+
+constexpr bool b21 = is_copy_constructible_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b22 = is_copy_constructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b23 = is_copy_constructible_type (^^S<int>[1]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b24 = is_copy_constructible_type (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_copy_constructible_type (^^S<int>[]));
+static_assert (!is_copy_constructible_type (^^U[]));
+static_assert (!is_copy_constructible_type (^^void));
+
+constexpr bool b25 = is_move_constructible_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b26 = is_move_constructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b27 = is_move_constructible_type (^^S<int>[1]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b28 = is_move_constructible_type (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_move_constructible_type (^^S<int>[]));
+static_assert (!is_move_constructible_type (^^U[]));
+static_assert (!is_move_constructible_type (^^void));
+
+// T and U shall be complete types, cv void, or arrays of unknown bound.
+constexpr bool b29 = is_assignable_type (^^S<int>, ^^int); // { dg-error
"preconditions not satisfied" }
+constexpr bool b30 = is_assignable_type (^^int, ^^S<int>); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_assignable_type (^^S<int>[], ^^int));
+static_assert (!is_assignable_type (^^int, ^^S<int>[]));
+static_assert (!is_assignable_type (^^void, ^^int));
+static_assert (!is_assignable_type (^^int, ^^void));
+
+// T shall be a complete type, cv void, or an array of unknown bound.
+constexpr bool b31 = is_copy_assignable_type (^^S<int>); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+constexpr bool b31u = is_copy_assignable_type (^^U); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+static_assert (!is_copy_assignable_type (^^S<int>[]));
+static_assert (!is_copy_assignable_type (^^U[]));
+static_assert (!is_copy_assignable_type (^^void));
+
+constexpr bool b32 = is_move_assignable_type (^^S<int>); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+constexpr bool b32u = is_move_assignable_type (^^U); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+static_assert (!is_move_assignable_type (^^S<int>[]));
+static_assert (!is_move_assignable_type (^^U[]));
+static_assert (!is_move_assignable_type (^^void));
+
+// T and U shall be complete types, cv void, or arrays of unknown bound.
+constexpr bool b33 = is_swappable_with_type (^^S<int>, ^^int); // { dg-message
"required from here" }
+constexpr bool b34 = is_swappable_with_type (^^int, ^^S<int>); // { dg-message
"required from here" }
+constexpr bool b33u = is_swappable_with_type (^^U, ^^int); // { dg-message
"required from here" }
+constexpr bool b34u = is_swappable_with_type (^^int, ^^U); // { dg-message
"required from here" }
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+static_assert (!is_swappable_with_type (^^S<int>[], ^^int));
+static_assert (!is_swappable_with_type (^^int, ^^S<int>[]));
+static_assert (!is_swappable_with_type (^^U[], ^^int));
+static_assert (!is_swappable_with_type (^^int, ^^U[]));
+static_assert (!is_swappable_with_type (^^void, ^^int));
+static_assert (!is_swappable_with_type (^^int, ^^void));
+
+constexpr bool b33n = is_nothrow_swappable_with_type (^^S<int>, ^^int);
// { dg-message "required from here" }
+constexpr bool b34n = is_nothrow_swappable_with_type (^^int, ^^S<int>);
// { dg-message "required from here" }
+static_assert (!is_nothrow_swappable_with_type (^^S<int>[], ^^int));
+static_assert (!is_nothrow_swappable_with_type (^^int, ^^S<int>[]));
+static_assert (!is_nothrow_swappable_with_type (^^void, ^^int));
+static_assert (!is_nothrow_swappable_with_type (^^int, ^^void));
+
+struct W;
+constexpr bool b35 = is_swappable_type (^^W); // { dg-message "required from
here" }
+static_assert (!is_swappable_type (^^S<int>[]));
+static_assert (!is_swappable_type (^^void));
+constexpr bool b35n = is_nothrow_swappable_type (^^W); // { dg-message
"required from here" }
+static_assert (!is_nothrow_swappable_type (^^S<int>[]));
+static_assert (!is_nothrow_swappable_type (^^void));
+// { dg-error "invalid use of incomplete type .struct W." "" { target *-*-* }
0 }
+
+//T shall be a complete type, cv void, or an array of unknown bound.
+constexpr bool b36 = is_destructible_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b36u = is_destructible_type (^^U); // { dg-error "preconditions
not satisfied" }
+static_assert (!is_destructible_type (^^S<int>[]));
+static_assert (!is_destructible_type (^^void));
+
+constexpr bool b36n = is_nothrow_destructible_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b36nu = is_nothrow_destructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_nothrow_destructible_type (^^S<int>[]));
+static_assert (!is_nothrow_destructible_type (^^U[]));
+static_assert (!is_nothrow_destructible_type (^^void));
+
+// T and all types in the template parameter pack Args shall be complete
+// types, cv void, or arrays of unknown bound.
+constexpr bool b37 = is_trivially_constructible_type (^^S<int>, {}); // {
dg-error "preconditions not satisfied" }
+constexpr bool b38 = is_trivially_constructible_type (^^int, { ^^S<int> });
// { dg-error "preconditions not satisfied" }
+static_assert (!is_trivially_constructible_type (^^S<int>[], {}));
+static_assert (!is_trivially_constructible_type (^^int, { ^^S<int>[] }));
+static_assert (!is_trivially_constructible_type (^^void, {}));
+static_assert (!is_trivially_constructible_type (^^int, { ^^void }));
+
+// T shall be a complete type, cv void, or an array of unknown bound.
+constexpr bool b39 = is_trivially_default_constructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b39u = is_trivially_default_constructible_type (^^U); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_trivially_default_constructible_type (^^S<int>[]));
+static_assert (!is_trivially_default_constructible_type (^^U[]));
+static_assert (!is_trivially_default_constructible_type (^^void));
+
+constexpr bool b40 = is_trivially_copy_constructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b40u = is_trivially_copy_constructible_type (^^U); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_trivially_copy_constructible_type (^^S<int>[]));
+static_assert (!is_trivially_copy_constructible_type (^^U[]));
+static_assert (!is_trivially_copy_constructible_type (^^void));
+
+constexpr bool b41 = is_trivially_move_constructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b41u = is_trivially_move_constructible_type (^^U); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_trivially_move_constructible_type (^^S<int>[]));
+static_assert (!is_trivially_move_constructible_type (^^U[]));
+static_assert (!is_trivially_move_constructible_type (^^void));
+
+// T and U shall be complete types, cv void, or arrays of unknown bound.
+constexpr bool b42 = is_trivially_assignable_type (^^S<int>, ^^int); // {
dg-error "preconditions not satisfied" }
+constexpr bool b43 = is_trivially_assignable_type (^^int, ^^S<int>); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_trivially_assignable_type (^^S<int>[], ^^int));
+static_assert (!is_trivially_assignable_type (^^int, ^^S<int>[]));
+static_assert (!is_trivially_assignable_type (^^void, ^^int));
+static_assert (!is_trivially_assignable_type (^^int, ^^void));
+
+// T shall be a complete type, cv void, or an array of unknown bound.
+constexpr bool b44 = is_trivially_copy_assignable_type (^^S<int>); // {
dg-error "preconditions not satisfied" "PR126073" { xfail *-*-* } }
+constexpr bool b44u = is_trivially_copy_assignable_type (^^U); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+static_assert (!is_trivially_copy_assignable_type (^^S<int>[]));
+static_assert (!is_trivially_copy_assignable_type (^^U[]));
+static_assert (!is_trivially_copy_assignable_type (^^void));
+
+constexpr bool b45 = is_trivially_move_assignable_type (^^S<int>); // {
dg-error "preconditions not satisfied" "PR126073" { xfail *-*-* } }
+constexpr bool b45u = is_trivially_move_assignable_type (^^U); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+static_assert (!is_trivially_move_assignable_type (^^S<int>[]));
+static_assert (!is_trivially_move_assignable_type (^^U[]));
+static_assert (!is_trivially_move_assignable_type (^^void));
+
+constexpr bool b46 = is_trivially_destructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b46u = is_trivially_destructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_trivially_destructible_type (^^S<int>[]));
+static_assert (!is_trivially_destructible_type (^^U[]));
+static_assert (!is_trivially_destructible_type (^^void));
+
+// T and all types in the template parameter pack Args shall be complete
+// types, cv void, or arrays of unknown bound.
+constexpr bool b47 = is_nothrow_constructible_type (^^S<int>, { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b48 = is_nothrow_constructible_type (^^int, { ^^S<int> }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b49 = is_nothrow_constructible_type (^^S<int>[1], { ^^int });
// { dg-error "preconditions not satisfied" }
+constexpr bool b50 = is_nothrow_constructible_type (^^int, { ^^S<int>[1] });
// { dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_constructible_type (^^S<int>[], { ^^int }));
+static_assert (!is_nothrow_constructible_type (^^int, { ^^S<int>[] }));
+constexpr bool b51 = is_nothrow_constructible_type (^^U, { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b52 = is_nothrow_constructible_type (^^int, { ^^U }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b53 = is_nothrow_constructible_type (^^U[1], { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b54 = is_nothrow_constructible_type (^^int, { ^^U[1] }); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_constructible_type (^^U[], { ^^int }));
+static_assert (!is_nothrow_constructible_type (^^int, { ^^U[] }));
+static_assert (!is_nothrow_constructible_type (^^int, { ^^void }));
+
+// T shall be a complete type, cv void, or an array of unknown bound.
+constexpr bool b55 = is_nothrow_default_constructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b56 = is_nothrow_default_constructible_type (^^S<int>[1]); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_default_constructible_type (^^S<int>[]));
+constexpr bool b57 = is_nothrow_default_constructible_type (^^U); // {
dg-error "preconditions not satisfied" }
+constexpr bool b58 = is_nothrow_default_constructible_type (^^U[1]); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_default_constructible_type (^^U[]));
+static_assert (!is_nothrow_default_constructible_type (^^void));
+
+constexpr bool b59 = is_nothrow_copy_constructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b60 = is_nothrow_copy_constructible_type (^^S<int>[1]); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_copy_constructible_type (^^S<int>[]));
+constexpr bool b61 = is_nothrow_copy_constructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b62 = is_nothrow_copy_constructible_type (^^U[1]); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_copy_constructible_type (^^U[]));
+static_assert (!is_nothrow_copy_constructible_type (^^void));
+
+constexpr bool b63 = is_nothrow_move_constructible_type (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b64 = is_nothrow_move_constructible_type (^^S<int>[1]); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_move_constructible_type (^^S<int>[]));
+constexpr bool b65 = is_nothrow_move_constructible_type (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b66 = is_nothrow_move_constructible_type (^^U[1]); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_move_constructible_type (^^U[]));
+static_assert (!is_nothrow_move_constructible_type (^^void));
+
+constexpr bool b67 = is_nothrow_assignable_type (^^S<int>, ^^int); // {
dg-error "preconditions not satisfied" }
+constexpr bool b68 = is_nothrow_assignable_type (^^int, ^^S<int>); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_assignable_type (^^S<int>[], ^^int));
+static_assert (!is_nothrow_assignable_type (^^int, ^^S<int>[]));
+static_assert (!is_nothrow_assignable_type (^^void, ^^int));
+static_assert (!is_nothrow_assignable_type (^^int, ^^void));
+
+constexpr bool b69 = is_nothrow_copy_assignable_type (^^S<int>); // {
dg-error "preconditions not satisfied" "PR126073" { xfail *-*-* } }
+constexpr bool b70 = is_nothrow_copy_assignable_type (^^U); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+static_assert (!is_nothrow_copy_assignable_type (^^S<int>[]));
+static_assert (!is_nothrow_copy_assignable_type (^^void));
+
+constexpr bool b71 = is_nothrow_move_assignable_type (^^S<int>); // {
dg-error "preconditions not satisfied" "PR126073" { xfail *-*-* } }
+constexpr bool b72 = is_nothrow_move_assignable_type (^^U); // { dg-error
"preconditions not satisfied" "PR126073" { xfail *-*-* } }
+static_assert (!is_nothrow_move_assignable_type (^^S<int>[]));
+static_assert (!is_nothrow_move_assignable_type (^^void));
+
+// T shall be an array type, a complete type, or cv void.
+constexpr bool b73 = is_implicit_lifetime_type (^^S<int>); // { dg-error
"preconditions not satisfied" }
+constexpr bool b74 = is_implicit_lifetime_type (^^U); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_implicit_lifetime_type (^^S<int>[1]));
+static_assert (!is_implicit_lifetime_type (^^void));
+
+// If T is a non-union class type, T shall be a complete type.
+constexpr bool b75 = has_virtual_destructor (^^S<int>); // { dg-error
"preconditions not satisfied" }
+static_assert (!has_virtual_destructor (^^S<int>[1]));
+static_assert (!has_virtual_destructor (^^U));
+static_assert (!has_virtual_destructor (^^U[1]));
+static_assert (!has_virtual_destructor (^^void));
+
+// remove_all_extents_t<T> shall be a complete type or cv void.
+constexpr bool b76 = has_unique_object_representations (^^S<int>); // {
dg-error "preconditions not satisfied" }
+constexpr bool b77 = has_unique_object_representations (^^S<int>[1]); // {
dg-error "preconditions not satisfied" }
+constexpr bool b78 = has_unique_object_representations (^^U); // { dg-error
"preconditions not satisfied" }
+constexpr bool b79 = has_unique_object_representations (^^U[1]); // { dg-error
"preconditions not satisfied" }
+static_assert (!has_unique_object_representations (^^void));
+
+// T and U shall be complete types, cv void, or arrays of unknown bound.
+constexpr bool b80 = reference_constructs_from_temporary (^^S<int>, ^^int);
// { dg-error "preconditions not satisfied" }
+constexpr bool b81 = reference_constructs_from_temporary (^^int, ^^S<int>);
// { dg-error "preconditions not satisfied" }
+static_assert (!reference_constructs_from_temporary (^^S<int>[], ^^int));
+static_assert (!reference_constructs_from_temporary (^^int, ^^S<int>[]));
+static_assert (!reference_constructs_from_temporary (^^void, ^^int));
+static_assert (!reference_constructs_from_temporary (^^int, ^^void));
+
+constexpr bool b82 = reference_converts_from_temporary (^^S<int>, ^^int); //
{ dg-error "preconditions not satisfied" }
+constexpr bool b83 = reference_converts_from_temporary (^^int, ^^S<int>); //
{ dg-error "preconditions not satisfied" }
+static_assert (!reference_converts_from_temporary (^^S<int>[], ^^int));
+static_assert (!reference_converts_from_temporary (^^int, ^^S<int>[]));
+static_assert (!reference_converts_from_temporary (^^void, ^^int));
+static_assert (!reference_converts_from_temporary (^^int, ^^void));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait18.C
b/gcc/testsuite/g++.dg/reflect/type_trait18.C
new file mode 100644
index 00000000000..05976a1fcb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/type_trait18.C
@@ -0,0 +1,126 @@
+// PR c++/125901
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// [meta.rel]
+
+#include <meta>
+
+struct S;
+union U;
+struct B {};
+
+// If Base and Derived are non-union class types and are not (possibly
+// cv-qualified versions of) the same type, Derived shall be a complete type.
+constexpr bool b1 = is_base_of_type (^^B, ^^S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b2 = is_base_of_type (^^B, ^^const S); // { dg-error
"preconditions not satisfied" }
+static_assert (is_base_of_type (^^S, ^^S));
+static_assert (is_base_of_type (^^S, ^^const S));
+static_assert (!is_base_of_type (^^B, ^^U));
+
+constexpr bool b15 = is_pointer_interconvertible_base_of_type (^^B, ^^S);
// { dg-error "preconditions not satisfied" }
+constexpr bool b16 = is_pointer_interconvertible_base_of_type (^^B, ^^const
S); // { dg-error "preconditions not satisfied" }
+static_assert (is_pointer_interconvertible_base_of_type (^^S, ^^S));
+static_assert (is_pointer_interconvertible_base_of_type (^^S, ^^const S));
+static_assert (!is_pointer_interconvertible_base_of_type (^^B, ^^U));
+
+// If Base and Derived are non-union class types, Derived shall be a complete
type.
+constexpr bool b3 = is_virtual_base_of_type (^^B, ^^S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b4 = is_virtual_base_of_type (^^B, ^^const S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b5 = is_virtual_base_of_type (^^S, ^^S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b6 = is_virtual_base_of_type (^^S, ^^const S); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_virtual_base_of_type (^^B, ^^U));
+static_assert (!is_virtual_base_of_type (^^U, ^^U));
+
+// From and To shall be complete types, cv void, or arrays of unknown bound.
+constexpr bool b7 = is_convertible_type (^^S, ^^B); // { dg-error
"preconditions not satisfied" }
+constexpr bool b8 = is_convertible_type (^^B, ^^S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b9 = is_convertible_type (^^S, ^^B[]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b10 = is_convertible_type (^^B[], ^^S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b11 = is_convertible_type (^^S, ^^void); // { dg-error
"preconditions not satisfied" }
+constexpr bool b12 = is_convertible_type (^^void, ^^S); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_convertible_type (^^S[], ^^B));
+static_assert (!is_convertible_type (^^B, ^^U[]));
+
+constexpr bool b7n = is_nothrow_convertible_type (^^S, ^^B); // { dg-error
"preconditions not satisfied" }
+constexpr bool b8n = is_nothrow_convertible_type (^^B, ^^S); // { dg-error
"preconditions not satisfied" }
+constexpr bool b9n = is_nothrow_convertible_type (^^S, ^^B[]); // { dg-error
"preconditions not satisfied" }
+constexpr bool b10n = is_nothrow_convertible_type (^^B[], ^^S); // {
dg-error "preconditions not satisfied" }
+constexpr bool b11n = is_nothrow_convertible_type (^^S, ^^void); // {
dg-error "preconditions not satisfied" }
+constexpr bool b12n = is_nothrow_convertible_type (^^void, ^^S); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_convertible_type (^^S[], ^^B));
+static_assert (!is_nothrow_convertible_type (^^B, ^^U[]));
+
+// T and U shall be complete types, cv void, or arrays of unknown bound.
+constexpr bool b13 = is_layout_compatible_type (^^S, ^^int); // { dg-error
"preconditions not satisfied" }
+constexpr bool b14 = is_layout_compatible_type (^^int, ^^S); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_layout_compatible_type (^^S[], ^^int));
+static_assert (!is_layout_compatible_type (^^int, ^^S[]));
+static_assert (!is_layout_compatible_type (^^void, ^^int));
+static_assert (!is_layout_compatible_type (^^int, ^^void));
+
+// Fn and all types in the template parameter pack ArgTypes shall be
+// complete types, cv void, or arrays of unknown bound.
+constexpr bool b17 = is_invocable_type (^^S, { ^^int }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b18 = is_invocable_type (^^int, { ^^S }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b19 = is_invocable_type (^^S[1], { ^^int }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b20 = is_invocable_type (^^int, { ^^S[1] }); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_invocable_type (^^S[], { ^^int }));
+static_assert (!is_invocable_type (^^int, { ^^S[] }));
+constexpr bool b21 = is_invocable_type (^^U, { ^^int }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b22 = is_invocable_type (^^int, { ^^U }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b23 = is_invocable_type (^^U[1], { ^^int }); // { dg-error
"preconditions not satisfied" }
+constexpr bool b24 = is_invocable_type (^^int, { ^^U[1] }); // { dg-error
"preconditions not satisfied" }
+static_assert (!is_invocable_type (^^U[], { ^^int }));
+static_assert (!is_invocable_type (^^int, { ^^U[] }));
+static_assert (!is_invocable_type (^^int, { ^^void }));
+
+constexpr bool b17n = is_nothrow_invocable_type (^^S, { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b18n = is_nothrow_invocable_type (^^int, { ^^S }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b19n = is_nothrow_invocable_type (^^S[1], { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b20n = is_nothrow_invocable_type (^^int, { ^^S[1] }); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_invocable_type (^^S[], { ^^int }));
+static_assert (!is_nothrow_invocable_type (^^int, { ^^S[] }));
+constexpr bool b21n = is_nothrow_invocable_type (^^U, { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b22n = is_nothrow_invocable_type (^^int, { ^^U }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b23n = is_nothrow_invocable_type (^^U[1], { ^^int }); // {
dg-error "preconditions not satisfied" }
+constexpr bool b24n = is_nothrow_invocable_type (^^int, { ^^U[1] }); // {
dg-error "preconditions not satisfied" }
+static_assert (!is_nothrow_invocable_type (^^U[], { ^^int }));
+static_assert (!is_nothrow_invocable_type (^^int, { ^^U[] }));
+static_assert (!is_nothrow_invocable_type (^^int, { ^^void }));
+
+// Fn, R, and all types in the template parameter pack ArgTypes shall be
+// complete types, cv void, or arrays of unknown bound.
+constexpr bool b25 = is_invocable_r_type (^^S, ^^int, { ^^int }); // {
dg-message "required from here" }
+constexpr bool b26 = is_invocable_r_type (^^int, ^^S, { ^^S }); // {
dg-message "required from here" }
+constexpr bool b27 = is_invocable_r_type (^^S[1], ^^int, { ^^int }); // {
dg-message "required from here" }
+constexpr bool b28 = is_invocable_r_type (^^int, ^^int, { ^^S[1] }); // {
dg-message "required from here" }
+constexpr bool b29 = is_invocable_r_type (^^int, ^^S, { ^^int }); // {
dg-message "required from here" }
+static_assert (!is_invocable_r_type (^^S[], ^^int, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^int, { ^^S[] }));
+constexpr bool b30 = is_invocable_r_type (^^U, ^^int, { ^^int }); // {
dg-message "required from here" }
+constexpr bool b31 = is_invocable_r_type (^^int, ^^int, { ^^U }); // {
dg-message "required from here" }
+constexpr bool b32 = is_invocable_r_type (^^U[1], ^^int, { ^^int }); // {
dg-message "required from here" }
+constexpr bool b33 = is_invocable_r_type (^^int, ^^int, { ^^U[1] }); // {
dg-message "required from here" }
+constexpr bool b34 = is_invocable_r_type (^^int, ^^U, { ^^int }); // {
dg-message "required from here" }
+static_assert (!is_invocable_r_type (^^U[], ^^int, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^int, { ^^U[] }));
+static_assert (!is_invocable_r_type (^^int, ^^U[], { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^int, { ^^void }));
+
+constexpr bool b25n = is_nothrow_invocable_r_type (^^S, ^^int, { ^^int }); //
{ dg-message "required from here" }
+constexpr bool b26n = is_nothrow_invocable_r_type (^^int, ^^S, { ^^S });
// { dg-message "required from here" }
+constexpr bool b27n = is_nothrow_invocable_r_type (^^S[1], ^^int, { ^^int });
// { dg-message "required from here" }
+constexpr bool b28n = is_nothrow_invocable_r_type (^^int, ^^int, { ^^S[1] });
// { dg-message "required from here" }
+constexpr bool b29n = is_nothrow_invocable_r_type (^^int, ^^S, { ^^int });
// { dg-message "required from here" }
+static_assert (!is_nothrow_invocable_r_type (^^S[], ^^int, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^int, ^^int, { ^^S[] }));
+constexpr bool b30n = is_nothrow_invocable_r_type (^^U, ^^int, { ^^int }); //
{ dg-message "required from here" }
+constexpr bool b31n = is_nothrow_invocable_r_type (^^int, ^^int, { ^^U }); //
{ dg-message "required from here" }
+constexpr bool b32n = is_nothrow_invocable_r_type (^^U[1], ^^int, { ^^int });
// { dg-message "required from here" }
+constexpr bool b33n = is_nothrow_invocable_r_type (^^int, ^^int, { ^^U[1] });
// { dg-message "required from here" }
+constexpr bool b34n = is_nothrow_invocable_r_type (^^int, ^^U, { ^^int });
// { dg-message "required from here" }
+static_assert (!is_nothrow_invocable_r_type (^^U[], ^^int, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^int, ^^int, { ^^U[] }));
+static_assert (!is_nothrow_invocable_r_type (^^int, ^^U[], { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^int, ^^int, { ^^void }));
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
base-commit: ac91bb5b441cd7330c1644937830fe83201c69c3
--
2.55.0