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

Reply via email to