https://gcc.gnu.org/g:46f8550df01af14d2b60321ab11b855284310a1b
commit r16-9246-g46f8550df01af14d2b60321ab11b855284310a1b Author: Marek Polacek <[email protected]> Date: Fri Jun 26 11:32:47 2026 -0400 c++/reflection: check type traits preconditions [PR125901] 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. Reviewed-by: Jason Merrill <[email protected]> (cherry picked from commit 0114024e4f9c167083607bb23e25aefa6ee14411) Diff: --- gcc/cp/cp-tree.h | 4 +- gcc/cp/reflect.cc | 695 +++++++++++++++++----------- 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, 933 insertions(+), 287 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d0372884f6e5..fb0965872661 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8662,7 +8662,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 74b3a8e26d47..cc26ede2e443 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, @@ -2794,7 +2796,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 @@ -4071,7 +4074,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; @@ -4127,10 +4131,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; } @@ -4138,9 +4179,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. */ @@ -4201,17 +4244,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. */ @@ -4239,41 +4286,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. */ @@ -4290,9 +4347,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. */ @@ -4309,9 +4368,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. */ @@ -4353,9 +4414,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. */ @@ -4383,58 +4446,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. @@ -4464,20 +4529,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. */ @@ -4505,9 +4571,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. */ @@ -4535,328 +4603,361 @@ 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_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false); - 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_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false); - 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) { tree arg = make_tree_vec (1); TREE_VEC_ELT (arg, 0) = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false); - 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_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_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false); - 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_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false); - 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_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false); - 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. */ @@ -4873,7 +4974,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) @@ -4884,7 +4986,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)), @@ -4896,69 +4999,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 @@ -5031,11 +5155,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. */ @@ -6079,8 +6204,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); @@ -7689,7 +7816,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); @@ -8263,85 +8391,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, @@ -8350,37 +8483,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, @@ -8389,43 +8538,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 e0ca8ab6a45b..18808354b6e8 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -14230,10 +14230,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; @@ -14241,7 +14244,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; } @@ -14260,9 +14263,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; } @@ -14332,7 +14338,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) @@ -14370,7 +14377,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; @@ -14381,7 +14388,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; @@ -14389,7 +14396,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; @@ -14398,7 +14405,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; @@ -14419,8 +14426,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; @@ -14428,14 +14435,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; @@ -14472,17 +14479,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 000000000000..5fca8658f1cb --- /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 000000000000..2a2c2ddeb787 --- /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 000000000000..05976a1fcb54 --- /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 }
