]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: C++26 Reflection [PR120775]
authorMarek Polacek <polacek@redhat.com>
Wed, 14 Jan 2026 16:37:39 +0000 (11:37 -0500)
committerMarek Polacek <polacek@redhat.com>
Thu, 15 Jan 2026 15:17:43 +0000 (10:17 -0500)
This patch implements C++26 Reflection as specified by P2996R13, which allows
users to perform magic.  This patch also implements related papers:
Annotations for Reflection (P3394R4),
Splicing a base class subobject (P3293R3),
define_static_{string,object,array} (P3491R3),
Function Parameter Reflection (P3096R12).
(I already implemented consteval blocks back in July.)
(We do not yet implement P3795.)

We also implemented some CWG issues that had been approved in Kona;
e.g., CWG 3101, 3109, 3111, 3115, 3117.

All metafunctions are implemented in this patch.

The feature needs to be enabled by -std=c++26 -freflection.

Some stats: the v1 patch was over 51,200 LOC which were written in ~335
commits.  It came with over 400 tests with 11,722 static_asserts.  We still
had about 50 TODOs and FIXMEs in the code.
v2 consists of about 56,000 LOC which were created in 440 commits.  We
now have 446 tests with 40 TODOs remaining.
v3 brought another 77 commits, mostly clean-ups and various bug fixes.

I'd like to thank:
Jakub Jelinek, whose efforts can only be described as heroic and who
never ceases to amaze me even after nearly 15 years of working together,
he implemented many difficult metafunctions, annotations, mangling,
converted our metafunction dispatch to using gperf, and so on and on;
Jonathan Wakely for his libstdc++ patch review and generous & impeccable
advice even at odd hours; Dan Katz for his work on the Reflection papers,
writing Reflection tests for clang++ (many of which I've stolen^Wused),
for his advice, bug reports, and generally cheering me on; Jason Merrill
for his guidance, patch review, and, in fact, encouraging me to take on
this project in the first place; Michael Levine, Valentyn Yukhymenko, and
Alex Yesmanchyk for their nice contributions to Reflection; and Tomasz
KamiƄski for providing test cases, finding bugs, and answering my C++
questions.

PR c++/120775
PR c++/123081
PR c++/122634

gcc/ChangeLog:

* attribs.cc (attribute_value_equal): Return false if either attribute
is ATTR_UNIQUE_VALUE_P.
(merge_attributes): Handle lists with ATTR_UNIQUE_VALUE_P values.
* doc/invoke.texi: Document -freflection.
* dwarf2out.cc (is_base_type) <case default>: Check
TREE_CODE >= LAST_AND_UNUSED_TREE_CODE instead of is_cxx_auto.
(gen_type_die_with_usage): For TREE_CODE >= LAST_AND_UNUSED_TREE_CODE
trees use use DW_TAG_unspecified_type.
* tree-core.h (struct tree_base): Update a comment.
* tree.h (ATTR_UNIQUE_VALUE_P): Define.
(BINFO_BASE_ACCESSES): Update the comment.

gcc/c-family/ChangeLog:

* c-attribs.cc (attribute_takes_identifier_p): Return false for C++
annotations.  Handle "old parm name".
* c-cppbuiltin.cc (c_cpp_builtins): Define __cpp_impl_reflection.
* c.opt (freflection): New.

gcc/cp/ChangeLog:

* Make-lang.in: Add cp/reflect.o.  Add a rule for cp/metafns.h.
* config-lang.in: Add reflect.cc.
* constexpr.cc (constexpr_global_ctx): Add consteval_block and
metafns_called members.  Initialize them.
(cxx_constexpr_quiet_p): New.
(cxx_constexpr_manifestly_const_eval): New.
(cxx_constexpr_caller): New.
(cxx_constexpr_consteval_block): New.
(enum value_cat): Move into cp-tree.h.
(cxx_eval_constant_expression): Move the declaration into cp-tree.h.
No longer static.  Handle REFLECT_EXPR.  Handle conversion of
a reflection to the meta::info type.
(cxx_eval_cxa_builtin_fn): Override current_function_decl.
(cxx_eval_builtin_function_call): Handle __builtin_is_string_literal.
(is_std_allocator): Also check __new_allocator.
(is_std_allocator_allocate): No longer static.
(cxa_allocate_and_throw_exception): New.
(cxx_eval_call_expression): Handle metafunctions.  Maybe set
metafns_called.
(reduced_constant_expression_p): Handle REFLECT_EXPR.
(cxx_eval_binary_expression): Use compare_reflections for comparing
reflections.
(find_immediate_fndecl): Don't walk REFLECT_EXPR_P.
(cxx_eval_outermost_constant_expr): Set global_ctx.consteval_block.
Detect consteval-only smuggling.
(potential_constant_expression_1): Return true for REFLECT_EXPR
and SPLICE_EXPR.
* constraint.cc (diagnose_trait_expr): Add CPTK_IS_CONSTEVAL_ONLY case.
* cp-gimplify.cc (immediate_escalating_function_p): No longer static.
(promote_function_to_consteval): Likewise.
(cp_gimplify_expr) <case CALL_EXPR>: Detect any surviving consteval-only
expressions.
<case CP_BUILT_IN_IS_STRING_LITERAL>: Handle.
(wipe_consteval_only_r): New.
(cp_fold_immediate_r): Detect invalid uses of consteval-only types.
Clear consteval-only DECL_EXPRs.
(cp_genericize_r): Wipe consteval-only vars from BIND_EXPR_VARS and
BLOCK_VARS.
* cp-objcp-common.cc (cp_common_init_ts): Mark META_TYPE, SPLICE_SCOPE,
SPLICE_EXPR, and REFLECT_EXPR.
* cp-trait.def (IS_CONSTEVAL_ONLY): New trait.
* cp-tree.def (REFLECT_EXPR, META_TYPE, SPLICE_EXPR, SPLICE_SCOPE): New
trees.
* cp-tree.h (enum cp_tree_index): Add CPTI_ANNOTATION_IDENTIFIER,
CPTI_STD_META, and CPTI_META_INFO_TYPE.
(std_meta_node): Define.
(meta_info_type_node): Define.
(annotation_identifier): Define.
(REFLECTION_TYPE_P): Define.
(REFLECT_EXPR_P): Define.
(REFLECT_EXPR_HANDLE): Define.
(enum reflect_kind): New.
(REFLECT_EXPR_KIND): Define.
(SET_REFLECT_EXPR_KIND): Define.
(SPLICE_EXPR_EXPRESSION_P): Define.
(SET_SPLICE_EXPR_EXPRESSION_P): Define.
(SPLICE_EXPR_MEMBER_ACCESS_P): Define.
(SET_SPLICE_EXPR_MEMBER_ACCESS_P): Define.
(SPLICE_EXPR_ADDRESS_P): Define.
(SET_SPLICE_EXPR_ADDRESS_P): Define.
(SPLICE_SCOPE_EXPR): Define.
(SPLICE_SCOPE_TYPE_P): Define.
(WILDCARD_TYPE_P): Include SPLICE_SCOPE.
(COMPONENT_REF_SPLICE_P): Define.
(SCALAR_TYPE_P): Include REFLECTION_TYPE_P.
(ENUM_BEING_DEFINED_P): Define.
(OLD_PARM_DECL_P): Define.
(MULTIPLE_NAMES_PARM_P): Define.
(cp_preserve_using_decl): Declare.
(DEF_OPERATOR, DEF_ASSN_OPERATOR): Include META.
(struct ovl_op_info_t): Add meta_name member.
(enum cp_built_in_function): Add CP_BUILT_IN_IS_STRING_LITERAL.
(build_stub_type): Declare.
(current_function_decl_without_access_scope): Declare.
(dependent_namespace_p): Declare.
(convert_reflect_constant_arg): Declare.
(finish_base_specifier): Adjust declaration.
(parsing_lambda_declarator): Declare.
(fold_builtin_is_string_literal): Declare.
(annotation_p): Declare.
(finish_class_member_access_expr): Adjust declaration.
(immediate_escalating_function_p): Declare.
(promote_function_to_consteval): Declare.
(is_std_allocator_allocate): Declare.
(cxa_allocate_and_throw_exception): Declare.
(enum value_cat): Define.
(cxx_eval_constant_expression): Declare.
(cxx_constexpr_quiet_p): Declare.
(cxx_constexpr_manifestly_const_eval): Declare.
(cxx_constexpr_caller): Declare.
(cxx_constexpr_consteval_block): Declare.
(init_reflection): Declare.
(metafunction_p): Declare.
(direct_base_parent): Declare.
(process_metafunction): Declare.
(get_reflection): Declare.
(get_null_reflection): Declare.
(splice): Declare.
(check_out_of_consteval_use): Declare.
(consteval_only_p): Declare.
(compare_reflections): Declare.
(valid_splice_type_p): Declare.
(valid_splice_scope_p): Declare.
(check_splice_expr): Declare.
(make_splice_scope): Declare.
(dependent_splice_p): Declare.
(reflection_mangle_prefix): Declare.
(check_consteval_only_fn): Declare.
* cvt.cc (convert_to_void): Call check_out_of_consteval_use.
* cxx-pretty-print.cc (cxx_pretty_printer::unary_expression): New
REFLECT_EXPR case.
(cxx_pretty_printer::expression): Likewise.
(cxx_pretty_printer::simple_type_specifier): New META_TYPE case.
(cxx_pretty_printer::type_id): Likewise.
* decl.cc (duplicate_decls): Merge parameter names for Reflection.
Maybe set OLD_PARM_DECL_P.
(initialize_predefined_identifiers): Add "annotation ".
(cxx_init_decl_processing): Add __builtin_is_string_literal.  Call
init_reflection.
(maybe_commonize_var): Do nothing for consteval_only_p.
(check_initializer): Default-initialize std::meta::info.
(make_rtl_for_nonlocal_decl): For consteval_only_p vars, set
DECL_EXTERNAL and return early.
(cp_finish_decl): Call check_out_of_consteval_use.  Don't go
creating a varpool node for consteval_only_p.
(get_tuple_size): Check the instantiation instead of the type.
(grokfndecl): Call check_consteval_only_fn.
(xref_basetypes): Stitch annotations onto BINFO_BASE_ACCESSES.
(finish_enum_value_list): Clear ENUM_BEING_DEFINED_P.
* decl2.cc (is_late_template_attribute): Handle all annotations as
late.
(cp_check_const_attributes): Don't handle annotations here.
(maybe_make_one_only): Do nothing for consteval_only_p.
(mark_needed): Likewise.
(min_vis_expr_r): Handle reflections.
(prune_vars_needing_no_initialization): Skip consteval_only_p.
(no_linkage_error): Return early for metafunctions.
(c_parse_final_cleanups): Don't write out consteval_only_p vars.  Avoid
complaining about metafunctions.
* error.cc (dump_type): New cases for CONST_DECL, META_TYPE, and
SPLICE_SCOPE.
(dump_type_prefix): New cases for META_TYPE and SPLICE_SCOPE.
(dump_type_suffix): Likewise.
(dump_decl): Dump SPLICE_EXPR.
(dump_expr): Dump REFLECT_EXPR and SPLICE_EXPR.
* init.cc (build_zero_init_1): Build a null reflection value.
(perform_member_init): Call check_out_of_consteval_use.
* lex.cc (DEF_OPERATOR, OPERATOR_TRANSITION): Update defines.
* mangle.cc (write_type): Mangle META_TYPE.
(write_expression): Handle REFLECT_EXPR.
(write_reflection): New.
(write_template_arg_literal): New REFLECT_EXPR case.
(write_template_arg): Handle REFLECT_EXPR.
* method.cc (build_stub_type): No longer static.
* module.cc (trees_out::type_node): Handle META_TYPE.
(trees_in::tree_node): Likewise.
* name-lookup.cc (name_lookup::adl_type): std::meta is an associated
namespace of std::meta::info.
(strip_using_decl): Don't strip when cp_preserve_using_decl.
(handle_namespace_attrs): Handle annotations.
(do_namespace_alias): Handle SPLICE_EXPR.
(lookup_qualified_name): When cp_preserve_using_decl, don't do
OVL_FUNCTION.
(finish_using_directive): Detect annotations on using directive.
* operators.def: Update for META_NAME.
* parser.cc: New cp_preserve_using_decl global.
(enum required_token): Add RT_CLOSE_SPLICE.
(get_required_cpp_ttype): Return CPP_CLOSE_SPLICE for RT_CLOSE_SPLICE.
(cp_parser_next_tokens_start_splice_type_spec_p): New.
(cp_parser_next_tokens_can_start_splice_scope_spec_p): New.
(cp_parser_splice_specifier): New.
(cp_parser_splice_type_specifier): New.
(cp_parser_splice_expression): New.
(cp_parser_splice_scope_specifier): New.
(cp_parser_splice_spec_is_nns_p): New.
(cp_parser_nth_token_starts_splice_without_nns_p): New.
(cp_parser_primary_expression): Handle CPP_OPEN_SPLICE.  Give an
error for ^^ outside reflection.
(cp_parser_unqualified_id): Allow r.~typename [:R:].
(cp_parser_nested_name_specifier_opt): Cope with splice-scope-specifier.
(cp_parser_qualifying_entity): Parse splice-scope-specifier.
(cp_parser_postfix_expression): Deal with [: :] after a typename.
(cp_parser_postfix_dot_deref_expression): Parse & handle splices
in a class member access.  Pass splice_p to
finish_class_member_access_expr.
(cp_parser_reflection_name): New.
(cp_parser_reflect_expression): New.
(cp_parser_unary_expression): Parse reflect-expression.
(cp_parser_declaration): Parse splice-scope-specifier.
(cp_parser_decomposition_declaration): Detect annotations on structured
bindings.
(cp_parser_decltype_expr): Parse splice-expression.
(cp_parser_template_id): New parsed_templ argument.  If it's nonnull,
don't parse the template name.  Turn an assert into a condition.
(cp_parser_type_specifier): Handle typename [: :].
(cp_parser_simple_type_specifier): Parse splice-type-specifier.
(cp_parser_enum_specifier): Set ENUM_BEING_DEFINED_P.
(cp_parser_namespace_alias_definition): Parse splice-specifier.
(cp_parser_using_directive): Likewise.
(cp_parser_type_id_1): New bool * parameter to distinguish between
types and type aliases.  Set it.
(cp_parser_type_id): Adjust the call to cp_parser_type_id_1.
(cp_parser_template_type_arg): Likewise.
(cp_parser_trailing_type_id): Likewise.
(cp_parser_base_specifier): Handle annotations.  Maybe give an error
for splice-scope-specifier.  Parse splice-type-specifier.  Pass
annotations to finish_base_specifier.
(cp_parser_annotation): New.
(cp_parser_std_attribute_list): Detect mixing annotations and attributes
in the same list.
(cp_parser_annotation_list): New.
(cp_parser_std_attribute_spec): Parse annotations.
(cp_parser_skip_balanced_tokens): Also handle CPP_OPEN_SPLICE
and CPP_CLOSE_SPLICE.
(cp_parser_type_requirement): Parse splice-type-specifier.
(cp_parser_lookup_name): Also consider dependent namespaces.  Don't
call check_accessibility_of_qualified_id for USING_DECLs.
(cp_parser_required_error): Handle RT_CLOSE_SPLICE.
* pt.cc (current_function_decl_without_access_scope): New.
(verify_unstripped_args_1): REFLECT_EXPR_P is OK.
(iterative_hash_template_arg): Handle REFLECT_EXPR.
(convert_nontype_argument): Maybe give an error for REFLECTION_TYPE_P.
(for_each_template_parm_r): Handle SPLICE_SCOPE.
(instantiate_class_template): Handle annotations.
(tsubst_pack_index): Make static.
(tsubst_decl): Handle NAMESPACE_DECL.
(tsubst_splice_scope): New.
(tsubst_splice_expr): New.
(tsubst): Don't return early for NAMESPACE_DECL.   New META_TYPE case.
Handle a splice-specifier that expanded into a NAMESPACE_DECL.  Handle
SPLICE_SCOPE, SPLICE_EXPR, and TEMPLATE_ID_EXPR.
(tsubst_scope): Also accept NAMESPACE_DECL.
(tsubst_qualified_id): Check dependent_namespace_p.
(tsubst_lambda_expr): Set LAMBDA_EXPR_CONSTEVAL_BLOCK_P.
(tsubst_expr): Allow dependent_splice_p in an assert.  Check
COMPONENT_REF_SPLICE_P and pass it to finish_class_member_access_expr.
<case NAMESPACE_DECL>: Remove.
New REFLECT_EXPR and SPLICE_EXPR cases.
(unify): Handle META_TYPE.
(instantiate_body): Call check_consteval_only_fn.
(tsubst_enum): Set ENUM_BEING_DEFINED_P.
(dependent_type_p_r): A splice-scope-specifier is dependent.
(dependent_namespace_p): New.
(value_dependent_expression_p): Handle REFLECT_EXPR.  Also handle
[meta.reflection.access.context]/8.
(type_dependent_expression_p): REFLECT_EXPR_P is not type-dependent.
(convert_reflect_constant_arg): New.
* search.cc (check_final_overrider): Adjust for CWG 3117.
* semantics.cc (finish_base_specifier): Handle annotations.
(parsing_lambda_declarator): No longer static.
(finish_id_expression_1): Check dependent_namespace_p.
(fold_builtin_is_string_literal): New.
(trait_expr_value): Handle CPTK_IS_CONSTEVAL_ONLY.
(finish_trait_expr): Likewise.
* tree.cc (handle_annotation_attribute): New.
(builtin_valid_in_constant_expr_p): Return true for
CP_BUILT_IN_IS_STRING_LITERAL.
(cp_tree_equal): Handle comparing REFLECT_EXPRs.
(internal_attributes): Add "annotation ".
(annotation_p): New.
* typeck.cc (finish_class_member_access_expr): New splice_p argument.
Handle dependent splices.  Implement splicing a base class subobject.
Handle class member access using a splice-expression.
(cp_build_binary_op): Handle comparing std::meta::infos.
(check_return_expr): Call check_out_of_consteval_use.
* metafns.gperf: New file.
* metafns.h: New file.
* reflect.cc: New file.

libcc1/ChangeLog:

* libcp1plugin.cc (start_class_def): Update the call to
finish_base_specifier.

libcpp/ChangeLog:

* charset.cc (_cpp_destroy_iconv): Destroy narrow_cset_desc and
utf8_cset_desc.
(cpp_translate_string): New.
(cpp_valid_identifier): New.
* include/cpplib.h: Add OPEN_SPLICE, CLOSE_SPLICE, and REFLECT_OP to
TTYPE_TABLE.
(cpp_translate_string): Declare.
(cpp_valid_identifier): Declare.
* internal.h (struct cpp_reader): Add reverse_narrow_cset_desc and
reverse_utf8_cset_desc fields.
* lex.cc (_cpp_lex_direct): Emit CPP_CLOSE_SPLICE, CPP_REFLECT_OP,
and CPP_OPEN_SPLICE tokens.

libstdc++-v3/ChangeLog:

* include/Makefile.am (std_headers): Add ${std_srcdir}/meta.
* include/Makefile.in: Regenerate.
* include/bits/iterator_concepts.h (std::ranges::__access::__begin): Add
constexpr.
* include/bits/version.def (reflection): New.
* include/bits/version.h: Regenerate.
* include/precompiled/stdc++.h: Include <meta> for C++26.
* include/std/meta: New file.
* include/std/type_traits (std::is_reflection): New trait.
(std::is_fundamental): Include is_reflection for C++26 -freflection.
(std::is_reflection_v): New variable template.
(std::is_consteval_only): New trait.
(std::is_consteval_only_v): New variable template.
* src/c++23/std.cc.in: Add <meta> exports.
* testsuite/20_util/variable_templates_for_traits.cc: Add -freflection as
dg-additional-options for C++26.  Add std::is_reflection_v test in that case.
* testsuite/20_util/is_consteval_only/requirements/explicit_instantiation.cc: New test.
* testsuite/20_util/is_consteval_only/requirements/typedefs.cc: New test.
* testsuite/20_util/is_consteval_only/value.cc: New test.
* testsuite/20_util/is_reflection/requirements/explicit_instantiation.cc: New test.
* testsuite/20_util/is_reflection/requirements/typedefs.cc: New test.
* testsuite/20_util/is_reflection/value.cc: New test.

gcc/testsuite/ChangeLog:

* g++.dg/DRs/dr2581-1.C: Add -freflection.
* g++.dg/DRs/dr2581-2.C: Likewise.
* g++.dg/reflect/access_context1.C: New test.
* g++.dg/reflect/access_context2.C: New test.
* g++.dg/reflect/access_context3.C: New test.
* g++.dg/reflect/adl1.C: New test.
* g++.dg/reflect/alignment_of1.C: New test.
* g++.dg/reflect/alignment_of2.C: New test.
* g++.dg/reflect/annotations1.C: New test.
* g++.dg/reflect/annotations2.C: New test.
* g++.dg/reflect/annotations3.C: New test.
* g++.dg/reflect/annotations4.C: New test.
* g++.dg/reflect/annotations5.C: New test.
* g++.dg/reflect/annotations6.C: New test.
* g++.dg/reflect/annotations7.C: New test.
* g++.dg/reflect/annotations8.C: New test.
* g++.dg/reflect/anon1.C: New test.
* g++.dg/reflect/anon2.C: New test.
* g++.dg/reflect/anon3.C: New test.
* g++.dg/reflect/bases_of1.C: New test.
* g++.dg/reflect/bases_of2.C: New test.
* g++.dg/reflect/bases_of3.C: New test.
* g++.dg/reflect/bit_size_of1.C: New test.
* g++.dg/reflect/bitfield1.C: New test.
* g++.dg/reflect/can_substitute1.C: New test.
* g++.dg/reflect/class1.C: New test.
* g++.dg/reflect/class2.C: New test.
* g++.dg/reflect/common_reference1.C: New test.
* g++.dg/reflect/common_type1.C: New test.
* g++.dg/reflect/compare1.C: New test.
* g++.dg/reflect/compare10.C: New test.
* g++.dg/reflect/compare2.C: New test.
* g++.dg/reflect/compare3.C: New test.
* g++.dg/reflect/compare4.C: New test.
* g++.dg/reflect/compare5.C: New test.
* g++.dg/reflect/compare6.C: New test.
* g++.dg/reflect/compare7.C: New test.
* g++.dg/reflect/compare8.C: New test.
* g++.dg/reflect/compare9.C: New test.
* g++.dg/reflect/compat1.C: New test.
* g++.dg/reflect/complete1.C: New test.
* g++.dg/reflect/constant_of1.C: New test.
* g++.dg/reflect/constant_of2.C: New test.
* g++.dg/reflect/constant_of3.C: New test.
* g++.dg/reflect/constant_of4.C: New test.
* g++.dg/reflect/constant_of5.C: New test.
* g++.dg/reflect/constant_of6.C: New test.
* g++.dg/reflect/constant_of7.C: New test.
* g++.dg/reflect/constant_of8.C: New test.
* g++.dg/reflect/constant_of9.C: New test.
* g++.dg/reflect/crash1.C: New test.
* g++.dg/reflect/crash10.C: New test.
* g++.dg/reflect/crash11.C: New test.
* g++.dg/reflect/crash12.C: New test.
* g++.dg/reflect/crash13.C: New test.
* g++.dg/reflect/crash14.C: New test.
* g++.dg/reflect/crash15.C: New test.
* g++.dg/reflect/crash16.C: New test.
* g++.dg/reflect/crash17.C: New test.
* g++.dg/reflect/crash18.C: New test.
* g++.dg/reflect/crash2.C: New test.
* g++.dg/reflect/crash3.C: New test.
* g++.dg/reflect/crash4.C: New test.
* g++.dg/reflect/crash5.C: New test.
* g++.dg/reflect/crash6.C: New test.
* g++.dg/reflect/crash7.C: New test.
* g++.dg/reflect/crash8.C: New test.
* g++.dg/reflect/crash9.C: New test.
* g++.dg/reflect/data_member_spec1.C: New test.
* g++.dg/reflect/data_member_spec2.C: New test.
* g++.dg/reflect/data_member_spec3.C: New test.
* g++.dg/reflect/data_member_spec4.C: New test.
* g++.dg/reflect/dealias1.C: New test.
* g++.dg/reflect/dealias2.C: New test.
* g++.dg/reflect/dealias3.C: New test.
* g++.dg/reflect/define_aggregate1.C: New test.
* g++.dg/reflect/define_aggregate2.C: New test.
* g++.dg/reflect/define_aggregate3.C: New test.
* g++.dg/reflect/define_aggregate4.C: New test.
* g++.dg/reflect/define_aggregate5.C: New test.
* g++.dg/reflect/define_static_array1.C: New test.
* g++.dg/reflect/define_static_array2.C: New test.
* g++.dg/reflect/define_static_array3.C: New test.
* g++.dg/reflect/define_static_array4.C: New test.
* g++.dg/reflect/define_static_object1.C: New test.
* g++.dg/reflect/define_static_object2.C: New test.
* g++.dg/reflect/define_static_string1.C: New test.
* g++.dg/reflect/dep1.C: New test.
* g++.dg/reflect/dep10.C: New test.
* g++.dg/reflect/dep11.C: New test.
* g++.dg/reflect/dep2.C: New test.
* g++.dg/reflect/dep3.C: New test.
* g++.dg/reflect/dep4.C: New test.
* g++.dg/reflect/dep5.C: New test.
* g++.dg/reflect/dep6.C: New test.
* g++.dg/reflect/dep7.C: New test.
* g++.dg/reflect/dep8.C: New test.
* g++.dg/reflect/dep9.C: New test.
* g++.dg/reflect/diag1.C: New test.
* g++.dg/reflect/diag2.C: New test.
* g++.dg/reflect/diag3.C: New test.
* g++.dg/reflect/diag4.C: New test.
* g++.dg/reflect/display_string_of1.C: New test.
* g++.dg/reflect/eh1.C: New test.
* g++.dg/reflect/eh2.C: New test.
* g++.dg/reflect/eh3.C: New test.
* g++.dg/reflect/eh4.C: New test.
* g++.dg/reflect/eh5.C: New test.
* g++.dg/reflect/eh6.C: New test.
* g++.dg/reflect/eh7.C: New test.
* g++.dg/reflect/eh8.C: New test.
* g++.dg/reflect/eh9.C: New test.
* g++.dg/reflect/enumerators_of1.C: New test.
* g++.dg/reflect/error1.C: New test.
* g++.dg/reflect/error10.C: New test.
* g++.dg/reflect/error2.C: New test.
* g++.dg/reflect/error3.C: New test.
* g++.dg/reflect/error4.C: New test.
* g++.dg/reflect/error5.C: New test.
* g++.dg/reflect/error6.C: New test.
* g++.dg/reflect/error8.C: New test.
* g++.dg/reflect/error9.C: New test.
* g++.dg/reflect/expr1.C: New test.
* g++.dg/reflect/expr10.C: New test.
* g++.dg/reflect/expr11.C: New test.
* g++.dg/reflect/expr12.C: New test.
* g++.dg/reflect/expr13.C: New test.
* g++.dg/reflect/expr14.C: New test.
* g++.dg/reflect/expr2.C: New test.
* g++.dg/reflect/expr3.C: New test.
* g++.dg/reflect/expr4.C: New test.
* g++.dg/reflect/expr5.C: New test.
* g++.dg/reflect/expr6.C: New test.
* g++.dg/reflect/expr7.C: New test.
* g++.dg/reflect/expr8.C: New test.
* g++.dg/reflect/expr9.C: New test.
* g++.dg/reflect/extract1.C: New test.
* g++.dg/reflect/extract2.C: New test.
* g++.dg/reflect/extract3.C: New test.
* g++.dg/reflect/extract4.C: New test.
* g++.dg/reflect/extract5.C: New test.
* g++.dg/reflect/extract6.C: New test.
* g++.dg/reflect/extract7.C: New test.
* g++.dg/reflect/extract8.C: New test.
* g++.dg/reflect/extract9.C: New test.
* g++.dg/reflect/feat1.C: New test.
* g++.dg/reflect/feat2.C: New test.
* g++.dg/reflect/has_c_language_linkage1.C: New test.
* g++.dg/reflect/has_default_argument1.C: New test.
* g++.dg/reflect/has_default_argument2.C: New test.
* g++.dg/reflect/has_default_member_initializer1.C: New test.
* g++.dg/reflect/has_ellipsis_parameter1.C: New test.
* g++.dg/reflect/has_external_linkage1.C: New test.
* g++.dg/reflect/has_external_linkage2.C: New test.
* g++.dg/reflect/has_identifier1.C: New test.
* g++.dg/reflect/has_identifier2.C: New test.
* g++.dg/reflect/has_internal_linkage1.C: New test.
* g++.dg/reflect/has_internal_linkage2.C: New test.
* g++.dg/reflect/has_linkage1.C: New test.
* g++.dg/reflect/has_module_linkage1.C: New test.
* g++.dg/reflect/has_module_linkage2.C: New test.
* g++.dg/reflect/has_parent1.C: New test.
* g++.dg/reflect/has_template_arguments1.C: New test.
* g++.dg/reflect/has_template_arguments2.C: New test.
* g++.dg/reflect/has_template_arguments3.C: New test.
* g++.dg/reflect/has_template_arguments4.C: New test.
* g++.dg/reflect/identifier_of1.C: New test.
* g++.dg/reflect/identifier_of2.C: New test.
* g++.dg/reflect/init1.C: New test.
* g++.dg/reflect/init10.C: New test.
* g++.dg/reflect/init11.C: New test.
* g++.dg/reflect/init12.C: New test.
* g++.dg/reflect/init13.C: New test.
* g++.dg/reflect/init14.C: New test.
* g++.dg/reflect/init15.C: New test.
* g++.dg/reflect/init16.C: New test.
* g++.dg/reflect/init17.C: New test.
* g++.dg/reflect/init2.C: New test.
* g++.dg/reflect/init3.C: New test.
* g++.dg/reflect/init4.C: New test.
* g++.dg/reflect/init5.C: New test.
* g++.dg/reflect/init6.C: New test.
* g++.dg/reflect/init7.C: New test.
* g++.dg/reflect/init8.C: New test.
* g++.dg/reflect/init9.C: New test.
* g++.dg/reflect/is_accessible1.C: New test.
* g++.dg/reflect/is_accessible2.C: New test.
* g++.dg/reflect/is_alias_template1.C: New test.
* g++.dg/reflect/is_assignment1.C: New test.
* g++.dg/reflect/is_bit_field1.C: New test.
* g++.dg/reflect/is_class_member1.C: New test.
* g++.dg/reflect/is_class_template1.C: New test.
* g++.dg/reflect/is_complete_type1.C: New test.
* g++.dg/reflect/is_complete_type2.C: New test.
* g++.dg/reflect/is_concept1.C: New test.
* g++.dg/reflect/is_const1.C: New test.
* g++.dg/reflect/is_consteval_only1.C: New test.
* g++.dg/reflect/is_constructible_type1.C: New test.
* g++.dg/reflect/is_constructible_type2.C: New test.
* g++.dg/reflect/is_constructor_template1.C: New test.
* g++.dg/reflect/is_constuctor1.C: New test.
* g++.dg/reflect/is_conversion_function1.C: New test.
* g++.dg/reflect/is_conversion_function_template1.C: New test.
* g++.dg/reflect/is_copy_assignment1.C: New test.
* g++.dg/reflect/is_copy_constructor1.C: New test.
* g++.dg/reflect/is_data_member_spec1.C: New test.
* g++.dg/reflect/is_default_constructor1.C: New test.
* g++.dg/reflect/is_defaulted1.C: New test.
* g++.dg/reflect/is_defaulted2.C: New test.
* g++.dg/reflect/is_deleted1.C: New test.
* g++.dg/reflect/is_deleted2.C: New test.
* g++.dg/reflect/is_destructor1.C: New test.
* g++.dg/reflect/is_enumerable_type1.C: New test.
* g++.dg/reflect/is_enumerator1.C: New test.
* g++.dg/reflect/is_explicit1.C: New test.
* g++.dg/reflect/is_explicit2.C: New test.
* g++.dg/reflect/is_explicit_object_parameter1.C: New test.
* g++.dg/reflect/is_final1.C: New test.
* g++.dg/reflect/is_function1.C: New test.
* g++.dg/reflect/is_function2.C: New test.
* g++.dg/reflect/is_function3.C: New test.
* g++.dg/reflect/is_function_parameter1.C: New test.
* g++.dg/reflect/is_function_parameter2.C: New test.
* g++.dg/reflect/is_function_template1.C: New test.
* g++.dg/reflect/is_function_template2.C: New test.
* g++.dg/reflect/is_function_type1.C: New test.
* g++.dg/reflect/is_literal_operator1.C: New test.
* g++.dg/reflect/is_literal_operator_template1.C: New test.
* g++.dg/reflect/is_lrvalue_reference_qualified1.C: New test.
* g++.dg/reflect/is_move_assignment1.C: New test.
* g++.dg/reflect/is_move_constructor1.C: New test.
* g++.dg/reflect/is_mutable_member1.C: New test.
* g++.dg/reflect/is_namespace1.C: New test.
* g++.dg/reflect/is_namespace_alias1.C: New test.
* g++.dg/reflect/is_namespace_member1.C: New test.
* g++.dg/reflect/is_noexcept1.C: New test.
* g++.dg/reflect/is_noexcept2.C: New test.
* g++.dg/reflect/is_noexcept3.C: New test.
* g++.dg/reflect/is_noexcept4.C: New test.
* g++.dg/reflect/is_nonstatic_data_member1.C: New test.
* g++.dg/reflect/is_object1.C: New test.
* g++.dg/reflect/is_object2.C: New test.
* g++.dg/reflect/is_operator_function1.C: New test.
* g++.dg/reflect/is_operator_function_template1.C: New test.
* g++.dg/reflect/is_override1.C: New test.
* g++.dg/reflect/is_pure_virtual1.C: New test.
* g++.dg/reflect/is_special_member_function1.C: New test.
* g++.dg/reflect/is_static_member1.C: New test.
* g++.dg/reflect/is_string_literal1.C: New test.
* g++.dg/reflect/is_structured_binding1.C: New test.
* g++.dg/reflect/is_structured_binding2.C: New test.
* g++.dg/reflect/is_template1.C: New test.
* g++.dg/reflect/is_template2.C: New test.
* g++.dg/reflect/is_type1.C: New test.
* g++.dg/reflect/is_type_alias1.C: New test.
* g++.dg/reflect/is_type_alias2.C: New test.
* g++.dg/reflect/is_type_alias3.C: New test.
* g++.dg/reflect/is_user_declared1.C: New test.
* g++.dg/reflect/is_user_declared2.C: New test.
* g++.dg/reflect/is_user_provided1.C: New test.
* g++.dg/reflect/is_user_provided2.C: New test.
* g++.dg/reflect/is_variable1.C: New test.
* g++.dg/reflect/is_variable_template1.C: New test.
* g++.dg/reflect/is_virtual1.C: New test.
* g++.dg/reflect/is_volatile1.C: New test.
* g++.dg/reflect/lex1.C: New test.
* g++.dg/reflect/lex2.C: New test.
* g++.dg/reflect/mangle1.C: New test.
* g++.dg/reflect/member-visibility1.C: New test.
* g++.dg/reflect/member-visibility2.C: New test.
* g++.dg/reflect/member1.C: New test.
* g++.dg/reflect/member10.C: New test.
* g++.dg/reflect/member11.C: New test.
* g++.dg/reflect/member12.C: New test.
* g++.dg/reflect/member13.C: New test.
* g++.dg/reflect/member14.C: New test.
* g++.dg/reflect/member15.C: New test.
* g++.dg/reflect/member16.C: New test.
* g++.dg/reflect/member17.C: New test.
* g++.dg/reflect/member18.C: New test.
* g++.dg/reflect/member19.C: New test.
* g++.dg/reflect/member2.C: New test.
* g++.dg/reflect/member20.C: New test.
* g++.dg/reflect/member3.C: New test.
* g++.dg/reflect/member4.C: New test.
* g++.dg/reflect/member5.C: New test.
* g++.dg/reflect/member6.C: New test.
* g++.dg/reflect/member7.C: New test.
* g++.dg/reflect/member8.C: New test.
* g++.dg/reflect/member9.C: New test.
* g++.dg/reflect/members_of1.C: New test.
* g++.dg/reflect/members_of2.C: New test.
* g++.dg/reflect/members_of3.C: New test.
* g++.dg/reflect/members_of4.C: New test.
* g++.dg/reflect/members_of5.C: New test.
* g++.dg/reflect/members_of6.C: New test.
* g++.dg/reflect/members_of7.C: New test.
* g++.dg/reflect/metafn-ptr1.C: New test.
* g++.dg/reflect/ns1.C: New test.
* g++.dg/reflect/ns2.C: New test.
* g++.dg/reflect/ns3.C: New test.
* g++.dg/reflect/ns4.C: New test.
* g++.dg/reflect/ns5.C: New test.
* g++.dg/reflect/ns6.C: New test.
* g++.dg/reflect/null1.C: New test.
* g++.dg/reflect/null2.C: New test.
* g++.dg/reflect/null3.C: New test.
* g++.dg/reflect/null4.C: New test.
* g++.dg/reflect/null5.C: New test.
* g++.dg/reflect/object_of1.C: New test.
* g++.dg/reflect/object_of2.C: New test.
* g++.dg/reflect/odr1.C: New test.
* g++.dg/reflect/offset_of1.C: New test.
* g++.dg/reflect/operator_of1.C: New test.
* g++.dg/reflect/override1.C: New test.
* g++.dg/reflect/p2996-1.C: New test.
* g++.dg/reflect/p2996-10.C: New test.
* g++.dg/reflect/p2996-11.C: New test.
* g++.dg/reflect/p2996-12.C: New test.
* g++.dg/reflect/p2996-13.C: New test.
* g++.dg/reflect/p2996-14.C: New test.
* g++.dg/reflect/p2996-15.C: New test.
* g++.dg/reflect/p2996-16.C: New test.
* g++.dg/reflect/p2996-17.C: New test.
* g++.dg/reflect/p2996-18.C: New test.
* g++.dg/reflect/p2996-19.C: New test.
* g++.dg/reflect/p2996-2.C: New test.
* g++.dg/reflect/p2996-20.C: New test.
* g++.dg/reflect/p2996-21.C: New test.
* g++.dg/reflect/p2996-3.C: New test.
* g++.dg/reflect/p2996-4.C: New test.
* g++.dg/reflect/p2996-5.C: New test.
* g++.dg/reflect/p2996-6.C: New test.
* g++.dg/reflect/p2996-7.C: New test.
* g++.dg/reflect/p2996-8.C: New test.
* g++.dg/reflect/p2996-9.C: New test.
* g++.dg/reflect/p3394-1.C: New test.
* g++.dg/reflect/p3491-1.C: New test.
* g++.dg/reflect/p3491-2.C: New test.
* g++.dg/reflect/p3491-3.C: New test.
* g++.dg/reflect/pack-index1.C: New test.
* g++.dg/reflect/parameters_of1.C: New test.
* g++.dg/reflect/parameters_of2.C: New test.
* g++.dg/reflect/parameters_of3.C: New test.
* g++.dg/reflect/parameters_of4.C: New test.
* g++.dg/reflect/parameters_of5.C: New test.
* g++.dg/reflect/parameters_of6.C: New test.
* g++.dg/reflect/parent_of1.C: New test.
* g++.dg/reflect/parm1.C: New test.
* g++.dg/reflect/parm2.C: New test.
* g++.dg/reflect/parm3.C: New test.
* g++.dg/reflect/parm4.C: New test.
* g++.dg/reflect/pr122634-1.C: New test.
* g++.dg/reflect/pr122634-2.C: New test.
* g++.dg/reflect/qrn1.C: New test.
* g++.dg/reflect/qrn2.C: New test.
* g++.dg/reflect/range_args.C: New test.
* g++.dg/reflect/reflect_constant1.C: New test.
* g++.dg/reflect/reflect_constant2.C: New test.
* g++.dg/reflect/reflect_constant3.C: New test.
* g++.dg/reflect/reflect_constant4.C: New test.
* g++.dg/reflect/reflect_constant5.C: New test.
* g++.dg/reflect/reflect_constant6.C: New test.
* g++.dg/reflect/reflect_constant7.C: New test.
* g++.dg/reflect/reflect_constant8.C: New test.
* g++.dg/reflect/reflect_constant9.C: New test.
* g++.dg/reflect/reflect_constant_array1.C: New test.
* g++.dg/reflect/reflect_constant_array2.C: New test.
* g++.dg/reflect/reflect_constant_array3.C: New test.
* g++.dg/reflect/reflect_constant_array4.C: New test.
* g++.dg/reflect/reflect_constant_string1.C: New test.
* g++.dg/reflect/reflect_constant_string2.C: New test.
* g++.dg/reflect/reflect_function1.C: New test.
* g++.dg/reflect/reflect_function2.C: New test.
* g++.dg/reflect/reflect_object1.C: New test.
* g++.dg/reflect/reflect_object2.C: New test.
* g++.dg/reflect/reflect_object3.C: New test.
* g++.dg/reflect/reflect_object4.C: New test.
* g++.dg/reflect/return_type_of1.C: New test.
* g++.dg/reflect/return_type_of2.C: New test.
* g++.dg/reflect/serialize1.C: New test.
* g++.dg/reflect/serialize2.C: New test.
* g++.dg/reflect/size_of1.C: New test.
* g++.dg/reflect/source_location_of1.C: New test.
* g++.dg/reflect/source_location_of2.C: New test.
* g++.dg/reflect/splice1.C: New test.
* g++.dg/reflect/splice2.C: New test.
* g++.dg/reflect/splice3.C: New test.
* g++.dg/reflect/splice4.C: New test.
* g++.dg/reflect/splice5.C: New test.
* g++.dg/reflect/splice6.C: New test.
* g++.dg/reflect/splice7.C: New test.
* g++.dg/reflect/splicing-base1.C: New test.
* g++.dg/reflect/splicing-base2.C: New test.
* g++.dg/reflect/splicing-base3.C: New test.
* g++.dg/reflect/splicing-base4.C: New test.
* g++.dg/reflect/storage_duration1.C: New test.
* g++.dg/reflect/storage_duration2.C: New test.
* g++.dg/reflect/storage_duration3.C: New test.
* g++.dg/reflect/subobjects_of1.C: New test.
* g++.dg/reflect/substitute1.C: New test.
* g++.dg/reflect/substitute2.C: New test.
* g++.dg/reflect/symbol_of1.C: New test.
* g++.dg/reflect/symbol_of2.C: New test.
* g++.dg/reflect/template_arguments_of1.C: New test.
* g++.dg/reflect/template_arguments_of2.C: New test.
* g++.dg/reflect/template_arguments_of3.C: New test.
* g++.dg/reflect/template_of1.C: New test.
* g++.dg/reflect/template_of2.C: New test.
* g++.dg/reflect/template_of3.C: New test.
* g++.dg/reflect/tuple1.C: New test.
* g++.dg/reflect/tuple2.C: New test.
* g++.dg/reflect/type1.C: New test.
* g++.dg/reflect/type10.C: New test.
* g++.dg/reflect/type2.C: New test.
* g++.dg/reflect/type3.C: New test.
* g++.dg/reflect/type4.C: New test.
* g++.dg/reflect/type5.C: New test.
* g++.dg/reflect/type6.C: New test.
* g++.dg/reflect/type7.C: New test.
* g++.dg/reflect/type8.C: New test.
* g++.dg/reflect/type9.C: New test.
* g++.dg/reflect/type_of1.C: New test.
* g++.dg/reflect/type_of2.C: New test.
* g++.dg/reflect/type_rels1.C: New test.
* g++.dg/reflect/type_trait1.C: New test.
* g++.dg/reflect/type_trait10.C: New test.
* g++.dg/reflect/type_trait11.C: New test.
* g++.dg/reflect/type_trait12.C: New test.
* g++.dg/reflect/type_trait13.C: New test.
* g++.dg/reflect/type_trait2.C: New test.
* g++.dg/reflect/type_trait3.C: New test.
* g++.dg/reflect/type_trait4.C: New test.
* g++.dg/reflect/type_trait5.C: New test.
* g++.dg/reflect/type_trait6.C: New test.
* g++.dg/reflect/type_trait8.C: New test.
* g++.dg/reflect/type_trait9.C: New test.
* g++.dg/reflect/u8display_string_of1.C: New test.
* g++.dg/reflect/u8identifier_of1.C: New test.
* g++.dg/reflect/u8symbol_of1.C: New test.
* g++.dg/reflect/underlying_type1.C: New test.
* g++.dg/reflect/using1.C: New test.
* g++.dg/reflect/value_or_object1.C: New test.
* g++.dg/reflect/variable_of1.C: New test.
* g++.dg/reflect/variable_of2.C: New test.
* g++.dg/reflect/variable_of3.C: New test.
* g++.dg/reflect/variant1.C: New test.
* g++.dg/reflect/variant2.C: New test.
* g++.dg/reflect/vector1.C: New test.
* g++.dg/reflect/visibility1.C: New test.

Co-authored-by: Jakub Jelinek <jakub@redhat.com>
Signed-off-by: Valentyn Yukhymenko <vyuhimenko@bloomberg.net>
Signed-off-by: Alex Yesmanchyk <ayesmanchyk@bloomberg.net>
Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
Reviewed-by: Jason Merrill <jason@redhat.com>
509 files changed:
gcc/attribs.cc
gcc/c-family/c-attribs.cc
gcc/c-family/c-cppbuiltin.cc
gcc/c-family/c.opt
gcc/cp/Make-lang.in
gcc/cp/config-lang.in
gcc/cp/constexpr.cc
gcc/cp/constraint.cc
gcc/cp/cp-gimplify.cc
gcc/cp/cp-objcp-common.cc
gcc/cp/cp-trait.def
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/cvt.cc
gcc/cp/cxx-pretty-print.cc
gcc/cp/decl.cc
gcc/cp/decl2.cc
gcc/cp/error.cc
gcc/cp/init.cc
gcc/cp/lex.cc
gcc/cp/mangle.cc
gcc/cp/metafns.gperf [new file with mode: 0644]
gcc/cp/metafns.h [new file with mode: 0644]
gcc/cp/method.cc
gcc/cp/module.cc
gcc/cp/name-lookup.cc
gcc/cp/operators.def
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/reflect.cc [new file with mode: 0644]
gcc/cp/search.cc
gcc/cp/semantics.cc
gcc/cp/tree.cc
gcc/cp/typeck.cc
gcc/doc/invoke.texi
gcc/dwarf2out.cc
gcc/testsuite/g++.dg/DRs/dr2581-1.C
gcc/testsuite/g++.dg/DRs/dr2581-2.C
gcc/testsuite/g++.dg/reflect/access_context1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/access_context2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/access_context3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/adl1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/alignment_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/alignment_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/annotations8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/anon1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/anon2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/anon3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/bases_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/bases_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/bases_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/bit_size_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/bitfield1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/can_substitute1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/class1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/class2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/common_reference1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/common_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compare9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/compat1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/complete1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/constant_of9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/crash9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/data_member_spec1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/data_member_spec2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/data_member_spec3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/data_member_spec4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dealias1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dealias2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dealias3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_aggregate1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_aggregate2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_aggregate3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_aggregate4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_aggregate5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_array1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_array2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_array3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_array4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_object1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_object2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/define_static_string1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/dep9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/diag1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/diag2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/diag3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/diag4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/display_string_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/eh9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/enumerators_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/error9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/expr9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/extract9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/feat1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/feat2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_default_argument1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_default_argument2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_external_linkage1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_external_linkage2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_identifier1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_identifier2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_internal_linkage2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_linkage1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_module_linkage1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_module_linkage2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_parent1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_template_arguments1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_template_arguments2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_template_arguments3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/has_template_arguments4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/identifier_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/identifier_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/init9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_accessible1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_accessible2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_alias_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_assignment1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_bit_field1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_class_member1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_class_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_complete_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_complete_type2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_concept1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_const1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_consteval_only1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_constructible_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_constructible_type2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_constructor_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_constuctor1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_conversion_function1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_conversion_function_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_copy_assignment1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_copy_constructor1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_data_member_spec1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_default_constructor1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_defaulted1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_defaulted2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_deleted1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_deleted2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_destructor1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_enumerable_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_enumerator1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_explicit1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_explicit2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_final1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function_parameter1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function_parameter2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function_template2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_function_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_literal_operator1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_literal_operator_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_lrvalue_reference_qualified1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_move_assignment1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_move_constructor1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_mutable_member1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_namespace1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_namespace_member1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_noexcept1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_noexcept2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_noexcept3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_noexcept4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_object1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_object2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_operator_function1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_operator_function_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_override1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_pure_virtual1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_special_member_function1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_static_member1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_string_literal1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_structured_binding1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_structured_binding2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_template2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_type_alias1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_type_alias2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_type_alias3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_user_declared1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_user_declared2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_user_provided1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_user_provided2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_variable1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_variable_template1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_virtual1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/is_volatile1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/lex1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/lex2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/mangle1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member-visibility1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member-visibility2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member20.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/member9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/members_of7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/metafn-ptr1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/ns1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/ns2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/ns3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/ns4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/ns5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/ns6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/null1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/null2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/null3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/null4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/null5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/object_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/object_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/odr1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/offset_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/operator_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/override1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-20.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-21.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p2996-9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p3394-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p3491-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p3491-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/p3491-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/pack-index1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parameters_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parameters_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parameters_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parameters_of4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parameters_of5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parameters_of6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parent_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parm1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parm2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parm3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/parm4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/pr122634-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/pr122634-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/qrn1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/qrn2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/range_args.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant_array1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant_array2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant_array3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant_array4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant_string1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_constant_string2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_function1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_function2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_object1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_object2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_object3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/reflect_object4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/return_type_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/return_type_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/serialize1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/serialize2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/size_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/source_location_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/source_location_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splice7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splicing-base1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splicing-base2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splicing-base3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/splicing-base4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/storage_duration1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/storage_duration2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/storage_duration3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/subobjects_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/substitute1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/substitute2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/symbol_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/symbol_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/template_arguments_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/template_arguments_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/template_arguments_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/template_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/template_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/template_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/tuple1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/tuple2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_rels1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/type_trait9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/u8display_string_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/u8identifier_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/u8symbol_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/underlying_type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/using1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/value_or_object1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/variable_of1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/variable_of2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/variable_of3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/variant1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/variant2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/vector1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/reflect/visibility1.C [new file with mode: 0644]
gcc/tree-core.h
gcc/tree.h
libcc1/libcp1plugin.cc
libcpp/charset.cc
libcpp/include/cpplib.h
libcpp/internal.h
libcpp/lex.cc
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/iterator_concepts.h
libstdc++-v3/include/bits/version.def
libstdc++-v3/include/bits/version.h
libstdc++-v3/include/precompiled/stdc++.h
libstdc++-v3/include/std/meta [new file with mode: 0644]
libstdc++-v3/include/std/type_traits
libstdc++-v3/src/c++23/std.cc.in
libstdc++-v3/testsuite/20_util/is_consteval_only/requirements/explicit_instantiation.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/is_consteval_only/requirements/typedefs.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/is_consteval_only/value.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/is_reflection/requirements/explicit_instantiation.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/is_reflection/requirements/typedefs.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/is_reflection/value.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc

index d57c175010759c4a95564f2df9f32e33958e2fea..db9a5c125ac88005628b602ad3e88aff0c23e0d5 100644 (file)
@@ -1458,6 +1458,10 @@ attribute_value_equal (const_tree attr1, const_tree attr2)
       && TREE_VALUE (attr2) != NULL_TREE
       && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
     {
+      if (ATTR_UNIQUE_VALUE_P (TREE_VALUE (attr1))
+         || ATTR_UNIQUE_VALUE_P (TREE_VALUE (attr2)))
+       return false;
+
       /* Handle attribute format.  */
       if (is_attribute_p ("format", get_attribute_name (attr1)))
        {
@@ -1739,11 +1743,34 @@ merge_attributes (tree a1, tree a2)
        attributes = a2;
       else
        {
-         /* Pick the longest list, and hang on the other list.  */
+         /* Pick the longest list, and hang on the other list,
+            unless both lists contain ATTR_UNIQUE_VALUE_P values.
+            In that case a1 list needs to go after the a2 list
+            because attributes from a single declaration are stored
+            in reverse order of their declarations.  */
+         bool a1_unique_value_p = false, a2_unique_value_p = false;
+         tree aa1 = a1, aa2 = a2;
+         for (; aa1 && aa2; aa1 = TREE_CHAIN (aa1), aa2 = TREE_CHAIN (aa2))
+           {
+             if (!a1_unique_value_p
+                 && TREE_VALUE (aa1)
+                 && TREE_CODE (TREE_VALUE (aa1)) == TREE_LIST
+                 && ATTR_UNIQUE_VALUE_P (TREE_VALUE (aa1)))
+               a1_unique_value_p = true;
+             if (!a2_unique_value_p
+                 && TREE_VALUE (aa2)
+                 && TREE_CODE (TREE_VALUE (aa2)) == TREE_LIST
+                 && ATTR_UNIQUE_VALUE_P (TREE_VALUE (aa2)))
+               a2_unique_value_p = true;
+           }
 
-         if (list_length (a1) < list_length (a2))
-           attributes = a2, a2 = a1;
+         if (aa2 && (!a1_unique_value_p || !a2_unique_value_p))
+           {
+             attributes = a2;
+             a2 = a1;
+           }
 
+         tree a3 = NULL_TREE, *pa = &a3;
          for (; a2 != 0; a2 = TREE_CHAIN (a2))
            {
              tree a;
@@ -1756,10 +1783,15 @@ merge_attributes (tree a1, tree a2)
              if (a == NULL_TREE)
                {
                  a1 = copy_node (a2);
-                 TREE_CHAIN (a1) = attributes;
-                 attributes = a1;
+                 *pa = a1;
+                 pa = &TREE_CHAIN (a1);
                }
            }
+         if (a3)
+           {
+             *pa = attributes;
+             attributes = a3;
+           }
        }
     }
   return attributes;
index 3b105df67d0859876c8eb25fe16e81d97bc80ed7..10d9a51418ef69c1f139e4cff42cba9c5a9b18f2 100644 (file)
@@ -715,14 +715,20 @@ attribute_takes_identifier_p (const_tree attr_id)
 {
   const struct attribute_spec *spec = lookup_attribute_spec (attr_id);
   if (spec == NULL)
-    /* Unknown attribute that we'll end up ignoring, return true so we
-       don't complain about an identifier argument.  */
-    return true;
+    {
+      /* Unknown attribute that we'll end up ignoring, return true so we
+        don't complain about an identifier argument.  Except C++
+        annotations.  */
+      if (c_dialect_cxx () && id_equal (attr_id, "annotation "))
+       return false;
+      return true;
+    }
   else if (!strcmp ("mode", spec->name)
           || !strcmp ("format", spec->name)
           || !strcmp ("cleanup", spec->name)
           || !strcmp ("access", spec->name)
-          || !strcmp ("counted_by", spec->name))
+          || !strcmp ("counted_by", spec->name)
+          || !strcmp ("old parm name", spec->name))
     return true;
   else
     return targetm.attribute_takes_identifier_p (attr_id);
index 68fdf3d9c2da7c31d1503b2e96c16287111db2fe..da7bb98c9da7a26cae7b161bc6fa5fbe48854297 100644 (file)
@@ -1116,6 +1116,10 @@ c_cpp_builtins (cpp_reader *pfile)
          cpp_define (pfile, "__cpp_pp_embed=202502L");
          cpp_define (pfile, "__cpp_constexpr_virtual_inheritance=202506L");
          cpp_define (pfile, "__cpp_expansion_statements=202506L");
+         if (flag_reflection)
+           cpp_define (pfile, "__cpp_impl_reflection=202506L");
+         else
+           cpp_warn (pfile, "__cpp_impl_reflection");
        }
       if (flag_concepts && cxx_dialect > cxx14)
        cpp_define (pfile, "__cpp_concepts=202002L");
index 797eb46b1273f84503b9d04c029bd2b6f68aab12..e286c3b0535bb4e66607044b483eb46e683da521 100644 (file)
@@ -2329,6 +2329,10 @@ frange-for-ext-temps
 C++ ObjC++ Var(flag_range_for_ext_temps)
 Enable lifetime extension of range based for temporaries.
 
+freflection
+C++ ObjC++ Var(flag_reflection) Init(0)
+Enable experimental C++26 Reflection.
+
 freplace-objc-classes
 ObjC ObjC++ LTO Var(flag_replace_objc_classes)
 Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime.
index b0ed541f9446dc76d0cd93e108fc3645521d8691..7f476531d84d138468eb8da26211ae300a0fb26f 100644 (file)
@@ -107,7 +107,7 @@ CXX_AND_OBJCXX_OBJS = \
        cp/method.o cp/module.o \
        cp/name-lookup.o cp/optimize.o \
        cp/parser.o cp/pt.o cp/ptree.o \
-       cp/rtti.o \
+       cp/reflect.o cp/rtti.o \
        cp/search.o cp/semantics.o \
        cp/tree.o cp/typeck.o cp/typeck2.o \
        cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
@@ -188,6 +188,24 @@ endif
 # This is the file that depends on the generated header file.
 cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
 
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+# Special build rule.  This is a maintainer rule, that is only
+# available when GCC is configured with --enable-maintainer-mode.  In
+# other cases, it is not available to avoid triggering rebuilds if a
+# user has the source checked out with unusual timestamps.
+$(srcdir)/cp/metafns.h: $(srcdir)/cp/metafns.gperf
+else
+# We keep the rule so that you can still force a rebuild, even if you
+# didn't configure GCC with --enable-maintainer-mode, by manually
+# deleting the $(srcdir)/cp/metafns.h file.
+$(srcdir)/cp/metafns.h:
+endif
+       cd $(srcdir)/cp; gperf -o -C -E -k '1,4,5,11,14,$$' -D -N find -L C++ \
+               metafns.gperf --output-file metafns.h
+
+# This is the file that depends on the generated header file.
+cp/reflect.o: $(srcdir)/cp/metafns.h
+
 components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
 components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
 
index 8ff475a09d9678a24ac99e182bdb5818c6e37aaa..845430f35a4a3263ed3d22b7bf5d5cecc42d45bf 100644 (file)
@@ -51,7 +51,7 @@ gtfiles="\
 \$(srcdir)/cp/mangle.cc \$(srcdir)/cp/method.cc \$(srcdir)/cp/module.cc \
 \$(srcdir)/cp/name-lookup.cc \
 \$(srcdir)/cp/parser.cc \$(srcdir)/cp/pt.cc \
-\$(srcdir)/cp/rtti.cc \
+\$(srcdir)/cp/reflect.cc \$(srcdir)/cp/rtti.cc \
 \$(srcdir)/cp/semantics.cc \
 \$(srcdir)/cp/tree.cc \$(srcdir)/cp/typeck2.cc \
 \$(srcdir)/cp/vtable-class-hierarchy.cc \
index 54a50c4b6b047c8cd31a7d46dfab8e125808750b..0873226bc06198e8c2567cdca552576e9f318591 100644 (file)
@@ -1200,15 +1200,29 @@ public:
   /* If non-null, only allow modification of existing values of the variables
      in this set.  Set by modifiable_tracker, below.  */
   hash_set<tree> *modifiable;
+  /* If cxx_eval_outermost_constant_expr is called on the consteval block
+     operator (), this is the FUNCTION_DECL of that operator ().  */
+  tree consteval_block;
   /* Number of heap VAR_DECL deallocations.  */
   unsigned heap_dealloc_count;
   /* Number of uncaught exceptions.  */
   unsigned uncaught_exceptions;
+  /* Some metafunctions aren't dependent just on their arguments, but also
+     on various other dependencies, e.g. has_identifier on a function parameter
+     reflection can change depending on further declarations of corresponding
+     function, is_complete_type depends on type definitions and template
+     specializations in between the calls, define_aggregate even defines
+     class types, etc.  Thus, we need to arrange for calls which call
+     at least some metafunctions to be non-cacheable, because their behavior
+     might not be the same.  Until we figure out which exact metafunctions
+     need this and which don't, do it for all of them.  */
+  bool metafns_called;
 
   /* Constructor.  */
   constexpr_global_ctx ()
     : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr),
-      heap_dealloc_count (0), uncaught_exceptions (0) {}
+      consteval_block (NULL_TREE), heap_dealloc_count (0),
+      uncaught_exceptions (0), metafns_called (false) {}
 
   bool is_outside_lifetime (tree t)
   {
@@ -1322,6 +1336,42 @@ struct constexpr_ctx {
   mce_value manifestly_const_eval;
 };
 
+/* Return ctx->quiet.  For use in reflect.cc.  */
+
+bool
+cxx_constexpr_quiet_p (const constexpr_ctx *ctx)
+{
+  return ctx->quiet;
+}
+
+/* Return ctx->manifestly_const_eval.  For use in reflect.cc.  */
+
+mce_value
+cxx_constexpr_manifestly_const_eval (const constexpr_ctx *ctx)
+{
+  return ctx->manifestly_const_eval;
+}
+
+/* Return ctx->call->fundef->decl or NULL_TREE.  For use in
+   reflect.cc.  */
+
+tree
+cxx_constexpr_caller (const constexpr_ctx *ctx)
+{
+  if (ctx->call)
+    return ctx->call->fundef->decl;
+  else
+    return NULL_TREE;
+}
+
+/* Return ctx->global->consteval_block.  For use in reflect.cc.  */
+
+tree
+cxx_constexpr_consteval_block (const constexpr_ctx *ctx)
+{
+  return ctx->global->consteval_block;
+}
+
 /* Predicates for the meaning of *jump_target.  */
 
 static bool
@@ -1589,17 +1639,6 @@ save_fundef_copy (tree fun, tree copy)
   *slot = copy;
 }
 
-/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST),
-   a glvalue (e.g. VAR_DECL or _REF), or nothing.  */
-
-enum value_cat {
-   vc_prvalue = 0,
-   vc_glvalue = 1,
-   vc_discard = 2
-};
-
-static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
-                                         value_cat, bool *, bool *, tree *);
 static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree,
                                     value_cat, bool *, bool *, tree *);
 static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree,
@@ -2034,6 +2073,10 @@ cxx_eval_cxa_builtin_fn (const constexpr_ctx *ctx, tree call,
            {
              if (type_build_dtor_call (TREE_TYPE (arg)))
                {
+                 /* So that we don't complain about out-of-consteval use.  */
+                 temp_override<tree> ovr (current_function_decl);
+                 if (ctx->call && ctx->call->fundef)
+                   current_function_decl = ctx->call->fundef->decl;
                  tree cleanup
                    = cxx_maybe_build_cleanup (arg, (ctx->quiet ? tf_none
                                                     : tf_warning_or_error));
@@ -2457,6 +2500,22 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
        }
       new_call = fold_builtin_is_corresponding_member (loc, nargs, args);
     }
+  else if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_STRING_LITERAL,
+                             BUILT_IN_FRONTEND))
+    {
+      location_t loc = EXPR_LOCATION (t);
+      if (nargs >= 1)
+       {
+         tree arg = CALL_EXPR_ARG (t, 0);
+         arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
+                                             non_constant_p, overflow_p,
+                                             jump_target);
+         if (*jump_target)
+           return NULL_TREE;
+         args[0] = arg;
+       }
+      new_call = fold_builtin_is_string_literal (loc, nargs, args);
+    }
   else
     new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
                                        CALL_EXPR_FN (t), nargs, args);
@@ -3184,12 +3243,14 @@ is_std_class (tree ctx, const char *name)
 bool
 is_std_allocator (tree ctx)
 {
-  return is_std_class (ctx, "allocator");
+  return (is_std_class (ctx, "allocator")
+         || (flag_reflection
+             && is_std_class (ctx, "__new_allocator")));
 }
 
 /* Return true if FNDECL is std::allocator<T>::{,de}allocate.  */
 
-static inline bool
+bool
 is_std_allocator_allocate (tree fndecl)
 {
   tree name = DECL_NAME (fndecl);
@@ -3670,6 +3731,43 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
     }
 }
 
+/* Allocate an exception for OBJECT and throw it.  */
+
+tree
+cxa_allocate_and_throw_exception (location_t loc, const constexpr_ctx *ctx,
+                                 tree object)
+{
+  tree type = TREE_TYPE (object);
+  /* This simulates a call to __cxa_allocate_exception.  We need
+     (struct exception *) &heap -- memory on the heap so that
+     it can survive the stack being unwound.  */
+  tree arr = build_array_of_n_type (type, 1);
+  tree var = cxa_allocate_exception (loc, ctx, arr, size_zero_node);
+  DECL_NAME (var) = heap_identifier;
+  ctx->global->put_value (var, NULL_TREE);
+
+  /* *(struct exception *) &heap  = exc{ ... }  */
+  tree ptr = build_nop (build_pointer_type (type), build_address (var));
+  object = cp_build_init_expr (cp_build_fold_indirect_ref (ptr), object);
+  bool non_constant_p = false, overflow_p = false;
+  tree jump_target = NULL_TREE;
+  cxx_eval_constant_expression (ctx, object, vc_prvalue, &non_constant_p,
+                               &overflow_p, &jump_target);
+  if (non_constant_p)
+    {
+      if (!ctx->quiet)
+       error_at (loc, "couldn%'t throw %qT", type);
+      return NULL_TREE;
+    }
+
+  /* Now we can __cxa_throw.  */
+  DECL_EXCEPTION_REFCOUNT (var)
+    = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (var), size_one_node);
+  ++ctx->global->uncaught_exceptions;
+
+  return var;
+}
+
 /* Subroutine of cxx_eval_constant_expression.
    Evaluate the call expression tree T in the context of OLD_CALL expression
    evaluation.  */
@@ -3752,6 +3850,35 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
   if (DECL_THUNK_P (fun))
     return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p,
                                jump_target);
+  if (metafunction_p (fun))
+    {
+      /* To be able to evaluate a metafunction, we may have to instantiate
+        constexpr functions.  If we're not allowed to instantiate, leave
+        this for later.  Don't evaluate metafunctions at all when mce_unknown,
+        otherwise we might fold those prematurely.  See
+        g++.dg/reflect/p2996-17.C.  */
+      if (uid_sensitive_constexpr_evaluation_p ()
+         || ctx->manifestly_const_eval == mce_unknown)
+       {
+         *non_constant_p = true;
+         return t;
+       }
+      ctx->global->metafns_called = true;
+      tree e = process_metafunction (ctx, fun, t, non_constant_p, overflow_p,
+                                    jump_target);
+      if (*jump_target)
+       return NULL_TREE;
+      if (*non_constant_p)
+       return t;
+      e = cxx_eval_constant_expression (ctx, e, vc_prvalue,
+                                       non_constant_p, overflow_p,
+                                       jump_target);
+      if (*jump_target)
+       return NULL_TREE;
+      if (*non_constant_p)
+       return t;
+      return e;
+    }
   bool non_constexpr_call = false;
   if (!maybe_constexpr_fn (fun))
     {
@@ -4201,6 +4328,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
          call_ctx.call = &new_call;
          unsigned save_heap_alloc_count = ctx->global->heap_vars.length ();
          unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count;
+         bool save_metafns_called = ctx->global->metafns_called;
 
          /* Make sure we fold std::is_constant_evaluated to true in an
             immediate function.  */
@@ -4232,6 +4360,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
                return NULL_TREE;
            }
 
+         ctx->global->metafns_called = false;
+
          tree jmp_target = NULL_TREE;
          cxx_eval_constant_expression (&call_ctx, body,
                                        vc_discard, non_constant_p, overflow_p,
@@ -4265,6 +4395,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
                }
            }
 
+         if (ctx->global->metafns_called)
+           cacheable = false;
+         ctx->global->metafns_called |= save_metafns_called;
+
          /* At this point, the object's constructor will have run, so
             the object is no longer under construction, and its possible
             'const' semantics now apply.  Make a note of this fact by
@@ -4405,6 +4539,7 @@ reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */)
   switch (TREE_CODE (t))
     {
     case PTRMEM_CST:
+    case REFLECT_EXPR:
       /* Even if we can't lower this yet, it's constant.  */
       return true;
 
@@ -4879,6 +5014,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
        lhs = cplus_expand_constant (lhs);
       else if (TREE_CODE (rhs) == PTRMEM_CST)
        rhs = cplus_expand_constant (rhs);
+      else if (REFLECT_EXPR_P (lhs) && REFLECT_EXPR_P (rhs))
+       {
+         const bool eq = compare_reflections (lhs, rhs);
+         r = constant_boolean_node (eq == is_code_eq, type);
+       }
     }
   if (r == NULL_TREE
       && TREE_CODE_CLASS (code) == tcc_comparison
@@ -8818,7 +8958,7 @@ merge_jump_target (location_t loc, const constexpr_ctx *ctx, tree r,
 /* FIXME unify with c_fully_fold */
 /* FIXME overflow_p is too global */
 
-static tree
+tree
 cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                              value_cat lval,
                              bool *non_constant_p, bool *overflow_p,
@@ -9011,6 +9151,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case CASE_LABEL_EXPR:
     case PREDICT_EXPR:
     case OMP_DECLARE_MAPPER:
+    case REFLECT_EXPR:
       return t;
 
     case PARM_DECL:
@@ -9981,6 +10122,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
              = build_pointer_type (TREE_TYPE (var));
          }
 
+       /* This can happen for std::meta::info(^^int) where the cast has no
+          meaning.  */
+       if (REFLECTION_TYPE_P (type) && REFLECT_EXPR_P (op))
+         {
+           r = op;
+           break;
+         }
+
        if (op == oldop && tcode != UNARY_PLUS_EXPR)
          /* We didn't fold at the top so we could check for ptr-int
             conversion.  */
@@ -10376,7 +10525,7 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/)
 /* Find immediate function decls in *TP if any.  */
 
 static tree
-find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/)
+find_immediate_fndecl (tree *tp, int *walk_subtrees, void */*data*/)
 {
   if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp))
     return *tp;
@@ -10384,6 +10533,8 @@ find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/)
       && TREE_CODE (PTRMEM_CST_MEMBER (*tp)) == FUNCTION_DECL
       && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (*tp)))
     return PTRMEM_CST_MEMBER (*tp);
+  if (REFLECT_EXPR_P (*tp))
+    *walk_subtrees = 0;
   return NULL_TREE;
 }
 
@@ -10468,6 +10619,12 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
            return t;
          else
            is_consteval = true;
+         tree lam;
+         if (manifestly_const_eval == mce_true
+             && LAMBDA_FUNCTION_P (fndecl)
+             && (lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (fndecl)))
+             && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam))
+           global_ctx.consteval_block = fndecl;
        }
     }
   else if (cxx_dialect >= cxx20
@@ -10684,6 +10841,37 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
       non_constant_p = true;
     }
 
+  /* Detect consteval-only smuggling: turning a consteval-only object
+     into one that is not.  For instance, in
+       struct B { };
+       struct D : B { info r; };
+       constexpr D d{^^::};
+       constexpr const B &b = d; // #1
+     #1 is wrong because D is a consteval-only type but B is not.  */
+  if (flag_reflection
+      && !non_constant_p
+      && object
+      && POINTER_TYPE_P (TREE_TYPE (object))
+      && !consteval_only_p (object)
+      && check_out_of_consteval_use (r, /*complain=*/false))
+    {
+      if (!allow_non_constant)
+       {
+         if (TYPE_REF_P (TREE_TYPE (object)))
+           error_at (cp_expr_loc_or_input_loc (t),
+                     "reference into an object of consteval-only type is "
+                     "not a constant expression unless it also has "
+                     "consteval-only type");
+         else
+           error_at (cp_expr_loc_or_input_loc (t),
+                     "pointer into an object of consteval-only type is "
+                     "not a constant expression unless it also has "
+                     "consteval-only type");
+       }
+      r = t;
+      non_constant_p = true;
+    }
+
   if (!non_constant_p && !constexpr_dtor)
     verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
 
@@ -11476,6 +11664,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case REQUIRES_EXPR:
     case STATIC_ASSERT:
     case DEBUG_BEGIN_STMT:
+    case REFLECT_EXPR:
       return true;
 
     case RETURN_EXPR:
@@ -12567,6 +12756,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
     case TU_LOCAL_ENTITY:
       return false;
 
+    /* A splice expression is dependent, but will be constant after
+       substitution.  */
+    case SPLICE_EXPR:
+      return true;
+
     case NONTYPE_ARGUMENT_PACK:
       {
        tree args = ARGUMENT_PACK_ARGS (t);
index b70ecf99a30a2d936d354cea795ec1b1d1ea8d21..0b91e8785631384221aecf8235ee9c1c02cf5411 100644 (file)
@@ -3316,6 +3316,9 @@ diagnose_trait_expr (location_t loc, tree expr, tree args)
     case CPTK_IS_VOLATILE:
       inform (loc, "%qT is not a volatile type", t1);
       break;
+    case CPTK_IS_CONSTEVAL_ONLY:
+      inform (decl_loc, "%qT is not consteval-only", t1);
+      break;
     case CPTK_RANK:
       inform (loc, "%qT cannot yield a rank", t1);
       break;
index df86c3903324e6c8032c61db5e4473b8a61ed2d9..3c0f415fa87cf50cdd060bec23a24fb16a02b446 100644 (file)
@@ -486,7 +486,7 @@ lvalue_has_side_effects (tree e)
 
 /* Return true if FN is an immediate-escalating function.  */
 
-static bool
+bool
 immediate_escalating_function_p (tree fn)
 {
   if (!fn || !flag_immediate_escalation)
@@ -524,7 +524,7 @@ unchecked_immediate_escalating_function_p (tree fn)
 
 /* Promote FN to an immediate function, including its clones.  */
 
-static void
+void
 promote_function_to_consteval (tree fn)
 {
   SET_DECL_IMMEDIATE_FUNCTION_P (fn);
@@ -856,6 +856,13 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
     case CALL_EXPR:
       ret = GS_OK;
+      /* At this point any function that takes/returns a consteval-only
+        expression is a problem.  */
+      for (int i = 0; i < call_expr_nargs (*expr_p); ++i)
+       if (check_out_of_consteval_use (CALL_EXPR_ARG (*expr_p, i)))
+         ret = GS_ERROR;
+      if (consteval_only_p (TREE_TYPE (*expr_p)))
+       ret = GS_ERROR;
       if (flag_strong_eval_order == 2
          && CALL_EXPR_FN (*expr_p)
          && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p)
@@ -965,6 +972,13 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
                          "__builtin_eh_ptr_adjust_ref");
                *expr_p = void_node;
                break;
+             case CP_BUILT_IN_IS_STRING_LITERAL:
+               *expr_p
+                 = fold_builtin_is_string_literal (EXPR_LOCATION (*expr_p),
+                                                   call_expr_nargs (*expr_p),
+                                                   &CALL_EXPR_ARG (*expr_p,
+                                                                   0));
+               break;
              default:
                break;
              }
@@ -1293,6 +1307,23 @@ cp_build_init_expr_for_ctor (tree call, tree init)
   return init;
 }
 
+/* For every DECL_EXPR check if it declares a consteval-only variable and
+   if so, overwrite it with a no-op.  The point here is not to leak
+   consteval-only variables into the middle end.  */
+
+static tree
+wipe_consteval_only_r (tree *stmt_p, int *, void *)
+{
+  if (TREE_CODE (*stmt_p) == DECL_EXPR)
+    {
+      tree d = DECL_EXPR_DECL (*stmt_p);
+      if (VAR_P (d) && consteval_only_p (d))
+       /* Wipe the DECL_EXPR so that it doesn't get into gimple.  */
+       *stmt_p = void_node;
+    }
+  return NULL_TREE;
+}
+
 /* A walk_tree callback for cp_fold_function and cp_fully_fold_init to handle
    immediate functions.  */
 
@@ -1320,12 +1351,32 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
       return NULL_TREE;
     }
 
+  /* Most invalid uses of consteval-only types should have been already
+     detected at this point.  And the valid ones won't be needed
+     anymore.  */
+  if (flag_reflection
+      && complain
+      && (data->flags & ff_genericize)
+      && TREE_CODE (stmt) == STATEMENT_LIST)
+    for (tree s : tsi_range (stmt))
+      if (check_out_of_consteval_use (s))
+       *stmt_p = void_node;
+
   tree decl = NULL_TREE;
   bool call_p = false;
 
   /* We are looking for &fn or fn().  */
   switch (code)
     {
+    case DECL_EXPR:
+      /* Clear consteval-only DECL_EXPRs.  */
+      if (flag_reflection)
+       {
+         tree d = DECL_EXPR_DECL (stmt);
+         if (VAR_P (d) && consteval_only_p (d))
+           *stmt_p = void_node;
+       }
+      break;
     case CALL_EXPR:
     case AGGR_INIT_EXPR:
       if (tree fn = cp_get_callee (stmt))
@@ -1344,8 +1395,15 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
       if (IF_STMT_CONSTEVAL_P (stmt))
        {
          if (!data->pset.add (stmt))
-           cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_,
-                         NULL);
+           {
+             cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_,
+                           nullptr);
+             if (flag_reflection)
+               /* Check & clear consteval-only DECL_EXPRs even here,
+                  because we wouldn't be walking this subtree otherwise.  */
+               cp_walk_tree (&THEN_CLAUSE (stmt), wipe_consteval_only_r,
+                             data_, nullptr);
+           }
          *walk_subtrees = 0;
          return NULL_TREE;
        }
@@ -1419,6 +1477,22 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
          *walk_subtrees = 0;
          return stmt;
        }
+      /* If we called a consteval function and it evaluated to a consteval-only
+        expression, it could be a problem if we are outside a manifestly
+        constant-evaluated context.  */
+      else if ((data->flags & ff_genericize)
+              && check_out_of_consteval_use (e, complain))
+       {
+         *stmt_p = void_node;
+         if (complain & tf_error)
+           return NULL_TREE;
+         else
+           {
+             *walk_subtrees = 0;
+             return stmt;
+           }
+       }
+
       /* We've evaluated the consteval function call.  */
       if (call_p)
        {
@@ -2030,6 +2104,20 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
              cp_walk_tree (&DECL_INITIAL (decl), cp_genericize_r, data, NULL);
          wtd->no_sanitize_p = no_sanitize_p;
        }
+      if (flag_reflection)
+       /* Wipe consteval-only vars from BIND_EXPR_VARS and BLOCK_VARS.  */
+       for (tree *p = &BIND_EXPR_VARS (stmt); *p; )
+         {
+           if (VAR_P (*p) && consteval_only_p (*p))
+             {
+               if (BIND_EXPR_BLOCK (stmt)
+                   && *p == BLOCK_VARS (BIND_EXPR_BLOCK (stmt)))
+                 BLOCK_VARS (BIND_EXPR_BLOCK (stmt)) = DECL_CHAIN (*p);
+               *p = DECL_CHAIN (*p);
+               continue;
+             }
+           p = &DECL_CHAIN (*p);
+         }
       wtd->bind_expr_stack.safe_push (stmt);
       cp_walk_tree (&BIND_EXPR_BODY (stmt),
                    cp_genericize_r, data, NULL);
index 1bbe43715e658d0da62274fa1e571ebf4af3b038..0f0d4a01eebbeac590169cd1e3da36304d0076a4 100644 (file)
@@ -646,6 +646,8 @@ cp_common_init_ts (void)
   MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
   MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION);
   MARK_TS_TYPE_NON_COMMON (PACK_INDEX_TYPE);
+  MARK_TS_TYPE_NON_COMMON (META_TYPE);
+  MARK_TS_TYPE_NON_COMMON (SPLICE_SCOPE);
 
   /* Statements.  */
   MARK_TS_EXP (CLEANUP_STMT);
@@ -696,6 +698,8 @@ cp_common_init_ts (void)
   MARK_TS_EXP (VEC_INIT_EXPR);
   MARK_TS_EXP (VEC_NEW_EXPR);
   MARK_TS_EXP (SPACESHIP_EXPR);
+  MARK_TS_EXP (SPLICE_EXPR);
+  MARK_TS_EXP (REFLECT_EXPR);
 
   /* Fold expressions.  */
   MARK_TS_EXP (BINARY_LEFT_FOLD_EXPR);
index c7fc40d054453b61eb4621d1dbeb4a5de0c8a049..395cadc5767d1012db28a5930dcb0c378752fe3b 100644 (file)
@@ -69,6 +69,7 @@ DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
+DEFTRAIT_EXPR (IS_CONSTEVAL_ONLY, "__builtin_is_consteval_only", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_DESTRUCTIBLE, "__is_destructible", 1)
index 3e11b4deb7ba8f8413dfca3a642e809f57d05dd4..770a681e124d27fa9ef984f663dd89d67e700114 100644 (file)
@@ -586,6 +586,24 @@ DEFTREECODE (POSTCONDITION_STMT, "postcondition_stmt", tcc_statement, 4)
    wasn't an exposure (e.g. in a non-inline function template).  */
 DEFTREECODE (TU_LOCAL_ENTITY, "tu_local_entity", tcc_exceptional, 0)
 
+/* C++26 reflection expression.  */
+DEFTREECODE (REFLECT_EXPR, "reflect_expr", tcc_expression, 1)
+
+/* Represents the std::meta::info type.  */
+DEFTREECODE (META_TYPE, "meta_type", tcc_type, 0)
+
+/* Represents a dependent splice expression.  If SPLICE_EXPR_EXPRESSION_P
+   is set, this tree represents a splice-expression (as opposed to
+   a splice-specifier).  */
+DEFTREECODE (SPLICE_EXPR, "splice_expr", tcc_expression, 1)
+
+/* Represents a dependent splice scope, or a dependent splice type
+   (SPLICE_SCOPE_TYPE_P says which one it is).  Its operand can be accessed
+   using SPLICE_SCOPE_EXPR.  The operand can be a SPLICE_EXPR or a
+   TEMPLATE_ID_EXPR; the SPLICE_SCOPE is necessary to denote that this
+   tree should expand to a type/scope.  */
+DEFTREECODE (SPLICE_SCOPE, "splice_scope", tcc_type, 0)
+
 /*
 Local variables:
 mode:c
index 7dc498ccae371cdb60d692e5a14f1572c5b4c6cf..d7acfc8b7a332bd82a83211baa459d6c24b189a5 100644 (file)
@@ -175,6 +175,7 @@ enum cp_tree_index
     CPTI_FOR_END_IDENTIFIER,
     CPTI_ABI_TAG_IDENTIFIER,
     CPTI_ALIGNED_IDENTIFIER,
+    CPTI_ANNOTATION_IDENTIFIER,
     CPTI_BEGIN_IDENTIFIER,
     CPTI_END_IDENTIFIER,
     CPTI_GET_IDENTIFIER,
@@ -211,6 +212,7 @@ enum cp_tree_index
 
     /* We must find these via the global namespace.  */
     CPTI_STD,
+    CPTI_STD_META,
     CPTI_ABI,
 
     /* These are created at init time, but the library/headers provide
@@ -236,6 +238,7 @@ enum cp_tree_index
     CPTI_DCAST,
 
     CPTI_PSEUDO_CONTRACT_VIOLATION,
+    CPTI_META_INFO_TYPE,
 
     CPTI_MAX
 };
@@ -257,6 +260,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define vtbl_type_node                 cp_global_trees[CPTI_VTBL_TYPE]
 #define vtbl_ptr_type_node             cp_global_trees[CPTI_VTBL_PTR_TYPE]
 #define std_node                       cp_global_trees[CPTI_STD]
+#define std_meta_node                  cp_global_trees[CPTI_STD_META]
 #define abi_node                       cp_global_trees[CPTI_ABI]
 #define global_namespace               cp_global_trees[CPTI_GLOBAL]
 #define const_type_info_type_node      cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE]
@@ -266,6 +270,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 /* std::align_val_t */
 #define align_type_node                        cp_global_trees[CPTI_ALIGN_TYPE]
 #define pseudo_contract_violation_type cp_global_trees[CPTI_PSEUDO_CONTRACT_VIOLATION]
+#define meta_info_type_node            cp_global_trees[CPTI_META_INFO_TYPE]
 
 /* We cache these tree nodes so as to call get_identifier less frequently.
    For identifiers for functions, including special member functions such
@@ -329,6 +334,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define for_end_identifier             cp_global_trees[CPTI_FOR_END_IDENTIFIER]
 #define abi_tag_identifier             cp_global_trees[CPTI_ABI_TAG_IDENTIFIER]
 #define aligned_identifier             cp_global_trees[CPTI_ALIGNED_IDENTIFIER]
+#define annotation_identifier          cp_global_trees[CPTI_ANNOTATION_IDENTIFIER]
 #define begin_identifier               cp_global_trees[CPTI_BEGIN_IDENTIFIER]
 #define end_identifier                 cp_global_trees[CPTI_END_IDENTIFIER]
 #define get__identifier                        cp_global_trees[CPTI_GET_IDENTIFIER]
@@ -454,6 +460,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR)
       CONSTEVAL_BLOCK_P (in STATIC_ASSERT)
       LAMBDA_EXPR_CONSTEVAL_BLOCK_P (in LAMBDA_EXPR)
+      SPLICE_EXPR_EXPRESSION_P (in SPLICE_EXPR)
+      OLD_PARM_DECL_P (in PARM_DECL)
+      COMPONENT_REF_SPLICE_P (in COMPONENT_REF)
    1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -476,6 +485,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates)
       MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR)
       LAMBDA_EXPR_CONST_QUAL_P (in LAMBDA_EXPR)
+      SPLICE_EXPR_MEMBER_ACCESS_P (in SPLICE_EXPR)
    2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -499,6 +509,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       STATIC_INIT_DECOMP_NONBASE_P (in the TREE_LIST
                                    for {static,tls}_aggregates)
       MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR)
+      MULTIPLE_NAMES_PARM_P (in PARM_DECL)
+      SPLICE_EXPR_ADDRESS_P (in SPLICE_EXPR)
    3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR)
       ICS_BAD_FLAG (in _CONV)
       FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -541,6 +553,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
    1: TYPE_HAS_USER_CONSTRUCTOR.
    2: TYPE_HAS_LATE_RETURN_TYPE (in FUNCTION_TYPE, METHOD_TYPE)
       TYPE_PTRMEMFUNC_FLAG (in RECORD_TYPE)
+      ENUM_BEING_DEFINED_P (in ENUMERAL_TYPE)
    4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
    5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
       ENUM_FIXED_UNDERLYING_TYPE_P (in ENUMERAL_TYPE)
@@ -1883,6 +1896,98 @@ struct GTY(()) tree_tu_local_entity {
 #define REQUIRES_EXPR_EXTRA_ARGS(NODE) \
   TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 2)
 
+/* True iff TYPE is cv decltype(^^int).  */
+#define REFLECTION_TYPE_P(TYPE) (TREE_CODE (TYPE) == META_TYPE)
+
+/* True if NODE is a REFLECT_EXPR.  */
+#define REFLECT_EXPR_P(NODE) (TREE_CODE (NODE) == REFLECT_EXPR)
+
+/* The handle of a reflection expression.  */
+#define REFLECT_EXPR_HANDLE(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, REFLECT_EXPR), 0)
+
+/* Various kinds of reflections.  Sometimes we cannot simply look at the
+   handle and figure out the kind from it.  For instance,
+
+     consteval void fn(int p) {
+       constexpr auto rp = parameters_of(^^fn)[0];
+       // is_variable(^^p) is true
+       // is_function_parameter(^^p) is false
+       // is_variable(rp) is false
+       // is_function_parameter(rp) is true
+     }
+
+   but we represent the handle p with a PARM_DECL in all cases.
+
+   The size is limited to addr_space_t because we only have 8 bits.  */
+
+enum reflect_kind : addr_space_t {
+  /* Detect the category from the handle.  */
+  REFLECT_UNDEF,
+  /* The reflection represents an object.  */
+  REFLECT_OBJECT,
+  /* The reflection represents a value.  */
+  REFLECT_VALUE,
+  /* The reflection represents a variable.  Used for underlying
+     variable of tuple structured binding.  */
+  REFLECT_VAR,
+  /* The reflection represents a function parameter.  */
+  REFLECT_PARM,
+  /* The reflection represents a data member description.  */
+  REFLECT_DATA_MEMBER_SPEC,
+  /* The reflection represents a direct base relationship.  */
+  REFLECT_BASE,
+  /* The reflection represents an annotation.  */
+  REFLECT_ANNOTATION
+};
+
+/* The reflect_kind of a REFLECT_EXPR.  */
+#define REFLECT_EXPR_KIND(NODE) \
+  (static_cast<reflect_kind> \
+   (REFLECT_EXPR_CHECK (NODE)->base.u.bits.address_space))
+
+#define SET_REFLECT_EXPR_KIND(NODE, VAL) \
+  (REFLECT_EXPR_CHECK (NODE)->base.u.bits.address_space = VAL)
+
+/* True if this SPLICE_EXPR represents a splice-expression (as opposed to
+   a splice-specifier), so it cannot expand to e.g. a type.  */
+#define SPLICE_EXPR_EXPRESSION_P(NODE) \
+   TREE_LANG_FLAG_0 (SPLICE_EXPR_CHECK (NODE))
+
+/* Helper macro to set SPLICE_EXPR_EXPRESSION_P.  This macro handles
+   dependent_splice_p trees: either [:T:] or [:T:]<arg>.  */
+#define SET_SPLICE_EXPR_EXPRESSION_P(NODE) \
+  (SPLICE_EXPR_EXPRESSION_P (TREE_CODE (NODE) == SPLICE_EXPR \
+                            ? NODE : TREE_OPERAND (NODE, 0)) = true)
+
+/* True if this SPLICE_EXPR is used in foo.[: bar :] or foo->[: bar :]
+   context.  */
+#define SPLICE_EXPR_MEMBER_ACCESS_P(NODE) \
+   TREE_LANG_FLAG_1 (SPLICE_EXPR_CHECK (NODE))
+
+/* Helper macro to set SPLICE_EXPR_MEMBER_ACCESS_P.  */
+#define SET_SPLICE_EXPR_MEMBER_ACCESS_P(NODE, VAL) \
+  (SPLICE_EXPR_MEMBER_ACCESS_P (TREE_CODE (NODE) == SPLICE_EXPR \
+                               ? NODE : TREE_OPERAND (NODE, 0)) = (VAL))
+
+/* True if we are taking the address of this SPLICE_EXPR.  */
+#define SPLICE_EXPR_ADDRESS_P(NODE) \
+   TREE_LANG_FLAG_2 (SPLICE_EXPR_CHECK (NODE))
+
+/* Helper macro to set SPLICE_EXPR_ADDRESS_P.  */
+#define SET_SPLICE_EXPR_ADDRESS_P(NODE, VAL) \
+  (SPLICE_EXPR_ADDRESS_P (TREE_CODE (NODE) == SPLICE_EXPR \
+                         ? NODE : TREE_OPERAND (NODE, 0)) = (VAL))
+
+/* The expression in question for a SPLICE_SCOPE.  */
+#define SPLICE_SCOPE_EXPR(NODE) \
+  (TYPE_VALUES_RAW (SPLICE_SCOPE_CHECK (NODE)))
+
+/* True if this splice represents a splice-type-specifier rather than
+   a splice-scope-specifier.  */
+#define SPLICE_SCOPE_TYPE_P(NODE) \
+  (SPLICE_SCOPE_CHECK (NODE))->type_common.string_flag
+
 enum cp_tree_node_structure_enum {
   TS_CP_GENERIC,
   TS_CP_IDENTIFIER,
@@ -2366,6 +2471,7 @@ enum languages { lang_c, lang_cplusplus };
    || TREE_CODE (T) == DECLTYPE_TYPE                   \
    || TREE_CODE (T) == TRAIT_TYPE                      \
    || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE         \
+   || TREE_CODE (T) == SPLICE_SCOPE                    \
    || TREE_CODE (T) == PACK_INDEX_TYPE)
 
 /* Nonzero if T is a class (or struct or union) type.  Also nonzero
@@ -4378,6 +4484,11 @@ templated_operator_saved_lookups (tree t)
 #define REF_PARENTHESIZED_P(NODE) \
   TREE_LANG_FLAG_2 (TREE_CHECK5 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR, PAREN_EXPR))
 
+/* True on a dependent COMPONENT_REF with a splice expression.  */
+
+#define COMPONENT_REF_SPLICE_P(NODE) \
+  TREE_LANG_FLAG_0 (COMPONENT_REF_CHECK (NODE))
+
 /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a
    constructor call, rather than an ordinary function call.  */
 #define AGGR_INIT_VIA_CTOR_P(NODE) \
@@ -4755,9 +4866,9 @@ get_vec_init_expr (tree t)
 
 /* [basic.types]
 
-   Arithmetic types, enumeration types, pointer types,
-   pointer-to-member types, and std::nullptr_t are collectively called
-   scalar types.
+   Arithmetic types, enumeration types, pointer types, pointer-to-member types,
+   std::meta::info, std::nullptr_t and cv-qualified versions of these types
+   are collectively called scalar types.
 
    Keep these checks in ascending code order.  */
 #define SCALAR_TYPE_P(TYPE)                    \
@@ -4766,7 +4877,8 @@ get_vec_init_expr (tree t)
    || ARITHMETIC_TYPE_P (TYPE)                 \
    || TYPE_PTR_P (TYPE)                                \
    || TYPE_PTRMEMFUNC_P (TYPE)                  \
-   || NULLPTR_TYPE_P (TYPE))
+   || NULLPTR_TYPE_P (TYPE)                    \
+   || REFLECTION_TYPE_P (TYPE))
 
 /* Determines whether this type is a C++0x scoped enumeration
    type. Scoped enumerations types are introduced via "enum class" or
@@ -4807,6 +4919,11 @@ get_vec_init_expr (tree t)
 #define OPAQUE_ENUM_P(TYPE)                            \
   (TREE_CODE (TYPE) == ENUMERAL_TYPE && ENUM_IS_OPAQUE (TYPE))
 
+/* Nonzero when the ENUMERAL_TYPE is being defined (enumerators parsed
+   or instantiated).  */
+#define ENUM_BEING_DEFINED_P(NODE) \
+  (TYPE_LANG_FLAG_2 (ENUMERAL_TYPE_CHECK (NODE)))
+
 /* [dcl.init.aggr]
 
    An aggregate is an array or a class with no user-provided
@@ -5174,6 +5291,18 @@ get_vec_init_expr (tree t)
 #define DECL_ARRAY_PARAMETER_P(NODE) \
   DECL_LANG_FLAG_1 (PARM_DECL_CHECK (NODE))
 
+/* Nonzero for PARM_DECL node means it is a parameter of an earlier
+   declaration which is no longer in DECL_ARGUMENTS (DECL_CONTEXT (NODE))
+   chain because a function definition has been parsed later.  */
+#define OLD_PARM_DECL_P(NODE) \
+  TREE_LANG_FLAG_0 (PARM_DECL_CHECK (NODE))
+
+/* Nonzero for PARM_DECL node means it has different names on different
+   declarations of the same FUNCTION_DECL.  If it is unnamed on one and
+   named on another, that is still fine.  */
+#define MULTIPLE_NAMES_PARM_P(NODE) \
+  TREE_LANG_FLAG_2 (PARM_DECL_CHECK (NODE))
+
 /* Nonzero for a FIELD_DECL who's NSMDI is currently being
    instantiated.  */
 #define DECL_INSTANTIATING_NSDMI_P(NODE) \
@@ -6035,6 +6164,8 @@ extern bool comparing_override_contracts;
 
 /* In parser.cc.  */
 
+extern bool cp_preserve_using_decl;
+
 /* Nonzero if we are parsing an unevaluated operand: an operand to
    sizeof, typeof, or alignof.  This is a count since operands to
    sizeof can be nested.  */
@@ -6532,8 +6663,8 @@ enum ovl_op_flags {
 enum ovl_op_code {
   OVL_OP_ERROR_MARK,
   OVL_OP_NOP_EXPR,
-#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) OVL_OP_##CODE,
-#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) /* NOTHING */
+#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, META) OVL_OP_##CODE,
+#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING, META) /* NOTHING */
 #include "operators.def"
   OVL_OP_MAX
 };
@@ -6548,6 +6679,9 @@ struct GTY(()) ovl_op_info_t {
   const char *name;
   /* The mangled name of the operator.  */
   const char *mangled_name;
+  /* The name of the std::meta::operators enumerator without
+     the "op_" prefix if any (otherwise NULL).  */
+  const char *meta_name;
   /* The (regular) tree code.  */
   enum tree_code tree_code : 16;
   /* The (compressed) operator code.  */
@@ -6939,6 +7073,7 @@ enum cp_built_in_function {
   CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
   CP_BUILT_IN_SOURCE_LOCATION,
   CP_BUILT_IN_EH_PTR_ADJUST_REF,
+  CP_BUILT_IN_IS_STRING_LITERAL,
   CP_BUILT_IN_LAST
 };
 
@@ -7690,6 +7825,7 @@ extern tree get_copy_ctor                 (tree, tsubst_flags_t);
 extern tree get_copy_assign                    (tree);
 extern tree get_default_ctor                   (tree);
 extern tree get_dtor                           (tree, tsubst_flags_t);
+extern tree build_stub_type                    (tree, int, bool);
 extern tree build_stub_object                  (tree);
 extern bool is_stub_object                     (tree);
 extern tree build_invoke                       (tree, const_tree,
@@ -7850,6 +7986,7 @@ extern void remove_dummy_lambda_op (tree, tree);
 extern tree canonical_type_parameter           (tree);
 extern void push_access_scope                  (tree);
 extern void pop_access_scope                   (tree);
+extern tree current_function_decl_without_access_scope ();
 extern bool check_template_shadow              (tree);
 extern tree get_innermost_template_args                (tree, int);
 extern void maybe_begin_member_template_processing (tree);
@@ -7983,6 +8120,7 @@ extern int processing_template_parmlist;
 extern bool dependent_type_p                   (tree);
 extern bool dependent_scope_p                  (tree);
 extern bool dependentish_scope_p               (tree);
+extern bool dependent_namespace_p              (tree);
 extern bool any_dependent_template_arguments_p  (const_tree);
 extern bool any_erroneous_template_args_p       (const_tree);
 extern bool dependent_template_p               (tree);
@@ -8065,6 +8203,7 @@ extern tree add_outermost_template_args           (tree, tree);
 extern tree add_extra_args                     (tree, tree, tsubst_flags_t, tree);
 extern tree build_extra_args                   (tree, tree, tsubst_flags_t);
 extern void finish_expansion_stmt              (tree, tree, tsubst_flags_t, tree);
+extern tree convert_reflect_constant_arg       (tree, tree);
 
 /* in rtti.cc */
 /* A vector of all tinfo decls that haven't been emitted yet.  */
@@ -8263,9 +8402,10 @@ extern tree finish_template_template_parm       (tree, tree);
 extern tree begin_class_definition             (tree);
 extern void finish_template_decl               (tree);
 extern tree finish_template_type               (tree, tree, int);
-extern tree finish_base_specifier              (tree, tree, bool);
+extern tree finish_base_specifier              (tree, tree, bool, tree);
 extern void finish_member_declaration          (tree);
 extern bool outer_automatic_var_p              (tree);
+extern bool parsing_lambda_declarator          ();
 extern tree process_outer_var_ref              (tree, tsubst_flags_t, bool force_use = false);
 extern cp_expr finish_id_expression            (tree, tree, tree,
                                                 cp_id_kind *,
@@ -8346,6 +8486,7 @@ extern tree finish_decltype_type                (tree, bool, tsubst_flags_t);
 extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
 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_type                  (enum cp_trait_kind, tree, tree, tsubst_flags_t);
@@ -8560,6 +8701,7 @@ extern tree cxx_copy_lang_qualifiers              (const_tree, const_tree);
 
 extern void cxx_print_statistics               (void);
 extern bool maybe_warn_zero_as_null_pointer_constant (tree, location_t);
+extern bool annotation_p                       (tree) ATTRIBUTE_PURE;
 
 /* in ptree.cc */
 extern void cxx_print_xnode                    (FILE *, tree, int);
@@ -8613,7 +8755,7 @@ extern tree decay_conversion                      (tree,
 extern tree build_class_member_access_expr      (cp_expr, tree, tree, bool,
                                                 tsubst_flags_t);
 extern tree finish_class_member_access_expr     (cp_expr, tree, bool,
-                                                tsubst_flags_t);
+                                                tsubst_flags_t, bool = false);
 extern tree lookup_destructor                  (tree, tree, tree, tsubst_flags_t);
 extern tree build_dependent_operator_type      (tree, enum tree_code, bool);
 extern tree build_x_indirect_ref               (location_t, tree,
@@ -8924,6 +9066,8 @@ extern tree process_stmt_assume_attribute (tree, tree, location_t);
 extern bool simple_empty_class_p               (tree, tree, tree_code);
 extern tree fold_builtin_source_location       (const_tree);
 extern tree get_source_location_impl_type      ();
+extern bool immediate_escalating_function_p    (tree);
+extern void promote_function_to_consteval      (tree);
 extern tree cp_fold_immediate                  (tree *, mce_value,
                                                 tree = current_function_decl);
 extern void process_and_check_pending_immediate_escalating_fns ();
@@ -9080,6 +9224,7 @@ extern bool is_nondependent_static_init_expression (tree);
 extern bool is_static_init_expression    (tree);
 extern bool is_std_class (tree, const char *);
 extern bool is_std_allocator (tree);
+extern bool is_std_allocator_allocate (tree);
 extern bool potential_rvalue_constant_expression (tree);
 extern bool require_potential_constant_expression (tree);
 extern bool require_constant_expression (tree);
@@ -9121,6 +9266,24 @@ extern tree find_failing_clause                  (const constexpr_ctx *ctx, tree);
 extern void diagnose_failing_condition         (tree, location_t, bool,
                                                 const constexpr_ctx * = nullptr);
 extern bool replace_decl                       (tree *, tree, tree);
+extern tree cxa_allocate_and_throw_exception   (location_t, const constexpr_ctx *,
+                                                tree);
+
+/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST),
+   a glvalue (e.g. VAR_DECL or _REF), or nothing.  */
+enum value_cat {
+   vc_prvalue = 0,
+   vc_glvalue = 1,
+   vc_discard = 2
+};
+
+extern tree cxx_eval_constant_expression       (const constexpr_ctx *, tree,
+                                                value_cat, bool *, bool *,
+                                                tree *);
+extern bool cxx_constexpr_quiet_p              (const constexpr_ctx *);
+extern mce_value cxx_constexpr_manifestly_const_eval (const constexpr_ctx *);
+extern tree cxx_constexpr_caller               (const constexpr_ctx *);
+extern tree cxx_constexpr_consteval_block      (const constexpr_ctx *);
 
 /* An RAII sentinel used to restrict constexpr evaluation so that it
    doesn't do anything that causes extra DECL_UID generation.  */
@@ -9168,6 +9331,27 @@ extern tree co_await_get_resume_call             (tree await_expr);
 extern void coro_set_transform_functions       (tree, tree, tree);
 extern void coro_set_ramp_function             (tree, tree);
 
+/* In reflect.cc */
+extern void init_reflection ();
+extern bool metafunction_p (tree) ATTRIBUTE_PURE;
+extern tree direct_base_parent (tree) ATTRIBUTE_PURE;
+extern tree process_metafunction (const constexpr_ctx *, tree, tree,
+                                 bool *, bool *, tree *);
+extern tree get_reflection (location_t, tree, reflect_kind = REFLECT_UNDEF);
+extern tree get_null_reflection () ATTRIBUTE_PURE;
+extern tree splice (tree);
+extern bool check_out_of_consteval_use (tree, bool = true);
+extern bool consteval_only_p (tree) ATTRIBUTE_PURE;
+extern bool compare_reflections (tree, tree) ATTRIBUTE_PURE;
+extern bool valid_splice_type_p (const_tree) ATTRIBUTE_PURE;
+extern bool valid_splice_scope_p (const_tree) ATTRIBUTE_PURE;
+extern bool check_splice_expr (location_t, location_t, tree, bool, bool, bool)
+  ATTRIBUTE_PURE;
+extern tree make_splice_scope (tree, bool);
+extern bool dependent_splice_p (const_tree) ATTRIBUTE_PURE;
+extern tree reflection_mangle_prefix (tree, char [3]);
+extern void check_consteval_only_fn (tree);
+
 /* Inline bodies.  */
 
 inline tree
index 771f72106cd28fd90660d14ace9bd8fba0774cec..a984611ea8e2ac061b7c0369dc7af3eb87e51641 100644 (file)
@@ -1212,6 +1212,12 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
    if (concept_check_p (expr))
      expr = evaluate_concept_check (expr);
 
+  /* Detect using expressions of consteval-only types outside manifestly
+     constant-evaluated contexts.  We are going to discard this expression,
+     so we can't wait till cp_fold_immediate_r.  */
+  if (check_out_of_consteval_use (expr))
+    return error_mark_node;
+
   if (VOID_TYPE_P (TREE_TYPE (expr)))
     return expr;
 
index 3bb1097445ba6def788d8ce22751ed689c6a64db..db13a83ff902ebc9eb6b4e69898c1b5736e3dfd1 100644 (file)
@@ -813,6 +813,7 @@ pp_cxx_delete_expression (cxx_pretty_printer *pp, tree t)
       sizeof ... ( identifier )
       new-expression
       delete-expression
+      reflect-expression
 
    unary-operator: one of
       *   &   +   -  !
@@ -898,6 +899,19 @@ cxx_pretty_printer::unary_expression (tree t)
       pp_cxx_cast_expression (this, TREE_OPERAND (t, 0));
       break;
 
+    case REFLECT_EXPR:
+      {
+       pp_cxx_ws_string (this, "^^");
+       tree h = REFLECT_EXPR_HANDLE (t);
+       if (DECL_P (h))
+         declaration (h);
+       else if (TYPE_P (h))
+         type_id (h);
+       else
+         expression (h);
+      }
+      break;
+
     default:
       c_pretty_printer::unary_expression (t);
       break;
@@ -1184,6 +1198,7 @@ cxx_pretty_printer::expression (tree t)
     case ALIGNOF_EXPR:
     case NOEXCEPT_EXPR:
     case UNARY_PLUS_EXPR:
+    case REFLECT_EXPR:
       unary_expression (t);
       break;
 
@@ -1427,6 +1442,10 @@ cxx_pretty_printer::simple_type_specifier (tree t)
       pp_cxx_trait (this, t);
       break;
 
+    case META_TYPE:
+      pp_cxx_ws_string (this, "std::meta::info");
+      break;
+
     default:
       c_pretty_printer::simple_type_specifier (t);
       break;
@@ -1923,6 +1942,7 @@ cxx_pretty_printer::type_id (tree t)
     case NULLPTR_TYPE:
     case TEMPLATE_ID_EXPR:
     case OFFSET_TYPE:
+    case META_TYPE:
       pp_cxx_type_specifier_seq (this, t);
       if (TYPE_PTRMEM_P (t))
        abstract_declarator (t);
index 46a17a596edce9bdc5e363cd7c99297d00b54216..f1ba57cd177ee24c21cc6813e04a804034d57e92 100644 (file)
@@ -134,6 +134,7 @@ static bool identify_goto (tree, location_t, const location_t *,
    Namespaces,
 
        tree std_node;
+       tree std_meta_node;
        tree abi_node;
 
    A FUNCTION_DECL which can call `abort'.  Not necessarily the
@@ -3043,9 +3044,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 
       /* Merge parameter attributes. */
       tree oldarg, newarg;
-      for (oldarg = DECL_ARGUMENTS(olddecl), newarg = DECL_ARGUMENTS(newdecl);
-           oldarg && newarg;
-           oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg))
+      for (oldarg = DECL_ARGUMENTS (olddecl),
+          newarg = DECL_ARGUMENTS (newdecl);
+          oldarg && newarg;
+          oldarg = DECL_CHAIN (oldarg), newarg = DECL_CHAIN (newarg))
        {
           DECL_ATTRIBUTES (newarg)
            = (*targetm.merge_decl_attributes) (oldarg, newarg);
@@ -3063,6 +3065,62 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
                      "earlier declaration");
            }
           DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
+         /* Merge names for std::meta::has_identifier and
+            std::meta::{,u8}identifier_of purposes.  If they are different
+            and both oldarg and newarg are named, add flag to force that
+            std::meta::has_identifier returns false.  If one is named and
+            one is unnamed, if neither is a olddecl nor newdecl is definition,
+            propagate DECL_NAME to both.  Otherwise stash the old name into
+            "old parm name" artificial attribute.  */
+         if (flag_reflection && DECL_NAME (oldarg) != DECL_NAME (newarg))
+           {
+             if (DECL_NAME (oldarg) && DECL_NAME (newarg))
+               {
+                 /* Different names.  */
+                 MULTIPLE_NAMES_PARM_P (oldarg) = 1;
+                 MULTIPLE_NAMES_PARM_P (newarg) = 1;
+               }
+             else if (!new_defines_function
+                      && types_match
+                      && DECL_INITIAL (olddecl) == NULL_TREE)
+               {
+                 /* For 2 non-definitions with matching types,
+                    one is named and one unnamed, propagate name
+                    to both.  */
+                 if (DECL_NAME (oldarg))
+                   DECL_NAME (newarg) = DECL_NAME (oldarg);
+                 else
+                   DECL_NAME (oldarg) = DECL_NAME (newarg);
+               }
+             /* Depending on which PARM_DECL we'll keep, look at the other
+                PARM_DECL's name.  */
+             else if (tree name = ((new_defines_function || !types_match)
+                                   ? DECL_NAME (oldarg) : DECL_NAME (newarg)))
+               {
+                 tree opn = lookup_attribute ("old parm name",
+                                              DECL_ATTRIBUTES (oldarg));
+                 if (opn)
+                   {
+                     if (TREE_VALUE (TREE_VALUE (opn)) == name)
+                       /* Name already in "old parm name" attribute.  */;
+                     else
+                       {
+                         /* Different names.  */
+                         MULTIPLE_NAMES_PARM_P (oldarg) = 1;
+                         MULTIPLE_NAMES_PARM_P (newarg) = 1;
+                       }
+                   }
+                 else
+                   {
+                     /* Save name into attribute.  */
+                     DECL_ATTRIBUTES (newarg)
+                       = tree_cons (get_identifier ("old parm name"),
+                                    tree_cons (NULL_TREE, name, NULL_TREE),
+                                    DECL_ATTRIBUTES (newarg));
+                     DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
+                   }
+               }
+           }
        }
 
       if (DECL_TEMPLATE_INSTANTIATION (olddecl)
@@ -3160,6 +3218,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
          if (tree contracts = DECL_CONTRACTS (newdecl))
            remap_contracts (olddecl, newdecl, contracts, true);
 
+         /* Mark the old PARM_DECLs in case std::meta::parameters_of has
+            been called on the old declaration and reflections of those
+            arguments are held across this point and used later.
+            Such PARM_DECLs are no longer present in
+            DECL_ARGUMENTS (DECL_CONTEXT (oldarg)) chain.  */
+         for (tree oldarg = DECL_ARGUMENTS (olddecl);
+              oldarg; oldarg = DECL_CHAIN (oldarg))
+           OLD_PARM_DECL_P (oldarg) = 1;
+
          /* These need to be copied so that the names are available.
             Note that if the types do match, we'll preserve inline
             info and other bits, but if not, we won't.  */
@@ -5330,6 +5397,7 @@ initialize_predefined_identifiers (void)
     {"heap []", &heap_vec_identifier, cik_normal},
     {"omp", &omp_identifier, cik_normal},
     {"internal ", &internal_identifier, cik_normal},
+    {"annotation ", &annotation_identifier, cik_normal},
     {NULL, NULL, cik_normal}
   };
 
@@ -5563,6 +5631,13 @@ cxx_init_decl_processing (void)
       set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
     }
 
+  decl
+    = add_builtin_function ("__builtin_is_string_literal",
+                           bool_vaftype,
+                           CP_BUILT_IN_IS_STRING_LITERAL,
+                           BUILT_IN_FRONTEND, NULL, NULL_TREE);
+  set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+
   integer_two_node = build_int_cst (NULL_TREE, 2);
 
   /* Guess at the initial static decls size.  */
@@ -5693,6 +5768,9 @@ cxx_init_decl_processing (void)
   if (modules_p ())
     init_modules (parse_in);
 
+  if (flag_reflection)
+    init_reflection ();
+
   make_fname_decl = cp_make_fname_decl;
   start_fname_decls ();
 
@@ -7220,6 +7298,10 @@ maybe_commonize_var (tree decl)
   if (DECL_ARTIFICIAL (decl) && !DECL_DECOMPOSITION_P (decl))
     return;
 
+  /* These are not output at all.  */
+  if (consteval_only_p (decl))
+    return;
+
   /* Static data in a function with comdat linkage also has comdat
      linkage.  */
   if ((TREE_STATIC (decl)
@@ -8577,6 +8659,16 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
          init = NULL_TREE;
        }
     }
+  else if (!init && REFLECTION_TYPE_P (type))
+    {
+      /* [dcl.init.general]: To default-initialize an object of type
+        std::meta::info means that the object is zero-initialized.  */
+      DECL_INITIAL (decl)
+       = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
+      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
+      TREE_CONSTANT (decl) = true;
+      init = NULL_TREE;
+    }
   else
     {
       if (CLASS_TYPE_P (core_type = strip_array_types (type))
@@ -8696,6 +8788,14 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
   if (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl))
     return;
 
+  /* Don't output reflection variables.  */
+  if (consteval_only_p (decl))
+    {
+      /* Disable assemble_variable.  */
+      DECL_EXTERNAL (decl) = true;
+      return;
+    }
+
   /* We defer emission of local statics until the corresponding
      DECL_EXPR is expanded.  But with constexpr its function might never
      be expanded, so go ahead and tell cgraph about the variable now.  */
@@ -9743,6 +9843,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
            }
        }
 
+      /* Detect stuff like 'info r = ^^int;' outside a manifestly
+        constant-evaluated context.  */
+      check_out_of_consteval_use (decl);
+
       /* If this is a local variable that will need a mangled name,
         register it now.  We must do this before processing the
         initializer for the variable, since the initialization might
@@ -9751,7 +9855,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
         variable.  */
       if (DECL_FUNCTION_SCOPE_P (decl)
          && TREE_STATIC (decl)
-         && !DECL_ARTIFICIAL (decl))
+         && !DECL_ARTIFICIAL (decl)
+         && !consteval_only_p (decl))
        {
          /* The variable holding an anonymous union will have had its
             discriminator set in finish_anon_union, after which it's
@@ -10280,7 +10385,7 @@ get_tuple_size (tree type)
   inst = complete_type (inst);
   if (inst == error_mark_node
       || !COMPLETE_TYPE_P (inst)
-      || !CLASS_TYPE_P (type))
+      || !CLASS_TYPE_P (inst))
     return NULL_TREE;
   tree val = lookup_qualified_name (inst, value_identifier,
                                    LOOK_want::NORMAL, /*complain*/false);
@@ -12574,6 +12679,8 @@ grokfndecl (tree ctype,
   if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
     return NULL_TREE;
 
+  check_consteval_only_fn (decl);
+
   if (ctype == NULL_TREE || check)
     return decl;
 
@@ -18369,6 +18476,8 @@ xref_basetypes (tree ref, tree base_list)
   unsigned max_vbases = 0; /* Maximum direct & indirect virtual bases.  */
   unsigned max_bases = 0;  /* Maximum direct bases.  */
   unsigned max_dvbases = 0; /* Maximum direct virtual bases.  */
+  /* Highest direct base index with annotations.  */
+  unsigned max_annotated_base = 0;
   int i;
   tree default_access;
   tree igo_prev; /* Track Inheritance Graph Order.  */
@@ -18406,6 +18515,8 @@ xref_basetypes (tree ref, tree base_list)
       else
        {
          max_bases++;
+         if (TREE_CODE (TREE_PURPOSE (*basep)) == TREE_LIST)
+           max_annotated_base = max_bases;
          if (TREE_TYPE (*basep))
            max_dvbases++;
          if (CLASS_TYPE_P (basetype))
@@ -18434,7 +18545,8 @@ xref_basetypes (tree ref, tree base_list)
 
   if (max_bases)
     {
-      vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases);
+      vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases + max_annotated_base);
+      BINFO_BASE_ACCESSES (binfo)->quick_grow (max_bases + max_annotated_base);
       /* A C++98 POD cannot have base classes.  */
       CLASSTYPE_NON_LAYOUT_POD_P (ref) = true;
 
@@ -18464,6 +18576,30 @@ xref_basetypes (tree ref, tree base_list)
   for (igo_prev = binfo; base_list; base_list = TREE_CHAIN (base_list))
     {
       tree access = TREE_PURPOSE (base_list);
+      tree annotations = NULL_TREE;
+      if (TREE_CODE (access) == TREE_LIST)
+       {
+         annotations = TREE_VALUE (access);
+         access = TREE_PURPOSE (access);
+         for (tree *d = &annotations; *d; )
+           {
+             if (annotation_p (*d))
+               {
+                 tree name = get_attribute_name (*d);
+                 tree args = TREE_VALUE (*d);
+                 const attribute_spec *as
+                   = lookup_attribute_spec (TREE_PURPOSE (*d));
+                 bool no_add_attrs = false;
+                 as->handler (&binfo, name, args, 0, &no_add_attrs);
+                 if (no_add_attrs)
+                   {
+                     *d = TREE_CHAIN (*d);
+                     continue;
+                   }
+               }
+             d = &TREE_CHAIN (*d);
+           }
+       }
       int via_virtual = TREE_TYPE (base_list) != NULL_TREE;
       tree basetype = TREE_VALUE (base_list);
 
@@ -18530,8 +18666,12 @@ xref_basetypes (tree ref, tree base_list)
       if (!BINFO_INHERITANCE_CHAIN (base_binfo))
        BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
 
+      unsigned len;
+      len = BINFO_N_BASE_BINFOS (binfo);
       BINFO_BASE_APPEND (binfo, base_binfo);
-      BINFO_BASE_ACCESS_APPEND (binfo, access);
+      BINFO_BASE_ACCESS (binfo, len) = access;
+      if (len < max_annotated_base)
+       BINFO_BASE_ACCESS (binfo, max_bases + len) = annotations;
       continue;
 
     dropped_base:
@@ -18547,6 +18687,17 @@ xref_basetypes (tree ref, tree base_list)
          -= vec_safe_length (CLASSTYPE_VBASECLASSES (basetype));
     }
 
+  unsigned len = BINFO_N_BASE_BINFOS (binfo);
+  if (len < max_bases)
+    {
+      if (len && max_annotated_base)
+       memmove (&BINFO_BASE_ACCESS (binfo, len),
+                &BINFO_BASE_ACCESS (binfo, max_bases),
+                MIN (max_annotated_base, len) * sizeof (tree));
+      BINFO_BASE_ACCESSES (binfo)->truncate (len + MIN (max_annotated_base,
+                                                       len));
+    }
+
   if (CLASSTYPE_VBASECLASSES (ref)
       && max_vbases == 0)
     vec_free (CLASSTYPE_VBASECLASSES (ref));
@@ -18816,6 +18967,8 @@ finish_enum_value_list (tree enumtype)
   tree minnode, maxnode;
   tree t;
 
+  ENUM_BEING_DEFINED_P (enumtype) = 0;
+
   bool fixed_underlying_type_p
     = ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE;
 
index c6449844965c2ab80456ebdcf7f7719cb66dbb33..4de6345135f81437a37866efda00edfe01c35167 100644 (file)
@@ -1678,6 +1678,11 @@ is_late_template_attribute (tree attr, tree decl)
     = lookup_attribute_spec (TREE_PURPOSE (attr));
   tree arg;
 
+  /* Handle all annotations as late, so that they aren't incorrectly
+     reordered if some have dependent expressions and others don't.  */
+  if (annotation_p (attr))
+    return true;
+
   if (!spec)
     /* Unknown attribute.  */
     return false;
@@ -1956,6 +1961,10 @@ cp_check_const_attributes (tree attributes)
       if (cxx_contract_attribute_p (attr))
        continue;
 
+      /* Annotation arguments are handled in handle_annotation_attribute.  */
+      if (annotation_p (attr))
+       continue;
+
       tree arg;
       /* As we implement alignas using gnu::aligned attribute and
         alignas argument is a constant expression, force manifestly
@@ -2666,6 +2675,10 @@ maybe_make_one_only (tree decl)
   if (! flag_weak)
     return;
 
+  /* These are not to be output.  */
+  if (consteval_only_p (decl))
+    return;
+
   /* We can't set DECL_COMDAT on functions, or cp_finish_file will think
      we can get away with not emitting them if they aren't used.  We need
      to for variables so that cp_finish_decl will update their linkage,
@@ -2822,6 +2835,10 @@ var_finalized_p (tree var)
 void
 mark_needed (tree decl)
 {
+  /* These are not to be output.  */
+  if (consteval_only_p (decl))
+    return;
+
   TREE_USED (decl) = 1;
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
@@ -3040,7 +3057,7 @@ min_vis_r (tree *tp, int *walk_subtrees, void *data)
 /* walk_tree helper function for expr_visibility.  */
 
 static tree
-min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data)
+min_vis_expr_r (tree *tp, int *walk_subtrees, void *data)
 {
   int *vis_p = (int *)data;
   int tpvis = VISIBILITY_DEFAULT;
@@ -3112,6 +3129,59 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data)
       tpvis = type_visibility (DECL_CONTEXT (t));
       break;
 
+    case REFLECT_EXPR:
+      tree r;
+      r = REFLECT_EXPR_HANDLE (t);
+      switch (REFLECT_EXPR_KIND (t))
+       {
+       case REFLECT_BASE:
+         /* For direct base class relationship, determine visibility
+            from both D and B types.  */
+         tpvis = type_visibility (BINFO_TYPE (r));
+         if (tpvis > *vis_p)
+           *vis_p = tpvis;
+         tpvis = type_visibility (direct_base_parent (r));
+         *walk_subtrees = 0;
+         break;
+       case REFLECT_DATA_MEMBER_SPEC:
+         /* For data member description determine visibility
+            from the type.  */
+         tpvis = type_visibility (TREE_VEC_ELT (r, 0));
+         *walk_subtrees = 0;
+         break;
+       case REFLECT_PARM:
+         /* For function parameter reflection determine visibility
+            based on parent_of.  */
+         tpvis = expr_visibility (DECL_CONTEXT (r));
+         *walk_subtrees = 0;
+         break;
+       case REFLECT_ANNOTATION:
+         /* Annotations are always local to the TU.  */
+         tpvis = VISIBILITY_ANON;
+         *walk_subtrees = 0;
+         break;
+       case REFLECT_OBJECT:
+         r = get_base_address (r);
+         gcc_fallthrough ();
+       default:
+         if (TYPE_P (r))
+           {
+             tpvis = type_visibility (r);
+             *walk_subtrees = 0;
+             break;
+           }
+         if ((VAR_P (r) && decl_function_context (r))
+             || TREE_CODE (r) == PARM_DECL)
+           {
+             /* Block scope variables are local to the TU.  */
+             tpvis = VISIBILITY_ANON;
+             *walk_subtrees = 0;
+             break;
+           }
+         break;
+       }
+      break;
+
     default:
       break;
     }
@@ -4994,6 +5064,14 @@ prune_vars_needing_no_initialization (tree *vars)
          continue;
        }
 
+      /* Reflections are consteval-only types and we don't want them
+        to survive until gimplification.  */
+      if (consteval_only_p (decl))
+       {
+         var = &TREE_CHAIN (t);
+         continue;
+       }
+
       /* This variable is going to need initialization and/or
         finalization, so we add it to the list.  */
       *var = TREE_CHAIN (t);
@@ -5342,6 +5420,12 @@ no_linkage_error (tree decl)
     /* An imported decl is ok.  */
     return;
 
+  /* Metafunctions are magic and should be considered defined even though
+     they have no bodies.  ??? This can't be checked in decl_defined_p;
+     we'd get redefinition errors for some of our metafunctions.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL && metafunction_p (decl))
+    return;
+
   tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false);
   if (t == NULL_TREE)
     /* The type that got us on no_linkage_decls must have gotten a name for
@@ -6016,7 +6100,9 @@ c_parse_final_cleanups (void)
       /* Static data members are just like namespace-scope globals.  */
       FOR_EACH_VEC_SAFE_ELT (pending_statics, i, decl)
        {
-         if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl)
+         if (consteval_only_p (decl)
+             || var_finalized_p (decl)
+             || DECL_REALLY_EXTERN (decl)
              /* Don't write it out if we haven't seen a definition.  */
              || DECL_IN_AGGR_P (decl))
            continue;
@@ -6058,6 +6144,8 @@ c_parse_final_cleanups (void)
             should have synthesized it above.)  */
          && !(header_module_p ()
               && (DECL_DEFAULTED_FN (decl) || decl_tls_wrapper_p (decl)))
+         /* Metafunctions are never defined.  */
+         && !metafunction_p (decl)
          /* Don't complain if the template was defined.  */
          && !(DECL_TEMPLOID_INSTANTIATION (decl)
               && DECL_INITIAL (DECL_TEMPLATE_RESULT
index c51725555a9dfefa070e2b22ca0a4bb91f64818b..c184846066e00b1ad8173e4a99d464c5b1699620 100644 (file)
@@ -749,6 +749,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
 
     case TEMPLATE_DECL:
     case NAMESPACE_DECL:
+    case CONST_DECL:
       dump_decl (pp, t, flags & ~TFF_DECL_SPECIFIERS);
       break;
 
@@ -877,6 +878,14 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
       pp_string (pp, "std::nullptr_t");
       break;
 
+    case META_TYPE:
+      pp_string (pp, "std::meta::info");
+      break;
+
+    case SPLICE_SCOPE:
+      dump_expr (pp, SPLICE_SCOPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS);
+      break;
+
     default:
       pp_unsupported_tree (pp, t);
       /* Fall through.  */
@@ -1136,6 +1145,8 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
     case FIXED_POINT_TYPE:
     case NULLPTR_TYPE:
     case PACK_INDEX_TYPE:
+    case META_TYPE:
+    case SPLICE_SCOPE:
       dump_type (pp, t, flags);
       pp->set_padding (pp_before);
       break;
@@ -1269,6 +1280,8 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
     case FIXED_POINT_TYPE:
     case NULLPTR_TYPE:
     case PACK_INDEX_TYPE:
+    case META_TYPE:
+    case SPLICE_SCOPE:
       break;
 
     default:
@@ -1615,9 +1628,14 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
        tree name = TREE_OPERAND (t, 0);
        tree args = TREE_OPERAND (t, 1);
 
-       if (!identifier_p (name))
-         name = OVL_NAME (name);
-       dump_decl (pp, name, flags);
+       if (TREE_CODE (name) == SPLICE_EXPR)
+         dump_expr (pp, name, flags);
+       else
+         {
+           if (!identifier_p (name))
+             name = OVL_NAME (name);
+           dump_decl (pp, name, flags);
+         }
        pp_cxx_begin_template_argument_list (pp);
        if (args == error_mark_node)
          pp_string (pp, M_("<template arguments error>"));
@@ -3311,6 +3329,27 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
        }
       break;
 
+    case REFLECT_EXPR:
+      {
+       pp_string (pp, "^^");
+       tree h = REFLECT_EXPR_HANDLE (t);
+       if (DECL_P (h))
+         dump_decl (pp, h, flags);
+       else if (TYPE_P (h))
+         dump_type (pp, h, flags);
+       else
+         dump_expr (pp, h, flags);
+       break;
+      }
+
+    case SPLICE_EXPR:
+      pp_cxx_ws_string (pp, "[:");
+      pp_cxx_whitespace (pp);
+      dump_expr (pp, TREE_OPERAND (t, 0), flags);
+      pp_cxx_whitespace (pp);
+      pp_cxx_ws_string (pp, ":]");
+      break;
+
       /*  This list is incomplete, but should suffice for now.
          It is very important that `sorry' does not call
          `report_error_function'.  That could cause an infinite loop.  */
index 01e3d007a49193eeaef359182b4172acab74057f..7b17220ee9b0e16af9270718f4d709c96c6d037d 100644 (file)
@@ -178,6 +178,10 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
 
   if (type == error_mark_node)
     ;
+  else if (REFLECTION_TYPE_P (type))
+    /* [dcl.init.general]: "if T is std::meta::info, the object is initialized
+       to a null reflection value".  */
+    init = get_null_reflection ();
   else if (static_storage_p && zero_init_p (type))
     /* In order to save space, we do not explicitly build initializers
        for items that do not need them.  GCC's semantics are that
@@ -993,6 +997,9 @@ perform_member_init (tree member, tree init, hash_set<tree> &uninitialized)
   if (init == error_mark_node)
     return;
 
+  if (check_out_of_consteval_use (init))
+    return;
+
   /* Effective C++ rule 12 requires that all data members be
      initialized.  */
   if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
index c490fe8fca961f69493ac347ac01941dfb8557dc..27c5192ab894217a1325e888db9baf7bd97c6eac 100644 (file)
@@ -85,12 +85,12 @@ cxx_finish (void)
 ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
   {
     {
-      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
-      {NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
-#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
-      {NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
+      {NULL_TREE, NULL, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
+      {NULL_TREE, NULL, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
+#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, META) \
+      {NULL_TREE, NAME, MANGLING, META, CODE, OVL_OP_##CODE, FLAGS},
 #define OPERATOR_TRANSITION }, {                       \
-      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
+      {NULL_TREE, NULL, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
 #include "operators.def"
     }
   };
index 7e39664ce8efc69d2dcb258f99cb9b48d5a20bd1..06bd396c03ef254c6ae5a54d46606b61e780edd0 100644 (file)
@@ -2439,6 +2439,7 @@ write_local_name (tree function, const tree local_entity,
                                 # class member access
      <type> ::= DT <expression> # decltype of an expression
      <type> ::= Dn              # decltype of nullptr
+     <type> ::= Dm             # decltype of ^^int
 
    TYPE is a type node.  */
 
@@ -2716,6 +2717,11 @@ write_type (tree type)
                ++is_builtin_type;
              break;
 
+           case META_TYPE:
+             write_string ("Dm");
+             ++is_builtin_type;
+             break;
+
            case TYPEOF_TYPE:
              sorry ("mangling %<typeof%>, use %<decltype%> instead");
              break;
@@ -3467,7 +3473,8 @@ write_expression (tree expr)
     write_template_param (expr);
   /* Handle literals.  */
   else if (TREE_CODE_CLASS (code) == tcc_constant
-          || code == CONST_DECL)
+          || code == CONST_DECL
+          || code == REFLECT_EXPR)
     write_template_arg_literal (expr);
   else if (code == EXCESS_PRECISION_EXPR
           && TREE_CODE (TREE_OPERAND (expr, 0)) == REAL_CST)
@@ -4104,6 +4111,140 @@ write_expression (tree expr)
     }
 }
 
+/* Non-terminal <reflection>.
+
+     <reflection> ::= nu                               # null reflection
+                 ::= vl <expression>                   # value
+                 ::= ob <expression>                   # object
+                 ::= vr <variable name>                # variable
+                 ::= sb <sb name>                      # structured binding
+                 ::= fn <function encoding>            # function
+                 ::= pa [ <nonnegative number> ] _ <encoding>  # fn param
+                 ::= en <prefix> <unqualified-name>    # enumerator
+                 ::= an [ <nonnegative number> ] _     # annotation
+                 ::= ta <alias prefix>                 # type alias
+                 ::= ty <type>                         # type
+                 ::= dm <prefix> <unqualified-name>    # ns data member
+                 ::= un <prefix> [ <nonnegative number> ] _ # unnamed bitfld
+                 ::= ct [ <prefix> ] <unqualified-name> # class template
+                 ::= ft [ <prefix> ] <unqualified-name> # function template
+                 ::= vt [ <prefix> ] <unqualified-name> # variable template
+                 ::= at [ <prefix> ] <unqualified-name> # alias template
+                 ::= co [ <prefix> ] <unqualified-name> # concept
+                 ::= na [ <prefix> ] <unqualified-name> # namespace alias
+                 ::= ns [ <prefix> ] <unqualified-name> # namespace
+                 ::= ng                                # ^^::
+                 ::= ba [ <nonnegative number> ] _ <type> # dir. base cls rel
+                 ::= ds <type> _ [ <unqualified-name> ] _
+                     [ <alignment number> ] _ [ <bit-width number> ] _
+                     [ n ]                             # data member spec  */
+
+static void
+write_reflection (tree refl)
+{
+  char prefix[3];
+  tree arg = reflection_mangle_prefix (refl, prefix);
+  write_string (prefix);
+  /* If there is no argument, nothing further needs to be mangled.  */
+  if (arg == NULL_TREE)
+    return;
+  if (strcmp (prefix, "vl") == 0 || strcmp (prefix, "ob") == 0)
+    write_expression (arg);
+  else if (strcmp (prefix, "vr") == 0 || strcmp (prefix, "sb") == 0)
+    write_name (arg, 0);
+  else if (strcmp (prefix, "fn") == 0)
+    write_encoding (arg);
+  else if (strcmp (prefix, "pa") == 0)
+    {
+      tree fn = DECL_CONTEXT (arg);
+      tree args = FUNCTION_FIRST_USER_PARM (fn);
+      int idx = 0;
+      while (arg != args)
+       {
+         args = DECL_CHAIN (args);
+         ++idx;
+       }
+      write_compact_number (idx);
+      write_encoding (fn);
+    }
+  else if (strcmp (prefix, "en") == 0)
+    {
+      write_prefix (decl_mangling_context (arg));
+      write_unqualified_name (arg);
+    }
+  else if (strcmp (prefix, "an") == 0)
+    write_compact_number (tree_to_uhwi (arg));
+  else if (strcmp (prefix, "ta") == 0)
+    {
+      arg = TYPE_NAME (arg);
+      write_prefix (arg);
+    }
+  else if (strcmp (prefix, "ty") == 0)
+    write_type (arg);
+  else if (strcmp (prefix, "dm") == 0)
+    {
+      tree ctx = decl_mangling_context (arg);
+      while (ctx && ANON_UNION_TYPE_P (ctx))
+       ctx = decl_mangling_context (TYPE_NAME (ctx));
+      write_prefix (ctx);
+      write_unqualified_name (arg);
+    }
+  else if (strcmp (prefix, "un") == 0)
+    {
+      tree ctx = DECL_CONTEXT (arg);
+      int idx = 0;
+      for (tree f = TYPE_FIELDS (ctx); f; f = DECL_CHAIN (f))
+       if (f == arg)
+         break;
+       else if (TREE_CODE (f) == FIELD_DECL && DECL_UNNAMED_BIT_FIELD (f))
+         ++idx;
+      write_prefix (decl_mangling_context (arg));
+      write_compact_number (idx);
+    }
+  else if (strcmp (prefix, "ct") == 0
+          || strcmp (prefix, "ft") == 0
+          || strcmp (prefix, "vt") == 0
+          || strcmp (prefix, "at") == 0
+          || strcmp (prefix, "co") == 0
+          || strcmp (prefix, "na") == 0
+          || strcmp (prefix, "ns") == 0)
+    {
+      write_prefix (decl_mangling_context (arg));
+      write_unqualified_name (arg);
+    }
+  else if (strcmp (prefix, "ba") == 0)
+    {
+      gcc_assert (TREE_CODE (arg) == TREE_BINFO);
+      tree c = arg, base_binfo;
+      while (BINFO_INHERITANCE_CHAIN (c))
+       c = BINFO_INHERITANCE_CHAIN (c);
+
+      unsigned idx;
+      for (idx = 0; BINFO_BASE_ITERATE (c, idx, base_binfo); idx++)
+       if (base_binfo == arg)
+         break;
+      write_compact_number (idx);
+      write_type (BINFO_TYPE (c));
+    }
+  else if (strcmp (prefix, "ds") == 0)
+    {
+      gcc_assert (TREE_CODE (arg) == TREE_VEC);
+      write_type (TREE_VEC_ELT (arg, 0));
+      write_char ('_');
+      if (TREE_VEC_ELT (arg, 1))
+       write_unqualified_id (TREE_VEC_ELT (arg, 1));
+      write_char ('_');
+      if (TREE_VEC_ELT (arg, 2))
+       write_number (tree_to_shwi (TREE_VEC_ELT (arg, 2)), 0, 10);
+      write_char ('_');
+      if (TREE_VEC_ELT (arg, 3))
+       write_number (tree_to_shwi (TREE_VEC_ELT (arg, 3)), 0, 10);
+      write_char ('_');
+      if (integer_nonzerop (TREE_VEC_ELT (arg, 4)))
+       write_char ('n');
+    }
+}
+
 /* Literal subcase of non-terminal <template-arg>.
 
      "Literal arguments, e.g. "A<42L>", are encoded with their type
@@ -4192,6 +4333,10 @@ write_template_arg_literal (const tree value)
          break;
        }
 
+      case REFLECT_EXPR:
+       write_reflection (value);
+       break;
+
       default:
        gcc_unreachable ();
       }
@@ -4273,7 +4418,8 @@ write_template_arg (tree node)
     write_template_template_arg (node);
   else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST)
           || code == CONST_DECL
-          || null_member_pointer_value_p (node))
+          || null_member_pointer_value_p (node)
+          || code == REFLECT_EXPR)
     write_template_arg_literal (node);
   else if (code == EXCESS_PRECISION_EXPR
           && TREE_CODE (TREE_OPERAND (node, 0)) == REAL_CST)
diff --git a/gcc/cp/metafns.gperf b/gcc/cp/metafns.gperf
new file mode 100644 (file)
index 0000000..b4e9362
--- /dev/null
@@ -0,0 +1,688 @@
+%language=C++
+%define class-name metafn_lookup
+%struct-type
+%{
+/* Copyright (C) 2025-2026 Free Software Foundation, Inc.
+   Written by Jakub Jelinek <jakub@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+enum metafn_code {
+  METAFN_OPERATOR_OF,
+  METAFN_SYMBOL_OF,
+  METAFN_U8SYMBOL_OF,
+  METAFN_HAS_IDENTIFIER,
+  METAFN_IDENTIFIER_OF,
+  METAFN_U8IDENTIFIER_OF,
+  METAFN_DISPLAY_STRING_OF,
+  METAFN_U8DISPLAY_STRING_OF,
+  METAFN_SOURCE_LOCATION_OF,
+  METAFN_TYPE_OF,
+  METAFN_OBJECT_OF,
+  METAFN_CONSTANT_OF,
+  METAFN_IS_PUBLIC,
+  METAFN_IS_PROTECTED,
+  METAFN_IS_PRIVATE,
+  METAFN_IS_VIRTUAL,
+  METAFN_IS_PURE_VIRTUAL,
+  METAFN_IS_OVERRIDE,
+  METAFN_IS_FINAL,
+  METAFN_IS_DELETED,
+  METAFN_IS_DEFAULTED,
+  METAFN_IS_USER_PROVIDED,
+  METAFN_IS_USER_DECLARED,
+  METAFN_IS_EXPLICIT,
+  METAFN_IS_NOEXCEPT,
+  METAFN_IS_BIT_FIELD,
+  METAFN_IS_ENUMERATOR,
+  METAFN_IS_ANNOTATION,
+  METAFN_IS_CONST,
+  METAFN_IS_VOLATILE,
+  METAFN_IS_MUTABLE_MEMBER,
+  METAFN_IS_LVALUE_REFERENCE_QUALIFIED,
+  METAFN_IS_RVALUE_REFERENCE_QUALIFIED,
+  METAFN_HAS_STATIC_STORAGE_DURATION,
+  METAFN_HAS_THREAD_STORAGE_DURATION,
+  METAFN_HAS_AUTOMATIC_STORAGE_DURATION,
+  METAFN_HAS_INTERNAL_LINKAGE,
+  METAFN_HAS_MODULE_LINKAGE,
+  METAFN_HAS_EXTERNAL_LINKAGE,
+  METAFN_HAS_C_LANGUAGE_LINKAGE,
+  METAFN_HAS_LINKAGE,
+  METAFN_IS_COMPLETE_TYPE,
+  METAFN_IS_ENUMERABLE_TYPE,
+  METAFN_IS_VARIABLE,
+  METAFN_IS_TYPE,
+  METAFN_IS_NAMESPACE,
+  METAFN_IS_TYPE_ALIAS,
+  METAFN_IS_NAMESPACE_ALIAS,
+  METAFN_IS_FUNCTION,
+  METAFN_IS_CONVERSION_FUNCTION,
+  METAFN_IS_OPERATOR_FUNCTION,
+  METAFN_IS_LITERAL_OPERATOR,
+  METAFN_IS_SPECIAL_MEMBER_FUNCTION,
+  METAFN_IS_CONSTRUCTOR,
+  METAFN_IS_DEFAULT_CONSTRUCTOR,
+  METAFN_IS_COPY_CONSTRUCTOR,
+  METAFN_IS_MOVE_CONSTRUCTOR,
+  METAFN_IS_ASSIGNMENT,
+  METAFN_IS_COPY_ASSIGNMENT,
+  METAFN_IS_MOVE_ASSIGNMENT,
+  METAFN_IS_DESTRUCTOR,
+  METAFN_IS_FUNCTION_PARAMETER,
+  METAFN_IS_EXPLICIT_OBJECT_PARAMETER,
+  METAFN_HAS_DEFAULT_ARGUMENT,
+  METAFN_HAS_ELLIPSIS_PARAMETER,
+  METAFN_IS_TEMPLATE,
+  METAFN_IS_FUNCTION_TEMPLATE,
+  METAFN_IS_VARIABLE_TEMPLATE,
+  METAFN_IS_CLASS_TEMPLATE,
+  METAFN_IS_ALIAS_TEMPLATE,
+  METAFN_IS_CONVERSION_FUNCTION_TEMPLATE,
+  METAFN_IS_OPERATOR_FUNCTION_TEMPLATE,
+  METAFN_IS_LITERAL_OPERATOR_TEMPLATE,
+  METAFN_IS_CONSTRUCTOR_TEMPLATE,
+  METAFN_IS_CONCEPT,
+  METAFN_IS_VALUE,
+  METAFN_IS_OBJECT,
+  METAFN_IS_STRUCTURED_BINDING,
+  METAFN_IS_CLASS_MEMBER,
+  METAFN_IS_NAMESPACE_MEMBER,
+  METAFN_IS_NONSTATIC_DATA_MEMBER,
+  METAFN_IS_STATIC_MEMBER,
+  METAFN_IS_BASE,
+  METAFN_HAS_DEFAULT_MEMBER_INITIALIZER,
+  METAFN_HAS_PARENT,
+  METAFN_PARENT_OF,
+  METAFN_DEALIAS,
+  METAFN_HAS_TEMPLATE_ARGUMENTS,
+  METAFN_TEMPLATE_OF,
+  METAFN_TEMPLATE_ARGUMENTS_OF,
+  METAFN_PARAMETERS_OF,
+  METAFN_VARIABLE_OF,
+  METAFN_RETURN_TYPE_OF,
+  METAFN_IS_ACCESSIBLE,
+  METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS,
+  METAFN_HAS_INACCESSIBLE_BASES,
+  METAFN_HAS_INACCESSIBLE_SUBOBJECTS,
+  METAFN_MEMBERS_OF,
+  METAFN_BASES_OF,
+  METAFN_STATIC_DATA_MEMBERS_OF,
+  METAFN_NONSTATIC_DATA_MEMBERS_OF,
+  METAFN_SUBOBJECTS_OF,
+  METAFN_ENUMERATORS_OF,
+  METAFN_OFFSET_OF,
+  METAFN_SIZE_OF,
+  METAFN_ALIGNMENT_OF,
+  METAFN_BIT_SIZE_OF,
+  METAFN_EXTRACT,
+  METAFN_CAN_SUBSTITUTE,
+  METAFN_SUBSTITUTE,
+  METAFN_REFLECT_CONSTANT,
+  METAFN_REFLECT_OBJECT,
+  METAFN_REFLECT_FUNCTION,
+  METAFN_REFLECT_CONSTANT_STRING,
+  METAFN_REFLECT_CONSTANT_ARRAY,
+  METAFN_DATA_MEMBER_SPEC,
+  METAFN_IS_DATA_MEMBER_SPEC,
+  METAFN_DEFINE_AGGREGATE,
+  METAFN_IS_VOID_TYPE,
+  METAFN_IS_NULL_POINTER_TYPE,
+  METAFN_IS_INTEGRAL_TYPE,
+  METAFN_IS_FLOATING_POINT_TYPE,
+  METAFN_IS_ARRAY_TYPE,
+  METAFN_IS_POINTER_TYPE,
+  METAFN_IS_LVALUE_REFERENCE_TYPE,
+  METAFN_IS_RVALUE_REFERENCE_TYPE,
+  METAFN_IS_MEMBER_OBJECT_POINTER_TYPE,
+  METAFN_IS_MEMBER_FUNCTION_POINTER_TYPE,
+  METAFN_IS_ENUM_TYPE,
+  METAFN_IS_UNION_TYPE,
+  METAFN_IS_CLASS_TYPE,
+  METAFN_IS_FUNCTION_TYPE,
+  METAFN_IS_REFLECTION_TYPE,
+  METAFN_IS_REFERENCE_TYPE,
+  METAFN_IS_ARITHMETIC_TYPE,
+  METAFN_IS_FUNDAMENTAL_TYPE,
+  METAFN_IS_OBJECT_TYPE,
+  METAFN_IS_SCALAR_TYPE,
+  METAFN_IS_COMPOUND_TYPE,
+  METAFN_IS_MEMBER_POINTER_TYPE,
+  METAFN_IS_CONST_TYPE,
+  METAFN_IS_VOLATILE_TYPE,
+  METAFN_IS_TRIVIALLY_COPYABLE_TYPE,
+  METAFN_IS_STANDARD_LAYOUT_TYPE,
+  METAFN_IS_EMPTY_TYPE,
+  METAFN_IS_POLYMORPHIC_TYPE,
+  METAFN_IS_ABSTRACT_TYPE,
+  METAFN_IS_FINAL_TYPE,
+  METAFN_IS_AGGREGATE_TYPE,
+  METAFN_IS_CONSTEVAL_ONLY_TYPE,
+  METAFN_IS_SIGNED_TYPE,
+  METAFN_IS_UNSIGNED_TYPE,
+  METAFN_IS_BOUNDED_ARRAY_TYPE,
+  METAFN_IS_UNBOUNDED_ARRAY_TYPE,
+  METAFN_IS_SCOPED_ENUM_TYPE,
+  METAFN_IS_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_DEFAULT_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_COPY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_MOVE_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_ASSIGNABLE_TYPE,
+  METAFN_IS_COPY_ASSIGNABLE_TYPE,
+  METAFN_IS_MOVE_ASSIGNABLE_TYPE,
+  METAFN_IS_SWAPPABLE_WITH_TYPE,
+  METAFN_IS_SWAPPABLE_TYPE,
+  METAFN_IS_DESTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_COPY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_ASSIGNABLE_TYPE,
+  METAFN_IS_TRIVIALLY_COPY_ASSIGNABLE_TYPE,
+  METAFN_IS_TRIVIALLY_MOVE_ASSIGNABLE_TYPE,
+  METAFN_IS_TRIVIALLY_DESTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_DEFAULT_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_COPY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_MOVE_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_ASSIGNABLE_TYPE,
+  METAFN_IS_NOTHROW_COPY_ASSIGNABLE_TYPE,
+  METAFN_IS_NOTHROW_MOVE_ASSIGNABLE_TYPE,
+  METAFN_IS_NOTHROW_SWAPPABLE_WITH_TYPE,
+  METAFN_IS_NOTHROW_SWAPPABLE_TYPE,
+  METAFN_IS_NOTHROW_DESTRUCTIBLE_TYPE,
+  METAFN_IS_IMPLICIT_LIFETIME_TYPE,
+  METAFN_HAS_VIRTUAL_DESTRUCTOR,
+  METAFN_HAS_UNIQUE_OBJECT_REPRESENTATIONS,
+  METAFN_REFERENCE_CONSTRUCTS_FROM_TEMPORARY,
+  METAFN_REFERENCE_CONVERTS_FROM_TEMPORARY,
+  METAFN_RANK,
+  METAFN_EXTENT,
+  METAFN_IS_SAME_TYPE,
+  METAFN_IS_BASE_OF_TYPE,
+  METAFN_IS_VIRTUAL_BASE_OF_TYPE,
+  METAFN_IS_CONVERTIBLE_TYPE,
+  METAFN_IS_NOTHROW_CONVERTIBLE_TYPE,
+  METAFN_IS_LAYOUT_COMPATIBLE_TYPE,
+  METAFN_IS_POINTER_INTERCONVERTIBLE_BASE_OF_TYPE,
+  METAFN_IS_INVOCABLE_TYPE,
+  METAFN_IS_INVOCABLE_R_TYPE,
+  METAFN_IS_NOTHROW_INVOCABLE_TYPE,
+  METAFN_IS_NOTHROW_INVOCABLE_R_TYPE,
+  METAFN_REMOVE_CONST,
+  METAFN_REMOVE_VOLATILE,
+  METAFN_REMOVE_CV,
+  METAFN_ADD_CONST,
+  METAFN_ADD_VOLATILE,
+  METAFN_ADD_CV,
+  METAFN_REMOVE_REFERENCE,
+  METAFN_ADD_LVALUE_REFERENCE,
+  METAFN_ADD_RVALUE_REFERENCE,
+  METAFN_MAKE_SIGNED,
+  METAFN_MAKE_UNSIGNED,
+  METAFN_REMOVE_EXTENT,
+  METAFN_REMOVE_ALL_EXTENTS,
+  METAFN_REMOVE_POINTER,
+  METAFN_ADD_POINTER,
+  METAFN_REMOVE_CVREF,
+  METAFN_DECAY,
+  METAFN_COMMON_TYPE,
+  METAFN_COMMON_REFERENCE,
+  METAFN_UNDERLYING_TYPE,
+  METAFN_INVOKE_RESULT,
+  METAFN_UNWRAP_REFERENCE,
+  METAFN_UNWRAP_REF_DECAY,
+  METAFN_TUPLE_SIZE,
+  METAFN_TUPLE_ELEMENT,
+  METAFN_VARIANT_SIZE,
+  METAFN_VARIANT_ALTERNATIVE,
+  METAFN_TYPE_ORDER,
+  METAFN_ANNOTATIONS_OF,
+  METAFN_ANNOTATIONS_OF_WITH_TYPE,
+  /* Special metafunctions.  */
+  METAFN_ACCESS_CONTEXT_CURRENT,
+  METAFN_EXCEPTION__S_EXCEPTION_CVT_TO_UTF8,
+  METAFN_EXCEPTION__S_EXCEPTION_CVT_FROM_UTF8
+};
+
+enum {
+  METAFN_KIND_SHIFT = 5,
+  METAFN_KIND_MASK = (1 << METAFN_KIND_SHIFT) - 1
+};
+
+/* Possible return types of metafunctions.  */
+enum metafn_kind_ret {
+  METAFN_KIND_RET_BOOL,
+  METAFN_KIND_RET_INFO,
+  METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_RET_MEMBER_OFFSET,
+  METAFN_KIND_RET_OPERATORS,
+  METAFN_KIND_RET_SOURCE_LOCATION,
+  METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_RET_U8STRING_VIEW,
+  METAFN_KIND_RET_STRONG_ORDERING,
+  METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_RET_ACCESS_CONTEXT,
+  METAFN_KIND_RET_TEMPLATE_PARM,
+};
+static_assert (METAFN_KIND_RET_TEMPLATE_PARM <= (int) METAFN_KIND_MASK);
+
+/* Possible argument types of metafunctions.  */
+enum metafn_kind_arg {
+  METAFN_KIND_ARG_VOID = 0,
+  METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARG_TINFO, /* info argument which throws if not a type.  */
+  METAFN_KIND_ARG_REFLECTION_RANGE,
+  /* reflection_range with type infos only.  */
+  METAFN_KIND_ARG_REFLECTION_RANGET,
+  METAFN_KIND_ARG_INPUT_RANGE,
+  METAFN_KIND_ARG_SIZE_T,
+  METAFN_KIND_ARG_UNSIGNED,
+  METAFN_KIND_ARG_OPERATORS,
+  METAFN_KIND_ARG_ACCESS_CONTEXT,
+  METAFN_KIND_ARG_DATA_MEMBER_OPTIONS,
+  METAFN_KIND_ARG_TEMPLATE_PARM, /* Some other template parameter.  */
+  METAFN_KIND_ARG_TEMPLATE_PARM_REF /* Reference to template parameter.  */
+};
+static_assert (METAFN_KIND_ARG_TEMPLATE_PARM_REF <= (int) METAFN_KIND_MASK);
+
+/* Possible sets of 0-3 arguments of metafunctions.  */
+enum metafn_kind_args {
+  METAFN_KIND_ARGS_VOID = METAFN_KIND_ARG_VOID,
+  METAFN_KIND_ARGS_INFO = METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO = METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_REFLECTION_RANGET = METAFN_KIND_ARG_REFLECTION_RANGET,
+  METAFN_KIND_ARGS_INPUT_RANGE = METAFN_KIND_ARG_INPUT_RANGE,
+  METAFN_KIND_ARGS_OPERATORS = METAFN_KIND_ARG_OPERATORS,
+  METAFN_KIND_ARGS_TEMPLATE_PARM = METAFN_KIND_ARG_TEMPLATE_PARM,
+  METAFN_KIND_ARGS_TEMPLATE_PARM_REF = METAFN_KIND_ARG_TEMPLATE_PARM_REF,
+  METAFN_KIND_ARGS_INFO_INFO
+    = (METAFN_KIND_ARG_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO_TINFO
+    = (METAFN_KIND_ARG_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_TINFO_UNSIGNED
+    = (METAFN_KIND_ARG_UNSIGNED << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_INFO_ACCESS_CONTEXT
+    = (METAFN_KIND_ARG_ACCESS_CONTEXT << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO_DATA_MEMBER_OPTIONS
+    = (METAFN_KIND_ARG_DATA_MEMBER_OPTIONS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_INFO_REFLECTION_RANGE
+    = (METAFN_KIND_ARG_REFLECTION_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARG_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_SIZE_T_TINFO
+    = (METAFN_KIND_ARG_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_ARG_SIZE_T,
+  METAFN_KIND_ARGS_TINFO_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARG_REFLECTION_RANGET << (2 * METAFN_KIND_SHIFT))
+      | METAFN_KIND_ARGS_TINFO_TINFO,
+};
+
+/* This encodes metafn_kind_ret in the low METAFN_KIND_SHIFT bits, then
+   first argument metafn_kind_arg in METAFN_KIND_SHIFT bits above that,
+   second argument metafn_kind_arg in METAFN_KIND_SHIFT bits above that
+   and third argument metafn_kind_arg in METAFN_KIND_SHIFT bits above that.
+   Missing argument is METAFN_KIND_ARG_VOID aka 0.  */
+enum metafn_kind {
+  METAFN_KIND_BOOL_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO
+    = (METAFN_KIND_ARGS_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT
+    = (METAFN_KIND_ARGS_INFO_ACCESS_CONTEXT << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO_TINFO
+    = (METAFN_KIND_ARGS_TINFO_TINFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_TINFO_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_TINFO_TINFO_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_INFO_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TINFO
+    = (METAFN_KIND_ARGS_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_TINFO_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TINFO_DATA_MEMBER_OPTIONS
+    = (METAFN_KIND_ARGS_TINFO_DATA_MEMBER_OPTIONS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_INFO_REFLECTION_RANGE
+    = (METAFN_KIND_ARGS_INFO_REFLECTION_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_INPUT_RANGE
+    = (METAFN_KIND_ARGS_INPUT_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TEMPLATE_PARM
+    = (METAFN_KIND_ARGS_TEMPLATE_PARM << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TEMPLATE_PARM_REF
+    = (METAFN_KIND_ARGS_TEMPLATE_PARM_REF << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_SIZE_T_TINFO
+    = (METAFN_KIND_ARGS_SIZE_T_TINFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_MEMBER_OFFSET_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_MEMBER_OFFSET,
+  METAFN_KIND_OPERATORS_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_OPERATORS,
+  METAFN_KIND_SIZE_T_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_SIZE_T_TINFO
+    = (METAFN_KIND_ARGS_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_SIZE_T_TINFO_UNSIGNED
+    = (METAFN_KIND_ARGS_TINFO_UNSIGNED << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_SOURCE_LOCATION_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_SOURCE_LOCATION,
+  METAFN_KIND_STRING_VIEW_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_STRING_VIEW_OPERATORS
+    = (METAFN_KIND_ARGS_OPERATORS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_U8STRING_VIEW_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_U8STRING_VIEW,
+  METAFN_KIND_U8STRING_VIEW_OPERATORS
+    = (METAFN_KIND_ARGS_OPERATORS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_U8STRING_VIEW,
+  METAFN_KIND_STRONG_ORDERING_TINFO_TINFO
+    = (METAFN_KIND_ARGS_TINFO_TINFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRONG_ORDERING,
+  METAFN_KIND_VECTOR_INFO_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_VECTOR_INFO_INFO_INFO
+    = (METAFN_KIND_ARGS_INFO_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT
+    = (METAFN_KIND_ARGS_INFO_ACCESS_CONTEXT << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_TEMPLATE_PARM_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_TEMPLATE_PARM,
+  METAFN_KIND_ACCESS_CONTEXT_VOID
+    = (METAFN_KIND_ARGS_VOID << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_ACCESS_CONTEXT,
+  METAFN_KIND_STRING_VIEW_INPUT_RANGE
+    = (METAFN_KIND_ARGS_INPUT_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_U8STRING_VIEW_INPUT_RANGE
+    = (METAFN_KIND_ARGS_INPUT_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_U8STRING_VIEW
+};
+%}
+struct metafn_info
+{
+  /* A name within "std::meta::" (or "std::meta::access_context::").  */
+  const char *name;
+
+  /* METAFN_ code.  */
+  metafn_code code;
+
+  /* METAFN_KIND_ kind of arguments and return type.  */
+  metafn_kind kind;
+};
+%%
+operator_of, METAFN_OPERATOR_OF, METAFN_KIND_OPERATORS_INFO,
+symbol_of, METAFN_SYMBOL_OF, METAFN_KIND_STRING_VIEW_OPERATORS,
+u8symbol_of, METAFN_U8SYMBOL_OF, METAFN_KIND_U8STRING_VIEW_OPERATORS,
+has_identifier, METAFN_HAS_IDENTIFIER, METAFN_KIND_BOOL_INFO,
+identifier_of, METAFN_IDENTIFIER_OF, METAFN_KIND_STRING_VIEW_INFO,
+u8identifier_of, METAFN_U8IDENTIFIER_OF, METAFN_KIND_U8STRING_VIEW_INFO,
+display_string_of, METAFN_DISPLAY_STRING_OF, METAFN_KIND_STRING_VIEW_INFO,
+u8display_string_of, METAFN_U8DISPLAY_STRING_OF, METAFN_KIND_U8STRING_VIEW_INFO,
+source_location_of, METAFN_SOURCE_LOCATION_OF, METAFN_KIND_SOURCE_LOCATION_INFO,
+type_of, METAFN_TYPE_OF, METAFN_KIND_INFO_INFO,
+object_of, METAFN_OBJECT_OF, METAFN_KIND_INFO_INFO,
+constant_of, METAFN_CONSTANT_OF, METAFN_KIND_INFO_INFO,
+is_public, METAFN_IS_PUBLIC, METAFN_KIND_BOOL_INFO,
+is_protected, METAFN_IS_PROTECTED, METAFN_KIND_BOOL_INFO,
+is_private, METAFN_IS_PRIVATE, METAFN_KIND_BOOL_INFO,
+is_virtual, METAFN_IS_VIRTUAL, METAFN_KIND_BOOL_INFO,
+is_pure_virtual, METAFN_IS_PURE_VIRTUAL, METAFN_KIND_BOOL_INFO,
+is_override, METAFN_IS_OVERRIDE, METAFN_KIND_BOOL_INFO,
+is_final, METAFN_IS_FINAL, METAFN_KIND_BOOL_INFO,
+is_deleted, METAFN_IS_DELETED, METAFN_KIND_BOOL_INFO,
+is_defaulted, METAFN_IS_DEFAULTED, METAFN_KIND_BOOL_INFO,
+is_user_provided, METAFN_IS_USER_PROVIDED, METAFN_KIND_BOOL_INFO,
+is_user_declared, METAFN_IS_USER_DECLARED, METAFN_KIND_BOOL_INFO,
+is_explicit, METAFN_IS_EXPLICIT, METAFN_KIND_BOOL_INFO,
+is_noexcept, METAFN_IS_NOEXCEPT, METAFN_KIND_BOOL_INFO,
+is_bit_field, METAFN_IS_BIT_FIELD, METAFN_KIND_BOOL_INFO,
+is_enumerator, METAFN_IS_ENUMERATOR, METAFN_KIND_BOOL_INFO,
+is_annotation, METAFN_IS_ANNOTATION, METAFN_KIND_BOOL_INFO,
+is_const, METAFN_IS_CONST, METAFN_KIND_BOOL_INFO,
+is_volatile, METAFN_IS_VOLATILE, METAFN_KIND_BOOL_INFO,
+is_mutable_member, METAFN_IS_MUTABLE_MEMBER, METAFN_KIND_BOOL_INFO,
+is_lvalue_reference_qualified, METAFN_IS_LVALUE_REFERENCE_QUALIFIED, METAFN_KIND_BOOL_INFO,
+is_rvalue_reference_qualified, METAFN_IS_RVALUE_REFERENCE_QUALIFIED, METAFN_KIND_BOOL_INFO,
+has_static_storage_duration, METAFN_HAS_STATIC_STORAGE_DURATION, METAFN_KIND_BOOL_INFO,
+has_thread_storage_duration, METAFN_HAS_THREAD_STORAGE_DURATION, METAFN_KIND_BOOL_INFO,
+has_automatic_storage_duration, METAFN_HAS_AUTOMATIC_STORAGE_DURATION, METAFN_KIND_BOOL_INFO,
+has_internal_linkage, METAFN_HAS_INTERNAL_LINKAGE, METAFN_KIND_BOOL_INFO,
+has_module_linkage, METAFN_HAS_MODULE_LINKAGE, METAFN_KIND_BOOL_INFO,
+has_external_linkage, METAFN_HAS_EXTERNAL_LINKAGE, METAFN_KIND_BOOL_INFO,
+has_c_language_linkage, METAFN_HAS_C_LANGUAGE_LINKAGE, METAFN_KIND_BOOL_INFO,
+has_linkage, METAFN_HAS_LINKAGE, METAFN_KIND_BOOL_INFO,
+is_complete_type, METAFN_IS_COMPLETE_TYPE, METAFN_KIND_BOOL_INFO,
+is_enumerable_type, METAFN_IS_ENUMERABLE_TYPE, METAFN_KIND_BOOL_INFO,
+is_variable, METAFN_IS_VARIABLE, METAFN_KIND_BOOL_INFO,
+is_type, METAFN_IS_TYPE, METAFN_KIND_BOOL_INFO,
+is_namespace, METAFN_IS_NAMESPACE, METAFN_KIND_BOOL_INFO,
+is_type_alias, METAFN_IS_TYPE_ALIAS, METAFN_KIND_BOOL_INFO,
+is_namespace_alias, METAFN_IS_NAMESPACE_ALIAS, METAFN_KIND_BOOL_INFO,
+is_function, METAFN_IS_FUNCTION, METAFN_KIND_BOOL_INFO,
+is_conversion_function, METAFN_IS_CONVERSION_FUNCTION, METAFN_KIND_BOOL_INFO,
+is_operator_function, METAFN_IS_OPERATOR_FUNCTION, METAFN_KIND_BOOL_INFO,
+is_literal_operator, METAFN_IS_LITERAL_OPERATOR, METAFN_KIND_BOOL_INFO,
+is_special_member_function, METAFN_IS_SPECIAL_MEMBER_FUNCTION, METAFN_KIND_BOOL_INFO,
+is_constructor, METAFN_IS_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,
+is_default_constructor, METAFN_IS_DEFAULT_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,
+is_copy_constructor, METAFN_IS_COPY_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,
+is_move_constructor, METAFN_IS_MOVE_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,
+is_assignment, METAFN_IS_ASSIGNMENT, METAFN_KIND_BOOL_INFO,
+is_copy_assignment, METAFN_IS_COPY_ASSIGNMENT, METAFN_KIND_BOOL_INFO,
+is_move_assignment, METAFN_IS_MOVE_ASSIGNMENT, METAFN_KIND_BOOL_INFO,
+is_destructor, METAFN_IS_DESTRUCTOR, METAFN_KIND_BOOL_INFO,
+is_function_parameter, METAFN_IS_FUNCTION_PARAMETER, METAFN_KIND_BOOL_INFO,
+is_explicit_object_parameter, METAFN_IS_EXPLICIT_OBJECT_PARAMETER, METAFN_KIND_BOOL_INFO,
+has_default_argument, METAFN_HAS_DEFAULT_ARGUMENT, METAFN_KIND_BOOL_INFO,
+has_ellipsis_parameter, METAFN_HAS_ELLIPSIS_PARAMETER, METAFN_KIND_BOOL_INFO,
+is_template, METAFN_IS_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_function_template, METAFN_IS_FUNCTION_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_variable_template, METAFN_IS_VARIABLE_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_class_template, METAFN_IS_CLASS_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_alias_template, METAFN_IS_ALIAS_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_conversion_function_template, METAFN_IS_CONVERSION_FUNCTION_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_operator_function_template, METAFN_IS_OPERATOR_FUNCTION_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_literal_operator_template, METAFN_IS_LITERAL_OPERATOR_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_constructor_template, METAFN_IS_CONSTRUCTOR_TEMPLATE, METAFN_KIND_BOOL_INFO,
+is_concept, METAFN_IS_CONCEPT, METAFN_KIND_BOOL_INFO,
+is_value, METAFN_IS_VALUE, METAFN_KIND_BOOL_INFO,
+is_object, METAFN_IS_OBJECT, METAFN_KIND_BOOL_INFO,
+is_structured_binding, METAFN_IS_STRUCTURED_BINDING, METAFN_KIND_BOOL_INFO,
+is_class_member, METAFN_IS_CLASS_MEMBER, METAFN_KIND_BOOL_INFO,
+is_namespace_member, METAFN_IS_NAMESPACE_MEMBER, METAFN_KIND_BOOL_INFO,
+is_nonstatic_data_member, METAFN_IS_NONSTATIC_DATA_MEMBER, METAFN_KIND_BOOL_INFO,
+is_static_member, METAFN_IS_STATIC_MEMBER, METAFN_KIND_BOOL_INFO,
+is_base, METAFN_IS_BASE, METAFN_KIND_BOOL_INFO,
+has_default_member_initializer, METAFN_HAS_DEFAULT_MEMBER_INITIALIZER, METAFN_KIND_BOOL_INFO,
+has_parent, METAFN_HAS_PARENT, METAFN_KIND_BOOL_INFO,
+parent_of, METAFN_PARENT_OF, METAFN_KIND_INFO_INFO,
+dealias, METAFN_DEALIAS, METAFN_KIND_INFO_INFO,
+has_template_arguments, METAFN_HAS_TEMPLATE_ARGUMENTS, METAFN_KIND_BOOL_INFO,
+template_of, METAFN_TEMPLATE_OF, METAFN_KIND_INFO_INFO,
+template_arguments_of, METAFN_TEMPLATE_ARGUMENTS_OF, METAFN_KIND_VECTOR_INFO_INFO,
+parameters_of, METAFN_PARAMETERS_OF, METAFN_KIND_VECTOR_INFO_INFO,
+variable_of, METAFN_VARIABLE_OF, METAFN_KIND_INFO_INFO,
+return_type_of, METAFN_RETURN_TYPE_OF, METAFN_KIND_INFO_INFO,
+is_accessible, METAFN_IS_ACCESSIBLE, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,
+has_inaccessible_nonstatic_data_members, METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,
+has_inaccessible_bases, METAFN_HAS_INACCESSIBLE_BASES, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,
+has_inaccessible_subobjects, METAFN_HAS_INACCESSIBLE_SUBOBJECTS, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,
+members_of, METAFN_MEMBERS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,
+bases_of, METAFN_BASES_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,
+static_data_members_of, METAFN_STATIC_DATA_MEMBERS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,
+nonstatic_data_members_of, METAFN_NONSTATIC_DATA_MEMBERS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,
+subobjects_of, METAFN_SUBOBJECTS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,
+enumerators_of, METAFN_ENUMERATORS_OF, METAFN_KIND_VECTOR_INFO_INFO,
+offset_of, METAFN_OFFSET_OF, METAFN_KIND_MEMBER_OFFSET_INFO,
+size_of, METAFN_SIZE_OF, METAFN_KIND_SIZE_T_INFO,
+alignment_of, METAFN_ALIGNMENT_OF, METAFN_KIND_SIZE_T_INFO,
+bit_size_of, METAFN_BIT_SIZE_OF, METAFN_KIND_SIZE_T_INFO,
+extract, METAFN_EXTRACT, METAFN_KIND_TEMPLATE_PARM_INFO,
+can_substitute, METAFN_CAN_SUBSTITUTE, METAFN_KIND_INFO_INFO_REFLECTION_RANGE,
+substitute, METAFN_SUBSTITUTE, METAFN_KIND_INFO_INFO_REFLECTION_RANGE,
+reflect_constant, METAFN_REFLECT_CONSTANT, METAFN_KIND_INFO_TEMPLATE_PARM,
+reflect_object, METAFN_REFLECT_OBJECT, METAFN_KIND_INFO_TEMPLATE_PARM_REF,
+reflect_function, METAFN_REFLECT_FUNCTION, METAFN_KIND_INFO_TEMPLATE_PARM_REF,
+reflect_constant_string, METAFN_REFLECT_CONSTANT_STRING, METAFN_KIND_INFO_INPUT_RANGE,
+reflect_constant_array, METAFN_REFLECT_CONSTANT_ARRAY, METAFN_KIND_INFO_INPUT_RANGE,
+data_member_spec, METAFN_DATA_MEMBER_SPEC, METAFN_KIND_INFO_TINFO_DATA_MEMBER_OPTIONS,
+is_data_member_spec, METAFN_IS_DATA_MEMBER_SPEC, METAFN_KIND_BOOL_INFO,
+define_aggregate, METAFN_DEFINE_AGGREGATE, METAFN_KIND_INFO_INFO_REFLECTION_RANGE,
+is_void_type, METAFN_IS_VOID_TYPE, METAFN_KIND_BOOL_TINFO,
+is_null_pointer_type, METAFN_IS_NULL_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,
+is_integral_type, METAFN_IS_INTEGRAL_TYPE, METAFN_KIND_BOOL_TINFO,
+is_floating_point_type, METAFN_IS_FLOATING_POINT_TYPE, METAFN_KIND_BOOL_TINFO,
+is_array_type, METAFN_IS_ARRAY_TYPE, METAFN_KIND_BOOL_TINFO,
+is_pointer_type, METAFN_IS_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,
+is_lvalue_reference_type, METAFN_IS_LVALUE_REFERENCE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_rvalue_reference_type, METAFN_IS_RVALUE_REFERENCE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_member_object_pointer_type, METAFN_IS_MEMBER_OBJECT_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,
+is_member_function_pointer_type, METAFN_IS_MEMBER_FUNCTION_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,
+is_enum_type, METAFN_IS_ENUM_TYPE, METAFN_KIND_BOOL_TINFO,
+is_union_type, METAFN_IS_UNION_TYPE, METAFN_KIND_BOOL_TINFO,
+is_class_type, METAFN_IS_CLASS_TYPE, METAFN_KIND_BOOL_TINFO,
+is_function_type, METAFN_IS_FUNCTION_TYPE, METAFN_KIND_BOOL_TINFO,
+is_reflection_type, METAFN_IS_REFLECTION_TYPE, METAFN_KIND_BOOL_TINFO,
+is_reference_type, METAFN_IS_REFERENCE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_arithmetic_type, METAFN_IS_ARITHMETIC_TYPE, METAFN_KIND_BOOL_TINFO,
+is_fundamental_type, METAFN_IS_FUNDAMENTAL_TYPE, METAFN_KIND_BOOL_TINFO,
+is_object_type, METAFN_IS_OBJECT_TYPE, METAFN_KIND_BOOL_TINFO,
+is_scalar_type, METAFN_IS_SCALAR_TYPE, METAFN_KIND_BOOL_TINFO,
+is_compound_type, METAFN_IS_COMPOUND_TYPE, METAFN_KIND_BOOL_TINFO,
+is_member_pointer_type, METAFN_IS_MEMBER_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,
+is_const_type, METAFN_IS_CONST_TYPE, METAFN_KIND_BOOL_TINFO,
+is_volatile_type, METAFN_IS_VOLATILE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_copyable_type, METAFN_IS_TRIVIALLY_COPYABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_standard_layout_type, METAFN_IS_STANDARD_LAYOUT_TYPE, METAFN_KIND_BOOL_TINFO,
+is_empty_type, METAFN_IS_EMPTY_TYPE, METAFN_KIND_BOOL_TINFO,
+is_polymorphic_type, METAFN_IS_POLYMORPHIC_TYPE, METAFN_KIND_BOOL_TINFO,
+is_abstract_type, METAFN_IS_ABSTRACT_TYPE, METAFN_KIND_BOOL_TINFO,
+is_final_type, METAFN_IS_FINAL_TYPE, METAFN_KIND_BOOL_TINFO,
+is_aggregate_type, METAFN_IS_AGGREGATE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_consteval_only_type, METAFN_IS_CONSTEVAL_ONLY_TYPE, METAFN_KIND_BOOL_TINFO,
+is_signed_type, METAFN_IS_SIGNED_TYPE, METAFN_KIND_BOOL_TINFO,
+is_unsigned_type, METAFN_IS_UNSIGNED_TYPE, METAFN_KIND_BOOL_TINFO,
+is_bounded_array_type, METAFN_IS_BOUNDED_ARRAY_TYPE, METAFN_KIND_BOOL_TINFO,
+is_unbounded_array_type, METAFN_IS_UNBOUNDED_ARRAY_TYPE, METAFN_KIND_BOOL_TINFO,
+is_scoped_enum_type, METAFN_IS_SCOPED_ENUM_TYPE, METAFN_KIND_BOOL_TINFO,
+is_constructible_type, METAFN_IS_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,
+is_default_constructible_type, METAFN_IS_DEFAULT_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_copy_constructible_type, METAFN_IS_COPY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_move_constructible_type, METAFN_IS_MOVE_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_assignable_type, METAFN_IS_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_copy_assignable_type, METAFN_IS_COPY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_move_assignable_type, METAFN_IS_MOVE_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_swappable_with_type, METAFN_IS_SWAPPABLE_WITH_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_swappable_type, METAFN_IS_SWAPPABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_destructible_type, METAFN_IS_DESTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_constructible_type, METAFN_IS_TRIVIALLY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,
+is_trivially_default_constructible_type, METAFN_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_copy_constructible_type, METAFN_IS_TRIVIALLY_COPY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_move_constructible_type, METAFN_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_assignable_type, METAFN_IS_TRIVIALLY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_trivially_copy_assignable_type, METAFN_IS_TRIVIALLY_COPY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_move_assignable_type, METAFN_IS_TRIVIALLY_MOVE_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_trivially_destructible_type, METAFN_IS_TRIVIALLY_DESTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_constructible_type, METAFN_IS_NOTHROW_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,
+is_nothrow_default_constructible_type, METAFN_IS_NOTHROW_DEFAULT_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_copy_constructible_type, METAFN_IS_NOTHROW_COPY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_move_constructible_type, METAFN_IS_NOTHROW_MOVE_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_assignable_type, METAFN_IS_NOTHROW_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_nothrow_copy_assignable_type, METAFN_IS_NOTHROW_COPY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_move_assignable_type, METAFN_IS_NOTHROW_MOVE_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_swappable_with_type, METAFN_IS_NOTHROW_SWAPPABLE_WITH_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_nothrow_swappable_type, METAFN_IS_NOTHROW_SWAPPABLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_nothrow_destructible_type, METAFN_IS_NOTHROW_DESTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,
+is_implicit_lifetime_type, METAFN_IS_IMPLICIT_LIFETIME_TYPE, METAFN_KIND_BOOL_TINFO,
+has_virtual_destructor, METAFN_HAS_VIRTUAL_DESTRUCTOR, METAFN_KIND_BOOL_TINFO,
+has_unique_object_representations, METAFN_HAS_UNIQUE_OBJECT_REPRESENTATIONS, METAFN_KIND_BOOL_TINFO,
+reference_constructs_from_temporary, METAFN_REFERENCE_CONSTRUCTS_FROM_TEMPORARY, METAFN_KIND_BOOL_TINFO_TINFO,
+reference_converts_from_temporary, METAFN_REFERENCE_CONVERTS_FROM_TEMPORARY, METAFN_KIND_BOOL_TINFO_TINFO,
+rank, METAFN_RANK, METAFN_KIND_SIZE_T_TINFO,
+extent, METAFN_EXTENT, METAFN_KIND_SIZE_T_TINFO_UNSIGNED,
+is_same_type, METAFN_IS_SAME_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_base_of_type, METAFN_IS_BASE_OF_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_virtual_base_of_type, METAFN_IS_VIRTUAL_BASE_OF_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_convertible_type, METAFN_IS_CONVERTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_nothrow_convertible_type, METAFN_IS_NOTHROW_CONVERTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_layout_compatible_type, METAFN_IS_LAYOUT_COMPATIBLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_pointer_interconvertible_base_of_type, METAFN_IS_POINTER_INTERCONVERTIBLE_BASE_OF_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,
+is_invocable_type, METAFN_IS_INVOCABLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,
+is_invocable_r_type, METAFN_IS_INVOCABLE_R_TYPE, METAFN_KIND_BOOL_TINFO_TINFO_REFLECTION_RANGET,
+is_nothrow_invocable_type, METAFN_IS_NOTHROW_INVOCABLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,
+is_nothrow_invocable_r_type, METAFN_IS_NOTHROW_INVOCABLE_R_TYPE, METAFN_KIND_BOOL_TINFO_TINFO_REFLECTION_RANGET,
+remove_const, METAFN_REMOVE_CONST, METAFN_KIND_INFO_TINFO,
+remove_volatile, METAFN_REMOVE_VOLATILE, METAFN_KIND_INFO_TINFO,
+remove_cv, METAFN_REMOVE_CV, METAFN_KIND_INFO_TINFO,
+add_const, METAFN_ADD_CONST, METAFN_KIND_INFO_TINFO,
+add_volatile, METAFN_ADD_VOLATILE, METAFN_KIND_INFO_TINFO,
+add_cv, METAFN_ADD_CV, METAFN_KIND_INFO_TINFO,
+remove_reference, METAFN_REMOVE_REFERENCE, METAFN_KIND_INFO_TINFO,
+add_lvalue_reference, METAFN_ADD_LVALUE_REFERENCE, METAFN_KIND_INFO_TINFO,
+add_rvalue_reference, METAFN_ADD_RVALUE_REFERENCE, METAFN_KIND_INFO_TINFO,
+make_signed, METAFN_MAKE_SIGNED, METAFN_KIND_INFO_TINFO,
+make_unsigned, METAFN_MAKE_UNSIGNED, METAFN_KIND_INFO_TINFO,
+remove_extent, METAFN_REMOVE_EXTENT, METAFN_KIND_INFO_TINFO,
+remove_all_extents, METAFN_REMOVE_ALL_EXTENTS, METAFN_KIND_INFO_TINFO,
+remove_pointer, METAFN_REMOVE_POINTER, METAFN_KIND_INFO_TINFO,
+add_pointer, METAFN_ADD_POINTER, METAFN_KIND_INFO_TINFO,
+remove_cvref, METAFN_REMOVE_CVREF, METAFN_KIND_INFO_TINFO,
+decay, METAFN_DECAY, METAFN_KIND_INFO_TINFO,
+common_type, METAFN_COMMON_TYPE, METAFN_KIND_INFO_REFLECTION_RANGET,
+common_reference, METAFN_COMMON_REFERENCE, METAFN_KIND_INFO_REFLECTION_RANGET,
+underlying_type, METAFN_UNDERLYING_TYPE, METAFN_KIND_INFO_TINFO,
+invoke_result, METAFN_INVOKE_RESULT, METAFN_KIND_INFO_TINFO_REFLECTION_RANGET,
+unwrap_reference, METAFN_UNWRAP_REFERENCE, METAFN_KIND_INFO_TINFO,
+unwrap_ref_decay, METAFN_UNWRAP_REF_DECAY, METAFN_KIND_INFO_TINFO,
+tuple_size, METAFN_TUPLE_SIZE, METAFN_KIND_SIZE_T_TINFO,
+tuple_element, METAFN_TUPLE_ELEMENT, METAFN_KIND_INFO_SIZE_T_TINFO,
+variant_size, METAFN_VARIANT_SIZE, METAFN_KIND_SIZE_T_TINFO,
+variant_alternative, METAFN_VARIANT_ALTERNATIVE, METAFN_KIND_INFO_SIZE_T_TINFO,
+type_order, METAFN_TYPE_ORDER, METAFN_KIND_STRONG_ORDERING_TINFO_TINFO,
+annotations_of, METAFN_ANNOTATIONS_OF, METAFN_KIND_VECTOR_INFO_INFO,
+annotations_of_with_type, METAFN_ANNOTATIONS_OF_WITH_TYPE, METAFN_KIND_VECTOR_INFO_INFO_INFO,
+current, METAFN_ACCESS_CONTEXT_CURRENT, METAFN_KIND_ACCESS_CONTEXT_VOID,
+_S_exception_cvt_to_utf8, METAFN_EXCEPTION__S_EXCEPTION_CVT_TO_UTF8, METAFN_KIND_U8STRING_VIEW_INPUT_RANGE,
+_S_exception_cvt_from_utf8, METAFN_EXCEPTION__S_EXCEPTION_CVT_FROM_UTF8, METAFN_KIND_STRING_VIEW_INPUT_RANGE,
diff --git a/gcc/cp/metafns.h b/gcc/cp/metafns.h
new file mode 100644 (file)
index 0000000..779c8dc
--- /dev/null
@@ -0,0 +1,1181 @@
+/* C++ code produced by gperf version 3.2.1 */
+/* Command-line: gperf -o -C -E -k '1,4,5,11,14,$' -D -N find -L C++ --output-file metafns.h metafns.gperf  */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "metafns.gperf"
+
+/* Copyright (C) 2025-2026 Free Software Foundation, Inc.
+   Written by Jakub Jelinek <jakub@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+enum metafn_code {
+  METAFN_OPERATOR_OF,
+  METAFN_SYMBOL_OF,
+  METAFN_U8SYMBOL_OF,
+  METAFN_HAS_IDENTIFIER,
+  METAFN_IDENTIFIER_OF,
+  METAFN_U8IDENTIFIER_OF,
+  METAFN_DISPLAY_STRING_OF,
+  METAFN_U8DISPLAY_STRING_OF,
+  METAFN_SOURCE_LOCATION_OF,
+  METAFN_TYPE_OF,
+  METAFN_OBJECT_OF,
+  METAFN_CONSTANT_OF,
+  METAFN_IS_PUBLIC,
+  METAFN_IS_PROTECTED,
+  METAFN_IS_PRIVATE,
+  METAFN_IS_VIRTUAL,
+  METAFN_IS_PURE_VIRTUAL,
+  METAFN_IS_OVERRIDE,
+  METAFN_IS_FINAL,
+  METAFN_IS_DELETED,
+  METAFN_IS_DEFAULTED,
+  METAFN_IS_USER_PROVIDED,
+  METAFN_IS_USER_DECLARED,
+  METAFN_IS_EXPLICIT,
+  METAFN_IS_NOEXCEPT,
+  METAFN_IS_BIT_FIELD,
+  METAFN_IS_ENUMERATOR,
+  METAFN_IS_ANNOTATION,
+  METAFN_IS_CONST,
+  METAFN_IS_VOLATILE,
+  METAFN_IS_MUTABLE_MEMBER,
+  METAFN_IS_LVALUE_REFERENCE_QUALIFIED,
+  METAFN_IS_RVALUE_REFERENCE_QUALIFIED,
+  METAFN_HAS_STATIC_STORAGE_DURATION,
+  METAFN_HAS_THREAD_STORAGE_DURATION,
+  METAFN_HAS_AUTOMATIC_STORAGE_DURATION,
+  METAFN_HAS_INTERNAL_LINKAGE,
+  METAFN_HAS_MODULE_LINKAGE,
+  METAFN_HAS_EXTERNAL_LINKAGE,
+  METAFN_HAS_C_LANGUAGE_LINKAGE,
+  METAFN_HAS_LINKAGE,
+  METAFN_IS_COMPLETE_TYPE,
+  METAFN_IS_ENUMERABLE_TYPE,
+  METAFN_IS_VARIABLE,
+  METAFN_IS_TYPE,
+  METAFN_IS_NAMESPACE,
+  METAFN_IS_TYPE_ALIAS,
+  METAFN_IS_NAMESPACE_ALIAS,
+  METAFN_IS_FUNCTION,
+  METAFN_IS_CONVERSION_FUNCTION,
+  METAFN_IS_OPERATOR_FUNCTION,
+  METAFN_IS_LITERAL_OPERATOR,
+  METAFN_IS_SPECIAL_MEMBER_FUNCTION,
+  METAFN_IS_CONSTRUCTOR,
+  METAFN_IS_DEFAULT_CONSTRUCTOR,
+  METAFN_IS_COPY_CONSTRUCTOR,
+  METAFN_IS_MOVE_CONSTRUCTOR,
+  METAFN_IS_ASSIGNMENT,
+  METAFN_IS_COPY_ASSIGNMENT,
+  METAFN_IS_MOVE_ASSIGNMENT,
+  METAFN_IS_DESTRUCTOR,
+  METAFN_IS_FUNCTION_PARAMETER,
+  METAFN_IS_EXPLICIT_OBJECT_PARAMETER,
+  METAFN_HAS_DEFAULT_ARGUMENT,
+  METAFN_HAS_ELLIPSIS_PARAMETER,
+  METAFN_IS_TEMPLATE,
+  METAFN_IS_FUNCTION_TEMPLATE,
+  METAFN_IS_VARIABLE_TEMPLATE,
+  METAFN_IS_CLASS_TEMPLATE,
+  METAFN_IS_ALIAS_TEMPLATE,
+  METAFN_IS_CONVERSION_FUNCTION_TEMPLATE,
+  METAFN_IS_OPERATOR_FUNCTION_TEMPLATE,
+  METAFN_IS_LITERAL_OPERATOR_TEMPLATE,
+  METAFN_IS_CONSTRUCTOR_TEMPLATE,
+  METAFN_IS_CONCEPT,
+  METAFN_IS_VALUE,
+  METAFN_IS_OBJECT,
+  METAFN_IS_STRUCTURED_BINDING,
+  METAFN_IS_CLASS_MEMBER,
+  METAFN_IS_NAMESPACE_MEMBER,
+  METAFN_IS_NONSTATIC_DATA_MEMBER,
+  METAFN_IS_STATIC_MEMBER,
+  METAFN_IS_BASE,
+  METAFN_HAS_DEFAULT_MEMBER_INITIALIZER,
+  METAFN_HAS_PARENT,
+  METAFN_PARENT_OF,
+  METAFN_DEALIAS,
+  METAFN_HAS_TEMPLATE_ARGUMENTS,
+  METAFN_TEMPLATE_OF,
+  METAFN_TEMPLATE_ARGUMENTS_OF,
+  METAFN_PARAMETERS_OF,
+  METAFN_VARIABLE_OF,
+  METAFN_RETURN_TYPE_OF,
+  METAFN_IS_ACCESSIBLE,
+  METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS,
+  METAFN_HAS_INACCESSIBLE_BASES,
+  METAFN_HAS_INACCESSIBLE_SUBOBJECTS,
+  METAFN_MEMBERS_OF,
+  METAFN_BASES_OF,
+  METAFN_STATIC_DATA_MEMBERS_OF,
+  METAFN_NONSTATIC_DATA_MEMBERS_OF,
+  METAFN_SUBOBJECTS_OF,
+  METAFN_ENUMERATORS_OF,
+  METAFN_OFFSET_OF,
+  METAFN_SIZE_OF,
+  METAFN_ALIGNMENT_OF,
+  METAFN_BIT_SIZE_OF,
+  METAFN_EXTRACT,
+  METAFN_CAN_SUBSTITUTE,
+  METAFN_SUBSTITUTE,
+  METAFN_REFLECT_CONSTANT,
+  METAFN_REFLECT_OBJECT,
+  METAFN_REFLECT_FUNCTION,
+  METAFN_REFLECT_CONSTANT_STRING,
+  METAFN_REFLECT_CONSTANT_ARRAY,
+  METAFN_DATA_MEMBER_SPEC,
+  METAFN_IS_DATA_MEMBER_SPEC,
+  METAFN_DEFINE_AGGREGATE,
+  METAFN_IS_VOID_TYPE,
+  METAFN_IS_NULL_POINTER_TYPE,
+  METAFN_IS_INTEGRAL_TYPE,
+  METAFN_IS_FLOATING_POINT_TYPE,
+  METAFN_IS_ARRAY_TYPE,
+  METAFN_IS_POINTER_TYPE,
+  METAFN_IS_LVALUE_REFERENCE_TYPE,
+  METAFN_IS_RVALUE_REFERENCE_TYPE,
+  METAFN_IS_MEMBER_OBJECT_POINTER_TYPE,
+  METAFN_IS_MEMBER_FUNCTION_POINTER_TYPE,
+  METAFN_IS_ENUM_TYPE,
+  METAFN_IS_UNION_TYPE,
+  METAFN_IS_CLASS_TYPE,
+  METAFN_IS_FUNCTION_TYPE,
+  METAFN_IS_REFLECTION_TYPE,
+  METAFN_IS_REFERENCE_TYPE,
+  METAFN_IS_ARITHMETIC_TYPE,
+  METAFN_IS_FUNDAMENTAL_TYPE,
+  METAFN_IS_OBJECT_TYPE,
+  METAFN_IS_SCALAR_TYPE,
+  METAFN_IS_COMPOUND_TYPE,
+  METAFN_IS_MEMBER_POINTER_TYPE,
+  METAFN_IS_CONST_TYPE,
+  METAFN_IS_VOLATILE_TYPE,
+  METAFN_IS_TRIVIALLY_COPYABLE_TYPE,
+  METAFN_IS_STANDARD_LAYOUT_TYPE,
+  METAFN_IS_EMPTY_TYPE,
+  METAFN_IS_POLYMORPHIC_TYPE,
+  METAFN_IS_ABSTRACT_TYPE,
+  METAFN_IS_FINAL_TYPE,
+  METAFN_IS_AGGREGATE_TYPE,
+  METAFN_IS_CONSTEVAL_ONLY_TYPE,
+  METAFN_IS_SIGNED_TYPE,
+  METAFN_IS_UNSIGNED_TYPE,
+  METAFN_IS_BOUNDED_ARRAY_TYPE,
+  METAFN_IS_UNBOUNDED_ARRAY_TYPE,
+  METAFN_IS_SCOPED_ENUM_TYPE,
+  METAFN_IS_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_DEFAULT_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_COPY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_MOVE_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_ASSIGNABLE_TYPE,
+  METAFN_IS_COPY_ASSIGNABLE_TYPE,
+  METAFN_IS_MOVE_ASSIGNABLE_TYPE,
+  METAFN_IS_SWAPPABLE_WITH_TYPE,
+  METAFN_IS_SWAPPABLE_TYPE,
+  METAFN_IS_DESTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_COPY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_TRIVIALLY_ASSIGNABLE_TYPE,
+  METAFN_IS_TRIVIALLY_COPY_ASSIGNABLE_TYPE,
+  METAFN_IS_TRIVIALLY_MOVE_ASSIGNABLE_TYPE,
+  METAFN_IS_TRIVIALLY_DESTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_DEFAULT_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_COPY_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_MOVE_CONSTRUCTIBLE_TYPE,
+  METAFN_IS_NOTHROW_ASSIGNABLE_TYPE,
+  METAFN_IS_NOTHROW_COPY_ASSIGNABLE_TYPE,
+  METAFN_IS_NOTHROW_MOVE_ASSIGNABLE_TYPE,
+  METAFN_IS_NOTHROW_SWAPPABLE_WITH_TYPE,
+  METAFN_IS_NOTHROW_SWAPPABLE_TYPE,
+  METAFN_IS_NOTHROW_DESTRUCTIBLE_TYPE,
+  METAFN_IS_IMPLICIT_LIFETIME_TYPE,
+  METAFN_HAS_VIRTUAL_DESTRUCTOR,
+  METAFN_HAS_UNIQUE_OBJECT_REPRESENTATIONS,
+  METAFN_REFERENCE_CONSTRUCTS_FROM_TEMPORARY,
+  METAFN_REFERENCE_CONVERTS_FROM_TEMPORARY,
+  METAFN_RANK,
+  METAFN_EXTENT,
+  METAFN_IS_SAME_TYPE,
+  METAFN_IS_BASE_OF_TYPE,
+  METAFN_IS_VIRTUAL_BASE_OF_TYPE,
+  METAFN_IS_CONVERTIBLE_TYPE,
+  METAFN_IS_NOTHROW_CONVERTIBLE_TYPE,
+  METAFN_IS_LAYOUT_COMPATIBLE_TYPE,
+  METAFN_IS_POINTER_INTERCONVERTIBLE_BASE_OF_TYPE,
+  METAFN_IS_INVOCABLE_TYPE,
+  METAFN_IS_INVOCABLE_R_TYPE,
+  METAFN_IS_NOTHROW_INVOCABLE_TYPE,
+  METAFN_IS_NOTHROW_INVOCABLE_R_TYPE,
+  METAFN_REMOVE_CONST,
+  METAFN_REMOVE_VOLATILE,
+  METAFN_REMOVE_CV,
+  METAFN_ADD_CONST,
+  METAFN_ADD_VOLATILE,
+  METAFN_ADD_CV,
+  METAFN_REMOVE_REFERENCE,
+  METAFN_ADD_LVALUE_REFERENCE,
+  METAFN_ADD_RVALUE_REFERENCE,
+  METAFN_MAKE_SIGNED,
+  METAFN_MAKE_UNSIGNED,
+  METAFN_REMOVE_EXTENT,
+  METAFN_REMOVE_ALL_EXTENTS,
+  METAFN_REMOVE_POINTER,
+  METAFN_ADD_POINTER,
+  METAFN_REMOVE_CVREF,
+  METAFN_DECAY,
+  METAFN_COMMON_TYPE,
+  METAFN_COMMON_REFERENCE,
+  METAFN_UNDERLYING_TYPE,
+  METAFN_INVOKE_RESULT,
+  METAFN_UNWRAP_REFERENCE,
+  METAFN_UNWRAP_REF_DECAY,
+  METAFN_TUPLE_SIZE,
+  METAFN_TUPLE_ELEMENT,
+  METAFN_VARIANT_SIZE,
+  METAFN_VARIANT_ALTERNATIVE,
+  METAFN_TYPE_ORDER,
+  METAFN_ANNOTATIONS_OF,
+  METAFN_ANNOTATIONS_OF_WITH_TYPE,
+  /* Special metafunctions.  */
+  METAFN_ACCESS_CONTEXT_CURRENT,
+  METAFN_EXCEPTION__S_EXCEPTION_CVT_TO_UTF8,
+  METAFN_EXCEPTION__S_EXCEPTION_CVT_FROM_UTF8
+};
+
+enum {
+  METAFN_KIND_SHIFT = 5,
+  METAFN_KIND_MASK = (1 << METAFN_KIND_SHIFT) - 1
+};
+
+/* Possible return types of metafunctions.  */
+enum metafn_kind_ret {
+  METAFN_KIND_RET_BOOL,
+  METAFN_KIND_RET_INFO,
+  METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_RET_MEMBER_OFFSET,
+  METAFN_KIND_RET_OPERATORS,
+  METAFN_KIND_RET_SOURCE_LOCATION,
+  METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_RET_U8STRING_VIEW,
+  METAFN_KIND_RET_STRONG_ORDERING,
+  METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_RET_ACCESS_CONTEXT,
+  METAFN_KIND_RET_TEMPLATE_PARM,
+};
+static_assert (METAFN_KIND_RET_TEMPLATE_PARM <= (int) METAFN_KIND_MASK);
+
+/* Possible argument types of metafunctions.  */
+enum metafn_kind_arg {
+  METAFN_KIND_ARG_VOID = 0,
+  METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARG_TINFO, /* info argument which throws if not a type.  */
+  METAFN_KIND_ARG_REFLECTION_RANGE,
+  /* reflection_range with type infos only.  */
+  METAFN_KIND_ARG_REFLECTION_RANGET,
+  METAFN_KIND_ARG_INPUT_RANGE,
+  METAFN_KIND_ARG_SIZE_T,
+  METAFN_KIND_ARG_UNSIGNED,
+  METAFN_KIND_ARG_OPERATORS,
+  METAFN_KIND_ARG_ACCESS_CONTEXT,
+  METAFN_KIND_ARG_DATA_MEMBER_OPTIONS,
+  METAFN_KIND_ARG_TEMPLATE_PARM, /* Some other template parameter.  */
+  METAFN_KIND_ARG_TEMPLATE_PARM_REF /* Reference to template parameter.  */
+};
+static_assert (METAFN_KIND_ARG_TEMPLATE_PARM_REF <= (int) METAFN_KIND_MASK);
+
+/* Possible sets of 0-3 arguments of metafunctions.  */
+enum metafn_kind_args {
+  METAFN_KIND_ARGS_VOID = METAFN_KIND_ARG_VOID,
+  METAFN_KIND_ARGS_INFO = METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO = METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_REFLECTION_RANGET = METAFN_KIND_ARG_REFLECTION_RANGET,
+  METAFN_KIND_ARGS_INPUT_RANGE = METAFN_KIND_ARG_INPUT_RANGE,
+  METAFN_KIND_ARGS_OPERATORS = METAFN_KIND_ARG_OPERATORS,
+  METAFN_KIND_ARGS_TEMPLATE_PARM = METAFN_KIND_ARG_TEMPLATE_PARM,
+  METAFN_KIND_ARGS_TEMPLATE_PARM_REF = METAFN_KIND_ARG_TEMPLATE_PARM_REF,
+  METAFN_KIND_ARGS_INFO_INFO
+    = (METAFN_KIND_ARG_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO_TINFO
+    = (METAFN_KIND_ARG_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_TINFO_UNSIGNED
+    = (METAFN_KIND_ARG_UNSIGNED << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_INFO_ACCESS_CONTEXT
+    = (METAFN_KIND_ARG_ACCESS_CONTEXT << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO_DATA_MEMBER_OPTIONS
+    = (METAFN_KIND_ARG_DATA_MEMBER_OPTIONS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_INFO_REFLECTION_RANGE
+    = (METAFN_KIND_ARG_REFLECTION_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_INFO,
+  METAFN_KIND_ARGS_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARG_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_ARG_TINFO,
+  METAFN_KIND_ARGS_SIZE_T_TINFO
+    = (METAFN_KIND_ARG_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_ARG_SIZE_T,
+  METAFN_KIND_ARGS_TINFO_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARG_REFLECTION_RANGET << (2 * METAFN_KIND_SHIFT))
+      | METAFN_KIND_ARGS_TINFO_TINFO,
+};
+
+/* This encodes metafn_kind_ret in the low METAFN_KIND_SHIFT bits, then
+   first argument metafn_kind_arg in METAFN_KIND_SHIFT bits above that,
+   second argument metafn_kind_arg in METAFN_KIND_SHIFT bits above that
+   and third argument metafn_kind_arg in METAFN_KIND_SHIFT bits above that.
+   Missing argument is METAFN_KIND_ARG_VOID aka 0.  */
+enum metafn_kind {
+  METAFN_KIND_BOOL_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO
+    = (METAFN_KIND_ARGS_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT
+    = (METAFN_KIND_ARGS_INFO_ACCESS_CONTEXT << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO_TINFO
+    = (METAFN_KIND_ARGS_TINFO_TINFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_TINFO_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_BOOL_TINFO_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_TINFO_TINFO_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_BOOL,
+  METAFN_KIND_INFO_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TINFO
+    = (METAFN_KIND_ARGS_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TINFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_TINFO_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TINFO_DATA_MEMBER_OPTIONS
+    = (METAFN_KIND_ARGS_TINFO_DATA_MEMBER_OPTIONS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_REFLECTION_RANGET
+    = (METAFN_KIND_ARGS_REFLECTION_RANGET << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_INFO_REFLECTION_RANGE
+    = (METAFN_KIND_ARGS_INFO_REFLECTION_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_INPUT_RANGE
+    = (METAFN_KIND_ARGS_INPUT_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TEMPLATE_PARM
+    = (METAFN_KIND_ARGS_TEMPLATE_PARM << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_TEMPLATE_PARM_REF
+    = (METAFN_KIND_ARGS_TEMPLATE_PARM_REF << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_INFO_SIZE_T_TINFO
+    = (METAFN_KIND_ARGS_SIZE_T_TINFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_INFO,
+  METAFN_KIND_MEMBER_OFFSET_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_MEMBER_OFFSET,
+  METAFN_KIND_OPERATORS_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_OPERATORS,
+  METAFN_KIND_SIZE_T_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_SIZE_T_TINFO
+    = (METAFN_KIND_ARGS_TINFO << METAFN_KIND_SHIFT) | METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_SIZE_T_TINFO_UNSIGNED
+    = (METAFN_KIND_ARGS_TINFO_UNSIGNED << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_SIZE_T,
+  METAFN_KIND_SOURCE_LOCATION_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_SOURCE_LOCATION,
+  METAFN_KIND_STRING_VIEW_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_STRING_VIEW_OPERATORS
+    = (METAFN_KIND_ARGS_OPERATORS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_U8STRING_VIEW_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_U8STRING_VIEW,
+  METAFN_KIND_U8STRING_VIEW_OPERATORS
+    = (METAFN_KIND_ARGS_OPERATORS << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_U8STRING_VIEW,
+  METAFN_KIND_STRONG_ORDERING_TINFO_TINFO
+    = (METAFN_KIND_ARGS_TINFO_TINFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRONG_ORDERING,
+  METAFN_KIND_VECTOR_INFO_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_VECTOR_INFO_INFO_INFO
+    = (METAFN_KIND_ARGS_INFO_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT
+    = (METAFN_KIND_ARGS_INFO_ACCESS_CONTEXT << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_VECTOR_INFO,
+  METAFN_KIND_TEMPLATE_PARM_INFO
+    = (METAFN_KIND_ARGS_INFO << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_TEMPLATE_PARM,
+  METAFN_KIND_ACCESS_CONTEXT_VOID
+    = (METAFN_KIND_ARGS_VOID << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_ACCESS_CONTEXT,
+  METAFN_KIND_STRING_VIEW_INPUT_RANGE
+    = (METAFN_KIND_ARGS_INPUT_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_STRING_VIEW,
+  METAFN_KIND_U8STRING_VIEW_INPUT_RANGE
+    = (METAFN_KIND_ARGS_INPUT_RANGE << METAFN_KIND_SHIFT)
+      | METAFN_KIND_RET_U8STRING_VIEW
+};
+#line 443 "metafns.gperf"
+struct metafn_info
+{
+  /* A name within "std::meta::" (or "std::meta::access_context::").  */
+  const char *name;
+
+  /* METAFN_ code.  */
+  metafn_code code;
+
+  /* METAFN_KIND_ kind of arguments and return type.  */
+  metafn_kind kind;
+};
+/* maximum key range = 879, duplicates = 0 */
+
+class metafn_lookup
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static const struct metafn_info *find (const char *str, size_t len);
+};
+
+inline unsigned int
+metafn_lookup::hash (const char *str, size_t len)
+{
+  static const unsigned short asso_values[] =
+    {
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918,   0, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918,   5, 100, 145,  10,  45,
+      165,   5,  55,  50,  72,  20, 248,   0,  55, 105,
+        0, 205,   0,  45,  35,  55,  25, 195,   5, 199,
+       20, 311,  20, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918, 918, 918, 918,
+      918, 918, 918, 918, 918, 918, 918
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[13])];
+#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9)))
+      [[fallthrough]];
+#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10)
+      __attribute__ ((__fallthrough__));
+#endif
+      /*FALLTHROUGH*/
+      case 13:
+      case 12:
+      case 11:
+        hval += asso_values[static_cast<unsigned char>(str[10])];
+#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9)))
+      [[fallthrough]];
+#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10)
+      __attribute__ ((__fallthrough__));
+#endif
+      /*FALLTHROUGH*/
+      case 10:
+      case 9:
+      case 8:
+      case 7:
+      case 6:
+      case 5:
+        hval += asso_values[static_cast<unsigned char>(str[4]+1)];
+#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9)))
+      [[fallthrough]];
+#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10)
+      __attribute__ ((__fallthrough__));
+#endif
+      /*FALLTHROUGH*/
+      case 4:
+        hval += asso_values[static_cast<unsigned char>(str[3])];
+#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9)))
+      [[fallthrough]];
+#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10)
+      __attribute__ ((__fallthrough__));
+#endif
+      /*FALLTHROUGH*/
+      case 3:
+      case 2:
+      case 1:
+        hval += asso_values[static_cast<unsigned char>(str[0])];
+        break;
+    }
+  return hval + asso_values[static_cast<unsigned char>(str[len - 1])];
+}
+
+const struct metafn_info *
+metafn_lookup::find (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 234,
+      MIN_WORD_LENGTH = 4,
+      MAX_WORD_LENGTH = 40,
+      MIN_HASH_VALUE = 39,
+      MAX_HASH_VALUE = 917
+    };
+
+#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+  static const struct metafn_info wordlist[] =
+    {
+#line 643 "metafns.gperf"
+      {"rank", METAFN_RANK, METAFN_KIND_SIZE_T_TINFO,},
+#line 573 "metafns.gperf"
+      {"is_void_type", METAFN_IS_VOID_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 578 "metafns.gperf"
+      {"is_pointer_type", METAFN_IS_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 484 "metafns.gperf"
+      {"is_volatile", METAFN_IS_VOLATILE, METAFN_KIND_BOOL_INFO,},
+#line 530 "metafns.gperf"
+      {"is_value", METAFN_IS_VALUE, METAFN_KIND_BOOL_INFO,},
+#line 537 "metafns.gperf"
+      {"is_base", METAFN_IS_BASE, METAFN_KIND_BOOL_INFO,},
+#line 498 "metafns.gperf"
+      {"is_variable", METAFN_IS_VARIABLE, METAFN_KIND_BOOL_INFO,},
+#line 649 "metafns.gperf"
+      {"is_nothrow_convertible_type", METAFN_IS_NOTHROW_CONVERTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 628 "metafns.gperf"
+      {"is_nothrow_constructible_type", METAFN_IS_NOTHROW_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,},
+#line 654 "metafns.gperf"
+      {"is_nothrow_invocable_type", METAFN_IS_NOTHROW_INVOCABLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,},
+#line 633 "metafns.gperf"
+      {"is_nothrow_copy_assignable_type", METAFN_IS_NOTHROW_COPY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 655 "metafns.gperf"
+      {"is_nothrow_invocable_r_type", METAFN_IS_NOTHROW_INVOCABLE_R_TYPE, METAFN_KIND_BOOL_TINFO_TINFO_REFLECTION_RANGET,},
+#line 630 "metafns.gperf"
+      {"is_nothrow_copy_constructible_type", METAFN_IS_NOTHROW_COPY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 646 "metafns.gperf"
+      {"is_base_of_type", METAFN_IS_BASE_OF_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 634 "metafns.gperf"
+      {"is_nothrow_move_assignable_type", METAFN_IS_NOTHROW_MOVE_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 631 "metafns.gperf"
+      {"is_nothrow_move_constructible_type", METAFN_IS_NOTHROW_MOVE_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 522 "metafns.gperf"
+      {"is_variable_template", METAFN_IS_VARIABLE_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 681 "metafns.gperf"
+      {"variant_size", METAFN_VARIANT_SIZE, METAFN_KIND_SIZE_T_TINFO,},
+#line 574 "metafns.gperf"
+      {"is_null_pointer_type", METAFN_IS_NULL_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 499 "metafns.gperf"
+      {"is_type", METAFN_IS_TYPE, METAFN_KIND_BOOL_INFO,},
+#line 467 "metafns.gperf"
+      {"is_public", METAFN_IS_PUBLIC, METAFN_KIND_BOOL_INFO,},
+#line 479 "metafns.gperf"
+      {"is_noexcept", METAFN_IS_NOEXCEPT, METAFN_KIND_BOOL_INFO,},
+#line 562 "metafns.gperf"
+      {"extract", METAFN_EXTRACT, METAFN_KIND_TEMPLATE_PARM_INFO,},
+#line 682 "metafns.gperf"
+      {"variant_alternative", METAFN_VARIANT_ALTERNATIVE, METAFN_KIND_INFO_SIZE_T_TINFO,},
+#line 600 "metafns.gperf"
+      {"is_polymorphic_type", METAFN_IS_POLYMORPHIC_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 469 "metafns.gperf"
+      {"is_private", METAFN_IS_PRIVATE, METAFN_KIND_BOOL_INFO,},
+#line 503 "metafns.gperf"
+      {"is_function", METAFN_IS_FUNCTION, METAFN_KIND_BOOL_INFO,},
+#line 500 "metafns.gperf"
+      {"is_namespace", METAFN_IS_NAMESPACE, METAFN_KIND_BOOL_INFO,},
+#line 651 "metafns.gperf"
+      {"is_pointer_interconvertible_base_of_type", METAFN_IS_POINTER_INTERCONVERTIBLE_BASE_OF_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 607 "metafns.gperf"
+      {"is_bounded_array_type", METAFN_IS_BOUNDED_ARRAY_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 483 "metafns.gperf"
+      {"is_const", METAFN_IS_CONST, METAFN_KIND_BOOL_INFO,},
+#line 529 "metafns.gperf"
+      {"is_concept", METAFN_IS_CONCEPT, METAFN_KIND_BOOL_INFO,},
+#line 645 "metafns.gperf"
+      {"is_same_type", METAFN_IS_SAME_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 553 "metafns.gperf"
+      {"bases_of", METAFN_BASES_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,},
+#line 492 "metafns.gperf"
+      {"has_module_linkage", METAFN_HAS_MODULE_LINKAGE, METAFN_KIND_BOOL_INFO,},
+#line 521 "metafns.gperf"
+      {"is_function_template", METAFN_IS_FUNCTION_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 632 "metafns.gperf"
+      {"is_nothrow_assignable_type", METAFN_IS_NOTHROW_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 504 "metafns.gperf"
+      {"is_conversion_function", METAFN_IS_CONVERSION_FUNCTION, METAFN_KIND_BOOL_INFO,},
+#line 637 "metafns.gperf"
+      {"is_nothrow_destructible_type", METAFN_IS_NOTHROW_DESTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 648 "metafns.gperf"
+      {"is_convertible_type", METAFN_IS_CONVERTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 638 "metafns.gperf"
+      {"is_implicit_lifetime_type", METAFN_IS_IMPLICIT_LIFETIME_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 520 "metafns.gperf"
+      {"is_template", METAFN_IS_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 629 "metafns.gperf"
+      {"is_nothrow_default_constructible_type", METAFN_IS_NOTHROW_DEFAULT_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 563 "metafns.gperf"
+      {"can_substitute", METAFN_CAN_SUBSTITUTE, METAFN_KIND_INFO_INFO_REFLECTION_RANGE,},
+#line 525 "metafns.gperf"
+      {"is_conversion_function_template", METAFN_IS_CONVERSION_FUNCTION_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 456 "metafns.gperf"
+      {"symbol_of", METAFN_SYMBOL_OF, METAFN_KIND_STRING_VIEW_OPERATORS,},
+#line 612 "metafns.gperf"
+      {"is_copy_constructible_type", METAFN_IS_COPY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 610 "metafns.gperf"
+      {"is_constructible_type", METAFN_IS_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,},
+#line 490 "metafns.gperf"
+      {"has_automatic_storage_duration", METAFN_HAS_AUTOMATIC_STORAGE_DURATION, METAFN_KIND_BOOL_INFO,},
+#line 615 "metafns.gperf"
+      {"is_copy_assignable_type", METAFN_IS_COPY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 679 "metafns.gperf"
+      {"tuple_size", METAFN_TUPLE_SIZE, METAFN_KIND_SIZE_T_TINFO,},
+#line 501 "metafns.gperf"
+      {"is_type_alias", METAFN_IS_TYPE_ALIAS, METAFN_KIND_BOOL_INFO,},
+#line 510 "metafns.gperf"
+      {"is_copy_constructor", METAFN_IS_COPY_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,},
+#line 546 "metafns.gperf"
+      {"variable_of", METAFN_VARIABLE_OF, METAFN_KIND_INFO_INFO,},
+#line 539 "metafns.gperf"
+      {"has_parent", METAFN_HAS_PARENT, METAFN_KIND_BOOL_INFO,},
+#line 587 "metafns.gperf"
+      {"is_reflection_type", METAFN_IS_REFLECTION_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 590 "metafns.gperf"
+      {"is_fundamental_type", METAFN_IS_FUNDAMENTAL_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 650 "metafns.gperf"
+      {"is_layout_compatible_type", METAFN_IS_LAYOUT_COMPATIBLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 561 "metafns.gperf"
+      {"bit_size_of", METAFN_BIT_SIZE_OF, METAFN_KIND_SIZE_T_INFO,},
+#line 513 "metafns.gperf"
+      {"is_copy_assignment", METAFN_IS_COPY_ASSIGNMENT, METAFN_KIND_BOOL_INFO,},
+#line 686 "metafns.gperf"
+      {"current", METAFN_ACCESS_CONTEXT_CURRENT, METAFN_KIND_ACCESS_CONTEXT_VOID,},
+#line 673 "metafns.gperf"
+      {"common_type", METAFN_COMMON_TYPE, METAFN_KIND_INFO_REFLECTION_RANGET,},
+#line 528 "metafns.gperf"
+      {"is_constructor_template", METAFN_IS_CONSTRUCTOR_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 683 "metafns.gperf"
+      {"type_order", METAFN_TYPE_ORDER, METAFN_KIND_STRONG_ORDERING_TINFO_TINFO,},
+#line 674 "metafns.gperf"
+      {"common_reference", METAFN_COMMON_REFERENCE, METAFN_KIND_INFO_REFLECTION_RANGET,},
+#line 538 "metafns.gperf"
+      {"has_default_member_initializer", METAFN_HAS_DEFAULT_MEMBER_INITIALIZER, METAFN_KIND_BOOL_INFO,},
+#line 680 "metafns.gperf"
+      {"tuple_element", METAFN_TUPLE_ELEMENT, METAFN_KIND_INFO_SIZE_T_TINFO,},
+#line 567 "metafns.gperf"
+      {"reflect_function", METAFN_REFLECT_FUNCTION, METAFN_KIND_INFO_TEMPLATE_PARM_REF,},
+#line 518 "metafns.gperf"
+      {"has_default_argument", METAFN_HAS_DEFAULT_ARGUMENT, METAFN_KIND_BOOL_INFO,},
+#line 613 "metafns.gperf"
+      {"is_move_constructible_type", METAFN_IS_MOVE_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 464 "metafns.gperf"
+      {"type_of", METAFN_TYPE_OF, METAFN_KIND_INFO_INFO,},
+#line 508 "metafns.gperf"
+      {"is_constructor", METAFN_IS_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,},
+#line 618 "metafns.gperf"
+      {"is_swappable_type", METAFN_IS_SWAPPABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 636 "metafns.gperf"
+      {"is_nothrow_swappable_type", METAFN_IS_NOTHROW_SWAPPABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 588 "metafns.gperf"
+      {"is_reference_type", METAFN_IS_REFERENCE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 495 "metafns.gperf"
+      {"has_linkage", METAFN_HAS_LINKAGE, METAFN_KIND_BOOL_INFO,},
+#line 635 "metafns.gperf"
+      {"is_nothrow_swappable_with_type", METAFN_IS_NOTHROW_SWAPPABLE_WITH_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 594 "metafns.gperf"
+      {"is_member_pointer_type", METAFN_IS_MEMBER_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 616 "metafns.gperf"
+      {"is_move_assignable_type", METAFN_IS_MOVE_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 519 "metafns.gperf"
+      {"has_ellipsis_parameter", METAFN_HAS_ELLIPSIS_PARAMETER, METAFN_KIND_BOOL_INFO,},
+#line 511 "metafns.gperf"
+      {"is_move_constructor", METAFN_IS_MOVE_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,},
+#line 545 "metafns.gperf"
+      {"parameters_of", METAFN_PARAMETERS_OF, METAFN_KIND_VECTOR_INFO_INFO,},
+#line 559 "metafns.gperf"
+      {"size_of", METAFN_SIZE_OF, METAFN_KIND_SIZE_T_INFO,},
+#line 514 "metafns.gperf"
+      {"is_move_assignment", METAFN_IS_MOVE_ASSIGNMENT, METAFN_KIND_BOOL_INFO,},
+#line 614 "metafns.gperf"
+      {"is_assignable_type", METAFN_IS_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 533 "metafns.gperf"
+      {"is_class_member", METAFN_IS_CLASS_MEMBER, METAFN_KIND_BOOL_INFO,},
+#line 597 "metafns.gperf"
+      {"is_trivially_copyable_type", METAFN_IS_TRIVIALLY_COPYABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 512 "metafns.gperf"
+      {"is_assignment", METAFN_IS_ASSIGNMENT, METAFN_KIND_BOOL_INFO,},
+#line 534 "metafns.gperf"
+      {"is_namespace_member", METAFN_IS_NAMESPACE_MEMBER, METAFN_KIND_BOOL_INFO,},
+#line 552 "metafns.gperf"
+      {"members_of", METAFN_MEMBERS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,},
+#line 620 "metafns.gperf"
+      {"is_trivially_constructible_type", METAFN_IS_TRIVIALLY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,},
+#line 625 "metafns.gperf"
+      {"is_trivially_copy_assignable_type", METAFN_IS_TRIVIALLY_COPY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 622 "metafns.gperf"
+      {"is_trivially_copy_constructible_type", METAFN_IS_TRIVIALLY_COPY_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 644 "metafns.gperf"
+      {"extent", METAFN_EXTENT, METAFN_KIND_SIZE_T_TINFO_UNSIGNED,},
+#line 583 "metafns.gperf"
+      {"is_enum_type", METAFN_IS_ENUM_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 543 "metafns.gperf"
+      {"template_of", METAFN_TEMPLATE_OF, METAFN_KIND_INFO_INFO,},
+#line 523 "metafns.gperf"
+      {"is_class_template", METAFN_IS_CLASS_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 507 "metafns.gperf"
+      {"is_special_member_function", METAFN_IS_SPECIAL_MEMBER_FUNCTION, METAFN_KIND_BOOL_INFO,},
+#line 468 "metafns.gperf"
+      {"is_protected", METAFN_IS_PROTECTED, METAFN_KIND_BOOL_INFO,},
+#line 535 "metafns.gperf"
+      {"is_nonstatic_data_member", METAFN_IS_NONSTATIC_DATA_MEMBER, METAFN_KIND_BOOL_INFO,},
+#line 677 "metafns.gperf"
+      {"unwrap_reference", METAFN_UNWRAP_REFERENCE, METAFN_KIND_INFO_TINFO,},
+#line 497 "metafns.gperf"
+      {"is_enumerable_type", METAFN_IS_ENUMERABLE_TYPE, METAFN_KIND_BOOL_INFO,},
+#line 589 "metafns.gperf"
+      {"is_arithmetic_type", METAFN_IS_ARITHMETIC_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 540 "metafns.gperf"
+      {"parent_of", METAFN_PARENT_OF, METAFN_KIND_INFO_INFO,},
+#line 471 "metafns.gperf"
+      {"is_pure_virtual", METAFN_IS_PURE_VIRTUAL, METAFN_KIND_BOOL_INFO,},
+#line 670 "metafns.gperf"
+      {"add_pointer", METAFN_ADD_POINTER, METAFN_KIND_INFO_TINFO,},
+#line 611 "metafns.gperf"
+      {"is_default_constructible_type", METAFN_IS_DEFAULT_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 675 "metafns.gperf"
+      {"underlying_type", METAFN_UNDERLYING_TYPE, METAFN_KIND_INFO_TINFO,},
+#line 516 "metafns.gperf"
+      {"is_function_parameter", METAFN_IS_FUNCTION_PARAMETER, METAFN_KIND_BOOL_INFO,},
+#line 459 "metafns.gperf"
+      {"identifier_of", METAFN_IDENTIFIER_OF, METAFN_KIND_STRING_VIEW_INFO,},
+#line 592 "metafns.gperf"
+      {"is_scalar_type", METAFN_IS_SCALAR_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 664 "metafns.gperf"
+      {"add_rvalue_reference", METAFN_ADD_RVALUE_REFERENCE, METAFN_KIND_INFO_TINFO,},
+#line 485 "metafns.gperf"
+      {"is_mutable_member", METAFN_IS_MUTABLE_MEMBER, METAFN_KIND_BOOL_INFO,},
+#line 502 "metafns.gperf"
+      {"is_namespace_alias", METAFN_IS_NAMESPACE_ALIAS, METAFN_KIND_BOOL_INFO,},
+#line 626 "metafns.gperf"
+      {"is_trivially_move_assignable_type", METAFN_IS_TRIVIALLY_MOVE_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 623 "metafns.gperf"
+      {"is_trivially_move_constructible_type", METAFN_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 509 "metafns.gperf"
+      {"is_default_constructor", METAFN_IS_DEFAULT_CONSTRUCTOR, METAFN_KIND_BOOL_INFO,},
+#line 481 "metafns.gperf"
+      {"is_enumerator", METAFN_IS_ENUMERATOR, METAFN_KIND_BOOL_INFO,},
+#line 531 "metafns.gperf"
+      {"is_object", METAFN_IS_OBJECT, METAFN_KIND_BOOL_INFO,},
+#line 603 "metafns.gperf"
+      {"is_aggregate_type", METAFN_IS_AGGREGATE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 515 "metafns.gperf"
+      {"is_destructor", METAFN_IS_DESTRUCTOR, METAFN_KIND_BOOL_INFO,},
+#line 582 "metafns.gperf"
+      {"is_member_function_pointer_type", METAFN_IS_MEMBER_FUNCTION_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 591 "metafns.gperf"
+      {"is_object_type", METAFN_IS_OBJECT_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 564 "metafns.gperf"
+      {"substitute", METAFN_SUBSTITUTE, METAFN_KIND_INFO_INFO_REFLECTION_RANGE,},
+#line 580 "metafns.gperf"
+      {"is_rvalue_reference_type", METAFN_IS_RVALUE_REFERENCE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 661 "metafns.gperf"
+      {"add_cv", METAFN_ADD_CV, METAFN_KIND_INFO_TINFO,},
+#line 565 "metafns.gperf"
+      {"reflect_constant", METAFN_REFLECT_CONSTANT, METAFN_KIND_INFO_TEMPLATE_PARM,},
+#line 624 "metafns.gperf"
+      {"is_trivially_assignable_type", METAFN_IS_TRIVIALLY_ASSIGNABLE_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 470 "metafns.gperf"
+      {"is_virtual", METAFN_IS_VIRTUAL, METAFN_KIND_BOOL_INFO,},
+#line 488 "metafns.gperf"
+      {"has_static_storage_duration", METAFN_HAS_STATIC_STORAGE_DURATION, METAFN_KIND_BOOL_INFO,},
+#line 663 "metafns.gperf"
+      {"add_lvalue_reference", METAFN_ADD_LVALUE_REFERENCE, METAFN_KIND_INFO_TINFO,},
+#line 579 "metafns.gperf"
+      {"is_lvalue_reference_type", METAFN_IS_LVALUE_REFERENCE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 557 "metafns.gperf"
+      {"enumerators_of", METAFN_ENUMERATORS_OF, METAFN_KIND_VECTOR_INFO_INFO,},
+#line 619 "metafns.gperf"
+      {"is_destructible_type", METAFN_IS_DESTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 544 "metafns.gperf"
+      {"template_arguments_of", METAFN_TEMPLATE_ARGUMENTS_OF, METAFN_KIND_VECTOR_INFO_INFO,},
+#line 652 "metafns.gperf"
+      {"is_invocable_type", METAFN_IS_INVOCABLE_TYPE, METAFN_KIND_BOOL_TINFO_REFLECTION_RANGET,},
+#line 659 "metafns.gperf"
+      {"add_const", METAFN_ADD_CONST, METAFN_KIND_INFO_TINFO,},
+#line 524 "metafns.gperf"
+      {"is_alias_template", METAFN_IS_ALIAS_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 599 "metafns.gperf"
+      {"is_empty_type", METAFN_IS_EMPTY_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 627 "metafns.gperf"
+      {"is_trivially_destructible_type", METAFN_IS_TRIVIALLY_DESTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 493 "metafns.gperf"
+      {"has_external_linkage", METAFN_HAS_EXTERNAL_LINKAGE, METAFN_KIND_BOOL_INFO,},
+#line 548 "metafns.gperf"
+      {"is_accessible", METAFN_IS_ACCESSIBLE, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,},
+#line 653 "metafns.gperf"
+      {"is_invocable_r_type", METAFN_IS_INVOCABLE_R_TYPE, METAFN_KIND_BOOL_TINFO_TINFO_REFLECTION_RANGET,},
+#line 647 "metafns.gperf"
+      {"is_virtual_base_of_type", METAFN_IS_VIRTUAL_BASE_OF_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 596 "metafns.gperf"
+      {"is_volatile_type", METAFN_IS_VOLATILE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 568 "metafns.gperf"
+      {"reflect_constant_string", METAFN_REFLECT_CONSTANT_STRING, METAFN_KIND_INFO_INPUT_RANGE,},
+#line 621 "metafns.gperf"
+      {"is_trivially_default_constructible_type", METAFN_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 527 "metafns.gperf"
+      {"is_literal_operator_template", METAFN_IS_LITERAL_OPERATOR_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 455 "metafns.gperf"
+      {"operator_of", METAFN_OPERATOR_OF, METAFN_KIND_OPERATORS_INFO,},
+#line 605 "metafns.gperf"
+      {"is_signed_type", METAFN_IS_SIGNED_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 609 "metafns.gperf"
+      {"is_scoped_enum_type", METAFN_IS_SCOPED_ENUM_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 617 "metafns.gperf"
+      {"is_swappable_with_type", METAFN_IS_SWAPPABLE_WITH_TYPE, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 556 "metafns.gperf"
+      {"subobjects_of", METAFN_SUBOBJECTS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,},
+#line 558 "metafns.gperf"
+      {"offset_of", METAFN_OFFSET_OF, METAFN_KIND_MEMBER_OFFSET_INFO,},
+#line 532 "metafns.gperf"
+      {"is_structured_binding", METAFN_IS_STRUCTURED_BINDING, METAFN_KIND_BOOL_INFO,},
+#line 473 "metafns.gperf"
+      {"is_final", METAFN_IS_FINAL, METAFN_KIND_BOOL_INFO,},
+#line 506 "metafns.gperf"
+      {"is_literal_operator", METAFN_IS_LITERAL_OPERATOR, METAFN_KIND_BOOL_INFO,},
+#line 666 "metafns.gperf"
+      {"make_unsigned", METAFN_MAKE_UNSIGNED, METAFN_KIND_INFO_TINFO,},
+#line 462 "metafns.gperf"
+      {"u8display_string_of", METAFN_U8DISPLAY_STRING_OF, METAFN_KIND_U8STRING_VIEW_INFO,},
+#line 639 "metafns.gperf"
+      {"has_virtual_destructor", METAFN_HAS_VIRTUAL_DESTRUCTOR, METAFN_KIND_BOOL_TINFO,},
+#line 595 "metafns.gperf"
+      {"is_const_type", METAFN_IS_CONST_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 478 "metafns.gperf"
+      {"is_explicit", METAFN_IS_EXPLICIT, METAFN_KIND_BOOL_INFO,},
+#line 571 "metafns.gperf"
+      {"is_data_member_spec", METAFN_IS_DATA_MEMBER_SPEC, METAFN_KIND_BOOL_INFO,},
+#line 496 "metafns.gperf"
+      {"is_complete_type", METAFN_IS_COMPLETE_TYPE, METAFN_KIND_BOOL_INFO,},
+#line 482 "metafns.gperf"
+      {"is_annotation", METAFN_IS_ANNOTATION, METAFN_KIND_BOOL_INFO,},
+#line 586 "metafns.gperf"
+      {"is_function_type", METAFN_IS_FUNCTION_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 547 "metafns.gperf"
+      {"return_type_of", METAFN_RETURN_TYPE_OF, METAFN_KIND_INFO_INFO,},
+#line 474 "metafns.gperf"
+      {"is_deleted", METAFN_IS_DELETED, METAFN_KIND_BOOL_INFO,},
+#line 466 "metafns.gperf"
+      {"constant_of", METAFN_CONSTANT_OF, METAFN_KIND_INFO_INFO,},
+#line 660 "metafns.gperf"
+      {"add_volatile", METAFN_ADD_VOLATILE, METAFN_KIND_INFO_TINFO,},
+#line 475 "metafns.gperf"
+      {"is_defaulted", METAFN_IS_DEFAULTED, METAFN_KIND_BOOL_INFO,},
+#line 640 "metafns.gperf"
+      {"has_unique_object_representations", METAFN_HAS_UNIQUE_OBJECT_REPRESENTATIONS, METAFN_KIND_BOOL_TINFO,},
+#line 581 "metafns.gperf"
+      {"is_member_object_pointer_type", METAFN_IS_MEMBER_OBJECT_POINTER_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 461 "metafns.gperf"
+      {"display_string_of", METAFN_DISPLAY_STRING_OF, METAFN_KIND_STRING_VIEW_INFO,},
+#line 517 "metafns.gperf"
+      {"is_explicit_object_parameter", METAFN_IS_EXPLICIT_OBJECT_PARAMETER, METAFN_KIND_BOOL_INFO,},
+#line 536 "metafns.gperf"
+      {"is_static_member", METAFN_IS_STATIC_MEMBER, METAFN_KIND_BOOL_INFO,},
+#line 465 "metafns.gperf"
+      {"object_of", METAFN_OBJECT_OF, METAFN_KIND_INFO_INFO,},
+#line 604 "metafns.gperf"
+      {"is_consteval_only_type", METAFN_IS_CONSTEVAL_ONLY_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 472 "metafns.gperf"
+      {"is_override", METAFN_IS_OVERRIDE, METAFN_KIND_BOOL_INFO,},
+#line 658 "metafns.gperf"
+      {"remove_cv", METAFN_REMOVE_CV, METAFN_KIND_INFO_TINFO,},
+#line 566 "metafns.gperf"
+      {"reflect_object", METAFN_REFLECT_OBJECT, METAFN_KIND_INFO_TEMPLATE_PARM_REF,},
+#line 576 "metafns.gperf"
+      {"is_floating_point_type", METAFN_IS_FLOATING_POINT_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 458 "metafns.gperf"
+      {"has_identifier", METAFN_HAS_IDENTIFIER, METAFN_KIND_BOOL_INFO,},
+#line 662 "metafns.gperf"
+      {"remove_reference", METAFN_REMOVE_REFERENCE, METAFN_KIND_INFO_TINFO,},
+#line 550 "metafns.gperf"
+      {"has_inaccessible_bases", METAFN_HAS_INACCESSIBLE_BASES, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,},
+#line 494 "metafns.gperf"
+      {"has_c_language_linkage", METAFN_HAS_C_LANGUAGE_LINKAGE, METAFN_KIND_BOOL_INFO,},
+#line 551 "metafns.gperf"
+      {"has_inaccessible_subobjects", METAFN_HAS_INACCESSIBLE_SUBOBJECTS, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,},
+#line 667 "metafns.gperf"
+      {"remove_extent", METAFN_REMOVE_EXTENT, METAFN_KIND_INFO_TINFO,},
+#line 549 "metafns.gperf"
+      {"has_inaccessible_nonstatic_data_members", METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS, METAFN_KIND_BOOL_INFO_ACCESS_CONTEXT,},
+#line 487 "metafns.gperf"
+      {"is_rvalue_reference_qualified", METAFN_IS_RVALUE_REFERENCE_QUALIFIED, METAFN_KIND_BOOL_INFO,},
+#line 642 "metafns.gperf"
+      {"reference_converts_from_temporary", METAFN_REFERENCE_CONVERTS_FROM_TEMPORARY, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 585 "metafns.gperf"
+      {"is_class_type", METAFN_IS_CLASS_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 477 "metafns.gperf"
+      {"is_user_declared", METAFN_IS_USER_DECLARED, METAFN_KIND_BOOL_INFO,},
+#line 570 "metafns.gperf"
+      {"data_member_spec", METAFN_DATA_MEMBER_SPEC, METAFN_KIND_INFO_TINFO_DATA_MEMBER_OPTIONS,},
+#line 486 "metafns.gperf"
+      {"is_lvalue_reference_qualified", METAFN_IS_LVALUE_REFERENCE_QUALIFIED, METAFN_KIND_BOOL_INFO,},
+#line 489 "metafns.gperf"
+      {"has_thread_storage_duration", METAFN_HAS_THREAD_STORAGE_DURATION, METAFN_KIND_BOOL_INFO,},
+#line 480 "metafns.gperf"
+      {"is_bit_field", METAFN_IS_BIT_FIELD, METAFN_KIND_BOOL_INFO,},
+#line 671 "metafns.gperf"
+      {"remove_cvref", METAFN_REMOVE_CVREF, METAFN_KIND_INFO_TINFO,},
+#line 676 "metafns.gperf"
+      {"invoke_result", METAFN_INVOKE_RESULT, METAFN_KIND_INFO_TINFO_REFLECTION_RANGET,},
+#line 542 "metafns.gperf"
+      {"has_template_arguments", METAFN_HAS_TEMPLATE_ARGUMENTS, METAFN_KIND_BOOL_INFO,},
+#line 505 "metafns.gperf"
+      {"is_operator_function", METAFN_IS_OPERATOR_FUNCTION, METAFN_KIND_BOOL_INFO,},
+#line 669 "metafns.gperf"
+      {"remove_pointer", METAFN_REMOVE_POINTER, METAFN_KIND_INFO_TINFO,},
+#line 541 "metafns.gperf"
+      {"dealias", METAFN_DEALIAS, METAFN_KIND_INFO_INFO,},
+#line 656 "metafns.gperf"
+      {"remove_const", METAFN_REMOVE_CONST, METAFN_KIND_INFO_TINFO,},
+#line 526 "metafns.gperf"
+      {"is_operator_function_template", METAFN_IS_OPERATOR_FUNCTION_TEMPLATE, METAFN_KIND_BOOL_INFO,},
+#line 641 "metafns.gperf"
+      {"reference_constructs_from_temporary", METAFN_REFERENCE_CONSTRUCTS_FROM_TEMPORARY, METAFN_KIND_BOOL_TINFO_TINFO,},
+#line 668 "metafns.gperf"
+      {"remove_all_extents", METAFN_REMOVE_ALL_EXTENTS, METAFN_KIND_INFO_TINFO,},
+#line 577 "metafns.gperf"
+      {"is_array_type", METAFN_IS_ARRAY_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 491 "metafns.gperf"
+      {"has_internal_linkage", METAFN_HAS_INTERNAL_LINKAGE, METAFN_KIND_BOOL_INFO,},
+#line 665 "metafns.gperf"
+      {"make_signed", METAFN_MAKE_SIGNED, METAFN_KIND_INFO_TINFO,},
+#line 554 "metafns.gperf"
+      {"static_data_members_of", METAFN_STATIC_DATA_MEMBERS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,},
+#line 593 "metafns.gperf"
+      {"is_compound_type", METAFN_IS_COMPOUND_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 601 "metafns.gperf"
+      {"is_abstract_type", METAFN_IS_ABSTRACT_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 572 "metafns.gperf"
+      {"define_aggregate", METAFN_DEFINE_AGGREGATE, METAFN_KIND_INFO_INFO_REFLECTION_RANGE,},
+#line 687 "metafns.gperf"
+      {"_S_exception_cvt_to_utf8", METAFN_EXCEPTION__S_EXCEPTION_CVT_TO_UTF8, METAFN_KIND_U8STRING_VIEW_INPUT_RANGE,},
+#line 688 "metafns.gperf"
+      {"_S_exception_cvt_from_utf8", METAFN_EXCEPTION__S_EXCEPTION_CVT_FROM_UTF8, METAFN_KIND_STRING_VIEW_INPUT_RANGE,},
+#line 608 "metafns.gperf"
+      {"is_unbounded_array_type", METAFN_IS_UNBOUNDED_ARRAY_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 598 "metafns.gperf"
+      {"is_standard_layout_type", METAFN_IS_STANDARD_LAYOUT_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 678 "metafns.gperf"
+      {"unwrap_ref_decay", METAFN_UNWRAP_REF_DECAY, METAFN_KIND_INFO_TINFO,},
+#line 569 "metafns.gperf"
+      {"reflect_constant_array", METAFN_REFLECT_CONSTANT_ARRAY, METAFN_KIND_INFO_INPUT_RANGE,},
+#line 457 "metafns.gperf"
+      {"u8symbol_of", METAFN_U8SYMBOL_OF, METAFN_KIND_U8STRING_VIEW_OPERATORS,},
+#line 575 "metafns.gperf"
+      {"is_integral_type", METAFN_IS_INTEGRAL_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 555 "metafns.gperf"
+      {"nonstatic_data_members_of", METAFN_NONSTATIC_DATA_MEMBERS_OF, METAFN_KIND_VECTOR_INFO_INFO_ACCESS_CONTEXT,},
+#line 672 "metafns.gperf"
+      {"decay", METAFN_DECAY, METAFN_KIND_INFO_TINFO,},
+#line 602 "metafns.gperf"
+      {"is_final_type", METAFN_IS_FINAL_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 657 "metafns.gperf"
+      {"remove_volatile", METAFN_REMOVE_VOLATILE, METAFN_KIND_INFO_TINFO,},
+#line 560 "metafns.gperf"
+      {"alignment_of", METAFN_ALIGNMENT_OF, METAFN_KIND_SIZE_T_INFO,},
+#line 463 "metafns.gperf"
+      {"source_location_of", METAFN_SOURCE_LOCATION_OF, METAFN_KIND_SOURCE_LOCATION_INFO,},
+#line 685 "metafns.gperf"
+      {"annotations_of_with_type", METAFN_ANNOTATIONS_OF_WITH_TYPE, METAFN_KIND_VECTOR_INFO_INFO_INFO,},
+#line 460 "metafns.gperf"
+      {"u8identifier_of", METAFN_U8IDENTIFIER_OF, METAFN_KIND_U8STRING_VIEW_INFO,},
+#line 684 "metafns.gperf"
+      {"annotations_of", METAFN_ANNOTATIONS_OF, METAFN_KIND_VECTOR_INFO_INFO,},
+#line 584 "metafns.gperf"
+      {"is_union_type", METAFN_IS_UNION_TYPE, METAFN_KIND_BOOL_TINFO,},
+#line 476 "metafns.gperf"
+      {"is_user_provided", METAFN_IS_USER_PROVIDED, METAFN_KIND_BOOL_INFO,},
+#line 606 "metafns.gperf"
+      {"is_unsigned_type", METAFN_IS_UNSIGNED_TYPE, METAFN_KIND_BOOL_TINFO,}
+    };
+#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3)
+#pragma GCC diagnostic pop
+#endif
+
+  static const short lookup[] =
+    {
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,
+       -1,  -1,   1,  -1,  -1,   2,   3,  -1,   4,  -1,
+       -1,  -1,   5,  -1,  -1,  -1,   6,   7,  -1,   8,
+        9,  10,  11,  -1,  12,  13,  14,  -1,  -1,  15,
+       16,  -1,  17,  -1,  -1,  18,  -1,  19,  -1,  20,
+       -1,  21,  22,  -1,  23,  -1,  -1,  -1,  -1,  24,
+       25,  26,  27,  -1,  -1,  28,  29,  -1,  30,  -1,
+       31,  -1,  32,  33,  -1,  34,  -1,  -1,  -1,  -1,
+       35,  36,  37,  38,  39,  40,  -1,  -1,  -1,  -1,
+       -1,  41,  42,  -1,  43,  -1,  44,  -1,  -1,  45,
+       -1,  46,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  47,  48,  49,  -1,
+       50,  -1,  -1,  51,  52,  -1,  53,  54,  55,  56,
+       57,  58,  -1,  59,  -1,  -1,  -1,  60,  -1,  -1,
+       -1,  61,  -1,  62,  -1,  63,  64,  65,  66,  -1,
+       -1,  67,  -1,  -1,  -1,  -1,  -1,  68,  -1,  -1,
+       -1,  69,  70,  -1,  71,  -1,  -1,  72,  -1,  -1,
+       73,  -1,  74,  75,  -1,  76,  -1,  77,  78,  79,
+       -1,  -1,  -1,  -1,  80,  -1,  -1,  -1,  81,  -1,
+       -1,  -1,  82,  83,  -1,  -1,  -1,  -1,  84,  -1,
+       85,  86,  -1,  87,  88,  89,  90,  -1,  91,  -1,
+       -1,  92,  -1,  -1,  -1,  -1,  93,  94,  -1,  -1,
+       -1,  95,  96,  -1,  -1,  -1,  97,  98,  -1,  -1,
+       -1,  -1,  -1,  -1,  99,  -1, 100,  -1, 101,  -1,
+       -1,  -1,  -1, 102, 103, 104, 105,  -1,  -1, 106,
+      107, 108,  -1,  -1,  -1,  -1,  -1,  -1, 109, 110,
+      111,  -1, 112, 113,  -1,  -1,  -1,  -1, 114,  -1,
+       -1, 115, 116, 117, 118,  -1,  -1,  -1,  -1, 119,
+       -1,  -1,  -1, 120,  -1,  -1, 121,  -1,  -1, 122,
+      123,  -1,  -1, 124,  -1,  -1, 125,  -1,  -1,  -1,
+       -1, 126,  -1, 127,  -1,  -1,  -1,  -1, 128, 129,
+      130,  -1,  -1, 131, 132, 133, 134, 135,  -1, 136,
+       -1,  -1, 137,  -1, 138, 139,  -1, 140, 141, 142,
+       -1, 143, 144, 145, 146,  -1, 147,  -1,  -1,  -1,
+       -1, 148, 149,  -1, 150,  -1, 151,  -1, 152, 153,
+       -1, 154,  -1,  -1,  -1,  -1, 155, 156, 157, 158,
+       -1,  -1,  -1, 159, 160,  -1,  -1, 161,  -1, 162,
+       -1,  -1, 163, 164,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1, 165,  -1, 166, 167, 168,  -1,  -1,  -1,
+       -1, 169, 170, 171, 172,  -1,  -1, 173,  -1,  -1,
+       -1,  -1,  -1,  -1, 174,  -1, 175,  -1,  -1, 176,
+       -1,  -1, 177,  -1,  -1, 178,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1, 179,  -1,  -1,  -1, 180,  -1,  -1,
+       -1,  -1, 181,  -1, 182, 183,  -1, 184,  -1, 185,
+       -1,  -1, 186,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1, 187,  -1, 188,  -1,  -1,  -1, 189, 190,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 191,
+       -1, 192,  -1,  -1,  -1,  -1, 193,  -1, 194, 195,
+      196, 197,  -1, 198,  -1,  -1,  -1,  -1,  -1, 199,
+      200,  -1,  -1, 201,  -1,  -1,  -1,  -1,  -1,  -1,
+      202, 203,  -1,  -1, 204,  -1,  -1,  -1,  -1,  -1,
+       -1, 205, 206,  -1,  -1,  -1,  -1,  -1,  -1, 207,
+      208, 209,  -1,  -1,  -1, 210,  -1,  -1,  -1,  -1,
+       -1,  -1, 211,  -1,  -1,  -1,  -1, 212,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1, 213,  -1,  -1,  -1, 214,  -1, 215, 216,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 217,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1, 218,  -1,  -1,
+       -1,  -1,  -1, 219,  -1,  -1,  -1, 220,  -1,  -1,
+       -1,  -1, 221,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+      222,  -1,  -1,  -1,  -1,  -1, 223,  -1,  -1,  -1,
+       -1,  -1, 224,  -1,  -1,  -1,  -1,  -1,  -1, 225,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1, 226,  -1,  -1,  -1,  -1,  -1, 227,  -1,
+       -1,  -1,  -1,  -1, 228,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1, 229,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1, 230,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 231,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1, 232,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+       -1,  -1,  -1,  -1,  -1,  -1,  -1, 233
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          int index = lookup[key];
+
+          if (index >= 0)
+            {
+              const char *s = wordlist[index].name;
+
+              if (*str == *s && !strcmp (str + 1, s + 1))
+                return &wordlist[index];
+            }
+        }
+    }
+  return static_cast<struct metafn_info *> (0);
+}
index e5ad3ac4494f7ddc9efc9a98cd4f15752653dac3..94fdc32d0bd6d92fab1ae14b87b8d13e4ef6a519 100644 (file)
@@ -1899,7 +1899,7 @@ maybe_synthesize_method (tree fndecl)
 /* Build a reference to type TYPE with cv-quals QUALS, which is an
    rvalue if RVALUE is true.  */
 
-static tree
+tree
 build_stub_type (tree type, int quals, bool rvalue)
 {
   tree argtype = cp_build_qualified_type (type, quals);
index e6b2b2f785812bd36db0a6752c47dc4baff21255..37b288767ab2998c2ad4c945534800e2f9d44b6c 100644 (file)
@@ -9843,6 +9843,10 @@ trees_out::type_node (tree type)
            wu (nunits.coeffs[ix]);
        }
       break;
+
+    case META_TYPE:
+      /* No additional data.  */
+      break;
     }
 
   tree_node (TYPE_ATTRIBUTES (type));
@@ -10688,6 +10692,11 @@ trees_in::tree_node (bool is_use)
                res = build_vector_type (res, nunits);
            }
            break;
+
+         case META_TYPE:
+           if (!get_overrun ())
+             res = meta_info_type_node;
+           break;
          }
 
        /* In the exporting TU, a derived type with attributes was built by
index 8847acc693c1c8e4cbfd888f9d740126d3b0c08d..1b3713dc40e18badf4888c5a024d30a03c3e1fd6 100644 (file)
@@ -1583,6 +1583,13 @@ name_lookup::adl_type (tree type)
       adl_type (TYPE_PTRMEM_POINTED_TO_TYPE (type));
       return;
     }
+  else if (REFLECTION_TYPE_P (type))
+    {
+      /* The namespace std::meta is an associated namespace of
+        std::meta::info.  */
+      adl_namespace (std_meta_node);
+      return;
+    }
 
   switch (TREE_CODE (type))
     {
@@ -2765,7 +2772,10 @@ strip_using_decl (tree decl)
   if (decl == NULL_TREE)
     return NULL_TREE;
 
-  while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
+  while (TREE_CODE (decl) == USING_DECL
+        && !DECL_DEPENDENT_P (decl)
+        && (LIKELY (!cp_preserve_using_decl)
+            || TREE_CODE (USING_DECL_DECLS (decl)) == NAMESPACE_DECL))
     decl = USING_DECL_DECLS (decl);
 
   if (TREE_CODE (decl) == USING_DECL && DECL_DEPENDENT_P (decl)
@@ -6683,6 +6693,15 @@ handle_namespace_attrs (tree ns, tree attributes)
            DECL_ATTRIBUTES (ns) = tree_cons (name, args,
                                              DECL_ATTRIBUTES (ns));
        }
+      else if (annotation_p (d))
+       {
+         const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (d));
+         bool no_add_attrs = false;
+         as->handler (&ns, name, args, 0, &no_add_attrs);
+         if (!no_add_attrs)
+           DECL_ATTRIBUTES (ns) = tree_cons (TREE_PURPOSE (d), args,
+                                             DECL_ATTRIBUTES (ns));
+       }
       else if (!attribute_ignored_p (d))
        {
          warning (OPT_Wattributes, "%qD attribute directive ignored",
@@ -6720,9 +6739,10 @@ do_namespace_alias (location_t loc, tree alias, tree name_space)
   if (name_space == error_mark_node)
     return;
 
-  gcc_assert (TREE_CODE (name_space) == NAMESPACE_DECL);
-
-  name_space = ORIGINAL_NAMESPACE (name_space);
+  if (TREE_CODE (name_space) == NAMESPACE_DECL)
+    name_space = ORIGINAL_NAMESPACE (name_space);
+  else
+    gcc_assert (TREE_CODE (name_space) == SPLICE_EXPR);
 
   /* Build the alias.  */
   alias = build_lang_decl_loc (loc, NAMESPACE_DECL, alias, void_type_node);
@@ -7532,7 +7552,9 @@ lookup_qualified_name (tree scope, tree name, LOOK_want want, bool complain)
 
          /* If we have a known type overload, pull it out.  This can happen
             for using decls.  */
-         if (TREE_CODE (t) == OVERLOAD && TREE_TYPE (t) != unknown_type_node)
+         if (TREE_CODE (t) == OVERLOAD
+             && TREE_TYPE (t) != unknown_type_node
+             && LIKELY (!cp_preserve_using_decl))
            t = OVL_FUNCTION (t);
        }
     }
@@ -9155,6 +9177,8 @@ finish_using_directive (tree target, tree attribs)
                diagnosed = true;
              }
          }
+       else if (annotation_p (a))
+         error ("annotation on using directive");
        else if (!attribute_ignored_p (a))
          warning (OPT_Wattributes, "%qD attribute directive ignored", name);
       }
index dc01b7482c79af97ac5c89f13fb0aa1404e09ed7..9f2c581ece11828e55c43fa53ffc77da54145241 100644 (file)
@@ -50,6 +50,12 @@ along with GCC; see the file COPYING3.  If not see
      ovl_op_flags bits.  Postincrement and postdecrement operators are
      marked as binary.
 
+   META_NAME
+
+     The name of std::meta::operators enumerator corresponding to the
+     operator, without the "op_" prefix or NULL if there is no
+     corresponding enumerator.
+
    Before including this file, you should define DEF_OPERATOR
    to take these arguments.
 
@@ -63,83 +69,88 @@ along with GCC; see the file COPYING3.  If not see
    FLAGS (OVL_OP_FLAG_BINARY).  */
 
 #ifndef DEF_ASSN_OPERATOR
-#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) \
-  DEF_OPERATOR(NAME, CODE, MANGLING, OVL_OP_FLAG_BINARY)
+#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING, META) \
+  DEF_OPERATOR(NAME, CODE, MANGLING, OVL_OP_FLAG_BINARY, META)
 #endif
 
 /* Memory allocation operators.  ARITY has special meaning. */
-DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC)
+DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC, "new")
 DEF_OPERATOR ("new []", VEC_NEW_EXPR, "na",
-             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_VEC)
+             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_VEC, "array_new")
 DEF_OPERATOR ("delete", DELETE_EXPR, "dl",
-             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE)
+             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE, "delete")
 DEF_OPERATOR ("delete []", VEC_DELETE_EXPR, "da",
-             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE | OVL_OP_FLAG_VEC)
+             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE
+             | OVL_OP_FLAG_VEC, "array_delete")
 
 /* Unary operators.  */
-DEF_OPERATOR ("+", UNARY_PLUS_EXPR, "ps", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("-", NEGATE_EXPR, "ng", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("&", ADDR_EXPR, "ad", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("*", INDIRECT_REF, "de", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("~", BIT_NOT_EXPR, "co", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("!", TRUTH_NOT_EXPR, "nt", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("++", PREINCREMENT_EXPR, "pp", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("--", PREDECREMENT_EXPR, "mm", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("->", COMPONENT_REF, "pt", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("sizeof", SIZEOF_EXPR, "sz", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("+", UNARY_PLUS_EXPR, "ps", OVL_OP_FLAG_UNARY, "plus")
+DEF_OPERATOR ("-", NEGATE_EXPR, "ng", OVL_OP_FLAG_UNARY, "minus")
+DEF_OPERATOR ("&", ADDR_EXPR, "ad", OVL_OP_FLAG_UNARY, "ampersand")
+DEF_OPERATOR ("*", INDIRECT_REF, "de", OVL_OP_FLAG_UNARY, "star")
+DEF_OPERATOR ("~", BIT_NOT_EXPR, "co", OVL_OP_FLAG_UNARY, "tilde")
+DEF_OPERATOR ("!", TRUTH_NOT_EXPR, "nt", OVL_OP_FLAG_UNARY, "exclamation")
+DEF_OPERATOR ("++", PREINCREMENT_EXPR, "pp", OVL_OP_FLAG_UNARY, "plus_plus")
+DEF_OPERATOR ("--", PREDECREMENT_EXPR, "mm", OVL_OP_FLAG_UNARY, "minus_minus")
+DEF_OPERATOR ("->", COMPONENT_REF, "pt", OVL_OP_FLAG_UNARY, "arrow")
+DEF_OPERATOR ("sizeof", SIZEOF_EXPR, "sz", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY, "co_await")
 
 /* These are extensions.  */
-DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY,
+             NULL)
+DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY,
+             NULL)
 
 /* Binary operators.  */
-DEF_OPERATOR ("+", PLUS_EXPR, "pl", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("-", MINUS_EXPR, "mi", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("*", MULT_EXPR, "ml", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("/", TRUNC_DIV_EXPR, "dv", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("%", TRUNC_MOD_EXPR, "rm", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("&", BIT_AND_EXPR, "an", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("|", BIT_IOR_EXPR, "or", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("^", BIT_XOR_EXPR, "eo", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("<<", LSHIFT_EXPR, "ls", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR (">>", RSHIFT_EXPR, "rs", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("+", PLUS_EXPR, "pl", OVL_OP_FLAG_BINARY, "plus")
+DEF_OPERATOR ("-", MINUS_EXPR, "mi", OVL_OP_FLAG_BINARY, "minus")
+DEF_OPERATOR ("*", MULT_EXPR, "ml", OVL_OP_FLAG_BINARY, "star")
+DEF_OPERATOR ("/", TRUNC_DIV_EXPR, "dv", OVL_OP_FLAG_BINARY, "slash")
+DEF_OPERATOR ("%", TRUNC_MOD_EXPR, "rm", OVL_OP_FLAG_BINARY, "percent")
+DEF_OPERATOR ("&", BIT_AND_EXPR, "an", OVL_OP_FLAG_BINARY, "ampersand")
+DEF_OPERATOR ("|", BIT_IOR_EXPR, "or", OVL_OP_FLAG_BINARY, "pipe")
+DEF_OPERATOR ("^", BIT_XOR_EXPR, "eo", OVL_OP_FLAG_BINARY, "caret")
+DEF_OPERATOR ("<<", LSHIFT_EXPR, "ls", OVL_OP_FLAG_BINARY, "less_less")
+DEF_OPERATOR (">>", RSHIFT_EXPR, "rs", OVL_OP_FLAG_BINARY, "greater_greater")
 
 /* defaultable_fn_check relies on the ordering of the comparison operators.  */
-DEF_OPERATOR ("==", EQ_EXPR, "eq", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("!=", NE_EXPR, "ne", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("<", LT_EXPR, "lt", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR (">", GT_EXPR, "gt", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("<=", LE_EXPR, "le", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR (">=", GE_EXPR, "ge", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("<=>", SPACESHIP_EXPR, "ss", OVL_OP_FLAG_BINARY)
-
-DEF_OPERATOR ("&&", TRUTH_ANDIF_EXPR, "aa", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("||", TRUTH_ORIF_EXPR, "oo", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR (",", COMPOUND_EXPR, "cm", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("->*", MEMBER_REF, "pm", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR (".*", DOTSTAR_EXPR, "ds", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("[]", ARRAY_REF, "ix", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", OVL_OP_FLAG_BINARY)
-DEF_OPERATOR ("--", POSTDECREMENT_EXPR, "mm", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("==", EQ_EXPR, "eq", OVL_OP_FLAG_BINARY, "equals_equals")
+DEF_OPERATOR ("!=", NE_EXPR, "ne", OVL_OP_FLAG_BINARY, "exclamation_equals")
+DEF_OPERATOR ("<", LT_EXPR, "lt", OVL_OP_FLAG_BINARY, "less")
+DEF_OPERATOR (">", GT_EXPR, "gt", OVL_OP_FLAG_BINARY, "greater")
+DEF_OPERATOR ("<=", LE_EXPR, "le", OVL_OP_FLAG_BINARY, "less_equals")
+DEF_OPERATOR (">=", GE_EXPR, "ge", OVL_OP_FLAG_BINARY, "greater_equals")
+DEF_OPERATOR ("<=>", SPACESHIP_EXPR, "ss", OVL_OP_FLAG_BINARY, "spaceship")
+
+DEF_OPERATOR ("&&", TRUTH_ANDIF_EXPR, "aa", OVL_OP_FLAG_BINARY,
+             "ampersand_ampersand")
+DEF_OPERATOR ("||", TRUTH_ORIF_EXPR, "oo", OVL_OP_FLAG_BINARY, "pipe_pipe")
+DEF_OPERATOR (",", COMPOUND_EXPR, "cm", OVL_OP_FLAG_BINARY, "comma")
+DEF_OPERATOR ("->*", MEMBER_REF, "pm", OVL_OP_FLAG_BINARY, "arrow_star")
+DEF_OPERATOR (".*", DOTSTAR_EXPR, "ds", OVL_OP_FLAG_BINARY, NULL)
+DEF_OPERATOR ("[]", ARRAY_REF, "ix", OVL_OP_FLAG_BINARY, "square_brackets")
+DEF_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", OVL_OP_FLAG_BINARY, "plus_plus")
+DEF_OPERATOR ("--", POSTDECREMENT_EXPR, "mm", OVL_OP_FLAG_BINARY,
+             "minus_minus")
 
 /* Miscellaneous.  */
-DEF_OPERATOR ("?:", COND_EXPR, "qu", OVL_OP_FLAG_NONE)
-DEF_OPERATOR ("()", CALL_EXPR, "cl", OVL_OP_FLAG_NONE)
+DEF_OPERATOR ("?:", COND_EXPR, "qu", OVL_OP_FLAG_NONE, NULL)
+DEF_OPERATOR ("()", CALL_EXPR, "cl", OVL_OP_FLAG_NONE, "parentheses")
 
 /* Operators needed for mangling.  */
-DEF_OPERATOR (NULL, CAST_EXPR, "cv", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR (NULL, DYNAMIC_CAST_EXPR, "dc", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR (NULL, REINTERPRET_CAST_EXPR, "rc", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR (NULL, CONST_CAST_EXPR, "cc", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR (NULL, STATIC_CAST_EXPR, "sc", OVL_OP_FLAG_UNARY)
-DEF_OPERATOR (NULL, SCOPE_REF, "sr", OVL_OP_FLAG_NONE)
-DEF_OPERATOR (NULL, EXPR_PACK_EXPANSION, "sp", OVL_OP_FLAG_NONE)
-DEF_OPERATOR (NULL, UNARY_LEFT_FOLD_EXPR, "fl", OVL_OP_FLAG_NONE)
-DEF_OPERATOR (NULL, UNARY_RIGHT_FOLD_EXPR, "fr", OVL_OP_FLAG_NONE)
-DEF_OPERATOR (NULL, BINARY_LEFT_FOLD_EXPR, "fL", OVL_OP_FLAG_NONE)
-DEF_OPERATOR (NULL, BINARY_RIGHT_FOLD_EXPR, "fR", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, CAST_EXPR, "cv", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR (NULL, DYNAMIC_CAST_EXPR, "dc", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR (NULL, REINTERPRET_CAST_EXPR, "rc", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR (NULL, CONST_CAST_EXPR, "cc", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR (NULL, STATIC_CAST_EXPR, "sc", OVL_OP_FLAG_UNARY, NULL)
+DEF_OPERATOR (NULL, SCOPE_REF, "sr", OVL_OP_FLAG_NONE, NULL)
+DEF_OPERATOR (NULL, EXPR_PACK_EXPANSION, "sp", OVL_OP_FLAG_NONE, NULL)
+DEF_OPERATOR (NULL, UNARY_LEFT_FOLD_EXPR, "fl", OVL_OP_FLAG_NONE, NULL)
+DEF_OPERATOR (NULL, UNARY_RIGHT_FOLD_EXPR, "fr", OVL_OP_FLAG_NONE, NULL)
+DEF_OPERATOR (NULL, BINARY_LEFT_FOLD_EXPR, "fL", OVL_OP_FLAG_NONE, NULL)
+DEF_OPERATOR (NULL, BINARY_RIGHT_FOLD_EXPR, "fR", OVL_OP_FLAG_NONE, NULL)
 
 #ifdef OPERATOR_TRANSITION
 OPERATOR_TRANSITION
@@ -147,17 +158,17 @@ OPERATOR_TRANSITION
 #endif
 
 /* Assignment operators.  */
-DEF_ASSN_OPERATOR ("=", NOP_EXPR, "aS")
-DEF_ASSN_OPERATOR ("+=", PLUS_EXPR, "pL")
-DEF_ASSN_OPERATOR ("-=", MINUS_EXPR, "mI")
-DEF_ASSN_OPERATOR ("*=", MULT_EXPR, "mL")
-DEF_ASSN_OPERATOR ("/=", TRUNC_DIV_EXPR, "dV")
-DEF_ASSN_OPERATOR ("%=", TRUNC_MOD_EXPR, "rM")
-DEF_ASSN_OPERATOR ("&=", BIT_AND_EXPR, "aN")
-DEF_ASSN_OPERATOR ("|=", BIT_IOR_EXPR, "oR")
-DEF_ASSN_OPERATOR ("^=", BIT_XOR_EXPR, "eO")
-DEF_ASSN_OPERATOR ("<<=", LSHIFT_EXPR, "lS")
-DEF_ASSN_OPERATOR (">>=", RSHIFT_EXPR, "rS")
+DEF_ASSN_OPERATOR ("=", NOP_EXPR, "aS", "equals")
+DEF_ASSN_OPERATOR ("+=", PLUS_EXPR, "pL", "plus_equals")
+DEF_ASSN_OPERATOR ("-=", MINUS_EXPR, "mI", "minus_equals")
+DEF_ASSN_OPERATOR ("*=", MULT_EXPR, "mL", "star_equals")
+DEF_ASSN_OPERATOR ("/=", TRUNC_DIV_EXPR, "dV", "slash_equals")
+DEF_ASSN_OPERATOR ("%=", TRUNC_MOD_EXPR, "rM", "percent_equals")
+DEF_ASSN_OPERATOR ("&=", BIT_AND_EXPR, "aN", "ampersand_equals")
+DEF_ASSN_OPERATOR ("|=", BIT_IOR_EXPR, "oR", "pipe_equals")
+DEF_ASSN_OPERATOR ("^=", BIT_XOR_EXPR, "eO", "caret_equals")
+DEF_ASSN_OPERATOR ("<<=", LSHIFT_EXPR, "lS", "less_less_equals")
+DEF_ASSN_OPERATOR (">>=", RSHIFT_EXPR, "rS", "greater_greater_equals")
 
 #undef DEF_ASSN_OPERATOR
 #undef DEF_OPERATOR
index 2dc4863ec5285d0517edf778ae438c9f359a0eb2..393c8b2ec44ee4872a447ff369c4257048123c9c 100644 (file)
@@ -152,6 +152,7 @@ enum required_token {
   RT_COMMA_CLOSE_PAREN, /* ',' or ')' */
   RT_PRAGMA_EOL, /* end of line */
   RT_NAME, /* identifier */
+  RT_CLOSE_SPLICE, /* ':]' */
 
   /* The type is CPP_KEYWORD */
   RT_NEW, /* new */
@@ -292,6 +293,10 @@ static FILE *cp_lexer_debug_stream;
    sizeof, typeof, or alignof.  */
 int cp_unevaluated_operand;
 
+/* Nonzero if we are parsing a reflect-expression and shouldn't strip
+   using-declarations.  */
+bool cp_preserve_using_decl;
+
 #if ENABLE_ANALYZER
 
 namespace ana {
@@ -2754,7 +2759,7 @@ static tree cp_parser_template_type_arg
   (cp_parser *);
 static tree cp_parser_trailing_type_id (cp_parser *);
 static tree cp_parser_type_id_1
-  (cp_parser *, cp_parser_flags, bool, bool, location_t *);
+  (cp_parser *, cp_parser_flags, bool, bool, location_t *, bool *);
 static void cp_parser_type_specifier_seq
   (cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *);
 static tree cp_parser_parameter_declaration_clause
@@ -2855,7 +2860,7 @@ static tree cp_parser_template_parameter
 static tree cp_parser_type_parameter
   (cp_parser *, bool *);
 static tree cp_parser_template_id
-  (cp_parser *, bool, bool, enum tag_types, bool);
+  (cp_parser *, bool, bool, enum tag_types, bool, tree = NULL_TREE);
 static tree cp_parser_template_id_expr
   (cp_parser *, bool, bool, bool);
 static tree cp_parser_template_name
@@ -3346,6 +3351,8 @@ get_required_cpp_ttype (required_token token_desc)
       return CPP_COLON;
     case RT_CLOSE_PAREN:
       return CPP_CLOSE_PAREN;
+    case RT_CLOSE_SPLICE:
+      return CPP_CLOSE_SPLICE;
 
     default:
       /* Use CPP_EOF as a "no completions possible" code.  */
@@ -6058,6 +6065,443 @@ cp_parser_pack_index (cp_parser *parser, tree pack)
   return make_pack_index (pack, index);
 }
 
+/* Return true iff the next tokens start a splice-type-specifier.
+   If REQUIRE_TYPENAME_P, we only return true if there is a preceding
+   typename keyword.  */
+
+static bool
+cp_parser_next_tokens_start_splice_type_spec_p (cp_parser *parser,
+                                               bool require_typename_p)
+{
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE))
+    return !require_typename_p;
+  return (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME)
+         && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SPLICE));
+}
+
+/* Return true iff the next tokens start a splice-scope-specifier.  */
+
+static bool
+cp_parser_next_tokens_can_start_splice_scope_spec_p (cp_parser *parser)
+{
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE))
+    return true;
+  return (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)
+         && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_SPLICE));
+}
+
+/* Parse a splice-specifier.
+
+   splice-specifier:
+     [: constant-expression :]
+
+    splice-specialization-specifier:
+      splice-specifier < template-argument-list[opt] >
+
+   TEMPLATE_P is true if we've parsed the leading template keyword.
+   TARGS_P is set to true if there is a splice-specialization-specifier.  */
+
+static cp_expr
+cp_parser_splice_specifier (cp_parser *parser, bool template_p = false,
+                           bool *targs_p = nullptr)
+{
+  /* Get the location of the '[:'.  */
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  /* Consume the '[:'.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* Get the location of the operand.  */
+  location_t caret_loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  if (!flag_reflection)
+    {
+      error_at (caret_loc,
+               "reflection is only available with %<-freflection%>");
+      return error_mark_node;
+    }
+
+  tree object_type = parser->context->object_type;
+  /* Clear parser->context->object_type.  E.g.,
+     struct A { static int x; };
+     int q = A ().[: ^^x :];
+     should be an error -- x is not a member-qualified name and isn't
+     in scope.  */
+  parser->context->object_type = NULL;
+  tree expr = cp_parser_constant_expression (parser,
+                                            /*allow_non_constant_p=*/false,
+                                            /*non_constant_p=*/nullptr,
+                                            /*strict_p=*/true);
+
+  /* Get the location of the ':]'.  */
+  location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  /* Consume the ':]'.  */
+  if (!cp_parser_require (parser, CPP_CLOSE_SPLICE, RT_CLOSE_SPLICE))
+    return error_mark_node;
+
+  /* Get the reflected operand.  */
+  expr = splice (expr);
+
+  /* If the next token is a '<', it's a splice-specialization-specifier.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+    {
+      /* For member access splice-specialization-specifier, try to wrap
+        non-dependent splice for function template into a BASELINK so
+        that cp_parser_template_id can handle it.  */
+      if (object_type
+         && DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (expr))
+         && !dependent_type_p (object_type))
+       {
+         tree scope = DECL_CONTEXT (OVL_FIRST (expr));
+         if (scope && CLASS_TYPE_P (scope))
+           {
+             tree access_path = lookup_base (object_type, scope, ba_unique,
+                                             NULL, tf_warning_or_error);
+             if (access_path == error_mark_node)
+               expr = error_mark_node;
+             else
+               expr
+                 = build_baselink (access_path, TYPE_BINFO (object_type),
+                                   expr,
+                                   IDENTIFIER_CONV_OP_P (OVL_NAME (expr))
+                                   ? TREE_TYPE (OVL_NAME (expr)) : NULL_TREE);
+           }
+       }
+      /* Let cp_parser_template_id parse the template arguments.  */
+      expr = cp_parser_template_id (parser, template_p,
+                                   /*check_dependency_p=*/true,
+                                   /*tag_type=*/none_type,
+                                   /*is_declaration=*/false,
+                                   expr);
+      if (targs_p)
+       *targs_p = true;
+    }
+
+  return cp_expr (expr, make_location (caret_loc, start_loc, finish_loc));
+}
+
+/* Parse a splice-type-specifier.
+
+   splice-type-specifier:
+     typename[opt] splice-specifier
+     typename[opt] splice-specialization-specifier
+
+ */
+
+static tree
+cp_parser_splice_type_specifier (cp_parser *parser)
+{
+  /* Consume the optional typename.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
+    cp_lexer_consume_token (parser->lexer);
+
+  cp_expr expr = cp_parser_splice_specifier (parser);
+  const location_t loc = (expr != error_mark_node
+                         ? expr.get_location () : input_location);
+  tree type = expr.get_value ();
+
+  if (TREE_CODE (type) == TYPE_DECL)
+    type = TREE_TYPE (type);
+
+  /* When we see [:T:] or [:T:]<arg> we don't know what it'll turn out
+     to be.  */
+  if (dependent_splice_p (type))
+    return make_splice_scope (type, /*type_p=*/true);
+
+  if (!valid_splice_type_p (type))
+    {
+      if (!cp_parser_simulate_error (parser))
+       error_at (loc, "reflection %qE not usable in a splice type", type);
+      type = NULL_TREE;
+    }
+
+  return type;
+}
+
+/* Parse a splice-expression.
+
+   splice-expression:
+     splice-specifier
+     template splice-specifier
+     template splice-specialization-specifier
+
+   TEMPLATE_P is true if we've parsed the leading template keyword.
+   ADDRESS_P is true if we are taking the address of the splice.
+   TEMPLATE_ARG_P is true iff this splice is a template argument.
+   MEMBER_ACCESS_P is true if this splice is used in foo.[: bar :] or
+   foo->[: bar :] context.  */
+
+static tree
+cp_parser_splice_expression (cp_parser *parser, bool template_p,
+                            bool address_p, bool template_arg_p,
+                            bool member_access_p, cp_id_kind *idk)
+{
+  bool targs_p = false;
+
+  /* E.g., [: X::x :] is a separate lookup and we shouldn't take into
+     account any previous scopes.  */
+  parser->scope = NULL_TREE;
+  parser->object_scope = NULL_TREE;
+  parser->qualifying_scope = NULL_TREE;
+
+  cp_expr expr = cp_parser_splice_specifier (parser, template_p, &targs_p);
+
+  /* And don't leave the scopes set, either.  */
+  parser->scope = NULL_TREE;
+  parser->object_scope = NULL_TREE;
+  parser->qualifying_scope = NULL_TREE;
+
+  const location_t loc = expr.get_location ();
+  tree t = expr.get_value ();
+  STRIP_ANY_LOCATION_WRAPPER (t);
+  tree unresolved = t;
+  t = MAYBE_BASELINK_FUNCTIONS (t);
+  t = resolve_nondeduced_context (t, tf_warning_or_error);
+
+  if (dependent_splice_p (t))
+    {
+      SET_SPLICE_EXPR_EXPRESSION_P (t);
+      SET_SPLICE_EXPR_MEMBER_ACCESS_P (t, member_access_p);
+      SET_SPLICE_EXPR_ADDRESS_P (t, address_p);
+    }
+
+  if (error_operand_p (t))
+    {
+      gcc_assert (seen_error ());
+      return error_mark_node;
+    }
+
+  if (template_p)
+    {
+      /* [expr.prim.splice] For a splice-expression of the form template
+        splice-specifier, the splice-specifier shall designate a function
+        template.  */
+      if (!targs_p)
+       {
+         if (!really_overloaded_fn (t) && !dependent_splice_p (t))
+           {
+             auto_diagnostic_group d;
+             error_at (loc, "reflection %qE not usable in a template splice",
+                       t);
+             inform (loc, "only function templates are allowed here");
+             return error_mark_node;
+           }
+       }
+      /* [expr.prim.splice] For a splice-expression of the form
+        template splice-specialization-specifier, the splice-specifier of the
+        splice-specialization-specifier shall designate a template.  */
+      else
+       {
+         if (really_overloaded_fn (t)
+             || get_template_info (t)
+             || TREE_CODE (t) == TEMPLATE_ID_EXPR)
+           /* OK */;
+         else
+           {
+             auto_diagnostic_group d;
+             error_at (loc, "reflection %qE not usable in a template splice",
+                       t);
+             inform (loc, "only templates are allowed here");
+             return error_mark_node;
+           }
+       }
+    }
+  else if (/* No 'template' but there were template arguments?  */
+          targs_p
+          /* No 'template' but the splice-specifier designates a template?  */
+          || really_overloaded_fn (t))
+    {
+      auto_diagnostic_group d;
+      if (targs_p)
+       error_at (loc, "reflection %qE not usable in a splice expression with "
+                 "template arguments", t);
+      else
+       error_at (loc, "reflection %qE not usable in a splice expression", t);
+      location_t sloc = expr.get_start ();
+      rich_location richloc (line_table, sloc);
+      richloc.add_fixit_insert_before (sloc, "template ");
+      inform (&richloc, "add %<template%> to denote a template");
+      return error_mark_node;
+    }
+
+  if (parser->in_template_argument_list_p
+      && !parser->greater_than_is_operator_p)
+    {
+      error_at (loc, "unparenthesized splice expression cannot be used as "
+               "a template argument");
+      return error_mark_node;
+    }
+
+  /* Make sure this splice-expression produces an expression.  */
+  if (!check_splice_expr (loc, expr.get_start (), t, address_p,
+                         member_access_p, /*complain=*/true))
+    return error_mark_node;
+
+  /* When doing foo.[: bar :], cp_parser_postfix_dot_deref_expression wants
+     to see an identifier or a TEMPLATE_ID_EXPR, if we have something like
+     s.template [: ^^S::var :]<int> where S::var is a variable template.  */
+  if (member_access_p)
+    {
+      /* Grab the unresolved expression then.  */
+      t = unresolved;
+      gcc_assert (TREE_CODE (t) == FIELD_DECL
+                 || VAR_P (t)
+                 || TREE_CODE (t) == CONST_DECL
+                 || TREE_CODE (t) == FUNCTION_DECL
+                 || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (t))
+                 || variable_template_p (t)
+                 || BASELINK_P (t)
+                 || TREE_CODE (t) == SPLICE_EXPR
+                 || TREE_CODE (t) == TEMPLATE_ID_EXPR
+                 || TREE_CODE (t) == TREE_BINFO);
+      /* ??? We're not setting *idk here.  */
+    }
+  else
+    {
+      /* We may have to instantiate; for instance, if we're dealing with
+        a variable template.  For &[: ^^S::x :], we have to create an
+        OFFSET_REF.  For a VAR_DECL, we need the convert_from_reference.  */
+      cp_unevaluated u;
+      /* CWG 3109 adjusted [class.protected] to say that checking access to
+        protected non-static members is disabled for members designated by a
+        splice-expression.  */
+      push_deferring_access_checks (dk_no_check);
+      const char *error_msg;
+      /* We don't have the parser scope here, so figure out the context.  In
+          struct S { static constexpr int i = 42; };
+          constexpr auto r = ^^S::i;
+          int i = [: r :];
+        we need to pass down 'S'.  */
+      tree ctx = DECL_P (t) ? DECL_CONTEXT (t) : NULL_TREE;
+      t = finish_id_expression (t, t, ctx, idk,
+                               /*integral_constant_expression_p=*/false,
+                               /*allow_non_integral_constant_expr_p=*/true,
+                               &parser->non_integral_constant_expression_p,
+                               template_p,
+                               /*done=*/true,
+                               address_p,
+                               template_arg_p,
+                               &error_msg,
+                               loc);
+      if (error_msg)
+       cp_parser_error (parser, error_msg);
+      pop_deferring_access_checks ();
+    }
+
+  return t;
+}
+
+/* Parse a splice-scope-specifier.
+
+   splice-scope-specifier:
+     splice-specifier
+     template[opt] splice-specialization-specifier
+
+   TYPENAME_P is true if we've seen the typename keyword.
+   TEMPLATE_P is true if we've seen the leading template keyword.  */
+
+static tree
+cp_parser_splice_scope_specifier (cp_parser *parser, bool typename_p,
+                                 bool template_p)
+{
+  bool targs_p = false;
+  cp_expr scope = cp_parser_splice_specifier (parser, template_p, &targs_p);
+  const location_t loc = scope.get_location ();
+  if (TREE_CODE (scope) == TYPE_DECL)
+    scope = TREE_TYPE (scope);
+
+  if (template_p && !targs_p)
+    {
+      error_at (loc, "extra %<template%> in a scope splice");
+      return error_mark_node;
+    }
+  /* [expr.prim.id.qual] The template may only be omitted from the
+     form template(opt) splice-specialization-specifier :: when the
+     splice-specialization-specifier is preceded by typename.  */
+  if (targs_p && !typename_p && !template_p)
+    {
+      auto_diagnostic_group d;
+      error_at (loc, "missing %<template%> in a scope splice with template "
+               "arguments");
+      inform (loc, "%<template%> may only be omitted when the scope splice "
+             "is preceded by %<typename%>");
+      return error_mark_node;
+    }
+
+  /* A dependent scope.  Turn this into SPLICE_SCOPE which is a type,
+     so that dependent_scope_p et al can recognize this.  */
+  if (dependent_splice_p (scope))
+    return make_splice_scope (scope, /*type_p=*/false);
+
+  if (!valid_splice_scope_p (scope))
+    {
+      auto_diagnostic_group d;
+      error_at (loc, "reflection not usable in a splice scope");
+      if (TYPE_P (scope))
+       inform (loc, "%qT is not a class, namespace, or enumeration",
+               tree (scope));
+      else
+       inform (loc, "%qE is not a class, namespace, or enumeration",
+               tree (scope));
+      scope = error_mark_node;
+    }
+
+  return scope;
+}
+
+/* We know the next token is '[:' (optionally preceded by a template or
+   typename) and we are wondering if a '::' follows right after the
+   closing ':]', or after the possible '<...>' after the ':]'.  Return
+   true if yes, false otherwise.  */
+
+static bool
+cp_parser_splice_spec_is_nns_p (cp_parser *parser)
+{
+  /* ??? It'd be nice to use saved_token_sentinel, but its rollback
+     uses cp_lexer_previous_token, but we may be the first token in the
+     file so there are no previous tokens.  Sigh.  */
+  cp_lexer_save_tokens (parser->lexer);
+
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME)
+      || cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+    cp_lexer_consume_token (parser->lexer);
+
+  bool ok = false;
+  size_t n = cp_parser_skip_balanced_tokens (parser, 1);
+  if (n != 1)
+    {
+      ok = true;
+      /* Consume tokens up to the ':]' (including).  */
+      for (n = n - 1; n; --n)
+       cp_lexer_consume_token (parser->lexer);
+
+      /* Consume the whole '<....>', if present.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)
+         && !cp_parser_skip_entire_template_parameter_list (parser))
+       ok = false;
+
+      ok = ok && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE);
+    }
+
+  /* Roll back the tokens we skipped.  */
+  cp_lexer_rollback_tokens (parser->lexer);
+
+  return ok;
+}
+
+/* Return true if the N-th token is '[:' and its closing ':]' is NOT
+   followed by a '::'.  For example, we could be checking if what follows
+   can be a splice-expression or not -- we can tell that '[:R:]::type' is
+   not a splice-expression.  */
+
+static bool
+cp_parser_nth_token_starts_splice_without_nns_p (cp_parser *parser, size_t n)
+{
+  return (cp_lexer_nth_token_is (parser->lexer, n, CPP_OPEN_SPLICE)
+         && !cp_parser_splice_spec_is_nns_p (parser));
+}
+
 /* Parse a primary-expression.
 
    primary-expression:
@@ -6066,6 +6510,9 @@ cp_parser_pack_index (cp_parser *parser, tree pack)
      ( expression )
      id-expression
      lambda-expression (C++11)
+     fold-expression
+     requires-expression
+     splice-expression
 
    GNU Extensions:
 
@@ -6349,6 +6796,11 @@ cp_parser_primary_expression (cp_parser *parser,
        return lam;
       }
 
+    case CPP_OPEN_SPLICE:
+      return cp_parser_splice_expression (parser, /*template_p=*/false,
+                                         address_p, template_arg_p,
+                                         /*member_access_p=*/false, idk);
+
     case CPP_OBJC_STRING:
       if (c_dialect_objc ())
        /* We have an Objective-C++ string literal. */
@@ -6505,13 +6957,23 @@ cp_parser_primary_expression (cp_parser *parser,
        case RID_TEMPLATE:
          if (parser->in_function_body
              && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
-                 == CPP_LESS))
+                 == CPP_LESS))
            {
              error_at (token->location,
                        "a template declaration cannot appear at block scope");
              cp_parser_skip_to_end_of_block_or_statement (parser);
              return error_mark_node;
            }
+         else if (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+                  == CPP_OPEN_SPLICE)
+           {
+             cp_lexer_consume_token (parser->lexer);
+             return cp_parser_splice_expression (parser, /*template_p=*/true,
+                                                 address_p, template_arg_p,
+                                                 /*member_access_p=*/false,
+                                                 idk);
+           }
+
          /* FALLTHRU */
        default:
          cp_parser_error (parser, "expected primary-expression");
@@ -6701,6 +7163,16 @@ cp_parser_primary_expression (cp_parser *parser,
        return decl;
       }
 
+    case CPP_XOR:
+      if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_XOR)
+       {
+         error_at (token->location,
+                   "reflection is only available in C++26 with "
+                   "%<-freflection%>");
+         return error_mark_node;
+       }
+      gcc_fallthrough ();
+
       /* Anything else is an error.  */
     default:
       cp_parser_error (parser, "expected primary-expression");
@@ -7168,6 +7640,20 @@ cp_parser_unqualified_id (cp_parser* parser,
            if (cp_parser_parse_definitely (parser))
              done = true;
          }
+       /* Allow r.~typename [:R:].  */
+       else if (!done
+                && cp_parser_next_tokens_start_splice_type_spec_p
+                    (parser, /*require_typename_p=*/true))
+         {
+           parser->scope = object_scope;
+           parser->object_scope = NULL_TREE;
+           parser->qualifying_scope = NULL_TREE;
+           type_decl = cp_parser_splice_type_specifier (parser);
+           if (!type_decl)
+             /* We don't have a TYPE_DECL, so return early.  */
+             return error_mark_node;
+           return build_min_nt_loc (loc, BIT_NOT_EXPR, type_decl);
+         }
        /* Look in the surrounding context.  */
        if (!done)
          {
@@ -7315,6 +7801,7 @@ check_template_keyword_in_nested_name_spec (tree name)
      type-name ::
      namespace-name ::
      computed-type-specifier ::
+     splice-scope-specifier ::
      nested-name-specifier identifier ::
      nested-name-specifier template [opt] simple-template-id ::
 
@@ -7402,6 +7889,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
       /* DR 743: decltype can be used in a nested-name-specifier.  */
       else if (token_is_decltype (token))
        ;
+      /* Could be a splice-scope-specifier.  */
+      else if (cp_parser_next_tokens_can_start_splice_scope_spec_p (parser))
+       ;
       else
        {
          /* If the next token is not an identifier, then it is
@@ -7779,6 +8269,23 @@ cp_parser_qualifying_entity (cp_parser *parser,
       return scope;
     }
 
+  /* In a nested-name-specifier, we can reach a splice-specifier
+     either via the computed-type-specifier -> splice-type-specifier
+     production, or via splice-scope-specifier.  But [dcl.type.splice]
+     says "A splice-specifier or splice-specialization-specifier immediately
+     followed by :: is never interpreted as part of a splice-type-specifier"
+     so we call only cp_parser_splice_scope_specifier.  */
+  if (cp_parser_next_tokens_can_start_splice_scope_spec_p (parser)
+      && cp_parser_splice_spec_is_nns_p (parser))
+    {
+      if (cp_parser_optional_template_keyword (parser))
+       template_keyword_p = true;
+      scope = cp_parser_splice_scope_specifier (parser,
+                                               typename_keyword_p,
+                                               template_keyword_p);
+      return scope;
+    }
+
   /* Before we try to parse the class-name, we must save away the
      current PARSER->SCOPE since cp_parser_class_name will destroy
      it.  */
@@ -7872,6 +8379,8 @@ literal_integer_zerop (const_tree expr)
      postfix-expression -> template [opt] id-expression
      postfix-expression . pseudo-destructor-name
      postfix-expression -> pseudo-destructor-name
+     postfix-expression . splice-expression
+     postfix-expression -> splice-expression
      postfix-expression ++
      postfix-expression --
      dynamic_cast < type-id > ( expression )
@@ -8076,6 +8585,12 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 
     case RID_TYPENAME:
       {
+       /* Just like cp_parser_type_specifier/RID_TYPENAME: if we see
+          'typename [:', this could be a typename-specifier.  But if
+          there's no '::' after the '[:x:]' then it is not.  */
+       if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 2))
+         goto default_;
+
        tree type;
        /* The syntax permitted here is the same permitted for an
           elaborated-type-specifier.  */
@@ -8277,6 +8792,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
       }
 
     default:
+    default_:
       {
        tree type;
 
@@ -8624,7 +9140,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
          /* postfix-expression . template [opt] id-expression
             postfix-expression . pseudo-destructor-name
             postfix-expression -> template [opt] id-expression
-            postfix-expression -> pseudo-destructor-name */
+            postfix-expression -> pseudo-destructor-name
+            postfix-expression . splice-expression
+            postfix-expression -> splice-expression  */
 
          /* Consume the `.' or `->' operator.  */
          cp_lexer_consume_token (parser->lexer);
@@ -8984,6 +9502,8 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
      postfix-expression . pseudo-destructor-name
      postfix-expression -> template [opt] id-expression
      postfix-expression -> pseudo-destructor-name
+     postfix-expression . splice-expression
+     postfix-expression -> splice-expression
 
    FOR_OFFSETOF is set if we're being called in that context.  That sorta
    limits what of the above we'll actually accept, but nevermind.
@@ -9108,15 +9628,32 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
         ordinary class member access expression, rather than a
         pseudo-destructor-name.  */
       bool template_p;
+      bool template_keyword_p = cp_parser_optional_template_keyword (parser);
       cp_token *token = cp_lexer_peek_token (parser->lexer);
-      /* Parse the id-expression.  */
-      name = (cp_parser_id_expression
-             (parser,
-              cp_parser_optional_template_keyword (parser),
-              /*check_dependency_p=*/true,
-              &template_p,
-              /*declarator_p=*/false,
-              /*optional_p=*/false));
+      /* See if there was this->[:R:].  Note that in this->[: ^^S :]::i;
+        the RHS is not a splice-expression.  */
+      const bool splice_p
+       = cp_parser_nth_token_starts_splice_without_nns_p (parser, 1);
+      if (splice_p)
+       {
+         name = cp_parser_splice_expression (parser, template_keyword_p,
+                                             /*address_p=*/false,
+                                             /*template_arg_p=*/false,
+                                             /*member_access_p=*/true, idk);
+         /* This is not the leading 'template' but the one after n-n-s,
+            which we don't have here.  */
+         template_p = false;
+       }
+      else
+       /* Parse the id-expression.  */
+       name = (cp_parser_id_expression
+               (parser,
+                template_keyword_p,
+                /*check_dependency_p=*/true,
+                &template_p,
+                /*declarator_p=*/false,
+                /*optional_p=*/false));
+
       /* In general, build a SCOPE_REF if the member name is qualified.
         However, if the name was not dependent and has already been
         resolved; there is no need to build the SCOPE_REF.  For example;
@@ -9125,10 +9662,16 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
             template <typename T> void f(T* t) { t->X::f(); }
 
         Even though "t" is dependent, "X::f" is not and has been resolved
-        to a BASELINK; there is no need to include scope information.  */
+        to a BASELINK; there is no need to include scope information.
 
-      /* But we do need to remember that there was an explicit scope for
-        virtual function calls.  */
+        But we do need to remember that there was an explicit scope for
+        virtual function calls.  If the name was represented by
+        a splice-expression, behave like this:
+
+          [:^^B::fn:]()  // do not disable virtual dispatch
+          [:^^B:]::fn()  // disable virtual dispatch
+
+        In the former, parser->scope has been cleared when we get here.  */
       if (parser->scope)
        *idk = CP_ID_KIND_QUALIFIED;
 
@@ -9149,6 +9692,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
                            parser->scope, name);
                  postfix_expression = error_mark_node;
                }
+             /* cp_parser_splice_expression may have given us a SCOPE_REF.  */
+             else if (TREE_CODE (name) == SCOPE_REF
+                      || TREE_CODE (name) == FIELD_DECL
+                      || VAR_P (name)
+                      || TREE_CODE (name) == CONST_DECL
+                      || TREE_CODE (name) == FUNCTION_DECL
+                      || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name)))
+               gcc_checking_assert (splice_p);
              else
                name = build_qualified_name (/*type=*/NULL_TREE,
                                             parser->scope,
@@ -9158,13 +9709,19 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
              parser->qualifying_scope = NULL_TREE;
              parser->object_scope = NULL_TREE;
            }
-         if (parser->scope && name && BASELINK_P (name))
+         if ((parser->scope || splice_p) && name && BASELINK_P (name))
            adjust_result_of_qualified_name_lookup
-             (name, parser->scope, scope);
+             (name,
+              /* For obj->[:^^R:] we won't have parser->scope, but we still
+                 have to perform this adjustment.  */
+              (splice_p
+               ? BINFO_TYPE (BASELINK_ACCESS_BINFO (name))
+               : parser->scope),
+              scope);
          postfix_expression
            = finish_class_member_access_expr (postfix_expression, name,
                                               template_p,
-                                              tf_warning_or_error);
+                                              tf_warning_or_error, splice_p);
          /* Build a location e.g.:
               ptr->access_expr
               ~~~^~~~~~~~~~~~~
@@ -9454,6 +10011,168 @@ cp_parser_pseudo_destructor_name (cp_parser* parser,
   *type = TREE_TYPE (cp_parser_nonclass_name (parser));
 }
 
+/* Parse a reflection-name.
+
+   reflection-name:
+    nested-name-specifier[opt] identifier
+    nested-name-specifier template identifier
+
+ */
+
+static tree
+cp_parser_reflection_name (cp_parser *parser)
+{
+  auto s = make_temp_override (cp_preserve_using_decl, true);
+
+  /* Look for the optional `::' operator.  */
+  bool global_scope_p
+    = (cp_parser_global_scope_opt (parser,
+                                  /*current_scope_valid_p=*/false)
+       != NULL_TREE);
+  /* And the optional nested-name-specifier.  */
+  bool nested_name_specifier_p
+    = (cp_parser_nested_name_specifier_opt (parser,
+                                           /*typename_keyword_p=*/false,
+                                           /*check_dependency_p=*/true,
+                                           /*type_p=*/false,
+                                           /*is_declaration=*/false,
+                                           /*template_keyword_p=*/false,
+                                           global_scope_p)
+       != NULL_TREE);
+  /* Look for the optional `template' keyword.  */
+  if (cp_parser_optional_template_keyword (parser)
+      && !global_scope_p
+      && !nested_name_specifier_p)
+    cp_parser_error (parser, "%<template%> must follow a nested-name-"
+                    "specifier");
+
+  /* Look for the identifier.  */
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+  tree name = cp_parser_identifier (parser);
+  tree decl = cp_parser_lookup_name_simple (parser, name, loc);
+  if (name != error_mark_node && decl == error_mark_node)
+    cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, loc);
+
+  /* If lookup finds a class member of an anonymous union, R represents
+     that class member.  */
+  if (VAR_P (decl) && DECL_ANON_UNION_VAR_P (decl))
+    {
+      tree v = DECL_VALUE_EXPR (decl);
+      if (v != error_mark_node && TREE_CODE (v) == COMPONENT_REF)
+       decl = TREE_OPERAND (v, 1);
+    }
+
+  return decl;
+}
+
+/* Parse a reflect-expression.
+
+   reflect-expression:
+     ^^ ::
+     ^^ reflection-name
+     ^^ type-id
+     ^^ id-expression
+
+  Returns a representation of the reflection.  */
+
+static tree
+cp_parser_reflect_expression (cp_parser *parser)
+{
+  if (!flag_reflection)
+    {
+      error_at (cp_lexer_peek_token (parser->lexer)->location,
+               "reflection is only available with %<-freflection%>");
+      return error_mark_node;
+    }
+
+  /* Consume the '^^'.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* Get the location of the operand.  */
+  const location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  /* We don't know what this might be.  Try and see what works.  */
+  cp_parser_parse_tentatively (parser);
+  tree t = cp_parser_reflection_name (parser);
+  if (TREE_CODE (t) == TYPE_DECL && !cp_parser_error_occurred (parser))
+    /* Need to call cp_parser_type_id, because say
+       using A = int;
+       ^^A &
+       should parse the type id rather than reflection-name.  */
+    cp_parser_simulate_error (parser);
+  /* For ^^tmpl<args>, looking for a nested-name-specifier in
+     cp_parser_reflection_name above creates a CPP_TEMPLATE_ID which
+     makes cp_parser_identifier cause a parser error.  So we don't
+     return early here.  */
+  if (cp_parser_parse_definitely (parser))
+    return get_reflection (loc, t);
+  /* Nope.  Well then, maybe it's a type-id.  */
+  cp_parser_parse_tentatively (parser);
+
+  bool type_alias_p;
+  t = cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_NONE, false, false,
+                          nullptr, &type_alias_p);
+  if (cp_parser_parse_definitely (parser))
+    {
+      /* With using A = int; ^^A is a type alias but ^^const A or ^^A & or
+        ^^A const is not.  With template<typename T> using B = C <T>;
+        ^^B <int> is a type alias though.  */
+      if (TYPE_P (t) && !type_alias_p)
+       t = strip_typedefs (t);
+      return get_reflection (loc, t);
+    }
+  /* Try an id-expression.  */
+  {
+    cp_parser_parse_tentatively (parser);
+    /* [expr.reflect] The id-expression of a reflect-expression is
+       an unevaluated operand.  */
+    cp_unevaluated u;
+    tree id = cp_parser_id_expression (parser,
+                                      /*template_keyword_p=*/false,
+                                      /*check_dependency_p=*/true,
+                                      /*template_p=*/nullptr,
+                                      /*declarator_p=*/false,
+                                      /*optional_p=*/false);
+    /* Lookup the name we got back from the id-expression.  */
+    if (identifier_p (id))
+      t = cp_parser_lookup_name_simple (parser, id, loc);
+    else
+      t = id;
+    /* We couldn't look ID up, harrumph.  */
+    if (id != error_mark_node && t == error_mark_node)
+      cp_parser_name_lookup_error (parser, id, t, NLE_NULL, loc);
+    /* We don't finish_id_expression here because we don't know in what
+       context this reflection will be used (address, class member access,
+       template argument, ...).  Except go ahead and (try to) resolve the
+       variable TEMPLATE_ID_EXPR (which is always considered type-dependent
+       because such TEMPLATE_ID_EXPRs don't have a type) now.  We don't need
+       to keep these TEMPLATE_ID_EXPRs for a possible class member access,
+       but most importantly, function templates with ^^vt<int> as one of its
+       template argument would never be mangled (mangle_decl checks if any
+       template arguments are dependent).  */
+    if (TREE_CODE (t) == TEMPLATE_ID_EXPR
+       && variable_template_p (TREE_OPERAND (t, 0))
+       && !concept_check_p (t))
+      t = finish_template_variable (t);
+    if (cp_parser_parse_definitely (parser))
+      return get_reflection (loc, t);
+  }
+
+  /* Last chance, see if there's ^^::.  This must be done only after we've
+     tried the other options.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
+    {
+      cp_lexer_consume_token (parser->lexer);
+      /* A reflect-expression of the form ^^:: represents the global
+        namespace.  */
+      return get_reflection (loc, global_namespace);
+    }
+
+  /* Oy vey, nothing worked.  */
+  error_at (loc, "%<^^%> cannot be applied to this operand");
+  return error_mark_node;
+}
+
 /* Parse a unary-expression.
 
    unary-expression:
@@ -9464,9 +10183,10 @@ cp_parser_pseudo_destructor_name (cp_parser* parser,
      unary-operator cast-expression
      sizeof unary-expression
      sizeof ( type-id )
-     alignof ( type-id )  [C++0x]
+     alignof ( type-id )  [C++11]
      new-expression
      delete-expression
+     reflect-expression        [C++26]
 
    GNU Extensions:
 
@@ -9730,6 +10450,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
       else if (keyword == RID_DELETE)
        return cp_parser_delete_expression (parser);
     }
+  else if (cp_lexer_next_token_is (parser->lexer, CPP_REFLECT_OP))
+    return cp_parser_reflect_expression (parser);
 
   /* Look for a unary operator.  */
   unary_operator = cp_parser_unary_operator (token);
@@ -16801,6 +17523,12 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
       /* `template <' indicates a template declaration.  */
       else if (token2->type == CPP_LESS)
        cp_parser_template_declaration (parser, /*member_p=*/false);
+      /* We can have
+          template [: ^^T :]<3>::type t = 4;
+        where the template binds to the splice-scope-specifier.  */
+      else if (token2->type == CPP_OPEN_SPLICE
+              && cp_parser_splice_spec_is_nns_p (parser))
+       cp_parser_block_declaration (parser, /*statement_p=*/false);
       /* Anything else must be an explicit instantiation.  */
       else
        {
@@ -17491,6 +18219,8 @@ cp_parser_decomposition_declaration (cp_parser *parser,
              attr = NULL_TREE;
            if (attr && first_attr == -1)
              first_attr = v.length ();
+           if (lookup_attribute ("internal ", "annotation ", attr))
+             error ("annotation on structured binding");
          }
        v.safe_push (e);
        ++cnt;
@@ -18569,9 +19299,22 @@ cp_parser_decltype_expr (cp_parser *parser,
          expression.  */
       cp_parser_abort_tentative_parse (parser);
 
-      /* Parse a full expression.  */
-      expr = cp_parser_expression (parser, /*pidk=*/NULL, /*cast_p=*/false,
-                                  /*decltype_p=*/true);
+      /* [dcl.type.decltype] "if E is an unparenthesized splice-expression,
+        decltype(E) is the type of the entity, object, or value designated
+        by the splice-specifier of E"  */
+      if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
+       {
+         cp_id_kind idk;
+         expr = cp_parser_splice_expression (parser, /*template_p=*/false,
+                                             /*address_p=*/false,
+                                             /*template_arg_p=*/false,
+                                             /*member_access_p=*/false, &idk);
+         id_expression_or_member_access_p = true;
+       }
+      else
+       /* Parse a full expression.  */
+       expr = cp_parser_expression (parser, /*pidk=*/NULL, /*cast_p=*/false,
+                                    /*decltype_p=*/true);
     }
 
   return expr;
@@ -20243,6 +20986,9 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
    of functions, returns a TEMPLATE_ID_EXPR.  If the template-name
    names a class, returns a TYPE_DECL for the specialization.
 
+   PARSED_TEMPL, if non-null, is the already parsed template-name.  This
+   is used when parsing a splice-specialization-specifier.
+
    If CHECK_DEPENDENCY_P is FALSE, names are looked up in
    uninstantiated templates.  */
 
@@ -20251,7 +20997,8 @@ cp_parser_template_id (cp_parser *parser,
                       bool template_keyword_p,
                       bool check_dependency_p,
                       enum tag_types tag_type,
-                      bool is_declaration)
+                      bool is_declaration,
+                      tree parsed_templ/*=NULL_TREE*/)
 {
   tree templ;
   tree arguments;
@@ -20272,28 +21019,32 @@ cp_parser_template_id (cp_parser *parser,
 
   /* Avoid performing name lookup if there is no possibility of
      finding a template-id.  */
-  if ((token->type != CPP_NAME && token->keyword != RID_OPERATOR)
-      || (token->type == CPP_NAME
-         && !cp_parser_nth_token_starts_template_argument_list_p
-              (parser, 2)))
+  if (!parsed_templ
+      && ((token->type != CPP_NAME && token->keyword != RID_OPERATOR)
+         || (token->type == CPP_NAME
+             && !cp_parser_nth_token_starts_template_argument_list_p
+                  (parser, 2))))
     {
       cp_parser_error (parser, "expected template-id");
       return error_mark_node;
     }
 
   /* Remember where the template-id starts.  */
-  if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+  if (!parsed_templ && cp_parser_uncommitted_to_tentative_parse_p (parser))
     start_of_id = cp_lexer_token_position (parser->lexer, false);
 
   push_deferring_access_checks (dk_deferred);
 
   /* Parse the template-name.  */
   is_identifier = false;
-  templ = cp_parser_template_name (parser, template_keyword_p,
-                                  check_dependency_p,
-                                  is_declaration,
-                                  tag_type,
-                                  &is_identifier);
+  if (parsed_templ)
+    templ = parsed_templ;
+  else
+    templ = cp_parser_template_name (parser, template_keyword_p,
+                                    check_dependency_p,
+                                    is_declaration,
+                                    tag_type,
+                                    &is_identifier);
 
   /* Push any access checks inside the firewall we're about to create.  */
   vec<deferred_access_check, va_gc> *checks = get_deferred_access_checks ();
@@ -20415,7 +21166,9 @@ cp_parser_template_id (cp_parser *parser,
     = make_location (token->location, token->location, parser->lexer);
 
   /* Build a representation of the specialization.  */
-  if (identifier_p (templ))
+  if (identifier_p (templ)
+      /* We can't do much with [:T:]<arg> at this point.  */
+      || TREE_CODE (templ) == SPLICE_EXPR)
     template_id = build_min_nt_loc (combined_loc,
                                    TEMPLATE_ID_EXPR,
                                    templ, arguments);
@@ -20465,7 +21218,20 @@ cp_parser_template_id (cp_parser *parser,
     {
       /* If it's not a class-template or a template-template, it should be
         a function-template.  */
-      gcc_assert (OVL_P (templ) || BASELINK_P (templ));
+      if (OVL_P (templ) || BASELINK_P (templ))
+       /* It is.  */;
+      else if (parsed_templ)
+       {
+         /* This means there was a splice-specifier.  Maybe the user
+            used the wrong reflection, so complain.  */
+         if (TYPE_P (templ))
+           error_at (token->location, "%qT is not a template", templ);
+         else
+           error_at (token->location, "%qE is not a template", templ);
+         return error_mark_node;
+       }
+      else
+       gcc_assert (false);
 
       template_id = lookup_template_function (templ, arguments);
       if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR)
@@ -21496,6 +22262,13 @@ cp_parser_type_specifier (cp_parser* parser,
 
       /* Fall through.  */
     case RID_TYPENAME:
+      /* If we see 'typename [:', this could be a typename-specifier.
+        But if there's no '::' after the '[:x:]' then it is probably
+        a simple-type-specifier.  */
+      if (keyword == RID_TYPENAME
+         && cp_parser_nth_token_starts_splice_without_nns_p (parser, 2))
+       break;
+
       /* Look for an elaborated-type-specifier.  */
       type_spec
        = (cp_parser_elaborated_type_specifier
@@ -21594,6 +22367,15 @@ cp_parser_type_specifier (cp_parser* parser,
 
      nested-name-specifier(opt) template-name
 
+   computed-type-specifier:
+     decltype-specifier
+     pack-index-specifier
+     splice-type-specifier
+
+   splice-type-specifier:
+     typename[opt] splice-specifier
+     typename[opt] splice-specialization-specifier
+
    GNU Extension:
 
    simple-type-specifier:
@@ -21961,6 +22743,15 @@ cp_parser_simple_type_specifier (cp_parser* parser,
            type = NULL_TREE;
        }
 
+      /* "[: ... :]" is a C++26 splice-type-specifier.  The second argument
+        decides if we require 'typename' before the splice-type-specifier.
+        In a type-only context ([temp.res.general]/4) we shouldn't require
+        it.  */
+      if (!type
+         && cp_parser_next_tokens_start_splice_type_spec_p (parser,
+                                                            !typename_p))
+       type = cp_parser_splice_type_specifier (parser);
+
       /* Otherwise, look for a type-name.  */
       if (!type)
        {
@@ -23137,6 +23928,7 @@ cp_parser_enum_specifier (cp_parser* parser)
        {
          new_value_list = true;
          SET_OPAQUE_ENUM_P (type, false);
+         ENUM_BEING_DEFINED_P (type) = 1;
          DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
        }
       else
@@ -23545,7 +24337,8 @@ cp_parser_namespace_body (cp_parser* parser)
 /* Parse a namespace-alias-definition.
 
    namespace-alias-definition:
-     namespace identifier = qualified-namespace-specifier ;  */
+     namespace identifier = qualified-namespace-specifier
+     namespace identifier = splice-specifier  */
 
 static void
 cp_parser_namespace_alias_definition (cp_parser* parser)
@@ -23574,10 +24367,13 @@ cp_parser_namespace_alias_definition (cp_parser* parser)
       return;
     }
   cp_parser_require (parser, CPP_EQ, RT_EQ);
-  /* Look for the qualified-namespace-specifier.  */
-  namespace_specifier
-    = cp_parser_qualified_namespace_specifier (parser);
-  cp_warn_deprecated_use_scopes (namespace_specifier);
+  if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
+    namespace_specifier = cp_parser_splice_specifier (parser);
+  else
+    /* Look for the qualified-namespace-specifier.  */
+    namespace_specifier = cp_parser_qualified_namespace_specifier (parser);
+  if (!dependent_namespace_p (namespace_specifier))
+    cp_warn_deprecated_use_scopes (namespace_specifier);
   /* Look for the `;' token.  */
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
@@ -24039,8 +24835,9 @@ cp_parser_alias_declaration (cp_parser* parser)
 /* Parse a using-directive.
 
    using-directive:
-     attribute-specifier-seq [opt] using namespace :: [opt]
-       nested-name-specifier [opt] namespace-name ;  */
+     attribute-specifier-seq [opt] using namespace nested-name-specifier [opt]
+       namespace-name ;
+     attribute-specifier-seq [opt] using namespace splice-specifier ;  */
 
 static void
 cp_parser_using_directive (cp_parser* parser)
@@ -24059,16 +24856,21 @@ cp_parser_using_directive (cp_parser* parser)
   cp_parser_require_keyword (parser, RID_USING, RT_USING);
   /* And the `namespace' keyword.  */
   cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
-  /* Look for the optional `::' operator.  */
-  cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
-  /* And the optional nested-name-specifier.  */
-  cp_parser_nested_name_specifier_opt (parser,
-                                      /*typename_keyword_p=*/false,
-                                      /*check_dependency_p=*/true,
-                                      /*type_p=*/false,
-                                      /*is_declaration=*/true);
-  /* Get the namespace being used.  */
-  namespace_decl = cp_parser_namespace_name (parser);
+  if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
+    namespace_decl = cp_parser_splice_specifier (parser);
+  else
+    {
+      /* Look for the optional `::' operator.  */
+      cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
+      /* And the optional nested-name-specifier.  */
+      cp_parser_nested_name_specifier_opt (parser,
+                                          /*typename_keyword_p=*/false,
+                                          /*check_dependency_p=*/true,
+                                          /*type_p=*/false,
+                                          /*is_declaration=*/true);
+      /* Get the namespace being used.  */
+      namespace_decl = cp_parser_namespace_name (parser);
+    }
   cp_warn_deprecated_use_scopes (namespace_decl);
   /* And any specified GNU attributes.  */
   if (cp_next_tokens_can_be_gnu_attribute_p (parser))
@@ -26827,15 +27629,25 @@ cp_parser_declarator_id (cp_parser* parser, bool optional_p)
    If IS_TRAILING_RETURN is true, we are in a trailing-return-type,
    i.e. we've just seen "->".
 
+   If TYPE_ALIAS_P is non-null, we set it to true or false depending
+   on if the type-id is a type alias or just a type.  E.g., given
+
+     template<typename> struct S {};
+     template<typename T> using A = const S<T>;
+
+   ^^A<int> is a type alias, but ^^const A<int>, ^^A<int> const, or ^^A<int>*
+   are just types, not type aliases.
+
    Returns the TYPE specified.  */
 
 static tree
 cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
                     bool is_template_arg, bool is_trailing_return,
-                    location_t *type_location)
+                    location_t *type_location, bool *type_alias_p)
 {
   cp_decl_specifier_seq type_specifier_seq;
   cp_declarator *abstract_declarator;
+  cp_token *next = nullptr;
 
   /* Parse the type-specifier-seq.  */
   cp_parser_type_specifier_seq (parser, flags,
@@ -26845,6 +27657,17 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
   if (type_location)
     *type_location = type_specifier_seq.locations[ds_type_spec];
 
+  /* If there is just ds_type_spec specified, this could be a type alias.  */
+  if (type_alias_p && is_typedef_decl (type_specifier_seq.type))
+    {
+      int i;
+      for (i = ds_first; i < ds_last; ++i)
+       if (i != ds_type_spec && type_specifier_seq.locations[i])
+         break;
+      if (i == ds_last)
+       next = cp_lexer_peek_token (parser->lexer);
+    }
+
   if (is_template_arg && type_specifier_seq.type
       && TREE_CODE (type_specifier_seq.type) == TEMPLATE_TYPE_PARM
       && CLASS_PLACEHOLDER_TEMPLATE (type_specifier_seq.type))
@@ -26872,6 +27695,11 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
   if (!cp_parser_parse_definitely (parser))
     abstract_declarator = NULL;
 
+  /* If we found * or & and similar after the type-specifier, it's not
+     a type alias.  */
+  if (type_alias_p)
+    *type_alias_p = cp_lexer_peek_token (parser->lexer) == next;
+
   bool auto_typeid_ok = false;
   /* DR 625 prohibits use of auto as a template-argument.  We allow 'auto'
      outside the template-argument-list context here only for the sake of
@@ -26934,7 +27762,8 @@ static tree
 cp_parser_type_id (cp_parser *parser, cp_parser_flags flags,
                   location_t *type_location)
 {
-  return cp_parser_type_id_1 (parser, flags, false, false, type_location);
+  return cp_parser_type_id_1 (parser, flags, false, false, type_location,
+                             nullptr);
 }
 
 /* Wrapper for cp_parser_type_id_1.  */
@@ -26947,7 +27776,7 @@ cp_parser_template_type_arg (cp_parser *parser)
     = G_("types may not be defined in template arguments");
   tree r = cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_NONE,
                                /*is_template_arg=*/true,
-                               /*is_trailing_return=*/false, nullptr);
+                               /*is_trailing_return=*/false, nullptr, nullptr);
   parser->type_definition_forbidden_message = saved_message;
   /* cp_parser_type_id_1 checks for auto, but only for
      ->auto_is_implicit_function_template_parm_p.  */
@@ -26965,7 +27794,7 @@ static tree
 cp_parser_trailing_type_id (cp_parser *parser)
 {
   return cp_parser_type_id_1 (parser, CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
-                             false, true, NULL);
+                             false, true, nullptr, nullptr);
 }
 
 /* Parse a type-specifier-seq.
@@ -30875,14 +31704,17 @@ cp_parser_base_clause (cp_parser* parser)
      public
 
    Returns a TREE_LIST.  The TREE_PURPOSE will be one of
-   ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_[VIRTUAL]_NODE to
-   indicate the specifiers provided.  The TREE_VALUE will be a TYPE
+   ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_NODE to
+   indicate the specifiers provided, or if the base specifier
+   has any annotations, a TREE_LIST with TREE_PURPOSE the
+   ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_NODE and
+   TREE_VALUE the list of annotations.  The TREE_VALUE will be a TYPE
    (or the ERROR_MARK_NODE) indicating the type that was specified.  */
 
 static tree
 cp_parser_base_specifier (cp_parser* parser)
 {
-  cp_token *token;
+  cp_token *token, *typename_token = nullptr, *splice_token = nullptr;
   bool done = false;
   bool virtual_p = false;
   bool duplicate_virtual_error_issued_p = false;
@@ -30892,10 +31724,28 @@ cp_parser_base_specifier (cp_parser* parser)
   tree type;
   location_t attrs_loc = cp_lexer_peek_token (parser->lexer)->location;
   tree std_attrs = cp_parser_std_attribute_spec_seq (parser);
+  tree annotations = NULL_TREE;
 
-  if (std_attrs != NULL_TREE && any_nonignored_attribute_p (std_attrs))
-    warning_at (attrs_loc, OPT_Wattributes,
-               "attributes on base specifiers are ignored");
+  if (std_attrs != NULL_TREE)
+    {
+      tree *pannotations = &annotations;
+      for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr))
+       {
+         if (annotation_p (attr))
+           {
+             *pannotations = attr;
+             pannotations = &TREE_CHAIN (attr);
+           }
+         else if (!attribute_ignored_p (attr))
+           {
+             if (std_attrs)
+               warning_at (attrs_loc, OPT_Wattributes,
+                           "attributes on base specifiers are ignored");
+             std_attrs = NULL_TREE;
+           }
+       }
+      *pannotations = NULL_TREE;
+    }
 
   /* Process the optional `virtual' and `access-specifier'.  */
   while (!done)
@@ -30948,17 +31798,14 @@ cp_parser_base_specifier (cp_parser* parser)
     }
   /* It is not uncommon to see programs mechanically, erroneously, use
      the 'typename' keyword to denote (dependent) qualified types
-     as base classes.  */
+     as base classes.  The diagnostic is deferred because if typename is
+     be followed by [:, it depends on whether it is splice-scope-specifier
+     or splice-type-specifier.  */
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
     {
-      token = cp_lexer_peek_token (parser->lexer);
-      if (!processing_template_decl)
-       error_at (token->location,
-                 "keyword %<typename%> not allowed outside of templates");
-      else
-       error_at (token->location,
-                 "keyword %<typename%> not allowed in this context "
-                 "(the base class is implicitly a type)");
+      typename_token = cp_lexer_peek_token (parser->lexer);
+      if (cp_parser_next_tokens_start_splice_type_spec_p (parser, true))
+       splice_token = cp_lexer_peek_nth_token (parser->lexer, 2);
       cp_lexer_consume_token (parser->lexer);
     }
 
@@ -30986,10 +31833,35 @@ cp_parser_base_specifier (cp_parser* parser)
   class_scope_p = (parser->scope && TYPE_P (parser->scope));
   template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
 
+  if (typename_token && cp_lexer_peek_token (parser->lexer) != splice_token)
+    {
+      /* Emit deferred diagnostics for invalid typename keyword if
+        cp_parser_nested_name_specifier_opt parsed splice-scope-specifier.  */
+      // TODO This error should be removed:
+      // struct A { struct B {}; };
+      // typename A::B b;
+      // is valid.
+      if (!processing_template_decl)
+       error_at (typename_token->location,
+                 "keyword %<typename%> not allowed outside of templates");
+      else
+       error_at (typename_token->location,
+                 "keyword %<typename%> not allowed in this context "
+                 "(the base class is implicitly a type)");
+    }
+
   if (!parser->scope
       && cp_lexer_next_token_is_decltype (parser->lexer))
     /* DR 950 allows decltype as a base-specifier.  */
     type = cp_parser_decltype (parser);
+  else if (!parser->scope
+          && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE))
+    {
+      /* Parse C++26 splice-type-specifier.  */
+      type = cp_parser_splice_type_specifier (parser);
+      if (type == NULL_TREE)
+       return error_mark_node;
+    }
   else
     {
       /* Otherwise, look for the class-name.  */
@@ -31009,7 +31881,7 @@ cp_parser_base_specifier (cp_parser* parser)
   if (type == error_mark_node)
     return error_mark_node;
 
-  return finish_base_specifier (type, access, virtual_p);
+  return finish_base_specifier (type, access, virtual_p, annotations);
 }
 
 /* Exception handling [gram.exception] */
@@ -32393,6 +33265,21 @@ cp_parser_check_std_attribute (location_t loc, tree attributes, tree attribute)
   return true;
 }
 
+/* Parse a C++-26 annotation.
+
+  annotation:
+    = constant-expression  */
+
+static tree
+cp_parser_annotation (cp_parser *parser)
+{
+  cp_parser_require (parser, CPP_EQ, RT_EQ);
+  auto suppression = make_temp_override (suppress_location_wrappers, 0);
+  return cp_parser_constant_expression (parser, /*allow_non_constant_p=*/false,
+                                       /*non_constant_p=*/nullptr,
+                                       /*strict_p=*/true);
+}
+
 /* Parse a list of standard C++-11 attributes.
 
    attribute-list:
@@ -32410,7 +33297,22 @@ cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns)
 
   while (true)
     {
-      location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+      token = cp_lexer_peek_token (parser->lexer);
+      location_t loc = token->location;
+      if (token->type == CPP_EQ)
+       {
+         error_at (loc, "mixing annotations and attributes in the same list");
+         tree annotation = cp_parser_annotation (parser);
+         if (annotation == error_mark_node)
+           break;
+         if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+           cp_lexer_consume_token (parser->lexer);
+         token = cp_lexer_peek_token (parser->lexer);
+         if (token->type != CPP_COMMA)
+           break;
+         cp_lexer_consume_token (parser->lexer);
+         continue;
+       }
       attribute = cp_parser_std_attribute (parser, attr_ns);
       if (attribute == error_mark_node)
        break;
@@ -32802,10 +33704,70 @@ void cp_parser_late_contract_condition (cp_parser *parser,
     }
 }
 
+/* Parse a C++-26 annotation list.
+
+   annotation-list:
+     annotation ... [opt]
+     annotation-list , annotation ... [opt]
+
+   annotation:
+     = constant-expression  */
+
+static tree
+cp_parser_annotation_list (cp_parser *parser)
+{
+  tree attributes = NULL_TREE;
+
+  while (true)
+    {
+      cp_token *token = cp_lexer_peek_token (parser->lexer);
+      location_t loc = token->location;
+      if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+       {
+         tree annotation = cp_parser_annotation (parser);
+         if (annotation == error_mark_node)
+           break;
+         annotation = build_tree_list (NULL_TREE, annotation);
+         if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+           {
+             cp_lexer_consume_token (parser->lexer);
+             annotation = make_pack_expansion (annotation);
+             if (annotation == error_mark_node)
+               break;
+           }
+         attributes = tree_cons (build_tree_list (internal_identifier,
+                                                  annotation_identifier),
+                                 annotation, attributes);
+       }
+      else if (token->type == CPP_NAME
+              || token->type == CPP_KEYWORD
+              || (token->flags & NAMED_OP))
+       {
+         error_at (loc, "mixing annotations and attributes in the same list");
+         if (cp_parser_std_attribute (parser, NULL_TREE) == error_mark_node)
+           break;
+         if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+           cp_lexer_consume_token (parser->lexer);
+       }
+      else
+       {
+         cp_parser_require (parser, CPP_EQ, RT_EQ);
+         break;
+       }
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type != CPP_COMMA)
+       break;
+      cp_lexer_consume_token (parser->lexer);
+    }
+  attributes = nreverse (attributes);
+  return attributes;
+}
+
 /* Parse a standard C++-11 attribute specifier.
 
    attribute-specifier:
      [ [ attribute-using-prefix [opt] attribute-list ] ]
+     [ [ annotation-list ]]
      contract-attribute-specifier
      alignment-specifier
 
@@ -32844,6 +33806,20 @@ cp_parser_std_attribute_spec (cp_parser *parser)
       cp_lexer_consume_token (parser->lexer);
 
       token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_EQ)
+       {
+         if (cxx_dialect < cxx26)
+           pedwarn (token->location, OPT_Wc__26_extensions,
+                    "annotations only available with %<-std=c++2c%> "
+                    "or %<-std=gnu++2c%>");
+         attributes = cp_parser_annotation_list (parser);
+         if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)
+             || !cp_parser_require (parser, CPP_CLOSE_SQUARE,
+                                    RT_CLOSE_SQUARE))
+           cp_parser_skip_to_end_of_statement (parser);
+         return attributes;
+       }
+
       if (token->type == CPP_NAME)
        {
          attr_name = token->u.value;
@@ -33005,7 +33981,7 @@ static size_t
 cp_parser_skip_balanced_tokens (cp_parser *parser, size_t n)
 {
   size_t orig_n = n;
-  int nparens = 0, nbraces = 0, nsquares = 0;
+  int nparens = 0, nbraces = 0, nsquares = 0, nsplices = 0;
   do
     switch (cp_lexer_peek_nth_token (parser->lexer, n++)->type)
       {
@@ -33025,6 +34001,9 @@ cp_parser_skip_balanced_tokens (cp_parser *parser, size_t n)
       case CPP_OPEN_SQUARE:
        ++nsquares;
        break;
+      case CPP_OPEN_SPLICE:
+       ++nsplices;
+       break;
       case CPP_CLOSE_PAREN:
        --nparens;
        break;
@@ -33034,10 +34013,13 @@ cp_parser_skip_balanced_tokens (cp_parser *parser, size_t n)
       case CPP_CLOSE_SQUARE:
        --nsquares;
        break;
+      case CPP_CLOSE_SPLICE:
+       --nsplices;
+       break;
       default:
        break;
       }
-  while (nparens || nbraces || nsquares);
+  while (nparens || nbraces || nsquares || nsplices);
   return n;
 }
 
@@ -33851,12 +34833,10 @@ cp_parser_simple_requirement (cp_parser *parser)
 
 /* Parse a type requirement
 
-     type-requirement
-         nested-name-specifier [opt] required-type-name ';'
-
-     required-type-name:
-         type-name
-         'template' [opt] simple-template-id  */
+     type-requirement:
+       typename nested-name-specifier [opt] type-name ';'
+       typename splice-specifier ';'
+       typename splice-specialization-specifier ';' */
 
 static tree
 cp_parser_type_requirement (cp_parser *parser)
@@ -33887,8 +34867,15 @@ cp_parser_type_requirement (cp_parser *parser)
       type = make_typename_type (parser->scope, type, typename_type,
                                  /*complain=*/tf_error);
     }
+  else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SPLICE))
+    {
+      /* tsubst_type_requirement wants this to be a type.  */
+      type = cp_parser_splice_type_specifier (parser);
+      if (!type)
+       type = error_mark_node;
+    }
   else
-   type = cp_parser_type_name (parser, /*typename_keyword_p=*/true);
+    type = cp_parser_type_name (parser, /*typename_keyword_p=*/true);
 
   if (TREE_CODE (type) == TYPE_DECL)
     type = TREE_TYPE (type);
@@ -34160,8 +35147,9 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
         looking up names in uninstantiated templates.  Even then, we
         cannot look up the name if the scope is not a class type; it
         might, for example, be a template type parameter.  */
-      dependent_p = (TYPE_P (parser->scope)
-                    && dependent_scope_p (parser->scope));
+      dependent_p = ((TYPE_P (parser->scope)
+                     && dependent_scope_p (parser->scope))
+                    || dependent_namespace_p (parser->scope));
       if ((check_dependency || !CLASS_TYPE_P (parser->scope))
          && dependent_p)
        /* Defer lookup.  */
@@ -34213,8 +35201,10 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
 
       /* If the scope is a dependent type and either we deferred lookup or
         we did lookup but didn't find the name, rememeber the name.  */
-      if (decl == error_mark_node && TYPE_P (parser->scope)
-         && dependentish_scope_p (parser->scope))
+      if (decl == error_mark_node
+         && ((TYPE_P (parser->scope)
+              && dependentish_scope_p (parser->scope))
+             || dependent_namespace_p (parser->scope)))
        {
          if (tag_type)
            {
@@ -34328,7 +35318,10 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
 
      During an explicit instantiation, access is not checked at all,
      as per [temp.explicit].  */
-  if (DECL_P (decl))
+  if (DECL_P (decl)
+      /* One cannot take the reflection of a using-declarator.  Skip this
+        check because we are going to report an error anyway.  */
+      && LIKELY (TREE_CODE (decl) != USING_DECL))
     check_accessibility_of_qualified_id (decl, object_type, parser->scope,
                                         tf_warning_or_error);
 
@@ -36666,6 +37659,9 @@ cp_parser_required_error (cp_parser *parser,
          case RT_CLASS_TYPENAME_TEMPLATE:
            gmsgid = G_("expected %<class%>, %<typename%>, or %<template%>");
            break;
+         case RT_CLOSE_SPLICE:
+           gmsgid = G_("expected %<:]%>");
+           break;
          default:
            gcc_unreachable ();
        }
index 1c7a2ac2b112a041bb8a034db76544e9fa289838..3c9ba31b212d4ab4910ed7b8f8d116d4968c1528 100644 (file)
@@ -277,6 +277,18 @@ pop_access_scope (tree t)
     pop_from_top_level ();
 }
 
+/* Return current function, ignoring temporary overrides
+   of current_function_decl by push_access_scope.  */
+
+tree
+current_function_decl_without_access_scope ()
+{
+  if (vec_safe_length (saved_access_scope))
+    return (*saved_access_scope)[0];
+  else
+    return current_function_decl;
+}
+
 /* Do any processing required when DECL (a member template
    declaration) is finished.  Returns the TEMPLATE_DECL corresponding
    to DECL, unless it is a specialization, in which case the DECL
@@ -1221,7 +1233,7 @@ verify_unstripped_args_1 (tree inner)
   for (int i = 0; i < TREE_VEC_LENGTH (inner); ++i)
     {
       tree arg = TREE_VEC_ELT (inner, i);
-      if (TREE_CODE (arg) == TEMPLATE_DECL)
+      if (TREE_CODE (arg) == TEMPLATE_DECL || REFLECT_EXPR_P (arg))
        /* OK */;
       else if (TYPE_P (arg))
        gcc_assert (strip_typedefs (arg, NULL) == arg);
@@ -1904,6 +1916,18 @@ iterative_hash_template_arg (tree arg, hashval_t val)
        return val;
       }
 
+    case REFLECT_EXPR:
+      val = iterative_hash_hashval_t (REFLECT_EXPR_KIND (arg), val);
+      if (REFLECT_EXPR_KIND (arg) == REFLECT_BASE)
+       {
+         tree binfo = REFLECT_EXPR_HANDLE (arg);
+         val = iterative_hash_template_arg (BINFO_TYPE (binfo), val);
+         val = iterative_hash_template_arg (direct_base_parent (binfo), val);
+         return val;
+       }
+      /* Now hash operands as usual.  */
+      break;
+
     default:
       break;
     }
@@ -1925,7 +1949,7 @@ iterative_hash_template_arg (tree arg, hashval_t val)
 
       switch (code)
        {
-       case  DECLTYPE_TYPE:
+       case DECLTYPE_TYPE:
          val = iterative_hash_template_arg (DECLTYPE_TYPE_EXPR (arg), val);
          break;
 
@@ -8005,6 +8029,17 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       if (expr == error_mark_node)
        return NULL_TREE;
     }
+  else if (REFLECTION_TYPE_P (type))
+    {
+      if (!REFLECTION_TYPE_P (TREE_TYPE (expr)))
+       {
+         if (complain & tf_error)
+           error ("%qE is not a valid template argument for type %qT "
+                  "because it is of type %qT", expr, type, TREE_TYPE (expr));
+         return NULL_TREE;
+       }
+      return expr;
+    }
   /* A template non-type parameter must be one of the above.  */
   else
     gcc_unreachable ();
@@ -10966,6 +11001,11 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
        return error_mark_node;
       break;
 
+    case SPLICE_SCOPE:
+      WALK_SUBTREE (SPLICE_SCOPE_EXPR (t));
+      *walk_subtrees = 0;
+      break;
+
     default:
       break;
     }
@@ -12770,20 +12810,31 @@ instantiate_class_template (tree type)
        {
          tree base;
          tree access = BINFO_BASE_ACCESS (pbinfo, i);
+         tree annotations = NULL_TREE;
           tree expanded_bases = NULL_TREE;
           int idx, len = 1;
 
+         if (i + BINFO_BASE_BINFOS (pbinfo)->length ()
+             < vec_safe_length (BINFO_BASE_ACCESSES (pbinfo)))
+           annotations
+             = BINFO_BASE_ACCESS (pbinfo,
+                                  i + BINFO_BASE_BINFOS (pbinfo)->length ());
+
           if (PACK_EXPANSION_P (BINFO_TYPE (pbase_binfo)))
             {
-              expanded_bases =
-               tsubst_pack_expansion (BINFO_TYPE (pbase_binfo),
-                                      args, tf_error, NULL_TREE);
+             expanded_bases
+               tsubst_pack_expansion (BINFO_TYPE (pbase_binfo),
+                                        args, tf_error, NULL_TREE);
               if (expanded_bases == error_mark_node)
                 continue;
 
               len = TREE_VEC_LENGTH (expanded_bases);
             }
 
+         if (annotations)
+           annotations = tsubst_attributes (annotations, args,
+                                            tf_warning_or_error, NULL_TREE);
+
           for (idx = 0; idx < len; idx++)
             {
               if (expanded_bases)
@@ -12797,7 +12848,13 @@ instantiate_class_template (tree type)
               if (base == error_mark_node)
                 continue;
 
-              base_list = tree_cons (access, base, base_list);
+             tree acc = access;
+             if (annotations)
+               /* Make sure each direct base from the pack has its unique
+                  set of annotations.  */
+               acc = build_tree_list (access, idx == 0 ? annotations
+                                              : copy_list (annotations));
+             base_list = tree_cons (acc, base, base_list);
               if (BINFO_VIRTUAL_P (pbase_binfo))
                 TREE_TYPE (base_list) = integer_type_node;
             }
@@ -14261,7 +14318,7 @@ tsubst_tree_vec (tree t, tree args, tsubst_flags_t complain, tree in_decl)
    node if only a partial substitution could be performed, or ERROR_MARK_NODE
    if there was an error.  */
 
-tree
+static tree
 tsubst_pack_index (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
   tree pack = PACK_INDEX_PACK (t);
@@ -16173,6 +16230,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
       }
       break;
 
+    case NAMESPACE_DECL:
+      if (dependent_namespace_p (t))
+       r = tsubst_expr (ORIGINAL_NAMESPACE (t), args, complain, in_decl);
+      else
+       r = t;
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -16612,6 +16676,78 @@ tsubst_tree_list (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   return chain;
 }
 
+/* Substitute ARGS into T, which is a splice scope.  */
+
+static tree
+tsubst_splice_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  tree r = tsubst (SPLICE_SCOPE_EXPR (t), args, complain, in_decl);
+  if (r == error_mark_node)
+    return r;
+  if (dependent_splice_p (r))
+    return make_splice_scope (r, SPLICE_SCOPE_TYPE_P (t));
+  if (SPLICE_SCOPE_TYPE_P (t)
+      ? !valid_splice_type_p (r)
+      : !valid_splice_scope_p (r))
+    {
+      if (complain & tf_error)
+       {
+         const location_t loc = EXPR_LOCATION (SPLICE_SCOPE_EXPR (t));
+         if (SPLICE_SCOPE_TYPE_P (t))
+           error_at (loc, "%qE is not usable in a splice type", r);
+         else
+           error_at (loc, "%qE is not usable in a splice scope", r);
+       }
+      return error_mark_node;
+    }
+
+  return r;
+}
+
+/* Substitute ARGS into T, which is a splice expression.  */
+
+static tree
+tsubst_splice_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  tree op = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl);
+  if (op == error_mark_node)
+    return error_mark_node;
+  op = splice (op);
+  if (dependent_splice_p (op))
+    {
+      if (SPLICE_EXPR_EXPRESSION_P (t))
+       SET_SPLICE_EXPR_EXPRESSION_P (op);
+      if (SPLICE_EXPR_MEMBER_ACCESS_P (t))
+       SET_SPLICE_EXPR_MEMBER_ACCESS_P (op, true);
+      if (SPLICE_EXPR_ADDRESS_P (t))
+       SET_SPLICE_EXPR_ADDRESS_P (op, true);
+      return op;
+    }
+  if (SPLICE_EXPR_EXPRESSION_P (t)
+      && !check_splice_expr (input_location, UNKNOWN_LOCATION, op,
+                            SPLICE_EXPR_ADDRESS_P (t),
+                            SPLICE_EXPR_MEMBER_ACCESS_P (t),
+                            (complain & tf_error)))
+    return error_mark_node;
+  if (outer_automatic_var_p (op))
+    op = process_outer_var_ref (op, complain);
+  /* Like in cp_parser_splice_expression, for foo.[: bar :]
+     cp_parser_postfix_dot_deref_expression wants to see only
+     certain kind of entities.  */
+  if (SPLICE_EXPR_MEMBER_ACCESS_P (t))
+    gcc_assert (TREE_CODE (op) == FIELD_DECL
+               || VAR_P (op)
+               || TREE_CODE (op) == CONST_DECL
+               || TREE_CODE (op) == FUNCTION_DECL
+               || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (op))
+               || variable_template_p (op)
+               || BASELINK_P (op)
+               || TREE_CODE (op) == TEMPLATE_ID_EXPR
+               || TREE_CODE (op) == TREE_BINFO);
+
+  return op;
+}
+
 /* Take the tree structure T and replace template parameters used
    therein with the argument vector ARGS.  IN_DECL is an associated
    decl for diagnostics.  If an error occurs, returns ERROR_MARK_NODE.
@@ -16639,7 +16775,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       || t == void_type_node
       || t == char_type_node
       || t == unknown_type_node
-      || TREE_CODE (t) == NAMESPACE_DECL
       || TREE_CODE (t) == TRANSLATION_UNIT_DECL)
     return t;
 
@@ -16775,6 +16910,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case VECTOR_TYPE:
     case BOOLEAN_TYPE:
     case NULLPTR_TYPE:
+    case META_TYPE:
     case LANG_TYPE:
       return t;
 
@@ -17328,6 +17464,39 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        if (f == error_mark_node)
          return error_mark_node;
 
+       /* We had [:X:]:: which was substituted into a NAMESPACE_DECL and not
+          a type.  */
+       if (TREE_CODE (ctx) == NAMESPACE_DECL)
+         {
+           if (TREE_CODE (f) == TEMPLATE_ID_EXPR)
+             {
+               tree d = TREE_OPERAND (f, 0);
+               tree n = TREE_OPERAND (f, 1);
+               f = lookup_template_class (d, n, in_decl, ctx, complain);
+               if (f == error_mark_node)
+                 return error_mark_node;
+             }
+           else
+             {
+               gcc_assert (TREE_CODE (f) == IDENTIFIER_NODE);
+               tree decl = lookup_qualified_name (ctx, f);
+               if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+                 {
+                   qualified_name_lookup_error (ctx, f, decl, input_location);
+                   return error_mark_node;
+                 }
+               if (TREE_CODE (decl) == NAMESPACE_DECL)
+                 return decl;
+               else
+                 {
+                   gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL);
+                   f = TREE_TYPE (decl);
+                 }
+             }
+           return cp_build_qualified_type
+                   (f, cp_type_quals (f) | cp_type_quals (t), complain);
+         }
+
        if (!MAYBE_CLASS_TYPE_P (ctx))
          {
            if (complain & tf_error)
@@ -17493,6 +17662,35 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case PACK_INDEX_TYPE:
       return tsubst_pack_index (t, args, complain, in_decl);
 
+    case SPLICE_SCOPE:
+      return tsubst_splice_scope (t, args, complain, in_decl);
+
+    case SPLICE_EXPR:
+      /* We are coming from tsubst_splice_scope for [:R:]
+        where R needs to expand to a type or scope.  */
+      gcc_checking_assert (!SPLICE_EXPR_EXPRESSION_P (t));
+      return tsubst_splice_expr (t, args, complain, in_decl);
+
+    case TEMPLATE_ID_EXPR:
+      {
+       /* We end up here coming from tsubst_splice_scope for
+          [:R:]<int>.  R needs to expand to a type or scope.  */
+       tree templ = TREE_OPERAND (t, 0);
+       gcc_assert (TREE_CODE (templ) == SPLICE_EXPR);
+       templ = tsubst_splice_expr (templ, args, complain, in_decl);
+       if (templ == error_mark_node)
+         return error_mark_node;
+       tree targs = TREE_OPERAND (t, 1);
+       if (targs)
+         targs = tsubst_template_args (targs, args, complain, in_decl);
+       if (targs == error_mark_node)
+         return error_mark_node;
+       tree r = finish_template_type (templ, targs, /*entering_scope=*/false);
+       if (TREE_CODE (r) == TYPE_DECL)
+         r = TREE_TYPE (r);
+       return r;
+      }
+
     case VOID_CST:
     case INTEGER_CST:
     case REAL_CST:
@@ -17522,7 +17720,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 static tree
 tsubst_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
-  gcc_checking_assert (TYPE_P (t));
+  gcc_checking_assert (TYPE_P (t) || TREE_CODE (t) == NAMESPACE_DECL);
   return tsubst (t, args, complain | tf_qualifying_scope, in_decl);
 }
 
@@ -17815,7 +18013,7 @@ tsubst_qualified_id (tree qualified_id, tree args,
   else
     expr = name;
 
-  if (dependent_scope_p (scope))
+  if (dependent_scope_p (scope) || dependent_namespace_p (scope))
     {
       if (TREE_CODE (expr) == SCOPE_REF)
        /* We built one in tsubst_baselink.  */
@@ -20515,10 +20713,9 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
   tree r = build_lambda_expr ();
 
-  LAMBDA_EXPR_LOCATION (r)
-    = LAMBDA_EXPR_LOCATION (t);
-  LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
-    = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
+  LAMBDA_EXPR_LOCATION (r) = LAMBDA_EXPR_LOCATION (t);
+  LAMBDA_EXPR_CONSTEVAL_BLOCK_P (r) = LAMBDA_EXPR_CONSTEVAL_BLOCK_P (t);
+  LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r) = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
   if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
     LAMBDA_EXPR_REGEN_INFO (r)
       = build_template_info (t, add_to_template_args (TI_ARGS (ti),
@@ -22144,7 +22341,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
            /* Assume access of this FIELD_DECL has already been checked; we
               don't recheck it to avoid bogus access errors when substituting
               a reduced constant initializer (97740).  */
-           gcc_checking_assert (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL);
+           gcc_checking_assert (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL
+                                || dependent_splice_p (TREE_OPERAND (t, 1)));
            push_deferring_access_checks (dk_deferred);
            r = finish_non_static_data_member (member, object, NULL_TREE,
                                               complain);
@@ -22220,7 +22418,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
        r = finish_class_member_access_expr (object, member,
                                             /*template_p=*/false,
-                                            complain);
+                                            complain,
+                                            COMPONENT_REF_SPLICE_P (t));
        if (REF_PARENTHESIZED_P (t))
          r = force_paren_expr (r);
        RETURN (r);
@@ -22542,9 +22741,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        }
       RETURN (t);
 
-    case NAMESPACE_DECL:
-      RETURN (t);
-
     case OVERLOAD:
       if (modules_p ())
        for (tree ovl : lkp_range (t))
@@ -22617,7 +22813,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       }
 
     case PACK_INDEX_EXPR:
-    RETURN (tsubst_pack_index (t, args, complain, in_decl));
+      RETURN (tsubst_pack_index (t, args, complain, in_decl));
 
     case EXPR_PACK_EXPANSION:
       error ("invalid use of pack expansion expression");
@@ -22834,6 +23030,30 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        RETURN (op);
       }
 
+    case REFLECT_EXPR:
+      {
+       tree h = REFLECT_EXPR_HANDLE (t);
+       reflect_kind kind = REFLECT_EXPR_KIND (t);
+       if (TYPE_P (h) || TREE_CODE (h) == NAMESPACE_DECL)
+         h = tsubst (h, args, complain, in_decl);
+       else if (kind == REFLECT_ANNOTATION)
+         /* annotations_of should be called on reflections of already
+            instantiated entities and so no need to tsubst the annotation
+            attribute and we rely on pointer equality of that.  */
+         ;
+       else
+         {
+           /* [expr.reflect] The id-expression of a reflect-expression is
+              an unevaluated operand.  */
+           cp_unevaluated u;
+           h = RECUR (h);
+         }
+       RETURN (get_reflection (EXPR_LOCATION (t), h, kind));
+      }
+
+    case SPLICE_EXPR:
+      RETURN (tsubst_splice_expr (t, args, complain, in_decl));
+
     default:
       /* Handle Objective-C++ constructs, if appropriate.  */
       if (tree subst = objcp_tsubst_expr (t, args, complain, in_decl))
@@ -26039,6 +26259,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
     case VOID_TYPE:
     case OPAQUE_TYPE:
     case NULLPTR_TYPE:
+    case META_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
        return unify_type_mismatch (explain_p, parm, arg);
 
@@ -28164,6 +28385,8 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p)
       if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
        cp_check_omp_declare_reduction (d);
 
+      check_consteval_only_fn (d);
+
       if (int errs = errorcount + sorrycount)
        if (errs > current_tinst_level->errors)
          if (function *f = DECL_STRUCT_FUNCTION (d))
@@ -28730,6 +28953,8 @@ tsubst_enum (tree tag, tree newtag, tree args)
   if (SCOPED_ENUM_P (newtag))
     begin_scope (sk_scoped_enum, newtag);
 
+  ENUM_BEING_DEFINED_P (newtag) = 1;
+
   for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e))
     {
       tree value;
@@ -29010,6 +29235,11 @@ dependent_type_p_r (tree type)
   if (TREE_CODE (type) == DEPENDENT_OPERATOR_TYPE)
     return true;
 
+  /* A splice-scope-specifier is dependent if its splice-specifier
+     or splice-specialization-specifier is dependent.  */
+  if (TREE_CODE (type) == SPLICE_SCOPE)
+    return true;
+
   if (any_dependent_type_attributes_p (TYPE_ATTRIBUTES (type)))
     return true;
 
@@ -29099,6 +29329,17 @@ dependentish_scope_p (tree scope)
   return dependent_scope_p (scope) || any_dependent_bases_p (scope);
 }
 
+/* Returns TRUE if NS is a dependent namespace, in which we can't do any
+   lookup.  */
+
+bool
+dependent_namespace_p (tree ns)
+{
+  if (TREE_CODE (ns) == NAMESPACE_DECL)
+    ns = ORIGINAL_NAMESPACE (ns);
+  return TREE_CODE (ns) == SPLICE_EXPR;
+}
+
 /* T is a SCOPE_REF.  Return whether it represents a non-static member of
    an unknown base of 'this' (and is therefore instantiation-dependent).  */
 
@@ -29377,6 +29618,24 @@ value_dependent_expression_p (tree expression)
            if (value_dependent_expression_p (op))
              return true;
          }
+       if (flag_reflection && !fn && CALL_EXPR_FN (expression))
+         {
+           fn = MAYBE_BASELINK_FUNCTIONS (CALL_EXPR_FN (expression));
+           if (fn && TREE_CODE (fn) != FUNCTION_DECL)
+             fn = NULL_TREE;
+         }
+       /* [meta.reflection.access.context]/8: An invocation of current that
+          appears at a program point P is value-dependent if eval-point(P)
+          is enclosed by a scope corresponding to a templated entity.  */
+       if (flag_reflection
+           && fn
+           && metafunction_p (fn)
+           && id_equal (DECL_NAME (fn), "current")
+           && DECL_CLASS_SCOPE_P (fn)
+           && id_equal (TYPE_IDENTIFIER (DECL_CONTEXT (fn)),
+                        "access_context"))
+         return true;
+
        return false;
       }
 
@@ -29409,6 +29668,24 @@ value_dependent_expression_p (tree expression)
              || value_dependent_expression_p (TREE_OPERAND (expression, 2))
              || value_dependent_expression_p (TREE_OPERAND (expression, 3)));
 
+    case REFLECT_EXPR:
+      /* [temp.dep.constexpr] A reflect-expression is value-dependent
+        if it contains a dependent nested-name-specifier, type-id,
+        namespace-name, or template-name, or if it contains
+        a value-dependent or type-dependent id-expression.  */
+      if (REFLECT_EXPR_KIND (expression) == REFLECT_BASE)
+       /* Direct base relationship isn't value-dependent and calling
+          uses_template_parms on TREE_BINFO leads to ICEs.  */
+       return false;
+      if (REFLECT_EXPR_KIND (expression) == REFLECT_DATA_MEMBER_SPEC)
+       {
+         /* Data member description is value dependent if the type is
+            dependent, other optional fields shouldn't be ever dependent.  */
+         tree h = REFLECT_EXPR_HANDLE (expression);
+         return dependent_type_p (TREE_VEC_ELT (h, 0));
+       }
+      return uses_template_parms (REFLECT_EXPR_HANDLE (expression));
+
     default:
       /* A constant expression is value-dependent if any subexpression is
         value-dependent.  */
@@ -29498,7 +29775,8 @@ type_dependent_expression_p (tree expression)
       || TREE_CODE (expression) == DELETE_EXPR
       || TREE_CODE (expression) == VEC_DELETE_EXPR
       || TREE_CODE (expression) == THROW_EXPR
-      || TREE_CODE (expression) == REQUIRES_EXPR)
+      || TREE_CODE (expression) == REQUIRES_EXPR
+      || REFLECT_EXPR_P (expression))
     return false;
 
   /* The types of these expressions depends only on the type to which
@@ -33136,6 +33414,24 @@ finish_expansion_stmt (tree expansion_stmt, tree args,
     }
 }
 
+/* Perform the appropriate conversion of the argument of
+   std::meta::reflect_constant.   EXPR is the argument, TYPE is its type.
+   Mainly, the point is to check that the type is valid in this context
+   and maybe replace the argument with a reference to the corresponding
+   template parameter object.  */
+
+tree
+convert_reflect_constant_arg (tree type, tree expr)
+{
+  if (invalid_nontype_parm_type_p (type, tf_none))
+    return error_mark_node;
+
+  expr = convert_nontype_argument (type, expr, tf_none);
+  if (!expr)
+    return error_mark_node;
+  return expr;
+}
+
 /* Set up the hash tables for template instantiations.  */
 
 void
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
new file mode 100644 (file)
index 0000000..237f630
--- /dev/null
@@ -0,0 +1,8608 @@
+/* C++ reflection code.
+   Copyright (C) 2025-2026 Free Software Foundation, Inc.
+   Written by Marek Polacek <polacek@redhat.com> and
+   Jakub Jelinek <jakub@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tm.h"
+#include "cp-tree.h"
+#include "stringpool.h" // for get_identifier
+#include "intl.h"
+#include "attribs.h"
+#include "c-family/c-pragma.h" // for parse_in
+#include "gimplify.h" // for unshare_expr
+#include "metafns.h"
+
+static tree eval_is_function_type (tree);
+static tree eval_is_object_type (location_t, 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_reflect_constant_array (location_t, const constexpr_ctx *,
+                                        tree, bool *, bool *, tree *, tree);
+static tree eval_reflect_function (location_t, const constexpr_ctx *, tree,
+                                  tree, bool *, tree *, tree);
+struct constexpr_ctx;
+
+/* Return the appropriate tsubst flags for processing a metafunction.  */
+
+static tsubst_flags_t
+complain_flags (const constexpr_ctx *ctx)
+{
+  return cxx_constexpr_quiet_p (ctx) ? tf_none : tf_warning_or_error;
+}
+
+/* Initialize state for reflection; e.g., initialize meta_info_type_node.  */
+
+void
+init_reflection ()
+{
+  /* The type std::meta::info is a scalar type for which equality and
+     inequality are meaningful, but for which no ordering relation is
+     defined.  */
+  meta_info_type_node = make_node (META_TYPE);
+  /* Make it a complete type.  */
+  TYPE_SIZE (meta_info_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
+  TYPE_SIZE_UNIT (meta_info_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
+  /* Name it.  */
+  record_builtin_type (RID_MAX, "decltype(^^int)", meta_info_type_node);
+
+  /* Create the `std::meta' namespace.  */
+  push_namespace (get_identifier ("std"));
+  push_namespace (get_identifier ("meta"), /*inline*/false);
+  std_meta_node = current_namespace;
+  pop_namespace ();
+  pop_namespace ();
+}
+
+/* Create a REFLECT_EXPR expression of kind KIND around T.  */
+
+static tree
+get_reflection_raw (location_t loc, tree t, reflect_kind kind = REFLECT_UNDEF)
+{
+  t = build1_loc (loc, REFLECT_EXPR, meta_info_type_node, t);
+  SET_REFLECT_EXPR_KIND (t, kind);
+  TREE_CONSTANT (t) = true;
+  TREE_READONLY (t) = true;
+  TREE_SIDE_EFFECTS (t) = false;
+  return t;
+}
+
+/* Return the reflection for T.
+
+    [basic.fundamental]: A value of type std::meta::info is called a reflection.
+    There exists a unique null reflection; every other reflection is
+    a representation of
+
+    -- a value of scalar type,
+    -- an object with static storage duration,
+    -- a variable,
+    -- a structured binding,
+    -- a function,
+    -- a function parameter,
+    -- an enumerator,
+    -- an annotation,
+    -- a type alias,
+    -- a type,
+    -- a class member,
+    -- an unnamed bit-field,
+    -- a class template,
+    -- a function template,
+    -- a variable template,
+    -- an alias template,
+    -- a concept,
+    -- a namespace alias,
+    -- a namespace,
+    -- a direct base class relationship, or
+    -- a data member description.
+
+   KIND is used to distinguish between categories that are represented
+   by the same handle.  */
+
+tree
+get_reflection (location_t loc, tree t, reflect_kind kind/*=REFLECT_UNDEF*/)
+{
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
+  /* [expr.reflect] If the type-id designates a placeholder type, R is
+     ill-formed.  */
+  if (is_auto (t))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a placeholder type");
+      return error_mark_node;
+    }
+  /* Constant template parameters and pack-index-expressions cannot
+     appear as operands of the reflection operator.  */
+  else if (PACK_INDEX_P (t))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a pack index");
+      return error_mark_node;
+    }
+  else if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a non-type template "
+               "parameter %qD", t);
+      return error_mark_node;
+    }
+  /* If the id-expression denotes a variable declared by an init-capture,
+     R is ill-formed.  */
+  else if (is_capture_proxy (t))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a local entity declared "
+               "by init-capture");
+      return error_mark_node;
+    }
+  /* If the id-expression denotes a local parameter introduced by
+     a requires-expression, R is ill-formed.  */
+  else if (TREE_CODE (t) == PARM_DECL && CONSTRAINT_VAR_P (t))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a local parameter of "
+               "a requires-expression %qD", t);
+      return error_mark_node;
+    }
+  /* If the id-expression denotes a local entity E for which there is
+     a lambda scope that intervenes between R and the point at which E
+     was introduced, R is ill-formed.  */
+  else if (outer_automatic_var_p (t)
+          /* Since outer_automatic_var_p is also true when we are in
+             a local class member function, additionally check that
+             we are in a lambda.  */
+          && ((current_function_decl
+               && LAMBDA_FUNCTION_P (current_function_decl))
+              || parsing_lambda_declarator ()))
+    {
+      auto_diagnostic_group d;
+      error_at (loc, "%<^^%> cannot be applied a local entity for which "
+               "there is an intervening lambda expression");
+      inform (DECL_SOURCE_LOCATION (t), "%qD declared here", t);
+      return error_mark_node;
+    }
+  /* If lookup finds a declaration that replaced a using-declarator during
+     a single search, R is ill-formed.  */
+  else if (TREE_CODE (t) == USING_DECL
+          || (TREE_CODE (t) == OVERLOAD && OVL_USING_P (t)))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a using-declaration");
+      return error_mark_node;
+    }
+  /* A concept is fine, but not Concept<arg>.  */
+  else if (concept_check_p (t))
+    {
+      error_at (loc, "%<^^%> cannot be applied to a concept check");
+      return error_mark_node;
+    }
+
+  /* Otherwise, if the template-name names a function template F,
+     then the template-name interpreted as an id-expression shall
+     denote an overload set containing only F.  R represents F.
+
+     When we have:
+       template<typename T>
+       void foo (T) {}
+       constexpr auto a = ^^foo;
+     we will get an OVERLOAD containing only one function.  */
+  tree r = MAYBE_BASELINK_FUNCTIONS (t);
+  if (OVL_P (r))
+    {
+      if (!OVL_SINGLE_P (r))
+       {
+         error_at (loc, "cannot take the reflection of an overload set");
+         return error_mark_node;
+       }
+    }
+  /* [expr.reflect] If the id-expression denotes an overload set S,
+     overload resolution for the expression &S with no target shall
+     select a unique function; R represents that function.  */
+  else if (!processing_template_decl && t != unknown_type_node)
+    /* Resolve all TEMPLATE_ID_EXPRs here.  */
+    t = resolve_nondeduced_context_or_error (t, tf_warning_or_error);
+
+  /* For injected-class-name, use the main variant so that comparing
+     reflections works (cf. compare3.C).  */
+  if (RECORD_OR_UNION_TYPE_P (t)
+      && TYPE_NAME (t)
+      && DECL_SELF_REFERENCE_P (TYPE_NAME (t)))
+    t = TYPE_MAIN_VARIANT (t);
+
+  /* It's annoying to deal with BIT_NOT_EXPR in a reflection later, so
+     look up the FUNCTION_DECL here.  */
+  if (TREE_CODE (t) == BIT_NOT_EXPR
+      && CLASS_TYPE_P (TREE_OPERAND (t, 0))
+      && COMPLETE_TYPE_P (TREE_OPERAND (t, 0)))
+    {
+      r = TREE_OPERAND (t, 0);
+      if (CLASSTYPE_LAZY_DESTRUCTOR (r))
+       lazily_declare_fn (sfk_destructor, r);
+      if (tree dtor = CLASSTYPE_DESTRUCTOR (r))
+       t = dtor;
+    }
+
+  if (t == error_mark_node)
+    return error_mark_node;
+
+  return get_reflection_raw (loc, t, kind);
+}
+
+/* Null reflection shared tree.  */
+
+static GTY(()) tree null_reflection;
+
+/* Return a null reflection value.  */
+
+tree
+get_null_reflection ()
+{
+  if (!null_reflection)
+    null_reflection = get_reflection_raw (UNKNOWN_LOCATION, unknown_type_node);
+  return null_reflection;
+}
+
+/* Do strip_typedefs on T, but only for types.  */
+
+static tree
+maybe_strip_typedefs (tree t)
+{
+  if (TYPE_P (t))
+    return strip_typedefs (t);
+  return t;
+}
+
+/* If PARM_DECL comes from an earlier reflection of a function parameter
+   and function definition is seen after that, DECL_ARGUMENTS is
+   overwritten and so the old PARM_DECL is no longer present in the
+   DECL_ARGUMENTS (DECL_CONTEXT (parm)) chain.  Return corresponding
+   PARM_DECL which is in the chain.  */
+
+static tree
+maybe_update_function_parm (tree parm)
+{
+  if (!OLD_PARM_DECL_P (parm))
+    return parm;
+  tree fn = DECL_CONTEXT (parm);
+  int oldlen = list_length (parm);
+  int newlen = list_length (DECL_ARGUMENTS (fn));
+  gcc_assert (newlen >= oldlen);
+  tree ret = DECL_ARGUMENTS (fn);
+  int n = newlen - oldlen;
+  while (n)
+    {
+      ret = DECL_CHAIN (ret);
+      --n;
+    }
+  return ret;
+}
+
+/* Return true if DECL comes from std::meta.  */
+
+static bool
+decl_in_std_meta_p (tree decl)
+{
+  return decl_namespace_context (decl) == std_meta_node;
+}
+
+/* Returns true if FNDECL, a FUNCTION_DECL, is a call to a metafunction
+   declared in namespace std::meta.  */
+
+bool
+metafunction_p (tree fndecl)
+{
+  if (!flag_reflection)
+    return false;
+
+  /* Metafunctions are expected to be marked consteval.  */
+  if (!DECL_IMMEDIATE_FUNCTION_P (fndecl))
+    return false;
+
+  if (special_function_p (fndecl))
+    return false;
+
+  if (!decl_in_std_meta_p (fndecl))
+    return false;
+
+  /* They should be user provided and not defined.  */
+  if (!user_provided_p (fndecl)
+      || (DECL_NAMESPACE_SCOPE_P (fndecl) && DECL_DELETED_FN (fndecl)))
+    return false;
+  if (DECL_INITIAL (fndecl))
+    return false;
+
+  return true;
+}
+
+/* Extract the N-th reflection argument from a metafunction call CALL.  */
+
+static tree
+get_info (const constexpr_ctx *ctx, tree call, int n, bool *non_constant_p,
+         bool *overflow_p, tree *jump_target)
+{
+  gcc_checking_assert (call_expr_nargs (call) > n);
+  tree info = get_nth_callarg (call, n);
+  gcc_checking_assert (REFLECTION_TYPE_P (TREE_TYPE (info)));
+  info = cxx_eval_constant_expression (ctx, info, vc_prvalue,
+                                      non_constant_p, overflow_p,
+                                      jump_target);
+  if (*jump_target)
+    return NULL_TREE;
+  if (!REFLECT_EXPR_P (info))
+    {
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  return info;
+}
+
+/* Try to get the underlying FUNCTION_DECL from reflection if any,
+   otherwise return R.  */
+
+static tree
+maybe_get_reflection_fndecl (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  r = OVL_FIRST (r);
+  return r;
+}
+
+/* Helper function for get_range_elts, called through cp_walk_tree.  */
+
+static tree
+replace_parm_r (tree *tp, int *walk_subtrees, void *data)
+{
+  tree *p = (tree *) data;
+  if (*tp == p[0])
+    *tp = p[1];
+  else if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
+static tree throw_exception (location_t, const constexpr_ctx *, const char *,
+                            tree, bool *, tree *);
+
+/* Kinds for get_range_elts.  */
+
+enum get_range_elts_kind {
+  GET_INFO_VEC,
+  REFLECT_CONSTANT_STRING,
+  REFLECT_CONSTANT_ARRAY
+};
+
+/* Extract the N-th input_range argument from a metafunction call CALL
+   and return it as TREE_VEC or STRING_CST or CONSTRUCTOR.  Helper function
+   for get_info_vec, eval_reflect_constant_string and
+   eval_reflect_constant_array.  For GET_INFO_VEC kind, <meta> ensures
+   the argument is reference to reflection_range concept and so both
+   range_value_t is info and range_refernce_t is cv info or cv info & or
+   cv info &&.  */
+
+static tree
+get_range_elts (location_t loc, const constexpr_ctx *ctx, tree call, int n,
+               bool *non_constant_p, bool *overflow_p, tree *jump_target,
+               get_range_elts_kind kind, tree fun)
+{
+  gcc_checking_assert (call_expr_nargs (call) > n);
+  tree arg = get_nth_callarg (call, n);
+  tree parm = DECL_ARGUMENTS (cp_get_callee_fndecl_nofold (call));
+  for (int i = 0; i < n; ++i)
+    parm = DECL_CHAIN (parm);
+  tree type = TREE_TYPE (arg);
+  gcc_checking_assert (TYPE_REF_P (type));
+  arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p,
+                                     overflow_p, jump_target);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  tree map[2] = { parm, arg };
+  /* To speed things up, check
+     if constexpr (std::ranges::contiguous_range <_R>).  */
+  tree ranges_ns = lookup_qualified_name (std_node, "ranges");
+  if (TREE_CODE (ranges_ns) != NAMESPACE_DECL)
+    {
+      error_at (loc, "%<std::ranges%> is not a namespace");
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  tree contiguous_range
+    = lookup_qualified_name (ranges_ns, "contiguous_range");
+  if (TREE_CODE (contiguous_range) != TEMPLATE_DECL
+      || !concept_definition_p (contiguous_range))
+    contiguous_range = NULL_TREE;
+  else
+    {
+      tree args = make_tree_vec (1);
+      TREE_VEC_ELT (args, 0) = TREE_TYPE (type);
+      contiguous_range = build2_loc (loc, TEMPLATE_ID_EXPR, boolean_type_node,
+                                    contiguous_range, args);
+      if (!integer_nonzerop (maybe_constant_value (contiguous_range)))
+       contiguous_range = NULL_TREE;
+    }
+  tree valuet = meta_info_type_node;
+  tree ret = NULL_TREE;
+  if (kind != GET_INFO_VEC)
+    {
+      tree args = make_tree_vec (1);
+      TREE_VEC_ELT (args, 0) = TREE_TYPE (type);
+      tree inst = lookup_template_class (get_identifier ("range_value_t"),
+                                        args, /*in_decl*/NULL_TREE,
+                                        /*context*/ranges_ns,
+                                        tf_warning_or_error);
+      inst = complete_type (inst);
+      if (inst == error_mark_node)
+       {
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
+      valuet = TYPE_MAIN_VARIANT (inst);
+      if (kind == REFLECT_CONSTANT_STRING
+         && valuet != char_type_node
+         && valuet != wchar_type_node
+         && valuet != char8_type_node
+         && valuet != char16_type_node
+         && valuet != char32_type_node)
+       {
+         if (!cxx_constexpr_quiet_p (ctx))
+           error_at (loc, "%<reflect_constant_string%> called with %qT "
+                          "rather than %<char%>, %<wchar_t%>, %<char8_t%>, "
+                          "%<char16_t%> or %<char32_t%>", inst);
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
+      /* Check for the reflect_object_string special-case, where r
+        refers to a string literal.  In that case CharT() should not
+        be appended.  */
+      if (kind == REFLECT_CONSTANT_STRING
+         && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE
+         && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) == valuet
+         && TYPE_DOMAIN (TREE_TYPE (type)))
+       {
+         tree a = arg;
+         tree maxv = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (type)));
+         STRIP_NOPS (a);
+         tree at;
+         if (TREE_CODE (a) == ADDR_EXPR
+             && TREE_CODE (TREE_OPERAND (a, 0)) == STRING_CST
+             && tree_fits_uhwi_p (maxv)
+             && ((unsigned) TREE_STRING_LENGTH (TREE_OPERAND (a, 0))
+                 == ((tree_to_uhwi (maxv) + 1)
+                      * tree_to_uhwi (TYPE_SIZE_UNIT (valuet))))
+             && (at = TREE_TYPE (TREE_OPERAND (a, 0)))
+             && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type),
+                                                           at))
+           return TREE_OPERAND (a, 0);
+       }
+      if (kind == REFLECT_CONSTANT_ARRAY)
+       {
+         if (!structural_type_p (valuet))
+           {
+             if (!cxx_constexpr_quiet_p (ctx))
+               {
+                 auto_diagnostic_group d;
+                 error_at (loc, "%<reflect_constant_array%> argument with "
+                                "%qT which is not a structural type", inst);
+                 structural_type_p (valuet, true);
+               }
+             *non_constant_p = true;
+             return NULL_TREE;
+           }
+         TREE_VEC_ELT (args, 0)
+           = build_stub_type (valuet,
+                              cp_type_quals (valuet) | TYPE_QUAL_CONST,
+                              false);
+         if (!is_xible (INIT_EXPR, valuet, args))
+           {
+             if (!cxx_constexpr_quiet_p (ctx))
+               error_at (loc, "%<reflect_constant_array%> argument with %qT "
+                              "which is not copy constructible", inst);
+             *non_constant_p = true;
+             return NULL_TREE;
+           }
+         TREE_VEC_ELT (args, 0) = TREE_TYPE (type);
+         tree instr
+           = lookup_template_class (get_identifier ("range_reference_t"),
+                                    args, /*in_decl*/NULL_TREE,
+                                    /*context*/ranges_ns,
+                                    tf_warning_or_error);
+         instr = complete_type (instr);
+         if (instr == error_mark_node)
+           {
+             *non_constant_p = true;
+             return NULL_TREE;
+           }
+         tree referencet = TYPE_MAIN_VARIANT (instr);
+         TREE_VEC_ELT (args, 0) = referencet;
+         if (!is_xible (INIT_EXPR, valuet, args))
+           {
+             if (!cxx_constexpr_quiet_p (ctx))
+               error_at (loc, "%<reflect_constant_array%> argument with %qT "
+                              "which is not constructible from %qT "
+                              "%<std::ranges::range_reference_t%>",
+                         inst, referencet);
+             *non_constant_p = true;
+             return NULL_TREE;
+           }
+       }
+    }
+  auto_vec<tree, 32> retvec;
+  tree p = convert_from_reference (parm);
+  auto obj_call = [=, &map] (tree obj, tsubst_flags_t complain) {
+    releasing_vec args;
+    vec_safe_push (args, p);
+    tree call = finish_call_expr (obj, &args, true, false, complain);
+    if (call == error_mark_node)
+      return call;
+    cp_walk_tree (&call, replace_parm_r, map, NULL);
+    if (complain != tf_none)
+      return call;
+    call = cxx_eval_constant_expression (ctx, call, vc_prvalue, non_constant_p,
+                                        overflow_p, jump_target);
+    if (*jump_target || *non_constant_p)
+      return NULL_TREE;
+    return call;
+  };
+  auto ret_retvec = [=, &retvec] () {
+    unsigned HOST_WIDE_INT sz = retvec.length ();
+    for (size_t i = 0; i < sz; ++i)
+      {
+       if (INTEGRAL_TYPE_P (valuet))
+         {
+           if (TREE_CODE (retvec[i]) != INTEGER_CST)
+             return throw_exception (loc, ctx,
+                                     "array element not a constant integer",
+                                     fun, non_constant_p, jump_target);
+         }
+       else
+         {
+           gcc_assert (kind == REFLECT_CONSTANT_ARRAY);
+           tree expr = convert_reflect_constant_arg (valuet, retvec[i]);
+           if (expr == error_mark_node)
+             return throw_exception (loc, ctx, "reflect_constant failed",
+                                     fun, non_constant_p, jump_target);
+           if (VAR_P (expr))
+             expr = unshare_expr (DECL_INITIAL (expr));
+           retvec[i] = expr;
+         }
+      }
+    if (kind == REFLECT_CONSTANT_ARRAY && sz == 0)
+      {
+       /* Return std::array <valuet, 0> {}.  */
+       tree args = make_tree_vec (2);
+       TREE_VEC_ELT (args, 0) = valuet;
+       TREE_VEC_ELT (args, 1) = size_zero_node;
+       tree inst = lookup_template_class (get_identifier ("array"), args,
+                                          /*in_decl*/NULL_TREE,
+                                          /*context*/std_node,
+                                          tf_warning_or_error);
+       tree type = complete_type (inst);
+       if (type == error_mark_node)
+         {
+           *non_constant_p = true;
+           return NULL_TREE;
+         }
+       tree ctor = build_constructor (init_list_type_node, nullptr);
+       CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+       TREE_CONSTANT (ctor) = true;
+       TREE_STATIC (ctor) = true;
+       tree r = finish_compound_literal (type, ctor, tf_warning_or_error,
+                                         fcl_functional);
+       if (TREE_CODE (r) == TARGET_EXPR)
+         r = TARGET_EXPR_INITIAL (r);
+       return r;
+      }
+    unsigned esz = tree_to_uhwi (TYPE_SIZE_UNIT (valuet));
+    unsigned last = kind == REFLECT_CONSTANT_STRING ? esz : 0;
+    tree index = build_index_type (size_int (last ? sz : sz - 1));
+    tree at = build_array_type (valuet, index);
+    at = cp_build_qualified_type (at, TYPE_QUAL_CONST);
+    if (kind == REFLECT_CONSTANT_STRING
+       || ((valuet == char_type_node
+            || valuet == wchar_type_node
+            || valuet == char8_type_node
+            || valuet == char16_type_node
+            || valuet == char32_type_node)
+           && integer_zerop (retvec.last ())))
+      {
+       unsigned HOST_WIDE_INT szt = sz * esz;
+       char *p;
+       if (szt < 4096)
+         p = XALLOCAVEC (char, szt + last);
+       else
+         p = XNEWVEC (char, szt + last);
+       for (size_t i = 0; i < sz; ++i)
+         native_encode_expr (retvec[i], (unsigned char *) p + i * esz,
+                             esz, 0);
+       if (last)
+         memset (p + szt, '\0', last);
+       tree ret = build_string (szt + last, p);
+       TREE_TYPE (ret) = at;
+       TREE_CONSTANT (ret) = 1;
+       TREE_READONLY (ret) = 1;
+       TREE_STATIC (ret) = 1;
+       if (szt >= 4096)
+         XDELETEVEC (p);
+       return ret;
+      }
+    vec<constructor_elt, va_gc> *elts = nullptr;
+    for (unsigned i = 0; i < sz; ++i)
+      CONSTRUCTOR_APPEND_ELT (elts, bitsize_int (i), retvec[i]);
+    return build_constructor (at, elts);
+  };
+  /* If true, call std::ranges::data (p) and std::ranges::size (p)
+     and if that works out and what the former returns can be handled,
+     grab the elements from the initializer of the decl pointed by the
+     first expression.  p has to be convert_from_reference (PARM_DECL)
+     rather than its value, otherwise it is not considered lvalue.  */
+  if (contiguous_range)
+    {
+      tree data = lookup_qualified_name (ranges_ns, "data");
+      tree size = lookup_qualified_name (ranges_ns, "size");
+      if (TREE_CODE (data) != VAR_DECL || TREE_CODE (size) != VAR_DECL)
+       {
+         error_at (loc, "%<std::ranges::data%> or %<std::ranges::size%> "
+                        "are not customization point objects");
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
+      data = obj_call (data, tf_none);
+      if (error_operand_p (data))
+       goto non_contiguous;
+      if (data == NULL_TREE)
+       return NULL_TREE;
+      size = obj_call (size, tf_none);
+      if (error_operand_p (size))
+       goto non_contiguous;
+      if (size == NULL_TREE)
+       return NULL_TREE;
+      if (!tree_fits_uhwi_p (size) || tree_to_uhwi (size) > INT_MAX)
+       goto non_contiguous;
+      if (integer_zerop (size))
+       {
+         if (kind == GET_INFO_VEC)
+           return make_tree_vec (0);
+         return ret_retvec ();
+       }
+      STRIP_NOPS (data);
+      unsigned HOST_WIDE_INT minidx = 0, pplus = 0;
+      if (TREE_CODE (data) == POINTER_PLUS_EXPR
+         && tree_fits_uhwi_p (TREE_OPERAND (data, 1))
+         && !wi::neg_p (wi::to_wide (TREE_OPERAND (data, 1))))
+       {
+         pplus = tree_to_uhwi (TREE_OPERAND (data, 1));
+         data = TREE_OPERAND (data, 0);
+         STRIP_NOPS (data);
+       }
+      if (TREE_CODE (data) != ADDR_EXPR)
+       goto non_contiguous;
+      data = TREE_OPERAND (data, 0);
+      if (TREE_CODE (data) == ARRAY_REF
+         && tree_fits_uhwi_p (TREE_OPERAND (data, 1)))
+       {
+         minidx = tree_to_uhwi (TREE_OPERAND (data, 1));
+         data = TREE_OPERAND (data, 0);
+       }
+      data = cxx_eval_constant_expression (ctx, data, vc_prvalue,
+                                          non_constant_p, overflow_p,
+                                          jump_target);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      if (TREE_CODE (TREE_TYPE (data)) != ARRAY_TYPE
+         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (data))) != valuet)
+       goto non_contiguous;
+      if (pplus
+         && (pplus % tree_to_uhwi (TYPE_SIZE_UNIT (valuet))) != 0)
+       goto non_contiguous;
+      minidx += pplus / tree_to_uhwi (TYPE_SIZE_UNIT (valuet));
+      if (kind != GET_INFO_VEC && TREE_CODE (data) == STRING_CST)
+       {
+         unsigned esz = tree_to_uhwi (TYPE_SIZE_UNIT (valuet));
+         unsigned HOST_WIDE_INT sz = tree_to_uhwi (size) * esz;
+         if (minidx > INT_MAX
+             || (unsigned) TREE_STRING_LENGTH (data) < sz + minidx * esz)
+           goto non_contiguous;
+         if (kind == REFLECT_CONSTANT_ARRAY && sz == 0)
+           return ret_retvec ();
+         tree index
+           = build_index_type (size_int ((kind == REFLECT_CONSTANT_ARRAY
+                                          ? -1 : 0) + tree_to_uhwi (size)));
+         tree at = build_array_type (valuet, index);
+         at = cp_build_qualified_type (at, TYPE_QUAL_CONST);
+         const unsigned char *q
+           = (const unsigned char *) TREE_STRING_POINTER (data);
+         q += minidx * esz;
+         if (kind == REFLECT_CONSTANT_ARRAY)
+           {
+             unsigned HOST_WIDE_INT i;
+             for (i = 0; i < esz; ++i)
+               if (q[sz - esz + i])
+                 break;
+             if (i != esz)
+               {
+                 /* Not a NUL terminated string.  Build a CONSTRUCTOR
+                    instead.  */
+                 for (i = 0; i < sz; i += esz)
+                   {
+                     tree t = native_interpret_expr (valuet, q + i, sz);
+                     retvec.safe_push (t);
+                   }
+                 return ret_retvec ();
+               }
+           }
+         char *p;
+         if (sz < 4096)
+           p = XALLOCAVEC (char, sz + esz);
+         else
+           p = XNEWVEC (char, sz + esz);
+         memcpy (p, q, sz);
+         memset (p + sz, '\0', esz);
+         ret = build_string (sz + (kind == REFLECT_CONSTANT_ARRAY
+                                   ? 0 : esz), p);
+         TREE_TYPE (ret) = at;
+         TREE_CONSTANT (ret) = 1;
+         TREE_READONLY (ret) = 1;
+         TREE_STATIC (ret) = 1;
+         if (sz >= 4096)
+           XDELETEVEC (p);
+         return ret;
+       }
+      if (TREE_CODE (data) != CONSTRUCTOR)
+       goto non_contiguous;
+      unsigned sz = tree_to_uhwi (size), i;
+      unsigned HOST_WIDE_INT j = 0;
+      tree *r, null = NULL_TREE;
+      if (kind == GET_INFO_VEC)
+       {
+         ret = make_tree_vec (sz);
+         r = TREE_VEC_BEGIN (ret);
+         null = get_null_reflection ();
+       }
+      else
+       {
+         retvec.safe_grow (sz, true);
+         r = retvec.address ();
+       }
+      for (i = 0; i < sz; ++i)
+       r[i] = null;
+      tree field, value;
+      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (data), i, field, value)
+       if (field == NULL_TREE)
+         {
+           if (j >= minidx && j - minidx < sz)
+             r[j - minidx] = value;
+           ++j;
+         }
+       else if (TREE_CODE (field) == RANGE_EXPR)
+         {
+           tree lo = TREE_OPERAND (field, 0);
+           tree hi = TREE_OPERAND (field, 1);
+           if (!tree_fits_uhwi_p (lo) || !tree_fits_uhwi_p (hi))
+             goto non_contiguous;
+           unsigned HOST_WIDE_INT m = tree_to_uhwi (hi);
+           for (j = tree_to_uhwi (lo); j <= m; ++j)
+             if (j >= minidx && j - minidx < sz)
+               r[j - minidx] = value;
+         }
+       else if (tree_fits_uhwi_p (field))
+         {
+           j = tree_to_uhwi (field);
+           if (j >= minidx && j - minidx < sz)
+             r[j - minidx] = value;
+           ++j;
+         }
+       else
+         goto non_contiguous;
+      if (kind == GET_INFO_VEC)
+       return ret;
+      for (i = 0; i < sz; ++i)
+       if (r[i] == NULL_TREE || !tree_fits_shwi_p (r[i]))
+         goto non_contiguous;
+      return ret_retvec ();
+    }
+ non_contiguous:
+  /* Otherwise, do it the slower way.  Initialize two temporaries,
+     one to std::ranges::base (p) and another to std::ranges::end (p)
+     and use a loop.  */
+  tree begin = lookup_qualified_name (ranges_ns, "begin");
+  tree end = lookup_qualified_name (ranges_ns, "end");
+  if (TREE_CODE (begin) != VAR_DECL || TREE_CODE (end) != VAR_DECL)
+    {
+      error_at (loc, "missing %<std::ranges::begin%> or %<std::ranges::end%>");
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  begin = obj_call (begin, tf_warning_or_error);
+  if (error_operand_p (begin))
+    {
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  end = obj_call (end, tf_warning_or_error);
+  if (error_operand_p (end))
+    {
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  if (!CLASS_TYPE_P (TREE_TYPE (begin)) && !POINTER_TYPE_P (TREE_TYPE (begin)))
+    {
+      error_at (loc, "incorrect type %qT of %<std::ranges::begin(arg)%>",
+               TREE_TYPE (begin));
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  if (VOID_TYPE_P (TREE_TYPE (end)))
+    {
+      error_at (loc, "incorrect type %qT of %<std::ranges::end(arg)%>",
+               TREE_TYPE (end));
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  begin = get_target_expr (begin);
+  end = get_target_expr (end);
+  begin = cxx_eval_constant_expression (ctx, begin, vc_glvalue, non_constant_p,
+                                       overflow_p, jump_target);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  end = cxx_eval_constant_expression (ctx, end, vc_glvalue, non_constant_p,
+                                     overflow_p, jump_target);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  tree cmp = build_new_op (loc, NE_EXPR, LOOKUP_NORMAL, begin, end,
+                          tf_warning_or_error);
+  tree deref = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, begin,
+                            NULL_TREE, tf_warning_or_error);
+  tree inc = build_new_op (loc, PREINCREMENT_EXPR, LOOKUP_NORMAL, begin,
+                          NULL_TREE, tf_warning_or_error);
+  cmp = condition_conversion (cmp);
+  if (error_operand_p (cmp)
+      || error_operand_p (deref)
+      || error_operand_p (inc))
+    {
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  // TODO: For REFLECT_CONSTANT_* handle proxy iterators.
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (deref)) != valuet)
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "unexpected type %qT of iterator dereference",
+                 TREE_TYPE (deref));
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  retvec.truncate (0);
+  /* while (begin != end) { push (*begin); ++begin; }  */
+  do
+    {
+      tree t = cxx_eval_constant_expression (ctx, cmp, vc_prvalue,
+                                            non_constant_p, overflow_p,
+                                            jump_target);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      if (integer_zerop (t))
+       break;
+      t = cxx_eval_constant_expression (ctx, deref, vc_prvalue, non_constant_p,
+                                       overflow_p, jump_target);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      retvec.safe_push (t);
+      cxx_eval_constant_expression (ctx, inc, vc_discard, non_constant_p,
+                                   overflow_p, jump_target);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  while (true);
+  if (kind != GET_INFO_VEC)
+    return ret_retvec ();
+  ret = make_tree_vec (retvec.length ());
+  tree v;
+  unsigned int i;
+  FOR_EACH_VEC_ELT (retvec, i, v)
+    TREE_VEC_ELT (ret, i) = v;
+  return ret;
+}
+
+/* Extract the N-th reflection_range argument from a metafunction call CALL
+   and return it as TREE_VEC.  */
+
+static tree
+get_info_vec (location_t loc, const constexpr_ctx *ctx, tree call, int n,
+             bool *non_constant_p, bool *overflow_p, tree *jump_target,
+             tree fun)
+{
+  return get_range_elts (loc, ctx, call, n, non_constant_p, overflow_p,
+                        jump_target, GET_INFO_VEC, fun);
+}
+
+/* Create std::meta::exception{ what, from }.  WHAT is the string for what(),
+   and FROM is the info for from().  */
+
+static tree
+get_meta_exception_object (location_t loc, const char *what, tree from,
+                          bool *non_constant_p)
+{
+  /* Don't throw in a template.  */
+  // TODO For -fno-exceptions, report an error.
+  if (processing_template_decl)
+    {
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+
+  tree type = lookup_qualified_name (std_meta_node, "exception",
+                                    LOOK_want::TYPE, /*complain*/true);
+  if (TREE_CODE (type) != TYPE_DECL || !CLASS_TYPE_P (TREE_TYPE (type)))
+    {
+      error_at (loc, "couldn%'t throw %qs", "std::meta::exception");
+      return NULL_TREE;
+    }
+  type = TREE_TYPE (type);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  what = _(what);
+  /* Translate what from SOURCE_CHARSET to exec charset.  */
+  cpp_string istr, ostr;
+  istr.len = strlen (what) + 1;
+  istr.text = (const unsigned char *) what;
+  if (!cpp_translate_string (parse_in, &istr, &ostr, CPP_STRING, false))
+    {
+      what = "";
+      ostr.text = NULL;
+    }
+  else
+    what = (const char *) ostr.text;
+  if (TREE_CODE (from) == FUNCTION_DECL && DECL_TEMPLATE_INFO (from))
+    from = DECL_TI_TEMPLATE (from);
+  tree string_lit = build_string (strlen (what) + 1, what);
+  free (const_cast <unsigned char *> (ostr.text));
+  TREE_TYPE (string_lit) = char_array_type_node;
+  string_lit = fix_string_type (string_lit);
+  CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, string_lit);
+  CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, get_reflection_raw (loc, from));
+  tree ctor = build_constructor (init_list_type_node, elts);
+  CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+  TREE_CONSTANT (ctor) = true;
+  TREE_STATIC (ctor) = true;
+  return finish_compound_literal (type, ctor, tf_warning_or_error,
+                                 fcl_functional);
+}
+
+/* Perform 'throw std::meta::exception{...}'.  MSGID is the string for what(),
+   FROM is the reflection for from().  */
+
+static tree
+throw_exception (location_t loc, const constexpr_ctx *ctx, const char *msgid,
+                tree from, bool *non_constant_p, tree *jump_target)
+{
+  if (tree obj = get_meta_exception_object (loc, msgid, from, non_constant_p))
+    *jump_target = cxa_allocate_and_throw_exception (loc, ctx, obj);
+  return NULL_TREE;
+}
+
+/* Wrapper around throw_exception to complain that the reflection does not
+   represent a type.  */
+
+static tree
+throw_exception_nontype (location_t loc, const constexpr_ctx *ctx,
+                        tree from, bool *non_constant_p, tree *jump_target)
+{
+  return throw_exception (loc, ctx,
+                         "reflection does not represent a type",
+                         from, non_constant_p, jump_target);
+}
+
+/* Wrapper around throw_exception to complain that the reflection does not
+   represent something that satisfies has_template_arguments.  */
+
+static tree
+throw_exception_notargs (location_t loc, const constexpr_ctx *ctx,
+                        tree from, bool *non_constant_p, tree *jump_target)
+{
+  return throw_exception (loc, ctx,
+                         "reflection does not have template arguments",
+                         from, non_constant_p, jump_target);
+}
+
+/* Wrapper around throw_exception to complain that the reflection does not
+   represent a function or a function type.  */
+
+static tree
+throw_exception_nofn (location_t loc, const constexpr_ctx *ctx,
+                     tree from, bool *non_constant_p, tree *jump_target)
+{
+  return throw_exception (loc, ctx, "reflection does not represent a "
+                                   "function or function type",
+                         from, non_constant_p, jump_target);
+}
+
+/* The values of std::meta::operators enumerators corresponding to
+   the ovl_op_code and IDENTIFIER_ASSIGN_OP_P pair.  */
+
+static unsigned char meta_operators[2][OVL_OP_MAX];
+
+/* Init the meta_operators table if not yet initialized.  */
+
+static void
+maybe_init_meta_operators (location_t loc)
+{
+  if (meta_operators[0][OVL_OP_ERROR_MARK])
+    return;
+  meta_operators[0][OVL_OP_ERROR_MARK] = 1;
+  tree operators = lookup_qualified_name (std_meta_node, "operators");
+  if (TREE_CODE (operators) != TYPE_DECL
+      || TREE_CODE (TREE_TYPE (operators)) != ENUMERAL_TYPE)
+    {
+    fail:
+      error_at (loc, "unexpected %<std::meta::operators%>");
+      return;
+    }
+  char buf[sizeof "op_greater_greater_equals"];
+  memcpy (buf, "op_", 3);
+  for (int i = 0; i < 2; ++i)
+    for (int j = OVL_OP_ERROR_MARK + 1; j < OVL_OP_MAX; ++j)
+      if (ovl_op_info[i][j].meta_name)
+       {
+         strcpy (buf + 3, ovl_op_info[i][j].meta_name);
+         tree id = get_identifier (buf);
+         tree t = lookup_enumerator (TREE_TYPE (operators), id);
+         if (t == NULL_TREE || TREE_CODE (t) != CONST_DECL)
+           goto fail;
+         tree v = DECL_INITIAL (t);
+         if (!tree_fits_uhwi_p (v) || tree_to_uhwi (v) > UCHAR_MAX)
+           goto fail;
+         meta_operators[i][j] = tree_to_uhwi (v);
+       }
+}
+
+/* Process std::meta::is_variable.
+   Returns: true if r represents a variable.  Otherwise, false.  */
+
+static tree
+eval_is_variable (const_tree r, reflect_kind kind)
+{
+  /* ^^param is a variable but parameters_of(parent_of(^^param))[0] is not.  */
+  if ((TREE_CODE (r) == PARM_DECL && kind != REFLECT_PARM)
+      || (VAR_P (r)
+         && kind == REFLECT_UNDEF
+         /* A structured binding is not a variable.  */
+         && !(DECL_DECOMPOSITION_P (r) && !DECL_DECOMP_IS_BASE (r)))
+      || (VAR_P (r)
+         /* Underlying variable of tuple using structured binding is a
+            variable.  */
+         && kind == REFLECT_VAR
+         && DECL_DECOMPOSITION_P (r)
+         && !DECL_DECOMP_IS_BASE (r)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_type.
+   Returns: true if r represents an entity whose underlying entity is
+   a type.  Otherwise, false.  */
+
+static tree
+eval_is_type (const_tree r)
+{
+  /* Null reflection isn't a type.  */
+  if (TYPE_P (r) && r != unknown_type_node)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_type_alias.
+   Returns: true if r represents a type alias.  Otherwise, false.  */
+
+static tree
+eval_is_type_alias (const_tree r)
+{
+  if (TYPE_P (r) && typedef_variant_p (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_namespace.
+   Returns: true if r represents an entity whose underlying entity is
+   a namespace.  Otherwise, false.  */
+
+static tree
+eval_is_namespace (const_tree r)
+{
+  if (TREE_CODE (r) == NAMESPACE_DECL)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_namespace_alias.
+   Returns: true if r represents a namespace alias.  Otherwise, false.  */
+
+static tree
+eval_is_namespace_alias (const_tree r)
+{
+  if (TREE_CODE (r) == NAMESPACE_DECL && DECL_NAMESPACE_ALIAS (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_function.
+   Returns: true if r represents a function.  Otherwise, false.  */
+
+static tree
+eval_is_function (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (TREE_CODE (r) == FUNCTION_DECL)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_function_template.
+   Returns: true if r represents a function template.  Otherwise, false.  */
+
+static tree
+eval_is_function_template (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (DECL_FUNCTION_TEMPLATE_P (r))
+    return boolean_true_node;
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_variable_template.
+   Returns: true if r represents a variable template.  Otherwise, false.  */
+
+static tree
+eval_is_variable_template (tree r)
+{
+  if (variable_template_p (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_class_template.
+   Returns: true if r represents a class template.  Otherwise, false.  */
+
+static tree
+eval_is_class_template (const_tree r)
+{
+  if (DECL_CLASS_TEMPLATE_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_alias_template.
+   Returns: true if r represents an alias template.  Otherwise, false.  */
+
+static tree
+eval_is_alias_template (const_tree r)
+{
+  if (DECL_ALIAS_TEMPLATE_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_concept.
+   Returns: true if r represents a concept.  Otherwise, false.  */
+
+static tree
+eval_is_concept (const_tree r)
+{
+  if (concept_definition_p (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_object.
+   Returns: true if r represents an object.  Otherwise, false.  */
+
+static tree
+eval_is_object (reflect_kind kind)
+{
+  if (kind == REFLECT_OBJECT)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_value.
+   Returns: true if r represents a value.  Otherwise, false.  */
+
+static tree
+eval_is_value (reflect_kind kind)
+{
+  if (kind == REFLECT_VALUE)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Like get_info_vec, but throw exception if any of the elements aren't
+   eval_is_type reflections and change their content to the corresponding
+   REFLECT_EXPR_HANDLE.  */
+
+static tree
+get_type_info_vec (location_t loc, const constexpr_ctx *ctx, tree call, int n,
+                  bool *non_constant_p, bool *overflow_p, tree *jump_target,
+                  tree fun)
+{
+  tree vec = get_info_vec (loc, ctx, call, n, non_constant_p, overflow_p,
+                          jump_target, fun);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  for (int i = 0; i < TREE_VEC_LENGTH (vec); i++)
+    {
+      tree type = REFLECT_EXPR_HANDLE (TREE_VEC_ELT (vec, i));
+      if (eval_is_type (type) != boolean_true_node)
+       return throw_exception_nontype (loc, ctx, fun, non_constant_p,
+                                       jump_target);
+      TREE_VEC_ELT (vec, i) = type;
+    }
+  return vec;
+}
+
+/* Process std::meta::is_structured_binding.
+   Returns: true if r represents a structured binding.  Otherwise, false.  */
+
+static tree
+eval_is_structured_binding (const_tree r, reflect_kind kind)
+{
+  if (DECL_DECOMPOSITION_P (r)
+      && !DECL_DECOMP_IS_BASE (r)
+      && kind != REFLECT_VAR)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_class_member.
+   Returns: true if r represents a class member.  Otherwise, false.  */
+
+static tree
+eval_is_class_member (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == CONST_DECL)
+    {
+      /* [class.mem.general]/5 - The enumerators of an unscoped enumeration
+        defined in the class are members of the class.  */
+      if (UNSCOPED_ENUM_P (DECL_CONTEXT (r)))
+       r = DECL_CONTEXT (r);
+      else
+       return boolean_false_node;
+    }
+  else if (TYPE_P (r) && typedef_variant_p (r))
+    r = TYPE_NAME (r);
+  if (DECL_P (r) && DECL_CLASS_SCOPE_P (r))
+    return boolean_true_node;
+  else if (TYPE_P (r) && TYPE_CLASS_SCOPE_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* For direct base class relationship R return the binfo related
+   to the derived type.  */
+
+static tree
+direct_base_parent_binfo (tree r)
+{
+  /* Looping needed for multiple virtual inheritance.  */
+  while (BINFO_INHERITANCE_CHAIN (r))
+    r = BINFO_INHERITANCE_CHAIN (r);
+  return r;
+}
+
+/* For direct base class relationship R return the derived type
+   (i.e. when R is (D, B) it returns D).  */
+
+tree
+direct_base_parent (tree r)
+{
+  return BINFO_TYPE (direct_base_parent_binfo (r));
+}
+
+/* Helper function for eval_is_{public, protected, private}.  */
+
+static tree
+eval_is_expected_access (tree r, reflect_kind kind, tree expected_access)
+{
+  if (eval_is_class_member (r) == boolean_true_node)
+    {
+      r = maybe_get_reflection_fndecl (r);
+
+      if (TYPE_P (r))
+       {
+         if (TYPE_NAME (r) == NULL_TREE || !DECL_P (TYPE_NAME (r)))
+           return boolean_false_node;
+         r = TYPE_NAME (r);
+       }
+
+      bool matches = false;
+      if (expected_access == access_private_node)
+       matches = TREE_PRIVATE (r);
+      else if (expected_access == access_protected_node)
+       matches = TREE_PROTECTED (r);
+      else if (expected_access == access_public_node)
+       matches = !(TREE_PRIVATE (r) || TREE_PROTECTED (r));
+      else
+       gcc_unreachable ();
+
+      if (matches)
+       return boolean_true_node;
+      else
+       return boolean_false_node;
+    }
+
+  if (kind == REFLECT_BASE)
+    {
+      gcc_assert (TREE_CODE (r) == TREE_BINFO);
+      tree c = direct_base_parent_binfo (r);
+
+      tree base_binfo;
+      for (unsigned ix = 0; BINFO_BASE_ITERATE (c, ix, base_binfo); ix++)
+       if (base_binfo == r)
+         {
+           tree access = BINFO_BASE_ACCESS (c, ix);
+           if (access == expected_access)
+             return boolean_true_node;
+           else
+             return boolean_false_node;
+         }
+      gcc_unreachable ();
+    }
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_public.
+   Returns: true if r represents either:
+   - a class member or unnamed bit-field that is public or
+   - a direct base class relationship (D, B) for which
+   B is a public base class of D.
+   Otherwise, false.  */
+
+static tree
+eval_is_public (tree r, reflect_kind kind)
+{
+  return eval_is_expected_access (r, kind, access_public_node);
+}
+
+/* Process std::meta::is_protected.
+   Returns: true if r represents either:
+   - a class member or unnamed bit-field that is protected, or
+   - a direct base class relationship (D, B) for which
+   B is a protected base class of D.
+   Otherwise, false.  */
+
+static tree
+eval_is_protected (tree r, reflect_kind kind)
+{
+  return eval_is_expected_access (r, kind, access_protected_node);
+}
+
+/* Process std::meta::is_private
+   Returns: true if r represents either:
+   - a class member or unnamed bit-field that is private, or
+   - a direct base class relationship (D, B) for which
+   B is a private base class of D.
+   Otherwise, false.  */
+
+static tree
+eval_is_private (tree r, reflect_kind kind)
+{
+  return eval_is_expected_access (r, kind, access_private_node);
+}
+
+/* Process std::meta::is_virtual.
+   Returns: true if r represents either a virtual member function or a direct
+   base class relationship (D,B) for which B is a virtual base class of D.
+   Otherwise, false.  */
+
+static tree
+eval_is_virtual (tree r, reflect_kind kind)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_VIRTUAL_P (r))
+    return boolean_true_node;
+
+  if (kind == REFLECT_BASE && BINFO_VIRTUAL_P (r))
+    return boolean_true_node;
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_pure_virtual.
+   Returns: true if r represents a member function that is pure virtual.
+   Otherwise, false.  */
+
+static tree
+eval_is_pure_virtual (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_PURE_VIRTUAL_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Helper function for eval_is_override, return true if FNDECL in TYPE
+   overrides another function.  */
+
+static bool
+is_override (tree type, tree fndecl)
+{
+  tree binfo = TYPE_BINFO (type), base_binfo;
+
+  for (unsigned ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+    {
+      tree basetype = BINFO_TYPE (base_binfo);
+      if (TYPE_POLYMORPHIC_P (basetype))
+       {
+         if (look_for_overrides_here (basetype, fndecl))
+           return true;
+         if (is_override (basetype, fndecl))
+           return true;
+       }
+    }
+  return false;
+}
+
+/* Process std::meta::is_override.
+   Returns: true if r represents a member function that overrides another
+   member function.  Otherwise, false.  */
+
+static tree
+eval_is_override (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && DECL_VIRTUAL_P (r)
+      && !DECL_STATIC_FUNCTION_P (r)
+      && is_override (DECL_CONTEXT (r), r))
+    return boolean_true_node;
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_namespace_member.
+   Returns: true if r represents a namespace member.  Otherwise, false.  */
+
+static tree
+eval_is_namespace_member (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == CONST_DECL)
+    {
+      if (UNSCOPED_ENUM_P (DECL_CONTEXT (r)))
+       r = DECL_CONTEXT (r);
+      else
+       return boolean_false_node;
+    }
+  else if (TYPE_P (r) && typedef_variant_p (r))
+    r = TYPE_NAME (r);
+  if (r == global_namespace || r == unknown_type_node)
+    return boolean_false_node;
+  if (DECL_P (r) && DECL_NAMESPACE_SCOPE_P (r))
+    return boolean_true_node;
+  else if (TYPE_P (r) && TYPE_NAMESPACE_SCOPE_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_nonstatic_data_member.
+   Returns: true if r represents a non-static data member.
+   Otherwise, false.  */
+
+static tree
+eval_is_nonstatic_data_member (const_tree r)
+{
+  if (TREE_CODE (r) == FIELD_DECL && !DECL_UNNAMED_BIT_FIELD (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_static_member.
+   Returns: true if r represents a static member.
+   Otherwise, false.  */
+
+static tree
+eval_is_static_member (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (r))
+    return boolean_true_node;
+  else if (VAR_P (r) && DECL_CLASS_SCOPE_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_base.
+   Returns: true if r represents a direct base class relationship.
+   Otherwise, false.  */
+
+static tree
+eval_is_base (tree r, reflect_kind kind)
+{
+  if (kind == REFLECT_BASE)
+    {
+      gcc_assert (TREE_CODE (r) == TREE_BINFO);
+      return boolean_true_node;
+    }
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_default_member_initializer.
+   Returns: true if r represents a non-static data member that has a default
+   member initializer.  Otherwise, false.  */
+
+static tree
+eval_has_default_member_initializer (const_tree r)
+{
+  if (TREE_CODE (r) == FIELD_DECL
+      && !DECL_UNNAMED_BIT_FIELD (r)
+      && DECL_INITIAL (r) != NULL_TREE)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_static_storage_duration.
+   Returns: true if r represents an object or variable that has static
+   storage duration.  Otherwise, false.  */
+
+static tree
+eval_has_static_storage_duration (const_tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_true_node
+      && decl_storage_duration (CONST_CAST_TREE (r)) == dk_static)
+    return boolean_true_node;
+  /* This includes DECL_NTTP_OBJECT_P objects.  */
+  else if (eval_is_object (kind) == boolean_true_node)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_thread_storage_duration.
+   Returns: true if r represents an object or variable that has thread
+   storage duration.  Otherwise, false.  */
+
+static tree
+eval_has_thread_storage_duration (const_tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_true_node
+      && decl_storage_duration (CONST_CAST_TREE (r)) == dk_thread)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_automatic_storage_duration.
+   Returns: true if r represents an object or variable that has automatic
+   storage duration.  Otherwise, false.  */
+
+static tree
+eval_has_automatic_storage_duration (const_tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_true_node
+      && decl_storage_duration (CONST_CAST_TREE (r)) == dk_auto)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_mutable_member.
+   Returns: true if r represents a mutable non-static data member.
+   Otherwise, false.  */
+
+static tree
+eval_is_mutable_member (tree r)
+{
+  if (TREE_CODE (r) == FIELD_DECL
+      && !DECL_UNNAMED_BIT_FIELD (r)
+      && DECL_MUTABLE_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_template.
+   Returns: true if r represents a function template, class template, variable
+   template, alias template, or concept.  Otherwise, false.  */
+
+static tree
+eval_is_template (tree r)
+{
+  if (eval_is_function_template (r) == boolean_true_node
+      || eval_is_class_template (r) == boolean_true_node
+      || eval_is_variable_template (r) == boolean_true_node
+      || eval_is_alias_template (r) == boolean_true_node
+      || eval_is_concept (r) == boolean_true_node)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_function_parameter.
+   Returns: true if r represents a function parameter.  Otherwise, false.  */
+
+static tree
+eval_is_function_parameter (const_tree r, reflect_kind kind)
+{
+  if (kind == REFLECT_PARM)
+    {
+      gcc_checking_assert (TREE_CODE (r) == PARM_DECL);
+      return boolean_true_node;
+    }
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_data_member_spec.
+   Returns: true if r represents a data member description.
+   Otherwise, false.  */
+
+static tree
+eval_is_data_member_spec (const_tree r, reflect_kind kind)
+{
+  if (kind == REFLECT_DATA_MEMBER_SPEC)
+    {
+      gcc_checking_assert (TREE_CODE (r) == TREE_VEC);
+      return boolean_true_node;
+    }
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_explicit_object_parameter.
+   Returns: true if r represents a function parameter that is an explicit
+   object parameter.  Otherwise, false.  */
+
+static tree
+eval_is_explicit_object_parameter (const_tree r, reflect_kind kind)
+{
+  if (eval_is_function_parameter (r, kind) == boolean_true_node
+      && r == DECL_ARGUMENTS (DECL_CONTEXT (r))
+      && DECL_XOBJ_MEMBER_FUNCTION_P (DECL_CONTEXT (r)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_default_argument.
+   Returns: If r represents a parameter P of a function F, then:
+   -- If F is a specialization of a templated function T, then true if there
+      exists a declaration D of T that precedes some point in the evaluation
+      context and D specifies a default argument for the parameter of T
+      corresponding to P.  Otherwise, false.
+   -- Otherwise, if there exists a declaration D of F that precedes some
+      point in the evaluation context and D specifies a default argument
+      for P, then true.
+   Otherwise, false.  */
+
+static tree
+eval_has_default_argument (tree r, reflect_kind kind)
+{
+  if (eval_is_function_parameter (r, kind) == boolean_false_node)
+    return boolean_false_node;
+  r = maybe_update_function_parm (r);
+  tree fn = DECL_CONTEXT (r);
+  tree args = FUNCTION_FIRST_USER_PARM (fn);
+  tree types = FUNCTION_FIRST_USER_PARMTYPE (fn);
+  while (r != args)
+    {
+      args = DECL_CHAIN (args);
+      types = TREE_CHAIN (types);
+    }
+  if (TREE_PURPOSE (types))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_ellipsis_parameter.
+   Returns: true if r represents a function or function type that has an
+   ellipsis in its parameter-type-list.  Otherwise, false.  */
+
+static tree
+eval_has_ellipsis_parameter (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL)
+    r = TREE_TYPE (r);
+  if (FUNC_OR_METHOD_TYPE_P (r) && stdarg_p (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_deleted.
+   Returns: true if r represents a function that is deleted.
+   Otherwise, false.  */
+
+static tree
+eval_is_deleted (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_MAYBE_DELETED (r))
+    {
+      ++function_depth;
+      maybe_synthesize_method (r);
+      --function_depth;
+    }
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_DELETED_FN (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_defaulted.
+   Returns: true if r represents a function that is defaulted.
+   Otherwise, false.  */
+
+static tree
+eval_is_defaulted (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_DEFAULTED_FN (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_user_provided.
+   Returns: true if r represents a function that is user-provided.
+   Otherwise, false.  */
+
+static tree
+eval_is_user_provided (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && user_provided_p (r)
+      // TODO: user_provided_p is false for non-members defaulted on
+      // first declaration.
+      && (!DECL_NAMESPACE_SCOPE_P (r) || !DECL_DELETED_FN (r)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_user_declared.
+   Returns: true if r represents a function that is user-declared.
+   Otherwise, false.  */
+
+static tree
+eval_is_user_declared (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && !DECL_ARTIFICIAL (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_explicit.
+   Returns: true if r represents
+   a member function that is declared explicit.
+   Otherwise, false.
+   If r represents a member function template
+   that is declared explicit, is_explicit(r)
+   is still false because in general such queries
+   for templates cannot be answered.  */
+
+static tree
+eval_is_explicit (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_NONCONVERTING_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_bit_field.
+   Returns: true if r represents a bit-field, or if r represents a data member
+   description (T,N,A,W,NUA) for which W is not _|_.  Otherwise, false.  */
+
+static tree
+eval_is_bit_field (const_tree r, reflect_kind kind)
+{
+  if (TREE_CODE (r) == FIELD_DECL && DECL_C_BIT_FIELD (r))
+    return boolean_true_node;
+  else if (kind == REFLECT_DATA_MEMBER_SPEC && TREE_VEC_ELT (r, 3))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_enumerator.
+   Returns: true if r represents an enumerator.  Otherwise, false.  */
+
+static tree
+eval_is_enumerator (const_tree r)
+{
+  /* This doesn't check !DECL_TEMPLATE_PARM_P because such CONST_DECLs
+     would already have been rejected in get_reflection.  */
+  if (TREE_CODE (r) == CONST_DECL)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Get the linkage name for T, or NULL_TREE, if N/A.  */
+
+static tree
+type_linkage_name (tree t)
+{
+  if (TYPE_NAME (t) == NULL_TREE
+      || !DECL_P (TYPE_NAME (t))
+      || (!DECL_IMPLICIT_TYPEDEF_P (TYPE_NAME (t))
+         && TYPE_NAME (t) == TYPE_NAME (TYPE_MAIN_VARIANT (t))
+         && !TYPE_MAIN_DECL (t)))
+    return NULL_TREE;
+
+  return TYPE_NAME (t);
+}
+
+/* Process std::meta::has_internal_linkage.
+   Returns: true if r represents a variable, function, type, template, or
+   namespace whose name has internal linkage.  Otherwise, false.  */
+
+static tree
+eval_has_internal_linkage (tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_false_node
+      && eval_is_function (r) == boolean_false_node
+      && eval_is_type (r) == boolean_false_node
+      && eval_is_template (r) == boolean_false_node
+      && eval_is_namespace (r) == boolean_false_node)
+    return boolean_false_node;
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  if (TYPE_P (r))
+    {
+      r = type_linkage_name (r);
+      if (!r)
+       return boolean_false_node;
+    }
+  if (decl_linkage (r) == lk_internal)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_module_linkage.
+   Returns: true if r represents a variable, function, type, template, or
+   namespace whose name has module linkage.  Otherwise, false.  */
+
+static tree
+eval_has_module_linkage (tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_false_node
+      && eval_is_function (r) == boolean_false_node
+      && eval_is_type (r) == boolean_false_node
+      && eval_is_template (r) == boolean_false_node
+      && eval_is_namespace (r) == boolean_false_node)
+    return boolean_false_node;
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  if (TYPE_P (r))
+    {
+      r = type_linkage_name (r);
+      if (!r)
+       return boolean_false_node;
+    }
+  if (decl_linkage (r) == lk_external
+      && DECL_LANG_SPECIFIC (r)
+      && DECL_MODULE_ATTACH_P (r)
+      && !DECL_MODULE_EXPORT_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_external_linkage.
+   Returns: true if r represents a variable, function, type, template, or
+   namespace whose name has external linkage.  Otherwise, false.  */
+
+static tree
+eval_has_external_linkage (tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_false_node
+      && eval_is_function (r) == boolean_false_node
+      && eval_is_type (r) == boolean_false_node
+      && eval_is_template (r) == boolean_false_node
+      && eval_is_namespace (r) == boolean_false_node)
+    return boolean_false_node;
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  if (TYPE_P (r))
+    {
+      r = type_linkage_name (r);
+      if (!r)
+       return boolean_false_node;
+    }
+  if (decl_linkage (r) == lk_external
+      && !(DECL_LANG_SPECIFIC (r)
+          && DECL_MODULE_ATTACH_P (r)
+          && !DECL_MODULE_EXPORT_P (r)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_c_language_linkage
+   Returns: true if r represents a variable, function, or function type with
+   C language linkage. Otherwise, false.  */
+
+static tree
+eval_has_c_language_linkage (tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_false_node
+      && eval_is_function (r) == boolean_false_node
+      && eval_is_function_type (r) == boolean_false_node)
+    return boolean_false_node;
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  if (TYPE_P (r))
+    {
+      r = type_linkage_name (r);
+      if (!r)
+       return boolean_false_node;
+    }
+  if (decl_linkage (r) != lk_none && DECL_LANGUAGE (r) == lang_c)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_linkage.
+   Returns: true if r represents a variable, function, type, template, or
+   namespace whose name has any linkage.  Otherwise, false.  */
+
+static tree
+eval_has_linkage (tree r, reflect_kind kind)
+{
+  if (eval_is_variable (r, kind) == boolean_false_node
+      && eval_is_function (r) == boolean_false_node
+      && eval_is_type (r) == boolean_false_node
+      && eval_is_template (r) == boolean_false_node
+      && eval_is_namespace (r) == boolean_false_node)
+    return boolean_false_node;
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  if (TYPE_P (r))
+    {
+      r = type_linkage_name (r);
+      if (!r)
+       return boolean_false_node;
+    }
+  if (decl_linkage (r) != lk_none)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_complete_type.
+   Returns: true if is_type(r) is true and there is some point in the
+   evaluation context from which the type represented by dealias(r) is
+   not an incomplete type.  Otherwise, false.  */
+
+static tree
+eval_is_complete_type (const_tree r)
+{
+  if (eval_is_type (r) == boolean_true_node)
+    {
+      complete_type (const_cast<tree> (r));
+      if (COMPLETE_TYPE_P (r))
+       return boolean_true_node;
+    }
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_enumerable_type.
+   A type T is enumerable from a point P if either
+   -- T is a class type complete at point P or
+   -- T is an enumeration type defined by a declaration D such that D is
+      reachable from P but P does not occur within an enum-specifier of D.
+  Returns: true if dealias(r) represents a type that is enumerable from some
+  point in the evaluation context.  Otherwise, false.  */
+
+static tree
+eval_is_enumerable_type (const_tree r)
+{
+  if (CLASS_TYPE_P (r))
+    {
+      complete_type (const_cast<tree> (r));
+      if (COMPLETE_TYPE_P (r))
+       return boolean_true_node;
+     }
+  else if (TREE_CODE (r) == ENUMERAL_TYPE)
+    {
+      r = TYPE_MAIN_VARIANT (r);
+      if (!ENUM_IS_OPAQUE (r) && !ENUM_BEING_DEFINED_P (r))
+       return boolean_true_node;
+    }
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_annotation.
+   Returns: true if r represents an annotation.  Otherwise, false.  */
+
+static tree
+eval_is_annotation (const_tree r, reflect_kind kind)
+{
+  if (kind == REFLECT_ANNOTATION)
+    {
+      gcc_assert (TREE_CODE (r) == TREE_LIST);
+      return boolean_true_node;
+    }
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_conversion_function.
+   Returns: true if r represents a function that is a conversion function.
+   Otherwise, false.  */
+
+static tree
+eval_is_conversion_function (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_CONV_FN_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_operator_function.
+   Returns: true if r represents a function that is an operator function.
+   Otherwise, false.  */
+
+static tree
+eval_is_operator_function (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && DECL_OVERLOADED_OPERATOR_P (r)
+      && !DECL_CONV_FN_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_literal_operator.
+   Returns: true if r represents a function that is a literal operator.
+   Otherwise, false.  */
+
+static tree
+eval_is_literal_operator (const_tree r)
+{
+  /* No MAYBE_BASELINK_FUNCTIONS here because a literal operator
+     must be a non-member function.  */
+  if (TREE_CODE (r) == FUNCTION_DECL && UDLIT_OPER_P (DECL_NAME (r)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_special_member_function.
+   Returns: true if r represents a function that is a special member function.
+   Otherwise, false.  */
+
+static tree
+eval_is_special_member_function (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && special_memfn_p (r) != sfk_none)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_constructor.
+   Returns: true if r represents a function that is a constructor.
+   Otherwise, false.  */
+
+static tree
+eval_is_constructor (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_default_constructor.
+   Returns: true if r represents a function that is a default constructor.
+   Otherwise, false.  */
+
+static tree
+eval_is_default_constructor (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && default_ctor_p (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_copy_constructor.
+   Returns: true if r represents a function that is a copy constructor.
+   Otherwise, false.  */
+
+static tree
+eval_is_copy_constructor (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_COPY_CONSTRUCTOR_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_move_constructor.
+   Returns: true if r represents a function that is a move constructor.
+   Otherwise, false.  */
+
+static tree
+eval_is_move_constructor (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL && DECL_MOVE_CONSTRUCTOR_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_assignment.
+   Returns: true if r represents a function that is an assignment operator.
+   Otherwise, false.  */
+
+static tree
+eval_is_assignment (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && DECL_ASSIGNMENT_OPERATOR_P (r)
+      && DECL_OVERLOADED_OPERATOR_IS (r, NOP_EXPR))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_copy_assignment.
+   Returns: true if r represents a function that is a copy assignment
+   operator.  Otherwise, false.  */
+
+static tree
+eval_is_copy_assignment (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && special_function_p (r) == sfk_copy_assignment)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_move_assignment.
+   Returns: true if r represents a function that is a move assignment
+   operator.  Otherwise, false.  */
+
+static tree
+eval_is_move_assignment (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && special_function_p (r) == sfk_move_assignment)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_destructor.
+   Returns: true if r represents a function that is a destructor.
+   Otherwise, false.  */
+
+static tree
+eval_is_destructor (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (TREE_CODE (r) == FUNCTION_DECL
+      && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_conversion_function_template.
+   Returns: true if r represents a conversion function template.
+   Otherwise, false.  */
+
+static tree
+eval_is_conversion_function_template (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (DECL_FUNCTION_TEMPLATE_P (r) && DECL_CONV_FN_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_operator_function_template.
+   Returns: true if r represents an operator function template.
+   Otherwise, false.  */
+
+static tree
+eval_is_operator_function_template (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (DECL_FUNCTION_TEMPLATE_P (r))
+    {
+      r = STRIP_TEMPLATE (r);
+      if (DECL_OVERLOADED_OPERATOR_P (r) && !DECL_CONV_FN_P (r))
+       return boolean_true_node;
+    }
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_literal_operator_template.
+   Returns: true if r represents a literal operator template.
+   Otherwise, false.  */
+
+static tree
+eval_is_literal_operator_template (tree r)
+{
+  /* No MAYBE_BASELINK_FUNCTIONS here because a literal operator
+     template must be a non-member function template.  */
+  r = OVL_FIRST (r);
+
+  if (DECL_FUNCTION_TEMPLATE_P (r) && UDLIT_OPER_P (DECL_NAME (r)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_constructor_template.
+   Returns: true if r represents a function that is an operator function
+   template.  Otherwise, false.  */
+
+static tree
+eval_is_constructor_template (tree r)
+{
+  r = maybe_get_reflection_fndecl (r);
+
+  if (DECL_FUNCTION_TEMPLATE_P (r) && DECL_CONSTRUCTOR_P (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::operator_of.
+   Returns: The value of the enumerator from the operators whose corresponding
+   operator-function-id is the unqualified name of the entity represented by
+   r.
+   Throws: meta::exception unless r represents an operator function or
+   operator function template.  */
+
+static tree
+eval_operator_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                 bool *non_constant_p, tree *jump_target, tree ret_type,
+                 tree fun)
+{
+  if (eval_is_operator_function (r) == boolean_false_node
+      && eval_is_operator_function_template (r) == boolean_false_node)
+    return throw_exception (loc, ctx,
+                           "reflection does not represent an operator "
+                           "function or operator function template",
+                           fun, non_constant_p, jump_target);
+  r = maybe_get_reflection_fndecl (r);
+  r = STRIP_TEMPLATE (r);
+  maybe_init_meta_operators (loc);
+  int i = IDENTIFIER_ASSIGN_OP_P (DECL_NAME (r)) ? 1 : 0;
+  int j = IDENTIFIER_CP_INDEX (DECL_NAME (r));
+  return build_int_cst (ret_type, meta_operators[i][j]);
+}
+
+/* Helper to build a string literal containing '\0' terminated NAME.
+   ELT_TYPE must be either char_type_node or char8_type_node, and the
+   function takes care of converting the name from SOURCE_CHARSET
+   to ordinary literal charset resp. UTF-8.  Returns the string
+   literal, or NULL_TREE if the conversion failed.  */
+
+static tree
+get_string_literal (const char *name, tree elt_type)
+{
+  cpp_string istr, ostr;
+  istr.len = strlen (name) + 1;
+  istr.text = (const unsigned char *) name;
+  if (!cpp_translate_string (parse_in, &istr, &ostr,
+                            elt_type == char_type_node
+                            ? CPP_STRING : CPP_UTF8STRING, false))
+    return NULL_TREE;
+  name = (const char *) ostr.text;
+  tree ret = build_string_literal (strlen (name) + 1, name, elt_type);
+  free (const_cast <char *> (name));
+  return ret;
+}
+
+/* Process std::meta::{,u8}symbol_of.
+   Returns: A string_view or u8string_view containing the characters of the
+   operator symbol name corresponding to op, respectively encoded with the
+   ordinary literal encoding or with UTF-8.
+   Throws: meta::exception unless the value of op corresponds to one of the
+   enumerators in operators.  */
+
+static tree
+eval_symbol_of (location_t loc, const constexpr_ctx *ctx, tree expr,
+               bool *non_constant_p, tree *jump_target, tree elt_type,
+               tree ret_type, tree fun)
+{
+  maybe_init_meta_operators (loc);
+  if (!tree_fits_uhwi_p (expr))
+    {
+    fail:
+      return throw_exception (loc, ctx,
+                             "operators argument is not a valid operator",
+                             fun, non_constant_p, jump_target);
+    }
+  unsigned HOST_WIDE_INT val = tree_to_uhwi (expr);
+  for (int i = 0; i < 2; ++i)
+    for (int j = OVL_OP_ERROR_MARK + 1; j < OVL_OP_MAX; ++j)
+      if (ovl_op_info[i][j].meta_name && meta_operators[i][j] == val)
+       {
+         const char *name = ovl_op_info[i][j].name;
+         char buf[64];
+         if (const char *sp = strchr (name, ' '))
+           {
+             memcpy (buf, name, sp - name);
+             strcpy (buf + (sp - name), sp + 1);
+             name = buf;
+           }
+         tree str = get_string_literal (name, elt_type);
+         /* Basic character set ought to be better convertible
+            into ordinary literal character set and must be always
+            convertible into UTF-8.  */
+         gcc_checking_assert (str);
+         releasing_vec args (make_tree_vector_single (str));
+         tree r = build_special_member_call (NULL_TREE,
+                                             complete_ctor_identifier,
+                                             &args, ret_type, LOOKUP_NORMAL,
+                                             tf_warning_or_error);
+         return build_cplus_new (ret_type, r, tf_warning_or_error);
+       }
+  goto fail;
+}
+
+/* has-type (exposition only).
+   Returns: true if r represents a value, annotation, object, variable,
+   function whose type does not contain an undeduced placeholder type and
+   that is not a constructor or destructor, enumerator, non-static data
+   member, unnamed bit-field, direct base class relationship, data member
+   description, or function parameter.  Otherwise, false.  */
+
+static bool
+has_type (tree r, reflect_kind kind)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL)
+    {
+      if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
+       return false;
+      if (undeduced_auto_decl (r))
+       return false;
+      return true;
+    }
+  if (CONSTANT_CLASS_P (r)
+      || eval_is_variable (r, kind) == boolean_true_node
+      || eval_is_enumerator (r) == boolean_true_node
+      || TREE_CODE (r) == FIELD_DECL
+      || eval_is_annotation (r, kind) == boolean_true_node
+      || eval_is_function_parameter (r, kind) == boolean_true_node
+      || eval_is_object (kind) == boolean_true_node
+      || eval_is_value (kind) == boolean_true_node
+      || kind == REFLECT_BASE
+      || kind == REFLECT_DATA_MEMBER_SPEC)
+    return true;
+  return false;
+}
+
+/* Helper function for eval_type_of.  Assuming has_type is true, return
+   the std::meta::type_of type (rather than reflection thereof).  */
+
+static tree
+type_of (tree r, reflect_kind kind)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == PARM_DECL && kind == REFLECT_PARM)
+    {
+      r = maybe_update_function_parm (r);
+      tree fn = DECL_CONTEXT (r);
+      tree args = FUNCTION_FIRST_USER_PARM (fn);
+      tree type = FUNCTION_FIRST_USER_PARMTYPE (fn);
+      while (r != args)
+       {
+         args = DECL_CHAIN (args);
+         type = TREE_CHAIN (type);
+       }
+      r = TREE_VALUE (type);
+    }
+  else if (kind == REFLECT_BASE)
+    r = BINFO_TYPE (r);
+  else if (kind == REFLECT_DATA_MEMBER_SPEC)
+    r = TREE_VEC_ELT (r, 0);
+  else if (eval_is_annotation (r, kind) == boolean_true_node)
+    {
+      r = TREE_TYPE (TREE_VALUE (TREE_VALUE (r)));
+      if (CLASS_TYPE_P (r))
+       {
+         int quals = cp_type_quals (r);
+         quals |= TYPE_QUAL_CONST;
+         r = cp_build_qualified_type (r, quals);
+       }
+    }
+  else if (TREE_CODE (r) == FIELD_DECL && DECL_BIT_FIELD_TYPE (r))
+    r = DECL_BIT_FIELD_TYPE (r);
+  else
+    r = TREE_TYPE (r);
+  return strip_typedefs (r);
+}
+
+/* Process std::meta::type_of.  Returns:
+   -- If r represents the ith parameter of a function F, then the ith type
+      in the parameter-type-list of F.
+   -- Otherwise, if r represents a value, object, variable, function,
+      non-static data member, or unnamed bit-field, then the type of what is
+      represented by r.
+   -- Otherwise, if r represents an annotation, then type_of(constant_of(r)).
+   -- Otherwise, if r represents an enumerator N of an enumeration E, then:
+      -- If E is defined by a declaration D that precedes a point P in the
+        evaluation context and P does not occur within an enum-specifier of
+        D, then a reflection of E.
+      -- Otherwise, a reflection of the type of N prior to the closing brace
+        of the enum-specifier as specified in [dcl.enum].
+   -- Otherwise, if r represents a direct base class relationship (D,B), then
+      a reflection of B.
+   -- Otherwise, for a data member description (T,N,A,W,NUA), a reflection of
+      the type T.  */
+
+static tree
+eval_type_of (location_t loc, const constexpr_ctx *ctx, tree r,
+             reflect_kind kind, bool *non_constant_p, tree *jump_target,
+             tree fun)
+{
+  if (!has_type (r, kind))
+    return throw_exception (loc, ctx, "reflection does not have a type",
+                           fun, non_constant_p, jump_target);
+  return get_reflection_raw (loc, type_of (r, kind));
+}
+
+/* Process std::meta::source_location_of.
+   Returns: If r represents a value, a type other than a class type or an
+   enumeration type, the global namespace, or a data member description,
+   then source_location{}.  Otherwise, an implementation-defined
+   source_location value.  */
+
+static tree
+eval_source_location_of (location_t loc, tree r, reflect_kind kind,
+                        tree std_source_location)
+{
+  if (!NON_UNION_CLASS_TYPE_P (std_source_location))
+    {
+      error_at (loc, "%qT is not a class type", std_source_location);
+      return error_mark_node;
+    }
+  location_t rloc = UNKNOWN_LOCATION;
+  if (kind == REFLECT_BASE)
+    /* We don't track location_t of the base specifiers, so at least
+       for now use location_t of the base parent (i.e. the derived
+       class).  */
+    r = direct_base_parent (r);
+  if (OVERLOAD_TYPE_P (r) || (TYPE_P (r) && typedef_variant_p (r)))
+    rloc = DECL_SOURCE_LOCATION (TYPE_NAME (r));
+  else if (DECL_P (r) && r != global_namespace)
+    rloc = DECL_SOURCE_LOCATION (r);
+  else if (eval_is_annotation (r, kind) == boolean_true_node)
+    rloc = EXPR_LOCATION (TREE_VALUE (TREE_VALUE (r)));
+  tree decl = NULL_TREE, field = NULL_TREE;
+  if (rloc != UNKNOWN_LOCATION)
+    {
+      /* Make sure __builtin_source_location (which depends on
+        std::source_location::__impl) will work without errors.  */
+      tree name = get_identifier ("__impl");
+      decl = lookup_qualified_name (std_source_location, name);
+      if (TREE_CODE (decl) != TYPE_DECL)
+       decl = NULL_TREE;
+      else
+       {
+         name = get_identifier ("__builtin_source_location");
+         decl = lookup_qualified_name (global_namespace, name);
+         if (TREE_CODE (decl) != FUNCTION_DECL
+             || !fndecl_built_in_p (decl, BUILT_IN_FRONTEND)
+             || DECL_FE_FUNCTION_CODE (decl) != CP_BUILT_IN_SOURCE_LOCATION
+             || !require_deduced_type (decl, tf_warning_or_error))
+           decl = NULL_TREE;
+       }
+    }
+  if (decl)
+    {
+      field = TYPE_FIELDS (std_source_location);
+      field = next_aggregate_field (field);
+      /* Make sure std::source_location has exactly a single non-static
+        data member (_M_impl in libstdc++, __ptr_ in libc++) with pointer
+        type.  Return {._M_impl = &*.Lsrc_locN}.  */
+      if (field != NULL_TREE
+         && POINTER_TYPE_P (TREE_TYPE (field))
+         && !next_aggregate_field (DECL_CHAIN (field)))
+       {
+         tree call = build_call_nary (TREE_TYPE (TREE_TYPE (decl)), decl, 0);
+         SET_EXPR_LOCATION (call, rloc);
+         call = fold_builtin_source_location (call);
+         return build_constructor_single (std_source_location, field, call);
+       }
+    }
+  return build_constructor (std_source_location, nullptr);
+}
+
+/* If R is (const T &) &foo, get foo.  */
+
+static tree
+maybe_get_reference_referent (tree r)
+{
+  if (TREE_CODE (r) == NOP_EXPR
+      && TYPE_REF_P (TREE_TYPE (r))
+      && TREE_CODE (TREE_OPERAND (r, 0)) == ADDR_EXPR)
+    {
+      STRIP_NOPS (r);
+      r = TREE_OPERAND (r, 0);
+    }
+  return r;
+}
+
+/* Process std::meta::object_of.
+   Returns:
+   -- If r represents an object, then r.
+   -- Otherwise, if r represents a reference, then a reflection of the object
+      referred to by that reference.
+   -- Otherwise, r represents a variable; a reflection of the object declared
+      by that variable.
+   Throws: meta::exception unless r is a reflection representing either
+   -- an object with static storage duration, or
+   -- a variable that either declares or refers to such an object, and if that
+      variable is a reference R, then either
+      -- R is usable in constant expressions, or
+      -- the lifetime of R began within the core constant expression currently
+        under evaluation.  */
+
+static tree
+eval_object_of (location_t loc, const constexpr_ctx *ctx, tree r,
+               reflect_kind kind, bool *non_constant_p, bool *overflow_p,
+               tree *jump_target, tree fun)
+{
+  tree orig = r;
+  if (TYPE_REF_P (TREE_TYPE (r)))
+    r = cxx_eval_constant_expression (ctx, r, vc_prvalue, non_constant_p,
+                                     overflow_p, jump_target);
+  r = maybe_get_reference_referent (r);
+  if (eval_has_static_storage_duration (orig, kind) == boolean_false_node
+      && (orig == r
+         || eval_has_static_storage_duration (r, kind) == boolean_false_node))
+    return throw_exception (loc, ctx, "reflection does not represent an"
+                                     " object with static storage duration,"
+                                     " or a reference to such an object",
+                           fun, non_constant_p, jump_target);
+  return get_reflection_raw (loc, r, REFLECT_OBJECT);
+}
+
+/* Process std::meta::constant_of.
+   Let R be a constant expression of type info such that R == r is true.
+   If r represents an annotation, then let C be its underlying constant.
+   Effects: Equivalent to:
+     if constexpr (is_annotation(R)) {
+       return C;
+     } else if constexpr (is_array_type(type_of(R)) {
+       return reflect_constant_array([: R :]);
+     } else if constexpr (is_function_type(type_of(R)) {
+       return reflect_function([: R :]);
+     } else {
+       return reflect_constant([: R :]);
+     }
+   Throws: meta::exception unless either r represents an annotation or
+   [: R :] is a valid splice-expression.  */
+
+static tree
+eval_constant_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                 reflect_kind kind, bool *non_constant_p, bool *overflow_p,
+                 tree *jump_target, tree fun)
+{
+  tree type;
+  if (has_type (r, kind))
+    type = type_of (r, kind);
+  else
+    type = maybe_strip_typedefs (r);
+
+  /* So that outer_automatic_var_p works below in check_splice_expr.  */
+  temp_override<tree> ovr (current_function_decl);
+  current_function_decl = cxx_constexpr_caller (ctx);
+
+  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)
+    {
+      const tsubst_flags_t complain = complain_flags (ctx);
+      /* Create a call to reflect_constant_array so that we can simply
+        let eval_reflect_constant_array do its job.  */
+      tree name = get_identifier ("reflect_constant_array");
+      tree call = lookup_qualified_name (std_meta_node, name);
+      if (error_operand_p (call) || !is_overloaded_fn (call))
+       {
+         if (complain)
+           error_at (loc, "couldn%'t look up %<%D::%D%>", std_meta_node, name);
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
+      /* We want the argument to be a CONSTRUCTOR or a STRING_CST.  */
+      r = cxx_eval_constant_expression (ctx, r, vc_prvalue, non_constant_p,
+                                       overflow_p, jump_target);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      releasing_vec args (make_tree_vector_single (r));
+      call = finish_call_expr (call, &args, /*disallow_virtual=*/true,
+                              /*koenig_p=*/false, complain);
+      if (call == error_mark_node)
+       {
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
+      return eval_reflect_constant_array (loc, ctx, call, non_constant_p,
+                                         overflow_p, jump_target, fun);
+    }
+  else if (eval_is_function_type (type) == boolean_true_node)
+    return eval_reflect_function (loc, ctx, type, r, non_constant_p,
+                                 jump_target, fun);
+  else if (!check_splice_expr (loc, UNKNOWN_LOCATION, r,
+                              /*address_p=*/false,
+                              /*member_access_p=*/false,
+                              /*complain_p=*/false)
+          /* One cannot query the value of a function template.
+             ??? But if [:^^X:] where X is a template is OK, should we
+             really throw?  We need an LWG issue.  */
+          || eval_is_template (r) == boolean_true_node)
+    return throw_exception (loc, ctx, "reflection does not represent an "
+                                     "annotation or a valid argument to "
+                                     "a splice-expression",
+                           fun, non_constant_p, jump_target);
+
+  r = cxx_eval_constant_expression (ctx, r, vc_prvalue, non_constant_p,
+                                   overflow_p, jump_target);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  /* Figure out the type for reflect_constant.  */
+  type = TREE_TYPE (convert_from_reference (r));
+  type = type_decays_to (type);
+  type = cv_unqualified (type);
+
+  return eval_reflect_constant (loc, ctx, type, r, non_constant_p, jump_target,
+                               fun);
+}
+
+/* Process std::meta::dealias.
+   Returns: If r represents an entity, then a reflection representing the
+   underlying entity of what r represents.  Otherwise, r.
+   This implements LWG 4427 so we do not throw.  */
+
+static tree
+eval_dealias (location_t loc, tree r, reflect_kind kind)
+{
+  r = maybe_strip_typedefs (r);
+  if (TREE_CODE (r) == NAMESPACE_DECL)
+    r = ORIGINAL_NAMESPACE (r);
+  return get_reflection_raw (loc, r, kind);
+}
+
+/* Process std::meta::is_noexcept.
+   Returns: true if r represents a noexcept function type or a function
+   with a non-throwing exception specification ([except.spec]).
+   Otherwise, false.
+   Note: If r represents a function template that is declared noexcept,
+   is_noexcept (r) is still false because in general such queries
+   for templates cannot be answered.  */
+
+static tree
+eval_is_noexcept (tree r)
+{
+  if (eval_is_function (r) == boolean_true_node)
+    {
+      r = maybe_get_reflection_fndecl (r);
+      maybe_instantiate_noexcept (r);
+      if (TYPE_NOTHROW_P (TREE_TYPE (r)))
+       return boolean_true_node;
+      else
+       return boolean_false_node;
+    }
+
+  if (eval_is_function_type (r) == boolean_true_node
+      && TYPE_NOTHROW_P (r))
+    return boolean_true_node;
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_const.
+   Let T be type_of(r) if has-type(r) is true.  Otherwise, let T be dealias(r).
+   Returns: true if T represents a const type, or a const-qualified function
+   type.  Otherwise, false.  */
+
+static tree
+eval_is_const (tree r, reflect_kind kind)
+{
+  if (has_type (r, kind))
+    r = type_of (r, kind);
+  else
+    r = maybe_strip_typedefs (r);
+  r = strip_array_types (r);
+  if (TREE_CODE (r) == METHOD_TYPE)
+    {
+      if (type_memfn_quals (r) & TYPE_QUAL_CONST)
+       return boolean_true_node;
+    }
+  else if (TYPE_P (r) && TYPE_READONLY (r))
+    return boolean_true_node;
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_volatile.
+   Let T be type_of(r) if has-type(r) is true.  Otherwise, let T be dealias(r).
+   Returns: true if T represents a volatile type, or a volatile-qualified
+   function type.  Otherwise, false.  */
+
+static tree
+eval_is_volatile (tree r, reflect_kind kind)
+{
+  if (has_type (r, kind))
+    r = type_of (r, kind);
+  else
+    r = maybe_strip_typedefs (r);
+  r = strip_array_types (r);
+  if (TREE_CODE (r) == METHOD_TYPE)
+    {
+      if (type_memfn_quals (r) & TYPE_QUAL_VOLATILE)
+       return boolean_true_node;
+    }
+  else if (TYPE_P (r) && TYPE_VOLATILE (r))
+    return boolean_true_node;
+  return boolean_false_node;
+}
+
+/* Process std::meta::has_template_arguments.
+   Returns: true if r represents a specialization of a function template,
+   variable template, class template, or an alias template.  Otherwise,
+   false.  */
+
+static tree
+eval_has_template_arguments (tree r)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  /* Presumably for
+       typedef cls_tmpl<int> TYPE;
+     'has_template_arguments (^^TYPE)' should be false?  */
+  if (TYPE_P (r)
+      && typedef_variant_p (r)
+      && !alias_template_specialization_p (r, nt_opaque))
+    return boolean_false_node;
+  if (primary_template_specialization_p (r)
+      || variable_template_specialization_p (r))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::template_of.
+   Returns: A reflection of the template of the specialization represented
+   by r.
+   Throws: meta::exception unless has_template_arguments(r) is true.  */
+
+static tree
+eval_template_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                 bool *non_constant_p, tree *jump_target, tree fun)
+{
+  if (eval_has_template_arguments (r) != boolean_true_node)
+    return throw_exception_notargs (loc, ctx, fun, non_constant_p, jump_target);
+
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TYPE_P (r) && typedef_variant_p (r))
+    r = TI_TEMPLATE (TYPE_ALIAS_TEMPLATE_INFO (r));
+  else if (CLASS_TYPE_P (r) && CLASSTYPE_TEMPLATE_INFO (r))
+    r = CLASSTYPE_TI_TEMPLATE (r);
+  else if (VAR_OR_FUNCTION_DECL_P (r) && DECL_TEMPLATE_INFO (r))
+    r = DECL_TI_TEMPLATE (r);
+  else
+    gcc_assert (false);
+
+  gcc_assert (TREE_CODE (r) == TEMPLATE_DECL);
+  return get_reflection_raw (loc, r);
+}
+
+/* Process std::meta::has_parent
+   Returns:
+   -- If r represents the global namespace, then false.
+   -- Otherwise, if r represents an entity that has C language linkage,
+      then false.
+   -- Otherwise, if r represents an entity that has a language linkage
+      other than C++ language linkage, then an implementation-defined value.
+   -- Otherwise, if r represents a type that is neither a class nor enumeration
+      type, then false.
+   -- Otherwise, if r represents an entity or direct base class relationship,
+      then true.
+   -- Otherwise, false.  */
+
+static tree
+eval_has_parent (tree r, reflect_kind kind)
+{
+  if (kind == REFLECT_OBJECT
+      || CONSTANT_CLASS_P (r)
+      || r == global_namespace
+      || kind == REFLECT_DATA_MEMBER_SPEC)
+    return boolean_false_node;
+  if (TYPE_P (r))
+    {
+      if (TYPE_NAME (r)
+         && DECL_P (TYPE_NAME (r))
+         && DECL_LANGUAGE (TYPE_NAME (r)) == lang_c)
+       return boolean_false_node;
+      else if (OVERLOAD_TYPE_P (r) || typedef_variant_p (r))
+       return boolean_true_node;
+      else
+       return boolean_false_node;
+    }
+  r = maybe_get_reflection_fndecl (r);
+  if (kind == REFLECT_BASE)
+    return boolean_true_node;
+  if (!DECL_P (r))
+    return boolean_false_node;
+  if (TREE_CODE (r) != NAMESPACE_DECL && DECL_LANGUAGE (r) == lang_c)
+    return boolean_false_node;
+  return boolean_true_node;
+}
+
+/* Process std::meta::parent_of.
+   Returns:
+   -- If r represents a non-static data member that is a direct member of an
+      anonymous union, or an unnamed bit-field declared within the
+      member-specification of such a union, then a reflection representing the
+      innermost enclosing anonymous union.
+   -- Otherwise, if r represents an enumerator, then a reflection representing
+      the corresponding enumeration type.
+   -- Otherwise, if r represents a direct base class relationship (D,B), then
+      a reflection representing D.
+   -- Otherwise, let E be a class, function, or namespace whose class scope,
+      function parameter scope, or namespace scope, respectively, is the
+      innermost such scope that either is, or encloses, the target scope of a
+      declaration of what is represented by r.
+      -- If E is the function call operator of a closure type for a
+        consteval-block-declaration, then parent_of(parent_of(^^E)).
+      -- Otherwise, ^^E.  */
+
+static tree
+eval_parent_of (location_t loc, const constexpr_ctx *ctx, tree r,
+               reflect_kind kind, bool *non_constant_p, tree *jump_target,
+               tree fun)
+{
+  if (eval_has_parent (r, kind) != boolean_true_node)
+    return throw_exception (loc, ctx, "reflection does not represent an "
+                                     "entity with parent",
+                           fun, non_constant_p, jump_target);
+  tree c;
+  r = maybe_get_reflection_fndecl (r);
+  if (TYPE_P (r))
+    {
+      if (TYPE_NAME (r) && DECL_P (TYPE_NAME (r)))
+       c = CP_DECL_CONTEXT (TYPE_NAME (r));
+      else
+       c = CP_TYPE_CONTEXT (r);
+    }
+  else if (kind == REFLECT_BASE)
+    c = direct_base_parent (r);
+  else
+    c = CP_DECL_CONTEXT (r);
+  tree lam;
+  while (LAMBDA_FUNCTION_P (c)
+        && (lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (c)))
+        && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam))
+    c = CP_TYPE_CONTEXT (CP_DECL_CONTEXT (c));
+  return get_reflection_raw (loc, c);
+}
+
+/* Return std::vector<info>.  */
+
+static tree
+get_vector_info ()
+{
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = meta_info_type_node;
+  tree inst = lookup_template_class (get_identifier ("vector"), args,
+                                    /*in_decl*/NULL_TREE,
+                                    /*context*/std_node, tf_none);
+  inst = complete_type (inst);
+  if (inst == error_mark_node || !COMPLETE_TYPE_P (inst))
+    {
+      error ("couldn%'t look up %qs", "std::vector");
+      return NULL_TREE;
+    }
+
+  return inst;
+}
+
+/* Build std::vector<info>{ ELTS }.  */
+
+static tree
+get_vector_of_info_elts (vec<constructor_elt, va_gc> *elts)
+{
+  tree ctor = build_constructor (init_list_type_node, elts);
+  CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+  TREE_CONSTANT (ctor) = true;
+  TREE_STATIC (ctor) = true;
+  tree type = get_vector_info ();
+  if (!type)
+    return error_mark_node;
+  tree r = finish_compound_literal (type, ctor, tf_warning_or_error,
+                                   fcl_functional);
+  if (TREE_CODE (r) == TARGET_EXPR)
+    r = TARGET_EXPR_INITIAL (r);
+  return r;
+}
+
+/* Process std::meta::parameters_of.
+   Returns:
+   -- If r represents a function F, then a vector containing reflections of
+      the parameters of F, in the order in which they appear in a declaration
+      of F.
+   -- Otherwise, r represents a function type T; a vector containing
+      reflections of the types in parameter-type-list of T, in the order in
+      which they appear in the parameter-type-list.
+
+   Throws: meta::exception unless r represents a function or a function
+   type.  */
+
+static tree
+eval_parameters_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                   bool *non_constant_p, tree *jump_target, tree fun)
+{
+  if (eval_is_function (r) != boolean_true_node
+      && eval_is_function_type (r) != boolean_true_node)
+    return throw_exception_nofn (loc, ctx, fun, non_constant_p, jump_target);
+
+  r = maybe_get_reflection_fndecl (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  tree args = (TREE_CODE (r) == FUNCTION_DECL
+              ? FUNCTION_FIRST_USER_PARM (r)
+              : TYPE_ARG_TYPES (r));
+  for (tree arg = args; arg && arg != void_list_node; arg = TREE_CHAIN (arg))
+    CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                           get_reflection_raw (loc, arg, REFLECT_PARM));
+  return get_vector_of_info_elts (elts);
+}
+
+/* Process std::meta::variable_of.
+   Returns: The reflection of the parameter variable corresponding to r.
+
+   Throws: meta::exception unless
+   -- r represents a parameter of a function F and
+   -- there is a point P in the evaluation context for which the innermost
+      non-block scope enclosing P is the function parameter scope associated
+      with F.  */
+
+static tree
+eval_variable_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                 reflect_kind kind, bool *non_constant_p, tree *jump_target,
+                 tree fun)
+{
+  if (eval_is_function_parameter (r, kind) == boolean_false_node
+      /* This doesn't consider the points corresponding to injected
+        declarations.  */
+      || DECL_CONTEXT (r) != current_function_decl)
+    return throw_exception (loc, ctx, "reflection does not represent "
+                                     "parameter of current function",
+                           fun, non_constant_p, jump_target);
+  r = maybe_update_function_parm (r);
+  return get_reflection_raw (loc, r, REFLECT_UNDEF);
+}
+
+/* Process std::meta::return_type_of.
+   Returns: The reflection of the return type of the function or function type
+   represented by r.
+
+   Throws: meta::exception unless either r represents a function and
+   has-type(r) is true or r represents a function type.  */
+
+static tree
+eval_return_type_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                    reflect_kind kind, bool *non_constant_p, tree *jump_target,
+                    tree fun)
+{
+  if ((eval_is_function (r) != boolean_true_node || !has_type (r, kind))
+      && eval_is_function_type (r) != boolean_true_node)
+    return throw_exception (loc, ctx, "reflection does not represent a "
+                           "function or function type with a return type",
+                           fun, non_constant_p, jump_target);
+
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (TREE_CODE (r) == FUNCTION_DECL)
+    r = TREE_TYPE (r);
+  r = TREE_TYPE (r);
+  return get_reflection_raw (loc, r, REFLECT_UNDEF);
+}
+
+/* Process std::meta::offset_of.
+   Let V be the offset in bits from the beginning of a complete object of the
+   type represented by parent_of(r) to the subobject associated with the
+   entity represented by r.
+   Returns: {V / CHAR_BIT, V % CHAR_BIT}.
+   Throws: meta::exception unless r represents a non-static data member,
+   unnamed bit-field, or direct base class relationship (D,B) for which either
+   B is not a virtual base class or D is not an abstract class.  */
+
+static tree
+eval_offset_of (location_t loc, const constexpr_ctx *ctx, tree r,
+               reflect_kind kind, tree member_offset, bool *non_constant_p,
+               tree *jump_target, tree fun)
+{
+  tree byte_off = NULL_TREE, bit_off = NULL_TREE;
+  if (kind == REFLECT_BASE)
+    {
+      tree d = direct_base_parent (r);
+      if (BINFO_VIRTUAL_P (r) && ABSTRACT_CLASS_TYPE_P (d))
+       return throw_exception (loc, ctx,
+                               "reflection of virtual direct base "
+                               "relationship with abstract derived "
+                               "class", fun, non_constant_p, jump_target);
+      byte_off = BINFO_OFFSET (r);
+    }
+  else if (TREE_CODE (r) != FIELD_DECL)
+    return throw_exception (loc, ctx, "reflection unsuitable for offset_of",
+                           fun, non_constant_p, jump_target);
+  else
+    bit_off = bit_position (r);
+  if (TREE_CODE (bit_off ? bit_off : byte_off) != INTEGER_CST)
+    return throw_exception (loc, ctx, "non-constant offset for offset_of",
+                           fun, non_constant_p, jump_target);
+  if (TREE_CODE (member_offset) != RECORD_TYPE)
+    {
+    fail:
+      error_at (loc, "unexpected return type of %qs", "std::meta::offset_of");
+      return build_zero_cst (member_offset);
+    }
+  tree bytes = next_aggregate_field (TYPE_FIELDS (member_offset));
+  if (!bytes || !INTEGRAL_TYPE_P (TREE_TYPE (bytes)))
+    goto fail;
+  tree bits = next_aggregate_field (DECL_CHAIN (bytes));
+  if (!bits || !INTEGRAL_TYPE_P (TREE_TYPE (bits)))
+    goto fail;
+  if (next_aggregate_field (DECL_CHAIN (bits)))
+    goto fail;
+  tree bytesv;
+  if (byte_off)
+    bytesv = byte_off;
+  else
+    bytesv = size_binop (TRUNC_DIV_EXPR, bit_off, bitsize_unit_node);
+  bytesv = fold_convert (TREE_TYPE (bytes), bytesv);
+  tree bitsv;
+  if (byte_off)
+    bitsv = build_zero_cst (TREE_TYPE (bits));
+  else
+    {
+      bitsv = size_binop (TRUNC_MOD_EXPR, bit_off, bitsize_unit_node);
+      bitsv = fold_convert (TREE_TYPE (bits), bitsv);
+    }
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  CONSTRUCTOR_APPEND_ELT (elts, bytes, bytesv);
+  CONSTRUCTOR_APPEND_ELT (elts, bits, bitsv);
+  return build_constructor (member_offset, elts);
+}
+
+/* Process std::meta::size_of.
+   Returns: If r represents
+     -- a non-static data member of type T,
+     -- a data member description (T,N,A,W,NUA), or
+     -- dealias(r) represents a type T,
+   then sizeof(T) if T is not a reference type and size_of(add_pointer(^^T))
+   otherwise.  Otherwise, size_of(type_of(r)).
+
+   Throws: meta::exception unless all of the following conditions are met:
+     -- dealias(r) is a reflection of a type, object, value, variable of
+       non-reference type, non-static data member that is not a bit-field,
+       direct base class relationship, or data member description
+       (T,N,A,W,NUA) where W is not _|_.
+     -- If dealias(r) represents a type, then is_complete_type(r) is true.  */
+
+static tree
+eval_size_of (location_t loc, const constexpr_ctx *ctx, tree r,
+             reflect_kind kind, tree ret_type, bool *non_constant_p,
+             tree *jump_target, tree fun)
+{
+  if (eval_is_type (r) != boolean_true_node
+      && eval_is_object (kind) != boolean_true_node
+      && eval_is_value (kind) != boolean_true_node
+      && (eval_is_variable (r, kind) != boolean_true_node
+         || TYPE_REF_P (TREE_TYPE (r)))
+      && (TREE_CODE (r) != FIELD_DECL || DECL_C_BIT_FIELD (r))
+      && kind != REFLECT_BASE
+      && (kind != REFLECT_DATA_MEMBER_SPEC || TREE_VEC_ELT (r, 3)))
+    return throw_exception (loc, ctx, "reflection not suitable for size_of",
+                           fun, non_constant_p, jump_target);
+  if (!INTEGRAL_TYPE_P (ret_type))
+    {
+      error_at (loc, "unexpected return type of %qs", "std::meta::size_of");
+      return build_zero_cst (ret_type);
+    }
+  tree type;
+  if (TYPE_P (r))
+    type = r;
+  else
+    type = type_of (r, kind);
+  tree ret;
+  if (!complete_type_or_maybe_complain (type, NULL_TREE, tf_none)
+      /* No special casing of references needed, c_sizeof_or_alignof_type
+        returns the same size for POINTER_TYPE and REFERENCE_TYPE.  */
+      || ((ret = c_sizeof_or_alignof_type (loc, type, true, false, 0))
+         == error_mark_node))
+    return throw_exception (loc, ctx,
+                           "reflection with incomplete type in size_of",
+                           fun, non_constant_p, jump_target);
+  return fold_convert (ret_type, ret);
+}
+
+/* Process std::meta::alignment_of.
+   Returns:
+   -- If dealias(r) represents a type T, then alignment_of(add_pointer(r)) if
+      T is a reference type and the alignment requirement of T otherwise.
+   -- Otherwise, if dealias(r) represents a variable or object, then the
+      alignment requirement of the variable or object.
+   -- Otherwise, if r represents a direct base class relationship, then
+      alignment_of(type_of(r)).
+   -- Otherwise, if r represents a non-static data member M of a class C,
+      then the alignment of the direct member subobject corresponding to M of a
+      complete object of type C.
+   -- Otherwise, r represents a data member description (T,N,A,W,NUA).
+      If A is not _|_, then the value A.  Otherwise, alignment_of(^^T).
+   Throws: meta::exception unless all of the following conditions are met:
+   -- dealias(r) is a reflection of a type, object, variable of non-reference
+      type, non-static data member that is not a bit-field, direct base class
+      relationship, or data member description (T,N,A,W,NUA) where W is _|_.
+   -- If dealias(r) represents a type, then is_complete_type(r) is true.  */
+
+static tree
+eval_alignment_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                  reflect_kind kind, tree ret_type, bool *non_constant_p,
+                  tree *jump_target, tree fun)
+{
+  if (eval_is_type (r) != boolean_true_node
+      && eval_is_object (kind) != boolean_true_node
+      && (eval_is_variable (r, kind) != boolean_true_node
+         || TYPE_REF_P (TREE_TYPE (r)))
+      && (TREE_CODE (r) != FIELD_DECL || DECL_C_BIT_FIELD (r))
+      && kind != REFLECT_BASE
+      && (kind != REFLECT_DATA_MEMBER_SPEC || TREE_VEC_ELT (r, 3)))
+    return throw_exception (loc, ctx, "reflection not suitable for alignment_of",
+                           fun, non_constant_p, jump_target);
+  if (!INTEGRAL_TYPE_P (ret_type))
+    {
+      error_at (loc, "unexpected return type of %qs", "std::meta::alignment_of");
+      return build_zero_cst (ret_type);
+    }
+  tree type;
+  if (kind == REFLECT_DATA_MEMBER_SPEC)
+    {
+      if (TREE_VEC_ELT (r, 2))
+       return fold_convert (ret_type, TREE_VEC_ELT (r, 2));
+      else
+       type = TREE_VEC_ELT (r, 0);
+    }
+  else if (kind == REFLECT_BASE)
+    type = BINFO_TYPE (r);
+  else if (TREE_CODE (r) == FIELD_DECL
+          || eval_is_variable (r, kind) == boolean_true_node
+          || (eval_is_object (kind) == boolean_true_node
+              && ((DECL_P (r) && TREE_CODE (r) != FUNCTION_DECL)
+                  || TREE_CODE (r) == COMPONENT_REF)))
+    {
+      if (TREE_CODE (r) == COMPONENT_REF)
+       r = TREE_OPERAND (r, 1);
+      return build_int_cst (ret_type, MAX (DECL_ALIGN_UNIT (r), 1));
+    }
+  else if (TYPE_P (r))
+    type = r;
+  else if (eval_is_object (kind) == boolean_true_node)
+    type = TREE_TYPE (r);
+  else
+    gcc_unreachable ();
+  if (TYPE_REF_P (type))
+    type = ptr_type_node;
+  if (FUNC_OR_METHOD_TYPE_P (type))
+    return throw_exception (loc, ctx, "alignment_of on function type",
+                           fun, non_constant_p, jump_target);
+  tree ret;
+  if (!complete_type_or_maybe_complain (type, NULL_TREE, tf_none)
+      /* No special casing of references needed, c_sizeof_or_alignof_type
+        returns the same alignment for POINTER_TYPE and REFERENCE_TYPE.  */
+      || ((ret = c_sizeof_or_alignof_type (loc, type, false, true, 0))
+         == error_mark_node))
+    return throw_exception (loc, ctx,
+                           "reflection with incomplete type in alignment_of",
+                           fun, non_constant_p, jump_target);
+  return fold_convert (ret_type, ret);
+}
+
+/* Process std::meta::bit_size_of.
+   Returns:
+     -- If r represents an unnamed bit-field or a non-static data member that
+       is a bit-field with width W, then W.
+     -- Otherwise, if r represents a data member description (T,N,A,W,NUA)
+       and W is not _|_, then W.
+     -- Otherwise, CHAR_BIT * size_of(r).
+
+   Throws: meta::exception unless all of the following conditions are met:
+
+     -- dealias(r) is a reflection of a type, object, value, variable of
+       non-reference type, non-static data member, unnamed bit-field, direct
+       base class relationship, or data member description.
+     -- If dealias(r) represents a type T, there is a point within the
+       evaluation context from which T is not incomplete.  */
+
+static tree
+eval_bit_size_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                 reflect_kind kind, tree ret_type, bool *non_constant_p,
+                 tree *jump_target, tree fun)
+{
+  if (eval_is_type (r) != boolean_true_node
+      && eval_is_object (kind) != boolean_true_node
+      && eval_is_value (kind) != boolean_true_node
+      && (eval_is_variable (r, kind) != boolean_true_node
+         || TYPE_REF_P (TREE_TYPE (r)))
+      && TREE_CODE (r) != FIELD_DECL
+      && kind != REFLECT_BASE
+      && kind != REFLECT_DATA_MEMBER_SPEC)
+    return throw_exception (loc, ctx,
+                           "reflection not suitable for bit_size_of",
+                           fun, non_constant_p, jump_target);
+  if (!INTEGRAL_TYPE_P (ret_type))
+    {
+      error_at (loc, "unexpected return type of %qs",
+               "std::meta::bit_size_of");
+      return build_zero_cst (ret_type);
+    }
+  tree type;
+  if (TREE_CODE (r) == FIELD_DECL && DECL_C_BIT_FIELD (r))
+    return fold_convert (ret_type, DECL_SIZE (r));
+  else if (TYPE_P (r))
+    type = r;
+  else if (kind == REFLECT_DATA_MEMBER_SPEC && TREE_VEC_ELT (r, 3))
+    return fold_convert (ret_type, TREE_VEC_ELT (r, 3));
+  else
+    type = type_of (r, kind);
+  tree ret;
+  if (!complete_type_or_maybe_complain (type, NULL_TREE, tf_none)
+      /* No special casing of references needed, c_sizeof_or_alignof_type
+        returns the same size for POINTER_TYPE and REFERENCE_TYPE.  */
+      || ((ret = c_sizeof_or_alignof_type (loc, type, true, false, 0))
+         == error_mark_node))
+    return throw_exception (loc, ctx,
+                           "reflection with incomplete type in bit_size_of",
+                           fun, non_constant_p, jump_target);
+  ret = size_binop (MULT_EXPR, ret, size_int (BITS_PER_UNIT));
+  return fold_convert (ret_type, ret);
+}
+
+/* Process std::meta::has_identifier.
+   Returns:
+   -- If r represents an entity that has a typedef name for linkage purposes,
+      then true.
+   -- Otherwise, if r represents an unnamed entity, then false.
+   -- Otherwise, if r represents a type alias, then !has_template_arguments(r).
+   -- Otherwise, if r represents a type, then true if
+      -- r represents a cv-unqualified class type and has_template_arguments(r)
+        is false, or
+      -- r represents a cv-unqualified enumeration type.
+      Otherwise, false.
+   -- Otherwise, if r represents a class type, then !has_template_arguments(r).
+   -- Otherwise, if r represents a function, then true if
+      has_template_arguments(r) is false and the function is not a constructor,
+      destructor, operator function, or conversion function.  Otherwise, false.
+   -- Otherwise, if r represents a template, then true if r does not represent
+      a constructor template, operator function template, or conversion
+      function template.  Otherwise, false.
+   -- Otherwise, if r represents the ith parameter of a function F that is an
+      (implicit or explicit) specialization of a templated function T and the
+      ith parameter of the instantiated declaration of T whose template
+      arguments are those of F would be instantiated from a pack, then false.
+   -- Otherwise, if r represents the parameter P of a function F, then let S
+      be the set of declarations, ignoring any explicit instantiations, that
+      precede some point in the evaluation context and that declare either F
+      or a templated function of which F is a specialization; true if
+      -- there is a declaration D in S that introduces a name N for either P
+        or the parameter corresponding to P in the templated function that
+        D declares and
+      -- no declaration in S does so using any name other than N.
+      Otherwise, false.
+   -- Otherwise, if r represents a variable, then false if the declaration of
+      that variable was instantiated from a function parameter pack.
+      Otherwise, !has_template_arguments(r).
+   -- Otherwise, if r represents a structured binding, then false if the
+      declaration of that structured binding was instantiated from a
+      structured binding pack.  Otherwise, true.
+   -- Otherwise, if r represents an enumerator, non-static-data member,
+      namespace, or namespace alias, then true.
+   -- Otherwise, if r represents a direct base class relationship, then
+      has_identifier(type_of(r)).
+   -- Otherwise, r represents a data member description (T,N,A,W,NUA); true if
+      N is not _|_.  Otherwise, false.  */
+
+static tree
+eval_has_identifier (tree r, reflect_kind kind)
+{
+  r = maybe_get_reflection_fndecl (r);
+  if (kind == REFLECT_BASE)
+    {
+      r = type_of (r, kind);
+      kind = REFLECT_UNDEF;
+    }
+  if (DECL_P (r)
+      && kind != REFLECT_PARM
+      && (!DECL_NAME (r) || IDENTIFIER_ANON_P (DECL_NAME (r))))
+    return boolean_false_node;
+  if (TYPE_P (r) && (!TYPE_NAME (r)
+                    || (TYPE_ANON_P (r) && !typedef_variant_p (r))
+                    || (DECL_P (TYPE_NAME (r))
+                        && !DECL_NAME (TYPE_NAME (r)))))
+    return boolean_false_node;
+  if (eval_is_type_alias (r) == boolean_true_node
+      || (CLASS_TYPE_P (r) && !cv_qualified_p (r)))
+    {
+      if (eval_has_template_arguments (r) == boolean_true_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  if (TYPE_P (r))
+    {
+      if (TREE_CODE (r) == ENUMERAL_TYPE && !cv_qualified_p (r))
+       return boolean_true_node;
+      else
+       return boolean_false_node;
+    }
+  if (eval_is_function (r) == boolean_true_node)
+    {
+      if (eval_has_template_arguments (r) == boolean_true_node
+         || eval_is_constructor (r) == boolean_true_node
+         || eval_is_destructor (r) == boolean_true_node
+         || eval_is_operator_function (r) == boolean_true_node
+         || eval_is_conversion_function (r) == boolean_true_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  if (eval_is_template (r) == boolean_true_node)
+    {
+      if (eval_is_constructor_template (r) == boolean_true_node
+         || eval_is_operator_function_template (r) == boolean_true_node
+         || eval_is_conversion_function_template (r) == boolean_true_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  if (eval_is_function_parameter (r, kind) == boolean_true_node)
+    {
+      r = maybe_update_function_parm (r);
+      if (MULTIPLE_NAMES_PARM_P (r))
+       return boolean_false_node;
+      if (DECL_NAME (r))
+       {
+         if (strchr (IDENTIFIER_POINTER (DECL_NAME (r)), '#'))
+           return boolean_false_node;
+         else
+           return boolean_true_node;
+       }
+      if (lookup_attribute ("old parm name", DECL_ATTRIBUTES (r)))
+       return boolean_true_node;
+      else
+       return boolean_false_node;
+    }
+  if (eval_is_variable (r, kind) == boolean_true_node)
+    {
+      if (strchr (IDENTIFIER_POINTER (DECL_NAME (r)), '#'))
+       return boolean_false_node;
+      if (eval_has_template_arguments (r) == boolean_true_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  if (eval_is_structured_binding (r, kind) == boolean_true_node)
+    {
+      if (strchr (IDENTIFIER_POINTER (DECL_NAME (r)), '#'))
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  if (eval_is_enumerator (r) == boolean_true_node
+      || TREE_CODE (r) == FIELD_DECL
+      || (TREE_CODE (r) == NAMESPACE_DECL && r != global_namespace))
+    return boolean_true_node;
+  if (kind == REFLECT_DATA_MEMBER_SPEC && TREE_VEC_ELT (r, 1))
+    return boolean_true_node;
+  return boolean_false_node;
+}
+
+/* Process std::meta::{,u8}identifier_of.
+   Let E be UTF-8 for u8identifier_of, and otherwise the ordinary literal
+   encoding.
+   Returns: An NTMBS, encoded with E, determined as follows:
+   -- If r represents an entity with a typedef name for linkage purposes,
+      then that name.
+   -- Otherwise, if r represents a literal operator or literal operator
+      template, then the ud-suffix of the operator or operator template.
+   -- Otherwise, if r represents the parameter P of a function F, then let S
+      be the set of declarations, ignoring any explicit instantiations, that
+      precede some point in the evaluation context and that declare either F
+      or a templated function of which F is a specialization; the name that
+      was introduced by a declaration in S for the parameter corresponding
+      to P.
+   -- Otherwise, if r represents an entity, then the identifier introduced by
+      the declaration of that entity.
+   -- Otherwise, if r represents a direct base class relationship, then
+      identifier_of(type_of(r)) or u8identifier_of(type_of(r)), respectively.
+   -- Otherwise, r represents a data member description (T,N,A,W,NUA);
+      a string_view or u8string_view, respectively, containing the identifier
+      N.
+   Throws: meta::exception unless has_identifier(r) is true and the identifier
+   that would be returned (see above) is representable by E.  */
+
+static tree
+eval_identifier_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                   reflect_kind kind, bool *non_constant_p, tree *jump_target,
+                   tree elt_type, tree ret_type, tree fun)
+{
+  if (eval_has_identifier (r, kind) == boolean_false_node)
+    return throw_exception (loc, ctx,
+                           "reflection with has_identifier false",
+                           fun, non_constant_p, jump_target);
+  r = maybe_get_reflection_fndecl (r);
+  const char *name = NULL;
+  if (kind == REFLECT_BASE)
+    {
+      r = type_of (r, kind);
+      kind = REFLECT_UNDEF;
+    }
+  if (eval_is_function_parameter (r, kind) == boolean_true_node)
+    {
+      r = maybe_update_function_parm (r);
+      if (DECL_NAME (r))
+       name = IDENTIFIER_POINTER (DECL_NAME (r));
+      else
+       {
+         tree opn = lookup_attribute ("old parm name", DECL_ATTRIBUTES (r));
+         opn = TREE_VALUE (TREE_VALUE (opn));
+         name = IDENTIFIER_POINTER (opn);
+       }
+    }
+  else if (DECL_P (r) && UDLIT_OPER_P (DECL_NAME (r)))
+    name = UDLIT_OP_SUFFIX (DECL_NAME (r));
+  else if (DECL_P (r))
+    name = IDENTIFIER_POINTER (DECL_NAME (r));
+  else if (TYPE_P (r))
+    {
+      if (DECL_P (TYPE_NAME (r)))
+       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (r)));
+      else
+       name = IDENTIFIER_POINTER (TYPE_NAME (r));
+    }
+  else if (kind == REFLECT_DATA_MEMBER_SPEC)
+    name = IDENTIFIER_POINTER (TREE_VEC_ELT (r, 1));
+  else
+    gcc_unreachable ();
+  tree str = get_string_literal (name, elt_type);
+  if (str == NULL_TREE)
+    {
+      if (elt_type == char_type_node)
+       return throw_exception (loc, ctx, "identifier_of not representable"
+                                         " in ordinary literal encoding",
+                               fun, non_constant_p, jump_target);
+      else
+       return throw_exception (loc, ctx, "u8identifier_of not representable"
+                                         " in UTF-8",
+                               fun, non_constant_p, jump_target);
+    }
+  releasing_vec args (make_tree_vector_single (str));
+  tree ret = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                       &args, ret_type, LOOKUP_NORMAL,
+                                       tf_warning_or_error);
+  return build_cplus_new (ret_type, ret, tf_warning_or_error);
+}
+
+/* Process std::meta::{,u8}display_string_of.
+   Returns: An implementation-defined string_view or u8string_view,
+   respectively.
+   Recommended practice: Where possible, implementations should return a
+   string suitable for identifying the represented construct.  */
+
+static tree
+eval_display_string_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                       reflect_kind kind, bool *non_constant_p,
+                       tree *jump_target, tree elt_type, tree ret_type,
+                       tree fun)
+{
+#if __GNUC__ >= 10
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+  r = maybe_get_reflection_fndecl (r);
+  pretty_printer pp, *refpp = global_dc->get_reference_printer ();
+  pp_format_decoder (&pp) = pp_format_decoder (refpp);
+  pp.set_format_postprocessor (pp_format_postprocessor (refpp)->clone ());
+  if (r == unknown_type_node)
+    pp_printf (&pp, "<null reflection>");
+  else if (TYPE_P (r))
+    pp_printf (&pp, "%T", r);
+  else if (kind == REFLECT_PARM)
+    {
+      r = maybe_update_function_parm (r);
+      tree fn = DECL_CONTEXT (r);
+      if (DECL_NAME (r))
+       pp_printf (&pp, "<parameter %D of %D>", r, fn);
+      else
+       {
+         int idx = 1;
+         for (tree args = FUNCTION_FIRST_USER_PARM (fn);
+              r != args; args = DECL_CHAIN (args))
+           ++idx;
+         pp_printf (&pp, "<unnamed parameter %d of %D>", idx, fn);
+       }
+    }
+  else if (kind == REFLECT_VALUE || kind == REFLECT_OBJECT)
+    pp_printf (&pp, "%E", r);
+  else if (DECL_P (r) && (DECL_NAME (r) || TREE_CODE (r) == NAMESPACE_DECL))
+    pp_printf (&pp, "%D", r);
+  else if (TREE_CODE (r) == FIELD_DECL)
+    pp_printf (&pp, "%T::<unnamed bit-field>", DECL_CONTEXT (r));
+  else if (kind == REFLECT_BASE)
+    {
+      tree d = direct_base_parent (r);
+      pp_printf (&pp, "%T: %T", d, BINFO_TYPE (r));
+    }
+  else if (kind == REFLECT_DATA_MEMBER_SPEC)
+    pp_printf (&pp, "(%T, %E, %E, %E, %s)", TREE_VEC_ELT (r, 0),
+              TREE_VEC_ELT (r, 1), TREE_VEC_ELT (r, 2), TREE_VEC_ELT (r, 3),
+              TREE_VEC_ELT (r, 4) == boolean_true_node
+              ? "true" : "false");
+  else if (eval_is_annotation (r, kind) == boolean_true_node)
+    pp_printf (&pp, "[[=%E]]",
+              tree_strip_any_location_wrapper (TREE_VALUE (TREE_VALUE (r))));
+  else
+    pp_string (&pp, "<unsupported reflection>");
+#if __GNUC__ >= 10
+#pragma GCC diagnostic pop
+#endif
+  tree str = get_string_literal (pp_formatted_text (&pp), elt_type);
+  if (str == NULL_TREE)
+    {
+      if (elt_type == char_type_node)
+       return throw_exception (loc, ctx, "identifier_of not representable"
+                                         " in ordinary literal encoding",
+                               fun, non_constant_p, jump_target);
+      else
+       return throw_exception (loc, ctx, "u8identifier_of not representable"
+                                         " in UTF-8", fun, non_constant_p,
+                                         jump_target);
+    }
+  releasing_vec args (make_tree_vector_single (str));
+  tree ret = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                       &args, ret_type, LOOKUP_NORMAL,
+                                       tf_warning_or_error);
+  return build_cplus_new (ret_type, ret, tf_warning_or_error);
+}
+
+/* Determine the reflection kind for R.  */
+
+static reflect_kind
+get_reflection_kind (tree r)
+{
+  if (eval_is_type (r) == boolean_true_node
+      || eval_is_template (r) == boolean_true_node
+      || eval_is_function (r) == boolean_true_node)
+    return REFLECT_UNDEF;
+  return obvalue_p (r) ? REFLECT_OBJECT : REFLECT_VALUE;
+}
+
+/* Get the reflection of template argument ARG as per
+   std::meta::template_arguments_of.  */
+
+static tree
+get_reflection_of_targ (tree arg)
+{
+  const location_t loc = location_of (arg);
+  /* canonicalize_type_argument already strip_typedefs.  */
+  arg = STRIP_REFERENCE_REF (arg);
+  arg = maybe_get_reference_referent (arg);
+  return get_reflection_raw (loc, arg, get_reflection_kind (arg));
+}
+
+/* Process std::meta::template_arguments_of.
+   Returns: A vector containing reflections of the template arguments of the
+   template specialization represented by r, in the order in which they appear
+   in the corresponding template argument list.
+   For a given template argument A, its corresponding reflection R is
+   determined as follows:
+
+   -- If A denotes a type or type alias, then R is a reflection representing
+      the underlying entity of A.
+   -- Otherwise, if A denotes a class template, variable template, concept,
+      or alias template, then R is a reflection representing A.
+   -- Otherwise, A is a constant template argument.  Let P be the
+      corresponding template parameter.
+      -- If P has reference type, then R is a reflection representing the
+        object or function referred to by A.
+      -- Otherwise, if P has class type, then R represents the corresponding
+        template parameter object.
+      -- Otherwise, R is a reflection representing the value of A.
+
+   Throws: meta::exception unless has_template_arguments(r) is true.  */
+
+static tree
+eval_template_arguments_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                           bool *non_constant_p, tree *jump_target, tree fun)
+{
+  if (eval_has_template_arguments (r) != boolean_true_node)
+    return throw_exception_notargs (loc, ctx, fun, non_constant_p, jump_target);
+
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  tree args = NULL_TREE;
+  if (TYPE_P (r) && typedef_variant_p (r))
+    {
+      if (tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (r))
+       args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo));
+    }
+  else
+    args = get_template_innermost_arguments (r);
+  gcc_assert (args);
+  for (tree arg : tree_vec_range (args))
+    {
+      if (ARGUMENT_PACK_P (arg))
+       {
+         tree pargs = ARGUMENT_PACK_ARGS (arg);
+         for (tree a : tree_vec_range (pargs))
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_of_targ (a));
+       }
+      else
+       CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, get_reflection_of_targ (arg));
+    }
+  return get_vector_of_info_elts (elts);
+}
+
+/* Helper for eval_remove_const to build non-const type.  */
+
+static tree
+remove_const (tree type)
+{
+  return cp_build_qualified_type (type,
+                                 cp_type_quals (type) & ~TYPE_QUAL_CONST);
+}
+
+/* Process std::meta::annotations_of and annotations_of_with_type.
+   Let E be
+   -- the corresponding base-specifier if item represents a direct base class
+      relationship,
+   -- otherwise, the entity represented by item.
+   Returns: A vector containing all of the reflections R representing each
+   annotation applying to each declaration of E that precedes either some
+   point in the evaluation context or a point immediately following the
+   class-specifier of the outermost class for which such a point is in a
+   complete-class context.
+   For any two reflections R1 and R2 in the returned vector, if the annotation
+   represented by R1 precedes the annotation represented by R2, then R1
+   appears before R2.
+   If R1 and R2 represent annotations from the same translation unit T, any
+   element in the returned vector between R1 and R2 represents an annotation
+   from T.
+
+   Throws: meta::exception unless item represents a type, type alias,
+   variable, function, namespace, enumerator, direct base class relationship,
+   or non-static data member.  */
+
+static tree
+eval_annotations_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                    reflect_kind kind, tree type, bool *non_constant_p,
+                    tree *jump_target, tree fun)
+{
+  if (!(eval_is_type (r) == boolean_true_node
+       || eval_is_type_alias (r) == boolean_true_node
+       || eval_is_variable (r, kind) == boolean_true_node
+       || eval_is_function (r) == boolean_true_node
+       || eval_is_namespace (r) == boolean_true_node
+       || eval_is_enumerator (r) == boolean_true_node
+       || eval_is_base (r, kind) == boolean_true_node
+       || eval_is_nonstatic_data_member (r) == boolean_true_node))
+    return throw_exception (loc, ctx,
+                           "reflection does not represent a type,"
+                           " type alias, variable, function, namespace,"
+                           " enumerator, direct base class relationship,"
+                           " or non-static data member",
+                           fun, non_constant_p, jump_target);
+
+  if (type)
+    {
+      type = maybe_strip_typedefs (type);
+      if (!TYPE_P (type)
+         || !complete_type_or_maybe_complain (type, NULL_TREE, tf_none))
+       return throw_exception (loc, ctx,
+                               "reflection does not represent a complete"
+                               " type or type alias", fun, non_constant_p,
+                               jump_target);
+      type = remove_const (type);
+    }
+
+  if (kind == REFLECT_BASE)
+    {
+      gcc_assert (TREE_CODE (r) == TREE_BINFO);
+      tree c = direct_base_parent_binfo (r), binfo = r, base_binfo;
+
+      r = NULL_TREE;
+      for (unsigned ix = 0; BINFO_BASE_ITERATE (c, ix, base_binfo); ix++)
+       if (base_binfo == binfo)
+         {
+           if (ix + BINFO_BASE_BINFOS (c)->length ()
+               < vec_safe_length (BINFO_BASE_ACCESSES (c)))
+             r = BINFO_BASE_ACCESS (c, ix + BINFO_BASE_BINFOS (c)->length ());
+           break;
+         }
+    }
+  else if (TYPE_P (r))
+    r = TYPE_ATTRIBUTES (r);
+  else if (DECL_P (r))
+    r = DECL_ATTRIBUTES (r);
+  else
+    gcc_unreachable ();
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  for (tree a = r; (a = lookup_attribute ("internal ", "annotation ", a));
+       a = TREE_CHAIN (a))
+    {
+      gcc_checking_assert (TREE_CODE (TREE_VALUE (a)) == TREE_LIST);
+      tree val = TREE_VALUE (TREE_VALUE (a));
+      if (type)
+       {
+         tree at = TREE_TYPE (val);
+         if (at != type && !same_type_p (remove_const (at), type))
+           continue;
+       }
+      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                             get_reflection_raw (loc, a, REFLECT_ANNOTATION));
+    }
+  if (elts)
+    {
+      /* Reverse the order.  */
+      unsigned l = elts->length ();
+      constructor_elt *ptr = elts->address ();
+
+      for (unsigned i = 0; i < l / 2; i++)
+       std::swap (ptr[i], ptr[l - i - 1]);
+    }
+  return get_vector_of_info_elts (elts);
+}
+
+/* Process std::meta::reflect_constant.
+   Mandates: is_copy_constructible_v<T> is true and T is a cv-unqualified
+   structural type that is not a reference type.
+   Let V be:
+   -- if T is a class type, then an object that is template-argument-equivalent
+      to the value of expr;
+   -- otherwise, the value of expr.
+   Returns: template_arguments_of(^^TCls<V>)[0], with TCls as defined below.
+   Throws: meta::exception unless the template-id TCls<V> would be valid given
+   the invented template
+     template<T P> struct TCls;  */
+
+static tree
+eval_reflect_constant (location_t loc, const constexpr_ctx *ctx, tree type,
+                      tree expr, bool *non_constant_p, tree *jump_target,
+                      tree fun)
+{
+  if (!structural_type_p (type)
+      || CP_TYPE_VOLATILE_P (type)
+      || CP_TYPE_CONST_P (type)
+      || TYPE_REF_P (type))
+    {
+      error_at (loc, "%qT must be a cv-unqualified structural type that is "
+               "not a reference type", type);
+      return error_mark_node;
+    }
+  expr = convert_reflect_constant_arg (type, convert_from_reference (expr));
+  if (expr == error_mark_node)
+    return throw_exception (loc, ctx, "reflect_constant failed", fun,
+                           non_constant_p, jump_target);
+  return get_reflection_raw (loc, expr, get_reflection_kind (expr));
+}
+
+/* Process std::meta::reflect_object.
+   Mandates: T is an object type.
+   Returns: A reflection of the object designated by expr.
+   Throws: meta::exception unless expr is suitable for use as a constant
+   template argument for a constant template parameter of type T&.  */
+
+static tree
+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)
+    {
+      error_at (loc, "%qT must be an object type", TREE_TYPE (type));
+      return error_mark_node;
+    }
+  type = cp_build_reference_type (type, /*rval=*/false);
+  tree e = convert_reflect_constant_arg (type, convert_from_reference (expr));
+  if (e == error_mark_node)
+    return throw_exception (loc, ctx, "reflect_object failed", fun,
+                           non_constant_p, jump_target);
+  /* We got (const T &) &foo.  Get the referent, since we want the object
+     designated by EXPR.  */
+  expr = maybe_get_reference_referent (expr);
+  return get_reflection_raw (loc, expr, REFLECT_OBJECT);
+}
+
+/* Process std::meta::reflect_function.
+   Mandates: T is a function type.
+   Returns: A reflection of the function designated by fn.
+   Throws: meta::exception unless fn is suitable for use as a constant
+   template argument for a constant template parameter of type T&.  */
+
+static tree
+eval_reflect_function (location_t loc, const constexpr_ctx *ctx, tree type,
+                      tree expr, bool *non_constant_p, tree *jump_target,
+                      tree fun)
+{
+  if (eval_is_function_type (type) != boolean_true_node)
+    {
+      error_at (loc, "%qT must be a function type", TREE_TYPE (type));
+      return error_mark_node;
+    }
+  type = cp_build_reference_type (type, /*rval=*/false);
+  tree e = convert_reflect_constant_arg (type, convert_from_reference (expr));
+  if (e == error_mark_node)
+    return throw_exception (loc, ctx, "reflect_function failed", fun,
+                           non_constant_p, jump_target);
+  /* We got (void (&<Ta885>) (void)) fn.  Get the function.  */
+  expr = maybe_get_reference_referent (expr);
+  return get_reflection_raw (loc, expr);
+}
+
+/* Reflection type traits [meta.reflection.traits].
+
+   Every function and function template declared in this subclause throws
+   an exception of type meta::exception unless the following conditions are
+   met:
+   -- For every parameter p of type info, is_type(p) is true.
+   -- For every parameter r whose type is constrained on reflection_range,
+      ranges::all_of(r, is_type) is true.  */
+
+/* Evaluate reflection type traits for which we have corresponding built-in
+   traits.  KIND says which trait we are interested in; TYPE1 and TYPE2 are
+   arguments to the trait.  */
+
+static tree
+eval_type_trait (location_t loc, tree type1, tree type2, cp_trait_kind kind)
+{
+  tree r = finish_trait_expr (loc, kind, type1, type2);
+  STRIP_ANY_LOCATION_WRAPPER (r);
+  return r;
+}
+
+/* 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)
+{
+  return eval_type_trait (loc, type, NULL_TREE, kind);
+}
+
+/* Process std::meta::is_function_type.  */
+
+static tree
+eval_is_function_type (tree type)
+{
+  if (FUNC_OR_METHOD_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_void_type.  */
+
+static tree
+eval_is_void_type (tree type)
+{
+  if (VOID_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_null_pointer_type.  */
+
+static tree
+eval_is_null_pointer_type (tree type)
+{
+  if (NULLPTR_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_integral_type.  */
+
+static tree
+eval_is_integral_type (tree type)
+{
+  if (CP_INTEGRAL_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_floating_point_type.  */
+
+static tree
+eval_is_floating_point_type (tree type)
+{
+  if (FLOAT_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_array_type.  */
+
+static tree
+eval_is_array_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_ARRAY);
+}
+
+/* Process std::meta::is_pointer_type.  */
+
+static tree
+eval_is_pointer_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_POINTER);
+}
+
+/* Process std::meta::is_lvalue_reference_type.  */
+
+static tree
+eval_is_lvalue_reference_type (tree type)
+{
+  if (TYPE_REF_P (type) && !TYPE_REF_IS_RVALUE (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_rvalue_reference_type.  */
+
+static tree
+eval_is_rvalue_reference_type (tree type)
+{
+  if (TYPE_REF_P (type) && TYPE_REF_IS_RVALUE (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_member_object_pointer_type.  */
+
+static tree
+eval_is_member_object_pointer_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_MEMBER_OBJECT_POINTER);
+}
+
+/* Process std::meta::is_member_function_pointer_type.  */
+
+static tree
+eval_is_member_function_pointer_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_MEMBER_FUNCTION_POINTER);
+}
+
+/* Process std::meta::is_enum_type.  */
+
+static tree
+eval_is_enum_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_ENUM);
+}
+
+/* Process std::meta::is_union_type.  */
+
+static tree
+eval_is_union_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_UNION);
+}
+
+/* Process std::meta::is_class_type.  */
+
+static tree
+eval_is_class_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_CLASS);
+}
+
+/* Process std::meta::is_reflection_type.  */
+
+static tree
+eval_is_reflection_type (tree type)
+{
+  if (REFLECTION_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_reference_type.  */
+
+static tree
+eval_is_reference_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_REFERENCE);
+}
+
+/* Process std::meta::is_arithmetic_type.  */
+
+static tree
+eval_is_arithmetic_type (tree type)
+{
+  if (ARITHMETIC_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_object_type.  */
+
+static tree
+eval_is_object_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_OBJECT);
+}
+
+/* Process std::meta::is_scalar_type.  */
+
+static tree
+eval_is_scalar_type (tree type)
+{
+  if (SCALAR_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_fundamental_type.  */
+
+static tree
+eval_is_fundamental_type (tree type)
+{
+  if (ARITHMETIC_TYPE_P (type)
+      || VOID_TYPE_P (type)
+      || NULLPTR_TYPE_P (type)
+      || REFLECTION_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_compound_type.  */
+
+static tree
+eval_is_compound_type (tree type)
+{
+  if (eval_is_fundamental_type (type) == boolean_false_node)
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_member_pointer_type.  */
+
+static tree
+eval_is_member_pointer_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_MEMBER_POINTER);
+}
+
+/* Process std::meta::is_const_type.  */
+
+static tree
+eval_is_const_type (tree type)
+{
+  if (CP_TYPE_CONST_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_volatile_type.  */
+
+static tree
+eval_is_volatile_type (tree type)
+{
+  if (CP_TYPE_VOLATILE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_trivially_copyable_type.  */
+
+static tree
+eval_is_trivially_copyable_type (tree type)
+{
+  if (trivially_copyable_p (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_standard_layout_type.  */
+
+static tree
+eval_is_standard_layout_type (tree type)
+{
+  if (std_layout_type_p (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_empty_type.  */
+
+static tree
+eval_is_empty_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_EMPTY);
+}
+
+/* Process std::meta::is_polymorphic_type.  */
+
+static tree
+eval_is_polymorphic_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_POLYMORPHIC);
+}
+
+/* Process std::meta::is_abstract_type.  */
+
+static tree
+eval_is_abstract_type (tree type)
+{
+  if (ABSTRACT_CLASS_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_final_type.  */
+
+static tree
+eval_is_final_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_FINAL);
+}
+
+/* Process std::meta::is_final.
+   Returns: true if r represents a final class or a final member function.
+   Otherwise, false.  */
+
+static tree
+eval_is_final (tree r)
+{
+  if (eval_is_function (r) == boolean_true_node)
+    {
+      r = maybe_get_reflection_fndecl (r);
+      if (TREE_CODE (r) == FUNCTION_DECL && DECL_FINAL_P (r))
+       return boolean_true_node;
+      else
+       return boolean_false_node;
+    }
+
+  if (eval_is_type (r) == boolean_true_node
+      && CLASS_TYPE_P (r)
+      && CLASSTYPE_FINAL (r))
+    return boolean_true_node;
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::is_aggregate_type.  */
+
+static tree
+eval_is_aggregate_type (tree type)
+{
+  if (CP_AGGREGATE_TYPE_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_consteval_only_type.  */
+
+static tree
+eval_is_consteval_only_type (tree type)
+{
+  if (consteval_only_p (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_signed_type.  */
+
+static tree
+eval_is_signed_type (tree type)
+{
+  if (ARITHMETIC_TYPE_P (type) && !TYPE_UNSIGNED (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_unsigned_type.  */
+
+static tree
+eval_is_unsigned_type (tree type)
+{
+  if (ARITHMETIC_TYPE_P (type) && TYPE_UNSIGNED (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_bounded_array_type.  */
+
+static tree
+eval_is_bounded_array_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_BOUNDED_ARRAY);
+}
+
+/* Process std::meta::is_unbounded_array_type.  */
+
+static tree
+eval_is_unbounded_array_type (tree type)
+{
+  if (array_of_unknown_bound_p (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_scoped_enum_type.  */
+
+static tree
+eval_is_scoped_enum_type (tree type)
+{
+  if (SCOPED_ENUM_P (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_constructible_type.  */
+
+static tree
+eval_is_constructible_type (tree type, tree tvec)
+{
+  if (is_xible (INIT_EXPR, type, tvec))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_default_constructible_type.  */
+
+static tree
+eval_is_default_constructible_type (tree type)
+{
+  if (is_xible (INIT_EXPR, type, make_tree_vec (0)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_copy_constructible_type.  */
+
+static tree
+eval_is_copy_constructible_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_move_constructible_type.  */
+
+static tree
+eval_is_move_constructible_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_assignable_type.  */
+
+static tree
+eval_is_assignable_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_ASSIGNABLE);
+}
+
+/* Process std::meta::is_copy_assignable_type.  */
+
+static tree
+eval_is_copy_assignable_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_move_assignable_type.  */
+
+static tree
+eval_is_move_assignable_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_destructible_type.  */
+
+static tree
+eval_is_destructible_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_DESTRUCTIBLE);
+}
+
+/* Process std::meta::is_trivially_constructible_type.  */
+
+static tree
+eval_is_trivially_constructible_type (tree type, tree tvec)
+{
+  if (is_trivially_xible (INIT_EXPR, type, tvec))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_trivially_default_constructible_type.  */
+
+static tree
+eval_is_trivially_default_constructible_type (tree type)
+{
+  if (is_trivially_xible (INIT_EXPR, type, make_tree_vec (0)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_trivially_copy_constructible_type.  */
+
+static tree
+eval_is_trivially_copy_constructible_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_trivially_move_constructible_type.  */
+
+static tree
+eval_is_trivially_move_constructible_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_trivially_assignable_type.  */
+
+static tree
+eval_is_trivially_assignable_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_TRIVIALLY_ASSIGNABLE);
+}
+
+/* Process std::meta::is_trivially_copy_assignable_type.  */
+
+static tree
+eval_is_trivially_copy_assignable_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_trivially_move_assignable_type.  */
+
+static tree
+eval_is_trivially_move_assignable_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_trivially_destructible_type.  */
+
+static tree
+eval_is_trivially_destructible_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_TRIVIALLY_DESTRUCTIBLE);
+}
+
+/* Process std::meta::is_nothrow_constructible_type.  */
+
+static tree
+eval_is_nothrow_constructible_type (tree type, tree tvec)
+{
+  if (is_nothrow_xible (INIT_EXPR, type, tvec))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_nothrow_default_constructible_type.  */
+
+static tree
+eval_is_nothrow_default_constructible_type (tree type)
+{
+  if (is_nothrow_xible (INIT_EXPR, type, make_tree_vec (0)))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::is_nothrow_copy_constructible_type.  */
+
+static tree
+eval_is_nothrow_copy_constructible_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_nothrow_move_constructible_type.  */
+
+static tree
+eval_is_nothrow_move_constructible_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_nothrow_assignable_type.  */
+
+static tree
+eval_is_nothrow_assignable_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_NOTHROW_ASSIGNABLE);
+}
+
+/* Process std::meta::is_nothrow_copy_assignable_type.  */
+
+static tree
+eval_is_nothrow_copy_assignable_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_nothrow_move_assignable_type.  */
+
+static tree
+eval_is_nothrow_move_assignable_type (tree type)
+{
+  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;
+}
+
+/* Process std::meta::is_nothrow_destructible_type.  */
+
+static tree
+eval_is_nothrow_destructible_type (location_t loc, tree type)
+{
+  return eval_type_trait (loc, type, CPTK_IS_NOTHROW_DESTRUCTIBLE);
+}
+
+/* Process std::meta::is_implicit_lifetime_type.  */
+
+static tree
+eval_is_implicit_lifetime_type (tree type)
+{
+  if (implicit_lifetime_type_p (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_virtual_destructor.  */
+
+static tree
+eval_has_virtual_destructor (tree type)
+{
+  if (type_has_virtual_destructor (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::has_unique_object_representations.  */
+
+static tree
+eval_has_unique_object_representations (tree type)
+{
+  if (type_has_unique_obj_representations (type))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Process std::meta::reference_constructs_from_temporary.  */
+
+static tree
+eval_reference_constructs_from_temporary (location_t loc, tree type1,
+                                         tree type2)
+{
+  return eval_type_trait (loc, type1, type2,
+                         CPTK_REF_CONSTRUCTS_FROM_TEMPORARY);
+}
+
+/* Process std::meta::reference_converts_from_temporary.  */
+
+static tree
+eval_reference_converts_from_temporary (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_REF_CONVERTS_FROM_TEMPORARY);
+}
+
+/* Process std::meta::rank.  */
+
+static tree
+eval_rank (tree type)
+{
+  size_t rank = 0;
+  for (; TREE_CODE (type) == ARRAY_TYPE; type = TREE_TYPE (type))
+    ++rank;
+  return build_int_cst (size_type_node, rank);
+}
+
+/* Process std::meta::extent.  */
+
+static tree
+eval_extent (location_t loc, tree type, tree i)
+{
+  size_t rank = tree_to_uhwi (i);
+  while (rank && TREE_CODE (type) == ARRAY_TYPE)
+    {
+      --rank;
+      type = TREE_TYPE (type);
+    }
+  if (rank
+      || TREE_CODE (type) != ARRAY_TYPE
+      || eval_is_bounded_array_type (loc, type) == boolean_false_node)
+     return size_zero_node;
+  return size_binop (PLUS_EXPR, TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+                    size_one_node);
+}
+
+/* Process std::meta::is_same_type.  */
+
+static tree
+eval_is_same_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_SAME);
+}
+
+/* Process std::meta::is_base_of_type.  */
+
+static tree
+eval_is_base_of_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_BASE_OF);
+}
+
+/* Process std::meta::is_virtual_base_of_type.  */
+
+static tree
+eval_is_virtual_base_of_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_VIRTUAL_BASE_OF);
+}
+
+/* Process std::meta::is_convertible_type.  */
+
+static tree
+eval_is_convertible_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_CONVERTIBLE);
+}
+
+/* Process std::meta::is_nothrow_convertible_type.  */
+
+static tree
+eval_is_nothrow_convertible_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_NOTHROW_CONVERTIBLE);
+}
+
+/* Process std::meta::is_layout_compatible_type.  */
+
+static tree
+eval_is_layout_compatible_type (location_t loc, tree type1, tree type2)
+{
+  return eval_type_trait (loc, type1, type2, CPTK_IS_LAYOUT_COMPATIBLE);
+}
+
+/* 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)
+{
+  return eval_type_trait (loc, type1, type2,
+                         CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF);
+}
+
+/* Process std::meta::is_invocable_type.  */
+
+static tree
+eval_is_invocable_type (location_t loc, tree type, tree tvec)
+{
+  tree r = finish_trait_expr (loc, CPTK_IS_INVOCABLE, type, tvec);
+  STRIP_ANY_LOCATION_WRAPPER (r);
+  return r;
+}
+
+/* Helper for various eval_* type trait functions which can't use builtin
+   trait and have to instantiate std::NAME<ARGS>::value.  */
+
+static tree
+finish_library_value_trait (location_t loc, const constexpr_ctx *ctx,
+                           const char *name, tree args, tree call,
+                           bool *non_constant_p, tree *jump_target, tree fun)
+{
+  tree inst = lookup_template_class (get_identifier (name), args,
+                                    /*in_decl*/NULL_TREE, /*context*/std_node,
+                                    tf_warning_or_error);
+  inst = complete_type (inst);
+  if (inst == error_mark_node
+      || !COMPLETE_TYPE_P (inst)
+      || !CLASS_TYPE_P (inst))
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "couldn%'t instantiate %<std::%s<%T>%>",
+                 name, args);
+      *non_constant_p = true;
+      return call;
+    }
+  tree val = lookup_qualified_name (inst, value_identifier,
+                                   LOOK_want::NORMAL, /*complain*/false);
+  if (val == error_mark_node)
+    return throw_exception (loc, ctx, "value member missing",
+                           fun, non_constant_p, jump_target);
+  if (VAR_P (val) || TREE_CODE (val) == CONST_DECL)
+    val = maybe_constant_value (val, NULL_TREE, mce_true);
+  if (TREE_CODE (TREE_TYPE (call)) == BOOLEAN_TYPE)
+    {
+      if (integer_zerop (val))
+       return boolean_false_node;
+      else if (integer_nonzerop (val))
+       return boolean_true_node;
+      else
+       return throw_exception (loc, ctx, "unexpected value of value member",
+                               fun, non_constant_p, jump_target);
+    }
+  else if (TREE_CODE (val) == INTEGER_CST)
+    {
+      val = build_converted_constant_expr (TREE_TYPE (call), val, tf_none);
+      if (TREE_CODE (val) == INTEGER_CST)
+       return val;
+    }
+  return throw_exception (loc, ctx, "unexpected value of value member",
+                         fun, non_constant_p, jump_target);
+}
+
+/* Process std::meta::is_{,nothrow_}invocable_r_type.  */
+
+static tree
+eval_is_invocable_r_type (location_t loc, const constexpr_ctx *ctx,
+                         tree tres, tree type, tree tvec, tree call,
+                         bool *non_constant_p, tree *jump_target, tree fun,
+                         const char *name)
+{
+  /* Create std::is_invocable_r<TYPE>::value.  */
+  tree args = make_tree_vec (TREE_VEC_LENGTH (tvec) + 2);
+  TREE_VEC_ELT (args, 0) = tres;
+  TREE_VEC_ELT (args, 1) = type;
+  for (int i = 0; i < TREE_VEC_LENGTH (tvec); ++i)
+    TREE_VEC_ELT (args, i + 2) = TREE_VEC_ELT (tvec, i);
+  return finish_library_value_trait (loc, ctx, name, args, call,
+                                    non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::is_nothrow_invocable_type.  */
+
+static tree
+eval_is_nothrow_invocable_type (location_t loc, tree type, tree tvec)
+{
+  tree r = finish_trait_expr (loc, CPTK_IS_NOTHROW_INVOCABLE, type, tvec);
+  STRIP_ANY_LOCATION_WRAPPER (r);
+  return r;
+}
+
+/* Process std::meta::is_{,nothrow_}swappable_with_type.  */
+
+static tree
+eval_is_swappable_with_type (location_t loc, const constexpr_ctx *ctx,
+                            tree type1, tree type2, tree call,
+                            bool *non_constant_p, tree *jump_target, tree fun,
+                            const char *name)
+{
+  /* Create std::is_swappable_with<TYPE>::value.  */
+  tree args = make_tree_vec (2);
+  TREE_VEC_ELT (args, 0) = type1;
+  TREE_VEC_ELT (args, 1) = type2;
+  return finish_library_value_trait (loc, ctx, name, args, call,
+                                    non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::is_{,nothrow_}swappable_type.  */
+
+static tree
+eval_is_swappable_type (location_t loc, const constexpr_ctx *ctx,
+                       tree type, tree call, bool *non_constant_p,
+                       tree *jump_target, tree fun, const char *name)
+{
+  /* Create std::is_swappable<TYPE>::value.  */
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = type;
+  return finish_library_value_trait (loc, ctx, name, args, call,
+                                    non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::remove_cvref.  */
+
+static tree
+eval_remove_cvref (location_t loc, tree type)
+{
+  if (TYPE_REF_P (type))
+    type = TREE_TYPE (type);
+  type = finish_trait_type (CPTK_REMOVE_CV, type, NULL_TREE, tf_none);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::decay.  */
+
+static tree
+eval_decay (location_t loc, tree type)
+{
+  type = finish_trait_type (CPTK_DECAY, type, NULL_TREE, tf_none);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Helper for various eval_* type trait functions which can't use builtin
+   trait and have to instantiate std::NAME<ARGS>::type.  */
+
+static tree
+finish_library_type_trait (location_t loc, const constexpr_ctx *ctx,
+                          const char *name, tree args, tree call,
+                          bool *non_constant_p, tree *jump_target, tree fun)
+{
+  tree inst = lookup_template_class (get_identifier (name), args,
+                                    /*in_decl*/NULL_TREE,
+                                    /*context*/std_node,
+                                    tf_warning_or_error);
+  if (inst == error_mark_node)
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "couldn%'t instantiate %<std::%s<%T>%>",
+                 name, args);
+      *non_constant_p = true;
+      return call;
+    }
+  tree type = make_typename_type (inst, type_identifier,
+                                 none_type, tf_none);
+  if (type == error_mark_node)
+    return throw_exception (loc, ctx, "type member missing",
+                           fun, non_constant_p, jump_target);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::common_{type,reference}.  */
+
+static tree
+eval_common_type (location_t loc, const constexpr_ctx *ctx, tree tvec,
+                 tree call, bool *non_constant_p, tree *jump_target, tree fun,
+                 const char *name)
+{
+  return finish_library_type_trait (loc, ctx, name, tvec, call,
+                                   non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::underlying_type.  */
+
+static tree
+eval_underlying_type (location_t loc, const constexpr_ctx *ctx, tree type,
+                     bool *non_constant_p, tree *jump_target, tree fun)
+{
+  if (TREE_CODE (type) != ENUMERAL_TYPE || !COMPLETE_TYPE_P (type))
+    return throw_exception (loc, ctx, "reflection does not represent "
+                                     "a complete enumeration type",
+                           fun, non_constant_p, jump_target);
+  type = finish_underlying_type (type);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::invoke_result.  */
+
+static tree
+eval_invoke_result (location_t loc, const constexpr_ctx *ctx, tree type,
+                   tree tvec, tree call, bool *non_constant_p,
+                   tree *jump_target, tree fun)
+{
+  tree args = make_tree_vec (TREE_VEC_LENGTH (tvec) + 1);
+  TREE_VEC_ELT (args, 0) = type;
+  for (int i = 0; i < TREE_VEC_LENGTH (tvec); ++i)
+    TREE_VEC_ELT (args, i + 1) = TREE_VEC_ELT (tvec, i);
+  return finish_library_type_trait (loc, ctx, "invoke_result", args, call,
+                                   non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::unwrap_{reference,ref_decay}.  */
+
+static tree
+eval_unwrap_reference (location_t loc, const constexpr_ctx *ctx, tree type,
+                      tree call, bool *non_constant_p, tree *jump_target,
+                      tree fun, const char *name)
+{
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = type;
+  return finish_library_type_trait (loc, ctx, name, args, call,
+                                   non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::type_order.  */
+
+static tree
+eval_type_order (tree type1, tree type2)
+{
+  return type_order_value (strip_typedefs (type1), strip_typedefs (type2));
+}
+
+/* Process std::meta::enumerators_of.
+   Returns: A vector containing the reflections of each enumerator of the
+   enumeration represented by dealias(type_enum), in the order in which they
+   are declared.
+   Throws: meta::exception unless dealias(type_enum) represents an enumeration
+   type, and is_enumerable_type(type_enum) is true.  */
+
+static tree
+eval_enumerators_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                    bool *non_constant_p, tree *jump_target, tree fun)
+{
+  if (TREE_CODE (r) != ENUMERAL_TYPE
+      || eval_is_enumerable_type (r) == boolean_false_node)
+    return throw_exception (loc, ctx, "reflection does not represent an "
+                                     "enumerable enumeration type", fun,
+                           non_constant_p, jump_target);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  for (tree t = TYPE_VALUES (r); t; t = TREE_CHAIN (t))
+    {
+      tree e = TREE_VALUE (t);
+      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, get_reflection_raw (loc, e));
+    }
+  return get_vector_of_info_elts (elts);
+}
+
+/* Process std::meta::remove_const.
+   Returns: a reflection representing the type denoted by
+   std::remove_const_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_const (location_t loc, tree type)
+{
+  return get_reflection_raw (loc, remove_const (strip_typedefs (type)));
+}
+
+/* Process std::meta::remove_volatile.
+   Returns: a reflection representing the type denoted by
+   std::remove_volatile_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_volatile (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  int quals = cp_type_quals (type);
+  quals &= ~TYPE_QUAL_VOLATILE;
+  type = cp_build_qualified_type (type, quals);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::remove_cv.
+   Returns: a reflection representing the type denoted by
+   std::remove_cv_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_cv (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  type = finish_trait_type (CPTK_REMOVE_CV, type, NULL_TREE, tf_none);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::add_const.
+   Returns: a reflection representing the type denoted by
+   std::add_const_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_add_const (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  if (!TYPE_REF_P (type) && !FUNC_OR_METHOD_TYPE_P (type))
+    {
+      int quals = cp_type_quals (type);
+      quals |= TYPE_QUAL_CONST;
+      type = cp_build_qualified_type (type, quals);
+    }
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::add_volatile.
+   Returns: a reflection representing the type denoted by
+   std::add_volatile_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_add_volatile (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  if (!TYPE_REF_P (type) && !FUNC_OR_METHOD_TYPE_P (type))
+    {
+      int quals = cp_type_quals (type);
+      quals |= TYPE_QUAL_VOLATILE;
+      type = cp_build_qualified_type (type, quals);
+    }
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::add_cv.
+   Returns: a reflection representing the type denoted by
+   std::add_cv_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_add_cv (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  if (!TYPE_REF_P (type) && !FUNC_OR_METHOD_TYPE_P (type))
+    {
+      int quals = cp_type_quals (type);
+      quals |= (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+      type = cp_build_qualified_type (type, quals);
+    }
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::remove_reference.
+   Returns: a reflection representing the type denoted by
+   std::remove_reference_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_reference (location_t loc, tree type)
+{
+  if (TYPE_REF_P (type))
+    type = TREE_TYPE (type);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::add_lvalue_reference.
+   Returns: a reflection representing the type denoted by
+   std::add_lvalue_reference_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_add_lvalue_reference (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  type = finish_trait_type (CPTK_ADD_LVALUE_REFERENCE, type, NULL_TREE, tf_none);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::add_rvalue_reference.
+   Returns: a reflection representing the type denoted by
+   std::add_rvalue_reference_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_add_rvalue_reference (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  type = finish_trait_type (CPTK_ADD_RVALUE_REFERENCE, type, NULL_TREE, tf_none);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::make_signed and std::meta::make_unsigned.
+   Returns: a reflection representing the type denoted by
+   std::make_signed_t<T> or std::make_unsigned_t<T>, respectively, where T is
+   the type or type alias represented by type.  */
+
+static tree
+eval_make_signed (location_t loc, const constexpr_ctx *ctx, tree type,
+                 bool unsignedp, bool *non_constant_p, tree *jump_target,
+                 tree fun)
+{
+  if (!INTEGRAL_TYPE_P (type) || TREE_CODE (type) == BOOLEAN_TYPE)
+    return throw_exception (loc, ctx, "reflection represents non-integral "
+                                     "or bool type", fun, non_constant_p,
+                                     jump_target);
+  tree ret = type;
+  if (TREE_CODE (type) == ENUMERAL_TYPE
+      || TYPE_MAIN_VARIANT (type) == wchar_type_node
+      || TYPE_MAIN_VARIANT (type) == char8_type_node
+      || TYPE_MAIN_VARIANT (type) == char16_type_node
+      || TYPE_MAIN_VARIANT (type) == char32_type_node)
+    {
+      tree unit = TYPE_SIZE_UNIT (type);
+      tree types[] = {
+       signed_char_type_node,
+       short_integer_type_node,
+       integer_type_node,
+       long_integer_type_node,
+       long_long_integer_type_node };
+      ret = NULL_TREE;
+      for (unsigned i = 0; i < ARRAY_SIZE (types); ++i)
+       if (tree_int_cst_equal (TYPE_SIZE_UNIT (types[i]), unit))
+         {
+           ret = c_common_signed_or_unsigned_type (unsignedp, types[i]);
+           break;
+         }
+      if (!ret)
+       ret = c_common_type_for_size (TYPE_PRECISION (type), unsignedp);
+    }
+  else if (TYPE_MAIN_VARIANT (type) == char_type_node)
+    ret = unsignedp ? unsigned_char_type_node : signed_char_type_node;
+  else if (unsignedp ^ (!!TYPE_UNSIGNED (type)))
+    ret = c_common_signed_or_unsigned_type (unsignedp, type);
+  if (ret != type)
+    {
+      int quals = cp_type_quals (type);
+      quals &= (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+      ret = cp_build_qualified_type (ret, quals);
+    }
+  else
+    ret = strip_typedefs (type);
+  return get_reflection_raw (loc, ret);
+}
+
+/* Process std::meta::remove_extent.
+   Returns: a reflection representing the type denoted by
+   std::remove_extent_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_extent (location_t loc, tree type)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    type = TREE_TYPE (type);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::remove_all_extents.
+   Returns: a reflection representing the type denoted by
+   std::remove_all_extents_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_all_extents (location_t loc, tree type)
+{
+  type = strip_array_types (type);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::remove_pointer.
+   Returns: a reflection representing the type denoted by
+   std::remove_pointer_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_remove_pointer (location_t loc, tree type)
+{
+  if (TYPE_PTR_P (type))
+    type = TREE_TYPE (type);
+  type = strip_typedefs (type);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::add_pointer.
+   Returns: a reflection representing the type denoted by
+   std::add_pointer_t<T>, where T is the type or type alias
+   represented by type.  */
+
+static tree
+eval_add_pointer (location_t loc, tree type)
+{
+  type = strip_typedefs (type);
+  type = finish_trait_type (CPTK_ADD_POINTER, type, NULL_TREE, tf_none);
+  return get_reflection_raw (loc, type);
+}
+
+/* Process std::meta::is_lvalue_reference_qualified and
+   std::meta::is_rvalue_reference_qualified.
+   Let T be type_of(r) if has-type(r) is true.  Otherwise, let T be
+   dealias(r).
+   Returns: true if T represents an lvalue- or rvalue-qualified
+   function type, respectively.  Otherwise, false.
+   RVALUE_P is true if we're processing is_rvalue_*, false if we're
+   processing is_lvalue_*.  */
+
+static tree
+eval_is_lrvalue_reference_qualified (tree r, reflect_kind kind,
+                                    bool rvalue_p)
+{
+  if (has_type (r, kind))
+    r = type_of (r, kind);
+  else
+    r = maybe_strip_typedefs (r);
+  if (FUNC_OR_METHOD_TYPE_P (r)
+      && FUNCTION_REF_QUALIFIED (r)
+      && rvalue_p == FUNCTION_RVALUE_QUALIFIED (r))
+    return boolean_true_node;
+
+  return boolean_false_node;
+}
+
+/* Process std::meta::can_substitute.
+   Let Z be the template represented by templ and let Args... be a sequence of
+   prvalue constant expressions that compute the reflections held by the
+   elements of arguments, in order.
+   Returns: true if Z<[:Args:]...> is a valid template-id that does not name
+   a function whose type contains an undeduced placeholder type.
+   Otherwise, false.
+   Throws: meta::exception unless templ represents a template, and every
+   reflection in arguments represents a construct usable as a template
+   argument.  */
+
+static tree
+eval_can_substitute (location_t loc, const constexpr_ctx *ctx,
+                    tree r, tree rvec, bool *non_constant_p, tree *jump_target,
+                    tree fun)
+{
+  if (eval_is_template (r) != boolean_true_node)
+    return throw_exception (loc, ctx,
+                           "reflection does not represent a template",
+                           fun, non_constant_p, jump_target);
+  for (int i = 0; i < TREE_VEC_LENGTH (rvec); ++i)
+    {
+      tree ra = TREE_VEC_ELT (rvec, i);
+      tree a = REFLECT_EXPR_HANDLE (ra);
+      reflect_kind kind = REFLECT_EXPR_KIND (ra);
+      // TODO: It is unclear on what kinds of reflections we should throw
+      // and what kinds of exceptions should merely result in can_substitute
+      // returning false.
+      if (a == unknown_type_node
+         || kind == REFLECT_PARM
+         || eval_is_namespace (a) == boolean_true_node
+         || eval_is_constructor (a) == boolean_true_node
+         || eval_is_destructor (a) == boolean_true_node
+         || eval_is_annotation (a, kind) == boolean_true_node
+         || (TREE_CODE (a) == FIELD_DECL && !DECL_UNNAMED_BIT_FIELD (a))
+         || kind == REFLECT_DATA_MEMBER_SPEC
+         || kind == REFLECT_BASE
+         || (!TYPE_P (a)
+             && eval_is_template (a) == boolean_false_node
+             && !has_type (a, kind)))
+       return throw_exception (loc, ctx,
+                               "invalid argument to can_substitute",
+                               fun, non_constant_p, jump_target);
+      a = resolve_nondeduced_context (a, tf_warning_or_error);
+      TREE_VEC_ELT (rvec, i) = a;
+    }
+  if (DECL_TYPE_TEMPLATE_P (r) || DECL_TEMPLATE_TEMPLATE_PARM_P (r))
+    {
+      tree type = lookup_template_class (r, rvec, NULL_TREE, NULL_TREE,
+                                        tf_none);
+      if (type == error_mark_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  else if (concept_definition_p (r))
+    {
+      tree c = build_concept_check (r, rvec, tf_none);
+      if (c == error_mark_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  else if (variable_template_p (r))
+    {
+      tree var = lookup_template_variable (r, rvec, tf_none);
+      if (var == error_mark_node)
+       return boolean_false_node;
+      var = finish_template_variable (var, tf_none);
+      if (var == error_mark_node)
+       return boolean_false_node;
+      else
+       return boolean_true_node;
+    }
+  else
+    {
+      tree fn = lookup_template_function (r, rvec);
+      if (fn == error_mark_node)
+       return boolean_false_node;
+      fn = resolve_nondeduced_context_or_error (fn, tf_none);
+      if (fn == error_mark_node)
+       return boolean_false_node;
+      return boolean_true_node;
+    }
+}
+
+/* Process std::meta::substitute.
+   Let Z be the template represented by templ and let Args... be a sequence of
+   prvalue constant expressions that compute the reflections held by the
+   elements of arguments, in order.
+   Returns: ^^Z<[:Args:]...>.
+   Throws: meta::exception unless can_substitute(templ, arguments) is true.  */
+
+static tree
+eval_substitute (location_t loc, const constexpr_ctx *ctx,
+                tree r, tree rvec, bool *non_constant_p, tree *jump_target,
+                tree fun)
+{
+  tree cs = eval_can_substitute (loc, ctx, r, rvec, non_constant_p, jump_target,
+                                fun);
+  if (*jump_target)
+    return cs;
+  if (cs == boolean_false_node)
+    return throw_exception (loc, ctx, "can_substitute returned false",
+                           fun, non_constant_p, jump_target);
+  tree ret = NULL_TREE;
+  if (DECL_TYPE_TEMPLATE_P (r) || DECL_TEMPLATE_TEMPLATE_PARM_P (r))
+    ret = lookup_template_class (r, rvec, NULL_TREE, NULL_TREE, tf_none);
+  else if (concept_definition_p (r))
+    {
+      ret = build_concept_check (r, rvec, tf_none);
+      ret = evaluate_concept_check (ret);
+      return get_reflection_raw (loc, ret, REFLECT_VALUE);
+    }
+  else if (variable_template_p (r))
+    {
+      ret = lookup_template_variable (r, rvec, tf_none);
+      ret = finish_template_variable (ret, tf_none);
+    }
+  else
+    ret = lookup_template_function (r, rvec);
+  return get_reflection_raw (loc, ret);
+}
+
+/* Process std::meta::tuple_size.
+   Returns: tuple_size_v<T>, where T is the type represented by
+   dealias(type).  */
+
+static tree
+eval_tuple_size (location_t loc, const constexpr_ctx *ctx, tree type,
+                tree call, bool *non_constant_p, tree *jump_target,
+                tree fun)
+{
+  /* Create std::tuple_size<TYPE>::value.  */
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = type;
+  return finish_library_value_trait (loc, ctx, "tuple_size", args, call,
+                                    non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::tuple_element.
+   Returns: A reflection representing the type denoted by
+   tuple_element_t<I, T>, where T is the type represented by dealias(type)
+   and I is a constant equal to index.  */
+
+static tree
+eval_tuple_element (location_t loc, const constexpr_ctx *ctx, tree i,
+                   tree type, tree call, bool *non_constant_p,
+                   tree *jump_target, tree fun)
+{
+  /* Create std::tuple_element<I,TYPE>::type.  */
+  tree args = make_tree_vec (2);
+  TREE_VEC_ELT (args, 0) = i;
+  TREE_VEC_ELT (args, 1) = type;
+  return finish_library_type_trait (loc, ctx, "tuple_element",
+                                   args, call, non_constant_p, jump_target,
+                                   fun);
+}
+
+/* Process std::meta::variant_size.
+   Returns: variant_size_v<T>, where T is the type represented by
+   dealias(type).  */
+
+static tree
+eval_variant_size (location_t loc, const constexpr_ctx *ctx, tree type,
+                  tree call, bool *non_constant_p, tree *jump_target,
+                  tree fun)
+{
+  /* Create std::variant_size<TYPE>::value.  */
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = type;
+  return finish_library_value_trait (loc, ctx, "variant_size", args, call,
+                                    non_constant_p, jump_target, fun);
+}
+
+/* Process std::meta::variant_alternative.
+   Returns: A reflection representing the type denoted by
+   variant_alternative_t<I, T>, where T is the type represented by
+   dealias(type) and I is a constant equal to index.  */
+
+static tree
+eval_variant_alternative (location_t loc, const constexpr_ctx *ctx, tree i,
+                         tree type, tree call, bool *non_constant_p,
+                         tree *jump_target, tree fun)
+{
+  /* Create std::variant_alternative<I,TYPE>::type.  */
+  tree args = make_tree_vec (2);
+  TREE_VEC_ELT (args, 0) = i;
+  TREE_VEC_ELT (args, 1) = type;
+  return finish_library_type_trait (loc, ctx, "variant_alternative",
+                                   args, call, non_constant_p, jump_target,
+                                   fun);
+}
+
+/* Process std::meta::data_member_spec.
+   Returns: A reflection of a data member description (T,N,A,W,NUA) where
+   -- T is the type represented by dealias(type),
+   -- N is either the identifier encoded by options.name or _|_ if
+      options.name does not contain a value,
+   -- A is either the alignment value held by options.alignment or _|_ if
+      options.alignment does not contain a value,
+   -- W is either the value held by options.bit_width or _|_ if
+      options.bit_width does not contain a value, and
+   -- NUA is the value held by options.no_unique_address.
+   Throws: meta::exception unless the following conditions are met:
+   -- dealias(type) represents either an object type or a reference type;
+   -- if options.name contains a value, then:
+      -- holds_alternative<u8string>(options.name->contents) is true and
+        get<u8string>(options.name->contents) contains a valid identifier
+        that is not a keyword when interpreted with UTF-8, or
+      -- holds_alternative<string>(options.name->contents) is true and
+        get<string>(options.name->contents) contains a valid identifier
+        that is not a keyword when interpreted with the ordinary literal
+        encoding;
+   -- if options.name does not contain a value, then options.bit_width
+      contains a value;
+   -- if options.bit_width contains a value V, then
+      -- is_integral_type(type) || is_enum_type(type) is true,
+      -- options.alignment does not contain a value,
+      -- options.no_unique_address is false,
+      -- V is not negative, and
+      -- if V equals 0, then options.name does not contain a value; and
+   -- if options.alignment contains a value, it is an alignment value not less
+      than alignment_of(type).  */
+
+static tree
+eval_data_member_spec (location_t loc, const constexpr_ctx *ctx,
+                      tree type, tree opts, bool *non_constant_p,
+                      bool *overflow_p, tree *jump_target, tree fun)
+{
+  type = strip_typedefs (type);
+  if (!TYPE_OBJ_P (type) && !TYPE_REF_P (type))
+    return throw_exception (loc, ctx, "type is not object or reference type",
+                           fun, non_constant_p, jump_target);
+  opts = convert_from_reference (opts);
+  if (!CLASS_TYPE_P (TREE_TYPE (opts)))
+    {
+    fail:
+      error_at (loc, "unexpected %<data_member_options%> argument");
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  tree args[5] = { type, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+  for (tree field = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (opts)));
+       field; field = next_aggregate_field (DECL_CHAIN (field)))
+    if (tree name = DECL_NAME (field))
+      {
+       if (id_equal (name, "name"))
+         args[1] = field;
+       else if (id_equal (name, "alignment"))
+         args[2] = field;
+       else if (id_equal (name, "bit_width"))
+         args[3] = field;
+       else if (id_equal (name, "no_unique_address"))
+         args[4] = field;
+      }
+  for (int i = 1; i < 5; ++i)
+    {
+      if (args[i] == NULL_TREE)
+       goto fail;
+      tree opt = build3 (COMPONENT_REF, TREE_TYPE (args[i]), opts, args[i],
+                        NULL_TREE);
+      if (i == 4)
+       {
+         /* The no_unique_address handling is simple.  */
+         if (TREE_CODE (TREE_TYPE (opt)) != BOOLEAN_TYPE)
+           goto fail;
+         opt = cxx_eval_constant_expression (ctx, opt, vc_prvalue,
+                                             non_constant_p, overflow_p,
+                                             jump_target);
+         if (*jump_target || *non_constant_p)
+           return NULL_TREE;
+         if (TREE_CODE (opt) != INTEGER_CST)
+           goto fail;
+         if (integer_zerop (opt))
+           args[i] = boolean_false_node;
+         else
+           args[i] = boolean_true_node;
+         continue;
+       }
+      /* Otherwise the member is optional<something>.  */
+      if (!CLASS_TYPE_P (TREE_TYPE (opt)))
+       goto fail;
+      tree has_value = build_static_cast (loc, boolean_type_node, opt,
+                                         tf_warning_or_error);
+      if (error_operand_p (has_value))
+       goto fail;
+      has_value = cxx_eval_constant_expression (ctx, has_value, vc_prvalue,
+                                               non_constant_p, overflow_p,
+                                               jump_target);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      if (TREE_CODE (has_value) != INTEGER_CST)
+       goto fail;
+      if (integer_zerop (has_value))
+       {
+         /* If it doesn't have value, store NULL_TREE.  */
+         args[i] = NULL_TREE;
+         continue;
+       }
+      tree deref = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, opt,
+                                NULL_TREE, tf_warning_or_error);
+      if (error_operand_p (deref))
+       goto fail;
+      if (i != 1)
+       {
+         /* For alignment and bit_width otherwise it should be int.  */
+         if (TYPE_MAIN_VARIANT (TREE_TYPE (deref)) != integer_type_node)
+           goto fail;
+         deref = cxx_eval_constant_expression (ctx, deref, vc_prvalue,
+                                               non_constant_p, overflow_p,
+                                               jump_target);
+         if (*jump_target || *non_constant_p)
+           return NULL_TREE;
+         if (TREE_CODE (deref) != INTEGER_CST)
+           goto fail;
+         args[i] = deref;
+         continue;
+       }
+      /* Otherwise it is a name.  */
+      if (!CLASS_TYPE_P (TREE_TYPE (deref)))
+       goto fail;
+      tree fields[3] = { NULL_TREE, NULL_TREE, NULL_TREE };
+      for (tree field = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (deref)));
+          field; field = next_aggregate_field (DECL_CHAIN (field)))
+       if (tree name = DECL_NAME (field))
+         {
+           if (id_equal (name, "_M_is_u8"))
+             fields[0] = field;
+           else if (id_equal (name, "_M_u8s"))
+             fields[1] = field;
+           else if (id_equal (name, "_M_s"))
+             fields[2] = field;
+         }
+      for (int j = 0; j < 3; ++j)
+       {
+         if (fields[j] == NULL_TREE)
+           goto fail;
+         if (j && j == (fields[0] == boolean_true_node ? 2 : 1))
+           continue;
+         tree f = build3 (COMPONENT_REF, TREE_TYPE (fields[j]), deref,
+                          fields[j], NULL_TREE);
+         if (j == 0)
+           {
+             /* The _M_is_u8 handling is simple.  */
+             if (TREE_CODE (TREE_TYPE (f)) != BOOLEAN_TYPE)
+               goto fail;
+             f = cxx_eval_constant_expression (ctx, f, vc_prvalue,
+                                               non_constant_p, overflow_p,
+                                               jump_target);
+             if (*jump_target || *non_constant_p)
+               return NULL_TREE;
+             if (TREE_CODE (f) != INTEGER_CST)
+               goto fail;
+             if (integer_zerop (f))
+               fields[0] = boolean_false_node;
+             else
+               fields[0] = boolean_true_node;
+             continue;
+           }
+         /* _M_u8s/_M_s handling is the same except for encoding.  */
+         if (!CLASS_TYPE_P (TREE_TYPE (f)))
+           goto fail;
+         tree fns = lookup_qualified_name (TREE_TYPE (f),
+                                           get_identifier ("c_str"));
+         if (error_operand_p (fns))
+           goto fail;
+         f = build_new_method_call (f, fns, NULL, NULL_TREE, LOOKUP_NORMAL,
+                                    NULL, tf_warning_or_error);
+         if (error_operand_p (f))
+           goto fail;
+         f = cxx_eval_constant_expression (ctx, f, vc_prvalue,
+                                           non_constant_p, overflow_p,
+                                           jump_target);
+         if (*jump_target || *non_constant_p)
+           return NULL_TREE;
+         STRIP_NOPS (f);
+         if (TREE_CODE (f) != ADDR_EXPR)
+           goto fail;
+         f = TREE_OPERAND (f, 0);
+         f = cxx_eval_constant_expression (ctx, f, vc_prvalue,
+                                           non_constant_p, overflow_p,
+                                           jump_target);
+         if (*jump_target || *non_constant_p)
+           return NULL_TREE;
+         if (TREE_CODE (f) != CONSTRUCTOR
+             || TREE_CODE (TREE_TYPE (f)) != ARRAY_TYPE)
+           goto fail;
+         tree eltt = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f)));
+         if (eltt != (j == 1 ? char8_type_node : char_type_node))
+           goto fail;
+         tree field, value;
+         unsigned k;
+         unsigned HOST_WIDE_INT l = 0;
+         bool ntmbs = false;
+         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (f), k, field, value)
+           if (!tree_fits_shwi_p (value))
+             goto fail;
+           else if (field == NULL_TREE)
+             {
+               if (integer_zerop (value))
+                 {
+                   ntmbs = true;
+                   break;
+                 }
+               ++l;
+             }
+           else if (TREE_CODE (field) == RANGE_EXPR)
+             {
+               tree lo = TREE_OPERAND (field, 0);
+               tree hi = TREE_OPERAND (field, 1);
+               if (!tree_fits_uhwi_p (lo) || !tree_fits_uhwi_p (hi))
+                 goto fail;
+               if (integer_zerop (value))
+                 {
+                   l = tree_to_uhwi (lo);
+                   ntmbs = true;
+                   break;
+                 }
+               l = tree_to_uhwi (hi) + 1;
+             }
+           else if (tree_fits_uhwi_p (field))
+             {
+               l = tree_to_uhwi (field);
+               if (integer_zerop (value))
+                 {
+                   ntmbs = true;
+                   break;
+                 }
+               ++l;
+             }
+           else
+             goto fail;
+         if (!ntmbs || l > INT_MAX - 1)
+           goto fail;
+         char *namep;
+         unsigned len = l;
+         if (l < 64)
+           namep = XALLOCAVEC (char, l + 1);
+         else
+           namep = XNEWVEC (char, l + 1);
+         memset (namep, 0, l + 1);
+         l = 0;
+         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (f), k, field, value)
+           if (field == NULL_TREE)
+             {
+               if (integer_zerop (value))
+                 break;
+               namep[l] = tree_to_shwi (value);
+               ++l;
+             }
+           else if (TREE_CODE (field) == RANGE_EXPR)
+             {
+               tree lo = TREE_OPERAND (field, 0);
+               tree hi = TREE_OPERAND (field, 1);
+               if (integer_zerop (value))
+                 break;
+               unsigned HOST_WIDE_INT m = tree_to_uhwi (hi);
+               for (l = tree_to_uhwi (lo); l <= m; ++l)
+                 namep[l] = tree_to_shwi (value);
+             }
+           else
+             {
+               l = tree_to_uhwi (field);
+               namep[l++] = tree_to_shwi (value);
+             }
+         namep[len] = '\0';
+         /* Convert namep from execution charset to SOURCE_CHARSET.  */
+         cpp_string istr, ostr;
+         istr.len = strlen (namep) + 1;
+         istr.text = (const unsigned char *) namep;
+         if (!cpp_translate_string (parse_in, &istr, &ostr,
+                                    j == 2 ? CPP_STRING : CPP_UTF8STRING,
+                                    true))
+           {
+             if (len >= 64)
+               XDELETEVEC (namep);
+             if (j == 1)
+               return throw_exception (loc, ctx,
+                                       "conversion from ordinary literal "
+                                       "encoding to source charset "
+                                       "failed", fun, non_constant_p,
+                                       jump_target);
+             else
+               return throw_exception (loc, ctx,
+                                       "conversion from UTF-8 encoding to "
+                                       "source charset failed",
+                                       fun, non_constant_p, jump_target);
+           }
+         if (len >= 64)
+           XDELETEVEC (namep);
+         if (!cpp_valid_identifier (parse_in, ostr.text))
+           return throw_exception (loc, ctx,
+                                   "name is not a valid identifier",
+                                   fun, non_constant_p, jump_target);
+         args[i] = get_identifier ((const char *) ostr.text);
+         switch (get_identifier_kind (args[i]))
+           {
+           case cik_keyword:
+             return throw_exception (loc, ctx, "name is a keyword",
+                                     fun, non_constant_p, jump_target);
+           case cik_trait:
+             return throw_exception (loc, ctx, "name is a built-in trait",
+                                     fun, non_constant_p, jump_target);
+           default:
+             break;
+           }
+       }
+    }
+  if (args[1] == NULL_TREE && args[3] == NULL_TREE)
+    return throw_exception (loc, ctx,
+                           "neither name nor bit_width specified",
+                           fun, non_constant_p, jump_target);
+  if (args[3])
+    {
+      if (!CP_INTEGRAL_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE)
+       return throw_exception (loc, ctx,
+                               "bit_width specified with non-integral "
+                               "and non-enumeration type",
+                               fun, non_constant_p, jump_target);
+      if (args[2])
+       return throw_exception (loc, ctx,
+                               "both alignment and bit_width specified",
+                               fun, non_constant_p, jump_target);
+      if (args[4] == boolean_true_node)
+       return throw_exception (loc, ctx,
+                               "bit_width specified with "
+                               "no_unique_address true",
+                               fun, non_constant_p, jump_target);
+      if (integer_zerop (args[3]) && args[1])
+       return throw_exception (loc, ctx,
+                               "bit_width 0 with specified name",
+                               fun, non_constant_p, jump_target);
+      if (tree_int_cst_sgn (args[3]) < 0)
+       return throw_exception (loc, ctx, "bit_width is negative",
+                               fun, non_constant_p, jump_target);
+    }
+  if (args[2])
+    {
+      if (!integer_pow2p (args[2]))
+       return throw_exception (loc, ctx,
+                               "alignment is not power of two",
+                               fun, non_constant_p, jump_target);
+      if (tree_int_cst_sgn (args[2]) < 0)
+       return throw_exception (loc, ctx, "alignment is negative",
+                               fun, non_constant_p, jump_target);
+      tree al = cxx_sizeof_or_alignof_type (loc, type, ALIGNOF_EXPR, true,
+                                           tf_none);
+      if (TREE_CODE (al) == INTEGER_CST
+         && wi::to_widest (al) > wi::to_widest (args[2]))
+       return throw_exception (loc, ctx,
+                               "alignment is smaller than alignment_of",
+                               fun, non_constant_p, jump_target);
+    }
+  tree ret = make_tree_vec (5);
+  for (int i = 0; i < 5; ++i)
+    TREE_VEC_ELT (ret, i) = args[i];
+  return get_reflection_raw (loc, ret, REFLECT_DATA_MEMBER_SPEC);
+}
+
+/* Process std::meta::define_aggregate.
+   Let C be the type represented by class_type and r_K be the Kth reflection
+   value in mdescrs.
+   For every r_K in mdescrs, let (T_K,N_K,A_K,W_K,NUA_K) be the corresponding
+   data member description represented by r_K.
+   Constant When:
+   -- class_type represents a cv-unqualified class type;
+   -- C is incomplete from every point in the evaluation context;
+   -- is_data_member_spec(r_K) is true for every r_K;
+   -- is_complete_type(T_K) is true for every r_K; and
+   -- for every pair (r_K,r_L) where K<L, if N_K is not _|_ and N_L is not
+      _|_, then either:
+      -- N_K is not the same identifier as N_L or
+      -- N_K is the identifier _ (U+005F LOW LINE).
+   Effects: Produces an injected declaration D that defines C and has
+   properties as follows:
+   -- The target scope of D is the scope to which C belongs.
+   -- The locus of D follows immediately after the core constant expression
+      currently under evaluation.
+   -- The characteristic sequence of D is the sequence of reflection values
+      r_K.
+   -- If C is a specialization of a templated class T, and C is not a local
+      class, then D is an explicit specialization of T.
+   -- For each r_K, there is a corresponding entity M_K with public access
+      belonging to the class scope of D with the following properties:
+      -- If N_K is _|_, M_K is an unnamed bit-field.
+        Otherwise, M_K is a non-static data member whose name is the
+        identifier N_K.
+      -- The type of M_K is T_K.
+      -- M_K is declared with the attribute [[no_unique_address]] if and only
+        if NUA_K is true.
+      -- If W_K is not _|_, M_K is a bit-field whose width is that value.
+        Otherwise, M_K is not a bit-field.
+      -- If A_K is not _|_, M_K has the alignment-specifier alignas(A_K).
+        Otherwise, M_K has no alignment-specifier.
+   -- For every r_L in mdescrs such that K<L, the declaration corresponding to
+      r_K precedes the declaration corresponding to r_L.
+   Returns: class_type.
+   Remarks: If C is a specialization of a templated class and it has not been
+   instantiated, C is treated as an explicit specialization.  */
+
+static tree
+eval_define_aggregate (location_t loc, const constexpr_ctx *ctx,
+                      tree type, tree rvec, tree call, bool *non_constant_p)
+{
+  tree orig_type = type;
+  if (!CLASS_TYPE_P (type))
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "first %<define_aggregate%> argument is not a class "
+                      "type reflection");
+      *non_constant_p = true;
+      return call;
+    }
+  if (typedef_variant_p (type))
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "first %<define_aggregate%> argument is a reflection "
+                      "of a type alias");
+      *non_constant_p = true;
+      return call;
+    }
+  if (cv_qualified_p (type))
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "first %<define_aggregate%> argument is a "
+                      "cv-qualified class type reflection");
+      *non_constant_p = true;
+      return call;
+    }
+  if (COMPLETE_TYPE_P (type))
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "first %<define_aggregate%> argument is a complete "
+                      "class type reflection");
+      *non_constant_p = true;
+      return call;
+    }
+  hash_set<tree> nameset;
+  for (int i = 0; i < TREE_VEC_LENGTH (rvec); ++i)
+    {
+      tree ra = TREE_VEC_ELT (rvec, i);
+      tree a = REFLECT_EXPR_HANDLE (ra);
+      if (REFLECT_EXPR_KIND (ra) != REFLECT_DATA_MEMBER_SPEC)
+       {
+         if (!cxx_constexpr_quiet_p (ctx))
+           error_at (loc, "%<define_aggregate%> argument not a data member "
+                          "description");
+         *non_constant_p = true;
+         return call;
+       }
+      if (eval_is_complete_type (TREE_VEC_ELT (a, 0)) != boolean_true_node)
+       {
+         if (!cxx_constexpr_quiet_p (ctx))
+           error_at (loc, "%<define_aggregate%> argument data member "
+                          "description without complete type");
+         *non_constant_p = true;
+         return call;
+       }
+      if (TREE_VEC_ELT (a, 1)
+         && !id_equal (TREE_VEC_ELT (a, 1), "_")
+         && nameset.add (TREE_VEC_ELT (a, 1)))
+       {
+         if (!cxx_constexpr_quiet_p (ctx))
+           error_at (loc, "name %qD used in multiple data member "
+                          "descriptions", TREE_VEC_ELT (a, 1));
+         *non_constant_p = true;
+         return call;
+       }
+      if (TYPE_WARN_IF_NOT_ALIGN (type)
+         && TREE_VEC_ELT (a, 3))
+       {
+         if (!cxx_constexpr_quiet_p (ctx))
+           error_at (loc, "cannot declare bit-field in "
+                          "%<warn_if_not_aligned%> type");
+         *non_constant_p = true;
+         return call;
+       }
+    }
+  tree consteval_block = cxx_constexpr_consteval_block (ctx);
+  if (consteval_block == NULL_TREE)
+    {
+      if (!cxx_constexpr_quiet_p (ctx))
+       error_at (loc, "%<define_aggregate%> not evaluated from "
+                      "%<consteval%> block");
+      *non_constant_p = true;
+      return call;
+    }
+  iloc_sentinel ils = loc;
+  type = TYPE_MAIN_VARIANT (type);
+  type = strip_typedefs (type);
+  tree cscope = NULL_TREE, tscope = NULL_TREE;
+  for (tree c = TYPE_CONTEXT (CP_DECL_CONTEXT (consteval_block)); c;
+       c = get_containing_scope (c))
+    {
+      if (c == type)
+       {
+         auto_diagnostic_group d;
+         error_at (loc, "%<define_aggregate%> evaluated from "
+                        "%<consteval%> block enclosed by %qT being "
+                        "defined", type);
+         inform (DECL_SOURCE_LOCATION (consteval_block),
+                 "%<consteval%> block defined here");
+         return get_reflection_raw (loc, orig_type);
+       }
+      if (cscope == NULL_TREE
+         && (TYPE_P (c) || TREE_CODE (c) == FUNCTION_DECL))
+       cscope = c;
+    }
+  for (tree c = TYPE_CONTEXT (type); c; c = get_containing_scope (c))
+    {
+      if (c == consteval_block)
+       {
+         auto_diagnostic_group d;
+         error_at (loc, "%<define_aggregate%> evaluated from "
+                        "%<consteval%> block which encloses %qT being "
+                        "defined", type);
+         inform (DECL_SOURCE_LOCATION (consteval_block),
+                 "%<consteval%> block defined here");
+         return get_reflection_raw (loc, orig_type);
+       }
+      if (tscope == NULL_TREE
+         && (TYPE_P (c) || TREE_CODE (c) == FUNCTION_DECL))
+       tscope = c;
+    }
+  if (cscope != tscope)
+    {
+      auto_diagnostic_group d;
+      if (cscope && tscope)
+       {
+         for (tree c = tscope; c; c = get_containing_scope (c))
+           if (c == cscope)
+             {
+               if (DECL_P (tscope))
+                 error_at (loc, "%qD intervenes between %qT scope and "
+                                "%<consteval%> block %<define_aggregate%> "
+                                "is evaluated from", tscope, type);
+               else
+                 error_at (loc, "%qT intervenes between %qT scope and "
+                                "%<consteval%> block %<define_aggregate%> "
+                                "is evaluated from", tscope, type);
+               cscope = NULL_TREE;
+               tscope = NULL_TREE;
+               break;
+             }
+         for (tree c = cscope; c; c = get_containing_scope (c))
+           if (c == tscope)
+             {
+               if (DECL_P (cscope))
+                 error_at (loc, "%qD intervenes between %<consteval%> block "
+                                "%<define_aggregate%> is evaluated from and "
+                                "%qT scope", cscope, type);
+               else
+                 error_at (loc, "%qT intervenes between %<consteval%> block "
+                                "%<define_aggregate%> is evaluated from and "
+                                "%qT scope", cscope, type);
+               cscope = NULL_TREE;
+               tscope = NULL_TREE;
+               break;
+             }
+         if (cscope && tscope)
+           {
+             if (DECL_P (cscope) && DECL_P (tscope))
+               error_at (loc, "%<define_aggregate%> evaluated from "
+                              "%<consteval%> block enclosed by %qD while "
+                              "%qT type being defined is enclosed by %qD",
+                         cscope, type, tscope);
+             else if (DECL_P (cscope))
+               error_at (loc, "%<define_aggregate%> evaluated from "
+                              "%<consteval%> block enclosed by %qD while "
+                              "%qT type being defined is enclosed by %qT",
+                         cscope, type, tscope);
+             else if (DECL_P (tscope))
+               error_at (loc, "%<define_aggregate%> evaluated from "
+                              "%<consteval%> block enclosed by %qT while "
+                              "%qT type being defined is enclosed by %qD",
+                         cscope, type, tscope);
+             else if (tscope)
+               error_at (loc, "%<define_aggregate%> evaluated from "
+                              "%<consteval%> block enclosed by %qT while "
+                              "%qT type being defined is enclosed by %qT",
+                         cscope, type, tscope);
+           }
+       }
+      else if (cscope && DECL_P (cscope))
+       error_at (loc, "%qD intervenes between %<consteval%> block "
+                      "%<define_aggregate%> is evaluated from and %qT scope",
+                 cscope, type);
+      else if (cscope)
+       error_at (loc, "%qT intervenes between %<consteval%> block "
+                      "%<define_aggregate%> is evaluated from and %qT scope",
+                 cscope, type);
+      else if (tscope && DECL_P (tscope))
+       error_at (loc, "%qD intervenes between %qT scope and %<consteval%> "
+                      "block %<define_aggregate%> is evaluated from",
+                 tscope, type);
+      else
+       error_at (loc, "%qT intervenes between %qT scope and %<consteval%> "
+                      "block %<define_aggregate%> is evaluated from",
+                 tscope, type);
+      inform (DECL_SOURCE_LOCATION (consteval_block),
+             "%<consteval%> block defined here");
+      return get_reflection_raw (loc, orig_type);
+    }
+  if (primary_template_specialization_p (type))
+    {
+      type = maybe_process_partial_specialization (type);
+      if (type == error_mark_node)
+       {
+         *non_constant_p = true;
+         return call;
+       }
+    }
+  if (!TYPE_BINFO (type))
+    xref_basetypes (type, NULL_TREE);
+  pushclass (type);
+  gcc_assert (!TYPE_FIELDS (type));
+  tree fields = NULL_TREE;
+  for (int i = 0; i < TREE_VEC_LENGTH (rvec); ++i)
+    {
+      tree ra = TREE_VEC_ELT (rvec, i);
+      tree a = REFLECT_EXPR_HANDLE (ra);
+      tree f = build_decl (cp_expr_loc_or_input_loc (ra), FIELD_DECL,
+                          TREE_VEC_ELT (a, 1), TREE_VEC_ELT (a, 0));
+      DECL_CHAIN (f) = fields;
+      DECL_IN_AGGR_P (f) = 1;
+      DECL_CONTEXT (f) = type;
+      TREE_PUBLIC (f) = 1;
+      /* Bit-field.  */
+      if (TREE_VEC_ELT (a, 3))
+       {
+         /* Temporarily stash the width in DECL_BIT_FIELD_REPRESENTATIVE.
+            check_bitfield_decl picks it from there later and sets DECL_SIZE
+            accordingly.  */
+         DECL_BIT_FIELD_REPRESENTATIVE (f) = TREE_VEC_ELT (a, 3);
+         SET_DECL_C_BIT_FIELD (f);
+         DECL_NONADDRESSABLE_P (f) = 1;
+         /* If this bit-field is unnamed, it's padding.  */
+         if (!TREE_VEC_ELT (a, 1))
+           DECL_PADDING_P (f) = 1;
+       }
+      else if (TREE_VEC_ELT (a, 2))
+       {
+         SET_DECL_ALIGN (f, tree_to_uhwi (TREE_VEC_ELT (a, 2))
+                             * BITS_PER_UNIT);
+         DECL_USER_ALIGN (f) = 1;
+       }
+      if (TREE_VEC_ELT (a, 4) == boolean_true_node)
+       {
+         tree attr = build_tree_list (NULL_TREE,
+                                      get_identifier ("no_unique_address"));
+         attr = build_tree_list (attr, NULL_TREE);
+         cplus_decl_attributes (&f, attr, 0);
+       }
+      fields = f;
+    }
+  TYPE_FIELDS (type) = fields;
+  finish_struct (type, NULL_TREE);
+  return get_reflection_raw (loc, orig_type);
+}
+
+/* Implement std::meta::reflect_constant_string.
+   Let CharT be ranges::range_value_t<R>.
+   Mandates: CharT is one of char, wchar_t, char8_t, char16_t, char32_t.
+   Let V be the pack of values of type CharT whose elements are the
+   corresponding elements of r, except that if r refers to a string literal
+   object, then V does not include the trailing null terminator of r.
+   Let P be the template parameter object of type
+   const CharT[sizeof...(V) + 1] initialized with {V..., CharT()}.
+   Returns: ^^P.  */
+
+static tree
+eval_reflect_constant_string (location_t loc, const constexpr_ctx *ctx,
+                             tree call, bool *non_constant_p,
+                             bool *overflow_p, tree *jump_target, tree fun)
+{
+  tree str = get_range_elts (loc, ctx, call, 0, non_constant_p, overflow_p,
+                            jump_target, REFLECT_CONSTANT_STRING, fun);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  tree decl = get_template_parm_object (str,
+                                       mangle_template_parm_object (str));
+  DECL_MERGEABLE (decl) = 1;
+  return get_reflection_raw (loc, decl);
+}
+
+/* Implement std::meta::reflect_constant_array.
+   Let T be ranges::range_value_t<R>.
+   Mandates: T is a structural type,
+   is_constructible_v<T, ranges::range_reference_t<R>> is true, and
+   is_copy_constructible_v<T> is true.
+   Let V be the pack of values of type info of the same size as r, where the
+   ith element is reflect_constant(e_i), where e_i is the ith element of r.
+   Let P be
+   -- If sizeof...(V) > 0 is true, then the template parameter object of type
+      const T[sizeof...(V)] initialized with {[:V:]...}.
+   -- Otherwise, the template parameter object of type array<T, 0> initialized
+      with {}.
+   Returns: ^^P.  */
+
+static tree
+eval_reflect_constant_array (location_t loc, const constexpr_ctx *ctx,
+                            tree call, bool *non_constant_p,
+                            bool *overflow_p, tree *jump_target, tree fun)
+{
+  tree str = get_range_elts (loc, ctx, call, 0, non_constant_p, overflow_p,
+                            jump_target, REFLECT_CONSTANT_ARRAY, fun);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  tree decl = get_template_parm_object (str,
+                                       mangle_template_parm_object (str));
+  DECL_MERGEABLE (decl) = 1;
+  return get_reflection_raw (loc, decl);
+}
+
+/* Process std::meta::access_context::current.  */
+
+static tree
+eval_access_context_current (location_t loc, const constexpr_ctx *ctx,
+                            tree call, bool *non_constant_p)
+{
+  tree scope = cxx_constexpr_caller (ctx);
+  /* Ignore temporary current_function_decl changes caused by
+     push_access_scope.  */
+  if (scope == NULL_TREE && current_function_decl)
+    scope = current_function_decl_without_access_scope ();
+  /* [meta.reflection.access.context]/(5.1.2): Otherwise, if an initialization
+     by an inherited constructor is using I, a point whose immediate scope is
+     the class scope corresponding to C.  */
+  if (scope && DECL_INHERITED_CTOR (scope))
+    scope = DECL_CONTEXT (scope);
+  if (scope == NULL_TREE)
+    {
+      if (cxx_constexpr_manifestly_const_eval (ctx) != mce_true)
+       {
+         /* Outside of functions limit this to manifestly constant-evaluation
+            so that we don't fold it prematurely.  */
+         if (!cxx_constexpr_quiet_p (ctx))
+           error_at (loc, "%<access_context::current%> used outside of "
+                          "manifestly constant-evaluation");
+         *non_constant_p = true;
+         return call;
+       }
+      if (current_class_type)
+       scope = current_class_type;
+      else if (current_namespace)
+       scope = current_namespace;
+      else
+       scope = global_namespace;
+    }
+  tree lam;
+  while (LAMBDA_FUNCTION_P (scope)
+        && (lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (scope)))
+        && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam))
+    scope = CP_TYPE_CONTEXT (CP_DECL_CONTEXT (scope));
+  tree access_context = TREE_TYPE (call);
+  if (TREE_CODE (access_context) != RECORD_TYPE)
+    {
+    fail:
+      error_at (loc, "unexpected return type of %qs",
+               "std::meta::access_context::current");
+      return build_zero_cst (access_context);
+    }
+  tree scopef = next_aggregate_field (TYPE_FIELDS (access_context));
+  if (!scopef || !REFLECTION_TYPE_P (TREE_TYPE (scopef)))
+    goto fail;
+  tree classf = next_aggregate_field (DECL_CHAIN (scopef));
+  if (!classf || !REFLECTION_TYPE_P (TREE_TYPE (classf)))
+    goto fail;
+  if (next_aggregate_field (DECL_CHAIN (classf)))
+    goto fail;
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  CONSTRUCTOR_APPEND_ELT (elts, scopef, get_reflection_raw (loc, scope));
+  CONSTRUCTOR_APPEND_ELT (elts, classf, get_null_reflection ());
+  return build_constructor (access_context, elts);
+}
+
+/* Helper function to extract scope and designating class from
+   access_context ACTX.  */
+
+static bool
+extract_access_context (location_t loc, tree actx, tree *scope,
+                       tree *designating_class)
+{
+  if (TREE_CODE (actx) != CONSTRUCTOR
+      || CONSTRUCTOR_NELTS (actx) != 2
+      || !REFLECT_EXPR_P (CONSTRUCTOR_ELT (actx, 0)->value)
+      || !REFLECT_EXPR_P (CONSTRUCTOR_ELT (actx, 1)->value))
+    {
+      error_at (loc, "invalid %<access_context%> argument");
+      return false;
+    }
+  *scope = REFLECT_EXPR_HANDLE (CONSTRUCTOR_ELT (actx, 0)->value);
+  *designating_class = REFLECT_EXPR_HANDLE (CONSTRUCTOR_ELT (actx, 1)->value);
+  if (*scope == unknown_type_node)
+    *scope = NULL_TREE;
+  else if (TREE_CODE (*scope) != FUNCTION_DECL
+          && TREE_CODE (*scope) != NAMESPACE_DECL
+          && !CLASS_TYPE_P (*scope))
+    {
+      error_at (loc, "unexpected %<access_context::scope()%>");
+      return false;
+    }
+  else if (CLASS_TYPE_P (*scope))
+    *scope = TYPE_MAIN_VARIANT (*scope);
+  if (*designating_class == unknown_type_node)
+    *designating_class = NULL_TREE;
+  else if (!CLASS_TYPE_P (*designating_class)
+          || !COMPLETE_TYPE_P (*designating_class))
+    {
+      error_at (loc, "unexpected %<access_context::designating_class()%>");
+      return false;
+    }
+  else
+    *designating_class = TYPE_MAIN_VARIANT (*designating_class);
+  return true;
+}
+
+/* Process std::meta::is_accessible.
+   Let PARENT-CLS(r) be:
+   -- If parent_of(r) represents a class C, then C.
+   -- Otherwise, PARENT-CLS(parent_of(r)).
+   Let DESIGNATING-CLS(r, ctx) be:
+   -- If ctx.designating_class() represents a class C, then C.
+   -- Otherwise, PARENT-CLS(r).
+   Returns:
+   -- If r represents an unnamed bit-field F, then is_accessible(r_H, ctx),
+      where r_H represents a hypothetical non-static data member of the class
+      represented by PARENT-CLS(r) with the same access as F.
+   -- Otherwise, if r does not represent a class member or a direct base class
+      relationship, then true.
+   -- Otherwise, if r represents
+      -- a class member that is not a (possibly indirect or variant) member of
+        DESIGNATING-CLS(r, ctx) or
+      -- a direct base class relationship such that parent_of(r) does not
+        represent DESIGNATING-CLS(r, ctx) or a (direct or indirect) base
+        class thereof,
+      then false.
+   -- Otherwise, if ctx.scope() is the null reflection, then true.
+   -- Otherwise, letting P be a program point whose immediate scope is the
+      function parameter scope, class scope, or namespace scope corresponding
+      to the function, class, or namespace represented by ctx.scope():
+      -- If r represents a direct base class relationship (D,B), then true if
+        base class B of DESIGNATING-CLS(r, ctx) is accessible at P;
+        otherwise false.
+      -- Otherwise, r represents a class member M; true if M would be
+        accessible at P with the designating class (as DESIGNATING-CLS(r, ctx)
+        if the effect of any using-declarations were ignored.  Otherwise,
+        false.
+   Throws: meta::exception if r represents a class member for which
+   PARENT-CLS(r) is an incomplete class.  */
+
+static tree
+eval_is_accessible (location_t loc, const constexpr_ctx *ctx, tree r,
+                   reflect_kind kind, tree actx, tree call,
+                   bool *non_constant_p, tree *jump_target, tree fun)
+{
+  tree scope = NULL_TREE, designating_class = NULL_TREE, c;
+  if (!extract_access_context (loc, actx, &scope, &designating_class))
+    {
+      *non_constant_p = true;
+      return call;
+    }
+
+  if (eval_is_class_member (r) == boolean_true_node)
+    {
+      r = maybe_get_reflection_fndecl (r);
+      c = r;
+      if (TREE_CODE (r) == CONST_DECL && UNSCOPED_ENUM_P (DECL_CONTEXT (r)))
+       c = DECL_CONTEXT (r);
+      if (TYPE_P (c))
+       {
+         if (TYPE_NAME (c) && DECL_P (TYPE_NAME (c)))
+           c = CP_DECL_CONTEXT (TYPE_NAME (c));
+         else
+           c = CP_TYPE_CONTEXT (c);
+       }
+      else
+       c = CP_DECL_CONTEXT (r);
+    }
+  else if (kind == REFLECT_BASE)
+    {
+      c = direct_base_parent (r);
+      r = BINFO_TYPE (r);
+    }
+  else
+    return boolean_true_node;
+  if (!CLASS_TYPE_P (c) || !COMPLETE_TYPE_P (c))
+    return throw_exception (loc, ctx,
+                           "incomplete parent class",
+                           fun, non_constant_p, jump_target);
+  if (designating_class)
+    {
+      tree p = c;
+      while (ANON_AGGR_TYPE_P (p) && p != designating_class)
+       p = CP_TYPE_CONTEXT (p);
+      if (p != designating_class
+         && (!CLASS_TYPE_P (p)
+             || !DERIVED_FROM_P (p, designating_class)))
+       return boolean_false_node;
+    }
+  if (scope == NULL_TREE)
+    return boolean_true_node;
+  if (designating_class == NULL_TREE)
+    designating_class = c;
+  if (TREE_CODE (scope) == NAMESPACE_DECL)
+    push_to_top_level ();
+  else if (TYPE_P (scope))
+    push_access_scope (TYPE_NAME (scope));
+  else
+    push_access_scope (scope);
+  tree ret = boolean_false_node;
+  if (kind == REFLECT_BASE)
+    {
+      if (accessible_base_p (designating_class, r, /*consider_local_p=*/true))
+       ret = boolean_true_node;
+    }
+  else
+    {
+      tree o = TYPE_P (r) ? TYPE_NAME (r) : r;
+      if (accessible_p (TYPE_BINFO (designating_class), o,
+                       /*consider_local_p=*/true))
+       ret = boolean_true_node;
+    }
+  if (TREE_CODE (scope) == NAMESPACE_DECL)
+    pop_from_top_level ();
+  else if (TYPE_P (scope))
+    pop_access_scope (TYPE_NAME (scope));
+  else
+    pop_access_scope (scope);
+  return ret;
+}
+
+/* Returns true if R is C-members-of-representable from
+   current point P.  */
+
+static bool
+members_of_representable_p (tree c, tree r)
+{
+  if (TREE_CODE (r) == CONST_DECL)
+    return false;
+  if (LAMBDA_TYPE_P (c) && !LAMBDA_FUNCTION_P (r))
+    return false;
+  if (TYPE_P (r))
+    {
+      if (CP_DECL_CONTEXT (TYPE_NAME (r)) != c)
+       return false;
+      if (LAMBDA_TYPE_P (r))
+       return false;
+      if (OVERLOAD_TYPE_P (r))
+       return true;
+      if (typedef_variant_p (r))
+       return true;
+    }
+  else if (DECL_P (r))
+    {
+      if (CP_DECL_CONTEXT (r) != c)
+       return false;
+      if (DECL_CLASS_TEMPLATE_P (r)
+         || DECL_FUNCTION_TEMPLATE_P (r)
+         || variable_template_p (r)
+         || DECL_ALIAS_TEMPLATE_P (r)
+         || concept_definition_p (r)
+         || TREE_CODE (r) == FIELD_DECL
+         || TREE_CODE (r) == NAMESPACE_DECL)
+       return true;
+      if (VAR_OR_FUNCTION_DECL_P (r) && !undeduced_auto_decl (r))
+       return true;
+    }
+  return false;
+}
+
+/* Callback for vector qsort to compare members by ascending DECL_UID.  */
+
+static int
+members_cmp (const void *a, const void *b)
+{
+  const constructor_elt *ea = (const constructor_elt *) a;
+  const constructor_elt *eb = (const constructor_elt *) b;
+  tree vala = REFLECT_EXPR_HANDLE (ea->value);
+  tree valb = REFLECT_EXPR_HANDLE (eb->value);
+  if (TYPE_P (vala))
+    vala = TYPE_NAME (vala);
+  if (TYPE_P (valb))
+    valb = TYPE_NAME (valb);
+  if (DECL_UID (vala) < DECL_UID (valb))
+    return -1;
+  if (DECL_UID (vala) > DECL_UID (valb))
+    return 1;
+  gcc_assert (ea == eb);
+  return 0;
+}
+
+/* Enumerate members of namespace NS for eval_members_of.  */
+
+static vec<constructor_elt, va_gc> *
+namespace_members_of (location_t loc, tree ns)
+{
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  hash_set<tree> *seen = nullptr;
+  for (tree o : *DECL_NAMESPACE_BINDINGS (ns))
+    {
+      if (TREE_CODE (o) == OVERLOAD && OVL_LOOKUP_P (o))
+       {
+         if (TREE_TYPE (o))
+           {
+             tree m = TREE_TYPE (TREE_TYPE (o));
+             if (members_of_representable_p (ns, m))
+               CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                       get_reflection_raw (loc, m));
+           }
+         if (OVL_DEDUP_P (o) || !OVL_FUNCTION (o))
+           continue;
+         o = OVL_FUNCTION (o);
+       }
+      for (ovl_iterator iter (o); iter; ++iter)
+       {
+         if (iter.hidden_p ())
+           continue;
+         tree b = *iter;
+         tree m = b;
+
+         if (VAR_P (b) && DECL_ANON_UNION_VAR_P (b))
+           {
+             /* TODO: This doesn't handle namespace N { static union {}; }
+                but we pedwarn on that, so perhaps it doesn't need to be
+                handled.  */
+             tree v = DECL_VALUE_EXPR (b);
+             gcc_assert (v && TREE_CODE (v) == COMPONENT_REF);
+             tree var = TREE_OPERAND (v, 0);
+             tree type = TREE_TYPE (var);
+             if (!seen)
+               seen = new hash_set<tree>;
+             if (members_of_representable_p (ns, type) && !seen->add (type))
+               CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                       get_reflection_raw (loc, type));
+             if (members_of_representable_p (ns, var) && !seen->add (var))
+               CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                       get_reflection_raw (loc, var));
+             continue;
+           }
+         if (TREE_CODE (b) == TYPE_DECL)
+           m = TREE_TYPE (b);
+         if (!members_of_representable_p (ns, m))
+           continue;
+         if (DECL_DECOMPOSITION_P (m) && !DECL_DECOMP_IS_BASE (m))
+           {
+             tree base = DECL_DECOMP_BASE (m);
+             if (!seen)
+               seen = new hash_set<tree>;
+             if (members_of_representable_p (ns, base) && !seen->add (base))
+               CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                       get_reflection_raw (loc, base));
+             if (!DECL_HAS_VALUE_EXPR_P (m))
+               CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                       get_reflection_raw (loc, m,
+                                                           REFLECT_VAR));
+             continue;
+           }
+         /* eval_is_accessible should be always true for namespace members,
+            so don't bother calling it here.  */
+         CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                 get_reflection_raw (loc, m));
+       }
+    }
+  delete seen;
+  if (elts)
+    elts->qsort (members_cmp);
+  return elts;
+}
+
+/* Enumerate members of class R for eval_*members_of.  KIND is
+   one of METAFN_{,{,NON}STATIC_DATA_}MEMBERS_OF or
+   METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS.
+   For the last kind don't append any elts except for the first one for
+   which is_accessible returned false.  */
+
+static vec<constructor_elt, va_gc> *
+class_members_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                 tree actx, tree call, bool *non_constant_p,
+                 tree *jump_target, enum metafn_code kind, tree fun)
+{
+  if (kind == METAFN_MEMBERS_OF)
+    {
+      if (modules_p ())
+       lazy_load_pendings (TYPE_NAME (r));
+      if (CLASSTYPE_LAZY_DEFAULT_CTOR (r))
+       lazily_declare_fn (sfk_constructor, r);
+      if (CLASSTYPE_LAZY_COPY_CTOR (r))
+       lazily_declare_fn (sfk_copy_constructor, r);
+      if (CLASSTYPE_LAZY_MOVE_CTOR (r))
+       lazily_declare_fn (sfk_move_constructor, r);
+      if (CLASSTYPE_LAZY_DESTRUCTOR (r))
+       lazily_declare_fn (sfk_destructor, r);
+      if (CLASSTYPE_LAZY_COPY_ASSIGN (r))
+       lazily_declare_fn (sfk_copy_assignment, r);
+      if (CLASSTYPE_LAZY_MOVE_ASSIGN (r))
+       lazily_declare_fn (sfk_move_assignment, r);
+    }
+  auto_vec <tree, 8> implicitly_declared;
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  for (tree field = TYPE_FIELDS (r); field; field = DECL_CHAIN (field))
+    {
+      tree m = field;
+      if (TREE_CODE (field) == FIELD_DECL && DECL_ARTIFICIAL (field))
+       continue; /* Ignore bases.  */
+      else if (DECL_SELF_REFERENCE_P (field))
+       continue;
+      else if (TREE_CODE (field) == TYPE_DECL)
+       m = TREE_TYPE (field);
+      else if (TREE_CODE (field) == FUNCTION_DECL)
+       {
+         /* Ignore cloned cdtors.  */
+         if (DECL_CLONED_FUNCTION_P (field))
+           continue;
+         /* Ignore functions with unsatisfied constraints.  */
+         if (!constraints_satisfied_p (field))
+           continue;
+         if (DECL_MAYBE_DELETED (field))
+           {
+             ++function_depth;
+             maybe_synthesize_method (field);
+             --function_depth;
+           }
+       }
+      if (members_of_representable_p (r, m))
+       {
+         if (kind == METAFN_STATIC_DATA_MEMBERS_OF
+             && eval_is_variable (m, REFLECT_UNDEF) != boolean_true_node)
+           continue; /* For static_data_members_of only include
+                        is_variable.  */
+         else if ((kind == METAFN_NONSTATIC_DATA_MEMBERS_OF
+                   || kind == METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS)
+                  && eval_is_nonstatic_data_member (m) != boolean_true_node)
+           continue; /* For nonstatic_data_members_of only include
+                        is_nonstatic_data_member.  */
+         tree a = eval_is_accessible (loc, ctx, m, REFLECT_UNDEF, actx, call,
+                                      non_constant_p, jump_target, fun);
+         if (*jump_target || *non_constant_p)
+           return nullptr;
+         if (a == boolean_false_node)
+           {
+             if (kind == METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS
+                 && elts == nullptr)
+               CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, boolean_true_node);
+             continue;
+           }
+         gcc_assert (a == boolean_true_node);
+         if (kind == METAFN_MEMBERS_OF
+             && TREE_CODE (m) == FUNCTION_DECL
+             && DECL_ARTIFICIAL (m))
+           {
+             /* Implicitly-declared special members or operator== members
+                appear after any user declared members.  */
+             implicitly_declared.safe_push (m);
+             continue;
+           }
+         else if (kind == METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS)
+           continue;
+         CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                 get_reflection_raw (loc, m));
+       }
+    }
+  /* TYPE_DECLs in TYPE_FIELDS come after other decls, so for members_of
+     the declaration order is not preserved.  */
+  if (kind == METAFN_MEMBERS_OF && elts)
+    elts->qsort (members_cmp);
+  if (kind == METAFN_MEMBERS_OF && !implicitly_declared.is_empty ())
+    {
+      gcc_assert (implicitly_declared.length () <= 8);
+      for (tree m : implicitly_declared)
+       if (default_ctor_p (m))
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+      for (tree m : implicitly_declared)
+       if (DECL_COPY_CONSTRUCTOR_P (m))
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+      for (tree m : implicitly_declared)
+       if (special_function_p (m) == sfk_copy_assignment)
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+      for (tree m : implicitly_declared)
+       if (DECL_MOVE_CONSTRUCTOR_P (m))
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+      for (tree m : implicitly_declared)
+       if (special_function_p (m) == sfk_move_assignment)
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+      for (tree m : implicitly_declared)
+       if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (m))
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+      for (tree m : implicitly_declared)
+       if (DECL_OVERLOADED_OPERATOR_IS (m, EQ_EXPR))
+         {
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                                   get_reflection_raw (loc, m));
+           break;
+         }
+    }
+  return elts;
+}
+
+/* Enumerate bases of class R for eval_*of.  KIND is METAFN_BASES_OF
+   or METAFN_HAS_INACCESSIBLE_BASES.  */
+
+static vec<constructor_elt, va_gc> *
+class_bases_of (location_t loc, const constexpr_ctx *ctx, tree r,
+               tree actx, tree call, bool *non_constant_p,
+               tree *jump_target, enum metafn_code kind, tree fun)
+{
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  tree binfo = TYPE_BINFO (r), base_binfo;
+  for (unsigned i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    {
+      tree a = eval_is_accessible (loc, ctx, base_binfo, REFLECT_BASE, actx,
+                                  call, non_constant_p, jump_target, fun);
+      if (*jump_target || *non_constant_p)
+       return nullptr;
+      if (a == boolean_false_node)
+       {
+         if (kind == METAFN_HAS_INACCESSIBLE_BASES && elts == nullptr)
+           CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, boolean_true_node);
+         continue;
+       }
+      gcc_assert (a == boolean_true_node);
+      if (kind == METAFN_HAS_INACCESSIBLE_BASES)
+       continue;
+      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
+                             get_reflection_raw (loc, base_binfo,
+                                                 REFLECT_BASE));
+    }
+  return elts;
+}
+
+/* Implement std::meta::members_of.
+   A declaration D members-of-precedes a point P if D precedes either P or the
+   point immediately following the class-specifier of the outermost class for
+   which P is in a complete-class context.
+   A declaration D of a member M of a class or namespace Q is
+   Q-members-of-eligible if
+   -- the host scope of D is the class scope or namespace scope associated
+      with Q,
+   -- D is not a friend declaration,
+   -- M is not a closure type,
+   -- M is not a specialization of a template,
+   -- if Q is a class that is not a closure type, then M is a direct member of
+      Q that is not a variant member of a nested anonymous union of Q, and
+   -- if Q is a closure type, then M is a function call operator or function
+      call operator template.
+   It is implementation-defined whether declarations of other members of a
+   closure type Q are Q-members-of-eligible.
+   A member M of a class or namespace Q is Q-members-of-representable from a
+   point P if a Q-members-of-eligible declaration of M members-of-precedes P,
+   and M is
+   -- a class or enumeration type
+   -- a type alias
+   -- a class template, function template, variable template, alias template,
+      or concept,
+   -- a variable or reference V for which the type of V does not contain an
+      undeduced placeholder type,
+   -- a function F for which
+      -- the type of F does not contain an undeduced placeholder type,
+      -- the constraints (if any) of F are satisfied, and
+      -- if F is a prospective destructor, F is the selected destructor,
+   -- a non-static data member,
+   -- a namespace, or
+   -- a namespace alias.
+   Returns: A vector containing reflections of all members M of the entity Q
+   represented by dealias(r) for which
+   -- M is Q-members-of-representable from some point in the evaluation
+      context and
+   -- is_accessible(^^M, ctx) is true.
+   If dealias(r) represents a class C, then the vector also contains
+   reflections representing all unnamed bit-fields B whose declarations
+   inhabit the class scope corresponding to C for which
+   is_accessible(^^B, ctx) is true.
+   Reflections of class members and unnamed bit-fields that are declared
+   appear in the order in which they are declared.
+   Throws: meta::exception unless dealias(r) is a reflection representing
+   either a class type that is complete from some point in the evaluation
+   context or a namespace.  */
+
+static tree
+eval_members_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                tree actx, tree call, bool *non_constant_p,
+                tree *jump_target, tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  if (TREE_CODE (r) == NAMESPACE_DECL)
+    r = ORIGINAL_NAMESPACE (r);
+  vec<constructor_elt, va_gc> *elts;
+  if (TREE_CODE (r) == NAMESPACE_DECL)
+    elts = namespace_members_of (loc, r);
+  else if (CLASS_TYPE_P (r)
+          && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      elts = class_members_of (loc, ctx, r, actx, call, non_constant_p,
+                              jump_target, METAFN_MEMBERS_OF, fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  else
+    return throw_exception (loc, ctx,
+                           "neither complete class type nor namespace",
+                           fun, non_constant_p, jump_target);
+  return get_vector_of_info_elts (elts);
+}
+
+/* Implement std::meta::bases_of.
+   Returns: Let C be the class represented by dealias(type).
+   A vector containing the reflections of all the direct base class
+   relationships B, if any, of C such that is_accessible(^^B, ctx) is true.
+   The direct base class relationships appear in the order in which the
+   corresponding base classes appear in the base-specifier-list of C.
+   Throws: meta::exception unless dealias(type) represents a class type that
+   is complete from some point in the evaluation context.  */
+
+static tree
+eval_bases_of (location_t loc, const constexpr_ctx *ctx, tree r,
+              tree actx, tree call, bool *non_constant_p,
+              tree *jump_target, tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  if (CLASS_TYPE_P (r)
+      && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      elts = class_bases_of (loc, ctx, r, actx, call, non_constant_p,
+                            jump_target, METAFN_BASES_OF, fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  else
+    return throw_exception (loc, ctx, "not a complete class type",
+                           fun, non_constant_p, jump_target);
+  return get_vector_of_info_elts (elts);
+}
+
+/* Implement std::meta::static_data_members_of.
+   Returns: A vector containing each element e of members_of(type, ctx) such
+   that is_variable(e) is true, preserving their order.
+   Throws: meta::exception unless dealias(type) represents a class type that
+   is complete from some point in the evaluation context.  */
+
+static tree
+eval_static_data_members_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                            tree actx, tree call, bool *non_constant_p,
+                            tree *jump_target, tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  if (CLASS_TYPE_P (r)
+      && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      elts = class_members_of (loc, ctx, r, actx, call, non_constant_p,
+                              jump_target, METAFN_STATIC_DATA_MEMBERS_OF,
+                              fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  else
+    return throw_exception (loc, ctx, "not a complete class type",
+                           fun, non_constant_p, jump_target);
+  return get_vector_of_info_elts (elts);
+}
+
+/* Implement std::meta::nonstatic_data_members_of.
+   Returns: A vector containing each element e of members_of(type, ctx) such
+   that is_nonstatic_data_member(e) is true, preserving their order.
+   Throws: meta::exception unless dealias(type) represents a class type that
+   is complete from some point in the evaluation context.  */
+
+static tree
+eval_nonstatic_data_members_of (location_t loc, const constexpr_ctx *ctx,
+                               tree r, tree actx, tree call,
+                               bool *non_constant_p, tree *jump_target,
+                               tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  if (CLASS_TYPE_P (r)
+      && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      elts = class_members_of (loc, ctx, r, actx, call, non_constant_p,
+                              jump_target, METAFN_NONSTATIC_DATA_MEMBERS_OF,
+                              fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  else
+    return throw_exception (loc, ctx, "not a complete class type",
+                           fun, non_constant_p, jump_target);
+  return get_vector_of_info_elts (elts);
+}
+
+/* Implement std::meta::subobjects_of.
+   Returns: A vector containing each element of bases_of(type, ctx) followed
+   by each element of nonstatic_data_members_of(type, ctx), preserving their
+   order.
+   Throws: meta::exception unless dealias(type) represents a class type that
+   is complete from some point in the evaluation context.  */
+
+static tree
+eval_subobjects_of (location_t loc, const constexpr_ctx *ctx, tree r,
+                   tree actx, tree call, bool *non_constant_p,
+                   tree *jump_target, tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  if (CLASS_TYPE_P (r)
+      && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      elts = class_bases_of (loc, ctx, r, actx, call, non_constant_p,
+                            jump_target, METAFN_BASES_OF, fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      vec<constructor_elt, va_gc> *elts2
+       = class_members_of (loc, ctx, r, actx, call, non_constant_p,
+                           jump_target, METAFN_NONSTATIC_DATA_MEMBERS_OF,
+                           fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      if (elts == nullptr)
+       elts = elts2;
+      else if (elts2)
+       vec_safe_splice (elts, elts2);
+    }
+  else
+    return throw_exception (loc, ctx, "not a complete class type",
+                           fun, non_constant_p, jump_target);
+  return get_vector_of_info_elts (elts);
+}
+
+/* Implement std::meta::has_inaccessible_nonstatic_data_members.
+   Returns: true if is_accessible(R, ctx) is false for any R in
+   nonstatic_data_members_of(r, access_context::unchecked()).
+   Otherwise, false.
+   Throws: meta::exception if
+   -- the evaluation of
+      nonstatic_data_members_of(r, access_context::unchecked()) would exit via
+      an exception and or
+   -- r represents a closure type.  */
+
+static tree
+eval_has_inaccessible_nonstatic_data_members (location_t loc,
+                                             const constexpr_ctx *ctx,
+                                             tree r, tree actx, tree call,
+                                             bool *non_constant_p,
+                                             tree *jump_target, tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  if (CLASS_TYPE_P (r)
+      && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      if (LAMBDA_TYPE_P (r))
+       return throw_exception (loc, ctx, "closure type", fun,
+                               non_constant_p, jump_target);
+      elts = class_members_of (loc, ctx, r, actx, call, non_constant_p,
+                              jump_target,
+                              METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS,
+                              fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  else
+    return throw_exception (loc, ctx, "not a complete class type",
+                           fun, non_constant_p, jump_target);
+  if (elts == nullptr)
+    return boolean_false_node;
+  else
+    return boolean_true_node;
+}
+
+/* Implement std::meta::has_inaccessible_bases.
+   Returns: true if is_accessible(R, ctx) is false for any R in
+   bases_of(r, access_context::unchecked()).  Otherwise, false.
+   Throws: meta::exception if the evaluation of
+   bases_of(r, access_context::unchecked()) would exit via an exception.  */
+
+static tree
+eval_has_inaccessible_bases (location_t loc, const constexpr_ctx *ctx,
+                            tree r, tree actx, tree call,
+                            bool *non_constant_p, tree *jump_target,
+                            tree fun)
+{
+  r = maybe_strip_typedefs (r);
+  vec<constructor_elt, va_gc> *elts = nullptr;
+  if (CLASS_TYPE_P (r)
+      && complete_type_or_maybe_complain (r, NULL_TREE, tf_none))
+    {
+      elts = class_bases_of (loc, ctx, r, actx, call, non_constant_p,
+                            jump_target, METAFN_HAS_INACCESSIBLE_BASES, fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+    }
+  else
+    return throw_exception (loc, ctx, "not a complete class type",
+                           fun, non_constant_p, jump_target);
+  if (elts == nullptr)
+    return boolean_false_node;
+  else
+    return boolean_true_node;
+}
+
+/* Implement std::meta::has_inaccessible_subobjects.
+   Effects: Equivalent to:
+   return has_inaccessible_bases(r, ctx)
+         || has_inaccessible_nonstatic_data_members(r, ctx);  */
+
+static tree
+eval_has_inaccessible_subobjects (location_t loc, const constexpr_ctx *ctx,
+                                 tree r, tree actx, tree call,
+                                 bool *non_constant_p, tree *jump_target,
+                                 tree fun)
+{
+  tree b = eval_has_inaccessible_bases (loc, ctx, r, actx, call,
+                                       non_constant_p, jump_target, fun);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  if (b == boolean_true_node)
+    return b;
+  return eval_has_inaccessible_nonstatic_data_members (loc, ctx, r, actx,
+                                                      call, non_constant_p,
+                                                      jump_target, fun);
+}
+
+/* Implement std::meta::exception::_S_exception_cvt_to_utf8 and
+   std::meta::exception::_S_exception_cvt_from_utf8.  This is
+   an implementation specific metafunction which translates string_view
+   into u8string_view resp. u8string_view into string_view for use in
+   std::meta::exception constructors.  On translation failure returns an empty
+   {u8,}string_view.  TO_UTF8 is true for _S_exception_cvt_to_utf8 and false
+   for _S_exception_cvt_from_utf8.  */
+
+static tree
+eval_exception__S_exception_cvt_tofrom_utf8 (location_t loc,
+                                            const constexpr_ctx *ctx,
+                                            tree call, bool *non_constant_p,
+                                            bool *overflow_p,
+                                            tree *jump_target, tree fun,
+                                            bool to_utf8)
+{
+  tree str = get_range_elts (loc, ctx, call, 0, non_constant_p, overflow_p,
+                            jump_target, REFLECT_CONSTANT_STRING, fun);
+  if (*jump_target || *non_constant_p)
+    return NULL_TREE;
+  if (TREE_CODE (str) != STRING_CST
+      || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (str)))
+         != (to_utf8 ? char_type_node : char8_type_node)))
+    {
+      error_at (loc, "unexpected argument to %qs",
+               to_utf8 ? "_S_exception_cvt_to_utf8"
+               : "_S_exception_cvt_from_utf8");
+      *non_constant_p = true;
+      return call;
+    }
+  /* We need to translate the string twice for the theoretical case
+     of non-UTF8 SOURCE_CHARSET.  First translate from {exec charset,UTF-8} to
+     SOURCE_CHARSET...  */
+  cpp_string istr, ostr;
+  istr.len = TREE_STRING_LENGTH (str) + 1;
+  istr.text = (const unsigned char *) TREE_STRING_POINTER (str);
+  const char *name;
+  if (!cpp_translate_string (parse_in, &istr, &ostr,
+                            to_utf8 ? CPP_STRING : CPP_UTF8STRING, true))
+    {
+      ostr.text = NULL;
+      name = "";
+    }
+  else
+    name = (const char *) ostr.text;
+  /* And then let get_string_literal translate from SOURCE_CHARSET to
+     {UTF-8,exec charset}.  */
+  tree dchar_type = to_utf8 ? char8_type_node : char_type_node;
+  str = get_string_literal (name, dchar_type);
+  free (const_cast <unsigned char *> (ostr.text));
+  if (str == NULL_TREE)
+    {
+      str = get_string_literal ("", dchar_type);
+      gcc_assert (str);
+    }
+  releasing_vec args (make_tree_vector_single (str));
+  tree ret = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                       &args, TREE_TYPE (call), LOOKUP_NORMAL,
+                                       tf_warning_or_error);
+  return build_cplus_new (TREE_TYPE (call), ret, tf_warning_or_error);
+}
+
+/* Helper for eval_extract, extracting a reference type T.
+   Returns: If r represents an object O, then a reference to O.
+   Otherwise, a reference to the object declared, or referred to, by the
+   variable represented by r.
+   Throws: meta::exception unless
+   -- r represents a variable or object of type U,
+   -- is_convertible_v<remove_reference_t<U>(*)[],
+      remove_reference_t<T>(*)[]> is true, and
+   -- If r represents a variable, then either that variable is usable in
+      constant expressions or its lifetime began within the core constant
+      expression currently under evaluation.  */
+
+static tree
+extract_ref (location_t loc, const constexpr_ctx *ctx, tree T, tree r,
+            reflect_kind kind, bool *non_constant_p, tree *jump_target,
+            tree fun)
+{
+  auto adjust_type = [](tree type) -> tree
+    {
+      if (TYPE_REF_P (type))
+       type = TREE_TYPE (type);
+      type = build_cplus_array_type (type, NULL_TREE);
+      return build_pointer_type (type);
+    };
+
+  const bool var_p = eval_is_variable (r, kind) == boolean_true_node;
+  if (var_p || eval_is_object (kind) == boolean_true_node)
+    {
+      /* The wording is saying that U is the type of r.  */
+      tree U = TREE_TYPE (r);
+      if (is_convertible (adjust_type (U), adjust_type (T))
+         && (!var_p || is_constant_expression (r)))
+       {
+         if (TYPE_REF_P (TREE_TYPE (r)))
+           {
+             r = DECL_INITIAL (r);
+             r = maybe_get_reference_referent (r);
+             gcc_checking_assert (!TYPE_REF_P (TREE_TYPE (r)));
+           }
+         return build_address (r);
+       }
+    }
+
+  return throw_exception (loc, ctx, "value cannot be extracted", fun,
+                         non_constant_p, jump_target);
+}
+
+/* Helper for extract_value.  Return true iff we can extract value of
+   type U using type T.  */
+
+static bool
+can_extract_value_p (tree T, tree U)
+{
+  if (POINTER_TYPE_P (U)
+      && (similar_type_p (T, U)
+         || (FUNCTION_POINTER_TYPE_P (T) && FUNCTION_POINTER_TYPE_P (U)))
+      && is_convertible (U, T))
+    return true;
+  else if (same_type_ignoring_top_level_qualifiers_p (T, U))
+    return true;
+  else if (TREE_CODE (U) == ARRAY_TYPE
+          && POINTER_TYPE_P (T)
+          && is_convertible (U, T))
+    {
+      /* remove_extent_t<U> */
+      U = TREE_TYPE (U);
+      U = strip_typedefs (U);
+      /* remove_extent_t<U>* */
+      U = build_pointer_type (U);
+      return similar_type_p (T, U);
+    }
+  else if (LAMBDA_TYPE_P (U)
+          && FUNCTION_POINTER_TYPE_P (T)
+          && is_convertible (U, T))
+    return true;
+  return false;
+}
+
+/* Helper for eval_extract, extracting a value.
+   Let U be the type of the value or object that r represents.
+   Returns: static_cast<T>([:R:]), where R is a constant expression of
+   type info such that R == r is true.
+   Throws: meta::exception unless
+   -- U is a pointer type, T and U are either similar or both function pointer
+      types, and is_convertible_v<U, T> is true,
+   -- U is not a pointer type and the cv-unqualified types of T and U are the
+      same,
+   -- U is an array type, T is a pointer type, remove_extent_t<U>* and T are
+      similar types, and the value r represents is convertible to T, or
+   -- U is a closure type, T is a function pointer type, and the value that r
+      represents is convertible to T.  */
+
+static tree
+extract_value (location_t loc, const constexpr_ctx *ctx, tree T, tree r,
+              bool *non_constant_p, tree *jump_target, tree fun)
+{
+  if (REFLECT_EXPR_P (r))
+    {
+      r = REFLECT_EXPR_HANDLE (r);
+      if (can_extract_value_p (T, TREE_TYPE (r)))
+       return build_static_cast (loc, T, r, tf_none);
+    }
+  return throw_exception (loc, ctx, "value cannot be extracted", fun,
+                         non_constant_p, jump_target);
+}
+
+/* Helper for extract_member_or_function.  Return true iff we can
+   extract an NSDM or function R of kind KIND using type T.  */
+
+static bool
+can_extract_member_or_function_p (tree T, tree r, reflect_kind kind)
+{
+  if (eval_is_nonstatic_data_member (r) == boolean_true_node)
+    {
+      if (eval_is_bit_field (r, kind) == boolean_true_node)
+       return false;
+      /* static union { int m; }; extract<int>(^^m); is invalid.  */
+      if (TREE_CODE (r) == FIELD_DECL
+         && ANON_UNION_TYPE_P (DECL_CONTEXT (r)))
+       {
+         tree c = CP_TYPE_CONTEXT (DECL_CONTEXT (r));
+         while (ANON_UNION_TYPE_P (c))
+           c = CP_TYPE_CONTEXT (c);
+         if (!TYPE_P (c))
+           return false;
+       }
+      /* Create the X C::* type.  */
+      tree type = build_offset_type (CP_DECL_CONTEXT (r), TREE_TYPE (r));
+      if (similar_type_p (type, T) && is_convertible (type, T))
+       return true;
+      return false;
+    }
+  else if (DECL_IOBJ_MEMBER_FUNCTION_P (r))
+    {
+      tree F = TREE_TYPE (r);
+      F = build_pointer_type (F);
+      F = build_ptrmemfunc_type (F);
+      if (same_type_p (T, F))
+       return true;
+      return false;
+    }
+  else if (TREE_CODE (r) == FUNCTION_DECL)
+    {
+      tree F = TREE_TYPE (r);
+      F = build_pointer_type (F);
+      if (same_type_p (T, F))
+       return true;
+      return false;
+    }
+
+  return false;
+}
+
+/* Helper for eval_extract, extracting a NSDM or function.
+   Returns:
+   -- If T is a pointer type, then a pointer value pointing to the function
+      represented by r.
+   -- Otherwise, a pointer-to-member value designating the non-static data
+      member or function represented by r.
+   Throws: meta::exception unless
+   -- r represents a non-static data member with type X, that is not
+      a bit-field, that is a direct member of class C, T and X C::*
+      are similar types, and is_convertible_v<X C::*, T> is true;
+   -- r represents an implicit object member function with type F or
+      F noexcept that is a direct member of a class C, and T is F C::*; or
+   -- r represents a non-member function, static member function, or
+      explicit object member function of function type F or F noexcept, and
+      T is F*.  */
+
+static tree
+extract_member_or_function (location_t loc, const constexpr_ctx *ctx,
+                           tree T, tree r, reflect_kind kind,
+                           bool *non_constant_p, tree *jump_target, tree fun)
+{
+  r = MAYBE_BASELINK_FUNCTIONS (r);
+  if (!can_extract_member_or_function_p (T, r, kind))
+    return throw_exception (loc, ctx, "value cannot be extracted", fun,
+                           non_constant_p, jump_target);
+
+  const tsubst_flags_t complain = complain_flags (ctx);
+  if (POINTER_TYPE_P (T))
+    return cp_build_addr_expr (r, complain);
+  else
+    {
+      if (!mark_used (r, complain))
+       {
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
+      r = build_offset_ref (DECL_CONTEXT (r), r, /*address_p=*/true, complain);
+      r = cp_build_addr_expr (r, complain);
+      r = cp_convert (T, r, complain);
+      return r;
+    }
+}
+
+/* Process std::meta::extract.
+   Let U be remove_cv_t<T>.
+   Effects: Equivalent to:
+     if constexpr (is_reference_type(^^T)) {
+       return extract-ref<T>(r);
+     } else if constexpr (is_nonstatic_data_member(r) || is_function(r)) {
+       return extract-member-or-function<U>(r);
+     } else {
+       return extract-value<U>(constant_of(r));
+     }
+  */
+
+static tree
+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)
+    return extract_ref (loc, ctx, type, r, kind, non_constant_p, jump_target,
+                       fun);
+  type = cv_unqualified (type);
+  if (eval_is_nonstatic_data_member (r) == boolean_true_node
+      || eval_is_function (r) == boolean_true_node)
+    return extract_member_or_function (loc, ctx, type, r, kind, non_constant_p,
+                                      jump_target, fun);
+  else
+    {
+      r = eval_constant_of (loc, ctx, r, kind, non_constant_p, overflow_p,
+                           jump_target, fun);
+      if (*jump_target || *non_constant_p)
+       return NULL_TREE;
+      return extract_value (loc, ctx, type, r, non_constant_p, jump_target,
+                           fun);
+    }
+}
+
+/* Expand a call to a metafunction FUN.  CALL is the CALL_EXPR.
+   JUMP_TARGET is set if we are throwing std::meta::exception.  */
+
+tree
+process_metafunction (const constexpr_ctx *ctx, tree fun, tree call,
+                     bool *non_constant_p, bool *overflow_p,
+                     tree *jump_target)
+{
+  tree name = DECL_NAME (fun);
+  const char *ident = IDENTIFIER_POINTER (name);
+  const location_t loc = cp_expr_loc_or_input_loc (call);
+  const metafn_info *minfo
+    = metafn_lookup::find (ident, IDENTIFIER_LENGTH (name));
+  if (minfo == NULL)
+    {
+    not_found:
+      error_at (loc, "unknown metafunction %qD", fun);
+      *non_constant_p = true;
+      return NULL_TREE;
+    }
+  tree h = NULL_TREE, h1 = NULL_TREE, hvec = NULL_TREE, expr = NULL_TREE;
+  tree type = NULL_TREE, ht, info;
+  reflect_kind kind = REFLECT_UNDEF;
+  for (int argno = 0; argno < 3; ++argno)
+    switch ((minfo->kind >> ((argno + 1) * METAFN_KIND_SHIFT))
+           & METAFN_KIND_MASK)
+      {
+      case METAFN_KIND_ARG_VOID:
+       break;
+      case METAFN_KIND_ARG_INFO:
+      case METAFN_KIND_ARG_TINFO:
+       gcc_assert (argno < 2);
+       info = get_info (ctx, call, argno, non_constant_p, overflow_p,
+                        jump_target);
+       if (*jump_target || *non_constant_p)
+         return NULL_TREE;
+       ht = REFLECT_EXPR_HANDLE (info);
+       if (((minfo->kind >> ((argno + 1) * METAFN_KIND_SHIFT))
+            & METAFN_KIND_MASK) == METAFN_KIND_ARG_TINFO)
+         {
+           if (eval_is_type (ht) != boolean_true_node)
+             return throw_exception_nontype (loc, ctx, fun, non_constant_p,
+                                             jump_target);
+         }
+       if (argno == 0)
+         {
+           kind = REFLECT_EXPR_KIND (info);
+           h = ht;
+         }
+       else
+         h1 = ht;
+       break;
+      case METAFN_KIND_ARG_REFLECTION_RANGE:
+       gcc_assert (argno == 1);
+       hvec = get_info_vec (loc, ctx, call, argno, non_constant_p,
+                            overflow_p, jump_target, fun);
+       if (*jump_target || *non_constant_p)
+         return NULL_TREE;
+       break;
+      case METAFN_KIND_ARG_REFLECTION_RANGET:
+       hvec = get_type_info_vec (loc, ctx, call, argno, non_constant_p,
+                               overflow_p, jump_target, fun);
+       if (*jump_target || *non_constant_p)
+         return NULL_TREE;
+       break;
+      case METAFN_KIND_ARG_INPUT_RANGE:
+       /* Handled in eval_reflect_constant_*.  */
+       gcc_assert (argno == 0);
+       break;
+      case METAFN_KIND_ARG_TEMPLATE_PARM:
+      case METAFN_KIND_ARG_TEMPLATE_PARM_REF:
+       type = TREE_VEC_ELT (get_template_innermost_arguments (fun), 0);
+       /* FALLTHRU */
+      case METAFN_KIND_ARG_SIZE_T:
+      case METAFN_KIND_ARG_OPERATORS:
+       gcc_assert (argno == 0);
+       expr = get_nth_callarg (call, 0);
+       expr = cxx_eval_constant_expression (ctx, expr, vc_prvalue,
+                                            non_constant_p, overflow_p,
+                                            jump_target);
+       if (*jump_target || *non_constant_p)
+         return NULL_TREE;
+       break;
+      case METAFN_KIND_ARG_UNSIGNED:
+      case METAFN_KIND_ARG_ACCESS_CONTEXT:
+      case METAFN_KIND_ARG_DATA_MEMBER_OPTIONS:
+       gcc_assert (argno == 1);
+       expr = get_nth_callarg (call, argno);
+       expr = cxx_eval_constant_expression (ctx, expr, vc_prvalue,
+                                            non_constant_p, overflow_p,
+                                            jump_target);
+       if (*jump_target || *non_constant_p)
+         return NULL_TREE;
+       break;
+      default:
+       gcc_unreachable ();
+      }
+
+  switch (minfo->code)
+    {
+    case METAFN_OPERATOR_OF:
+      return eval_operator_of (loc, ctx, h, non_constant_p, jump_target,
+                              TREE_TYPE (call), fun);
+    case METAFN_SYMBOL_OF:
+      return eval_symbol_of (loc, ctx, expr, non_constant_p, jump_target,
+                            char_type_node, TREE_TYPE (call), fun);
+    case METAFN_U8SYMBOL_OF:
+      return eval_symbol_of (loc, ctx, expr, non_constant_p, jump_target,
+                            char8_type_node, TREE_TYPE (call), fun);
+    case METAFN_HAS_IDENTIFIER:
+      return eval_has_identifier (h, kind);
+    case METAFN_IDENTIFIER_OF:
+      return eval_identifier_of (loc, ctx, h, kind, non_constant_p, jump_target,
+                                char_type_node, TREE_TYPE (call), fun);
+    case METAFN_U8IDENTIFIER_OF:
+      return eval_identifier_of (loc, ctx, h, kind, non_constant_p, jump_target,
+                                char8_type_node, TREE_TYPE (call), fun);
+    case METAFN_DISPLAY_STRING_OF:
+      return eval_display_string_of (loc, ctx, h, kind, non_constant_p,
+                                    jump_target, char_type_node,
+                                    TREE_TYPE (call), fun);
+    case METAFN_U8DISPLAY_STRING_OF:
+      return eval_display_string_of (loc, ctx, h, kind, non_constant_p,
+                                    jump_target, char8_type_node,
+                                    TREE_TYPE (call), fun);
+    case METAFN_SOURCE_LOCATION_OF:
+      return eval_source_location_of (loc, h, kind, TREE_TYPE (call));
+    case METAFN_TYPE_OF:
+      return eval_type_of (loc, ctx, h, kind, non_constant_p, jump_target, fun);
+    case METAFN_OBJECT_OF:
+      return eval_object_of (loc, ctx, h, kind, non_constant_p, overflow_p,
+                            jump_target, fun);
+    case METAFN_CONSTANT_OF:
+      return eval_constant_of (loc, ctx, h, kind, non_constant_p, overflow_p,
+                              jump_target, fun);
+    case METAFN_IS_PUBLIC:
+      return eval_is_public (h, kind);
+    case METAFN_IS_PROTECTED:
+      return eval_is_protected (h, kind);
+    case METAFN_IS_PRIVATE:
+      return eval_is_private (h, kind);
+    case METAFN_IS_VIRTUAL:
+      return eval_is_virtual (h, kind);
+    case METAFN_IS_PURE_VIRTUAL:
+      return eval_is_pure_virtual (h);
+    case METAFN_IS_OVERRIDE:
+      return eval_is_override (h);
+    case METAFN_IS_FINAL:
+      return eval_is_final (h);
+    case METAFN_IS_DELETED:
+      return eval_is_deleted (h);
+    case METAFN_IS_DEFAULTED:
+      return eval_is_defaulted (h);
+    case METAFN_IS_USER_PROVIDED:
+      return eval_is_user_provided (h);
+    case METAFN_IS_USER_DECLARED:
+      return eval_is_user_declared (h);
+    case METAFN_IS_EXPLICIT:
+      return eval_is_explicit (h);
+    case METAFN_IS_NOEXCEPT:
+      return eval_is_noexcept (h);
+    case METAFN_IS_BIT_FIELD:
+      return eval_is_bit_field (h, kind);
+    case METAFN_IS_ENUMERATOR:
+      return eval_is_enumerator (h);
+    case METAFN_IS_ANNOTATION:
+      return eval_is_annotation (h, kind);
+    case METAFN_IS_CONST:
+      return eval_is_const (h, kind);
+    case METAFN_IS_VOLATILE:
+      return eval_is_volatile (h, kind);
+    case METAFN_IS_MUTABLE_MEMBER:
+      return eval_is_mutable_member (h);
+    case METAFN_IS_LVALUE_REFERENCE_QUALIFIED:
+      return eval_is_lrvalue_reference_qualified (h, kind, /*rvalue_p=*/false);
+    case METAFN_IS_RVALUE_REFERENCE_QUALIFIED:
+      return eval_is_lrvalue_reference_qualified (h, kind, /*rvalue_p=*/true);
+    case METAFN_HAS_STATIC_STORAGE_DURATION:
+      return eval_has_static_storage_duration (h, kind);
+    case METAFN_HAS_THREAD_STORAGE_DURATION:
+      return eval_has_thread_storage_duration (h, kind);
+    case METAFN_HAS_AUTOMATIC_STORAGE_DURATION:
+      return eval_has_automatic_storage_duration (h, kind);
+    case METAFN_HAS_INTERNAL_LINKAGE:
+      return eval_has_internal_linkage (h, kind);
+    case METAFN_HAS_MODULE_LINKAGE:
+      return eval_has_module_linkage (h, kind);
+    case METAFN_HAS_EXTERNAL_LINKAGE:
+      return eval_has_external_linkage (h, kind);
+    case METAFN_HAS_C_LANGUAGE_LINKAGE:
+      return eval_has_c_language_linkage (h, kind);
+    case METAFN_HAS_LINKAGE:
+      return eval_has_linkage (h, kind);
+    case METAFN_IS_COMPLETE_TYPE:
+      return eval_is_complete_type (h);
+    case METAFN_IS_ENUMERABLE_TYPE:
+      return eval_is_enumerable_type (h);
+    case METAFN_IS_VARIABLE:
+      return eval_is_variable (h, kind);
+    case METAFN_IS_TYPE:
+      return eval_is_type (h);
+    case METAFN_IS_NAMESPACE:
+      return eval_is_namespace (h);
+    case METAFN_IS_TYPE_ALIAS:
+      return eval_is_type_alias (h);
+    case METAFN_IS_NAMESPACE_ALIAS:
+      return eval_is_namespace_alias (h);
+    case METAFN_IS_FUNCTION:
+      return eval_is_function (h);
+    case METAFN_IS_CONVERSION_FUNCTION:
+      return eval_is_conversion_function (h);
+    case METAFN_IS_OPERATOR_FUNCTION:
+      return eval_is_operator_function (h);
+    case METAFN_IS_LITERAL_OPERATOR:
+      return eval_is_literal_operator (h);
+    case METAFN_IS_SPECIAL_MEMBER_FUNCTION:
+      return eval_is_special_member_function (h);
+    case METAFN_IS_CONSTRUCTOR:
+      return eval_is_constructor (h);
+    case METAFN_IS_DEFAULT_CONSTRUCTOR:
+      return eval_is_default_constructor (h);
+    case METAFN_IS_COPY_CONSTRUCTOR:
+      return eval_is_copy_constructor (h);
+    case METAFN_IS_MOVE_CONSTRUCTOR:
+      return eval_is_move_constructor (h);
+    case METAFN_IS_ASSIGNMENT:
+      return eval_is_assignment (h);
+    case METAFN_IS_COPY_ASSIGNMENT:
+      return eval_is_copy_assignment (h);
+    case METAFN_IS_MOVE_ASSIGNMENT:
+      return eval_is_move_assignment (h);
+    case METAFN_IS_DESTRUCTOR:
+      return eval_is_destructor (h);
+    case METAFN_IS_FUNCTION_PARAMETER:
+      return eval_is_function_parameter (h, kind);
+    case METAFN_IS_EXPLICIT_OBJECT_PARAMETER:
+      return eval_is_explicit_object_parameter (h, kind);
+    case METAFN_HAS_DEFAULT_ARGUMENT:
+      return eval_has_default_argument (h, kind);
+    case METAFN_HAS_ELLIPSIS_PARAMETER:
+      return eval_has_ellipsis_parameter (h);
+    case METAFN_IS_TEMPLATE:
+      return eval_is_template (h);
+    case METAFN_IS_FUNCTION_TEMPLATE:
+      return eval_is_function_template (h);
+    case METAFN_IS_VARIABLE_TEMPLATE:
+      return eval_is_variable_template (h);
+    case METAFN_IS_CLASS_TEMPLATE:
+      return eval_is_class_template (h);
+    case METAFN_IS_ALIAS_TEMPLATE:
+      return eval_is_alias_template (h);
+    case METAFN_IS_CONVERSION_FUNCTION_TEMPLATE:
+      return eval_is_conversion_function_template (h);
+    case METAFN_IS_OPERATOR_FUNCTION_TEMPLATE:
+      return eval_is_operator_function_template (h);
+    case METAFN_IS_LITERAL_OPERATOR_TEMPLATE:
+      return eval_is_literal_operator_template (h);
+    case METAFN_IS_CONSTRUCTOR_TEMPLATE:
+      return eval_is_constructor_template (h);
+    case METAFN_IS_CONCEPT:
+      return eval_is_concept (h);
+    case METAFN_IS_VALUE:
+      return eval_is_value (kind);
+    case METAFN_IS_OBJECT:
+      return eval_is_object (kind);
+    case METAFN_IS_STRUCTURED_BINDING:
+      return eval_is_structured_binding (h, kind);
+    case METAFN_IS_CLASS_MEMBER:
+      return eval_is_class_member (h);
+    case METAFN_IS_NAMESPACE_MEMBER:
+      return eval_is_namespace_member (h);
+    case METAFN_IS_NONSTATIC_DATA_MEMBER:
+      return eval_is_nonstatic_data_member (h);
+    case METAFN_IS_STATIC_MEMBER:
+      return eval_is_static_member (h);
+    case METAFN_IS_BASE:
+      return eval_is_base (h, kind);
+    case METAFN_HAS_DEFAULT_MEMBER_INITIALIZER:
+      return eval_has_default_member_initializer (h);
+    case METAFN_HAS_PARENT:
+      return eval_has_parent (h, kind);
+    case METAFN_PARENT_OF:
+      return eval_parent_of (loc, ctx, h, kind, non_constant_p, jump_target,
+                            fun);
+    case METAFN_DEALIAS:
+      return eval_dealias (loc, h, kind);
+    case METAFN_HAS_TEMPLATE_ARGUMENTS:
+      return eval_has_template_arguments (h);
+    case METAFN_TEMPLATE_OF:
+      return eval_template_of (loc, ctx, h, non_constant_p, jump_target, fun);
+    case METAFN_TEMPLATE_ARGUMENTS_OF:
+      return eval_template_arguments_of (loc, ctx, h, non_constant_p,
+                                        jump_target, fun);
+    case METAFN_PARAMETERS_OF:
+      return eval_parameters_of (loc, ctx, h, non_constant_p, jump_target,
+                                fun);
+    case METAFN_VARIABLE_OF:
+      return eval_variable_of (loc, ctx, h, kind, non_constant_p, jump_target,
+                              fun);
+    case METAFN_RETURN_TYPE_OF:
+      return eval_return_type_of (loc, ctx, h, kind, non_constant_p,
+                                 jump_target, fun);
+    case METAFN_IS_ACCESSIBLE:
+      return eval_is_accessible (loc, ctx, h, kind, expr, call,
+                                non_constant_p, jump_target, fun);
+    case METAFN_HAS_INACCESSIBLE_NONSTATIC_DATA_MEMBERS:
+      return eval_has_inaccessible_nonstatic_data_members (loc, ctx, h, expr,
+                                                          call,
+                                                          non_constant_p,
+                                                          jump_target, fun);
+    case METAFN_HAS_INACCESSIBLE_BASES:
+      return eval_has_inaccessible_bases (loc, ctx, h, expr, call,
+                                         non_constant_p, jump_target, fun);
+    case METAFN_HAS_INACCESSIBLE_SUBOBJECTS:
+      return eval_has_inaccessible_subobjects (loc, ctx, h, expr, call,
+                                              non_constant_p, jump_target,
+                                              fun);
+    case METAFN_MEMBERS_OF:
+      return eval_members_of (loc, ctx, h, expr, call, non_constant_p,
+                             jump_target, fun);
+    case METAFN_BASES_OF:
+      return eval_bases_of (loc, ctx, h, expr, call, non_constant_p,
+                           jump_target, fun);
+    case METAFN_STATIC_DATA_MEMBERS_OF:
+      return eval_static_data_members_of (loc, ctx, h, expr, call,
+                                         non_constant_p, jump_target,
+                                         fun);
+    case METAFN_NONSTATIC_DATA_MEMBERS_OF:
+      return eval_nonstatic_data_members_of (loc, ctx, h, expr, call,
+                                            non_constant_p, jump_target,
+                                            fun);
+    case METAFN_SUBOBJECTS_OF:
+      return eval_subobjects_of (loc, ctx, h, expr, call, non_constant_p,
+                                jump_target, fun);
+    case METAFN_ENUMERATORS_OF:
+      return eval_enumerators_of (loc, ctx, h, non_constant_p, jump_target,
+                                 fun);
+    case METAFN_OFFSET_OF:
+      return eval_offset_of (loc, ctx, h, kind, TREE_TYPE (call),
+                            non_constant_p, jump_target, fun);
+    case METAFN_SIZE_OF:
+      return eval_size_of (loc, ctx, h, kind, TREE_TYPE (call), non_constant_p,
+                          jump_target, fun);
+    case METAFN_ALIGNMENT_OF:
+      return eval_alignment_of (loc, ctx, h, kind, TREE_TYPE (call),
+                               non_constant_p, jump_target, fun);
+    case METAFN_BIT_SIZE_OF:
+      return eval_bit_size_of (loc, ctx, h, kind, TREE_TYPE (call),
+                              non_constant_p, jump_target, fun);
+    case METAFN_EXTRACT:
+      {
+       type = TREE_VEC_ELT (get_template_innermost_arguments (fun), 0);
+       return eval_extract (loc, ctx, type, h, kind, non_constant_p,
+                            overflow_p, jump_target, fun);
+      }
+    case METAFN_CAN_SUBSTITUTE:
+      return eval_can_substitute (loc, ctx, h, hvec, non_constant_p,
+                                 jump_target, fun);
+    case METAFN_SUBSTITUTE:
+      return eval_substitute (loc, ctx, h, hvec, non_constant_p, jump_target,
+                             fun);
+    case METAFN_REFLECT_CONSTANT:
+      return eval_reflect_constant (loc, ctx, type, expr, non_constant_p,
+                                   jump_target, fun);
+    case METAFN_REFLECT_OBJECT:
+      return eval_reflect_object (loc, ctx, type, expr, non_constant_p,
+                                 jump_target, fun);
+    case METAFN_REFLECT_FUNCTION:
+      return eval_reflect_function (loc, ctx, type, expr, non_constant_p,
+                                   jump_target, fun);
+    case METAFN_REFLECT_CONSTANT_STRING:
+      return eval_reflect_constant_string (loc, ctx, call, non_constant_p,
+                                          overflow_p, jump_target, fun);
+    case METAFN_REFLECT_CONSTANT_ARRAY:
+      return eval_reflect_constant_array (loc, ctx, call, non_constant_p,
+                                         overflow_p, jump_target, fun);
+    case METAFN_DATA_MEMBER_SPEC:
+      return eval_data_member_spec (loc, ctx, h, expr, non_constant_p,
+                                   overflow_p, jump_target, fun);
+    case METAFN_IS_DATA_MEMBER_SPEC:
+      return eval_is_data_member_spec (h, kind);
+    case METAFN_DEFINE_AGGREGATE:
+      return eval_define_aggregate (loc, ctx, h, hvec, call, non_constant_p);
+    case METAFN_IS_VOID_TYPE:
+      return eval_is_void_type (h);
+    case METAFN_IS_NULL_POINTER_TYPE:
+      return eval_is_null_pointer_type (h);
+    case METAFN_IS_INTEGRAL_TYPE:
+      return eval_is_integral_type (h);
+    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);
+    case METAFN_IS_POINTER_TYPE:
+      return eval_is_pointer_type (loc, h);
+    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);
+    case METAFN_IS_MEMBER_FUNCTION_POINTER_TYPE:
+      return eval_is_member_function_pointer_type (loc, h);
+    case METAFN_IS_ENUM_TYPE:
+      return eval_is_enum_type (loc, h);
+    case METAFN_IS_UNION_TYPE:
+      return eval_is_union_type (loc, h);
+    case METAFN_IS_CLASS_TYPE:
+      return eval_is_class_type (loc, h);
+    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);
+    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);
+    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);
+    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);
+    case METAFN_IS_STANDARD_LAYOUT_TYPE:
+      return eval_is_standard_layout_type (h);
+    case METAFN_IS_EMPTY_TYPE:
+      return eval_is_empty_type (loc, h);
+    case METAFN_IS_POLYMORPHIC_TYPE:
+      return eval_is_polymorphic_type (loc, h);
+    case METAFN_IS_ABSTRACT_TYPE:
+      return eval_is_abstract_type (h);
+    case METAFN_IS_FINAL_TYPE:
+      return eval_is_final_type (loc, h);
+    case METAFN_IS_AGGREGATE_TYPE:
+      return eval_is_aggregate_type (h);
+    case METAFN_IS_CONSTEVAL_ONLY_TYPE:
+      return eval_is_consteval_only_type (h);
+    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);
+    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);
+    case METAFN_IS_DEFAULT_CONSTRUCTIBLE_TYPE:
+      return eval_is_default_constructible_type (h);
+    case METAFN_IS_COPY_CONSTRUCTIBLE_TYPE:
+      return eval_is_copy_constructible_type (h);
+    case METAFN_IS_MOVE_CONSTRUCTIBLE_TYPE:
+      return eval_is_move_constructible_type (h);
+    case METAFN_IS_ASSIGNABLE_TYPE:
+      return eval_is_assignable_type (loc, h, h1);
+    case METAFN_IS_COPY_ASSIGNABLE_TYPE:
+      return eval_is_copy_assignable_type (h);
+    case METAFN_IS_MOVE_ASSIGNABLE_TYPE:
+      return eval_is_move_assignable_type (h);
+    case METAFN_IS_SWAPPABLE_WITH_TYPE:
+      return eval_is_swappable_with_type (loc, ctx, h, h1, call,
+                                         non_constant_p, jump_target, fun,
+                                         "is_swappable_with");
+    case METAFN_IS_SWAPPABLE_TYPE:
+      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);
+    case METAFN_IS_TRIVIALLY_CONSTRUCTIBLE_TYPE:
+      return eval_is_trivially_constructible_type (h, hvec);
+    case METAFN_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_TYPE:
+      return eval_is_trivially_default_constructible_type (h);
+    case METAFN_IS_TRIVIALLY_COPY_CONSTRUCTIBLE_TYPE:
+      return eval_is_trivially_copy_constructible_type (h);
+    case METAFN_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE_TYPE:
+      return eval_is_trivially_move_constructible_type (h);
+    case METAFN_IS_TRIVIALLY_ASSIGNABLE_TYPE:
+      return eval_is_trivially_assignable_type (loc, h, h1);
+    case METAFN_IS_TRIVIALLY_COPY_ASSIGNABLE_TYPE:
+      return eval_is_trivially_copy_assignable_type (h);
+    case METAFN_IS_TRIVIALLY_MOVE_ASSIGNABLE_TYPE:
+      return eval_is_trivially_move_assignable_type (h);
+    case METAFN_IS_TRIVIALLY_DESTRUCTIBLE_TYPE:
+      return eval_is_trivially_destructible_type (loc, h);
+    case METAFN_IS_NOTHROW_CONSTRUCTIBLE_TYPE:
+      return eval_is_nothrow_constructible_type (h, hvec);
+    case METAFN_IS_NOTHROW_DEFAULT_CONSTRUCTIBLE_TYPE:
+      return eval_is_nothrow_default_constructible_type (h);
+    case METAFN_IS_NOTHROW_COPY_CONSTRUCTIBLE_TYPE:
+      return eval_is_nothrow_copy_constructible_type (h);
+    case METAFN_IS_NOTHROW_MOVE_CONSTRUCTIBLE_TYPE:
+      return eval_is_nothrow_move_constructible_type (h);
+    case METAFN_IS_NOTHROW_ASSIGNABLE_TYPE:
+      return eval_is_nothrow_assignable_type (loc, h, h1);
+    case METAFN_IS_NOTHROW_COPY_ASSIGNABLE_TYPE:
+      return eval_is_nothrow_copy_assignable_type (h);
+    case METAFN_IS_NOTHROW_MOVE_ASSIGNABLE_TYPE:
+      return eval_is_nothrow_move_assignable_type (h);
+    case METAFN_IS_NOTHROW_SWAPPABLE_WITH_TYPE:
+      return eval_is_swappable_with_type (loc, ctx, h, h1, call,
+                                         non_constant_p, jump_target, fun,
+                                         "is_nothrow_swappable_with");
+    case METAFN_IS_NOTHROW_SWAPPABLE_TYPE:
+      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);
+    case METAFN_IS_IMPLICIT_LIFETIME_TYPE:
+      return eval_is_implicit_lifetime_type (h);
+    case METAFN_HAS_VIRTUAL_DESTRUCTOR:
+      return eval_has_virtual_destructor (h);
+    case METAFN_HAS_UNIQUE_OBJECT_REPRESENTATIONS:
+      return eval_has_unique_object_representations (h);
+    case METAFN_REFERENCE_CONSTRUCTS_FROM_TEMPORARY:
+      return eval_reference_constructs_from_temporary (loc, h, h1);
+    case METAFN_REFERENCE_CONVERTS_FROM_TEMPORARY:
+      return eval_reference_converts_from_temporary (loc, h, h1);
+    case METAFN_RANK:
+      return eval_rank (h);
+    case METAFN_EXTENT:
+      return eval_extent (loc, h, expr);
+    case METAFN_IS_SAME_TYPE:
+      return eval_is_same_type (loc, h, h1);
+    case METAFN_IS_BASE_OF_TYPE:
+      return eval_is_base_of_type (loc, h, h1);
+    case METAFN_IS_VIRTUAL_BASE_OF_TYPE:
+      return eval_is_virtual_base_of_type (loc, h, h1);
+    case METAFN_IS_CONVERTIBLE_TYPE:
+      return eval_is_convertible_type (loc, h, h1);
+    case METAFN_IS_NOTHROW_CONVERTIBLE_TYPE:
+      return eval_is_nothrow_convertible_type (loc, h, h1);
+    case METAFN_IS_LAYOUT_COMPATIBLE_TYPE:
+      return eval_is_layout_compatible_type (loc, h, h1);
+    case METAFN_IS_POINTER_INTERCONVERTIBLE_BASE_OF_TYPE:
+      return eval_is_pointer_interconvertible_base_of_type (loc, h, h1);
+    case METAFN_IS_INVOCABLE_TYPE:
+      return eval_is_invocable_type (loc, h, hvec);
+    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);
+    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,
+                                      "is_nothrow_invocable_r");
+    case METAFN_REMOVE_CONST:
+      return eval_remove_const (loc, h);
+    case METAFN_REMOVE_VOLATILE:
+      return eval_remove_volatile (loc, h);
+    case METAFN_REMOVE_CV:
+      return eval_remove_cv (loc, h);
+    case METAFN_ADD_CONST:
+      return eval_add_const (loc, h);
+    case METAFN_ADD_VOLATILE:
+      return eval_add_volatile (loc, h);
+    case METAFN_ADD_CV:
+      return eval_add_cv (loc, h);
+    case METAFN_REMOVE_REFERENCE:
+      return eval_remove_reference (loc, h);
+    case METAFN_ADD_LVALUE_REFERENCE:
+      return eval_add_lvalue_reference (loc, h);
+    case METAFN_ADD_RVALUE_REFERENCE:
+      return eval_add_rvalue_reference (loc, h);
+    case METAFN_MAKE_SIGNED:
+      return eval_make_signed (loc, ctx, h, false, non_constant_p, jump_target,
+                              fun);
+    case METAFN_MAKE_UNSIGNED:
+      return eval_make_signed (loc, ctx, h, true, non_constant_p, jump_target,
+                              fun);
+    case METAFN_REMOVE_EXTENT:
+      return eval_remove_extent (loc, h);
+    case METAFN_REMOVE_ALL_EXTENTS:
+      return eval_remove_all_extents (loc, h);
+    case METAFN_REMOVE_POINTER:
+      return eval_remove_pointer (loc, h);
+    case METAFN_ADD_POINTER:
+      return eval_add_pointer (loc, h);
+    case METAFN_REMOVE_CVREF:
+      return eval_remove_cvref (loc, h);
+    case METAFN_DECAY:
+      return eval_decay (loc, h);
+    case METAFN_COMMON_TYPE:
+      return eval_common_type (loc, ctx, hvec, call, non_constant_p,
+                              jump_target, fun, ident);
+    case METAFN_COMMON_REFERENCE:
+      return eval_common_type (loc, ctx, hvec, call, non_constant_p,
+                              jump_target, fun, ident);
+    case METAFN_UNDERLYING_TYPE:
+      return eval_underlying_type (loc, ctx, h, non_constant_p, jump_target,
+                                  fun);
+    case METAFN_INVOKE_RESULT:
+      return eval_invoke_result (loc, ctx, h, hvec, call, non_constant_p,
+                                jump_target, fun);
+    case METAFN_UNWRAP_REFERENCE:
+      return eval_unwrap_reference (loc, ctx, h, call, non_constant_p,
+                                   jump_target, fun, ident);
+    case METAFN_UNWRAP_REF_DECAY:
+      return eval_unwrap_reference (loc, ctx, h, call, non_constant_p,
+                                   jump_target, fun, ident);
+    case METAFN_TUPLE_SIZE:
+      return eval_tuple_size (loc, ctx, h, call, non_constant_p, jump_target,
+                             fun);
+    case METAFN_TUPLE_ELEMENT:
+      return eval_tuple_element (loc, ctx, expr, h1, call,
+                                non_constant_p, jump_target, fun);
+    case METAFN_VARIANT_SIZE:
+      return eval_variant_size (loc, ctx, h, call, non_constant_p,
+                               jump_target, fun);
+    case METAFN_VARIANT_ALTERNATIVE:
+      return eval_variant_alternative (loc, ctx, expr, h1, call,
+                                      non_constant_p, jump_target, fun);
+    case METAFN_TYPE_ORDER:
+      return eval_type_order (h, h1);
+    case METAFN_ANNOTATIONS_OF:
+      return eval_annotations_of (loc, ctx, h, kind, NULL_TREE, non_constant_p,
+                                 jump_target, fun);
+    case METAFN_ANNOTATIONS_OF_WITH_TYPE:
+      return eval_annotations_of (loc, ctx, h, kind, h1, non_constant_p,
+                                 jump_target, fun);
+    /* Special metafunctions.  */
+    case METAFN_ACCESS_CONTEXT_CURRENT:
+      if (DECL_CLASS_SCOPE_P (fun)
+         && TYPE_NAME (DECL_CONTEXT (fun))
+         && TREE_CODE (TYPE_NAME (DECL_CONTEXT (fun))) == TYPE_DECL
+         && DECL_NAME (TYPE_NAME (DECL_CONTEXT (fun)))
+         && id_equal (DECL_NAME (TYPE_NAME (DECL_CONTEXT (fun))),
+                      "access_context"))
+       return eval_access_context_current (loc, ctx, call, non_constant_p);
+      goto not_found;
+    case METAFN_EXCEPTION__S_EXCEPTION_CVT_TO_UTF8:
+    case METAFN_EXCEPTION__S_EXCEPTION_CVT_FROM_UTF8:
+      if (DECL_CLASS_SCOPE_P (fun)
+         && TYPE_NAME (DECL_CONTEXT (fun))
+         && TREE_CODE (TYPE_NAME (DECL_CONTEXT (fun))) == TYPE_DECL
+         && DECL_NAME (TYPE_NAME (DECL_CONTEXT (fun)))
+         && id_equal (DECL_NAME (TYPE_NAME (DECL_CONTEXT (fun))),
+                      "exception"))
+       {
+         bool to_utf8
+           = minfo->code == METAFN_EXCEPTION__S_EXCEPTION_CVT_TO_UTF8;
+         return eval_exception__S_exception_cvt_tofrom_utf8 (loc, ctx, call,
+                                                             non_constant_p,
+                                                             overflow_p,
+                                                             jump_target,
+                                                             fun, to_utf8);
+       }
+      goto not_found;
+    }
+  goto not_found;
+}
+
+/* Splice reflection REFL; i.e., return its entity.  */
+
+tree
+splice (tree refl)
+{
+  if (refl == error_mark_node)
+    return error_mark_node;
+
+  /* Who in the world am I?  That's the great puzzle and we have to wait
+     until instantiation to find out.  */
+  if (instantiation_dependent_expression_p (refl))
+    return build_nt (SPLICE_EXPR, refl);
+
+  /* [basic.splice] "The constant-expression of a splice-specifier shall
+     be a converted constant expression of type std::meta::info."  */
+  refl = build_converted_constant_expr (meta_info_type_node, refl,
+                                       tf_warning_or_error);
+
+  if (processing_template_decl)
+    refl = fold_non_dependent_expr (refl, tf_warning_or_error, true);
+  else
+    refl = cxx_constant_value (refl);
+  if (!REFLECT_EXPR_P (refl))
+    /* I don't wanna do your dirty work no more.  */
+    return error_mark_node;
+
+  /* We are bringing some entity from the unevaluated expressions world
+     to possibly outside of that, mark it used.  */
+  if (!mark_used (REFLECT_EXPR_HANDLE (refl)))
+    return error_mark_node;
+
+  refl = REFLECT_EXPR_HANDLE (refl);
+  /* Function templates are wrapped in OVERLOAD from name lookup
+     and a lot of places assume that.  Furthermore, if reflection comes
+     from ^^fntmpl, it is wrapped with OVERLOAD already, only when
+     it comes from e.g. members_of it is not.  */
+  if (DECL_FUNCTION_TEMPLATE_P (refl))
+    refl = ovl_make (refl, NULL_TREE);
+
+  return refl;
+}
+
+/* A walker for consteval_only_p.  It cannot be a lambda, because we
+   have to call this recursively, sigh.  */
+
+static tree
+consteval_only_type_r (tree *tp, int *walk_subtrees, void *data)
+{
+  tree t = *tp;
+  /* Types can contain themselves recursively, hence this.  */
+  auto visited = static_cast<hash_set<tree> *>(data);
+
+  if (!TYPE_P (t))
+    return NULL_TREE;
+
+  if (REFLECTION_TYPE_P (t))
+    return t;
+
+  if (typedef_variant_p (t))
+    /* Tell cp_walk_subtrees to look through typedefs.  */
+    *walk_subtrees = 2;
+
+  if (RECORD_OR_UNION_TYPE_P (t))
+    {
+      /* Don't walk template arguments; A<info>::type isn't a consteval-only
+        type.  */
+      *walk_subtrees = 0;
+      /* So we have to walk the fields manually.  */
+      for (tree member = TYPE_FIELDS (t);
+          member; member = DECL_CHAIN (member))
+       if (TREE_CODE (member) == FIELD_DECL)
+         if (tree r = cp_walk_tree (&TREE_TYPE (member),
+                                    consteval_only_type_r, visited, visited))
+           return r;
+    }
+
+  return NULL_TREE;
+}
+
+/* True if T is a consteval-only type as per [basic.types.general]:
+   "A type is consteval-only if it is either std::meta::info or a type
+   compounded from a consteval-only type", or something that has
+   a consteval-only type.  */
+
+bool
+consteval_only_p (tree t)
+{
+  if (!flag_reflection)
+    return false;
+
+  if (!TYPE_P (t))
+    t = TREE_TYPE (t);
+
+  if (!t)
+    return false;
+
+  /* We need the complete type otherwise we'd have no fields for class
+     templates and thus come up with zilch for things like
+       template<typename T>
+       struct X : T { };
+     which could be consteval-only, depending on T.  */
+  t = complete_type (t);
+
+  /* Classes with std::meta::info members are also consteval-only.  */
+  hash_set<tree> visited;
+  return !!cp_walk_tree (&t, consteval_only_type_r, &visited, &visited);
+}
+
+/* Detect if a consteval-only expression EXPR or a consteval-only
+   variable EXPR not declared constexpr/constinit is used outside
+   a manifestly constant-evaluated context.  E.g.:
+
+     void f() {
+       constexpr auto r = ^^int;  // OK
+       [: r :] i = 42;  // still OK
+       auto z = r;  // bad
+     }
+
+   But
+
+     consteval void g() {
+       constexpr auto r = ^^int;
+       auto z = r;
+     }
+
+   is OK.  If COMPLAIN, emit an error; otherwise we're in the search-only
+   mode.  Return true if we found a problematic expression.  */
+
+bool
+check_out_of_consteval_use (tree expr, bool complain/*=true*/)
+{
+  if (!flag_reflection || in_immediate_context ())
+    return false;
+
+  auto walker = [](tree *tp, int *walk_subtrees, void *) -> tree
+    {
+      tree t = *tp;
+
+      /* No need to look into types or unevaluated operands.  */
+      if (TYPE_P (t)
+         || unevaluated_p (TREE_CODE (t))
+         /* Don't walk INIT_EXPRs, because we'd emit bogus errors about
+            member initializers.  */
+         || TREE_CODE (t) == INIT_EXPR
+         /* Don't walk BIND_EXPR_VARS.  */
+         || TREE_CODE (t) == BIND_EXPR
+         /* And don't recurse on DECL_EXPRs.  */
+         || TREE_CODE (t) == DECL_EXPR)
+       {
+         *walk_subtrees = false;
+         return NULL_TREE;
+       }
+
+      /* A subexpression of a manifestly constant-evaluated expression is
+        an immediate function context.  For example,
+
+          consteval void foo (std::meta::info) { }
+          void g() { foo (^^void); }
+
+        is all good.  */
+      if (tree decl = cp_get_callee_fndecl_nofold (t))
+       if (immediate_invocation_p (decl))
+         {
+           *walk_subtrees = false;
+           return NULL_TREE;
+         }
+
+      if (VAR_P (t)
+         && (DECL_DECLARED_CONSTEXPR_P (t) || DECL_DECLARED_CONSTINIT_P (t)))
+       /* This is fine, don't bother checking the type.  */
+       return NULL_TREE;
+
+      /* Now check the type to see if we are dealing with a consteval-only
+        expression.  */
+      if (!consteval_only_p (t))
+       return NULL_TREE;
+
+      if (current_function_decl
+         /* Already escalated.  */
+         && (DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+             /* These functions are magic.  */
+             || is_std_allocator_allocate (current_function_decl)))
+       {
+         *walk_subtrees = false;
+         return NULL_TREE;
+       }
+
+      /* We might have to escalate if we are in an immediate-escalating
+        function.  */
+      if (immediate_escalating_function_p (current_function_decl))
+       {
+         promote_function_to_consteval (current_function_decl);
+         *walk_subtrees = false;
+         return NULL_TREE;
+       }
+
+      *walk_subtrees = false;
+      return t;
+    };
+
+  if (tree t = cp_walk_tree_without_duplicates (&expr, walker, nullptr))
+    {
+      if (complain)
+       {
+         if (VAR_P (t))
+           {
+             auto_diagnostic_group d;
+             error_at (cp_expr_loc_or_input_loc (t),
+                       "consteval-only variable %qD not declared %<constexpr%> "
+                       "used outside a constant-evaluated context", t);
+             if (TREE_STATIC (t) || CP_DECL_THREAD_LOCAL_P (t))
+               inform (DECL_SOURCE_LOCATION (t), "add %<constexpr%> or "
+                       "%<constinit%>");
+             else
+               inform (DECL_SOURCE_LOCATION (t), "add %<constexpr%>");
+           }
+         else
+           error_at (cp_expr_loc_or_input_loc (t),
+                     "consteval-only expressions are only allowed in "
+                     "a constant-evaluated context");
+       }
+      return true;
+    }
+
+  return false;
+}
+
+/* Return true if the reflections LHS and RHS are equal.  */
+
+bool
+compare_reflections (tree lhs, tree rhs)
+{
+  reflect_kind lkind;
+  do
+    {
+      lkind = REFLECT_EXPR_KIND (lhs);
+      if (lkind != REFLECT_EXPR_KIND (rhs))
+       return false;
+      lhs = REFLECT_EXPR_HANDLE (lhs);
+      rhs = REFLECT_EXPR_HANDLE (rhs);
+    }
+  while (REFLECT_EXPR_P (lhs) && REFLECT_EXPR_P (rhs));
+
+  lhs = resolve_nondeduced_context (lhs, tf_warning_or_error);
+  rhs = resolve_nondeduced_context (rhs, tf_warning_or_error);
+
+  /* TEMPLATE_DECLs are wrapped in an OVERLOAD.  When we have
+
+       template_of (^^fun_tmpl<int>) == ^^fun_tmpl
+
+     the RHS will be OVERLOAD<TEMPLATE_DECL> but the LHS will
+     only be TEMPLATE_DECL.  They should compare equal, though.  */
+  // ??? Can we do something better?
+  lhs = maybe_get_reflection_fndecl (lhs);
+  rhs = maybe_get_reflection_fndecl (rhs);
+  if (lkind == REFLECT_PARM)
+    {
+      lhs = maybe_update_function_parm (lhs);
+      rhs = maybe_update_function_parm (rhs);
+    }
+  else if (lkind == REFLECT_DATA_MEMBER_SPEC)
+    return (TREE_VEC_ELT (lhs, 0) == TREE_VEC_ELT (rhs, 0)
+           && TREE_VEC_ELT (lhs, 1) == TREE_VEC_ELT (rhs, 1)
+           && tree_int_cst_equal (TREE_VEC_ELT (lhs, 2),
+                                  TREE_VEC_ELT (rhs, 2))
+           && tree_int_cst_equal (TREE_VEC_ELT (lhs, 3),
+                                  TREE_VEC_ELT (rhs, 3))
+           && TREE_VEC_ELT (lhs, 4) == TREE_VEC_ELT (rhs, 4));
+
+  if (lhs == rhs)
+    return true;
+
+  /* Some trees are not shared.  */
+  if (TREE_CODE (lhs) == TREE_CODE (rhs))
+    switch (TREE_CODE (lhs))
+      {
+      case ARRAY_REF:
+      case COMPONENT_REF:
+      case REAL_CST:
+       return cp_tree_equal (lhs, rhs);
+      default:
+       break;
+      }
+
+  if (TYPE_P (lhs) && TYPE_P (rhs))
+    if (!typedef_variant_p (lhs) && !typedef_variant_p (rhs))
+      return same_type_p (lhs, rhs);
+
+  return false;
+}
+
+/* Return true if T is a valid splice-type-specifier.
+   [dcl.type.splice]: For a splice-type-specifier of the form
+   "typename[opt] splice-specifier", the splice-specifier shall designate
+   a type, a class template, or an alias template.
+   For a splice-type-specifier of the form
+   "typename[opt] splice-specialization-specifier", the splice-specifier
+   of the splice-specialization-specifier shall designate a template T
+   that is either a class template or an alias template.  */
+
+bool
+valid_splice_type_p (const_tree t)
+{
+  return TYPE_P (t);
+}
+
+/* Return true if T is a valid splice-scope-specifier.
+   [basic.lookup.qual.general]: If a splice-scope-specifier is followed
+   by a ::, it shall either be a dependent splice-scope-specifier or it
+   shall designate a namespace, class, enumeration, or dependent type.  */
+
+bool
+valid_splice_scope_p (const_tree t)
+{
+  return (CLASS_TYPE_P (t)
+         || TREE_CODE (t) == ENUMERAL_TYPE
+         || TREE_CODE (t) == NAMESPACE_DECL);
+}
+
+/* Check a function DECL for CWG 3115: Every function of consteval-only
+   type shall be an immediate function.  */
+
+void
+check_consteval_only_fn (tree decl)
+{
+  if (!DECL_IMMEDIATE_FUNCTION_P (decl)
+      && consteval_only_p (decl)
+      /* But if the function can be escalated, merrily we roll along.  */
+      && !immediate_escalating_function_p (decl)
+      && !is_std_allocator_allocate (decl))
+    error_at (DECL_SOURCE_LOCATION (decl),
+             "function of consteval-only type must be declared %qs",
+             "consteval");
+}
+
+/* Check if T is a valid result of splice-expression.  ADDRESS_P is true if
+   we are taking the address of the splice.  MEMBER_ACCESS_P is true if this
+   splice is used in foo.[: bar :] or foo->[: bar :] context.  COMPLAIN_P is
+   true if any errors should be emitted.  Returns true is no problems are
+   found, false otherwise.  */
+
+bool
+check_splice_expr (location_t loc, location_t start_loc, tree t,
+                  bool address_p, bool member_access_p, bool complain_p)
+{
+  /* We may not have gotten an expression.  */
+  if (TREE_CODE (t) == TYPE_DECL
+      || TREE_CODE (t) == NAMESPACE_DECL
+      || TYPE_P (t))
+    {
+      if (complain_p)
+       {
+         if (TYPE_P (t))
+           {
+             auto_diagnostic_group d;
+             error_at (loc, "expected a reflection of an expression instead "
+                       "of type %qT", t);
+             if (start_loc != UNKNOWN_LOCATION)
+               {
+                 rich_location richloc (line_table, start_loc);
+                 richloc.add_fixit_insert_before (start_loc, "typename");
+                 inform (&richloc, "add %<typename%> to denote a type "
+                         "outside a type-only context");
+               }
+             else
+               inform (loc, "add %<typename%> to denote a type outside "
+                       "a type-only context");
+           }
+         else
+           error_at (loc, "expected a reflection of an expression instead "
+                     "of %qD", t);
+       }
+      return false;
+    }
+  /* [expr.prim.splice]/2 For a splice-expression of the form
+     splice-specifier, the expression is ill-formed if it is:  */
+  /* -- a constructor or a destructor  */
+  if (TREE_CODE (t) == FUNCTION_DECL
+      && (DECL_CONSTRUCTOR_P (t) || DECL_DESTRUCTOR_P (t)))
+    {
+      if (complain_p)
+       error_at (loc, "cannot use constructor or destructor %qD in a splice "
+                 "expression", t);
+      return false;
+    }
+  /* -- an unnamed bit-field  */
+  if (TREE_CODE (t) == FIELD_DECL && DECL_UNNAMED_BIT_FIELD (t))
+    {
+      if (complain_p)
+       error_at (loc, "cannot use an unnamed bit-field %qD in a splice "
+                 "expression", t);
+      return false;
+    }
+  /* Class members may not be implicitly referenced through a splice.
+     But taking the address is fine, and so is class member access a la
+     foo.[: ^^S::bar :].  */
+  if (!address_p
+      && !member_access_p
+      && DECL_P (t)
+      && DECL_NONSTATIC_MEMBER_P (t))
+    {
+      if (complain_p)
+       error_at (loc, "cannot implicitly reference a class member %qD "
+                 "through a splice", t);
+      return false;
+    }
+  /* [expr.unary.op]/3.1 "If the operand [of unary &] is a qualified-id or
+     splice-expression designating a non-static member m, other than an
+     explicit object member function, m shall be a direct member of some
+     class C that is not an anonymous union."  */
+  if (address_p
+      && TREE_CODE (t) == FIELD_DECL
+      && ANON_UNION_TYPE_P (DECL_CONTEXT (t)))
+    {
+      tree c = CP_TYPE_CONTEXT (DECL_CONTEXT (t));
+      while (ANON_UNION_TYPE_P (c))
+       c = CP_TYPE_CONTEXT (c);
+      if (!TYPE_P (c))
+       {
+         if (complain_p)
+           error_at (loc, "unary %<&%> applied to an anonymous union member "
+                     "%qD that is not a direct member of a named class", t);
+         return false;
+       }
+    }
+
+  /* [expr.prim.splice]/2: "The expression is ill-formed if S [the construct
+     designated by splice-specifier] is
+     -- a local entity such that there is a lambda scope that intervenes
+     between the expression and the point at which S was introduced"
+     This also checks ODR violations (reflect/odr1.C).  */
+  if (outer_automatic_var_p (t)
+      && process_outer_var_ref (t, tf_none) == error_mark_node)
+    {
+      /* Not letting process_outer_var_ref emit the error so that we can
+        say "in a splice expression".  */
+      if (complain_p)
+       {
+         auto_diagnostic_group d;
+         error_at (loc, "use of local variable with automatic storage from "
+                   "containing function in a splice expression");
+         inform (DECL_SOURCE_LOCATION (t), "%q#D declared here", t);
+       }
+      return false;
+    }
+
+  /* If we had a reflect_kind here, we could just check for
+     REFLECT_ANNOTATION and be done with it.  But we don't have it yet (TODO),
+     so do it the suboptimal way.  */
+  if (TREE_CODE (t) == TREE_LIST && annotation_p (t))
+    {
+      if (complain_p)
+       error_at (loc, "cannot use an annotation %qE in a splice expression",
+                 t);
+      return false;
+    }
+
+  /* Same, but with REFLECT_DATA_MEMBER_SPEC.  */
+  if (TREE_CODE (t) == TREE_VEC)
+    {
+      if (complain_p)
+       error_at (loc, "cannot use a data member specification in a "
+                 "splice expression");
+      return false;
+    }
+
+  return true;
+}
+
+/* Create a new SPLICE_SCOPE tree.  EXPR is its SPLICE_SCOPE_EXPR, and
+   TYPE_P says if it should have SPLICE_SCOPE_TYPE_P set.  */
+
+tree
+make_splice_scope (tree expr, bool type_p)
+{
+  tree t = cxx_make_type (SPLICE_SCOPE);
+  SPLICE_SCOPE_EXPR (t) = expr;
+  SPLICE_SCOPE_TYPE_P (t) = type_p;
+  return t;
+}
+
+/* Return true if T is a splice expression; that is, it is either [:T:] or
+   [:T:]<arg>.  */
+
+bool
+dependent_splice_p (const_tree t)
+{
+  return (TREE_CODE (t) == SPLICE_EXPR
+         || (TREE_CODE (t) == TEMPLATE_ID_EXPR
+             && TREE_CODE (TREE_OPERAND (t, 0)) == SPLICE_EXPR));
+}
+
+/* Annotation index for mangling.  */
+
+static GTY(()) int annotation_idx;
+
+/* Helper function for mangle.cc (write_reflection).
+   Determine 2 letter mangling prefix and store it into prefix.
+   Additionally return the reflection handle possibly adjusted so that
+   write_reflection can mangle the operands of it if any are needed.  */
+
+tree
+reflection_mangle_prefix (tree refl, char prefix[3])
+{
+  tree h = REFLECT_EXPR_HANDLE (refl);
+  reflect_kind kind = REFLECT_EXPR_KIND (refl);
+  if (h == unknown_type_node)
+    {
+      strcpy (prefix, "nu");
+      return NULL_TREE;
+    }
+  if (eval_is_value (kind) == boolean_true_node)
+    {
+      strcpy (prefix, "vl");
+      if (VAR_P (h) && DECL_NTTP_OBJECT_P (h))
+       h = tparm_object_argument (h);
+      return h;
+    }
+  if (eval_is_object (kind) == boolean_true_node)
+    {
+      strcpy (prefix, "ob");
+      return h;
+    }
+  if (eval_is_variable (h, kind) == boolean_true_node)
+    {
+      strcpy (prefix, "vr");
+      return h;
+    }
+  if (eval_is_structured_binding (h, kind) == boolean_true_node)
+    {
+      strcpy (prefix, "sb");
+      return h;
+    }
+  if (eval_is_function (h) == boolean_true_node)
+    {
+      strcpy (prefix, "fn");
+      return maybe_get_reflection_fndecl (h);
+    }
+  if (eval_is_function_parameter (h, kind) == boolean_true_node)
+    {
+      strcpy (prefix, "pa");
+      return maybe_update_function_parm (h);
+    }
+  if (eval_is_enumerator (h) == boolean_true_node)
+    {
+      strcpy (prefix, "en");
+      return h;
+    }
+  if (eval_is_annotation (h, kind) == boolean_true_node)
+    {
+      strcpy (prefix, "an");
+      if (TREE_PURPOSE (TREE_VALUE (h)) == NULL_TREE)
+       TREE_PURPOSE (TREE_VALUE (h))
+         = build_int_cst (integer_type_node, annotation_idx++);
+      return TREE_PURPOSE (TREE_VALUE (h));
+    }
+  if (eval_is_type_alias (h) == boolean_true_node)
+    {
+      strcpy (prefix, "ta");
+      return h;
+    }
+  if (eval_is_type (h) == boolean_true_node)
+    {
+      strcpy (prefix, "ty");
+      return h;
+    }
+  if (eval_is_nonstatic_data_member (h) == boolean_true_node)
+    {
+      strcpy (prefix, "dm");
+      return h;
+    }
+  if (TREE_CODE (h) == FIELD_DECL && DECL_UNNAMED_BIT_FIELD (h))
+    {
+      strcpy (prefix, "un");
+      return h;
+    }
+  if (eval_is_class_template (h) == boolean_true_node)
+    {
+      strcpy (prefix, "ct");
+      return h;
+    }
+  if (eval_is_function_template (h) == boolean_true_node)
+    {
+      strcpy (prefix, "ft");
+      h = maybe_get_reflection_fndecl (h);
+      return h;
+    }
+  if (eval_is_variable_template (h) == boolean_true_node)
+    {
+      strcpy (prefix, "vt");
+      return h;
+    }
+  if (eval_is_alias_template (h) == boolean_true_node)
+    {
+      strcpy (prefix, "at");
+      return h;
+    }
+  if (eval_is_concept (h) == boolean_true_node)
+    {
+      strcpy (prefix, "co");
+      return h;
+    }
+  if (eval_is_namespace_alias (h) == boolean_true_node)
+    {
+      strcpy (prefix, "na");
+      return h;
+    }
+  if (eval_is_namespace (h) == boolean_true_node)
+    {
+      if (h == global_namespace)
+       {
+         strcpy (prefix, "ng");
+         return NULL_TREE;
+       }
+      strcpy (prefix, "ns");
+      return h;
+    }
+  if (eval_is_base (h, kind) == boolean_true_node)
+    {
+      strcpy (prefix, "ba");
+      return h;
+    }
+  if (eval_is_data_member_spec (h, kind) == boolean_true_node)
+    {
+      strcpy (prefix, "ds");
+      return h;
+    }
+  gcc_unreachable ();
+}
+
+#include "gt-cp-reflect.h"
index db7c2d7702a572bd87e24d6a9b896fb06a83147d..3c174a91daa2f063e474df0b1d271cf1768d4cfd 100644 (file)
@@ -2123,11 +2123,15 @@ check_final_overrider (tree overrider, tree basefn)
       return 0;
     }
 
-  /* A consteval virtual function shall not override a virtual function that is
-     not consteval. A consteval virtual function shall not be overridden by a
-     virtual function that is not consteval.  */
-  if (DECL_IMMEDIATE_FUNCTION_P (overrider)
-      != DECL_IMMEDIATE_FUNCTION_P (basefn))
+  /* A class with a consteval virtual function that overrides a virtual
+     function that is not consteval shall have consteval-only type (CWG 3117).
+     A consteval virtual function shall not be overridden by a virtual
+     function that is not consteval.  */
+  if ((DECL_IMMEDIATE_FUNCTION_P (basefn)
+       && !DECL_IMMEDIATE_FUNCTION_P (overrider))
+      || (!DECL_IMMEDIATE_FUNCTION_P (basefn)
+         && DECL_IMMEDIATE_FUNCTION_P (overrider)
+         && !consteval_only_p (overrider)))
     {
       auto_diagnostic_group d;
       if (DECL_IMMEDIATE_FUNCTION_P (overrider))
index 78d717cade3bcca3f83021f78265291ddeace846..af0870ca57d43539c1cfb6d3caaf8b64b100932d 100644 (file)
@@ -4456,15 +4456,18 @@ finish_template_type (tree name, tree args, int entering_scope)
     return TYPE_NAME (type);
 }
 
-/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
-   Return a TREE_LIST containing the ACCESS_SPECIFIER and the
-   BASE_CLASS, or NULL_TREE if an error occurred.  The
+/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER
+   and ANNOTATIONS.
+   Return a TREE_LIST containing the ACCESS_SPECIFIER (or if there are
+   ANNOTATIONS, TREE_LIST containing the ACCESS_SPECIFIER and ANNOTATIONS)
+   and the BASE_CLASS, or NULL_TREE if an error occurred.  The
    ACCESS_SPECIFIER is one of
-   access_{default,public,protected_private}_node.  For a virtual base
+   access_{default,public,protected,private}_node.  For a virtual base
    we set TREE_TYPE.  */
 
 tree
-finish_base_specifier (tree base, tree access, bool virtual_p)
+finish_base_specifier (tree base, tree access, bool virtual_p,
+                      tree annotations)
 {
   tree result;
 
@@ -4486,6 +4489,8 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
             class type?  */
          base = TYPE_MAIN_VARIANT (base);
        }
+      if (annotations)
+       access = build_tree_list (access, nreverse (annotations));
       result = build_tree_list (access, base);
       if (virtual_p)
        TREE_TYPE (result) = integer_type_node;
@@ -4524,7 +4529,7 @@ baselink_for_fns (tree fns)
 
 /* Returns true iff we are currently parsing a lambda-declarator.  */
 
-static bool
+bool
 parsing_lambda_declarator ()
 {
   cp_binding_level *b = current_binding_level;
@@ -4774,6 +4779,7 @@ finish_id_expression_1 (tree id_expression,
        {
          /* Name lookup failed.  */
          if (scope
+             && !dependent_namespace_p (scope)
              && (!TYPE_P (scope)
                  || (!dependentish_scope_p (scope)
                      && !(identifier_p (id_expression)
@@ -13654,6 +13660,57 @@ fold_builtin_is_corresponding_member (location_t loc, int nargs,
                                   fold_convert (TREE_TYPE (arg1), arg2)));
 }
 
+/* Fold __builtin_is_string_literal call.  */
+
+tree
+fold_builtin_is_string_literal (location_t loc, int nargs, tree *args)
+{
+  /* Unless users call the builtin directly, the following 3 checks should be
+     ensured from std::is_string_literal overloads.  */
+  if (nargs != 1)
+    {
+      error_at (loc, "%<__builtin_is_string_literal%> needs a single "
+               "argument");
+      return boolean_false_node;
+    }
+  tree arg = args[0];
+  if (error_operand_p (arg))
+    return boolean_false_node;
+  if (!TYPE_PTR_P (TREE_TYPE (arg))
+      || !TYPE_READONLY (TREE_TYPE (TREE_TYPE (arg)))
+      || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (arg))))
+    {
+    arg_invalid:
+      error_at (loc, "%<__builtin_is_string_literal%> "
+                    "argument is not %<const char*%>, %<const wchar_t*%>, "
+                    "%<const char8_t*%>, %<const char16_t*%> or "
+                    "%<const char32_t*%>");
+      return boolean_false_node;
+    }
+  tree chart = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg)));
+  if (chart != char_type_node
+      && chart != wchar_type_node
+      && chart != char8_type_node
+      && chart != char16_type_node
+      && chart != char32_type_node)
+    goto arg_invalid;
+
+  STRIP_NOPS (arg);
+  while (TREE_CODE (arg) == POINTER_PLUS_EXPR)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      STRIP_NOPS (arg);
+    }
+  if (TREE_CODE (arg) != ADDR_EXPR)
+    return boolean_false_node;
+  arg = TREE_OPERAND (arg, 0);
+  if (TREE_CODE (arg) == ARRAY_REF)
+    arg = TREE_OPERAND (arg, 0);
+  if (TREE_CODE (arg) != STRING_CST)
+    return boolean_false_node;
+  return boolean_true_node;
+}
+
 /* [basic.types] 8.  True iff TYPE is an object type.  */
 
 static bool
@@ -13913,6 +13970,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_DEDUCIBLE:
       return type_targs_deducible_from (type1, type2);
 
+    case CPTK_IS_CONSTEVAL_ONLY:
+      return consteval_only_p (type1);
+
     /* __array_rank, __builtin_type_order and __builtin_structured_binding_size
        are handled in finish_trait_expr.  */
     case CPTK_RANK:
@@ -14093,6 +14153,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_STD_LAYOUT:
     case CPTK_IS_TRIVIAL:
     case CPTK_IS_TRIVIALLY_COPYABLE:
+    case CPTK_IS_CONSTEVAL_ONLY:
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       if (!check_trait_type (type1, /* kind = */ 2))
        return error_mark_node;
index 7fa2f8a5846deecb5ef79afd1241917fc5400851..a57eefaf11f330ef43261d805ee792f50acd9b81 100644 (file)
@@ -48,6 +48,7 @@ static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
 static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
 static tree handle_contract_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_dangling_attribute (tree *, tree, tree, int, bool *);
+static tree handle_annotation_attribute (tree *, tree, tree, int, bool *);
 
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
    Otherwise, returns clk_none.  */
@@ -568,6 +569,7 @@ builtin_valid_in_constant_expr_p (const_tree decl)
          case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
          case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
          case CP_BUILT_IN_EH_PTR_ADJUST_REF:
+         case CP_BUILT_IN_IS_STRING_LITERAL:
            return true;
          default:
            break;
@@ -4508,6 +4510,12 @@ cp_tree_equal (tree t1, tree t2)
        return equivalent_member_references (t1, t2);
       break;
 
+    case REFLECT_EXPR:
+      if (!cp_tree_equal (REFLECT_EXPR_HANDLE (t1), REFLECT_EXPR_HANDLE (t2))
+         || REFLECT_EXPR_KIND (t1) != REFLECT_EXPR_KIND (t2))
+       return false;
+      return true;
+
     default:
       break;
     }
@@ -5603,7 +5611,9 @@ const scoped_attribute_specs std_attribute_table =
 static const attribute_spec internal_attributes[] =
 {
   { "aligned", 0, 1, false, false, false, false,
-    handle_alignas_attribute, attr_aligned_exclusions }
+    handle_alignas_attribute, attr_aligned_exclusions },
+  { "annotation ", 1, 1, false, false, false, false,
+    handle_annotation_attribute, NULL }
 };
 
 const scoped_attribute_specs internal_attribute_table =
@@ -5891,6 +5901,78 @@ handle_no_dangling_attribute (tree *node, tree name, tree args, int,
   return NULL_TREE;
 }
 
+/* Perform checking for annotations.  */
+
+tree
+handle_annotation_attribute (tree *node, tree ARG_UNUSED (name),
+                            tree args, int ARG_UNUSED (flags),
+                            bool *no_add_attrs)
+{
+  if (TYPE_P (*node)
+      && TREE_CODE (*node) != ENUMERAL_TYPE
+      && TREE_CODE (*node) != RECORD_TYPE
+      && TREE_CODE (*node) != UNION_TYPE)
+    {
+      error ("annotation on a type other than class or enumeration "
+            "definition");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (TREE_CODE (*node) == LABEL_DECL)
+    {
+      error ("annotation applied to a label");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (TREE_CODE (*node) == FIELD_DECL && DECL_UNNAMED_BIT_FIELD (*node))
+    {
+      error ("annotation on unnamed bit-field");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (!type_dependent_expression_p (TREE_VALUE (args)))
+    {
+      if (!structural_type_p (TREE_TYPE (TREE_VALUE (args))))
+       {
+         auto_diagnostic_group d;
+         error ("annotation does not have structural type");
+         structural_type_p (TREE_TYPE (TREE_VALUE (args)), true);
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+      if (CLASS_TYPE_P (TREE_TYPE (TREE_VALUE (args))))
+       {
+         tree arg = make_tree_vec (1);
+         tree type = TREE_TYPE (TREE_VALUE (args));
+         tree ctype
+           = cp_build_qualified_type (type, cp_type_quals (type)
+                                            | TYPE_QUAL_CONST);
+         TREE_VEC_ELT (arg, 0)
+           = cp_build_reference_type (ctype, /*rval=*/false);
+         if (!is_xible (INIT_EXPR, type, arg))
+           {
+             auto_diagnostic_group d;
+             error ("annotation does not have copy constructible type");
+             is_xible (INIT_EXPR, type, arg, /*explain=*/true);
+             *no_add_attrs = true;
+             return NULL_TREE;
+           }
+       }
+    }
+  if (!processing_template_decl)
+    {
+      location_t loc = EXPR_LOCATION (TREE_VALUE (args));
+      TREE_VALUE (args) = cxx_constant_value (TREE_VALUE (args));
+      if (error_operand_p (TREE_VALUE (args)))
+        *no_add_attrs = true;
+      auto suppression
+       = make_temp_override (suppress_location_wrappers, 0);
+      TREE_VALUE (args) = maybe_wrap_with_location (TREE_VALUE (args), loc);
+    }
+  ATTR_UNIQUE_VALUE_P (args) = 1;
+  return NULL_TREE;
+}
+
 /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
    thing pointed to by the constant.  */
 
@@ -6811,6 +6893,14 @@ maybe_adjust_arg_pos_for_attribute (const_tree fndecl)
   return n > 0 ? n - 1 : 0;
 }
 
+/* True if ATTR is annotation.  */
+
+bool
+annotation_p (tree attr)
+{
+  return is_attribute_p ("annotation ", get_attribute_name (attr));
+}
+
 \f
 /* Release memory we no longer need after parsing.  */
 void
index 3c7b334e0a6b52a15a72191860d0d22e22d35191..290359c938e8ed4cf944b7dfd37df6db33923f3d 100644 (file)
@@ -3466,16 +3466,18 @@ complain_about_unrecognized_member (tree access_path, tree name,
 
 /* This function is called by the parser to process a class member
    access expression of the form OBJECT.NAME.  NAME is a node used by
-   the parser to represent a name; it is not yet a DECL.  It may,
-   however, be a BASELINK where the BASELINK_FUNCTIONS is a
-   TEMPLATE_ID_EXPR.  Templates must be looked up by the parser, and
+   the parser to represent a name; it is not yet a DECL, except when
+   SPLICE_P.  It may, however, be a BASELINK where the BASELINK_FUNCTIONS
+   is a TEMPLATE_ID_EXPR.  Templates must be looked up by the parser, and
    there is no reason to do the lookup twice, so the parser keeps the
    BASELINK.  TEMPLATE_P is true iff NAME was explicitly declared to
-   be a template via the use of the "A::template B" syntax.  */
+   be a template via the use of the "A::template B" syntax.  SPLICE_P
+   is true if NAME was designated by a splice-expression.  */
 
 tree
 finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
-                                tsubst_flags_t complain)
+                                tsubst_flags_t complain,
+                                bool splice_p/*=false*/)
 {
   tree expr;
   tree object_type;
@@ -3511,11 +3513,18 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
             lookup until we instantiate the T.  */
          || (TREE_CODE (name) == IDENTIFIER_NODE
              && IDENTIFIER_CONV_OP_P (name)
-             && dependent_type_p (TREE_TYPE (name))))
+             && dependent_type_p (TREE_TYPE (name)))
+         /* This is OBJECT.[:R:], which is dependent.  */
+         || dependent_splice_p (name)
+         /* This is OBJECT.[:T::R:], which is dependent.  */
+         || (TREE_CODE (name) == SCOPE_REF
+             && dependent_splice_p (TREE_OPERAND (name, 1))))
        {
        dependent:
-         return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
+         expr = build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
                                   orig_object, orig_name, NULL_TREE);
+         COMPONENT_REF_SPLICE_P (expr) = splice_p;
+         return expr;
        }
     }
   else if (c_dialect_objc ()
@@ -3549,6 +3558,16 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
   if (BASELINK_P (name))
     /* A member function that has already been looked up.  */
     member = name;
+  else if (TREE_CODE (name) == TREE_BINFO)
+    {
+      /* Splicing a base class subobject.  We can only get here via
+        e1.[:e2:].  */
+      expr = build_base_path (PLUS_EXPR, object, name, /*nonnull=*/true,
+                             complain);
+      if (expr == error_mark_node && (complain & tf_error))
+       error_not_base_type (BINFO_TYPE (name), object_type);
+      return expr;
+    }
   else
     {
       bool is_template_id = false;
@@ -3575,6 +3594,13 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
              return error_mark_node;
            }
        }
+      else if (splice_p
+              && (TREE_CODE (name) == FIELD_DECL
+                  || VAR_P (name)
+                  || TREE_CODE (name) == CONST_DECL
+                  || TREE_CODE (name) == FUNCTION_DECL
+                  || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name))))
+       scope = DECL_CONTEXT (OVL_FIRST (name));
 
       if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
        {
@@ -3582,7 +3608,11 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
          template_args = TREE_OPERAND (name, 1);
          name = TREE_OPERAND (name, 0);
 
-         if (!identifier_p (name))
+         if (splice_p
+             && (DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name))
+                 || variable_template_p (name)))
+           scope = DECL_CONTEXT (OVL_FIRST (name));
+         else if (!identifier_p (name))
            name = OVL_NAME (name);
        }
 
@@ -3600,7 +3630,11 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
                           scope, name, object_type);
                  return error_mark_node;
                }
-             tree val = lookup_enumerator (scope, name);
+             tree val;
+             if (splice_p && TREE_CODE (name) == CONST_DECL)
+               val = name;
+             else
+               val = lookup_enumerator (scope, name);
              if (!val)
                {
                  if (complain & tf_error)
@@ -3615,7 +3649,16 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
            }
 
          gcc_assert (CLASS_TYPE_P (scope));
-         gcc_assert (identifier_p (name) || TREE_CODE (name) == BIT_NOT_EXPR);
+         gcc_assert (identifier_p (name)
+                     || TREE_CODE (name) == BIT_NOT_EXPR
+                     || (splice_p
+                         && (TREE_CODE (name) == FIELD_DECL
+                             || VAR_P (name)
+                             || TREE_CODE (name) == CONST_DECL
+                             || TREE_CODE (name) == FUNCTION_DECL
+                             || DECL_FUNCTION_TEMPLATE_P
+                                               (OVL_FIRST (name))
+                             || variable_template_p (name))));
 
          if (constructor_name_p (name, scope))
            {
@@ -3629,8 +3672,13 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
             one copy of the data member that is shared by all the objects of
             the class.  So NAME can be unambiguously referred to even if
             there are multiple indirect base classes containing NAME.  */
-         const base_access ba = [scope, name] ()
+         const base_access ba = [scope, name, splice_p] ()
            {
+             /* [class.access.base]/5: A member m is accessible at the
+                point R when designated in class N if
+                -- m is designated by a splice-expression  */
+             if (splice_p)
+               return ba_unique;
              if (identifier_p (name))
                {
                  tree m = lookup_member (scope, name, /*protect=*/0,
@@ -3662,6 +3710,25 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
            goto dependent;
          member = lookup_destructor (object, scope, name, complain);
        }
+      else if (splice_p && (TREE_CODE (name) == FIELD_DECL
+                           || VAR_P (name)
+                           || TREE_CODE (name) == CONST_DECL
+                           || TREE_CODE (name) == FUNCTION_DECL
+                           || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name))
+                           || variable_template_p (name)))
+       {
+         member = name;
+         name = OVL_FIRST (name);
+         if (any_dependent_type_attributes_p (DECL_ATTRIBUTES (name)))
+           /* Dependent type attributes on the decl mean that the TREE_TYPE is
+              wrong, so don't use it.  */
+           goto dependent;
+         if (is_overloaded_fn (name))
+           member
+             = build_baselink (access_path, TYPE_BINFO (object_type), member,
+                               IDENTIFIER_CONV_OP_P (DECL_NAME (name))
+                               ? TREE_TYPE (DECL_NAME (name)) : NULL_TREE);
+       }
       else
        {
          /* Look up the member.  */
@@ -3741,9 +3808,10 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
            BASELINK_QUALIFIED_P (member) = 1;
          orig_name = member;
        }
-      return build_min_non_dep (COMPONENT_REF, expr,
+      expr = build_min_non_dep (COMPONENT_REF, expr,
                                orig_object, orig_name,
                                NULL_TREE);
+      COMPONENT_REF_SPLICE_P (STRIP_REFERENCE_REF (expr)) = splice_p;
     }
 
   return expr;
@@ -6279,6 +6347,10 @@ cp_build_binary_op (const op_location_t &location,
          return cp_build_binary_op (location,
                                     EQ_EXPR, e, integer_zero_node, complain);
        }
+      /* [expr.eq]: "If both operands are of type std::meta::info,
+        comparison is defined as follows..."  */
+      else if (code0 == META_TYPE && code1 == META_TYPE)
+       result_type = type0;
       else
        {
          gcc_assert (!TYPE_PTRMEMFUNC_P (type0)
@@ -11714,6 +11786,12 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
        *dangling = true;
     }
 
+  if (check_out_of_consteval_use (retval))
+    {
+      current_function_return_value = error_mark_node;
+      return error_mark_node;
+    }
+
   /* A naive attempt to reduce the number of -Wdangling-reference false
      positives: if we know that this function can return a variable with
      static storage duration rather than one of its parameters, suppress
index 46d53705870182a84a5ba36d6e0147af6dcd96da..b703b531d7551b67a3d056e0ee1aae8979c0f9b7 100644 (file)
@@ -252,7 +252,7 @@ in the following sections.
 -fnew-ttp-matching
 -fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names
 -fno-optional-diags
--fno-pretty-templates  -frange-for-ext-temps
+-fno-pretty-templates  -frange-for-ext-temps  -freflection
 -fno-rtti  -fsized-deallocation
 -fstrict-enums  -fstrong-eval-order@r{[}=@var{kind}@r{]}
 -ftemplate-backtrace-limit=@var{n}
@@ -3682,6 +3682,10 @@ so lifetime of the temporaries is extended until the end of the loop
 by default.  This option allows enabling that behavior also
 in earlier versions of the standard.
 
+@opindex freflection
+@item -freflection
+Enable experimental C++26 Reflection.
+
 @opindex fno-rtti
 @opindex frtti
 @item -fno-rtti
index 286efa8a95d4f1417e0a5a46a18fadfb655d2b99..8c6bab4bdb5e41f78faaf48f8d664ff001819332 100644 (file)
@@ -13494,7 +13494,10 @@ is_base_type (tree type)
       return false;
 
     default:
-      if (is_cxx_auto (type))
+      if (is_cxx ()
+         && TREE_CODE (type) >= LAST_AND_UNUSED_TREE_CODE
+         && TYPE_P (type)
+         && TYPE_IDENTIFIER (type))
        return false;
       gcc_unreachable ();
     }
@@ -26959,6 +26962,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
 
     case NULLPTR_TYPE:
     case LANG_TYPE:
+    unspecified_type:
       /* Just use DW_TAG_unspecified_type.  */
       {
         dw_die_ref type_die = lookup_type_die (type);
@@ -26988,6 +26992,11 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
          equate_type_number_to_die (type, *die);
          break;
        }
+      if (is_cxx ()
+         && TREE_CODE (type) >= LAST_AND_UNUSED_TREE_CODE
+         && TYPE_P (type)
+         && TYPE_IDENTIFIER (type))
+       goto unspecified_type;
       gcc_unreachable ();
     }
 
index 855c0d8f117abededae6ed8dea684b01b6b0e04c..cb761b7378ecc8fabb8ab1f06cf02397d33ee386 100644 (file)
@@ -1,6 +1,6 @@
 // DR 2581 - Undefined behavior for predefined macros
 // { dg-do preprocess }
-// { dg-additional-options "-fcontracts" { target c++26 } }
+// { dg-additional-options "-fcontracts -freflection" { target c++26 } }
 // { dg-additional-options "-fmodules -fcoroutines" { target c++20 } }
 
 #undef defined                         // { dg-error "'defined' cannot be used as a macro name" }
@@ -63,7 +63,7 @@
 #undef __cpp_impl_coroutine            // { dg-warning "undefining '__cpp_impl_coroutine'" "" { target c++20 } }
 #undef __cpp_impl_destroying_delete    // { dg-warning "undefining '__cpp_impl_destroying_delete'" "" { target c++20 } }
 #undef __cpp_impl_three_way_comparison // { dg-warning "undefining '__cpp_impl_three_way_comparison'" "" { target c++20 } }
-#undef __cpp_impl_reflection
+#undef __cpp_impl_reflection           // { dg-warning "undefining '__cpp_impl_reflection'" "" { target c++26 } }
 #undef __cpp_implicit_move             // { dg-warning "undefining '__cpp_implicit_move'" "" { target c++23 } }
 #undef __cpp_inheriting_constructors   // { dg-warning "undefining '__cpp_inheriting_constructors'" "" { target c++20 } }
 #undef __cpp_init_captures             // { dg-warning "undefining '__cpp_init_captures'" "" { target c++20 } }
index f09c672608fecd42d42839d37970404e5a07e225..77bf93b27410591f51e02aaa346665a54d4e3882 100644 (file)
@@ -1,6 +1,6 @@
 // DR 2581 - Undefined behavior for predefined macros
 // { dg-do preprocess }
-// { dg-additional-options "-fcontracts" { target c++26 } }
+// { dg-additional-options "-fcontracts -freflection" { target c++26 } }
 // { dg-additional-options "-fmodules -fcoroutines" { target c++20 } }
 
 #define defined defined                                // { dg-error "'defined' cannot be used as a macro name" }
@@ -64,7 +64,7 @@
 #define __cpp_impl_coroutine 201902L           // { dg-error "'__cpp_impl_coroutine' redefined" "" { target c++20 } }
 #define __cpp_impl_destroying_delete 201806L   // { dg-error "'__cpp_impl_destroying_delete' redefined" "" { target c++20 } }
 #define __cpp_impl_three_way_comparison 201907L        // { dg-error "'__cpp_impl_three_way_comparison' redefined" "" { target c++20 } }
-#define __cpp_impl_reflection 202506L
+#define __cpp_impl_reflection 202506L          // { dg-error "'__cpp_impl_reflection' redefined" "" { target c++26 } }
 #define __cpp_implicit_move 202207L            // { dg-error "'__cpp_implicit_move' redefined" "" { target c++23 } }
 #define __cpp_inheriting_constructors 201511L  // { dg-error "'__cpp_inheriting_constructors' redefined" "" { target c++20 } }
 #define __cpp_init_captures 201803L            // { dg-error "'__cpp_init_captures' redefined" "" { target c++14 } }
diff --git a/gcc/testsuite/g++.dg/reflect/access_context1.C b/gcc/testsuite/g++.dg/reflect/access_context1.C
new file mode 100644 (file)
index 0000000..c0ec0d3
--- /dev/null
@@ -0,0 +1,175 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::access_context.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct S {};
+
+constexpr access_context a = access_context::unprivileged ();
+static_assert (a.scope () == ^^:: && a.designating_class () == null_reflection);
+constexpr access_context b = access_context::unchecked ();
+static_assert (b.scope () == null_reflection && b.designating_class () == null_reflection);
+constexpr access_context c = access_context::current ();
+static_assert (c.scope () == ^^:: && c.designating_class () == null_reflection);
+constexpr access_context d = access_context::unprivileged ().via (^^S);
+static_assert (d.scope () == ^^:: && d.designating_class () == ^^S);
+constexpr access_context e = access_context::unchecked ().via (^^const S);
+static_assert (e.scope () == null_reflection && e.designating_class () == ^^const S);
+constexpr access_context f = access_context::current ().via (^^volatile S);
+static_assert (f.scope () == ^^:: && f.designating_class () == ^^volatile S);
+
+consteval info
+foo (info x = access_context::current ().scope ())
+{
+  static_assert (access_context::current ().scope () == ^^foo);
+  return x;
+}
+
+static_assert (foo (^^std) == ^^std);
+static_assert (foo () == ^^::);
+
+namespace N
+{
+  struct S {};
+  constexpr access_context a = access_context::current ().via (^^::S).via (^^S);
+  static_assert (a.scope () == ^^N && a.designating_class () == ^^S);
+  static_assert (access_context::unprivileged ().scope () == ^^::);
+  static_assert (access_context::unchecked ().scope () == null_reflection);
+  namespace M
+  {
+    constexpr access_context a = access_context::current ().via (^^S).via (^^::S);
+    static_assert (a.scope () == ^^M && a.designating_class () == ^^::S);
+    static_assert (foo () == ^^M);
+    consteval {
+      static_assert (access_context::current ().scope () == ^^M);
+      consteval {
+        static_assert (access_context::current ().scope () == ^^M);
+      }
+    }
+  }
+}
+
+struct T
+{
+  static_assert (access_context::unprivileged ().scope () == ^^::);
+  static_assert (access_context::unchecked ().scope () == null_reflection);
+  static_assert (access_context::current ().scope () == ^^T);
+  static_assert (access_context::unprivileged ().designating_class () == null_reflection);
+  static_assert (access_context::unchecked ().designating_class () == null_reflection);
+  static_assert (access_context::current ().designating_class () == null_reflection);
+  static_assert (foo () == ^^T);
+  info t = access_context::current ().scope ();
+};
+
+struct U
+{
+  consteval U () {}
+  info u = access_context::current ().scope ();
+};
+
+struct V : U
+{
+  using U::U;
+  info v = access_context::current ().scope ();
+  consteval {
+    static_assert (access_context::current ().scope () == ^^V);
+    consteval {
+      static_assert (access_context::current ().scope () == ^^V);
+    }
+  }
+};
+
+void
+bar ()
+{
+  static constexpr access_context a = access_context::current ();
+  static_assert (a.scope () == ^^bar && a.designating_class () == null_reflection);
+  static_assert (foo (^^foo) == ^^foo);
+  static_assert (foo () == ^^bar);
+  static_assert (T {}.t == ^^bar);
+  consteval {
+    static_assert (access_context::current ().scope () == ^^bar);
+    consteval {
+      static_assert (access_context::current ().scope () == ^^bar);
+    }
+  }
+  auto l = [] () {
+    int v = 0;
+    static_assert (access_context::current ().scope () == parent_of (^^v));
+    static_assert (parent_of (parent_of (access_context::current ().scope ())) == ^^bar);
+  };
+  auto l2 = [] () -> int (&) [access_context::current ().scope () == ^^bar ? 2 : 3] {
+    static int a[2];
+    return a;
+  };
+}
+
+consteval {
+  static_assert (access_context::current ().scope () == ^^::);
+  consteval {
+    static_assert (access_context::current ().scope () == ^^::);
+  }
+  static_assert (access_context::current ().via (^^S).via (null_reflection).designating_class () == null_reflection);
+}
+
+consteval bool
+baz ()
+{
+  constexpr U u;
+  static_assert (is_constructor (u.u) && parent_of (u.u) == ^^U);
+  constexpr V v;
+  static_assert (is_constructor (v.u) && parent_of (v.u) == ^^U);
+  static_assert (is_constructor (v.v) && parent_of (v.v) == ^^V);
+  return true;
+}
+
+static_assert (baz ());
+
+consteval info
+qux ()
+{
+  return ^^qux;
+}
+
+constexpr info q = qux ();
+static_assert (q == ^^qux);
+
+namespace O
+{
+  int a[2];
+  auto
+  foo () -> int (&) [access_context::current ().scope () == ^^O ? 2 : 3]
+  {
+    return a;
+  }
+}
+
+consteval bool
+can_do_via (info r)
+{
+  try { access_context::current ().via (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+struct W;
+
+static_assert (can_do_via (^^S));
+static_assert (can_do_via (^^T));
+static_assert (can_do_via (^^U));
+static_assert (can_do_via (^^V));
+static_assert (can_do_via (^^N::S));
+static_assert (can_do_via (null_reflection));
+static_assert (!can_do_via (^^W));
+static_assert (!can_do_via (^^::));
+static_assert (!can_do_via (^^O));
+static_assert (!can_do_via (^^bar));
+static_assert (!can_do_via (^^int));
+enum E { E0, E1 };
+static_assert (!can_do_via (^^E));
+static_assert (!can_do_via (^^E0));
+static_assert (!can_do_via (reflect_constant (42)));
diff --git a/gcc/testsuite/g++.dg/reflect/access_context2.C b/gcc/testsuite/g++.dg/reflect/access_context2.C
new file mode 100644 (file)
index 0000000..ddcb5b8
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::access_context.
+
+#include <meta>
+
+using namespace std::meta;
+
+template <typename T>
+struct S
+{
+  static constexpr auto ctx = access_context::current ();
+};
+
+static_assert (S <int>::ctx.designating_class () == info {} && S <int>::ctx.scope () == ^^S <int>);
diff --git a/gcc/testsuite/g++.dg/reflect/access_context3.C b/gcc/testsuite/g++.dg/reflect/access_context3.C
new file mode 100644 (file)
index 0000000..9f4983e
--- /dev/null
@@ -0,0 +1,50 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::access_context.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct Ctor
+{
+  consteval Ctor()
+  { }
+
+  access_context ctx = access_context::current ();
+};
+
+constexpr Ctor ctor;
+static_assert (is_constructor (ctor.ctx.scope ()) && parent_of(ctor.ctx.scope()) == ^^Ctor);
+
+struct Dfltd
+{
+  Dfltd() = default;
+
+  access_context ctx = access_context::current ();
+};
+
+constexpr Dfltd dfltd;
+static_assert (is_constructor (dfltd.ctx.scope ()) && parent_of(dfltd.ctx.scope()) == ^^Dfltd);
+
+struct Aggr {
+  access_context ctx = access_context::current ();
+};
+
+constexpr Aggr aggrCtor;
+static_assert (is_constructor (aggrCtor.ctx.scope ()) && parent_of(aggrCtor.ctx.scope()) == ^^Aggr);
+
+constexpr Aggr aggrInit{};
+static_assert (aggrInit.ctx.scope () == ^^::);
+
+consteval Aggr
+func(Aggr aggr = {})
+{ return aggr; }
+
+static_assert (func().ctx.scope () == ^^::);
+
+constexpr void
+bar()
+{
+  static_assert (func().ctx.scope () == ^^bar);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/adl1.C b/gcc/testsuite/g++.dg/reflect/adl1.C
new file mode 100644 (file)
index 0000000..437fb14
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// ADL.  The namespace std::meta is an associated namespace of
+// std::meta::info, which allows standard library meta functions
+// to be invoked without explicit qualification.
+
+#include <meta>
+
+struct S {};
+
+bool b1 = std::meta::has_identifier (^^S);
+bool b2 = has_identifier (^^S);
+
+
+std::string_view name2 = std::meta::identifier_of(^^S);  // Okay.
+std::string_view name1 = identifier_of(^^S);             // Also okay.
diff --git a/gcc/testsuite/g++.dg/reflect/alignment_of1.C b/gcc/testsuite/g++.dg/reflect/alignment_of1.C
new file mode 100644 (file)
index 0000000..cee44c8
--- /dev/null
@@ -0,0 +1,165 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::alignment_of.
+
+#include <meta>
+#include <cstddef>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+extern int arr2[];
+extern int arr3[2];
+alignas (32) int arr4[] = {1, 2, 3};
+alignas (64) extern int arr5[2];
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+} s;
+struct S2 {
+  char p;
+  int mem;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+  static int ta;
+  alignas (128) static constexpr int tb = 42;
+};
+int T::ta;
+struct U {
+  int u;
+};
+static short v1;
+alignas (64) static long long v2;
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+int &ref = arr[0];
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_alignment_of (info r)
+{
+  try { alignment_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_alignment_of (std::meta::reflect_constant (42)));
+static_assert (has_alignment_of (std::meta::reflect_object (arr)));
+static_assert (has_alignment_of (std::meta::reflect_object (arr[1])));
+static_assert (has_alignment_of (std::meta::reflect_object (s.mem)));
+static_assert (has_alignment_of (^^arr));
+static_assert (!has_alignment_of (^^a3));
+static_assert (!has_alignment_of (^^fn));
+static_assert (!has_alignment_of (^^fn2));
+static_assert (!has_alignment_of (^^Enum::A));
+static_assert (has_alignment_of (^^Alias));
+static_assert (has_alignment_of (^^S));
+static_assert (has_alignment_of (^^S::mem));
+static_assert (!has_alignment_of (members_of (^^S, access_context::current ())[1]));
+static_assert (!has_alignment_of (^^TCls));
+static_assert (!has_alignment_of (^^TFn));
+static_assert (!has_alignment_of (^^TVar));
+static_assert (!has_alignment_of (^^Concept));
+static_assert (!has_alignment_of (^^NSAlias));
+static_assert (!has_alignment_of (^^NS));
+static_assert (has_alignment_of (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (has_alignment_of (std::meta::data_member_spec (^^int, { .name = "member" })));
+static_assert (!has_alignment_of (std::meta::data_member_spec (^^int, { .name = "member", .bit_width = 6 })));
+static_assert (!has_alignment_of (std::meta::data_member_spec (^^int, { .bit_width = 15 })));
+static_assert (has_alignment_of (^^arr2));
+static_assert (has_alignment_of (^^arr3));
+static_assert (!has_alignment_of (^^ref));
+static_assert (alignment_of (std::meta::reflect_object (arr)) == alignment_of (^^arr));
+static_assert (alignment_of (std::meta::reflect_object (arr[1])) == alignof (int));
+static_assert (alignment_of (std::meta::reflect_object (s.mem)) == alignment_of (^^S::mem));
+static_assert (alignment_of (^^arr) >= alignof (int));
+static_assert (alignment_of (^^arr4) == 32);
+static_assert (alignment_of (^^Alias) == alignof (int));
+static_assert (alignment_of (^^S) == alignof (S));
+static_assert (alignment_of (^^S::mem) == offsetof (S2, mem));
+static_assert (alignment_of (std::meta::bases_of (^^S, ctx)[0]) == alignof (B));
+static_assert (alignment_of (std::meta::data_member_spec (^^int, { .name = "member" })) == alignof (int));
+static_assert (alignment_of (^^arr3) >= alignof (int));
+static_assert (alignment_of (^^arr5) == 64);
+static_assert (alignment_of (^^T::ta) >= alignof (int));
+static_assert (alignment_of (^^T::tb) == 128);
+static_assert (alignment_of (^^v1) >= alignof (short));
+static_assert (alignment_of (^^v2) == 64);
+using fnt = int (int, int);
+static_assert (!has_alignment_of (^^fnt));
+void bar (long, const T f, int g[2], T &);
+
+int
+foo (int a, const long b, T c, int d[4], T &e, int f)
+{
+  static_assert (has_alignment_of (^^a));
+  static_assert (has_alignment_of (^^b));
+  static_assert (has_alignment_of (^^c));
+  static_assert (has_alignment_of (^^d));
+  static_assert (!has_alignment_of (^^e));
+  static_assert (!has_alignment_of (parameters_of (^^foo)[0]));
+  static_assert (!has_alignment_of (parameters_of (^^foo)[5]));
+  static_assert (!has_alignment_of (parameters_of (^^bar)[0]));
+  static_assert (alignment_of (^^a) >= alignof (int));
+  static_assert (alignment_of (^^b) >= alignof (long));
+  static_assert (alignment_of (^^c) >= alignof (T));
+  static_assert (alignment_of (^^d) >= alignof (int *));
+  return 0;
+}
+
+struct V
+{
+  char a;
+  long long f;
+  int : 2;
+  int g : 3;
+  int &h;
+  alignas (32) int i;
+  alignas (64) long long j;
+};
+struct V2
+{
+  char p;
+  char a;
+};
+struct V3
+{
+  char p;
+  long long f;
+};
+struct V4
+{
+  char p;
+  int *h;
+};
+using CV = const V;
+
+static_assert (alignment_of (^^int) == alignof (int));
+static_assert (alignment_of (^^char) == alignof (char));
+static_assert (alignment_of (^^V) == alignof (V));
+static_assert (alignment_of (^^CV) == alignof (V));
+static_assert (alignment_of (^^char *) == alignof (char *));
+static_assert (alignment_of (^^char &) == alignof (char *));
+static_assert (alignment_of (^^char &&) == alignof (char *));
+static_assert (alignof (char) == alignof (char *) || alignment_of (^^char &) != alignof (char &));
+static_assert (alignof (char) == alignof (char *) || alignment_of (^^char &&) != alignof (char &&));
+static_assert (alignment_of (^^V::a) == offsetof (V2, a));
+static_assert (alignment_of (^^V::f) == offsetof (V3, f));
+static_assert (!has_alignment_of (^^V::g));
+static_assert (alignment_of (^^V::h) == offsetof (V4, h));
+static_assert (alignment_of (^^V::i) == 32);
+static_assert (alignment_of (^^V::j) == 64);
diff --git a/gcc/testsuite/g++.dg/reflect/alignment_of2.C b/gcc/testsuite/g++.dg/reflect/alignment_of2.C
new file mode 100644 (file)
index 0000000..b0ff90d
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-options "-freflection" }
+// Test std::meta::alignment_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S
+{
+  char a;
+  int b;
+};
+struct [[gnu::packed]] V
+{
+  char a;
+  long long f;
+  int *h;
+  S i;
+} v;
+
+static_assert (alignment_of (^^v) == 1);
+static_assert (alignment_of (^^V) == alignof (V));
+static_assert (alignment_of (^^V::a) == 1);
+static_assert (alignment_of (^^V::f) == 1);
+static_assert (alignment_of (^^V::h) == 1);
+static_assert (alignment_of (^^V::i) == 1);
diff --git a/gcc/testsuite/g++.dg/reflect/annotations1.C b/gcc/testsuite/g++.dg/reflect/annotations1.C
new file mode 100644 (file)
index 0000000..561407f
--- /dev/null
@@ -0,0 +1,139 @@
+// C++ 26 P3394R4 - Annotations for Reflection
+// { dg-do compile { target c++26 } }
+
+int arr[2];
+struct S { int a, b; };
+S arr2[2];
+
+void
+foo (int n)
+{
+  [[=1]] int x1;
+  auto a = [] [[=1]] () {};
+  auto b = [] constexpr [[=1]] {};     // { dg-error "annotation on a type other than class or enumeration definition" }
+  auto c = [] noexcept [[=1]] {};      // { dg-error "annotation on a type other than class or enumeration definition" }
+  auto d = [] () [[=1]] {};            // { dg-error "annotation on a type other than class or enumeration definition" }
+  auto e = new int [n] [[=1]];         // { dg-warning "attributes ignored on outermost array type in new expression" }
+  auto e2 = new int [n] [[=1]] [42];   // { dg-warning "attributes ignored on outermost array type in new expression" }
+  auto f = new int [n][42] [[=1]];     // { dg-error "annotation on a type other than class or enumeration definition" }
+  [[=1]];                              // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[=1]] {}                            // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[=1]] if (true) {}                  // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[=1]] while (false) {}              // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[=1]] goto lab;                     // { dg-warning "attributes at the beginning of statement are ignored" }
+  [[=1]] lab:;                         // { dg-error "annotation applied to a label" }
+  [[=1]] try {} catch (int) {}         // { dg-warning "attributes at the beginning of statement are ignored" }
+  if ([[=1]] int x = 0) {}
+  switch (n)
+    {
+    [[=1]] case 1:                     // { dg-error "annotation applied to a label" }
+    [[=1]] break;                      // { dg-warning "attributes at the beginning of statement are ignored" }
+    [[=1]] default:                    // { dg-error "annotation applied to a label" }
+          break;
+    }
+  for ([[=1]] auto a : arr) {}
+  for ([[=1]] auto [a, b] : arr2) {}
+  [[=1]] asm ("");                     // { dg-warning "attributes ignored on 'asm' declaration" }
+  try {} catch ([[=1]] int x) {}
+  try {} catch ([[=1]] int) {}
+  try {} catch (int [[=1]] x) {}       // { dg-warning "attribute ignored" }
+  try {} catch (int [[=1]]) {}         // { dg-warning "attribute ignored" }
+  try {} catch (int x [[=1]]) {}
+}
+
+[[=1]] int bar ();
+using foobar [[=1]] = int;
+[[=1]] int a;
+[[=1]] auto [b, c] = arr;
+auto [b3 [[=1]], c3 [[=1]]] = arr;     // { dg-error "annotation on structured binding" }
+[[=1]];                                        // { dg-warning "attribute ignored" }
+inline [[=1]] void baz () {}           // { dg-warning "attribute ignored" }
+                                               // { dg-error "standard attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+constexpr [[=1]] int qux () { return 0; }      // { dg-warning "attribute ignored" }
+                                               // { dg-error "standard attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+int [[=1]] d;                          // { dg-warning "attribute ignored" }
+int const [[=1]] e = 1;                        // { dg-warning "attribute ignored" }
+struct A {} [[=1]];                    // { dg-warning "attribute ignored in declaration of 'struct A'" }
+struct A [[=1]];                       // { dg-warning "attribute ignored" }
+struct A [[=1]] a1;                    // { dg-warning "attribute ignored" }
+A [[=1]] a2;                           // { dg-warning "attribute ignored" }
+enum B { B0 } [[=1]];                  // { dg-warning "attribute ignored in declaration of 'enum B'" }
+enum B [[=1]];                         // { dg-warning "attribute ignored" }
+enum B [[=1]] b1;                      // { dg-warning "attribute ignored" }
+B [[=1]] b2;                           // { dg-warning "attribute ignored" }
+struct [[=1]] C {};
+int f [[=1]];
+int g[2] [[=1]];                       // { dg-error "annotation on a type other than class or enumeration definition" }
+int g2 [[=1]] [2];
+int corge () [[=1]];                   // { dg-error "annotation on a type other than class or enumeration definition" }
+int *[[=1]] h;                         // { dg-error "annotation on a type other than class or enumeration definition" }
+int & [[=1]] i = f;                    // { dg-error "annotation on a type other than class or enumeration definition" }
+int && [[=1]] j = 0;                   // { dg-error "annotation on a type other than class or enumeration definition" }
+int S::* [[=1]] k;                     // { dg-error "annotation on a type other than class or enumeration definition" }
+auto l = sizeof (int [2] [[=1]]);      // { dg-error "annotation on a type other than class or enumeration definition" }
+int freddy ([[=1]] int a,
+           [[=1]] int,
+           [[=1]] int c = 0,
+           [[=1]] int = 0);
+void
+corge ([[=1]] int a,
+       [[=1]] int,
+       [[=1]] int c = 0,
+       [[=1]] int = 0)
+{
+}
+[[=1]] void
+garply ()
+{
+}
+int grault (int [[=1]] a,              // { dg-warning "attribute ignored" }
+           int [[=1]],                 // { dg-warning "attribute ignored" }
+           int [[=1]] c = 0,           // { dg-warning "attribute ignored" }
+           int [[=1]] = 0);            // { dg-warning "attribute ignored" }
+void
+waldo (int [[=1]] a,                   // { dg-warning "attribute ignored" }
+       int [[=1]],                     // { dg-warning "attribute ignored" }
+       int [[=1]] c = 0,               // { dg-warning "attribute ignored" }
+       int [[=1]] = 0)                 // { dg-warning "attribute ignored" }
+{
+}
+int plugh (int a [[=1]],
+           int b [[=1]] = 0);
+void
+thud (int a [[=1]],
+      int b [[=1]] = 0)
+{
+}
+enum [[=1]] D { D0 };
+enum class [[=1]] E { E0 };
+enum F {};
+enum [[=1]] F;                         // { dg-warning "type attributes ignored after type is already defined" }
+enum G {
+  G0 [[=1]],
+  G1 [[=1]] = 2
+};
+namespace [[=1]] H { using H0 = int; }
+namespace [[=1]] {}
+[[=1]] using namespace H;              // { dg-error "annotation on using directive" }
+struct [[=1]] I
+{
+  [[=1]];                              // { dg-error "declaration does not declare anything" }
+  [[=1]] int i;
+  [[=1]] int foo ();
+  [[=1]] int bar () { return 1; }
+  [[=1]] int : 0;                      // { dg-error "annotation on unnamed bit-field" }
+  [[=1]] int i2 : 5;
+  [[=1]] static int i3;
+  static int i4;
+};
+[[=1]] int I::i4 = 0;
+struct J : [[=1]] C {};
+template <typename T>
+concept K [[=1]] = requires { true; };
+typedef int L [[=1]];
+template <typename T>
+struct M {};
+template <>
+struct [[=1]] M<int> { int m; };
+typedef int N[2] [[=1]];               // { dg-error "annotation on a type other than class or enumeration definition" }
+typedef int O [[=1]] [2];
diff --git a/gcc/testsuite/g++.dg/reflect/annotations2.C b/gcc/testsuite/g++.dg/reflect/annotations2.C
new file mode 100644 (file)
index 0000000..77b5811
--- /dev/null
@@ -0,0 +1,44 @@
+// C++ 26 P3394R4 - Annotations for Reflection
+// { dg-do compile { target c++26 } }
+
+struct [[=0]] A;
+struct [[=1, =2]] A {
+  [[=1]] [[=1]] [[=2]] int a;
+  [[=3, =4, =5]] static int b; 
+};
+namespace [[=6, =6]] [[=6]] N
+{
+};
+namespace [[=7]] [[= 7 + 1]] [[= 7 + 2]] N
+{
+};
+[[=9.5L]] int c;
+struct B { constexpr B () : b (42) {} int b; };
+[[=B ()]] int d;
+struct C { constexpr C () : c (42) {} int c; ~C () {} };
+[[=C ()]] int e;                                               // { dg-error "temporary of non-literal type 'C' in a constant expression" }
+                                                               // { dg-error "annotation does not have structural type" "" { target *-*-* } .-1 }
+struct D { constexpr D () : d (42) {} volatile int d; };
+[[=D ()]] int f;                                               // { dg-error "temporary of non-literal type 'D' in a constant expression" }
+                                                               // { dg-error "annotation does not have structural type" "" { target *-*-* } .-1 }
+struct E { constexpr E () : e (42) {} private: int e; };
+[[=E ()]] int g;                                               // { dg-error "annotation does not have structural type" }
+struct F { constexpr F () : f (42) {} protected: int f; };
+[[=F ()]] int h;                                               // { dg-error "annotation does not have structural type" }
+struct G { constexpr G () : g (42) {} mutable int g; };
+[[=G ()]] int i;                                               // { dg-error "annotation does not have structural type" }
+struct H { constexpr H () : h (42) {} int h; G g; };
+[[=H ()]] int j;                                               // { dg-error "annotation does not have structural type" }
+[[=c]] int k;                                                  // { dg-error "the value of 'c' is not usable in a constant expression" }
+[[=(throw 1, 0)]] int l;                                       // { dg-error "uncaught exception '1'" }
+struct I { int a, b; long c; };
+constexpr B m = B ();
+constexpr I n = { 1, 2, 3 };
+template <auto ...A>
+[[=1, =A...]] int o;
+int p = o<1, m, n> + o<2, 42>;
+[[maybe_unused]] [[=3]] [[gnu::unused]] int q;
+[[=3, gnu::unused, gnu::aligned(16), =4]] int r;               // { dg-error "mixing annotations and attributes in the same list" }
+[[gnu::unused, =5, gnu::aligned(16), =6]] int s;               // { dg-error "mixing annotations and attributes in the same list" }
+[[using gnu:unused, =7, aligned(16), =8]] int t;               // { dg-error "mixing annotations and attributes in the same list" }
+[[using gnu:=9]] int u;                                                // { dg-error "mixing annotations and attributes in the same list" }
diff --git a/gcc/testsuite/g++.dg/reflect/annotations3.C b/gcc/testsuite/g++.dg/reflect/annotations3.C
new file mode 100644 (file)
index 0000000..1f80d7a
--- /dev/null
@@ -0,0 +1,174 @@
+// C++ 26 P3394R4 - Annotations for Reflection
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::annotations_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<class, class> inline constexpr bool same_type_v = false;
+template<class T> inline constexpr bool same_type_v<T, T> = true;
+
+[[=42, =42]] int x;
+static_assert (annotations_of (^^x).size () == 2);
+static_assert (same_type_v<decltype (annotations_of (^^x)), std::vector<info>>);
+static_assert (type_of (annotations_of (^^x)[0]) == ^^int);
+static_assert (type_of (annotations_of (^^x)[1]) == ^^int);
+
+[[=42]] int foo ();
+[[=24L]] int foo ();
+static_assert (annotations_of (^^foo).size () == 2);
+static_assert (type_of (annotations_of (^^foo)[0]) == ^^int);
+static_assert (type_of (annotations_of (^^foo)[1]) == ^^long);
+
+[[=1]] void bar ();
+[[=2U, =3UL]] void baz ();
+void baz [[=4ULL]] ();
+
+static_assert (annotations_of (^^bar).size () == 1);
+static_assert (type_of (annotations_of (^^bar)[0]) == ^^int);
+static_assert (annotations_of (^^baz).size () == 3);
+static_assert (type_of (annotations_of (^^baz)[0]) == ^^unsigned);
+static_assert (type_of (annotations_of (^^baz)[1]) == ^^unsigned long);
+static_assert (type_of (annotations_of (^^baz)[2]) == ^^unsigned long long);
+
+struct [[=42]] C {};
+constexpr std::meta::info a0 = annotations_of (^^C)[0];
+static_assert (is_annotation (a0));
+static_assert (type_of (a0) == ^^int);
+
+template <class T>
+struct [[=42]] D {};
+
+//constexpr std::meta::info a1 = annotations_of (^^D<int>)[0];
+//constexpr std::meta::info a2 = annotations_of (^^D<char>)[0];
+//static_assert (is_annotation (a1) && is_annotation (a2));
+
+[[=1, =2L, =3.0, =4U, =5U, =6L, =7U]] int y;
+static_assert (annotations_of (^^y).size () == 7);
+static_assert (type_of (annotations_of (^^y)[0]) == ^^int);
+static_assert (type_of (annotations_of (^^y)[1]) == ^^long);
+static_assert (type_of (annotations_of (^^y)[2]) == ^^double);
+static_assert (type_of (annotations_of (^^y)[3]) == ^^unsigned);
+static_assert (type_of (annotations_of (^^y)[4]) == ^^unsigned);
+static_assert (type_of (annotations_of (^^y)[5]) == ^^long);
+static_assert (type_of (annotations_of (^^y)[6]) == ^^unsigned);
+static_assert (annotations_of_with_type (^^y, ^^int).size () == 1);
+static_assert (type_of (annotations_of_with_type (^^y, ^^int)[0]) == ^^int);
+static_assert (annotations_of_with_type (^^y, ^^long).size () == 2);
+static_assert (type_of (annotations_of_with_type (^^y, ^^long)[0]) == ^^long);
+static_assert (type_of (annotations_of_with_type (^^y, ^^long)[1]) == ^^long);
+static_assert (annotations_of_with_type (^^y, ^^unsigned).size () == 3);
+static_assert (type_of (annotations_of_with_type (^^y, ^^unsigned)[0]) == ^^unsigned);
+static_assert (type_of (annotations_of_with_type (^^y, ^^unsigned)[1]) == ^^unsigned);
+static_assert (type_of (annotations_of_with_type (^^y, ^^unsigned)[2]) == ^^unsigned);
+static_assert (annotations_of_with_type (^^y, ^^const double).size () == 1);
+static_assert (type_of (annotations_of_with_type (^^y, ^^double)[0]) == ^^double);
+static_assert (annotations_of_with_type (^^y, ^^volatile double).size () == 0);
+static_assert (annotations_of_with_type (^^y, ^^float).size () == 0);
+
+int z;
+static_assert (annotations_of (^^z).size () == 0);
+
+struct V { int a, b, c; };
+[[=1, =V { 2, 3, 4 }, =1.0]] int an;
+static_assert (type_of (annotations_of (^^an)[0]) == ^^int);
+static_assert (type_of (annotations_of (^^an)[1]) == ^^const V);
+static_assert (type_of (annotations_of (^^an)[2]) == ^^double);
+
+struct W { [[=1, =2L, =3U, =4UL]] int a; [[=V { 2, 3, 4 }, =1.0f]] int b; };
+static_assert (type_of (annotations_of (^^W::a)[0]) == ^^int);
+static_assert (type_of (annotations_of (^^W::a)[1]) == ^^long);
+static_assert (type_of (annotations_of (^^W::a)[2]) == ^^unsigned);
+static_assert (type_of (annotations_of (^^W::a)[3]) == ^^long unsigned);
+static_assert (type_of (annotations_of (^^W::b)[0]) == ^^const V);
+static_assert (type_of (annotations_of (^^W::b)[1]) == ^^float);
+
+[[=1, =1.0f]] [[=2U]] extern int an2;
+[[=3L, =4.0]] [[=5UL, =5UL]] extern int an2;
+[[=6LL, =V { 7, 8, 9 }]] [[=6ULL, =6ULL]] int an2;
+static_assert (annotations_of (^^an2).size () == 11);
+static_assert (type_of (annotations_of (^^an2)[0]) == ^^int);
+static_assert (type_of (annotations_of (^^an2)[1]) == ^^float);
+static_assert (type_of (annotations_of (^^an2)[2]) == ^^unsigned);
+static_assert (type_of (annotations_of (^^an2)[3]) == ^^long);
+static_assert (type_of (annotations_of (^^an2)[4]) == ^^double);
+static_assert (type_of (annotations_of (^^an2)[5]) == ^^unsigned long);
+static_assert (type_of (annotations_of (^^an2)[6]) == ^^unsigned long);
+static_assert (type_of (annotations_of (^^an2)[7]) == ^^long long);
+static_assert (type_of (annotations_of (^^an2)[8]) == ^^const V);
+static_assert (type_of (annotations_of (^^an2)[9]) == ^^unsigned long long);
+static_assert (type_of (annotations_of (^^an2)[10]) == ^^unsigned long long);
+
+namespace [[=1, =2U]] [[=3L, =4.0]] N
+{
+  static_assert (annotations_of (^^N).size () == 4);
+  static_assert (type_of (annotations_of (^^N)[0]) == ^^int);
+  static_assert (type_of (annotations_of (^^N)[1]) == ^^unsigned);
+  static_assert (type_of (annotations_of (^^N)[2]) == ^^long);
+  static_assert (type_of (annotations_of (^^N)[3]) == ^^double);
+}
+
+namespace [[=5.0f]] [[=6LL]] N
+{
+  static_assert (annotations_of (^^N).size () == 6);
+  static_assert (type_of (annotations_of (^^N)[0]) == ^^int);
+  static_assert (type_of (annotations_of (^^N)[1]) == ^^unsigned);
+  static_assert (type_of (annotations_of (^^N)[2]) == ^^long);
+  static_assert (type_of (annotations_of (^^N)[3]) == ^^double);
+  static_assert (type_of (annotations_of (^^N)[4]) == ^^float);
+  static_assert (type_of (annotations_of (^^N)[5]) == ^^long long);
+}
+
+struct F { int f; };
+struct G { int g; };
+struct H { int h; };
+struct I : [[=1U, =2L]] [[=3]] F, [[=4ULL]] G, H { int i; };
+
+constexpr auto ctx = access_context::unchecked ();
+static_assert (annotations_of (bases_of (^^I, ctx)[0]).size () == 3);
+static_assert (type_of (annotations_of (bases_of (^^I, ctx)[0])[0]) == ^^unsigned);
+static_assert (type_of (annotations_of (bases_of (^^I, ctx)[0])[1]) == ^^long);
+static_assert (type_of (annotations_of (bases_of (^^I, ctx)[0])[2]) == ^^int);
+static_assert (annotations_of (bases_of (^^I, ctx)[1]).size () == 1);
+static_assert (type_of (annotations_of (bases_of (^^I, ctx)[1])[0]) == ^^unsigned long long);
+static_assert (annotations_of (bases_of (^^I, ctx)[2]).size () == 0);
+
+struct J { int j; };
+struct K { int k; };
+struct L { int l; };
+template <typename ...T>
+struct M : [[=1]] F, G, [[=2U, =V { 1, 2, 3 }]] [[=3LL]] T... { int m; };
+static_assert (bases_of (^^M <>, ctx).size () == 2);
+static_assert (annotations_of (bases_of (^^M <>, ctx)[0]).size () == 1);
+static_assert (type_of (annotations_of (bases_of (^^M <>, ctx)[0])[0]) == ^^int);
+static_assert (annotations_of (bases_of (^^M <>, ctx)[1]).size () == 0);
+static_assert (bases_of (^^M <J, K, L>, ctx).size () == 5);
+static_assert (annotations_of (bases_of (^^M <J, K, L>, ctx)[0]).size () == 1);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[0])[0]) == ^^int);
+static_assert (annotations_of (bases_of (^^M <J, K, L>, ctx)[1]).size () == 0);
+static_assert (annotations_of (bases_of (^^M <J, K, L>, ctx)[2]).size () == 3);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[2])[0]) == ^^unsigned);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[2])[1]) == ^^const V);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[2])[2]) == ^^long long);
+static_assert (annotations_of (bases_of (^^M <J, K, L>, ctx)[3]).size () == 3);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[3])[0]) == ^^unsigned);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[3])[1]) == ^^const V);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[3])[2]) == ^^long long);
+static_assert (annotations_of (bases_of (^^M <J, K, L>, ctx)[4]).size () == 3);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[4])[0]) == ^^unsigned);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[4])[1]) == ^^const V);
+static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[4])[2]) == ^^long long);
+
+template <auto ...V>
+consteval auto
+qux ()
+{
+  [[=1, =V..., =2]] int an;
+  return ^^an;
+}
+
+static_assert (annotations_of (qux <> ()).size () == 2);
+static_assert (annotations_of (qux <3, 4, 5> ()).size () == 5);
+static_assert (annotations_of (qux <V { 1, 2, 3 }, V { 2, 3, 4 }> ()).size () == 4);
diff --git a/gcc/testsuite/g++.dg/reflect/annotations4.C b/gcc/testsuite/g++.dg/reflect/annotations4.C
new file mode 100644 (file)
index 0000000..ef1c416
--- /dev/null
@@ -0,0 +1,79 @@
+// C++ 26 P3394R4 - Annotations for Reflection
+// { dg-do compile { target c++26 } }
+
+struct E { constexpr E () : e (42) {} private: int e; };
+int arr[2];
+struct S { int a, b; };
+S arr2[2];
+
+void
+foo (int n)
+{
+  [[=E ()]] int x1;                            // { dg-error "annotation does not have structural type" }
+  auto a = [] [[=E ()]] () {};                 // { dg-error "annotation does not have structural type" }
+  if ([[=E ()]] int x = 0) {}                  // { dg-error "annotation does not have structural type" }
+  for ([[=E ()]] auto a : arr) {}              // { dg-error "annotation does not have structural type" }
+  for ([[=E ()]] auto [a, b] : arr2) {}                // { dg-error "annotation does not have structural type" }
+  try {} catch ([[=E ()]] int x) {}            // { dg-error "annotation does not have structural type" }
+  try {} catch ([[=E ()]] int) {}              // { dg-error "annotation does not have structural type" }
+  try {} catch (int x [[=E ()]]) {}            // { dg-error "annotation does not have structural type" }
+}
+
+[[=E ()]] int bar ();                          // { dg-error "annotation does not have structural type" }
+using foobar [[=E ()]] = int;                  // { dg-error "annotation does not have structural type" }
+[[=E ()]] int a;                               // { dg-error "annotation does not have structural type" }
+[[=E ()]] auto [b, c] = arr;                   // { dg-error "annotation does not have structural type" }
+struct [[=E ()]] C {};                         // { dg-error "annotation does not have structural type" }
+int f [[=E ()]];                               // { dg-error "annotation does not have structural type" }
+int g2 [[=E ()]] [2];                          // { dg-error "annotation does not have structural type" }
+int freddy ([[=E ()]] int a,                   // { dg-error "annotation does not have structural type" }
+           [[=E ()]] int,                      // { dg-error "annotation does not have structural type" }
+           [[=E ()]] int c = 0,                // { dg-error "annotation does not have structural type" }
+           [[=E ()]] int = 0);                 // { dg-error "annotation does not have structural type" }
+void
+corge ([[=E ()]] int a,                                // { dg-error "annotation does not have structural type" }
+       [[=E ()]] int,                          // { dg-error "annotation does not have structural type" }
+       [[=E ()]] int c = 0,                    // { dg-error "annotation does not have structural type" }
+       [[=E ()]] int = 0)                      // { dg-error "annotation does not have structural type" }
+{
+}
+[[=E ()]] void
+garply ()                                      // { dg-error "annotation does not have structural type" }
+{
+}
+int plugh (int a [[=E ()]],                    // { dg-error "annotation does not have structural type" }
+          int b [[=E ()]] = 0);                // { dg-error "annotation does not have structural type" }
+void
+thud (int a [[=E ()]],                         // { dg-error "annotation does not have structural type" }
+      int b [[=E ()]] = 0)                     // { dg-error "annotation does not have structural type" }
+{
+}
+enum [[=E ()]] D { D0 };                       // { dg-error "annotation does not have structural type" }
+enum class [[=E ()]] Z { Z0 };                 // { dg-error "annotation does not have structural type" }
+enum F {};
+enum G {
+  G0 [[=E ()]],                                        // { dg-error "annotation does not have structural type" }
+  G1 [[=E ()]] = 2                             // { dg-error "annotation does not have structural type" }
+};
+namespace [[=E ()]] H { using H0 = int; }      // { dg-error "annotation does not have structural type" }
+namespace [[=E ()]] {}                         // { dg-error "annotation does not have structural type" }
+struct [[=E ()]] I                             // { dg-error "annotation does not have structural type" }
+{
+  [[=E ()]] int i;                             // { dg-error "annotation does not have structural type" }
+  [[=E ()]] int foo ();                                // { dg-error "annotation does not have structural type" }
+  [[=E ()]] int bar () { return 1; }           // { dg-error "annotation does not have structural type" }
+  [[=E ()]] int i2 : 5;                                // { dg-error "annotation does not have structural type" }
+  [[=E ()]] static int i3;                     // { dg-error "annotation does not have structural type" }
+  static int i4;
+};
+[[=E ()]] int I::i4 = 0;                       // { dg-error "annotation does not have structural type" }
+struct J : [[=E ()]] C {};                     // { dg-error "annotation does not have structural type" }
+template <typename T>
+concept K [[=E ()]] = requires { true; };      // { dg-error "annotation does not have structural type" "" { xfail *-*-* } }
+constexpr bool k = K <int>;
+typedef int L [[=E ()]];                       // { dg-error "annotation does not have structural type" }
+template <typename T>
+struct M {};
+template <>
+struct [[=E ()]] M<int> { int m; };            // { dg-error "annotation does not have structural type" }
+typedef int O [[=E ()]] [2];                   // { dg-error "annotation does not have structural type" }
diff --git a/gcc/testsuite/g++.dg/reflect/annotations5.C b/gcc/testsuite/g++.dg/reflect/annotations5.C
new file mode 100644 (file)
index 0000000..df4e909
--- /dev/null
@@ -0,0 +1,30 @@
+// C++ 26 P3394R4 - Annotations for Reflection
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::annotations_of.
+
+#include <meta>
+#include <ranges>
+#include <vector>
+
+[[=1, =1, =2, =1.0f]] void foo ();
+static_assert ((std::meta::annotations_of (^^foo)
+               | std::views::transform (std::meta::constant_of)
+               | std::ranges::to<std::vector> ())
+              == std::vector { std::meta::reflect_constant (1),
+                               std::meta::reflect_constant (1),
+                               std::meta::reflect_constant (2),
+                               std::meta::reflect_constant (1.0f) });
+
+[[=1]] [[=2]] void bar ();
+[[=3]] [[=3]] void bar ();
+[[=4L, =42]] void bar ();
+static_assert ((std::meta::annotations_of (^^bar)
+               | std::views::transform (std::meta::constant_of)
+               | std::ranges::to<std::vector> ())
+              == std::vector { std::meta::reflect_constant (1),
+                               std::meta::reflect_constant (2),
+                               std::meta::reflect_constant (3),
+                               std::meta::reflect_constant (3),
+                               std::meta::reflect_constant (4L),
+                               std::meta::reflect_constant (42) });
diff --git a/gcc/testsuite/g++.dg/reflect/annotations6.C b/gcc/testsuite/g++.dg/reflect/annotations6.C
new file mode 100644 (file)
index 0000000..98db4cc
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::annotations_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+extern int v;
+
+consteval std::size_t
+foo ()
+{
+  return annotations_of (^^v).size ();
+}
+
+static_assert (foo () == 0);
+[[=1]] [[=2]] extern int v;
+static_assert (foo () == 2);
+[[=3, =4, =5]] extern int v;
+static_assert (foo () == 5);
+[[=6]] extern int v;
+static_assert (foo () == 6);
+[[=6]] int v;
+static_assert (foo () == 7);
diff --git a/gcc/testsuite/g++.dg/reflect/annotations7.C b/gcc/testsuite/g++.dg/reflect/annotations7.C
new file mode 100644 (file)
index 0000000..c4a5a96
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct U {
+  constexpr U() = default;
+  U(const U&) = delete;
+};
+constexpr U u;
+struct [[ =u ]] deletedCopy{};         // { dg-error "annotation does not have copy constructible type" }
+                                       // { dg-error "use of deleted function 'U::U\\\(const U\\\&\\\)'" "" { target *-*-* } .-1 }
+struct [[ =U{} ]] deletedCopy2{};      // { dg-error "annotation does not have copy constructible type" }
+                                       // { dg-error "use of deleted function 'U::U\\\(const U\\\&\\\)'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/reflect/annotations8.C b/gcc/testsuite/g++.dg/reflect/annotations8.C
new file mode 100644 (file)
index 0000000..100ea20
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct [[=42]] A {};
+template <auto I>
+inline auto b = [] (auto &&x) { x.template operator () <I> (); };
+
+int
+main ()
+{
+  auto l = [&] <auto> {};
+  auto w = b <annotations_of (^^A)[0]>;
+  w (l);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/anon1.C b/gcc/testsuite/g++.dg/reflect/anon1.C
new file mode 100644 (file)
index 0000000..52307a9
--- /dev/null
@@ -0,0 +1,50 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// https://github.com/cplusplus/CWG/issues/705
+
+auto foo() {
+  union { int what; };
+  return &[:^^what:];  // { dg-error "not a direct member of a named class" }
+}
+
+static union { int m; };
+constexpr auto r = ^^m;
+auto p = &[:r:]; // { dg-error "not a direct member of a named class" }
+
+namespace N {
+  static union { int mn; };
+  constexpr auto rn = ^^mn;
+  auto pn = &[:rn:];  // { dg-error "not a direct member of a named class" }
+}
+
+struct S {
+  union {
+    int m;
+  };
+};
+
+constexpr auto r2 = ^^S::m;
+constexpr auto p2 = &[: ^^r2 :];
+
+void
+f ()
+{
+  static union {
+    int x;
+  };
+  auto rx = &[: ^^x :]; // { dg-error "not a direct member of a named class" }
+
+  union {
+    union {
+      int u;
+    };
+  };
+  auto ru = &[: ^^u :]; // { dg-error "not a direct member of a named class" }
+
+  struct L {
+    union {
+      int z;
+    };
+  };
+  auto rz = &[: ^^L::z :];
+}
diff --git a/gcc/testsuite/g++.dg/reflect/anon2.C b/gcc/testsuite/g++.dg/reflect/anon2.C
new file mode 100644 (file)
index 0000000..cd06424
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+static union { int m; };
+constexpr auto r = ^^m;
+auto p = [:r:]; // { dg-error "cannot implicitly reference a class member .<unnamed union>::m. through a splice" }
+
+namespace N {
+  static union { int mn; };
+  constexpr auto rn = ^^mn;
+  auto pn = [:rn:];  // { dg-error "cannot implicitly reference a class member .N::<unnamed union>::mn. through a splice" }
+}
+
+struct S {
+  union {
+    int m;
+  };
+};
+
+constexpr auto p2 = [: ^^S::m :]; // { dg-error "cannot implicitly reference a class member .S::<unnamed union>::m. through a splice" }
+
+void
+f ()
+{
+  static union {
+    int x;
+  };
+  auto rx = [: ^^x :]; // { dg-error "cannot implicitly reference a class member .f\\\(\\\)::<unnamed union>::x. through a splice" }
+
+  union {
+    union {
+      int u;
+    };
+  };
+  auto ru = [: ^^u :]; // { dg-error "cannot implicitly reference a class member .f\\\(\\\)::<unnamed union>::<unnamed union>::u. through a splice" }
+
+  struct L {
+    union {
+      int z;
+    };
+  };
+  auto rz = [: ^^L::z :]; // { dg-error "cannot implicitly reference a class member .f\\(\\)::L::<unnamed union>::z. through a splice" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/anon3.C b/gcc/testsuite/g++.dg/reflect/anon3.C
new file mode 100644 (file)
index 0000000..0a735cf
--- /dev/null
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+auto foo() {
+  union U { int what; };
+  return &[:^^U::what:];
+}
+
+union U { int m; };
+constexpr auto r = ^^U::m;
+auto p = &[:r:];
+
+namespace N {
+  union V { int mn; };
+  constexpr auto rn = ^^V::mn;
+  auto pn = &[:rn:];
+}
+
+struct S {
+  union W {
+    int m;
+  };
+};
+
+constexpr auto r2 = ^^S::W::m;
+constexpr auto p2 = &[: ^^r2 :];
+
+void
+f ()
+{
+  union U1 {
+    int x;
+  };
+  auto rx = &[: ^^U1::x :];
+
+  union UU {
+    union U2 {
+      int u;
+    };
+  };
+  auto ru = &[: ^^UU::U2::u :];
+
+  struct L {
+    union U3 {
+      int z;
+    };
+  };
+  auto rz = &[: ^^L::U3::z :];
+}
diff --git a/gcc/testsuite/g++.dg/reflect/bases_of1.C b/gcc/testsuite/g++.dg/reflect/bases_of1.C
new file mode 100644 (file)
index 0000000..76cb51c
--- /dev/null
@@ -0,0 +1,188 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::bases_of and has_inaccessible_bases.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+struct D { int d; };
+struct E { int e; };
+struct F { int f; };
+struct G { int g; };
+struct H { int h; };
+struct I : public A, protected B, private C { int i; };
+struct J : protected D, private E, public F { int j; };
+struct K : public G, protected I, private H, public J { int k; };
+struct L : virtual A { int l; };
+struct M : virtual A { int m; };
+struct N : public L, protected M, public virtual A { int n; };
+
+constexpr access_context gctx = access_context::current ();
+constexpr access_context uctx = access_context::unchecked ();
+
+static_assert (bases_of (^^A, uctx).size () == 0);
+static_assert (bases_of (^^B, uctx).size () == 0);
+static_assert (bases_of (^^C, uctx).size () == 0);
+static_assert (!has_inaccessible_bases (^^C, uctx));
+static_assert (bases_of (^^D, uctx).size () == 0);
+static_assert (bases_of (^^E, uctx).size () == 0);
+static_assert (bases_of (^^F, uctx).size () == 0);
+static_assert (bases_of (^^G, uctx).size () == 0);
+static_assert (bases_of (^^H, uctx).size () == 0);
+static_assert (bases_of (^^I, uctx).size () == 3);
+static_assert (is_base (bases_of (^^I, uctx)[0]));
+static_assert (parent_of (bases_of (^^I, uctx)[0]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[0]) == ^^A);
+static_assert (identifier_of (bases_of (^^I, uctx)[0]) == "A");
+static_assert (is_accessible (bases_of (^^I, uctx)[0], gctx));
+static_assert (size_of (bases_of (^^I, uctx)[0]) == sizeof (A));
+static_assert (offset_of (bases_of (^^I, uctx)[0]).total_bits () == 0);
+static_assert (is_base (bases_of (^^I, uctx)[1]));
+static_assert (parent_of (bases_of (^^I, uctx)[1]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[1]) == ^^B);
+static_assert (identifier_of (bases_of (^^I, uctx)[1]) == "B");
+static_assert (!is_accessible (bases_of (^^I, uctx)[1], gctx));
+static_assert (size_of (bases_of (^^I, uctx)[1]) == sizeof (B));
+static_assert (offset_of (bases_of (^^I, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (A));
+static_assert (is_base (bases_of (^^I, uctx)[2]));
+static_assert (parent_of (bases_of (^^I, uctx)[2]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[2]) == ^^C);
+static_assert (identifier_of (bases_of (^^I, uctx)[2]) == "C");
+static_assert (!is_accessible (bases_of (^^I, uctx)[2], gctx));
+static_assert (size_of (bases_of (^^I, uctx)[2]) == sizeof (C));
+static_assert (offset_of (bases_of (^^I, uctx)[2]).total_bits () == __CHAR_BIT__ * (sizeof (A) + sizeof (B)));
+static_assert (!has_inaccessible_bases (^^I, uctx));
+static_assert (bases_of (^^J, uctx).size () == 3);
+static_assert (is_base (bases_of (^^J, uctx)[0]));
+static_assert (parent_of (bases_of (^^J, uctx)[0]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[0]) == ^^D);
+static_assert (identifier_of (bases_of (^^J, uctx)[0]) == "D");
+static_assert (!is_accessible (bases_of (^^J, uctx)[0], gctx));
+static_assert (size_of (bases_of (^^J, uctx)[0]) == sizeof (D));
+static_assert (offset_of (bases_of (^^J, uctx)[0]).total_bits () == 0);
+static_assert (is_base (bases_of (^^J, uctx)[1]));
+static_assert (parent_of (bases_of (^^J, uctx)[1]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[1]) == ^^E);
+static_assert (identifier_of (bases_of (^^J, uctx)[1]) == "E");
+static_assert (!is_accessible (bases_of (^^J, uctx)[1], gctx));
+static_assert (size_of (bases_of (^^J, uctx)[1]) == sizeof (E));
+static_assert (offset_of (bases_of (^^J, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (D));
+static_assert (is_base (bases_of (^^J, uctx)[2]));
+static_assert (parent_of (bases_of (^^J, uctx)[2]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[2]) == ^^F);
+static_assert (identifier_of (bases_of (^^J, uctx)[2]) == "F");
+static_assert (is_accessible (bases_of (^^J, uctx)[2], gctx));
+static_assert (size_of (bases_of (^^J, uctx)[2]) == sizeof (F));
+static_assert (offset_of (bases_of (^^J, uctx)[2]).total_bits () == __CHAR_BIT__ * (sizeof (D) + sizeof (E)));
+static_assert (!has_inaccessible_bases (^^J, uctx));
+static_assert (bases_of (^^K, uctx).size () == 4);
+static_assert (is_base (bases_of (^^K, uctx)[0]));
+static_assert (parent_of (bases_of (^^K, uctx)[0]) == ^^K);
+static_assert (type_of (bases_of (^^K, uctx)[0]) == ^^G);
+static_assert (identifier_of (bases_of (^^K, uctx)[0]) == "G");
+static_assert (is_accessible (bases_of (^^K, uctx)[0], gctx));
+static_assert (size_of (bases_of (^^K, uctx)[0]) == sizeof (G));
+static_assert (offset_of (bases_of (^^K, uctx)[0]).total_bits () == 0);
+static_assert (is_base (bases_of (^^K, uctx)[1]));
+static_assert (parent_of (bases_of (^^K, uctx)[1]) == ^^K);
+static_assert (type_of (bases_of (^^K, uctx)[1]) == ^^I);
+static_assert (identifier_of (bases_of (^^K, uctx)[1]) == "I");
+static_assert (!is_accessible (bases_of (^^K, uctx)[1], gctx));
+static_assert (size_of (bases_of (^^K, uctx)[1]) == sizeof (I));
+static_assert (offset_of (bases_of (^^K, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (G));
+static_assert (is_base (bases_of (^^K, uctx)[2]));
+static_assert (parent_of (bases_of (^^K, uctx)[2]) == ^^K);
+static_assert (type_of (bases_of (^^K, uctx)[2]) == ^^H);
+static_assert (identifier_of (bases_of (^^K, uctx)[2]) == "H");
+static_assert (!is_accessible (bases_of (^^K, uctx)[2], gctx));
+static_assert (size_of (bases_of (^^K, uctx)[2]) == sizeof (H));
+static_assert (offset_of (bases_of (^^K, uctx)[2]).total_bits () == __CHAR_BIT__ * (sizeof (G) + sizeof (I)));
+static_assert (is_base (bases_of (^^K, uctx)[3]));
+static_assert (parent_of (bases_of (^^K, uctx)[3]) == ^^K);
+static_assert (type_of (bases_of (^^K, uctx)[3]) == ^^J);
+static_assert (identifier_of (bases_of (^^K, uctx)[3]) == "J");
+static_assert (is_accessible (bases_of (^^K, uctx)[3], gctx));
+static_assert (size_of (bases_of (^^K, uctx)[3]) == sizeof (J));
+static_assert (offset_of (bases_of (^^K, uctx)[3]).total_bits () == __CHAR_BIT__ * (sizeof (G) + sizeof (I) + sizeof (H)));
+static_assert (!has_inaccessible_bases (^^K, uctx));
+static_assert (bases_of (^^L, uctx).size () == 1);
+static_assert (is_base (bases_of (^^L, uctx)[0]));
+static_assert (parent_of (bases_of (^^L, uctx)[0]) == ^^L);
+static_assert (type_of (bases_of (^^L, uctx)[0]) == ^^A);
+static_assert (identifier_of (bases_of (^^L, uctx)[0]) == "A");
+static_assert (is_accessible (bases_of (^^L, uctx)[0], gctx));
+static_assert (size_of (bases_of (^^L, uctx)[0]) == sizeof (A));
+static_assert (offset_of (bases_of (^^L, uctx)[0]).total_bits () == __CHAR_BIT__ * (sizeof (void *) + sizeof (int)));
+static_assert (bases_of (^^M, uctx).size () == 1);
+static_assert (is_base (bases_of (^^M, uctx)[0]));
+static_assert (parent_of (bases_of (^^M, uctx)[0]) == ^^M);
+static_assert (type_of (bases_of (^^M, uctx)[0]) == ^^A);
+static_assert (identifier_of (bases_of (^^M, uctx)[0]) == "A");
+static_assert (is_accessible (bases_of (^^M, uctx)[0], gctx));
+static_assert (size_of (bases_of (^^M, uctx)[0]) == sizeof (A));
+static_assert (offset_of (bases_of (^^M, uctx)[0]).total_bits () == __CHAR_BIT__ * (sizeof (void *) + sizeof (int)));
+static_assert (bases_of (^^N, uctx).size () == 3);
+static_assert (is_base (bases_of (^^N, uctx)[0]));
+static_assert (parent_of (bases_of (^^N, uctx)[0]) == ^^N);
+static_assert (type_of (bases_of (^^N, uctx)[0]) == ^^L);
+static_assert (identifier_of (bases_of (^^N, uctx)[0]) == "L");
+static_assert (is_accessible (bases_of (^^N, uctx)[0], gctx));
+static_assert (size_of (bases_of (^^N, uctx)[0]) == sizeof (L));
+static_assert (offset_of (bases_of (^^N, uctx)[0]).total_bits () == 0);
+static_assert (is_base (bases_of (^^N, uctx)[1]));
+static_assert (parent_of (bases_of (^^N, uctx)[1]) == ^^N);
+static_assert (type_of (bases_of (^^N, uctx)[1]) == ^^M);
+static_assert (identifier_of (bases_of (^^N, uctx)[1]) == "M");
+static_assert (!is_accessible (bases_of (^^N, uctx)[1], gctx));
+static_assert (size_of (bases_of (^^N, uctx)[1]) == sizeof (M));
+#if (__SIZEOF_POINTER__ == 4 || __SIZEOF_POINTER__ == 8) && __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+// For LP64, L and M bases have vptr and the int field + 32 bits of padding,
+// for ILP32 they have no padding.
+static_assert (offset_of (bases_of (^^N, uctx)[1]).total_bits () == __CHAR_BIT__ * 2 * sizeof (void *));
+#endif
+static_assert (is_base (bases_of (^^N, uctx)[2]));
+static_assert (parent_of (bases_of (^^N, uctx)[2]) == ^^N);
+static_assert (type_of (bases_of (^^N, uctx)[2]) == ^^A);
+static_assert (identifier_of (bases_of (^^N, uctx)[2]) == "A");
+static_assert (is_accessible (bases_of (^^N, uctx)[2], gctx));
+static_assert (size_of (bases_of (^^N, uctx)[2]) == sizeof (A));
+#if (__SIZEOF_POINTER__ == 4 || __SIZEOF_POINTER__ == 8) && __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+// For LP64, N::n is in the of M and then comes the A base.
+// For ILP32 N::n is after the M base.
+static_assert (offset_of (bases_of (^^N, uctx)[2]).total_bits () == __CHAR_BIT__ * (4 * sizeof (void *) + (sizeof (void *) == 8 ? 0 : sizeof (int))));
+static_assert (offset_of (^^N::n).total_bits () == __CHAR_BIT__  * (4 * sizeof (void *) - ((sizeof (void *) == 8 ? sizeof (int) : 0))));
+#endif
+
+static_assert (bases_of (^^A, gctx).size () == 0);
+static_assert (bases_of (^^B, gctx).size () == 0);
+static_assert (bases_of (^^C, gctx).size () == 0);
+static_assert (!has_inaccessible_bases (^^C, gctx));
+static_assert (bases_of (^^D, gctx).size () == 0);
+static_assert (bases_of (^^E, gctx).size () == 0);
+static_assert (bases_of (^^F, gctx).size () == 0);
+static_assert (bases_of (^^G, gctx).size () == 0);
+static_assert (bases_of (^^H, gctx).size () == 0);
+static_assert (bases_of (^^I, gctx).size () == 1);
+static_assert (bases_of (^^I, gctx)[0] == bases_of (^^I, uctx)[0]);
+static_assert (has_inaccessible_bases (^^I, gctx));
+static_assert (bases_of (^^J, gctx).size () == 1);
+static_assert (bases_of (^^J, gctx)[0] == bases_of (^^J, uctx)[2]);
+static_assert (has_inaccessible_bases (^^J, gctx));
+static_assert (bases_of (^^K, gctx).size () == 2);
+static_assert (bases_of (^^K, gctx)[0] == bases_of (^^K, uctx)[0]);
+static_assert (bases_of (^^K, gctx)[1] == bases_of (^^K, uctx)[3]);
+static_assert (has_inaccessible_bases (^^K, gctx));
+static_assert (bases_of (^^L, gctx).size () == 1);
+static_assert (bases_of (^^L, gctx)[0] == bases_of (^^L, uctx)[0]);
+static_assert (!has_inaccessible_bases (^^L, gctx));
+static_assert (bases_of (^^M, gctx).size () == 1);
+static_assert (bases_of (^^M, gctx)[0] == bases_of (^^M, uctx)[0]);
+static_assert (!has_inaccessible_bases (^^L, gctx));
+static_assert (bases_of (^^N, gctx).size () == 2);
+static_assert (bases_of (^^N, gctx)[0] == bases_of (^^N, uctx)[0]);
+static_assert (bases_of (^^N, gctx)[1] == bases_of (^^N, uctx)[2]);
+static_assert (has_inaccessible_bases (^^N, gctx));
diff --git a/gcc/testsuite/g++.dg/reflect/bases_of2.C b/gcc/testsuite/g++.dg/reflect/bases_of2.C
new file mode 100644 (file)
index 0000000..8502053
--- /dev/null
@@ -0,0 +1,73 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::bases_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A {};
+struct B : virtual A {};
+struct C : virtual A {};
+struct D : virtual B, virtual C {};
+struct E : virtual D {};
+struct F : virtual D, virtual E {};
+struct G : virtual E, virtual F {};
+struct H : virtual A {};
+struct I : virtual F, virtual H {};
+struct J : virtual G, virtual I {};
+
+constexpr access_context uctx = access_context::unchecked ();
+
+static_assert (bases_of (^^A, uctx).size () == 0);
+static_assert (bases_of (^^B, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^B, uctx)[0]) == ^^B);
+static_assert (type_of (bases_of (^^B, uctx)[0]) == ^^A);
+static_assert (offset_of (bases_of (^^B, uctx)[0]).total_bits () == 0);
+static_assert (bases_of (^^C, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^C, uctx)[0]) == ^^C);
+static_assert (type_of (bases_of (^^C, uctx)[0]) == ^^A);
+static_assert (offset_of (bases_of (^^C, uctx)[0]).total_bits () == 0);
+static_assert (bases_of (^^D, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^D, uctx)[0]) == ^^D);
+static_assert (type_of (bases_of (^^D, uctx)[0]) == ^^B);
+static_assert (offset_of (bases_of (^^D, uctx)[0]).total_bits () == 0);
+static_assert (parent_of (bases_of (^^D, uctx)[1]) == ^^D);
+static_assert (type_of (bases_of (^^D, uctx)[1]) == ^^C);
+static_assert (offset_of (bases_of (^^D, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (bases_of (^^E, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^E, uctx)[0]) == ^^E);
+static_assert (type_of (bases_of (^^E, uctx)[0]) == ^^D);
+static_assert (offset_of (bases_of (^^E, uctx)[0]).total_bits () == 0);
+static_assert (bases_of (^^F, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^F, uctx)[0]) == ^^F);
+static_assert (type_of (bases_of (^^F, uctx)[0]) == ^^D);
+static_assert (offset_of (bases_of (^^F, uctx)[0]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (parent_of (bases_of (^^F, uctx)[1]) == ^^F);
+static_assert (type_of (bases_of (^^F, uctx)[1]) == ^^E);
+static_assert (offset_of (bases_of (^^F, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (bases_of (^^G, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^G, uctx)[0]) == ^^G);
+static_assert (type_of (bases_of (^^G, uctx)[0]) == ^^E);
+static_assert (offset_of (bases_of (^^G, uctx)[0]).total_bits () == 0);
+static_assert (parent_of (bases_of (^^G, uctx)[1]) == ^^G);
+static_assert (type_of (bases_of (^^G, uctx)[1]) == ^^F);
+static_assert (offset_of (bases_of (^^G, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (bases_of (^^H, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^H, uctx)[0]) == ^^H);
+static_assert (type_of (bases_of (^^H, uctx)[0]) == ^^A);
+static_assert (offset_of (bases_of (^^H, uctx)[0]).total_bits () == 0);
+static_assert (bases_of (^^I, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^I, uctx)[0]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[0]) == ^^F);
+static_assert (offset_of (bases_of (^^I, uctx)[0]).total_bits () == 0);
+static_assert (parent_of (bases_of (^^I, uctx)[1]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[1]) == ^^H);
+static_assert (offset_of (bases_of (^^I, uctx)[1]).total_bits () == __CHAR_BIT__ * 2 * sizeof (void *));
+static_assert (bases_of (^^J, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^J, uctx)[0]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[0]) == ^^G);
+static_assert (offset_of (bases_of (^^J, uctx)[0]).total_bits () == 0);
+static_assert (parent_of (bases_of (^^J, uctx)[1]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[1]) == ^^I);
+static_assert (offset_of (bases_of (^^J, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
diff --git a/gcc/testsuite/g++.dg/reflect/bases_of3.C b/gcc/testsuite/g++.dg/reflect/bases_of3.C
new file mode 100644 (file)
index 0000000..1648cb3
--- /dev/null
@@ -0,0 +1,88 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::bases_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A {};
+struct B : private virtual A {};
+struct C : protected virtual A {};
+struct D : public virtual B, protected virtual C {};
+struct E : private virtual D {};
+struct F : public virtual D, public virtual E {};
+struct G : protected virtual E, private virtual F {};
+struct H : protected virtual A {};
+struct I : public virtual F, private virtual H {};
+struct J : virtual G, virtual I {};
+
+constexpr access_context gctx = access_context::current ();
+constexpr access_context uctx = access_context::unchecked ();
+
+static_assert (bases_of (^^A, uctx).size () == 0);
+static_assert (bases_of (^^B, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^B, uctx)[0]) == ^^B);
+static_assert (type_of (bases_of (^^B, uctx)[0]) == ^^A);
+static_assert (offset_of (bases_of (^^B, uctx)[0]).total_bits () == 0);
+static_assert (!is_accessible (bases_of (^^B, uctx)[0], gctx));
+static_assert (bases_of (^^C, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^C, uctx)[0]) == ^^C);
+static_assert (type_of (bases_of (^^C, uctx)[0]) == ^^A);
+static_assert (offset_of (bases_of (^^C, uctx)[0]).total_bits () == 0);
+static_assert (!is_accessible (bases_of (^^C, uctx)[0], gctx));
+static_assert (bases_of (^^D, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^D, uctx)[0]) == ^^D);
+static_assert (type_of (bases_of (^^D, uctx)[0]) == ^^B);
+static_assert (offset_of (bases_of (^^D, uctx)[0]).total_bits () == 0);
+static_assert (is_accessible (bases_of (^^D, uctx)[0], gctx));
+static_assert (parent_of (bases_of (^^D, uctx)[1]) == ^^D);
+static_assert (type_of (bases_of (^^D, uctx)[1]) == ^^C);
+static_assert (offset_of (bases_of (^^D, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (!is_accessible (bases_of (^^D, uctx)[1], gctx));
+static_assert (bases_of (^^E, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^E, uctx)[0]) == ^^E);
+static_assert (type_of (bases_of (^^E, uctx)[0]) == ^^D);
+static_assert (offset_of (bases_of (^^E, uctx)[0]).total_bits () == 0);
+static_assert (!is_accessible (bases_of (^^E, uctx)[0], gctx));
+static_assert (bases_of (^^F, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^F, uctx)[0]) == ^^F);
+static_assert (type_of (bases_of (^^F, uctx)[0]) == ^^D);
+static_assert (offset_of (bases_of (^^F, uctx)[0]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (is_accessible (bases_of (^^F, uctx)[0], gctx));
+static_assert (parent_of (bases_of (^^F, uctx)[1]) == ^^F);
+static_assert (type_of (bases_of (^^F, uctx)[1]) == ^^E);
+static_assert (offset_of (bases_of (^^F, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (is_accessible (bases_of (^^F, uctx)[1], gctx));
+static_assert (bases_of (^^G, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^G, uctx)[0]) == ^^G);
+static_assert (type_of (bases_of (^^G, uctx)[0]) == ^^E);
+static_assert (offset_of (bases_of (^^G, uctx)[0]).total_bits () == 0);
+static_assert (!is_accessible (bases_of (^^G, uctx)[0], gctx));
+static_assert (parent_of (bases_of (^^G, uctx)[1]) == ^^G);
+static_assert (type_of (bases_of (^^G, uctx)[1]) == ^^F);
+static_assert (offset_of (bases_of (^^G, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (!is_accessible (bases_of (^^G, uctx)[1], gctx));
+static_assert (bases_of (^^H, uctx).size () == 1);
+static_assert (parent_of (bases_of (^^H, uctx)[0]) == ^^H);
+static_assert (type_of (bases_of (^^H, uctx)[0]) == ^^A);
+static_assert (offset_of (bases_of (^^H, uctx)[0]).total_bits () == 0);
+static_assert (!is_accessible (bases_of (^^H, uctx)[0], gctx));
+static_assert (bases_of (^^I, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^I, uctx)[0]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[0]) == ^^F);
+static_assert (offset_of (bases_of (^^I, uctx)[0]).total_bits () == 0);
+static_assert (is_accessible (bases_of (^^I, uctx)[0], gctx));
+static_assert (parent_of (bases_of (^^I, uctx)[1]) == ^^I);
+static_assert (type_of (bases_of (^^I, uctx)[1]) == ^^H);
+static_assert (offset_of (bases_of (^^I, uctx)[1]).total_bits () == __CHAR_BIT__ * 2 * sizeof (void *));
+static_assert (!is_accessible (bases_of (^^I, uctx)[1], gctx));
+static_assert (bases_of (^^J, uctx).size () == 2);
+static_assert (parent_of (bases_of (^^J, uctx)[0]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[0]) == ^^G);
+static_assert (offset_of (bases_of (^^J, uctx)[0]).total_bits () == 0);
+static_assert (is_accessible (bases_of (^^J, uctx)[0], gctx));
+static_assert (parent_of (bases_of (^^J, uctx)[1]) == ^^J);
+static_assert (type_of (bases_of (^^J, uctx)[1]) == ^^I);
+static_assert (offset_of (bases_of (^^J, uctx)[1]).total_bits () == __CHAR_BIT__ * sizeof (void *));
+static_assert (is_accessible (bases_of (^^J, uctx)[1], gctx));
diff --git a/gcc/testsuite/g++.dg/reflect/bit_size_of1.C b/gcc/testsuite/g++.dg/reflect/bit_size_of1.C
new file mode 100644 (file)
index 0000000..4ba4028
--- /dev/null
@@ -0,0 +1,125 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::bit_size_of.
+
+#include <meta>
+#include <climits>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+extern int arr2[];
+extern int arr3[2];
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+int &ref = arr[0];
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_bit_size_of (info r)
+{
+  try { bit_size_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (has_bit_size_of (std::meta::reflect_constant (42)));
+static_assert (has_bit_size_of (std::meta::reflect_object (arr[1])));
+static_assert (has_bit_size_of (^^arr));
+static_assert (!has_bit_size_of (^^a3));
+static_assert (!has_bit_size_of (^^fn));
+static_assert (!has_bit_size_of (^^fn2));
+static_assert (!has_bit_size_of (^^Enum::A));
+static_assert (has_bit_size_of (^^Alias));
+static_assert (has_bit_size_of (^^S));
+static_assert (has_bit_size_of (^^S::mem));
+static_assert (has_bit_size_of (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!has_bit_size_of (^^TCls));
+static_assert (!has_bit_size_of (^^TFn));
+static_assert (!has_bit_size_of (^^TVar));
+static_assert (!has_bit_size_of (^^Concept));
+static_assert (!has_bit_size_of (^^NSAlias));
+static_assert (!has_bit_size_of (^^NS));
+static_assert (has_bit_size_of (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (has_bit_size_of (std::meta::data_member_spec (^^int, { .name = "member" })));
+static_assert (has_bit_size_of (std::meta::data_member_spec (^^int, { .name = "member2", .bit_width = 6 })));
+static_assert (!has_bit_size_of (^^arr2));
+static_assert (has_bit_size_of (^^arr3));
+static_assert (!has_bit_size_of (^^ref));
+static_assert (bit_size_of (^^arr) == CHAR_BIT * sizeof (arr));
+static_assert (bit_size_of (std::meta::reflect_constant (42)) == CHAR_BIT * sizeof (int));
+static_assert (bit_size_of (^^Alias) == CHAR_BIT * sizeof (int));
+static_assert (bit_size_of (^^S) == CHAR_BIT * sizeof (S));
+static_assert (bit_size_of (^^S::mem) == CHAR_BIT * sizeof (S::mem));
+static_assert (bit_size_of (^^arr3) == CHAR_BIT * sizeof (arr3));
+using fnt = int (int, int);
+static_assert (!has_bit_size_of (^^fnt));
+void bar (long, const T f, int g[2], T &);
+
+int
+foo (int a, const long b, T c, int d[4], T &e, int f)
+{
+  static_assert (has_bit_size_of (^^a));
+  static_assert (has_bit_size_of (^^b));
+  static_assert (has_bit_size_of (^^c));
+  static_assert (has_bit_size_of (^^d));
+  static_assert (!has_bit_size_of (^^e));
+  static_assert (!has_bit_size_of (parameters_of (^^foo)[0]));
+  static_assert (!has_bit_size_of (parameters_of (^^foo)[5]));
+  static_assert (!has_bit_size_of (parameters_of (^^bar)[0]));
+  static_assert (bit_size_of (^^a) == CHAR_BIT * sizeof (int));
+  static_assert (bit_size_of (^^b) == CHAR_BIT * sizeof (long));
+  static_assert (bit_size_of (^^c) == CHAR_BIT * sizeof (T));
+  static_assert (bit_size_of (^^d) == CHAR_BIT * sizeof (int *));
+  return 0;
+}
+
+struct V
+{
+  char a;
+  long long f;
+  int : 2;
+  int g : 3;
+  int &h;
+  long long i : sizeof (long long) * CHAR_BIT - 3;
+};
+using CV = const V;
+
+static_assert (bit_size_of (^^int) == CHAR_BIT * sizeof (int));
+static_assert (bit_size_of (^^char) == CHAR_BIT * sizeof (char));
+static_assert (bit_size_of (^^V) == CHAR_BIT * sizeof (V));
+static_assert (bit_size_of (^^CV) == CHAR_BIT * sizeof (V));
+static_assert (bit_size_of (^^char *) == CHAR_BIT * sizeof (char *));
+static_assert (bit_size_of (^^char &) == CHAR_BIT * sizeof (char *));
+static_assert (sizeof (char) == sizeof (char *) || bit_size_of (^^char &) != CHAR_BIT * sizeof (char &));
+static_assert (bit_size_of (^^V::a) == CHAR_BIT * sizeof (char));
+static_assert (bit_size_of (^^V::f) == CHAR_BIT * sizeof (long long));
+static_assert (bit_size_of (^^V::g) == 3);
+static_assert (bit_size_of (^^V::h) == CHAR_BIT * sizeof (int *));
+static_assert (bit_size_of (^^V::i) == CHAR_BIT * sizeof (long long) - 3);
+static_assert (bit_size_of (std::meta::bases_of (^^S, ctx)[0]) == CHAR_BIT * sizeof (B));
+static_assert (bit_size_of (std::meta::data_member_spec (^^int, { .name = "member" })) == CHAR_BIT * sizeof (int));
+static_assert (bit_size_of (std::meta::data_member_spec (^^int, { .name = "member2", .bit_width = 6 })) == 6);
diff --git a/gcc/testsuite/g++.dg/reflect/bitfield1.C b/gcc/testsuite/g++.dg/reflect/bitfield1.C
new file mode 100644 (file)
index 0000000..c6dc010
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A {
+  int x : 4, y : 4;
+};
+
+constexpr auto f() {
+  return &[:^^A::y:];  // { dg-error "invalid pointer to bit-field .A::y." }
+}
+
+static_assert(2 == A{1, 2}.*(f()));
diff --git a/gcc/testsuite/g++.dg/reflect/can_substitute1.C b/gcc/testsuite/g++.dg/reflect/can_substitute1.C
new file mode 100644 (file)
index 0000000..a0dd750
--- /dev/null
@@ -0,0 +1,200 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::can_substitute.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+template <reflection_range R = std::initializer_list <info>>
+consteval bool
+could_substitute (info r, R &&args)
+{
+  try { can_substitute (r, args); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!could_substitute (null_reflection, {}));
+static_assert (!could_substitute (^^::, {}));
+static_assert (!could_substitute (^^ns, {}));
+static_assert (!could_substitute (^^ns_alias, {}));
+static_assert (!could_substitute (reflect_constant (3), {}));
+static_assert (!could_substitute (^^cls, {}));
+static_assert (!could_substitute (^^cls::dm, {}));
+static_assert (!could_substitute (^^cls::ref_dm, {}));
+static_assert (!could_substitute (^^cls::static_dm, {}));
+static_assert (!could_substitute (^^cls::mem_fun, {}));
+static_assert (!could_substitute (^^cls::static_mem_fun, {}));
+static_assert (!could_substitute (^^cls::type, {}));
+static_assert (!could_substitute (^^cls_var, {}));
+static_assert (!could_substitute (^^onion, {}));
+static_assert (!could_substitute (^^anon, {}));
+static_assert (!could_substitute (^^fun, {}));
+static_assert (!could_substitute (^^alias, {}));
+static_assert (!could_substitute (^^var, {}));
+static_assert (!could_substitute (^^ref, {}));
+static_assert (!could_substitute (^^rref, {}));
+static_assert (!could_substitute (^^ptr, {}));
+static_assert (could_substitute (^^cls_tmpl, {}));
+static_assert (!could_substitute (^^cls_tmpl<int>, {}));
+static_assert (!could_substitute (^^incomplete_cls<int>, {}));
+static_assert (could_substitute (^^fun_tmpl, {}));
+static_assert (!could_substitute (^^fun_tmpl<int>, {}));
+static_assert (could_substitute (^^conc, {}));
+static_assert (!could_substitute (substitute (^^conc, { ^^int }), {}));
+static_assert (could_substitute (^^var_tmpl, {}));
+static_assert (!could_substitute (^^var_tmpl<int>, {}));
+static_assert (could_substitute (^^cls_tmpl_alias, {}));
+static_assert (!could_substitute (^^cls_tmpl_alias<int>, {}));
+static_assert (!could_substitute (^^Enum, {}));
+static_assert (!could_substitute (^^Enum::A, {}));
+static_assert (!could_substitute (^^Enum_class, {}));
+static_assert (!could_substitute (^^Enum_class::A, {}));
+static_assert (!could_substitute (^^decomp, {}));
+static_assert (!could_substitute (^^decomp_ref, {}));
+static_assert (!could_substitute (^^arr, {}));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "a" });
+static_assert (!could_substitute (dms, {}));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!could_substitute (bases_of (^^Derived, access_context::unchecked ())[0], {}));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!could_substitute (^^T, {}));
+  static_assert (!could_substitute (R, {}));
+  static_assert (!could_substitute (R2, {}));
+  static_assert (could_substitute (R3, {}));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls_tmpl_alias>();
+  static_assert (!could_substitute (^^p, {}));
+  static_assert (!could_substitute (^^c, {}));
+}
+
+template <typename T>
+struct S {};
+
+template <float F, int N>
+struct T {};
+
+template <typename ...T>
+struct U {};
+
+template <typename T>
+T foo (T x) { return x; }
+
+template <int N>
+constexpr int v = N;
+
+template <typename T>
+concept C = requires { T::s; };
+
+struct V { int s; };
+
+struct NS {
+  constexpr NS (int x) : ns (x) {}
+  constexpr NS (const NS &x) : ns (x.ns) {}
+  constexpr ~NS () {}
+private:
+  int ns;
+};
+[[=1]] void bar (int x);
+
+static_assert (could_substitute (^^S, {}));
+static_assert (!could_substitute (^^S, { null_reflection }));
+static_assert (!could_substitute (^^S, { parameters_of (^^bar)[0] }));
+static_assert (!could_substitute (^^S, { annotations_of (^^bar)[0] }));
+static_assert (!could_substitute (^^S, { ^^:: }));
+static_assert (!could_substitute (^^S, { ^^ns }));
+static_assert (!could_substitute (^^S, { ^^ns_alias }));
+static_assert (!could_substitute (^^S, { ^^NS::~NS }));
+static_assert (could_substitute (^^S, { reflect_constant (42) }));
+constexpr int n = 42;
+static_assert (could_substitute (^^S, { ^^n }));
+constexpr NS nsv (42);
+static_assert (could_substitute (^^S, { ^^nsv }));
+
+static_assert (!can_substitute (^^S, {}));
+static_assert (can_substitute (^^S, { ^^int }));
+static_assert (can_substitute (^^S, { ^^V }));
+static_assert (can_substitute (^^S, { ^^NS }));
+static_assert (!can_substitute (^^S, { ^^int, ^^long }));
+static_assert (!can_substitute (^^S, { reflect_constant (42) }));
+static_assert (!can_substitute (^^S, { ^^n }));
+static_assert (!can_substitute (^^S, { ^^nsv }));
+static_assert (!can_substitute (^^T, {}));
+static_assert (!can_substitute (^^T, { ^^float, ^^int }));
+constexpr float fv = 42.0f;
+static_assert (can_substitute (^^T, { ^^fv, reflect_constant (42) }));
+static_assert (can_substitute (^^T, { ^^fv, reflect_constant (0) }));
+static_assert (can_substitute (^^T, { ^^fv, ^^n }));
+static_assert (!can_substitute (^^T, { ^^n, ^^fv }));
+static_assert (!can_substitute (^^T, { ^^fv, ^^n, ^^fv }));
+
+static_assert (can_substitute (^^U, {}));
+static_assert (can_substitute (^^U, { ^^int }));
+static_assert (can_substitute (^^U, { ^^int, ^^long, ^^const int &, ^^float, ^^double }));
+static_assert (!can_substitute (^^U, { ^^int, ^^long, ^^const int &, ^^n, ^^float }));
+
+static_assert (!can_substitute (^^v, {}));
+static_assert (can_substitute (^^v, { reflect_constant (15) }));
+static_assert (can_substitute (^^v, { ^^n }));
+static_assert (!can_substitute (^^v, { ^^n, ^^n }));
+static_assert (!can_substitute (^^v, { ^^int }));
+
+static_assert (!can_substitute (^^C, {}));
+static_assert (can_substitute (^^C, { ^^int }));
+static_assert (can_substitute (^^C, { ^^V }));
+static_assert (!can_substitute (^^C, { ^^int, ^^int }));
+static_assert (!can_substitute (^^C, { reflect_constant (42) }));
+static_assert (!can_substitute (^^C, { ^^n }));
+
+static_assert (!can_substitute (^^foo, {}));
+static_assert (can_substitute (^^foo, { ^^int }));
+static_assert (can_substitute (^^foo, { ^^V }));
+static_assert (can_substitute (^^foo, { ^^NS }));
+static_assert (!can_substitute (^^foo, { ^^int, ^^long }));
+static_assert (!can_substitute (^^foo, { reflect_constant (42) }));
+static_assert (!can_substitute (^^foo, { ^^n }));
diff --git a/gcc/testsuite/g++.dg/reflect/class1.C b/gcc/testsuite/g++.dg/reflect/class1.C
new file mode 100644 (file)
index 0000000..8c9a06a
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on classes.
+
+struct S {
+  using T = int;
+};
+
+void
+f1 ()
+{
+  constexpr auto s = ^^S;
+  [: s :]::T i = 42;
+  typename [: s :]::T j = 42;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/class2.C b/gcc/testsuite/g++.dg/reflect/class2.C
new file mode 100644 (file)
index 0000000..b717521
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test using a splice expression in an explicit destructor call.
+
+struct S { };
+struct X { };
+
+void
+ok (S s)
+{
+  /* [class.dtor]/16:
+     In an explicit destructor call, the destructor is specified by
+     a ~ followed by a type-name or computed-type-specifier that
+     denotes the destructor's class type.  */
+  s.~typename [:^^S:]();
+}
+
+void
+bad (S s)
+{
+  /* [expr.prim.splice]/2.1.2
+     For a splice-expression of the form splice-specifier, let S be
+     the construct designated by splice-specifier. The expression is
+     ill-formed if S is [...] a destructor  */
+  s.~[:^^S:](); // { dg-error "expected" }
+  s.~typename [:^^X:](); // { dg-error "the destructor refers to .X." }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/common_reference1.C b/gcc/testsuite/g++.dg/reflect/common_reference1.C
new file mode 100644 (file)
index 0000000..2dff165
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::common_reference.
+
+#include <meta>
+using namespace std::meta;
+
+template <reflection_range R = std::initializer_list <info>>
+consteval bool
+has_common_reference (R &&args)
+{
+  try { common_reference (args); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+struct A { };
+struct B { };
+struct C { };
+struct D { };
+struct E { };
+struct F { };
+
+template<template<typename> class AQual, template<typename> class BQual>
+struct std::basic_common_reference<A, B, AQual, BQual>
+{
+  using type = BQual<AQual<C>>;
+};
+
+template<> struct std::common_type<D, E> { using type = F; };
+
+static_assert (common_reference ({ ^^int }) == ^^int);
+static_assert (common_reference ({ ^^int & }) == ^^int &);
+static_assert (common_reference ({ ^^void }) == ^^void);
+static_assert (common_reference ({ ^^const void }) == ^^const void);
+static_assert (common_reference ({ ^^const void, ^^void }) == ^^void);
+static_assert (common_reference ({ ^^void (*const) (), ^^void (*) () }) == ^^void (*) ());
+static_assert (common_reference ({ ^^int, ^^int }) == ^^int);
+static_assert (common_reference ({ ^^int &, ^^int }) == ^^int);
+static_assert (common_reference ({ ^^int, ^^int & }) == ^^int);
+static_assert (common_reference ({ ^^int &&, ^^int }) == ^^int);
+static_assert (common_reference ({ ^^int &, ^^int & }) == ^^int &);
+static_assert (common_reference ({ ^^int &, ^^int && }) == ^^const int &);
+static_assert (common_reference ({ ^^int &&, ^^int & }) == ^^const int &);
+static_assert (common_reference ({ ^^int &&, ^^int && }) == ^^int &&);
+static_assert (common_reference ({ ^^int &&, ^^const int && }) == ^^const int &&);
+static_assert (common_reference ({ ^^int &, ^^int &, ^^int && }) == ^^const int &);
+static_assert (common_reference ({ ^^int &&, ^^int &, ^^int & }) == ^^const int &);
+static_assert (common_reference ({ ^^char &, ^^int & }) == ^^int);
+static_assert (common_reference ({ ^^long &, ^^int & }) == ^^long);
+static_assert (common_reference ({ ^^A, ^^B }) == ^^C);
+static_assert (common_reference ({ ^^A &, ^^B }) == ^^C &);
+static_assert (common_reference ({ ^^A &, ^^const B }) == ^^C &);
+static_assert (common_reference ({ ^^const A, ^^B & }) == ^^const C &);
+static_assert (common_reference ({ ^^const A &, ^^B && }) == ^^const C &);
+static_assert (common_reference ({ ^^const A, ^^B && }) == ^^const C &&);
+static_assert (common_reference ({ ^^D, ^^E }) == ^^F);
+static_assert (common_reference ({ ^^D &, ^^E }) == ^^F);
+static_assert (common_reference ({ ^^D &, ^^E && }) == ^^F);
+static_assert (!has_common_reference ({ ^^::, ^^int }));
+static_assert (!has_common_reference ({ ^^int, ^^int, ^^std }));
diff --git a/gcc/testsuite/g++.dg/reflect/common_type1.C b/gcc/testsuite/g++.dg/reflect/common_type1.C
new file mode 100644 (file)
index 0000000..996531a
--- /dev/null
@@ -0,0 +1,151 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::common_type.
+
+#include <meta>
+using namespace std::meta;
+
+template <reflection_range R = std::initializer_list <info>>
+consteval bool
+has_common_type (R &&args)
+{
+  try { common_type (args); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+struct S {};
+struct B {};
+struct D : B {};
+struct F1 { operator void * (); };
+struct F2 { operator void * (); };
+struct G1 { operator const void * (); };
+struct G2 { operator volatile void * (); };
+template <typename T>
+struct ImplicitTo { operator T (); };
+template <typename T>
+struct ExplicitTo { explicit operator T (); };
+template <typename T>
+struct PrivateImplicitTo { private: operator T (); };
+auto lmd1 = [] (int, double) {};
+auto lmd2 = [] (int, double) {};
+struct Abstract { virtual ~Abstract () = 0; };
+enum class ScEn;
+enum UnscEn : int;
+struct Ukn;
+union U { int i; };
+union U2 { long i; };
+union UConv1 { operator Abstract * (); };
+union UConv2 { operator Abstract * (); };
+struct X1 {};
+struct X2 {};
+struct RX12 {};
+struct RX21 {};
+struct Y1 {};
+struct Y2 {};
+struct Y3 {};
+struct Y4 {};
+
+namespace std {
+  template <>
+  struct common_type <X1, X2> { typedef RX12 type; };
+  template <>
+  struct common_type <X2, X1> { typedef RX21 type; };
+  template <>
+  struct common_type <RX12, X1> { typedef Y1 type; };
+  template <>
+  struct common_type <X1, RX12> { typedef Y2 type; };
+  template <>
+  struct common_type <RX21, X1> { typedef Y3 type; };
+  template <>
+  struct common_type <X1, RX21> { typedef Y4 type; };
+}
+
+using A = int;
+static_assert (common_type ({ ^^int }) == ^^int);
+static_assert (common_type ({ ^^A }) == ^^int);
+static_assert (common_type ({ ^^const int }) == ^^int);
+static_assert (common_type ({ ^^int, ^^int }) == ^^int);
+static_assert (common_type ({ ^^A, ^^int }) == ^^int);
+static_assert (common_type ({ ^^A, ^^A }) == ^^int);
+static_assert (common_type ({ ^^const int, ^^int }) == ^^int);
+static_assert (common_type ({ ^^ScEn, ^^ScEn }) == ^^ScEn);
+static_assert (common_type ({ ^^UnscEn, ^^UnscEn }) == ^^UnscEn);
+static_assert (common_type ({ ^^UnscEn, ^^int }) == ^^int);
+static_assert (common_type ({ ^^int, ^^int, ^^int }) == ^^int);
+static_assert (common_type ({ ^^int, ^^int, ^^int, ^^int }) == ^^int);
+static_assert (common_type ({ ^^int, ^^int, ^^int, ^^int, ^^int }) == ^^int);
+static_assert (common_type ({ ^^S, ^^S }) == ^^S);
+static_assert (common_type ({ ^^const S, ^^const S }) == ^^S);
+static_assert (common_type ({ ^^std::initializer_list<int>, ^^std::initializer_list<int> }) == ^^std::initializer_list<int>);
+static_assert (common_type ({ ^^B, ^^D }) == ^^B);
+static_assert (common_type ({ ^^D, ^^B }) == ^^B);
+static_assert (common_type ({ ^^F1, ^^F2 }) == ^^void *);
+static_assert (common_type ({ ^^F2, ^^F1 }) == ^^void *);
+static_assert (common_type ({ ^^G1, ^^G2 }) == ^^const volatile void *);
+static_assert (common_type ({ ^^G2, ^^G1 }) == ^^const volatile void *);
+static_assert (common_type ({ ^^int *, ^^const volatile int * }) == ^^const volatile int *);
+static_assert (common_type ({ ^^void *, ^^const volatile int * }) == ^^const volatile void *);
+static_assert (common_type ({ ^^void }) == ^^void);
+static_assert (common_type ({ ^^const void }) == ^^void);
+static_assert (common_type ({ ^^void, ^^void }) == ^^void);
+static_assert (common_type ({ ^^const void, ^^const void }) == ^^void);
+static_assert (common_type ({ ^^int &, ^^int && }) == ^^int);
+static_assert (common_type ({ ^^int &, ^^int & }) == ^^int);
+static_assert (common_type ({ ^^int &&, ^^int && }) == ^^int);
+static_assert (common_type ({ ^^int &&, ^^const int && }) == ^^int);
+static_assert (common_type ({ ^^U &, ^^const U && }) == ^^U);
+static_assert (common_type ({ ^^U &, ^^U & }) == ^^U);
+static_assert (common_type ({ ^^U &&, ^^U && }) == ^^U);
+static_assert (common_type ({ ^^int B::*, ^^int D::* }) == ^^int D::*);
+static_assert (common_type ({ ^^int D::*, ^^int B::* }) == ^^int D::*);
+static_assert (common_type ({ ^^const int B::*, ^^volatile int D::* }) == ^^const volatile int D::*);
+static_assert (common_type ({ ^^int (B::*) (), ^^int (D::*) () }) == ^^int (D::*) ());
+static_assert (common_type ({ ^^int (B::*) () const, ^^int (D::*) () const }) == ^^int (D::*) () const);
+static_assert (common_type ({ ^^int [3], ^^int [3] }) == ^^int *);
+static_assert (common_type ({ ^^int [1], ^^const int [3] }) == ^^const int *);
+static_assert (common_type ({ ^^void (), ^^void () }) == ^^void (*) ());
+static_assert (common_type ({ ^^void (&) (), ^^void (&) () }) == ^^void (*) ());
+static_assert (common_type ({ ^^void (&) (), ^^void (&&) () }) == ^^void (*) ());
+static_assert (common_type ({ ^^void (&&) (), ^^void (&) () }) == ^^void (*) ());
+static_assert (common_type ({ ^^void (&&) (), ^^void (&&) () }) == ^^void (*) ());
+static_assert (common_type ({ ^^ImplicitTo<int>, ^^int }) == ^^int);
+static_assert (common_type ({ ^^const ImplicitTo<int>, ^^int }) == ^^int);
+static_assert (common_type ({ ^^ImplicitTo<int>, ^^ImplicitTo<int> }) == ^^ImplicitTo<int>);
+static_assert (common_type ({ ^^ImplicitTo<int>, ^^int, ^^ImplicitTo<int> }) == ^^int);
+static_assert (common_type ({ ^^ExplicitTo<int>, ^^ExplicitTo<int> }) == ^^ExplicitTo<int>);
+static_assert (common_type ({ ^^decltype (lmd1), ^^decltype (lmd1) }) == ^^decltype (lmd1));
+static_assert (common_type ({ ^^decltype (lmd1) &, ^^decltype (lmd1) & }) == ^^decltype (lmd1));
+static_assert (common_type ({ ^^decltype (lmd1) &, ^^decltype (lmd2) & }) == ^^void (*) (int, double));
+static_assert (common_type ({ ^^decltype (nullptr), ^^void * }) == ^^void *);
+static_assert (common_type ({ ^^decltype (nullptr), ^^int * }) == ^^int *);
+static_assert (common_type ({ ^^const decltype (nullptr) &, ^^int * }) == ^^int *);
+static_assert (common_type ({ ^^decltype (nullptr), ^^const volatile int * }) == ^^const volatile int *);
+static_assert (common_type ({ ^^decltype (nullptr), ^^int (B::*) () }) == ^^int (B::*) ());
+static_assert (common_type ({ ^^decltype (nullptr), ^^int (B::*) () const }) == ^^int (B::*) () const);
+static_assert (common_type ({ ^^decltype (nullptr), ^^const int B::* }) == ^^const int B::*);
+static_assert (common_type ({ ^^Abstract &, ^^Abstract & }) == ^^Abstract);
+static_assert (common_type ({ ^^Ukn &, ^^Ukn & }) == ^^Ukn);
+static_assert (common_type ({ ^^ImplicitTo<B &>, ^^B & }) == ^^B);
+static_assert (common_type ({ ^^ImplicitTo<B &> &, ^^B && }) == ^^B);
+static_assert (common_type ({ ^^UConv1, ^^const Abstract * & }) == ^^const Abstract *);
+static_assert (common_type ({ ^^UConv1, ^^UConv2 }) == ^^Abstract *);
+static_assert (common_type ({ ^^UConv1 &, ^^UConv2 & }) == ^^Abstract *);
+static_assert (common_type ({ ^^Abstract &&, ^^Abstract && }) == ^^Abstract);
+static_assert (common_type ({ ^^const Abstract &&, ^^const Abstract && }) == ^^Abstract);
+static_assert (common_type ({ ^^volatile Abstract &&, ^^volatile Abstract && }) == ^^Abstract);
+static_assert (common_type ({ ^^Ukn &&, ^^Ukn && }) == ^^Ukn);
+static_assert (common_type ({ ^^const Ukn &&, ^^const Ukn && }) == ^^Ukn);
+static_assert (common_type ({ ^^volatile Ukn &&, ^^volatile Ukn && }) == ^^Ukn);
+static_assert (common_type ({ ^^X1, ^^X2 }) == ^^RX12);
+static_assert (common_type ({ ^^const X1, ^^X2 }) == ^^RX12);
+static_assert (common_type ({ ^^X1 &, ^^const X2 }) == ^^RX12);
+static_assert (common_type ({ ^^const X1 &, ^^const X2 & }) == ^^RX12);
+static_assert (common_type ({ ^^X2, ^^X1 }) == ^^RX21);
+static_assert (common_type ({ ^^X1, ^^X2, ^^X1 }) == ^^Y1);
+static_assert (common_type ({ ^^X2, ^^X1, ^^X1 }) == ^^Y3);
+static_assert (common_type ({ ^^X1, ^^X1, ^^X2 }) == ^^RX12);
+static_assert (common_type ({ ^^X1 &, ^^const X1, ^^const X2 && }) == ^^RX12);
+static_assert (common_type ({ ^^X1, ^^X1, ^^X2, ^^X1 }) == ^^Y1);
+static_assert (!has_common_type ({ ^^::, ^^int }));
+static_assert (!has_common_type ({ ^^int, ^^int, ^^std }));
diff --git a/gcc/testsuite/g++.dg/reflect/compare1.C b/gcc/testsuite/g++.dg/reflect/compare1.C
new file mode 100644 (file)
index 0000000..e54902b
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test comparison of reflections.  Valid uses.
+
+#include <meta>
+
+namespace N {
+  namespace M {
+  }
+}
+
+namespace NN = N;
+namespace NM = N::M;
+
+static_assert(^^int == ^^int);
+static_assert(^^int != ^^const int);
+static_assert(^^int != ^^int &);
+static_assert(^^int const == ^^const int);
+
+static_assert(^^char == ^^char);
+static_assert(^^char != ^^unsigned char);
+static_assert(^^char != ^^signed char);
+
+static_assert(^^:: == ^^::);
+static_assert(^^:: != ^^N);
+static_assert(^^N == ^^N);
+static_assert(^^N != ^^N::M);
+static_assert(^^N != ^^NN);
+static_assert(^^N::M == ^^N::M);
+static_assert(^^N::M != ^^NM);
+
+using Alias = int;
+static_assert(^^int != ^^Alias);
+static_assert(^^int == std::meta::dealias (^^Alias));
+
+namespace AliasNS = ::std;
+static_assert(^^::std != ^^AliasNS);
+static_assert(^^:: == parent_of(^^::std));
diff --git a/gcc/testsuite/g++.dg/reflect/compare10.C b/gcc/testsuite/g++.dg/reflect/compare10.C
new file mode 100644 (file)
index 0000000..7f63b79
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test comparing COMPONENT_REFs.
+
+#include <meta>
+
+struct S { int x, y; };
+
+consteval auto f(S &s) {
+  return std::meta::reflect_object(s.x);
+}
+
+S s;
+int& x = s.x;
+static_assert(object_of(^^x) == f(s));
diff --git a/gcc/testsuite/g++.dg/reflect/compare2.C b/gcc/testsuite/g++.dg/reflect/compare2.C
new file mode 100644 (file)
index 0000000..9e2816f
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test comparison of reflections.  Invalid uses.
+
+consteval void
+f ()
+{
+  bool b = ^^int > ^^int;   // { dg-error "invalid operands of types .std::meta::info. and .std::meta::info. to binary" }
+  b = ^^int >= ^^int;      // { dg-error "invalid operands of types .std::meta::info. and .std::meta::info. to binary" }
+  b = ^^int <= ^^int;      // { dg-error "invalid operands of types .std::meta::info. and .std::meta::info. to binary" }
+  +^^int;                  // { dg-error "wrong type argument to unary plus" }
+  !^^int;                  // { dg-error "could not convert .\\^\\^int. from .std::meta::info. to .bool." }
+                           // { dg-error "in argument to unary" "" { target *-*-* } .-1 }
+  ~^^int;                  // { dg-error "wrong type argument to bit-complement" }
+  *^^int;                  // { dg-error "invalid type argument of unary" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/compare3.C b/gcc/testsuite/g++.dg/reflect/compare3.C
new file mode 100644 (file)
index 0000000..2a49773
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test comparison of reflections.
+
+namespace N {
+namespace foo {
+struct foo {
+  static_assert(^^foo == ^^::N::foo::foo);
+};
+static_assert(^^foo == ^^::N::foo::foo);
+}
+
+namespace tfoo {
+template <typename T> struct tfoo {
+  static_assert(^^tfoo == ^^tfoo<T>);
+};
+static_assert(^^tfoo == ^^::N::tfoo::tfoo);
+
+tfoo<int> instantiation;
+}
+
+static_assert(^^foo == ^^::N::foo);
+static_assert(^^tfoo == ^^::N::tfoo);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/compare4.C b/gcc/testsuite/g++.dg/reflect/compare4.C
new file mode 100644 (file)
index 0000000..f3b41c5
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test comparison of reflections.
+
+using info = decltype(^^void);
+
+int x;
+void fn();
+struct S {
+  int x;
+  static constexpr int s_x = 11;
+  void fn();
+  static void s_fn();
+};
+enum Enum { A, B, C };
+enum class EnumCls { A, B, C };
+
+static_assert(&[:^^x:] == &x);
+static_assert([:^^fn:] == fn);
+
+static_assert(&[:^^S::x:] == &S::x);
+static_assert(&[:^^S::s_x:] == &S::s_x);
+static_assert(&[:^^S::fn:] == &S::fn);
+static_assert([:^^S::s_fn:] == S::s_fn);
+
+static_assert([:^^Enum::B:] == Enum::B);
+static_assert([:^^EnumCls::B:] == EnumCls::B);
diff --git a/gcc/testsuite/g++.dg/reflect/compare5.C b/gcc/testsuite/g++.dg/reflect/compare5.C
new file mode 100644 (file)
index 0000000..f8aa7bb
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test splicing of explicit object member functions.
+
+struct Y {
+    int g(this Y const&, int, int);
+};
+static_assert(&Y::g == &[:^^Y::g:]);
diff --git a/gcc/testsuite/g++.dg/reflect/compare6.C b/gcc/testsuite/g++.dg/reflect/compare6.C
new file mode 100644 (file)
index 0000000..4dd10eb
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+enum Enum { A, B, C };
+enum class EnumCls { A, B, C };
+
+constexpr info rB = ^^B, rClsB = ^^EnumCls::B;
+static_assert(rB != rClsB);
+static_assert(int([:rB:]) == int([:rClsB:]));
+static_assert(static_cast<Enum>([:rClsB:]) == B);
diff --git a/gcc/testsuite/g++.dg/reflect/compare7.C b/gcc/testsuite/g++.dg/reflect/compare7.C
new file mode 100644 (file)
index 0000000..5c67c57
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Reflection of a reflection.
+
+using info = decltype(^^void);
+constexpr info r1 = ^^int;
+constexpr info r2 = ^^int;
+constexpr info rr1 = ^^r1;
+constexpr info rr2 = ^^r2;
+static_assert (r1 == ^^int);
+static_assert (r1 == r2);
+static_assert (r1 != rr1);
+static_assert (r1 != rr2);
+static_assert (^^r1 != ^^r2);
+static_assert (^^int != rr1);
+static_assert (^^r1 == rr1);
+static_assert (rr2 != rr1);
+static_assert (rr2 != ^^r1);
+static_assert (rr2 == ^^r2);
+static_assert (rr1 != ^^r2);
diff --git a/gcc/testsuite/g++.dg/reflect/compare8.C b/gcc/testsuite/g++.dg/reflect/compare8.C
new file mode 100644 (file)
index 0000000..6ea6c83
--- /dev/null
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Reflection of a reflection.
+
+template <int N>
+void
+foo ()
+{
+}
+
+template <typename ... T>
+void
+bar ()
+{
+}
+
+template <int N>
+struct R {};
+
+template <typename ... T>
+struct S {};
+
+using info = decltype (^^int);
+constexpr info r1 = ^^foo;
+constexpr info r2 = ^^foo <42>;
+constexpr info r3 = ^^foo <43>;
+constexpr info r4 = ^^R;
+constexpr info r5 = ^^R <42>;
+constexpr info r6 = ^^R <43>;
+constexpr info r7 = ^^bar;
+constexpr info r8 = ^^bar <>;
+constexpr info r9 = ^^bar <int>;
+constexpr info r10 = ^^bar <int, int>;
+constexpr info r11 = ^^bar <int, int, long>;
+constexpr info r12 = ^^S;
+constexpr info r13 = ^^S <>;
+constexpr info r14 = ^^S <int>;
+constexpr info r15 = ^^S <int, int>;
+constexpr info r16 = ^^S <int, int, long>;
+static_assert (r1 == ^^foo);
+static_assert (r2 == ^^foo <42>);
+static_assert (r3 == ^^foo <43>);
+static_assert (r4 == ^^R);
+static_assert (r5 == ^^R <42>);
+static_assert (r6 == ^^R <43>);
+static_assert (r7 == ^^bar);
+static_assert (r8 == ^^bar <>);
+static_assert (r9 == ^^bar <int>);
+static_assert (r10 == ^^bar <int, int>);
+static_assert (r11 == ^^bar <int, int, long>);
+static_assert (r12 == ^^S);
+static_assert (r13 == ^^S <>);
+static_assert (r14 == ^^S <int>);
+static_assert (r15 == ^^S <int, int>);
+static_assert (r16 == ^^S <int, int, long>);
+static_assert (r1 != r2);
+static_assert (r2 != r3);
+static_assert (r4 != r5);
+static_assert (r5 != r6);
+static_assert (r7 != r8);
+static_assert (r8 != r9);
+static_assert (r9 != r10);
+static_assert (r10 != r11);
+static_assert (r12 != r13);
+static_assert (r13 != r14);
+static_assert (r14 != r15);
+static_assert (r15 != r16);
diff --git a/gcc/testsuite/g++.dg/reflect/compare9.C b/gcc/testsuite/g++.dg/reflect/compare9.C
new file mode 100644 (file)
index 0000000..7481586
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test comparison of reflections.
+
+#include <meta>
+#include <ranges>
+
+static union { int a; };
+struct S { void foo () {} };
+template <typename T>
+consteval auto bar () { int v = 42; return parent_of (^^v); }
+template <typename T>
+consteval std::meta::info baz () { int v = 42; return parent_of (^^v); }
+
+constexpr auto ctx = std::meta::access_context::unchecked ();
+// TODO: These should work
+//static_assert (^^a == members_of (parent_of (^^a), ctx)[0]);
+//static_assert (^^S::~S == (members_of (^^S, ctx) | std::views::filter (std::meta::is_destructor) | std::ranges::to <std::vector> ())[0]);
+static_assert (^^S::foo == members_of (^^S, ctx)[0]);
+static_assert (^^bar <int> == bar <int> ());
+constexpr auto b = ^^bar <long>;
+static_assert (b == bar <long> ());
+static_assert (^^baz <int> == baz <int> ());
+constexpr auto c = ^^baz <long>;
+static_assert (c == baz <long> ());
diff --git a/gcc/testsuite/g++.dg/reflect/compat1.C b/gcc/testsuite/g++.dg/reflect/compat1.C
new file mode 100644 (file)
index 0000000..8cb9f9a
--- /dev/null
@@ -0,0 +1,13 @@
+// C++26 P2996R13 - Reflection for C++26
+// [diff.cpp23.dcl.dcl] tests
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct C { int operator ^ (int); };
+int operator ^ (int (C::*p) (int), C);
+int i = &C::operator ^^ C {};  // { dg-error "expected type-specifier before '\\\^\\\^' token" "" { target c++26 } }
+
+struct [[using CC:]] C;                // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+                               // { dg-error "expected '\\\]' before 'CC'" "" { target c++26 } .-1 }
+                               // { dg-error "expected identifier before ';' token" "" { target c++26 } .-2 }
+struct [[using DD: ]] D;       // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
diff --git a/gcc/testsuite/g++.dg/reflect/complete1.C b/gcc/testsuite/g++.dg/reflect/complete1.C
new file mode 100644 (file)
index 0000000..269a209
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test which constructs or metafunctions implicitly instantiate.
+
+#include <meta>
+
+template <int N>
+struct S {
+  static_assert (N < 42);      // { dg-line static_assert }
+};
+// { dg-error "static assertion failed" "" { target *-*-* } static_assert }
+// { dg-bogus "the comparison reduces to '\\\(42 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(43 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(44 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-bogus "the comparison reduces to '\\\(45 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-bogus "the comparison reduces to '\\\(46 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(47 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(48 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(49 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(50 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(51 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(52 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(53 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(54 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(55 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(56 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(57 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-bogus "the comparison reduces to '\\\(58 < 42\\\)'" "" { target *-*-* } static_assert }
+// { dg-message "the comparison reduces to '\\\(59 < 42\\\)'" "" { target *-*-* } static_assert }
+
+S<0> s1;
+constexpr auto a = ^^S<42>;
+bool b = is_complete_type (^^S<43>);
+bool c = is_enumerable_type (^^S<44>);
+constexpr auto d = data_member_spec (^^S<45>, { .name = "_" });
+consteval {
+  define_aggregate (^^S<46>, { data_member_spec (^^int, { .name = "_" }) });
+}
+auto e = size_of (^^S<47>);
+auto f = bit_size_of (^^S<48>);
+int g;
+constexpr auto h = annotations_of_with_type (^^g, ^^S<49>);
+constexpr auto ctx = std::meta::access_context::current ();
+auto i = members_of (^^S<50>, ctx).size ();
+auto j = bases_of (^^S<51>, ctx).size ();
+auto k = static_data_members_of (^^S<52>, ctx).size ();
+auto l = nonstatic_data_members_of (^^S<53>, ctx).size ();
+auto m = subobjects_of (^^S<54>, ctx).size ();
+bool n = has_inaccessible_nonstatic_data_members (^^S<55>, ctx);
+bool o = has_inaccessible_bases (^^S<56>, ctx);
+bool p = has_inaccessible_subobjects (^^S<57>, ctx);
+consteval {
+  define_aggregate (^^S<58>, { data_member_spec (^^S<59>, { .name = "_" }) });
+}
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of1.C b/gcc/testsuite/g++.dg/reflect/constant_of1.C
new file mode 100644 (file)
index 0000000..f467e60
--- /dev/null
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr int x = 0;
+constexpr int y = 0;
+
+// OK, x and y are different variables, so their reflections compare different
+static_assert (^^x != ^^y);
+
+// OK, both constant_of(^^x) and constant_of(^^y) represent the value 0
+static_assert (constant_of (^^x) == constant_of (^^y));
+
+// OK, likewise
+static_assert (constant_of (^^x) == reflect_constant (0));
+
+struct S { int m; };
+constexpr S s {42};
+static_assert (is_object (constant_of (^^s)) && is_object (reflect_object (s)));
+// OK, template parameter object that is template-argument-equivalent to s is
+// a different object than s
+static_assert (constant_of (^^s) != reflect_object (s));
+static_assert (constant_of (^^s) == constant_of (reflect_object (s)));
+constexpr auto r1 = reflect_constant (s);
+constexpr auto r2 = reflect_object (s);
+static_assert (is_object (r1) && is_object (r2));
+static_assert (r1 != r2);
+static_assert (r1 == constant_of (r2));
+
+consteval info fn() {
+  constexpr int x = 42;
+  return ^^x;
+}
+
+// error: x is outside its lifetime
+constexpr info r = constant_of (fn ());
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of2.C b/gcc/testsuite/g++.dg/reflect/constant_of2.C
new file mode 100644 (file)
index 0000000..dae41c9
--- /dev/null
@@ -0,0 +1,87 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr int i = 1;
+static_assert (constant_of (^^i) == constant_of (object_of (^^i)));
+const int &r = i;
+static_assert (constant_of (^^i) == reflect_constant (1));
+static_assert (object_of (^^r) == object_of (^^i));
+
+const int constGlobal = 11;
+constexpr auto rref = reflect_object (constGlobal);
+
+static_assert (constant_of (^^constGlobal) != ^^constGlobal);
+static_assert ([:constant_of (^^constGlobal):] == 11);
+static_assert ([:constant_of (rref):] == 11);
+static_assert (constant_of (^^constGlobal) == constant_of (rref));
+static_assert (constant_of (^^constGlobal) == reflect_constant (11));
+
+enum Enum { A };
+static constexpr Enum e = A;
+
+enum EnumCls { CA };
+static constexpr EnumCls ce = CA;
+
+static_assert (constant_of (^^A) != constant_of (^^CA));
+static_assert (constant_of (^^A) != reflect_constant (0));
+static_assert (constant_of (^^A) == reflect_constant (Enum (0)));
+
+static_assert (constant_of (^^A) != reflect_constant (EnumCls (0)));
+static_assert (constant_of (^^e) != reflect_constant (0));
+static_assert (constant_of (^^e) == reflect_constant (Enum (0)));
+static_assert (constant_of (^^e) != reflect_constant (EnumCls (0)));
+static_assert (constant_of (^^ce) != reflect_constant (0));
+static_assert (constant_of (^^ce) != reflect_constant (Enum (0)));
+static_assert (constant_of (^^ce) == reflect_constant (EnumCls (0)));
+
+using Alias1 = int;
+constexpr Alias1 a1 = 3;
+// ??? In clang++, type_of here produces "^^const int".  But
+// <https://eel.is/c++draft/meta.reflection#queries-2> doesn't say anything
+// about dealias.  On the other side it in all cases talks about
+// reflection of types and type aliases aren't types, just entities
+// with underlying entity thereof.
+static_assert (type_of (^^a1) == ^^const int);
+static_assert (type_of (constant_of (^^a1)) == ^^int);
+
+struct S{};
+using Alias2 = S;
+constexpr Alias2 a2 {};
+// And here maybe it should be ^^S instead of ^^Alias2.
+static_assert (type_of (^^a2) == ^^const Alias2);
+// constant_of produces _ZTAXtl1SEE whose type is "const S".
+static_assert (type_of (constant_of (^^a2)) == ^^const S);
+
+constexpr const int &ref = a1;
+static_assert (type_of (constant_of (^^ref)) == ^^int);
+
+constexpr std::pair<std::pair<int, bool>, int> p = {{1, true}, 2};
+static_assert (type_of (constant_of (reflect_object (p.first))) == ^^const std::pair<int, bool>);
+constexpr info rfirst = reflect_object (p.first);
+static_assert (is_object (rfirst) && !is_value (rfirst));
+static_assert (type_of (rfirst) == ^^const std::pair<int, bool>);
+static_assert (rfirst != reflect_constant (std::make_pair (1, true)));
+
+constexpr info rvfirst = constant_of (rfirst);
+static_assert (is_object (rvfirst) && !is_value (rvfirst));
+static_assert (type_of (rvfirst) == ^^const std::pair<int, bool>);
+static_assert (rvfirst == reflect_constant (std::make_pair (1, true)));
+static_assert ([:rvfirst:].first == 1);
+
+constexpr int g = 3;
+consteval info
+fn ()
+{
+  const int &rg = g;
+  static_assert ([:constant_of(^^rg):] == 3);
+  return constant_of (^^rg);
+}
+static_assert ([:fn ():] == 3);
+
+constexpr int foo () { return 42; }
+static_assert (constant_of (^^foo) == reflect_function (foo));
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of3.C b/gcc/testsuite/g++.dg/reflect/constant_of3.C
new file mode 100644 (file)
index 0000000..e386d26
--- /dev/null
@@ -0,0 +1,60 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+const int K = 0;
+consteval const int &fn() { return K; }
+
+constexpr auto v = constant_of (reflect_constant (fn ()));
+static_assert (is_value (v) && !is_object (v));
+static_assert (type_of (v) == ^^int);
+static_assert (!is_variable (v));
+static_assert (v == reflect_constant (0));
+
+template<int N>
+constexpr int V = N;
+
+struct W {
+  static constexpr int I = 42;
+};
+
+// clang++ doesn't accept this.  That seems wrong.
+constexpr auto v2 = constant_of (^^V<3>);
+static_assert (is_value (v2) && !is_object (v2));
+static_assert (type_of (v2) == ^^int);
+static_assert (!is_variable (v2));
+static_assert (v2 == reflect_constant (3));
+
+constexpr auto v3 = constant_of (^^W::I);
+static_assert (is_value (v3) && !is_object (v3));
+static_assert (type_of (v3) == ^^int);
+static_assert (!is_variable (v3));
+static_assert (v3 == reflect_constant (42));
+
+constexpr auto v4 = constant_of (reflect_constant (42));
+static_assert (is_value (v4) && !is_object (v4));
+static_assert (type_of (v4) == ^^int);
+static_assert (!is_variable (v4));
+static_assert (v4 == reflect_constant (42));
+
+template<info R>
+void
+f ()
+{
+  constexpr auto v = constant_of (R);
+  static_assert (is_value (v) && !is_object (v));
+  static_assert (type_of (v) == ^^int);
+  static_assert (!is_variable (v));
+  static_assert (v == reflect_constant (42));
+}
+
+void
+g ()
+{
+  constexpr int b = 42;
+  f<^^b>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of4.C b/gcc/testsuite/g++.dg/reflect/constant_of4.C
new file mode 100644 (file)
index 0000000..d08d4a3
--- /dev/null
@@ -0,0 +1,50 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  int k;
+  int bf:32;
+};
+
+constexpr info null_reflection;
+static union { int m; };
+namespace NS { }
+using T = int;
+
+consteval bool
+constant_of_ok (info r)
+{
+  try { constant_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!constant_of_ok (^^S::k));
+static_assert (!constant_of_ok (^^m));
+static_assert (!constant_of_ok (^^int));
+static_assert (!constant_of_ok (^^NS));
+static_assert (!constant_of_ok (^^S::bf));
+static_assert (!constant_of_ok (null_reflection));
+static_assert (!constant_of_ok (^^T));
+
+template<typename>
+struct X { };
+static_assert (!constant_of_ok (^^X));
+static_assert (!constant_of_ok (^^X<int>));
+
+template<int N>
+constexpr int bar () { return N; }
+static_assert (!constant_of_ok (^^bar));
+
+template<int N>
+constexpr int V = N;
+
+static_assert (!constant_of_ok (^^V));
+
+int x = 10;
+constexpr auto rx = constant_of (^^x); // { dg-error "not usable in a constant expression" }
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of5.C b/gcc/testsuite/g++.dg/reflect/constant_of5.C
new file mode 100644 (file)
index 0000000..07187e9
--- /dev/null
@@ -0,0 +1,86 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+[[=1, =1, =2, =1.0f]] int i;
+static_assert (type_of (constant_of (annotations_of (^^i)[0])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^i)[1])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^i)[2])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^i)[3])) == ^^float);
+
+[[=1, =1, =2, =1.0f]] void fn();
+static_assert (type_of (constant_of (annotations_of (^^fn)[0])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^fn)[1])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^fn)[2])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^fn)[3])) == ^^float);
+
+struct [[=3, =3, =4, =2.0f]] S;
+static_assert (type_of (constant_of (annotations_of (^^S)[0])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^S)[1])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^S)[2])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^S)[3])) == ^^float);
+#if 0
+template <typename> struct [[=5, =5, =6, =3.0f]] TCls {};
+// TODO Should work but we don't propagate the annotations correctly to the
+// instantiation.  See also the TODO in annotations3.C.
+static_assert (type_of (constant_of (annotations_of (^^TCls<int>)[0])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^TCls<int>)[1])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^TCls<int>)[2])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^TCls<int>)[3])) == ^^float);
+#endif
+template <typename> [[=5, =5, =6, =3.0f]] void TFn();
+static_assert (type_of (constant_of (annotations_of (^^TFn<int>)[0])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^TFn<int>)[1])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^TFn<int>)[2])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^TFn<int>)[3])) == ^^float);
+namespace [[=7, =7, =8, =4.0f]] NS {}
+static_assert (type_of (constant_of (annotations_of (^^NS)[0])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^NS)[1])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^NS)[2])) == ^^int);
+static_assert (type_of (constant_of (annotations_of (^^NS)[3])) == ^^float);
+
+constexpr struct X {} x;
+[[=x]] void foo ();
+
+// TODO clang++ says ^^X, we say ^^const X.
+static_assert (type_of (annotations_of (^^foo)[0]) == ^^const X);
+static_assert (type_of (constant_of (annotations_of (^^foo)[0])) == ^^const X);
+
+template<info R>
+[[=[:constant_of (annotations_of (R)[0]):]]] void bar();
+
+template<info R>
+struct [[=[:constant_of (annotations_of (R)[0]):]]] Y {};
+
+static_assert (extract<int>(annotations_of (^^bar<^^::fn>)[0]) == 1);
+//static_assert (extract<int>(annotations_of (^^Y<^^::S>)[0]) == 3);
+
+struct [[=42, =42.0f]] S1;
+struct [[=42, =40]] S2;
+
+static_assert (annotations_of (^^S1)[0] == annotations_of (^^S1)[0]);
+static_assert (annotations_of (^^S1)[0] != annotations_of (^^S2)[0]);
+static_assert (annotations_of (^^S1)[0] != annotations_of (^^S1)[1]);
+
+static_assert (constant_of (annotations_of (^^S1)[0]) == reflect_constant (42));
+static_assert (constant_of (annotations_of (^^S1)[0]) == constant_of (annotations_of (^^S2)[0]));
+
+// A test from clang.
+struct test_struct {};
+constexpr test_struct test;
+
+[[=test]] void func() {}
+[[=1]] void func2() {}
+
+constexpr auto func_first = constant_of (annotations_of (^^func)[0]);
+constexpr auto func2_first = constant_of (annotations_of (^^func2)[0]);
+
+static_assert (constant_of (^^test) == reflect_constant (test));
+// TODO We evaluate the decltype to test_struct.
+//static_assert (std::same_as<decltype([:func_first:]), const test_struct &>);
+static_assert (func2_first == reflect_constant (1));
+static_assert (func_first == reflect_constant (test));
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of6.C b/gcc/testsuite/g++.dg/reflect/constant_of6.C
new file mode 100644 (file)
index 0000000..6db96c0
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+[[=1, =1, =2, =1.0f]] void fn();
+struct [[=3, =3, =4, =2.0f]] S;
+
+template<info R>
+[[=[:constant_of (annotations_of (R)[0]):]]] void bar();
+
+template<info R>
+struct [[=[:constant_of (annotations_of (R)[0]):]]] Y {};
+
+constexpr auto y = constant_of (annotations_of (^^bar<^^::fn>)[0]);
+constexpr auto z = constant_of (annotations_of (^^Y<^^::S>)[0]);
+// { dg-error "call to non-.constexpr." "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of7.C b/gcc/testsuite/g++.dg/reflect/constant_of7.C
new file mode 100644 (file)
index 0000000..1958fdc
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr int arr[] = { 1, 2, 3, 4 };
+constexpr auto r = constant_of (^^arr);
+static_assert (!is_value (r) && !is_object (r));
+static_assert (*[:r:] == 1);
+static_assert ([:r:][0] == 1);
+static_assert ([:r:][1] == 2);
+static_assert ([:r:][2] == 3);
+static_assert ([:r:][3] == 4);
+static_assert (type_of (r) == ^^const int [4]);
+constexpr auto q = reflect_constant ([: ^^arr :]);
+static_assert (type_of (q) == ^^const int *);
+static_assert ([:q:][0] == 1);
+static_assert ([:q:][1] == 2);
+static_assert ([:q:][2] == 3);
+static_assert ([:q:][3] == 4);
+
+using U = int;
+constexpr U arr2[] = { 5, 6, 7, 8 };
+constexpr auto r2 = constant_of (^^arr2);
+static_assert (!is_value (r2) && !is_object (r2));
+static_assert ([:r2:][0] == 5);
+static_assert ([:r2:][1] == 6);
+static_assert ([:r2:][2] == 7);
+static_assert ([:r2:][3] == 8);
+// ??? Probably should be const int *.
+static_assert (type_of (r2) == ^^const U [4]);
+constexpr auto q2 = reflect_constant ([: ^^arr2 :]);
+static_assert (type_of (q2) == ^^const U *);
+static_assert ([:q2:][0] == 5);
+static_assert ([:q2:][1] == 6);
+static_assert ([:q2:][2] == 7);
+static_assert ([:q2:][3] == 8);
+
+struct S { int m; };
+constexpr S arr3[] = { S{1}, S{2}, S{3} };
+constexpr auto r3 = constant_of (^^arr3);
+static_assert (!is_value (r3) && !is_object (r3));
+static_assert ([:r3:][0].m == 1);
+static_assert ([:r3:][1].m == 2);
+static_assert ([:r3:][2].m == 3);
+static_assert (type_of (r3) == ^^const S [3]);
+constexpr auto q3 = reflect_constant ([: ^^arr3 :]);
+static_assert (type_of (q3) == ^^const S *);
+static_assert ([:q3:][0].m == 1);
+static_assert ([:q3:][1].m == 2);
+static_assert ([:q3:][2].m == 3);
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of8.C b/gcc/testsuite/g++.dg/reflect/constant_of8.C
new file mode 100644 (file)
index 0000000..bd2e4ce
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of, CWG 3111.
+
+#include <meta>
+using namespace std::meta;
+
+constexpr int is[] = {1, 2, 3};
+constexpr info r = reflect_constant_array (is);
+static_assert (constant_of (^^is) == r);
+
+constexpr int mis[2][2] = {{1, 2}, {3, 4}};
+// LWG4483 Multidimensional arrays
+// constexpr info mr = reflect_constant_array (mis);
+// static_assert (constant_of (^^mis) == mr);
+
diff --git a/gcc/testsuite/g++.dg/reflect/constant_of9.C b/gcc/testsuite/g++.dg/reflect/constant_of9.C
new file mode 100644 (file)
index 0000000..5cbc409
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::constant_of, CWG 3111.
+
+#include <meta>
+using namespace std::meta;
+
+void f() {}
+static_assert (constant_of (^^f) == reflect_function (f));
diff --git a/gcc/testsuite/g++.dg/reflect/crash1.C b/gcc/testsuite/g++.dg/reflect/crash1.C
new file mode 100644 (file)
index 0000000..c93b6e1
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct free_entry {
+  free_entry *next;
+} first_free_entry;
+
+struct A;
+struct B {
+  A *a;
+} BT;
+
+struct A {
+  B b;
+};
diff --git a/gcc/testsuite/g++.dg/reflect/crash10.C b/gcc/testsuite/g++.dg/reflect/crash10.C
new file mode 100644 (file)
index 0000000..0584584
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S { };
+using X = S;
+
+template <auto V> constexpr int e = [:V:];  // { dg-error "expected a reflection of an expression instead of type .X." }
+template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a reflection of an expression instead of type .X." }
+constexpr auto h = ^^X;
+constexpr auto i = e<([:^^h:])>;
+constexpr auto j = e2<^^X>;
diff --git a/gcc/testsuite/g++.dg/reflect/crash11.C b/gcc/testsuite/g++.dg/reflect/crash11.C
new file mode 100644 (file)
index 0000000..3aef5d0
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<typename T>
+struct Z {};
+
+struct S {
+  static constexpr auto r = ^^Z;
+};
+
+template<typename T, auto R>
+void
+g ()
+{
+  template [: R :]<int> c0; // { dg-error "not a function template|expected" }
+  template [: T::r :]<int> c1;  // { dg-error "not a function template|expected" }
+}
+
+void
+f ()
+{
+  g<S, ^^Z>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash12.C b/gcc/testsuite/g++.dg/reflect/crash12.C
new file mode 100644 (file)
index 0000000..a234c95
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct X { constexpr operator std::meta::info(); }; // { dg-error "function of consteval-only type" }
+// { dg-warning "used but never defined" "" { target *-*-* } .-1 }
+constexpr auto r = std::meta::type_of (X{}); // { dg-error "used before its definition" }
diff --git a/gcc/testsuite/g++.dg/reflect/crash13.C b/gcc/testsuite/g++.dg/reflect/crash13.C
new file mode 100644 (file)
index 0000000..50779e8
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+struct S {
+  int j;
+};
+
+template <info R>
+consteval int fn() {
+  auto x = [:R:]; // { dg-error "cannot implicitly reference a class member" }
+  return true;
+}
+static_assert (fn<^^S::j>());
diff --git a/gcc/testsuite/g++.dg/reflect/crash14.C b/gcc/testsuite/g++.dg/reflect/crash14.C
new file mode 100644 (file)
index 0000000..e965413
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+constexpr int i = 0;
+const int p = ++std::meta::extract<const int &>(^^i); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/reflect/crash15.C b/gcc/testsuite/g++.dg/reflect/crash15.C
new file mode 100644 (file)
index 0000000..74f3df9
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -g" }
+
+void
+foo ()
+{
+  constexpr auto r = ^^int;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash16.C b/gcc/testsuite/g++.dg/reflect/crash16.C
new file mode 100644 (file)
index 0000000..9d3b367
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype (^^int);
+
+struct A { int x, y; };
+struct B { info x, y; };
+struct C { int x; info y; };
+
+void
+foo ()
+{
+  constexpr A a { 3, 4 };
+  constexpr auto [ax, ay] = a;
+  static_assert (ax == 3);
+  static_assert (ay == 4);
+
+  constexpr B b { ^^::, ^^int };
+  constexpr auto [bx, by] = b;
+  static_assert (b.x == ^^::);
+  static_assert (b.y == ^^int);
+  static_assert (bx == ^^::);
+  static_assert (by == ^^int);
+
+  constexpr C c { 4, ^^:: };
+  constexpr auto [cx, cy] = c;
+  static_assert (c.x == 4);
+  static_assert (c.y == ^^::);
+  static_assert (cx == 4);
+  static_assert (cy == ^^::);
+
+  constexpr int d[] { 6, 7 };
+  constexpr auto [dx, dy] = d;
+  static_assert (dx == 6);
+  static_assert (dy == 7);
+
+  constexpr info e[] { ^^::, ^^int };
+  constexpr auto [ex, ey] = e;
+  static_assert (e[0] == ^^::);
+  static_assert (e[1] == ^^int);
+  static_assert (ex == ^^::);
+  static_assert (ey == ^^int);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash17.C b/gcc/testsuite/g++.dg/reflect/crash17.C
new file mode 100644 (file)
index 0000000..c6344ce
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+template <typename>
+void
+foo ()
+{
+  constexpr int i = [: reflect_constant (5) :];
+  constexpr info f = reflect_constant_array (std::vector { 1, 2, 3 });
+  constexpr auto &arr = [: f :];
+  constexpr auto &arr2 = [: reflect_constant_array (std::vector { 1, 2, 3 }) :];
+}
+
+void
+bar ()
+{
+  constexpr auto &arr = [: reflect_constant_array (std::vector { 1, 2, 3 }) :];   
+}
+
+int
+main ()
+{
+  foo <int> ();
+  bar ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash18.C b/gcc/testsuite/g++.dg/reflect/crash18.C
new file mode 100644 (file)
index 0000000..3fe0873
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+// We also test this elsewhere but we only crashed when there were no other
+// errors.
+void fn (decltype(^^::)) {} // { dg-error "function of consteval-only type must be declared .consteval." }
diff --git a/gcc/testsuite/g++.dg/reflect/crash2.C b/gcc/testsuite/g++.dg/reflect/crash2.C
new file mode 100644 (file)
index 0000000..83927fb
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  template<typename T>
+  static void tfn () { }
+  template<typename T>
+  static constexpr int var = 1;
+};
+
+template<typename T>
+void
+f ()
+{
+  // Parsed as "S::tfn < S".
+  [: ^^T :]::tfn<[: ^^T :]>(); // { dg-error "expected primary-expression|expected a reflection of an expression instead of type .S." }
+// { dg-warning "expected .template. keyword" "" { target *-*-* } .-1 }
+  int i = [: ^^T :]::var<int>; // { dg-error "missing|expected" }
+}
+
+void
+g ()
+{
+  f<S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash3.C b/gcc/testsuite/g++.dg/reflect/crash3.C
new file mode 100644 (file)
index 0000000..51cf3d8
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template <auto V> constexpr int e = [:V:];  // { dg-error "expected a reflection of an expression instead of type .int." }
+template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a reflection of an expression instead of type .int." }
+constexpr auto h = ^^int;
+constexpr auto i = e<([:^^h:])>;
+constexpr auto j = e2<^^int>;
diff --git a/gcc/testsuite/g++.dg/reflect/crash4.C b/gcc/testsuite/g++.dg/reflect/crash4.C
new file mode 100644 (file)
index 0000000..acbdbe7
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  int j;
+  static int i;
+} s;
+
+int X;
+
+// Typo: should have been ^^s.
+decltype([: ^^S :].j) x;  // { dg-error "expected a reflection of an expression" }
+decltype([: ^^S :].i) z;  // { dg-error "expected a reflection of an expression" }
+decltype([: ^^X :].x) y;  // { dg-error "request for member|expected" }
+decltype([: ^^:: :].x w;  // { dg-error "expected a reflection of an expression" }
diff --git a/gcc/testsuite/g++.dg/reflect/crash5.C b/gcc/testsuite/g++.dg/reflect/crash5.C
new file mode 100644 (file)
index 0000000..a2479d6
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  int j;
+  int k;
+};
+
+// Forgot to define info and we crashed :-(
+template <info R>   // { dg-error ".info. has not been declared" }
+consteval int fn() {
+  S s = {11, 13};
+  return s.[:R:];   // { dg-error ".R. was not declared" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash6.C b/gcc/testsuite/g++.dg/reflect/crash6.C
new file mode 100644 (file)
index 0000000..13ce48a
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+template<typename T>
+constexpr T magic = 1234;
+
+template<info R>
+void
+f ()
+{
+  [:R:] r; // { dg-error "expected" }
+  [:R:]<int> r; // { dg-error "reflection .\\\[: R :\\\]<int>. not usable in a splice expression" }
+}
+
+void
+g ()
+{
+  f<^^magic>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash7.C b/gcc/testsuite/g++.dg/reflect/crash7.C
new file mode 100644 (file)
index 0000000..50905ac
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+struct S {
+  template<typename T>
+  static T t{};
+} s;
+
+template<info R>
+void
+f ()
+{
+  int j = s.template [:R:]<int>; // { dg-error "expected a reflection of an expression instead of type .S." }
+}
+
+void
+g ()
+{
+  f<^^S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash8.C b/gcc/testsuite/g++.dg/reflect/crash8.C
new file mode 100644 (file)
index 0000000..451a1b6
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+// Test using a splice expression in an explicit destructor call
+// but without reflection enabled, which ICEd.
+
+struct S { };
+
+void
+oy (S s)
+{
+  s.~typename [:^^S:](); // { dg-error "reflection" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/crash9.C b/gcc/testsuite/g++.dg/reflect/crash9.C
new file mode 100644 (file)
index 0000000..1f8aff6
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace N { }
+
+template <auto V> constexpr int e = [:V:];  // { dg-error "expected a reflection of an expression instead of .N." }
+template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a reflection of an expression instead of .N." }
+constexpr auto h = ^^N;
+constexpr auto i = e<([:^^h:])>;
+constexpr auto j = e2<^^N>;
diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec1.C b/gcc/testsuite/g++.dg/reflect/data_member_spec1.C
new file mode 100644 (file)
index 0000000..c213992
--- /dev/null
@@ -0,0 +1,119 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::data_member_spec.
+
+#include <meta>
+
+using namespace std::meta;
+
+enum E { E0, E1 };
+struct S {};
+
+consteval bool
+valid_data_member_spec (info r, data_member_options opts)
+{
+  try { data_member_spec (r, opts); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+consteval bool
+foo ()
+{
+  std::string n1 = "bar";
+  data_member_options a = { .name = n1 };
+  auto dmsa = data_member_spec (^^S, a);
+  if (!is_data_member_spec (dmsa))
+    throw 1;
+  std::u8string_view n2 = u8"baz";
+  data_member_options b = { .name = n2, .alignment = 2 * alignof (long), .no_unique_address = true };
+  auto dmsb = data_member_spec (^^long, b);
+  if (!is_data_member_spec (dmsb))
+    throw 2;
+  data_member_options c = { .bit_width = 7 };
+  auto dmsc = data_member_spec (^^int, c);
+  if (!is_data_member_spec (dmsc))
+    throw 3;
+  data_member_options d = { .name = "extremely_long_identifier1", .bit_width = 6 };
+  auto dmsd = data_member_spec (^^E, d);
+  if (!is_data_member_spec (dmsd))
+    throw 4;
+  data_member_options e = { .bit_width = 0 };
+  auto dmse = data_member_spec (^^int, e);
+  if (!is_data_member_spec (dmse))
+    throw 5;
+  data_member_options f = { .name = u8"extremely_long_identifier2", .alignment = 2 * alignof (E) };
+  auto dmsf = data_member_spec (^^E &, f);
+  if (!is_data_member_spec (dmsf))
+    throw 6;
+  if (dmsa != data_member_spec (^^S, { .name = "bar" }))
+    throw 7;
+  if (dmsb != data_member_spec (^^long, { .name = u8"baz", .alignment = 2 * alignof (long), .no_unique_address = true }))
+    throw 8;
+  if (dmsc != data_member_spec (^^int, { .bit_width = 7ULL }))
+    throw 9;
+  if (dmsd != data_member_spec (^^E, { .name = "extremely_long_identifier1", .bit_width = 6 }))
+    throw 10;
+  if (dmse != data_member_spec (^^int, { .bit_width = 0U }))
+    throw 11;
+  if (dmsf != data_member_spec (^^E &, { .name = u8"extremely_long_identifier2", .alignment = 2 * alignof (E) }))
+    throw 12;
+  if (dmsa == data_member_spec (^^const S, { .name = "bar" }))
+    throw 13;
+  if (dmsa == data_member_spec (^^S, { .name = "foo" }))
+    throw 14;
+  if (dmsb == data_member_spec (^^long, { .name = u8"baz", .alignment = 4 * alignof (long), .no_unique_address = true }))
+    throw 15;
+  if (dmsb == data_member_spec (^^long, { .name = u8"baz", .alignment = 2 * alignof (long), .no_unique_address = false }))
+    throw 16;
+  if (dmsc == data_member_spec (^^int, { .bit_width = 8 }))
+    throw 17;
+  if (dmsd == data_member_spec (^^E, { .name = "extremely_long_identifier3", .bit_width = 6 }))
+    throw 18;
+  if (dmsd == data_member_spec (^^E, { .name = "extremely_long_identifier", .bit_width = 5 }))
+    throw 19;
+  if (dmse == data_member_spec (^^int, { .name = "a" }))
+    throw 20;
+  if (data_member_spec (^^int, { .name = "a" }) == data_member_spec (^^int, { .name = "a", .no_unique_address = true }))
+    throw 21;
+  return true;
+}
+
+static_assert (foo ());
+
+static_assert (!valid_data_member_spec (^^void, { .name = "a" }));
+static_assert (!valid_data_member_spec (^^int (int), { .name = "a" }));
+static_assert (!valid_data_member_spec (^^int, {}));
+static_assert (!valid_data_member_spec (^^int, { .alignment = alignof (int) }));
+static_assert (!valid_data_member_spec (^^int, { .no_unique_address = true }));
+static_assert (!valid_data_member_spec (^^int, { .name = "for" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "if" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "char8_t" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "virtual" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "static_assert" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "__is_convertible" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "__builtin_is_implicit_lifetime" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "007" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "operator++" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "operator ++" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "foo\\u00AA" }));
+static_assert (!valid_data_member_spec (^^int, { .name = "+ -" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"\u00AA" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"\u00AB" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"\u00B6" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"\u00BA" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"\u00C0" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"\u00D6" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"\u0384" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"\u0669" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"A\u0669" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"\u0E59" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"A\u0E59" }));
+static_assert (!valid_data_member_spec (^^S, { .name = "a", .bit_width = 4 }));
+static_assert (!valid_data_member_spec (^^int, { .name = "a", .alignment = alignof (int), .bit_width = 4 }));
+static_assert (!valid_data_member_spec (^^int, { .name = "a", .bit_width = 4, .no_unique_address = true }));
+static_assert (!valid_data_member_spec (^^int, { .name = "a", .bit_width = 0 }));
+static_assert (!valid_data_member_spec (^^int, { .name = "a", .bit_width = -42 }));
+static_assert (!valid_data_member_spec (^^int, { .name = "a", .alignment = 41 }));
+static_assert (!valid_data_member_spec (^^int, { .name = "a", .alignment = -__INT_MAX__ - 1 }));
+static_assert (!valid_data_member_spec (^^long long, { .name = "a", .alignment = alignof (long long) / 2 }));
diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec2.C b/gcc/testsuite/g++.dg/reflect/data_member_spec2.C
new file mode 100644 (file)
index 0000000..3c0043f
--- /dev/null
@@ -0,0 +1,113 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::data_member_spec.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+valid_data_member_spec (info r, data_member_options opts)
+{
+  try { data_member_spec (r, opts); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!valid_data_member_spec (null_reflection, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^::, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^ns, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^ns_alias, { .name = "dms" }));
+static_assert (!valid_data_member_spec (reflect_constant (3), { .name = "dms" }));
+static_assert (valid_data_member_spec (^^cls, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls::dm, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls::ref_dm, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls::static_dm, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls::mem_fun, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls::static_mem_fun, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^cls::type, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls_var, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^onion, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^anon, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^fun, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^alias, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^var, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^ref, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^rref, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^ptr, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls_tmpl, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^cls_tmpl<int>, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^incomplete_cls<int>, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^fun_tmpl, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^fun_tmpl<int>, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^conc, { .name = "dms" }));
+static_assert (!valid_data_member_spec (substitute (^^conc, { ^^int }), { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^var_tmpl, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^var_tmpl<int>, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^cls_tmpl_alias, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^cls_tmpl_alias<int>, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^Enum, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^Enum::A, { .name = "dms" }));
+static_assert (valid_data_member_spec (^^Enum_class, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^Enum_class::A, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^decomp, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^decomp_ref, { .name = "dms" }));
+static_assert (!valid_data_member_spec (^^arr, { .name = "dms" }));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!valid_data_member_spec (dms, { .name = "dms" }));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!valid_data_member_spec (bases_of (^^Derived, access_context::unchecked ())[0], { .name = "dms" }));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (valid_data_member_spec (^^T, { .name = "dms" }));
+  static_assert (!valid_data_member_spec (R, { .name = "dms" }));
+  static_assert (!valid_data_member_spec (R2, { .name = "dms" }));
+  static_assert (valid_data_member_spec (R3, { .name = "dms" }));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!valid_data_member_spec (^^p, { .name = "dms" }));
+  static_assert (!valid_data_member_spec (^^c, { .name = "dms" }));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec3.C b/gcc/testsuite/g++.dg/reflect/data_member_spec3.C
new file mode 100644 (file)
index 0000000..e29013d
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::data_member_spec.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+valid_data_member_spec (info r, data_member_options opts)
+{
+  try { data_member_spec (r, opts); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!valid_data_member_spec (^^int, { .name = u8"đŸ‘·" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"đŸ‘·.♀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"⏰" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"🕐" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"☠" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"💀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"✋" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"👊" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"✈" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"🚀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"â˜č" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"😀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"đŸ’©" }));
diff --git a/gcc/testsuite/g++.dg/reflect/data_member_spec4.C b/gcc/testsuite/g++.dg/reflect/data_member_spec4.C
new file mode 100644 (file)
index 0000000..49c6b9b
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-options "-freflection" }
+// Test std::meta::data_member_spec.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+valid_data_member_spec (info r, data_member_options opts)
+{
+  try { data_member_spec (r, opts); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (valid_data_member_spec (^^int, { .name = u8"đŸ‘·" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"đŸ‘·.♀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"⏰" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"🕐" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"☠" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"💀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"✋" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"👊" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"✈" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"🚀" }));
+static_assert (!valid_data_member_spec (^^int, { .name = u8"â˜č" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"😀" }));
+static_assert (valid_data_member_spec (^^int, { .name = u8"đŸ’©" }));
diff --git a/gcc/testsuite/g++.dg/reflect/dealias1.C b/gcc/testsuite/g++.dg/reflect/dealias1.C
new file mode 100644 (file)
index 0000000..81fd469
--- /dev/null
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::dealias.
+
+#include <meta>
+
+using namespace std::meta;
+
+namespace N { }
+
+using int_alias = int;
+using int_alias_alias = int_alias;
+template <typename T> using alias_templ = T;
+
+typedef int T1;
+typedef T1 T2;
+
+namespace N_alias = N;
+namespace N_alias_alias = N_alias;
+
+typename [: dealias (^^int) :] i1 = 42;
+typename [: dealias (^^int_alias_alias) :] i2 = 42;
+
+static_assert (dealias (^^int) == ^^int);
+static_assert (dealias (^^int_alias) == ^^int);
+static_assert (dealias (^^int_alias_alias) == ^^int);
+static_assert (dealias (^^alias_templ<int_alias_alias>) == ^^int);
+static_assert (dealias (^^T1) == ^^int);
+static_assert (dealias (^^T2) == ^^int);
+
+static_assert (dealias (^^::) == ^^::);
+static_assert (dealias (^^N) == ^^N);
+static_assert (dealias (^^N_alias) == ^^N);
+static_assert (dealias (^^N_alias_alias) == ^^N);
+
+static_assert (dealias (std::meta::info{}) == std::meta::info{});
diff --git a/gcc/testsuite/g++.dg/reflect/dealias2.C b/gcc/testsuite/g++.dg/reflect/dealias2.C
new file mode 100644 (file)
index 0000000..ecf3e3e
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::dealias.
+
+#include <meta>
+using namespace std::meta;
+
+constexpr int i = 42;
+static_assert (dealias (reflect_object (i)) == reflect_object (i));
+static_assert (dealias (constant_of (^^i)) == constant_of (^^i));
+static_assert (dealias (reflect_constant (42)) == reflect_constant (42));
+[[=1, =1, =2, =1.0f]] void fn ();
+static_assert (dealias (annotations_of (^^fn)[0]) == annotations_of (^^fn)[0]);
+static_assert (dealias (^^i) == ^^i);
diff --git a/gcc/testsuite/g++.dg/reflect/dealias3.C b/gcc/testsuite/g++.dg/reflect/dealias3.C
new file mode 100644 (file)
index 0000000..21a52ca
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::dealias.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<typename T>
+struct S {};
+static_assert (dealias (^^S) == ^^S);
+
+template <typename T> using A1 = T;
+static_assert (dealias (^^A1) == ^^A1);
+
+template <typename T> using A2 = S<T>;
+static_assert (dealias (^^A2) == ^^A2);
+
+template <typename T> using A3 = S<T*>;
+static_assert (dealias (^^A3) == ^^A3);
+
+template <typename T>
+int v = sizeof(T);
+static_assert (dealias (^^v) == ^^v);
+
+template <typename T>
+void fn();
+static_assert (dealias (^^fn) == ^^fn);
+
+template<typename T>
+concept C = true;
+static_assert (dealias (^^C) == ^^C);
diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate1.C b/gcc/testsuite/g++.dg/reflect/define_aggregate1.C
new file mode 100644 (file)
index 0000000..0bf8043
--- /dev/null
@@ -0,0 +1,108 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::define_aggregate.
+
+#include <cstddef>
+#include <meta>
+
+using namespace std::meta;
+
+enum E { E0, E1 };
+struct S0 {};
+struct S1;
+struct S2;
+struct S3;
+struct S4;
+struct S5;
+union U1;
+template <int N>
+struct S6;
+template <int N>
+struct S7 { long e; short f; };
+struct S8;
+struct S9;
+using A9 = S9;
+
+consteval {
+  if (define_aggregate (^^S1, {}) != ^^S1)
+    throw 1;
+  if (define_aggregate (^^S2, { data_member_spec (^^S1, { .name = "bar" }),
+                               data_member_spec (^^long, { .name = u8"baz",
+                                                           .alignment = 2 * alignof (long),
+                                                           .no_unique_address = true }),
+                               data_member_spec (^^unsigned int, { .bit_width = 7 }),
+                               data_member_spec (^^E, { .name = "extremely_long_identifier1",
+                                                        .bit_width = 6 }),
+                               data_member_spec (^^int, { .bit_width = 0 }),
+                               data_member_spec (^^const E *, { .name = u8"extremely_long_identifier2",
+                                                                .alignment = 2 * alignof (E *) }) }) != ^^S2)
+    throw 2;
+  if (define_aggregate (^^S3, { data_member_spec (^^S0, { .name = "a",
+                                                         .no_unique_address = true }),
+                               data_member_spec (^^S1, { .name = "b",
+                                                         .no_unique_address = true }) }) != ^^S3)
+    throw 3;
+  if (define_aggregate (^^S4, { data_member_spec (^^S0, { .name = "c" }),
+                               data_member_spec (^^S1, { .name = "d" }) }) != ^^S4)
+    throw 4;
+  if (define_aggregate (^^S5, { data_member_spec (^^const E &, { .name = u8"qu\N{LATIN SMALL LETTER AE}" }),
+                               data_member_spec (^^const E &, { .name = u8"foo" }) }) != ^^S5)
+    throw 5;
+  if (define_aggregate (^^U1, { data_member_spec (^^int, { .name = u8"_" }),
+                               data_member_spec (^^long long, { .name = "abc" }) }) != ^^U1)
+    throw 6;
+  if (define_aggregate (^^S6 <42>, { data_member_spec (^^int, { .name = "a" }),
+                                    data_member_spec (^^long, { .name = "b" }) }) != ^^S6 <42>)
+    throw 7;
+  if (define_aggregate (substitute (^^S6, { reflect_constant (43) }),
+                       { data_member_spec (^^long, { .name = "c" }),
+                         data_member_spec (^^unsigned int, { .name = "d", .bit_width = 3 }) }) != ^^S6 <43>)
+    throw 8;
+  if (define_aggregate (^^S7 <42>, { data_member_spec (^^short, { .name = "g" }),
+                                    data_member_spec (^^float, { .name = "h" }) }) != ^^S7 <42>)
+    throw 9;
+  if (define_aggregate (^^S8, { data_member_spec (^^U1, { .name = "u" }) }) != ^^S8)
+    throw 10;
+  if (define_aggregate (dealias (^^A9), { data_member_spec (^^U1, { .name = "u" }) }) != ^^S9)
+    throw 10;
+}
+
+constexpr E e0 = E0, e1 = E1;
+S2 s2 = { .bar = {}, .baz = 42LL, .extremely_long_identifier1 = E1, .extremely_long_identifier2 = &e0 };
+S3 s3 = { .a = {}, .b = {} };
+S4 s4 = { .c = {}, .d = {} };
+constexpr S5 s5 = { e0, e1 };
+U1 u1 = { ._ = 5 }, u1a = { .abc = 42LL };
+S6 <42> s642 = { .a = 1, .b = 2 };
+S6 <43> s643 = { .c = 6, .d = 7 };
+S7 <42> s742 = { .g = 5, .h = 6.0f };
+S7 <43> s743 = { .e = 8, .f = 9 };
+S8 s8 = { .u = { .abc = 2LL } };
+S9 s9 = { .u = { ._ = 3 } };
+consteval {
+  S6 <43> x;
+  x.c = -1;
+  x.d = 7;
+  ++x.d;
+  if (x.d != 0)
+    throw 11;
+  --x.d;
+  if (x.d != 7)
+    throw 12;
+}
+static_assert (type_of (^^S2::bar) == ^^S1);
+static_assert (type_of (^^S2::baz) == ^^long);
+static_assert (type_of (^^S2::extremely_long_identifier1) == ^^E);
+static_assert (type_of (^^S2::extremely_long_identifier2) == ^^const E *);
+static_assert (offsetof (S2, bar) == 0);
+static_assert (offsetof (S2, baz) >= 2 * alignof (long) && offsetof (S2, baz) % (2 * alignof (long)) == 0);
+static_assert (offsetof (S2, extremely_long_identifier2) > offsetof (S2, baz));
+static_assert (offsetof (S2, extremely_long_identifier2) % (2 * alignof (E)) == 0);
+static_assert (type_of (^^S3::a) == ^^S0);
+static_assert (type_of (^^S3::b) == ^^S1);
+static_assert (sizeof (S3) == sizeof (S0) && sizeof (S4) == 2 * sizeof (S0));
+static_assert (type_of (^^S4::c) == ^^S0);
+static_assert (type_of (^^S4::d) == ^^S1);
+static_assert (s5.qu\u00E6 == E0 && s5.foo == E1);
+static_assert (type_of (^^S5::qu\u00E6) == ^^const E &);
+static_assert (type_of (^^S5::foo) == ^^const E &);
diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate2.C b/gcc/testsuite/g++.dg/reflect/define_aggregate2.C
new file mode 100644 (file)
index 0000000..07f959a
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::define_aggregate.
+
+#include <cstddef>
+#include <meta>
+
+using namespace std::meta;
+
+enum E { E0, E1 };
+struct S0 {};
+struct S1;
+struct S2;
+struct S3;
+struct S4;
+struct S5;
+template <int N>
+struct S7 { long e; short f; };
+S7 <15> s715;
+struct S8;
+using A8 = S8;
+struct S9;
+struct S10;
+struct S11;
+struct S12;
+consteval { define_aggregate (^^::, {}); }             // { dg-error "first 'define_aggregate' argument is not a class type reflection" }
+consteval { define_aggregate (^^int, {}); }            // { dg-error "first 'define_aggregate' argument is not a class type reflection" }
+consteval { define_aggregate (^^E, {}); }              // { dg-error "first 'define_aggregate' argument is not a class type reflection" }
+consteval { define_aggregate (^^S0, {}); }             // { dg-error "first 'define_aggregate' argument is a complete class type reflection" }
+consteval { define_aggregate (^^S7 <15>, {}); }                // { dg-error "first 'define_aggregate' argument is a complete class type reflection" }
+consteval { define_aggregate (^^A8, {}); }             // { dg-error "first 'define_aggregate' argument is a reflection of a type alias" }
+consteval { define_aggregate (^^const S9, {}); }       // { dg-error "first 'define_aggregate' argument is a cv-qualified class type reflection" }
+consteval { define_aggregate (^^volatile S10, {}); }   // { dg-error "first 'define_aggregate' argument is a cv-qualified class type reflection" }
+consteval { define_aggregate (^^S11 const volatile, {}); } // { dg-error "first 'define_aggregate' argument is a cv-qualified class type reflection" }
+consteval { define_aggregate (^^S1, { ^^int }); }      // { dg-error "'define_aggregate' argument not a data member description" }
+consteval { define_aggregate (^^S2, { data_member_spec (^^S5, { .name = "a" }) }); }   // { dg-error "'define_aggregate' argument data member description without complete type" }
+consteval { define_aggregate (^^S3, { data_member_spec (^^int, { .name = "a" }),       // { dg-error "name 'a' used in multiple data member descriptions" }
+                                     data_member_spec (^^long, { .name = "a" }) }); }
+consteval { define_aggregate (^^S4, { data_member_spec (^^int, { .name = u8"_" }),
+                                     data_member_spec (^^long, { .name = u8"_" }) }); }
+consteval { define_aggregate (^^S12, { data_member_spec (^^int, { .name = "foobar" }), // { dg-error "name 'foobar' used in multiple data member descriptions" }
+                                      data_member_spec (^^long, { .name = u8"foobar" }) }); }
+constexpr S4 s4 = { 1, 2 };
+consteval { auto a = s4._; }                           // { dg-error "request for member '_' is ambiguous" }
diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate3.C b/gcc/testsuite/g++.dg/reflect/define_aggregate3.C
new file mode 100644 (file)
index 0000000..db04a80
--- /dev/null
@@ -0,0 +1,217 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::define_aggregate.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S1;
+struct S2;
+static_assert (define_aggregate (^^S1, {}) == ^^S1);   // { dg-error "non-constant condition for static assertion" }
+// { dg-error "'define_aggregate' not evaluated from 'consteval' block" "" { target *-*-* } .-1 }
+consteval bool foo () { return define_aggregate (^^S2, {}) == ^^S2; }
+// { dg-error "'define_aggregate' not evaluated from 'consteval' block" "" { target *-*-* } .-1 }
+const bool a = foo ();                                 // { dg-error "call to consteval function 'foo\\\(\\\)' is not a constant expression" }
+
+struct S3 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S3, {});                       // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S3' being defined" }
+  }
+};
+
+template <typename T>
+struct S4 {
+  consteval {
+    define_aggregate (^^S4 <T>, {});
+  }
+};
+
+consteval {
+  define_aggregate (^^S4 <long>, {});
+}
+
+template <typename T>
+struct S5 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S5 <T>, {});                   // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S5<int>' being defined" }
+  }
+};
+
+S5 <int> s5;
+
+consteval bool bar (info x) { return define_aggregate (x, {}) == x; }  // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S6' being defined" }
+
+struct S6 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    bar (^^S6);
+  }
+};
+
+consteval bool baz (info x) { return define_aggregate (x, {}) == x; }  // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S7<char>' being defined" }
+
+template <typename T>
+struct S7 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    baz (^^S7 <T>);
+  }
+};
+
+S7 <char> s7;
+
+consteval {                                            // { dg-message "'consteval' block defined here" }
+  struct S8;
+  define_aggregate (^^S8, {});                         // { dg-error "'define_aggregate' evaluated from 'consteval' block which encloses '<lambda\\\(\\\)> static::S8'" }
+};
+
+struct S9;
+consteval {
+  constexpr auto a = define_aggregate (^^S9, {});      // { dg-error "'define_aggregate' not evaluated from 'consteval' block" }
+}
+
+struct S10;
+consteval {
+  const auto a = define_aggregate (^^S10, {});
+}
+static_assert (is_complete_type (^^S10));
+
+consteval {
+  struct S11 {
+    struct S12;
+  };
+  define_aggregate (^^S11::S12, {});                   // { dg-error "'define_aggregate' evaluated from 'consteval' block which encloses '<lambda\\\(\\\)> static::S11::S12' being defined" }
+}
+
+consteval info
+baz ()
+{
+  struct S13;
+  return ^^S13;
+}
+
+consteval {                                            // { dg-message "'consteval' block defined here" }
+  define_aggregate (baz (), {});                       // { dg-error "'consteval std::meta::info baz\\\(\\\)' intervenes between 'baz\\\(\\\)::S13' scope and 'consteval' block 'define_aggregate' is evaluated from" }
+}
+
+struct S14 {
+  struct S15;
+};
+
+consteval {                                            // { dg-message "'consteval' block defined here" }
+  define_aggregate (^^S14::S15, {});                   // { dg-error "'S14' intervenes between 'S14::S15' scope and 'consteval' block 'define_aggregate' is evaluated from" }
+}
+
+struct S16;
+
+void
+qux ()
+{
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S16, {});                      // { dg-error "'void qux\\\(\\\)' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'S16' scope" }
+  }
+}
+
+struct S17;
+
+struct S18 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S17, {});                      // { dg-error "'S18' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'S17' scope" }
+  }
+};
+
+void
+garply ()
+{
+  struct S19;
+  consteval {
+    define_aggregate (^^S19, {});
+  }
+}
+
+void
+fred ()
+{
+  struct S20;
+  [] () {
+    consteval {                                                // { dg-message "'consteval' block defined here" }
+      define_aggregate (^^S20, {});                    // { dg-error "'fred\\\(\\\)::<lambda\\\(\\\)>' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'fred\\\(\\\)::S20' scope" }
+    }
+  } ();
+}
+
+consteval info
+corge ()
+{
+  struct S21;
+  return ^^S21;
+}
+
+void
+plugh ()
+{
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (corge (), {});                   // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'void plugh\\\(\\\)' while 'corge\\\(\\\)::S21' type being defined is enclosed by 'consteval std::meta::info corge\\\(\\\)'" }
+  }
+}
+
+struct S22 {
+  struct S23;
+};
+
+struct S24 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S22::S23, {});                 // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S24' while 'S22::S23' type being defined is enclosed by 'S22'" }
+  }
+};
+
+consteval info
+waldo ()
+{
+  struct S25;
+  return ^^S25;
+}
+
+struct S26 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (waldo (), {});                   // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S26' while 'waldo\\\(\\\)::S25' type being defined is enclosed by 'consteval std::meta::info waldo\\\(\\\)'" }
+  }
+};
+
+struct S27 {
+  struct S28;
+};
+
+void
+grault ()
+{
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S27::S28, {});                 // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'void grault\\\(\\\)' while 'S27::S28' type being defined is enclosed by 'S27'" }
+  }
+}
+
+void
+xyzzy ()
+{
+  struct S29 {
+    struct S30;
+  };
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S29::S30, {});                 // { dg-error "'xyzzy\\\(\\\)::S29' intervenes between 'xyzzy\\\(\\\)::S29::S30' scope and 'consteval' block 'define_aggregate' is evaluated from" }
+  }
+  static constexpr auto a = [] () consteval {
+    struct S31;
+    return ^^S31;
+  } ();
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (a, {});                          // { dg-error "'xyzzy\\\(\\\)::<lambda\\\(\\\)>' intervenes between 'xyzzy\\\(\\\)::<lambda\\\(\\\)>::S31' scope and 'consteval' block 'define_aggregate' is evaluated from" }
+  }
+}
+
+struct S32 {
+  struct S33 {
+    struct S34;
+  };
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    define_aggregate (^^S33::S34, {});                 // { dg-error "'S32::S33' intervenes between 'S32::S33::S34' scope and 'consteval' block 'define_aggregate' is evaluated from" }
+  }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate4.C b/gcc/testsuite/g++.dg/reflect/define_aggregate4.C
new file mode 100644 (file)
index 0000000..c620c5b
--- /dev/null
@@ -0,0 +1,225 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::define_aggregate.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr auto uctx = access_context::unchecked ();
+constexpr auto ctx = access_context::unprivileged ();
+
+void
+foo ()
+{
+  struct S;
+  class C;
+  union U;
+  static_assert (!is_complete_type (^^S));
+  static_assert (!is_complete_type (^^C));
+  static_assert (!is_complete_type (^^U));
+  consteval {
+    if (is_complete_type (^^S))
+      throw 1;
+    if (is_complete_type (^^C))
+      throw 2;
+    if (is_complete_type (^^U))
+      throw 3;
+    define_aggregate (^^S, {});
+    define_aggregate (^^C, {});
+    define_aggregate (^^U, {});
+    if (!is_complete_type (^^S))
+      throw 4;
+    if (!is_complete_type (^^C))
+      throw 5;
+    if (!is_complete_type (^^U))
+      throw 6;
+    if (!nonstatic_data_members_of (^^S, uctx).empty ())
+      throw 7;
+    if (!nonstatic_data_members_of (^^C, uctx).empty ())
+      throw 8;
+    if (!nonstatic_data_members_of (^^U, uctx).empty ())
+      throw 9;
+  }
+  static_assert (is_complete_type (^^S));
+  static_assert (is_complete_type (^^C));
+  static_assert (is_complete_type (^^U));
+  static_assert (nonstatic_data_members_of (^^S, uctx).empty ());
+  static_assert (nonstatic_data_members_of (^^C, uctx).empty ());
+  static_assert (nonstatic_data_members_of (^^U, uctx).empty ());
+}
+
+void
+bar ()
+{
+  struct S;
+  class C;
+  union U;
+  union U2;
+  static_assert (!is_complete_type (^^S));
+  static_assert (!is_complete_type (^^C));
+  static_assert (!is_complete_type (^^U));
+  consteval {
+    if (is_complete_type (^^S))
+      throw 1;
+    if (is_complete_type (^^C))
+      throw 2;
+    if (is_complete_type (^^U))
+      throw 3;
+    define_aggregate (^^S, { data_member_spec (^^int, { .name = "a", .alignment = 32 }),
+                            data_member_spec (^^bool, { .name = "b" }),
+                            data_member_spec (^^int, { .bit_width = 0 }),
+                            data_member_spec (^^int, { .name = "_", .bit_width = 3 }),});
+    define_aggregate (^^C, { data_member_spec (^^int, { .name = "a", .alignment = 32 }),
+                            data_member_spec (^^bool, { .name = "b" }),
+                            data_member_spec (^^int, { .bit_width = 0 }),
+                            data_member_spec (^^int, { .name = "_", .bit_width = 3 }),});
+    define_aggregate (^^U, { data_member_spec (^^int, { .name = "a", .alignment = 32 }),
+                            data_member_spec (^^bool, { .name = "b" }),
+                            data_member_spec (^^int, { .bit_width = 0 }),
+                            data_member_spec (^^int, { .name = "_", .bit_width = 3 }),});
+    define_aggregate (^^U2, { data_member_spec (^^int, { .name = "a" }),
+                             data_member_spec (^^bool, { .name = "b" }),
+                             data_member_spec (^^int, { .bit_width = 0 }),
+                             data_member_spec (^^int, { .name = "_", .bit_width = 3 }),});
+    if (!is_complete_type (^^S))
+      throw 4;
+    if (!is_complete_type (^^C))
+      throw 5;
+    if (!is_complete_type (^^U))
+      throw 6;
+    if (!nonstatic_data_members_of (^^S, uctx).size () == 3)
+      throw 7;
+    if (!nonstatic_data_members_of (^^C, uctx).size () == 3)
+      throw 8;
+    if (!nonstatic_data_members_of (^^U, uctx).size () == 3)
+      throw 9;
+    if (!nonstatic_data_members_of (^^S, ctx).size () == 3)
+      throw 10;
+    if (!nonstatic_data_members_of (^^C, ctx).size () == 3)
+      throw 11;
+    if (!nonstatic_data_members_of (^^U, ctx).size () == 3)
+      throw 12;
+    if (!alignment_of (nonstatic_data_members_of (^^S, uctx)[0]) == 32)
+      throw 13;
+    if (!bit_size_of (members_of (^^S, uctx)[2]) == 0)
+      throw 14;
+    if (!is_bit_field (members_of (^^S, ctx)[2]))
+      throw 15;
+    if (!bit_size_of (members_of (^^S, uctx)[3]) == 3)
+      throw 16;
+    if (!is_bit_field (members_of (^^S, ctx)[3]))
+      throw 17;
+    if (!alignment_of (nonstatic_data_members_of (^^C, uctx)[0]) == 32)
+      throw 18;
+    if (!bit_size_of (members_of (^^C, uctx)[2]) == 0)
+      throw 19;
+    if (!is_bit_field (members_of (^^C, ctx)[2]))
+      throw 20;
+    if (!bit_size_of (members_of (^^C, uctx)[3]) == 3)
+      throw 21;
+    if (!is_bit_field (members_of (^^C, ctx)[3]))
+      throw 22;
+    if (!alignment_of (nonstatic_data_members_of (^^U, uctx)[0]) == 32)
+      throw 23;
+    if (!bit_size_of (members_of (^^U, uctx)[2]) == 0)
+      throw 24;
+    if (!is_bit_field (members_of (^^U, ctx)[2]))
+      throw 25;
+    if (!bit_size_of (members_of (^^U, uctx)[3]) == 3)
+      throw 26;
+    if (!is_bit_field (members_of (^^U, ctx)[3]))
+      throw 27;
+    if (!is_public (members_of (^^S, uctx)[0]))
+      throw 28;
+    if (!is_public (members_of (^^S, uctx)[1]))
+      throw 29;
+    if (!is_public (members_of (^^S, uctx)[2]))
+      throw 30;
+    if (!is_public (members_of (^^S, uctx)[3]))
+      throw 31;
+    if (!is_public (members_of (^^C, uctx)[0]))
+      throw 32;
+    if (!is_public (members_of (^^C, uctx)[1]))
+      throw 33;
+    if (!is_public (members_of (^^C, uctx)[2]))
+      throw 34;
+    if (!is_public (members_of (^^C, uctx)[3]))
+      throw 35;
+    if (!is_public (members_of (^^U, uctx)[0]))
+      throw 36;
+    if (!is_public (members_of (^^U, uctx)[1]))
+      throw 37;
+    if (!is_public (members_of (^^U, uctx)[2]))
+      throw 38;
+    if (!is_public (members_of (^^U, uctx)[3]))
+      throw 39;
+    if (!is_class_type (^^S))
+      throw 40;
+    if (!is_class_type (^^C))
+      throw 41;
+    if (!is_union_type (^^U))
+      throw 42;
+  }
+  static_assert (is_complete_type (^^S));
+  static_assert (is_complete_type (^^C));
+  static_assert (is_complete_type (^^U));
+  static_assert (nonstatic_data_members_of (^^S, uctx).size () == 3);
+  static_assert (nonstatic_data_members_of (^^C, uctx).size () == 3);
+  static_assert (nonstatic_data_members_of (^^U, uctx).size () == 3);
+  static_assert (nonstatic_data_members_of (^^S, ctx).size () == 3);
+  static_assert (nonstatic_data_members_of (^^C, ctx).size () == 3);
+  static_assert (nonstatic_data_members_of (^^U, ctx).size () == 3);
+  static_assert (alignment_of (nonstatic_data_members_of (^^S, uctx)[0]) == 32);
+  static_assert (bit_size_of (members_of (^^S, uctx)[2]) == 0);
+  static_assert (is_bit_field (members_of (^^S, ctx)[2]));
+  static_assert (bit_size_of (members_of (^^S, uctx)[3]) == 3);
+  static_assert (is_bit_field (members_of (^^S, ctx)[3]));
+  static_assert (alignment_of (nonstatic_data_members_of (^^C, uctx)[0]) == 32);
+  static_assert (bit_size_of (members_of (^^C, uctx)[2]) == 0);
+  static_assert (is_bit_field (members_of (^^C, ctx)[2]));
+  static_assert (bit_size_of (members_of (^^C, uctx)[3]) == 3);
+  static_assert (is_bit_field (members_of (^^C, ctx)[3]));
+  static_assert (alignment_of (nonstatic_data_members_of (^^U, uctx)[0]) == 32);
+  static_assert (bit_size_of (members_of (^^U, uctx)[2]) == 0);
+  static_assert (is_bit_field (members_of (^^U, ctx)[2]));
+  static_assert (bit_size_of (members_of (^^U, uctx)[3]) == 3);
+  static_assert (is_bit_field (members_of (^^U, ctx)[3]));
+  static_assert (is_public (members_of (^^S, uctx)[0]));
+  static_assert (is_public (members_of (^^S, uctx)[1]));
+  static_assert (is_public (members_of (^^S, uctx)[2]));
+  static_assert (is_public (members_of (^^S, uctx)[3]));
+  static_assert (is_public (members_of (^^C, uctx)[0]));
+  static_assert (is_public (members_of (^^C, uctx)[1]));
+  static_assert (is_public (members_of (^^C, uctx)[2]));
+  static_assert (is_public (members_of (^^C, uctx)[3]));
+  static_assert (is_public (members_of (^^U, uctx)[0]));
+  static_assert (is_public (members_of (^^U, uctx)[1]));
+  static_assert (is_public (members_of (^^U, uctx)[2]));
+  static_assert (is_public (members_of (^^U, uctx)[3]));
+  static_assert (is_class_type (^^S));
+  static_assert (is_class_type (^^C));
+  static_assert (is_union_type (^^U));
+  static_assert (sizeof (U2) == sizeof (int));
+  constexpr S s = { 1, true, 2 };
+  static_assert (s.a == 1 && s.b == true && s._ == 2);
+  constexpr C c = { 3, false, -4 };
+  static_assert (c.a == 3 && c.b == false && c._ == -4);
+  union U u { .a = 42 };
+  u.b = true;
+  u._ = 3;
+  u.[: nonstatic_data_members_of (^^U, ctx)[2] :] = 1;
+}
+
+void
+baz ()
+{
+  struct E {};
+  struct S;
+  consteval {
+    define_aggregate (^^S, { data_member_spec (^^int, { .name = "_" }),
+                            data_member_spec (^^E, { .name = "_", .no_unique_address = true }) });
+  }
+  static_assert (sizeof (S) == sizeof (int));
+}
\ No newline at end of file
diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate5.C b/gcc/testsuite/g++.dg/reflect/define_aggregate5.C
new file mode 100644 (file)
index 0000000..00501c5
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+#include <ranges>
+
+struct foo;
+
+consteval {
+  using namespace std::meta;
+  using namespace std::views;
+  using std::make_pair;
+  using std::vector;
+  using std::pair;
+  define_aggregate (^^foo, join (vector <vector <pair <bool, info>>> {
+    { make_pair (true, data_member_spec (^^int, { .name = "i" })) },
+    { make_pair (false, data_member_spec (^^std::string, { .name = "s" })),
+      make_pair (true, data_member_spec (^^bool, { .name = "b" })) }})
+       | filter ([] (auto x) constexpr { return x.first; })
+       | transform ([] (auto x) constexpr { return x.second; }));
+}
+
+static_assert (type_of (^^foo::i) == ^^int);
+static_assert (type_of (^^foo::b) == ^^bool);
+static_assert (nonstatic_data_members_of (^^foo, std::meta::access_context::current ()).size () == 2);
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_array1.C b/gcc/testsuite/g++.dg/reflect/define_static_array1.C
new file mode 100644 (file)
index 0000000..61a6a53
--- /dev/null
@@ -0,0 +1,91 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::define_static_array.
+
+#include <array>
+#include <meta>
+#include <ranges>
+#include <span>
+
+struct V { int a, b, c; };
+constexpr auto a = std::define_static_array ("abcd");
+constexpr auto b = std::define_static_array (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}");
+constexpr auto c = std::define_static_array (std::vector <char> {});
+constexpr auto d = std::define_static_array (std::array { 1, 2, 42, 3 });
+constexpr float ea[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
+constexpr auto e = std::define_static_array (ea);
+constexpr int fb[] = { 1, 2, 3, 4, 5, 6 };
+constexpr std::span <const int> fa (fb);
+constexpr auto f = std::define_static_array (fa);
+constexpr auto g = std::define_static_array (fa.subspan (1, 4));
+constexpr auto h = std::define_static_array (fa.subspan (1, 4) | std::views::reverse);
+constexpr auto i = std::define_static_array (std::vector <V> { V { 1, 2, 3 }, V { 2, 3, 4 }, V { 3, 4, 5 } });
+constexpr auto j = std::define_static_array (std::vector <long long> {});
+constexpr auto k = std::define_static_array (std::meta::nonstatic_data_members_of (^^V, std::meta::access_context::current ()));
+static_assert (a.data () == std::define_static_string ("abcd") && a.size () == 5);
+static_assert (b.data () == std::define_static_string (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}")
+              && b.size () == sizeof (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}") / sizeof (char32_t));
+static_assert (c.data () == nullptr && c.size () == 0);
+static_assert (d.data () == std::define_static_array (std::vector <int> { 1, 2, 42, 3 }).data ()
+              && d.size () == 4 && d[0] == 1 && d[1] == 2 && d[2] == 42 && d[3] == 3);
+static_assert (e.data () == std::define_static_array (std::array { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f }).data ()
+              && e.size () == 6 && e[0] == 1.0f && e[1] == 2.0f && e[2] == 3.0f && e[3] == 4.0f && e[4] == 5.0f && e[5] == 6.0f);
+static_assert (f.data () == std::define_static_array (std::vector <int> { 1, 2, 3, 4, 5, 6 }).data ()
+              && f.size () == 6);
+static_assert (d.data () != f.data ());
+static_assert (g.data () == std::define_static_array (std::array { 2, 3, 4, 5 }).data ()
+              && g.size () == 4);
+static_assert (h.data () == std::define_static_array (std::vector <int> { 5, 4, 3, 2 }).data ()
+              && h.size () == 4 && h[0] == 5 && h[1] == 4 && h[2] == 3 && h[3] == 2);
+static_assert (i.size () == 3);
+static_assert (j.data () == nullptr && j.size () == 0);
+static_assert (k.size () == 3 && k[0] == ^^V::a && k[1] == ^^V::b && k[2] == ^^V::c);
+
+int
+main ()
+{
+  if (std::string_view (a) != std::string_view ("abcd", 5))
+    __builtin_abort ();
+  if (std::u32string_view (b) != std::u32string_view (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}", 9))
+    __builtin_abort ();
+  for (const char &x : c)
+    __builtin_abort ();
+  int i = 0;
+  for (const int &x : d)
+    if (x != "\x{1}\x{2}\x{2a}\x{3}"[i++])
+      __builtin_abort ();
+  if (i != 4)
+    __builtin_abort ();
+  i = 0;
+  for (const float &x : e)
+    if (x != ++i)
+      __builtin_abort ();
+  if (i != 6)
+    __builtin_abort ();
+  i = 0;
+  for (const int &x : f)
+    if (x != ++i)
+      __builtin_abort ();
+  if (i != 6)
+    __builtin_abort ();
+  i = 1;
+  for (const int &x : g)
+    if (x != ++i)
+      __builtin_abort ();
+  if (i != 5)
+    __builtin_abort ();
+  i = 6;
+  for (const int &x : h)
+    if (x != --i)
+      __builtin_abort ();
+  if (i != 2)
+    __builtin_abort ();
+  i = 0;
+  for (const V &x : ::i)
+    if (x.a != i + 1 || x.b != i + 2 || x.c != i + 3)
+      __builtin_abort ();
+    else
+      ++i;
+  if (i != 3)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_array2.C b/gcc/testsuite/g++.dg/reflect/define_static_array2.C
new file mode 100644 (file)
index 0000000..01c20c3
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::define_static_array.
+
+#include <meta>
+
+struct A {
+  int a;
+  consteval A (int x) : a(x) {}
+  consteval A (const A &x) : a(x.a + 1) {}
+};
+static_assert (std::vector <A> { 1 }[0].a == 2);
+constexpr auto a = std::define_static_array (std::vector <A> { 1, 11, 21 });
+static_assert (a.size () == 3);
+static_assert (a[0].a >= 2 && a[1].a >= 12 && a[2].a >= 22);
+// TODO: I believe there should be at least 2 copy ctors per element rather
+// than just one.  One is already in the vector construction.
+// Then [meta.define.static]/10 models it as if reflect_constant was called
+// on each element and reflect_constant takes the class by value rather than
+// reference, so one needs to copy construct from a const reference to the
+// range element into a TARGET_EXPR of the reflect_constant argument.
+// And not sure if there shouldn't be further bumps inside of
+// reflect_constant, libcxx bumps 3 times.
+// static_assert (a[0].a == 3 && a[1].a == 13 && a[2].a == 23);
+
+// I believe the copy-constructor of this class breaks the rule for NTTP
+// from [temp.arg.nontype] p4 (copies are not structurally equivalent),
+// that we seem to not currently implement. It makes this test moot
+// as reflect_constant should throw an exception.
+// So language seems to say, that you should have no way to observe this copies.
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_array3.C b/gcc/testsuite/g++.dg/reflect/define_static_array3.C
new file mode 100644 (file)
index 0000000..c196c04
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_array.
+
+#include <meta>
+#include <ranges>
+#include <span>
+
+constexpr int arr[4]{1, 2, 3, 4};
+constexpr std::span<const int> spn = std::define_static_array(std::span<const int, 4>(arr));
+static_assert ([: std::meta::constant_of(^^arr) :] == spn.data());
+
+constexpr int marr[2][2]{1, 2, 3, 4};
+// LWG4483 multidimensional arrays
+// constexpr std::span<const int[2]> mspn = std::define_static_array(std::span<const int[2], 2>(marr));
+// static_assert ([: std::meta::constant_of(^^marr) :] == mspn.data());
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_array4.C b/gcc/testsuite/g++.dg/reflect/define_static_array4.C
new file mode 100644 (file)
index 0000000..1c70e73
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_array.
+
+#include <meta>
+#include <ranges>
+
+constexpr int x[]{1,2,3,4,5};
+constexpr int y[]{11,12,13,14,15};
+constexpr auto as_pair = []<typename T1, typename T2>(const std::tuple<T1, T2>& t) static
+{ return std::pair<T1, T2>(t); };
+
+constexpr std::span spn = std::define_static_array(std::views::zip (x, y) | std::views::transform (as_pair));
+// FIXME these should pass
+// static_assert (^^decltype(spn) == ^^std::span<const std::pair<int, int>>);
+// static_assert (spn[2].first == 3);
+// static_assert (spn[2].second == 13);
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_object1.C b/gcc/testsuite/g++.dg/reflect/define_static_object1.C
new file mode 100644 (file)
index 0000000..1e2be04
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::define_static_object.
+
+#include <meta>
+
+struct V { int a, b, c; };
+constexpr auto a = std::define_static_object (42);
+constexpr auto b = std::define_static_object (U'\N{LATIN CAPITAL LETTER AE}');
+constexpr auto c = std::define_static_object (V { 1, 2, 42 });
+static_assert (a == std::define_static_object (42) && *a == 42);
+static_assert (is_same_type (type_of (^^a), ^^const int *const));
+static_assert (b == std::define_static_object (U'\N{LATIN CAPITAL LETTER AE}') && *b == U'\N{LATIN CAPITAL LETTER AE}');
+static_assert (is_same_type (type_of (^^b), ^^const char32_t *const));
+static_assert (c == std::define_static_object (V { 1, 2, 42 }) && c->a == 1 && c->b == 2 && c->c == 42);
+static_assert (is_same_type (type_of (^^c), ^^const V *const));
+static_assert (a == std::define_static_array (std::vector <int> { 42 }).data ());
+static_assert (b == std::define_static_array (std::vector <char32_t> { U'\N{LATIN CAPITAL LETTER AE}' }).data ());
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_object2.C b/gcc/testsuite/g++.dg/reflect/define_static_object2.C
new file mode 100644 (file)
index 0000000..f1a70d3
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::define_static_object.
+
+#include <meta>
+
+constexpr int arr[]{1, 2, 3};
+// LWG4483 use extract(reflect_constant_array())
+// constexpr const int(*ptr)[3] = std::define_static_object(arr);
+// static_assert( *ptr == std::define_static_array(arr).data() );
+// static_assert( ptr = &std::meta::constant_of(arr) );
+
+constexpr int marr[3][3]{1, 2, 3};
+// LWG4483 array are not structural so this fail
+// constexpr const int(*mptr)[3][3] = std::define_static_object(marr);
+// static_assert( *mptr == std::define_static_array(marr).data() );
+// static_assert( mptr = &std::meta::constant_of(marr) );
+
diff --git a/gcc/testsuite/g++.dg/reflect/define_static_string1.C b/gcc/testsuite/g++.dg/reflect/define_static_string1.C
new file mode 100644 (file)
index 0000000..b0a14c6
--- /dev/null
@@ -0,0 +1,133 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::define_static_string.
+
+#include <meta>
+#include <ranges>
+#include <span>
+
+constexpr const char *a = std::define_static_string ("abcd");
+constexpr const char8_t *b = std::define_static_string (u8"abcd\N{LATIN SMALL LETTER AE}");
+constexpr const wchar_t *c = std::define_static_string (L"abcd");
+constexpr const char16_t *d = std::define_static_string (u"abcd\0ef");
+constexpr const char32_t *e = std::define_static_string (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}");
+constexpr auto f = std::define_static_string (std::string_view ("abcd", 5));
+constexpr auto g = std::define_static_string (std::string_view ("abcdefg", 4));
+constexpr auto h = std::define_static_string (std::u8string_view (u8"ab\0\N{LATIN SMALL LETTER AE}", 5));
+constexpr auto i = std::define_static_string (std::string_view ("abcdefgh", 9).substr (0, 5));
+constexpr auto j = std::define_static_string (std::string_view ("abcdefgh", 9).substr (4, 3));
+constexpr auto k = std::define_static_string (std::u32string_view (U"abcdefgh", 9).substr (3, 4));
+constexpr char8_t la[] = { u8'h', u8'e', u8'l', u8'l', u8'o', u8'\0' };
+constexpr auto l = std::define_static_string (la);
+constexpr std::span <const char8_t> ma (la);
+constexpr auto m = std::define_static_string (ma);
+constexpr auto n = std::define_static_string (ma.subspan (1, 4));
+constexpr auto o = std::define_static_string (ma.subspan (1, 4) | std::views::reverse);
+constexpr auto p = std::define_static_string (std::vector <wchar_t> { L'W', L'o', L'r', L'l', L'd' });
+constexpr auto q = std::define_static_string (std::vector <char16_t> { u'e', u'x', u't', u'r', u'e', u'm', u'e', u'l', u'y',
+                                                                      u' ', u'l', u'o', u'n', u'g',
+                                                                      u' ', u's', u't', u'r', u'i', u'n', u'g',
+                                                                      u' ', u'w', u'i', u't', u'h',
+                                                                      u' ', u'n', u'o', u'n', u'-', u'A', u'S', u'C', u'I', u'I',
+                                                                      u' ', u'c', u'h', u'a', u'r', u'a', u'c', u't', u'e', u'r', u's',
+                                                                      u' ', u'\N{LATIN SMALL LETTER A WITH ACUTE}' });
+const char *r = std::define_static_string ("some string");
+const char8_t *s = std::define_static_string (u8"\N{GRINNING FACE}\N{GRINNING FACE WITH SMILING EYES}");
+static_assert (a == std::define_static_string ("abcd"));
+static_assert (b == std::define_static_string (u8"abcd\N{LATIN SMALL LETTER AE}"));
+static_assert (c == std::define_static_string (L"abcd"));
+static_assert (d == std::define_static_string (u"abcd\0ef"));
+static_assert (e == std::define_static_string (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}"));
+static_assert (f == std::define_static_string ("abcd\0"));
+static_assert (g == a);
+static_assert (h == std::define_static_string (u8"ab\0\N{LATIN SMALL LETTER AE}"));
+static_assert (i == std::define_static_string ("abcde"));
+static_assert (a != i);
+static_assert (j == std::define_static_string ("efg"));
+static_assert (a != j);
+static_assert (k == std::define_static_string (U"defg"));
+static_assert (l == std::define_static_string (u8"hello\0"));
+static_assert (m == l);
+static_assert (n == std::define_static_string (u8"ello"));
+static_assert (o == std::define_static_string (u8"olle"));
+static_assert (p == std::define_static_string (L"World"));
+static_assert (q == std::define_static_string (u"extremely long string with non-ASCII characters \N{LATIN SMALL LETTER A WITH ACUTE}"));
+static_assert (std::define_static_string ("bar") != std::define_static_string ("baz"));
+
+template <typename T, const T *P>
+struct C { const T *p = P; };
+
+static_assert (std::is_same_v <C <char, std::define_static_string ("foobar")>,
+                              C <char, std::define_static_string (std::vector <char> { 'f', 'o', 'o', 'b', 'a', 'r' })>>);
+static_assert (!std::is_same_v <C <char, std::define_static_string ("foobar")>,
+                               C <char, std::define_static_string (std::vector <char> { 'f', 'o', 'O', 'b', 'a', 'r' })>>);
+static_assert (std::is_same_v <C <wchar_t, std::define_static_string (L"hello")>,
+                              C <wchar_t, std::define_static_string (L"hello")>>);
+static_assert (std::is_same_v <C <char8_t, std::define_static_string (u8"hello\0")>,
+                              C <char8_t, std::define_static_string (ma)>>);
+static_assert (std::is_same_v <C <char8_t, std::define_static_string (u8"\N{LATIN SMALL LETTER AE}")>,
+                              C <char8_t, std::define_static_string (u8"\N{LATIN SMALL LETTER AE}")>>);
+static_assert (std::is_same_v <C <char16_t, std::define_static_string (u"\N{LATIN CAPITAL LETTER AE}")>,
+                              C <char16_t, std::define_static_string (std::vector <char16_t> { u'\N{LATIN CAPITAL LETTER AE}' })>>);
+static_assert (std::is_same_v <C <char32_t, std::define_static_string (U"\N{GRINNING FACE}\N{GRINNING FACE WITH SMILING EYES}")>,
+                              C <char32_t, std::define_static_string (std::vector <char32_t> { U'\N{GRINNING FACE}', U'\N{GRINNING FACE WITH SMILING EYES}' })>>);
+
+template <auto V>
+consteval auto
+foo ()
+{
+  return V[0];
+}
+
+static_assert (foo <std::define_static_string ("foo")> () == 'f');
+static_assert (foo <std::define_static_string (L"bar")> () == L'b');
+static_assert (foo <std::define_static_string (u8"qux")> () == u8'q');
+static_assert (foo <std::define_static_string (u"\N{LATIN SMALL LETTER AE}\N{LATIN CAPITAL LETTER AE}")> () == u'\N{LATIN SMALL LETTER AE}');
+static_assert (foo <std::define_static_string (U"\N{GRINNING FACE WITH SMILING EYES}\N{GRINNING FACE}")> () == U'\N{GRINNING FACE WITH SMILING EYES}');
+
+int
+main ()
+{
+  if (std::string_view (a) != std::string_view ("abcd"))
+    __builtin_abort ();
+  if (std::u8string_view (b) != std::u8string_view (u8"abcd\N{LATIN SMALL LETTER AE}"))
+    __builtin_abort ();
+  if (std::wstring_view (c) != std::wstring_view (L"abcd"))
+    __builtin_abort ();
+  if (std::u16string_view (d) != std::u16string_view (u"abcd\0ef"))
+    __builtin_abort ();
+  if (std::u32string_view (e) != std::u32string_view (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}"))
+    __builtin_abort ();
+  if (std::string_view (f) != std::string_view ("abcd\0"))
+    __builtin_abort ();
+  if (g != a)
+    __builtin_abort ();
+  if (std::u8string_view (h) != std::u8string_view (u8"ab\0\N{LATIN SMALL LETTER AE}"))
+    __builtin_abort ();
+  if (std::string_view (i) != std::string_view ("abcde"))
+    __builtin_abort ();
+  if (a == i)
+    __builtin_abort ();
+  if (std::string_view (j) != std::string_view ("efg"))
+    __builtin_abort ();
+  if (a == j)
+    __builtin_abort ();
+  if (std::u32string_view (k) != std::u32string_view (U"defg"))
+    __builtin_abort ();
+  if (std::u8string_view (l) != std::u8string_view (u8"hello\0"))
+    __builtin_abort ();
+  if (m != l)
+    __builtin_abort ();
+  if (std::u8string_view (n) != std::u8string_view (u8"ello"))
+    __builtin_abort ();
+  if (std::u8string_view (o) != std::u8string_view (u8"olle"))
+    __builtin_abort ();
+  if (std::wstring_view (p) != std::wstring_view (L"World"))
+    __builtin_abort ();
+  if (std::u16string_view (q) != std::u16string_view (u"extremely long string with non-ASCII characters \N{LATIN SMALL LETTER A WITH ACUTE}"))
+    __builtin_abort ();
+  if (r != std::define_static_string ("some string"))
+    __builtin_abort ();
+  if (s != std::define_static_string (u8"\N{GRINNING FACE}\N{GRINNING FACE WITH SMILING EYES}"))
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep1.C b/gcc/testsuite/g++.dg/reflect/dep1.C
new file mode 100644 (file)
index 0000000..4bfc995
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test dependent splice specifiers.
+
+template<template<class> class X>
+struct S {
+  typename [: ^^X :]<int, float> m; // { dg-error "wrong number of template arguments" }
+};
+
+template<class> struct V1 {};
+template<class, class = int> struct V2 {};
+
+S<V1> s1; // { dg-message "required from here" }
+S<V2> s2; // OK
diff --git a/gcc/testsuite/g++.dg/reflect/dep10.C b/gcc/testsuite/g++.dg/reflect/dep10.C
new file mode 100644 (file)
index 0000000..f942a2e
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Partial substitution of a SPLICE_SCOPE.
+
+template<typename>
+void f()
+{
+   auto func = []<auto Mem>() static {
+      return [: ^^[:Mem:] ::func :];
+   };
+}
+
+void g() {
+   f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep11.C b/gcc/testsuite/g++.dg/reflect/dep11.C
new file mode 100644 (file)
index 0000000..ad9f584
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Stolen from LLVM's splice-exprs.cpp.
+
+using info = decltype(^^::);
+
+template<info FN>
+struct Cls {
+    template <typename RESULT, typename... Args>
+    struct Impl {
+        Impl(decltype(&[:FN:]));
+    };
+    template <typename RESULT, typename... Args>
+    Impl(RESULT (*)(Args...)) -> Impl<RESULT, Args...>;
+};
+
+void fn(int);
+static_assert(^^decltype(Cls<^^fn>::Impl(&fn)) == ^^Cls<^^fn>::Impl<void, int>);
diff --git a/gcc/testsuite/g++.dg/reflect/dep2.C b/gcc/testsuite/g++.dg/reflect/dep2.C
new file mode 100644 (file)
index 0000000..dfc27b2
--- /dev/null
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+template<typename T>
+constexpr int
+fn (T t)
+{
+  return t;
+}
+
+template<typename T>
+constexpr T
+foo ()
+{
+  constexpr auto r = ^^fn<T>;
+  int n = [: r :](42);
+  return n;
+}
+
+void
+g ()
+{
+  constexpr int r = foo<int>();
+  static_assert (r == 42);
+}
+
+template<typename T>
+consteval info
+h ()
+{
+  return ^^T;
+}
+
+constexpr info i = h<int>();
diff --git a/gcc/testsuite/g++.dg/reflect/dep3.C b/gcc/testsuite/g++.dg/reflect/dep3.C
new file mode 100644 (file)
index 0000000..1b606de
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  template<typename T>
+  struct NS { };
+
+  template<typename T>
+  void foo ();
+
+  template<typename T>
+  S &operator|(const T&);
+
+  template<typename T>
+  static int V;
+};
+
+template<typename T>
+void
+g ()
+{
+  // Looks like r1 and r4 should work.
+  //constexpr auto r1 = ^^T::template NS;
+  constexpr auto r2 = ^^T::template foo;
+  constexpr auto r3 = ^^T::template operator|;
+  //constexpr auto r4 = ^^T::template V;
+}
+
+void
+f ()
+{
+  g<S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep4.C b/gcc/testsuite/g++.dg/reflect/dep4.C
new file mode 100644 (file)
index 0000000..a264ab1
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+consteval int fn1 () { return 42; }
+consteval int fn2 (int a = 5) { return a; }
+
+constexpr info r1 = ^^fn1;
+constexpr info r2 = ^^fn2;
+static_assert([: r1 :]() == 42);
+static_assert([: r2 :]() == 5);
+static_assert([: r2 :](11) == 11);
+
+// With a dependent reflection.
+template <info R> consteval int fn() { return [:R:](); }
+static_assert(fn<r1>() == 42);
+static_assert(fn<r2>() == 5);
+
+void
+runtime ()
+{
+  [:^^runtime:];
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep5.C b/gcc/testsuite/g++.dg/reflect/dep5.C
new file mode 100644 (file)
index 0000000..4a118de
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  static constexpr int x = 42;
+  using type = int;
+  static void fn (int) { }
+  template<typename T>
+  static void tfn () { }
+  template<typename T>
+  static T var;
+};
+
+template<typename T>
+void
+f ()
+{
+  static_assert ([: ^^T :]::x == 42);
+  typename [: ^^T :]::type a = 42;
+  [: ^^T :]::fn (42);
+  [: ^^T :]::template tfn<([: ^^T :])>();  // { dg-error "expected a reflection of an expression instead of type .S." }
+  auto x = [: ^^T :]::template var<([: ^^T :])>;  // { dg-error "expected a reflection of an expression instead of type .S." }
+}
+
+void
+g ()
+{
+  f<S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep6.C b/gcc/testsuite/g++.dg/reflect/dep6.C
new file mode 100644 (file)
index 0000000..55ebdb7
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that we give a nice error about a missing typename.
+
+struct S {
+  using type = int;
+};
+
+template<typename T>
+void
+f ()
+{
+  [: ^^T :]::type i = 42; // { dg-error "need .typename. before .\\\[: \\\^\\\^T :\\\]::type. because .\\\[: \\\^\\\^T :\\\]. is a dependent scope" }
+}
+
+void
+g ()
+{
+  f<S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep7.C b/gcc/testsuite/g++.dg/reflect/dep7.C
new file mode 100644 (file)
index 0000000..3ed80fd
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<typename T>
+struct Z {};
+
+struct S {
+  static constexpr auto r = ^^Z;
+};
+
+template<typename T, auto R>
+void
+g ()
+{
+ typename [: R :]<int> c1;
+ typename [: T::r :]<int> c2;
+}
+
+void
+f ()
+{
+  g<S, ^^Z>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep8.C b/gcc/testsuite/g++.dg/reflect/dep8.C
new file mode 100644 (file)
index 0000000..cc2c2d7
--- /dev/null
@@ -0,0 +1,70 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+struct S {
+  int i;
+  static int si;
+  static int mfn () { return 1; }
+};
+
+int S::si;
+
+template<typename T>
+struct C {
+  int i;
+  static T si;
+  static T mfn() { return 1; }
+};
+
+template<info R>
+void
+f ()
+{
+  typename [:R:] r{1};
+  ++[:R:]::si;
+  [:R:]::si += [:R:]::mfn ();
+  using L = [:R:];
+  L r2{2};
+}
+
+template<info R>
+struct A {
+  typename [:R:] r;
+  int i = [:R:]::mfn ();
+  using L = [:R:];
+  L r2;
+  int mem () { return [:R:]::si; }
+};
+
+template<info R>
+void
+f2 ()
+{
+  typename [:R:]<int> r{1};
+  ++template [:R:]<int>::si;
+  template [:R:]<int>::si += template [:R:]<int>::mfn ();
+  using L = [:R:]<int>;
+  L r2{2};
+}
+
+template<info R>
+struct A2 {
+  typename [:R:]<int> r;
+  int i = template [:R:]<int>::mfn ();
+  using L = [:R:]<int>;
+  L r2;
+  int mem () { return template [:R:]<int>::si; }
+};
+
+void
+doit ()
+{
+  f<^^S>();
+  f<^^C<int>>();
+  A<^^S> a;
+  A<^^C<int>> a2;
+  f2<^^C>();
+  A2<^^C> a3;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/dep9.C b/gcc/testsuite/g++.dg/reflect/dep9.C
new file mode 100644 (file)
index 0000000..b894152
--- /dev/null
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Dependent variable templates.
+
+using info = decltype(^^void);
+
+template<typename T>
+constexpr T magic = 1234;
+
+void foo (int);
+
+template<info R>
+void
+f ()
+{
+  int i = template [:R:]<int>;
+  constexpr int ci = template [:R:]<int>;
+  foo (template [:R:]<int>);
+}
+
+template<auto R>
+void
+f2 ()
+{
+  int i = [:R:];
+  constexpr int ic = [:R:];
+  foo ([:R:]);
+}
+
+constexpr info V = ^^magic;
+constexpr info VT = ^^magic<int>;
+
+void
+g ()
+{
+  f<^^magic>();
+  f<V>();
+  f2<^^magic<int>>();
+  f2<VT>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag1.C b/gcc/testsuite/g++.dg/reflect/diag1.C
new file mode 100644 (file)
index 0000000..2d34623
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that we offer some helpful diagnostic.
+
+struct S {
+  template<typename T>
+  void tfn (T) { }
+};
+
+template<typename T>
+constexpr T fortytwo = 42;
+
+void
+f ()
+{
+  S s;
+  s.[: ^^S::tfn :](42); // { dg-error "reflection .S::tfn. not usable in a splice expression" }
+// { dg-message "add .template. to denote a template" "" { target *-*-* } .-1 }
+  s.template [: ^^S::tfn :](42);
+
+  constexpr auto r = ^^fortytwo;
+  constexpr int i1 = [:r:]<int>; // { dg-error "reflection .fortytwo<int>. not usable in a splice expression with template arguments" }
+// { dg-message "add .template. to denote a template" "" { target *-*-* } .-1 }
+  constexpr int i2 = template [:r:]<int>;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag2.C b/gcc/testsuite/g++.dg/reflect/diag2.C
new file mode 100644 (file)
index 0000000..7c2c827
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// This used to say ''splice_scope' not supported by
+// dump_type_prefix<typeprefixerror>r'splice_scope' not supported
+// by dump_type_suffix'.  Eeech.
+
+using info = decltype(^^void);
+
+struct S {
+  int i;
+};
+
+template<info R>
+void
+f ()
+{
+  typename [:R:] r{1};  // { dg-message "previous declaration as .\\\[: R :\\\] r." }
+  typename [:R:] r{2};  // { dg-error "conflicting declaration .\\\[: R :\\\] r." }
+}
+
+int
+main ()
+{
+  f<^^S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag3.C b/gcc/testsuite/g++.dg/reflect/diag3.C
new file mode 100644 (file)
index 0000000..754a8b2
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that we suggest adding "constexpr" or "constinit" (where allowed).
+
+auto foo = ^^int;  // { dg-error "consteval-only variable .foo." }
+// { dg-message "add .constexpr. or .constinit." "" { target *-*-* } .-1 }
+constinit auto foo_ = ^^int;
+constexpr auto foo__ = ^^int;
+thread_local auto tfoo = ^^int;  // { dg-error "consteval-only variable .tfoo." }
+// { dg-message "add .constexpr. or .constinit." "" { target *-*-* } .-1 }
+thread_local constinit auto tfoo_ = ^^int;
+thread_local constexpr auto tfoo__ = ^^int;
+
+void
+f ()
+{
+  auto ref = ^^int;  // { dg-error "consteval-only variable .ref." }
+// { dg-message "add .constexpr." "" { target *-*-* } .-1 }
+  constexpr auto ref_ = ^^int;
+  static auto sref = ^^int;  // { dg-error "consteval-only variable .sref." }
+// { dg-message "add .constexpr. or .constinit." "" { target *-*-* } .-1 }
+  static auto constinit sref_ = ^^int;
+  static auto constexpr sref__ = ^^int;
+  thread_local auto tref = ^^int; // { dg-error "consteval-only variable .tref." }
+// { dg-message "add .constexpr. or .constinit." "" { target *-*-* } .-1 }
+  thread_local constinit auto tref_ = ^^int;
+  thread_local constexpr auto tref__ = ^^int;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag4.C b/gcc/testsuite/g++.dg/reflect/diag4.C
new file mode 100644 (file)
index 0000000..5aabeae
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that we suggest adding "typename" (where allowed).
+
+constexpr auto r = ^^int;
+
+template<typename> struct S {};
+
+void
+g ()
+{
+  [:r:] i = 42;  // { dg-error "expected a reflection of an expression" }
+// { dg-message "add .typename. to denote a type outside a type-only context" "" { target *-*-* } .-1 }
+
+  S<([:r:])> s;  // { dg-error "expected a reflection of an expression|template argument 1 is invalid" }
+// { dg-message "add .typename. to denote a type outside a type-only context" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/display_string_of1.C b/gcc/testsuite/g++.dg/reflect/display_string_of1.C
new file mode 100644 (file)
index 0000000..b88828f
--- /dev/null
@@ -0,0 +1,230 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::display_string_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T () {}
+  T (const T &) {}
+  ~T () {}
+};
+struct U {
+  int u;
+  int v : 5;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+namespace {
+  namespace NS2 {}
+};
+namespace NS3 {
+  namespace {
+    namespace {
+      namespace NS4 {}
+    }
+  }
+};
+enum { Z };
+
+constexpr auto ctx = access_context::current ();
+
+struct AN { int a; long b; char c; };
+
+[[=1, =AN { 1, 42, ' ' }]] void bar (long, const T f, int g[2], T &);
+
+struct V1 {
+  constexpr V1 (int) {}
+};
+struct V2 {
+  V2 &operator = (const V2 &);
+};
+struct V3 {
+  V3 &operator = (V3 &&);
+};
+struct V4 {
+  V4 &operator += (const V4 &);
+};
+struct V5 {
+  operator int ();
+};
+int operator ""_a (const char *);
+
+void
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (display_string_of (^^a) == "a");
+  static_assert (display_string_of (^^b) == "b");
+  static_assert (display_string_of (^^c) == "c");
+  static_assert (display_string_of (^^d) == "d");
+  static_assert (display_string_of (^^e) == "e");
+  static_assert (display_string_of (parameters_of (^^foo)[0]) == "<parameter a of void foo(int, long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^foo)[1]) == "<parameter b of void foo(int, long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^foo)[2]) == "<parameter c of void foo(int, long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^foo)[3]) == "<parameter d of void foo(int, long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^foo)[4]) == "<parameter e of void foo(int, long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^bar)[0]) == "<unnamed parameter 1 of void bar(long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^bar)[1]) == "<parameter f of void bar(long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^bar)[2]) == "<parameter g of void bar(long int, T, int*, T&)>");
+  static_assert (display_string_of (parameters_of (^^bar)[3]) == "<unnamed parameter 4 of void bar(long int, T, int*, T&)>");
+  static_assert (display_string_of (null_reflection) == "<null reflection>");
+  static_assert (display_string_of (^^::) == "::");
+  static_assert (display_string_of (^^NS2) == "{anonymous}::NS2");
+  static_assert (display_string_of (parent_of (^^NS2)) == "{anonymous}");
+  static_assert (display_string_of (^^NS3::NS4) == "NS3::{anonymous}::{anonymous}::NS4");
+  static_assert (display_string_of (parent_of (^^NS3::NS4)) == "NS3::{anonymous}::{anonymous}");
+  static_assert (display_string_of (parent_of (parent_of (^^NS3::NS4))) == "NS3::{anonymous}");
+  static_assert (display_string_of (parent_of (parent_of (parent_of   (^^NS3::NS4)))) == "NS3");
+  static_assert (display_string_of (^^Z) == "Z");
+  static_assert (display_string_of (parent_of (^^Z)) == "<unnamed enum>");
+  static_assert (display_string_of (reflect_constant (42)) == "42");
+  static_assert (display_string_of (reflect_object (arr[1])) == "arr[1]");
+  static_assert (display_string_of (^^arr) == "arr");
+  static_assert (display_string_of (^^a3) == "a3");
+  static_assert (display_string_of (^^fn) == "void fn()");
+  static_assert (display_string_of (^^fn2) == "auto& fn2()");
+  static_assert (display_string_of (^^Enum::A) == "A");
+  static_assert (display_string_of (^^Alias) == "Alias {aka int}");
+  static_assert (display_string_of (^^S) == "S");
+  static_assert (display_string_of (^^S::mem) == "S::mem");
+  static_assert (display_string_of (members_of (^^S, ctx)[1]) == "S::<unnamed bit-field>");
+  static_assert (display_string_of (^^TCls) == "template<auto <anonymous> > struct TCls");
+  static_assert (display_string_of (^^TFn) == "template<auto <anonymous> > void TFn()");
+  static_assert (display_string_of (^^TVar) == "template<auto <anonymous> > int TVar<<anonymous> >");
+  static_assert (display_string_of (^^Concept) == "template<auto <anonymous> > concept Concept");
+  static_assert (display_string_of (^^NSAlias) == "NSAlias");
+  static_assert (display_string_of (^^NS) == "NS");
+  static_assert (display_string_of (bases_of (^^S, ctx)[0]) == "S: B");
+  static_assert (display_string_of (data_member_spec (^^int, { .name = "member", .alignment = 128, .no_unique_address = true })) == "(int, member, 128, , true)");
+  static_assert (display_string_of (data_member_spec (^^const int, { .name = "member", .bit_width = 6 })) == "(const int, member, , 6, false)");
+  static_assert (display_string_of (data_member_spec (^^int, { .bit_width = 0 })) == "(int, , , 0, false)");
+  static_assert (display_string_of (data_member_spec (^^long, { .bit_width = 5 })) == "(long int, , , 5, false)");
+  static_assert (display_string_of (annotations_of (^^bar)[0]) == "[[=1]]");
+  static_assert (display_string_of (annotations_of (^^bar)[1]) == "[[=AN{1, 42, ' '}]]");
+  static_assert (display_string_of (^^int) == "int");
+  static_assert (display_string_of (^^unsigned) == "unsigned int");
+  static_assert (display_string_of (^^unsigned long) == "long unsigned int");
+  static_assert (display_string_of (^^const long long &) == "const long long int&");
+  static_assert (display_string_of (^^const double **) == "const double**");
+  static_assert (display_string_of (^^int (int)) == "int(int)");
+  static_assert (display_string_of (^^int (&) (int, long, S &)) == "int (&)(int, long int, S&)");
+  static_assert (display_string_of (^^int (*) (int, long, S &)) == "int (*)(int, long int, S&)");
+  static_assert (display_string_of (members_of (^^V2, ctx)[0]) == "V2& V2::operator=(const V2&)");
+  static_assert (display_string_of (members_of (^^V3, ctx)[0]) == "V3& V3::operator=(V3&&)");
+  static_assert (display_string_of (members_of (^^V4, ctx)[0]) == "V4& V4::operator+=(const V4&)");
+  static_assert (display_string_of (members_of (^^V5, ctx)[0]) == "V5::operator int()");
+  static_assert (display_string_of (^^operator""_a) == "int operator\"\"_a(const char*)");
+}
+
+namespace NS5 {
+  int arr[] = {1, 2, 3};
+  auto [a1, a2, a3] = arr;
+  void fn();
+  auto &fn2();
+  enum Enum { A };
+  using Alias = int;
+  struct B {};
+  struct S : B {
+    int mem;
+    int : 0;
+  };
+  struct T {
+    T () {}
+    T (const T &) {}
+    ~T () {}
+  };
+  struct U {
+    int u;
+    int v : 5;
+  };
+  template<auto> struct TCls {};
+  template<auto> void TFn();
+  template<auto> int TVar;
+  template<auto> concept Concept = requires { true; };
+  enum { Z };
+
+  struct AN { int a; long b; char c; };
+
+  [[=1, =AN { 1, 42, ' ' }]] void bar (long, const T f, int g[2], T &);
+
+  struct V1 {
+    constexpr V1 (int) {}
+  };
+  struct V2 {
+    V2 &operator = (const V2 &);
+  };
+  struct V3 {
+    V3 &operator = (V3 &&);
+  };
+  struct V4 {
+    V4 &operator += (const V4 &);
+  };
+  struct V5 {
+    operator int ();
+  };
+  int operator ""_a (const char *);
+
+  void
+  foo (int a, const long b, T c, int d[4], T &e)
+  {
+    static_assert (display_string_of (^^a) == "a");
+    static_assert (display_string_of (^^b) == "b");
+    static_assert (display_string_of (^^c) == "c");
+    static_assert (display_string_of (^^d) == "d");
+    static_assert (display_string_of (^^e) == "e");
+    static_assert (display_string_of (parameters_of (^^foo)[0]) == "<parameter a of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^foo)[1]) == "<parameter b of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^foo)[2]) == "<parameter c of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^foo)[3]) == "<parameter d of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^foo)[4]) == "<parameter e of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^bar)[0]) == "<unnamed parameter 1 of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^bar)[1]) == "<parameter f of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^bar)[2]) == "<parameter g of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (display_string_of (parameters_of (^^bar)[3]) == "<unnamed parameter 4 of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (display_string_of (^^Z) == "NS5::Z");
+    static_assert (display_string_of (parent_of (^^Z)) == "NS5::<unnamed enum>");
+    static_assert (display_string_of (reflect_constant (42)) == "42");
+    static_assert (display_string_of (reflect_object (arr[1])) == "NS5::arr[1]");
+    static_assert (display_string_of (^^arr) == "NS5::arr");
+    static_assert (display_string_of (^^a3) == "NS5::a3");
+    static_assert (display_string_of (^^fn) == "void NS5::fn()");
+    static_assert (display_string_of (^^fn2) == "auto& NS5::fn2()");
+    static_assert (display_string_of (^^Enum::A) == "NS5::A");
+    static_assert (display_string_of (^^Alias) == "NS5::Alias {aka int}");
+    static_assert (display_string_of (^^S) == "NS5::S");
+    static_assert (display_string_of (^^S::mem) == "NS5::S::mem");
+    static_assert (display_string_of (members_of (^^S, ctx)[1]) == "NS5::S::<unnamed bit-field>");
+    static_assert (display_string_of (^^TCls) == "template<auto <anonymous> > struct NS5::TCls");
+    static_assert (display_string_of (^^TFn) == "template<auto <anonymous> > void NS5::TFn()");
+    static_assert (display_string_of (^^TVar) == "template<auto <anonymous> > int NS5::TVar<<anonymous> >");
+    static_assert (display_string_of (^^Concept) == "template<auto <anonymous> > concept NS5::Concept");
+    static_assert (display_string_of (bases_of (^^S, ctx)[0]) == "NS5::S: NS5::B");
+    static_assert (display_string_of (annotations_of (^^bar)[0]) == "[[=1]]");
+    static_assert (display_string_of (annotations_of (^^bar)[1]) == "[[=NS5::AN{1, 42, ' '}]]");
+    static_assert (display_string_of (^^int (&) (int, long, S &)) == "int (&)(int, long int, NS5::S&)");
+    static_assert (display_string_of (^^int (*) (int, long, S &)) == "int (*)(int, long int, NS5::S&)");
+    static_assert (display_string_of (members_of (^^V2, ctx)[0]) == "NS5::V2& NS5::V2::operator=(const NS5::V2&)");
+    static_assert (display_string_of (members_of (^^V3, ctx)[0]) == "NS5::V3& NS5::V3::operator=(NS5::V3&&)");
+    static_assert (display_string_of (members_of (^^V4, ctx)[0]) == "NS5::V4& NS5::V4::operator+=(const NS5::V4&)");
+    static_assert (display_string_of (members_of (^^V5, ctx)[0]) == "NS5::V5::operator int()");
+    static_assert (display_string_of (^^operator""_a) == "int NS5::operator\"\"_a(const char*)");
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/eh1.C b/gcc/testsuite/g++.dg/reflect/eh1.C
new file mode 100644 (file)
index 0000000..10eba7b
--- /dev/null
@@ -0,0 +1,355 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test throwing std::meta::exception.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval void
+eval (int n)
+{
+  switch (n)
+    {
+    case 0:
+      is_reference_type (^^n);
+      break;
+    case 1:
+      is_class_type (^^n);
+      break;
+    case 2:
+      is_union_type (^^n);
+      break;
+    case 3:
+      is_enum_type (^^n);
+      break;
+    case 4:
+      is_member_function_pointer_type (^^n);
+      break;
+    case 5:
+      is_member_object_pointer_type (^^n);
+      break;
+    case 6:
+      is_array_type (^^n);
+      break;
+    case 7:
+      is_pointer_type (^^n);
+      break;
+    case 8:
+      is_void_type (^^n);
+      break;
+    case 9:
+      is_null_pointer_type (^^n);
+      break;
+    case 10:
+      is_integral_type (^^n);
+      break;
+    case 11:
+      is_floating_point_type (^^n);
+      break;
+    case 12:
+      is_lvalue_reference_type (^^n);
+      break;
+    case 13:
+      is_rvalue_reference_type (^^n);
+      break;
+    case 14:
+      is_reflection_type (^^n);
+      break;
+    case 15:
+      remove_const (^^n);
+      break;
+    case 16:
+      remove_volatile (^^n);
+      break;
+    case 17:
+      remove_cv (^^n);
+      break;
+    case 18:
+      add_const (^^n);
+      break;
+    case 19:
+      add_volatile (^^n);
+      break;
+    case 20:
+      add_cv (^^n);
+      break;
+    case 21:
+      is_object_type (^^n);
+      break;
+    case 22:
+      is_arithmetic_type (^^n);
+      break;
+    case 23:
+      is_member_pointer_type (^^n);
+      break;
+    case 24:
+      is_scalar_type (^^n);
+      break;
+    case 25:
+      is_fundamental_type (^^n);
+      break;
+    case 26:
+      is_compound_type (^^n);
+      break;
+    case 27:
+      remove_reference (^^n);
+      break;
+    case 28:
+      add_lvalue_reference (^^n);
+      break;
+    case 29:
+      add_rvalue_reference (^^n);
+      break;
+    case 30:
+      make_signed (^^n);
+      break;
+    case 31:
+      make_unsigned (^^n);
+      break;
+    case 32:
+      remove_extent (^^n);
+      break;
+    case 33:
+      remove_all_extents (^^n);
+      break;
+    case 34:
+      remove_pointer (^^n);
+      break;
+    case 35:
+      add_pointer (^^n);
+      break;
+    case 36:
+      is_const_type (^^n);
+      break;
+    case 37:
+      is_volatile_type (^^n);
+      break;
+    case 38:
+      is_trivially_copyable_type (^^n);
+      break;
+    case 41:
+      is_standard_layout_type (^^n);
+      break;
+    case 42:
+      is_empty_type (^^n);
+      break;
+    case 43:
+      is_polymorphic_type (^^n);
+      break;
+    case 44:
+      is_abstract_type (^^n);
+      break;
+    case 45:
+      is_final_type (^^n);
+      break;
+    case 46:
+      is_aggregate_type (^^n);
+      break;
+    case 47:
+      is_consteval_only_type (^^n);
+      break;
+    case 48:
+      is_signed_type (^^n);
+      break;
+    case 49:
+      is_unsigned_type (^^n);
+      break;
+    case 50:
+      is_bounded_array_type (^^n);
+      break;
+    case 51:
+      is_unbounded_array_type (^^n);
+      break;
+    case 52:
+      is_scoped_enum_type (^^n);
+      break;
+    case 53:
+      is_default_constructible_type (^^n);
+      break;
+    case 54:
+      is_copy_constructible_type (^^n);
+      break;
+    case 55:
+      is_move_constructible_type (^^n);
+      break;
+    case 56:
+      is_copy_assignable_type (^^n);
+      break;
+    case 57:
+      is_move_assignable_type (^^n);
+      break;
+    case 58:
+      is_destructible_type (^^n);
+      break;
+    case 59:
+      is_trivially_default_constructible_type (^^n);
+      break;
+    case 60:
+      is_trivially_copy_constructible_type (^^n);
+      break;
+    case 61:
+      is_trivially_move_constructible_type (^^n);
+      break;
+    case 62:
+      is_trivially_copy_assignable_type (^^n);
+      break;
+    case 63:
+      is_trivially_move_assignable_type (^^n);
+      break;
+    case 64:
+      is_trivially_destructible_type (^^n);
+      break;
+    case 65:
+      is_nothrow_default_constructible_type (^^n);
+      break;
+    case 66:
+      is_nothrow_copy_constructible_type (^^n);
+      break;
+    case 67:
+      is_nothrow_move_constructible_type (^^n);
+      break;
+    case 68:
+      is_nothrow_copy_assignable_type (^^n);
+      break;
+    case 69:
+      is_nothrow_move_assignable_type (^^n);
+      break;
+    case 70:
+      is_nothrow_destructible_type (^^n);
+      break;
+    case 72:
+      has_virtual_destructor (^^n);
+      break;
+    case 73:
+      has_unique_object_representations (^^n);
+      break;
+    case 74:
+      rank (^^n);
+      break;
+    case 75:
+      extent (^^n);
+      break;
+    case 76:
+      extent (^^n, 2);
+      break;
+    case 77:
+      remove_cvref (^^n);
+      break;
+    case 78:
+      decay (^^n);
+      break;
+    case 79:
+      underlying_type (^^n);
+      break;
+    case 80:
+      is_implicit_lifetime_type (^^n);
+      break;
+    case 81:
+      is_swappable_type (^^n);
+      break;
+    case 82:
+      is_nothrow_swappable_type (^^n);
+      break;
+    case 83:
+      unwrap_reference (^^n);
+      break;
+    case 84:
+      unwrap_ref_decay (^^n);
+      break;
+   default:
+      break;
+    }
+}
+
+consteval bool
+test (int n)
+{
+  try { eval (n); }
+  catch (std::meta::exception &) { return true; }
+  catch (...) { return false; }
+  return false;
+}
+
+static_assert (test (0));
+static_assert (test (1));
+static_assert (test (2));
+static_assert (test (3));
+static_assert (test (4));
+static_assert (test (5));
+static_assert (test (6));
+static_assert (test (7));
+static_assert (test (8));
+static_assert (test (9));
+static_assert (test (10));
+static_assert (test (11));
+static_assert (test (12));
+static_assert (test (13));
+static_assert (test (14));
+static_assert (test (15));
+static_assert (test (16));
+static_assert (test (17));
+static_assert (test (18));
+static_assert (test (19));
+static_assert (test (20));
+static_assert (test (21));
+static_assert (test (22));
+static_assert (test (23));
+static_assert (test (24));
+static_assert (test (25));
+static_assert (test (26));
+static_assert (test (27));
+static_assert (test (28));
+static_assert (test (29));
+static_assert (test (30));
+static_assert (test (31));
+static_assert (test (32));
+static_assert (test (33));
+static_assert (test (34));
+static_assert (test (35));
+static_assert (test (36));
+static_assert (test (37));
+static_assert (test (38));
+static_assert (test (41));
+static_assert (test (42));
+static_assert (test (43));
+static_assert (test (44));
+static_assert (test (45));
+static_assert (test (46));
+static_assert (test (47));
+static_assert (test (48));
+static_assert (test (49));
+static_assert (test (50));
+static_assert (test (51));
+static_assert (test (52));
+static_assert (test (53));
+static_assert (test (54));
+static_assert (test (55));
+static_assert (test (56));
+static_assert (test (57));
+static_assert (test (58));
+static_assert (test (59));
+static_assert (test (60));
+static_assert (test (61));
+static_assert (test (62));
+static_assert (test (63));
+static_assert (test (64));
+static_assert (test (65));
+static_assert (test (66));
+static_assert (test (67));
+static_assert (test (68));
+static_assert (test (69));
+static_assert (test (70));
+static_assert (test (72));
+static_assert (test (73));
+static_assert (test (74));
+static_assert (test (75));
+static_assert (test (76));
+static_assert (test (77));
+static_assert (test (78));
+static_assert (test (79));
+static_assert (test (80));
+static_assert (test (81));
+static_assert (test (82));
+static_assert (test (83));
+static_assert (test (84));
diff --git a/gcc/testsuite/g++.dg/reflect/eh2.C b/gcc/testsuite/g++.dg/reflect/eh2.C
new file mode 100644 (file)
index 0000000..21f9879
--- /dev/null
@@ -0,0 +1,91 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test throwing std::meta::exception.
+
+#include <meta>
+
+using namespace std::meta;
+
+int i;
+static_assert (is_reference_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_class_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_union_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_enum_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_member_function_pointer_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_member_object_pointer_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_pointer_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_array_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_void_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_null_pointer_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_integral_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_floating_point_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_lvalue_reference_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_rvalue_reference_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert (is_reflection_type (^^i)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_const (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_volatile (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_cv (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((add_const (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((add_volatile (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((add_cv (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_object_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_arithmetic_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_member_pointer_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_scalar_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_fundamental_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_compound_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_reference (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((add_lvalue_reference (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((add_rvalue_reference (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((make_signed (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((make_unsigned (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_extent (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_all_extents (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_pointer (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((add_pointer (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_const_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_volatile_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_copyable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_standard_layout_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_empty_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_polymorphic_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_abstract_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_final_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_aggregate_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_consteval_only_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_signed_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_unsigned_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_bounded_array_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_unbounded_array_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_scoped_enum_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_default_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_copy_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_move_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_copy_assignable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_move_assignable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_destructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_default_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_copy_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_move_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_copy_assignable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_move_assignable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_trivially_destructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_default_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_copy_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_move_constructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_copy_assignable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_move_assignable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_destructible_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((has_virtual_destructor (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((has_unique_object_representations (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((rank (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((extent (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((extent (^^i, 42), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((remove_cvref (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((decay (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((underlying_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_implicit_lifetime_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_swappable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((is_nothrow_swappable_type (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((unwrap_reference (^^i), true)); // { dg-error "non-constant|uncaught exception" }
+static_assert ((unwrap_ref_decay (^^i), true)); // { dg-error "non-constant|uncaught exception" }
diff --git a/gcc/testsuite/g++.dg/reflect/eh3.C b/gcc/testsuite/g++.dg/reflect/eh3.C
new file mode 100644 (file)
index 0000000..a08afec
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test throwing std::meta::exception.
+
+#include <meta>
+
+consteval void
+foo ()
+{
+  throw std::meta::exception{"foo", ^^int};
+}
+
+consteval bool
+test ()
+{
+  try { foo (); }
+  catch (std::meta::exception &) { return true; }
+  catch (...) { return false; }
+  return false;
+}
+
+static_assert (test ());
diff --git a/gcc/testsuite/g++.dg/reflect/eh4.C b/gcc/testsuite/g++.dg/reflect/eh4.C
new file mode 100644 (file)
index 0000000..754ac90
--- /dev/null
@@ -0,0 +1,221 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test throwing std::meta::exception.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S { };
+
+consteval void
+eval (int n)
+{
+  switch (n)
+    {
+    case 0:
+      is_same_type (^^S, ^^n);
+      break;
+    case 1:
+      is_same_type (^^n, ^^S);
+      break;
+    case 2:
+      is_base_of_type (^^S, ^^n);
+      break;
+    case 3:
+      is_base_of_type (^^n, ^^S);
+      break;
+    case 4:
+      is_virtual_base_of_type (^^S, ^^n);
+      break;
+    case 5:
+      is_virtual_base_of_type (^^n, ^^S);
+      break;
+    case 6:
+      is_convertible_type (^^S, ^^n);
+      break;
+    case 7:
+      is_convertible_type (^^n, ^^S);
+      break;
+    case 8:
+      is_nothrow_convertible_type (^^S, ^^n);
+      break;
+    case 9:
+      is_nothrow_convertible_type (^^n, ^^S);
+      break;
+    case 10:
+      is_layout_compatible_type (^^S, ^^n);
+      break;
+    case 11:
+      is_layout_compatible_type (^^n, ^^S);
+      break;
+    case 12:
+      is_pointer_interconvertible_base_of_type (^^S, ^^n);
+      break;
+    case 13:
+      is_pointer_interconvertible_base_of_type (^^n, ^^S);
+      break;
+    case 14:
+      is_assignable_type (^^S, ^^n);
+      break;
+    case 15:
+      is_assignable_type (^^n, ^^S);
+      break;
+    case 16:
+      is_trivially_assignable_type (^^S, ^^n);
+      break;
+    case 17:
+      is_trivially_assignable_type (^^n, ^^S);
+      break;
+    case 18:
+      is_nothrow_assignable_type (^^S, ^^n);
+      break;
+    case 19:
+      is_nothrow_assignable_type (^^n, ^^S);
+      break;
+    case 20:
+      reference_constructs_from_temporary (^^S, ^^n);
+      break;
+    case 21:
+      reference_constructs_from_temporary (^^n, ^^S);
+      break;
+    case 22:
+      reference_converts_from_temporary (^^S, ^^n);
+      break;
+    case 23:
+      reference_converts_from_temporary (^^n, ^^S);
+      break;
+    case 24:
+      type_order (^^S, ^^n);
+      break;
+    case 25:
+      type_order (^^n, ^^S);
+      break;
+    case 26:
+      is_constructible_type (^^n, {});
+      break;
+    case 27:
+      is_constructible_type (^^S, { ^^S, ^^n, ^^S });
+      break;
+    case 28:
+      is_trivially_constructible_type (^^n, {});
+      break;
+    case 29:
+      is_trivially_constructible_type (^^S, { ^^n, ^^S, ^^S, ^^S });
+      break;
+    case 30:
+      is_nothrow_constructible_type (^^n, {});
+      break;
+    case 31:
+      is_nothrow_constructible_type (^^S, { ^^S, ^^S, ^^S, ^^S, ^^n });
+      break;
+    case 32:
+      is_invocable_type (^^n, {});
+      break;
+    case 33:
+      is_invocable_type (^^S, { ^^S, ^^S, ^^n, ^^S });
+      break;
+    case 34:
+      is_nothrow_invocable_type (^^n, {});
+      break;
+    case 35:
+      is_nothrow_invocable_type (^^S, { ^^S, ^^n, ^^S });
+      break;
+    case 36:
+      is_invocable_r_type (^^n, ^^S, {});
+      break;
+    case 37:
+      is_invocable_r_type (^^S, ^^n, {});
+      break;
+    case 38:
+      is_invocable_r_type (^^S, ^^S, { ^^S, ^^n, ^^S });
+      break;
+    case 39:
+      is_nothrow_invocable_r_type (^^n, ^^S, {});
+      break;
+    case 40:
+      is_nothrow_invocable_r_type (^^S, ^^n, {});
+      break;
+    case 41:
+      is_nothrow_invocable_r_type (^^S, ^^S, { ^^S, ^^n, ^^S });
+      break;
+    case 42:
+      invoke_result (^^n, {});
+      break;
+    case 43:
+      invoke_result (^^S, { ^^S, ^^n, ^^S });
+      break;
+    case 44:
+      is_swappable_with_type (^^S, ^^n);
+      break;
+    case 45:
+      is_swappable_with_type (^^n, ^^S);
+      break;
+    case 46:
+      is_nothrow_swappable_with_type (^^S, ^^n);
+      break;
+    case 47:
+      is_nothrow_swappable_with_type (^^n, ^^S);
+      break;
+    default:
+      break;
+    }
+}
+
+consteval bool
+test (int n)
+{
+  try { eval (n); }
+  catch (std::meta::exception &) { return true; }
+  catch (...) { return false; }
+  return false;
+}
+
+static_assert (test (0));
+static_assert (test (1));
+static_assert (test (2));
+static_assert (test (3));
+static_assert (test (4));
+static_assert (test (5));
+static_assert (test (6));
+static_assert (test (7));
+static_assert (test (8));
+static_assert (test (9));
+static_assert (test (10));
+static_assert (test (11));
+static_assert (test (12));
+static_assert (test (13));
+static_assert (test (14));
+static_assert (test (15));
+static_assert (test (16));
+static_assert (test (17));
+static_assert (test (18));
+static_assert (test (19));
+static_assert (test (20));
+static_assert (test (21));
+static_assert (test (22));
+static_assert (test (23));
+static_assert (test (24));
+static_assert (test (25));
+static_assert (test (26));
+static_assert (test (27));
+static_assert (test (28));
+static_assert (test (29));
+static_assert (test (30));
+static_assert (test (31));
+static_assert (test (32));
+static_assert (test (33));
+static_assert (test (34));
+static_assert (test (35));
+static_assert (test (36));
+static_assert (test (37));
+static_assert (test (38));
+static_assert (test (39));
+static_assert (test (40));
+static_assert (test (41));
+static_assert (test (42));
+static_assert (test (43));
+static_assert (test (44));
+static_assert (test (45));
+static_assert (test (46));
+static_assert (test (47));
diff --git a/gcc/testsuite/g++.dg/reflect/eh5.C b/gcc/testsuite/g++.dg/reflect/eh5.C
new file mode 100644 (file)
index 0000000..9e6c781
--- /dev/null
@@ -0,0 +1,103 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test throwing std::meta::exception.
+
+#include <meta>
+
+using namespace std::meta;
+
+template <int N>
+struct S {};
+
+consteval bool
+foo (info x)
+{
+  try
+    {
+      is_class_type (x);
+    }
+  catch (std::meta::exception &ex)
+    {
+      std::string_view what = ex.what ();
+      info from = ex.from ();
+      std::source_location loc = ex.where ();
+      if (loc.line () != std::source_location::current ().line () - 7
+         || from != ^^std::meta::is_class_type
+         || what != "reflection does not represent a type"
+         || ex.u8what () != u8"reflection does not represent a type")
+       return false;
+      return true;
+    }
+  return false;
+}
+
+consteval bool
+bar (info x)
+{
+  try
+    {
+      parameters_of (x);
+    }
+  catch (std::meta::exception &ex)
+    {
+      std::string_view what = ex.what ();
+      info from = ex.from ();
+      std::source_location loc = ex.where ();
+      if (loc.line () != std::source_location::current ().line () - 7
+         || from != ^^std::meta::parameters_of
+         || what != "reflection does not represent a function or function type"
+         || ex.u8what () != u8"reflection does not represent a function or function type")
+       return false;
+      return true;
+    }
+  return false;
+}
+
+consteval bool
+baz (info x)
+{
+  try
+    {
+      data_member_spec (x, { .name = "consteval" });
+    }
+  catch (std::meta::exception &ex)
+    {
+      std::string_view what = ex.what ();
+      info from = ex.from ();
+      std::source_location loc = ex.where ();
+      if (loc.line () != std::source_location::current ().line () - 7
+         || from != ^^std::meta::data_member_spec
+         || what != "name is a keyword"
+         || ex.u8what () != u8"name is a keyword")
+       return false;
+      return true;
+    }
+  return false;
+}
+
+consteval bool
+qux (info x)
+{
+  try
+    {
+      can_substitute (^^S, { x });
+    }
+  catch (std::meta::exception &ex)
+    {
+      std::string_view what = ex.what ();
+      info from = ex.from ();
+      std::source_location loc = ex.where ();
+      if (loc.line () != std::source_location::current ().line () - 7
+         || from != ^^std::meta::can_substitute
+         || what != "invalid argument to can_substitute"
+         || ex.u8what () != u8"invalid argument to can_substitute")
+       return false;
+      return true;
+    }
+  return false;
+}
+
+static_assert (foo (^^::));
+static_assert (bar (^^::));
+static_assert (baz (^^int));
+static_assert (qux (^^::));
diff --git a/gcc/testsuite/g++.dg/reflect/eh6.C b/gcc/testsuite/g++.dg/reflect/eh6.C
new file mode 100644 (file)
index 0000000..b33cf31
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-freflection -fexec-charset=IBM1047" }
+// Test throwing std::meta::exception.
+
+#include "eh5.C"
diff --git a/gcc/testsuite/g++.dg/reflect/eh7.C b/gcc/testsuite/g++.dg/reflect/eh7.C
new file mode 100644 (file)
index 0000000..2a06524
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-freflection -fexec-charset=IBM1047" }
+// Test std::meta::exception.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+foo ()
+{
+  exception a (u8"This is a string", ^^foo);
+  if (std::string_view (a.what ()) != std::string_view ("This is a string"))
+    return false;
+  exception b ("This is a string", ^^foo);
+  if (b.u8what () != std::u8string_view (u8"This is a string"))
+    return false;
+  return true;
+}
+
+static_assert (foo ());
diff --git a/gcc/testsuite/g++.dg/reflect/eh8.C b/gcc/testsuite/g++.dg/reflect/eh8.C
new file mode 100644 (file)
index 0000000..ac4afa4
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "ISO-8859-2" }
+// { dg-options "-freflection -fexec-charset=ISO-8859-2" }
+// Test std::meta::exception.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+foo ()
+{
+  exception a (u8"h\u00e1\U0000010Dky a \u010d\u00E1rky", ^^foo);
+  if (std::string_view (a.what ()) != std::string_view ("h\u00e1\U0000010Dky a \u010d\u00E1rky"))
+    return false;
+  exception b ("h\u00e1\U0000010Dky a \u010d\u00E1rky", ^^foo);
+  if (b.u8what () != std::u8string_view (u8"h\u00e1\U0000010Dky a \u010d\u00E1rky"))
+    return false;
+  return true;
+}
+
+consteval bool
+bar ()
+{
+  exception a (u8"\N{GRINNING FACE}\N{GRINNING FACE WITH SMILING EYES}\N{LEFT SPEECH BUBBLE}", ^^foo);
+  const char *b = a.what ();   // { dg-message "in 'constexpr' expansion of 'a.std::meta::exception::what\\\(\\\)" }
+  return true;                 // { dg-error "inline assembly is not a constant expression" "" { target *-*-* } 0 }
+}
+
+static_assert (foo ());
+constexpr auto c = bar ();
diff --git a/gcc/testsuite/g++.dg/reflect/eh9.C b/gcc/testsuite/g++.dg/reflect/eh9.C
new file mode 100644 (file)
index 0000000..3051d41
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test throwing an exception in a template.
+
+#include <meta>
+
+enum E : int;
+template <int K>
+constexpr auto R = enumerators_of(^^E)[0];
+enum E : int { A, B, C };
+static_assert(R<0> == ^^A);
diff --git a/gcc/testsuite/g++.dg/reflect/enumerators_of1.C b/gcc/testsuite/g++.dg/reflect/enumerators_of1.C
new file mode 100644 (file)
index 0000000..1714118
--- /dev/null
@@ -0,0 +1,189 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::enumerators_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+consteval bool
+has_enumerators_of (info r)
+{
+  try { enumerators_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_enumerators_of (null_reflection));
+static_assert (!has_enumerators_of (^^int));
+static_assert (!has_enumerators_of (^^::));
+static_assert (!has_enumerators_of (^^foo));
+
+class S;
+enum class E;
+typedef E TE;
+static_assert (!has_enumerators_of (^^S));
+static_assert (!has_enumerators_of (^^E));
+static_assert (!has_enumerators_of (^^TE));
+
+template<typename> struct cls_tmpl {};
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+static_assert (!has_enumerators_of (^^cls_tmpl));
+static_assert (!has_enumerators_of (^^cls_tmpl<int>));
+static_assert (!has_enumerators_of (^^cls_tmpl_alias));
+static_assert (!has_enumerators_of (^^cls_tmpl_alias<int>));
+
+class S {
+  void foo ()
+  {
+    static_assert (!has_enumerators_of (^^S));
+  }
+  static_assert (!has_enumerators_of (^^S));
+};
+static_assert (!has_enumerators_of (^^S));
+
+enum class E {
+//  A1 = (has_enumerators_of (^^E) || has_enumerators_of (^^TE)) ? 1 : 2,
+  A2 = has_enumerators_of (^^E) ? 10 : 20,
+  A3 = has_enumerators_of (^^TE) ? 20 : 30
+};
+static_assert (has_enumerators_of (^^E));
+//static_assert (static_cast <int> (E::A1) == 2);
+static_assert (static_cast <int> (E::A2) == 20);
+static_assert (static_cast <int> (E::A3) == 30);
+static_assert (has_enumerators_of (^^TE));
+
+enum F : int;
+using TF = F;
+static_assert (!has_enumerators_of (^^F));
+static_assert (!has_enumerators_of (^^TF));
+enum F : int {
+//  B1 = (has_enumerators_of (^^F) || has_enumerators_of (^^TF)) ? 3 : 4,
+  B2 = has_enumerators_of (^^F) ? 30 : 40,
+  B3 = has_enumerators_of (^^TF) ? 40 : 42
+};
+static_assert (has_enumerators_of (^^F));
+//static_assert (B1 == 4);
+static_assert (B2 == 40);
+static_assert (B3 == 42);
+static_assert (has_enumerators_of (^^TF));
+
+enum G {
+  C = has_enumerators_of (^^G) ? 5 : 6
+};
+static_assert (has_enumerators_of (^^G));
+static_assert (C == 6);
+
+enum H : int;
+typedef H TH;
+static_assert (!has_enumerators_of (^^H));
+static_assert (!has_enumerators_of (^^TH));
+
+enum H : int {};
+static_assert (has_enumerators_of (^^H));
+static_assert (has_enumerators_of (^^TH));
+
+enum I : short;
+using TI = I;
+static_assert (!has_enumerators_of (^^I));
+static_assert (!has_enumerators_of (^^TI));
+enum I : short {};
+static_assert (has_enumerators_of (^^I));
+static_assert (has_enumerators_of (^^TI));
+
+template <typename T>
+void
+qux ()
+{
+  enum J : T;
+  using K = J;
+  // FIXME: No idea if this is supposed to be false or true.
+  // We certainly during instantiation don't differentiate between
+  // forward enum declarations and later definitions.
+  //  static_assert (!has_enumerators_of (^^J));
+  //  static_assert (!has_enumerators_of (dealias(^^K)));
+  enum J : T {
+    D = (has_enumerators_of (^^J) || has_enumerators_of (^^K))
+       ? sizeof (T) * 2 : sizeof (T)
+  };
+  static_assert (has_enumerators_of (^^J));
+  static_assert (D == sizeof (T));
+  static_assert (has_enumerators_of (^^K));
+}
+
+void
+corge ()
+{
+  qux <int> ();
+  qux <unsigned char> ();
+}
+
+enum L : int;
+using TL = L;
+static_assert (!has_enumerators_of (^^L));
+static_assert (!has_enumerators_of (^^TL));
+enum L : int {
+  L0, L1 = 42, L2, L3 = 14, L4 = 16, L6 = 18, L5 = 24
+};
+static_assert (enumerators_of (^^L).size () == 7);
+static_assert (enumerators_of (^^L)[0] == ^^L0);
+static_assert (enumerators_of (^^L)[1] == ^^L1);
+static_assert (enumerators_of (^^L)[2] == ^^L2);
+static_assert (enumerators_of (^^L)[3] == ^^L3);
+static_assert (enumerators_of (^^L)[4] == ^^L4);
+static_assert (enumerators_of (^^L)[5] == ^^L6);
+static_assert (enumerators_of (^^L)[6] == ^^L5);
+static_assert (enumerators_of (^^TL).size () == 7);
+static_assert (enumerators_of (^^TL)[0] == ^^L0);
+static_assert (enumerators_of (^^TL)[1] == ^^L1);
+static_assert (enumerators_of (^^TL)[2] == ^^L2);
+static_assert (enumerators_of (^^TL)[3] == ^^L3);
+static_assert (enumerators_of (^^TL)[4] == ^^L4);
+static_assert (enumerators_of (^^TL)[5] == ^^L6);
+static_assert (enumerators_of (^^TL)[6] == ^^L5);
+
+enum M {
+  M5, M13, M2 = 8, M0, M17
+};
+static_assert (enumerators_of (^^M).size () == 5);
+static_assert (enumerators_of (^^M)[0] == ^^M5);
+static_assert (enumerators_of (^^M)[1] == ^^M13);
+static_assert (enumerators_of (^^M)[2] == ^^M2);
+static_assert (enumerators_of (^^M)[3] == ^^M0);
+static_assert (enumerators_of (^^M)[4] == ^^M17);
+static_assert (enumerators_of (parent_of (^^M5)).size () == 5);
+
+enum N : int;
+typedef N TN;
+static_assert (!has_enumerators_of (^^N));
+static_assert (!has_enumerators_of (^^TN));
+
+enum N : int { N1 = 5 };
+static_assert (enumerators_of (^^N).size () == 1);
+static_assert (enumerators_of (^^N)[0] == ^^N1);
+static_assert (enumerators_of (^^TN).size () == 1);
+static_assert (enumerators_of (^^TN)[0] == ^^N1);
+
+enum O : short;
+using TO = O;
+static_assert (!has_enumerators_of (^^O));
+static_assert (!has_enumerators_of (^^TO));
+enum O : short { O1 = 2, O2 = 3, O3 = 4};
+static_assert (enumerators_of (^^O).size () == 3);
+static_assert (enumerators_of (^^O)[0] == ^^O1);
+static_assert (enumerators_of (^^O)[1] == ^^O2);
+static_assert (enumerators_of (^^O)[2] == ^^O3);
+static_assert (enumerators_of (^^TO).size () == 3);
+static_assert (enumerators_of (^^TO)[0] == ^^O1);
+static_assert (enumerators_of (^^TO)[1] == ^^O2);
+static_assert (enumerators_of (^^TO)[2] == ^^O3);
+
+enum { P1, P2, P3 };
+static_assert (enumerators_of (parent_of (^^P1)).size() == 3);
+static_assert (enumerators_of (parent_of (^^P1))[0] == ^^P1);
+static_assert (enumerators_of (parent_of (^^P1))[1] == ^^P2);
+static_assert (enumerators_of (parent_of (^^P1))[2] == ^^P3);
+
diff --git a/gcc/testsuite/g++.dg/reflect/error1.C b/gcc/testsuite/g++.dg/reflect/error1.C
new file mode 100644 (file)
index 0000000..ad30862
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct X { };
+
+void
+f1 ()
+{
+  constexpr auto r = ^^int;
+  [: r ] i = 42;  // { dg-error "expected .:].|expected unqualified-id" }
+  [: :] x1;      // { dg-error "expected primary-expression|forbids|reflection not usable" }
+  [: int :] x2;          // { dg-error "expected|reflection not usable" }
+  [: X :] x3;    // { dg-error "expected|reflection not usable" }
+  constexpr X x;
+  [: x :] x4;    // { dg-error "could not convert .x. from .const X. to .std::meta::info.|reflection not usable" }
+
+  constexpr auto e1 = ^^42;  // { dg-error "cannot be applied" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error10.C b/gcc/testsuite/g++.dg/reflect/error10.C
new file mode 100644 (file)
index 0000000..2ca2b18
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+int g;
+
+void
+fn0 (int, typename [: ^^:: :] i) // { dg-error "reflection .::. not usable in a splice type|declared" }
+{
+}
+
+void
+fn1 (int, typename [: ^^g :] i) // { dg-error "reflection .g. not usable in a splice type|declared" }
+{
+}
+
+void
+fn2 (int, typename [: ^^fn1 :] i) // { dg-error "reflection .fn1. not usable in a splice type|declared" }
+{
+}
+
+void
+fn3 (int p, typename [: ^^p :] i) // { dg-error "reflection .p. not usable in a splice type|declared" }
+{
+}
+
+enum Harold { Budd };
+
+void
+fn4 (int, typename [: ^^Budd :] i) // { dg-error "reflection .Budd. not usable in a splice type|declared" }
+{
+}
+
+template<int>
+struct S {};
+
+void
+fn5 (int, typename [: ^^S :] i) // { dg-error "reflection .S. not usable in a splice type|declared" }
+{
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error2.C b/gcc/testsuite/g++.dg/reflect/error2.C
new file mode 100644 (file)
index 0000000..766862b
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A {
+  A();
+  ~A();
+};
+
+void
+g ()
+{
+  // clang accepts these, but EDG rejects too.
+  constexpr auto r1 = ^^A::A;    // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r2 = ^^A::A();          // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r3 = ^^A::A::A;  // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r4 = ^^A::~A;
+  [: r4 :];      // { dg-error "cannot use constructor or destructor .A::~A\\(\\). in a splice expression" }
+  [: ^^A::~A :];  // { dg-error "cannot use constructor or destructor .A::~A\\(\\). in a splice expression" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error3.C b/gcc/testsuite/g++.dg/reflect/error3.C
new file mode 100644 (file)
index 0000000..1f3ed4f
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+typename[: ^^:: :] x = 0;  // { dg-error "expected" }
+[: ^^:: :] x2 = 0;  // { dg-error "expected" }
diff --git a/gcc/testsuite/g++.dg/reflect/error4.C b/gcc/testsuite/g++.dg/reflect/error4.C
new file mode 100644 (file)
index 0000000..cb3dd80
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace A {}
+constexpr auto NS_A = ^^A;
+
+namespace B {
+  namespace [:NS_A:] { // { dg-error "expected" }
+    void fn();  // Is this '::A::fn' or '::B::A::fn' ?
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error5.C b/gcc/testsuite/g++.dg/reflect/error5.C
new file mode 100644 (file)
index 0000000..2b125ff
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+namespace N { }
+
+template<info R>
+void
+f ()
+{
+  int i = [:R:]; // { dg-error "expected a reflection of an expression instead of .N." }
+}
+
+void
+g ()
+{
+  f<^^N>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error6.C b/gcc/testsuite/g++.dg/reflect/error6.C
new file mode 100644 (file)
index 0000000..25527e8
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Detect taking the reflection of a using-declarator as per [expr.reflect]/5.
+
+namespace NS {
+  namespace Inner {
+    consteval int fn() { return 42; }
+    template <auto V> consteval int tfn() { return V; }
+  }  // namespace Inner
+
+  using Inner::fn;
+  using Inner::tfn;
+}  // namespace NS
+
+// splice-expressions
+static_assert([:^^NS::fn:]() == 42);  // { dg-error "cannot be applied to a using-declaration" }
+static_assert(template [:^^NS::tfn:]<4>() == 4);  // { dg-error "cannot be applied to a using-declaration|expected" }
+
+// nested proxies
+struct A { int m; };
+struct B : A { using A::m; };
+struct C : B { using B::m; };
+
+static_assert(&[:^^C::m:] == &A::m); // { dg-error "cannot be applied to a using-declaration" }
diff --git a/gcc/testsuite/g++.dg/reflect/error8.C b/gcc/testsuite/g++.dg/reflect/error8.C
new file mode 100644 (file)
index 0000000..8f35b09
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test static consteval-only vars in a consteval function.
+
+consteval void
+f1 ()
+{
+  static auto i = ^^int;  // { dg-error ".i. defined .static. in .constexpr. context" }
+}
+
+consteval void
+f2 ()
+{
+  static const auto i = ^^int;  // { dg-error ".i. defined .static. in .constexpr. context" }
+}
+
+consteval void
+f3 ()
+{
+  static constexpr auto i = ^^int;
+}
+
+consteval
+void
+f4 ()
+{
+  static constinit auto i = ^^int;  // { dg-error ".i. defined .static. in .constexpr. context" }
+}
+
+void
+z ()
+{
+  f1();  // { dg-error "call to consteval function|in a constant expression" }
+  f2();  // { dg-error "call to consteval function|in a constant expression" }
+  f3();
+  f4();  // { dg-error "call to consteval function|in a constant expression" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error9.C b/gcc/testsuite/g++.dg/reflect/error9.C
new file mode 100644 (file)
index 0000000..fe0829a
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<typename> concept conc = requires { true; };
+constexpr auto r = ^^conc;
+constexpr auto x = ^^conc<int>;  // { dg-error "cannot be applied to a concept check" }
diff --git a/gcc/testsuite/g++.dg/reflect/expr1.C b/gcc/testsuite/g++.dg/reflect/expr1.C
new file mode 100644 (file)
index 0000000..8f89358
--- /dev/null
@@ -0,0 +1,68 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on id-expression.
+
+int arr[2] = { 1, 2 };
+
+template<typename T>
+void foo (T) { }
+
+struct S {
+  int i;
+  operator int() { return this->i; }
+  ~S();
+};
+
+static int operator+(S a, S b) { return a.i + b.i; }
+
+void operator ""_km(long double);
+template <char...> double operator ""_fm();
+
+void
+f (S a, S b)
+{
+  // unqualified-id
+  constexpr auto r1 = ^^foo<int>;
+  [: r1 :](1);
+
+  constexpr auto r2 = ^^operator+;
+  [: r2 :](a, b);
+
+  constexpr auto r3 = ^^operator ""_km;
+  constexpr auto r4 = ^^operator ""_fm;
+  constexpr auto r5 = ^^operator ""_fm<'a'>;
+
+  auto & [ c, d ] = arr;
+  constexpr auto r6 = ^^c;
+  constexpr auto r7 = ^^d;
+  [: r6 :] = 1;
+  [: r7 :] = 1;
+}
+
+void
+g (S a, S b)
+{
+  // qualified-id
+  constexpr auto r1 = ^^::foo<int>;
+  [: r1 :](1);
+
+  constexpr auto r2 = ^^::operator+;
+  [: r2 :](a, b);
+
+  constexpr auto r3 = ^^S::operator int;
+  constexpr auto r4 = ^^::operator ""_km;
+  constexpr auto r5 = ^^S::~S;
+  constexpr auto r6 = ^^::operator ""_fm;
+  constexpr auto r7 = ^^::operator ""_fm<'a'>;
+}
+
+consteval int
+h ()
+{
+  int x = 41;
+  constexpr auto rx = ^^x;
+  ++[: rx :];
+  return x;
+}
+
+static_assert(h () == 42);
diff --git a/gcc/testsuite/g++.dg/reflect/expr10.C b/gcc/testsuite/g++.dg/reflect/expr10.C
new file mode 100644 (file)
index 0000000..7b195e7
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections in consteval blocks.
+
+using info = decltype(^^void);
+
+consteval info foo (info i) { return i; }
+
+constexpr info u = ^^int;
+
+consteval {
+  auto z = ^^int;
+  u;
+  ^^double;
+  static constexpr auto gl = ^^double;
+  foo (^^int);
+}
+
+struct S {
+  consteval {
+    auto z = ^^int;
+    ^^double;
+    static constexpr auto gl = ^^double;
+    foo (^^int);
+  }
+};
+
+void
+g ()
+{
+  constexpr info r = ^^int;
+  consteval {
+    r;
+    ^^double;
+    auto l = ^^double;
+    static constexpr auto gl = ^^double;
+    foo (^^int);
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr11.C b/gcc/testsuite/g++.dg/reflect/expr11.C
new file mode 100644 (file)
index 0000000..20af4bc
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections in if and while.
+
+using info = decltype(^^void);
+consteval info foo (info i) { return i; }
+
+void
+f ()
+{
+  constexpr auto q = ^^float;
+  if constexpr (foo (^^::) == ^^::)
+    {
+      auto r = ^^int; // { dg-error "consteval-only variable .r." }
+      constexpr auto cr = ^^int;
+    }
+  if constexpr (auto r = ^^int;  // { dg-error "consteval-only variable .r." }
+               r == ^^int);     // { dg-error "the value of .r. is not usable" }
+  if constexpr (constexpr auto r = ^^int; r == ^^int);
+  if constexpr (q != ^^char);
+  if constexpr (^^int != ^^char);
+  if (q != ^^char);  // { dg-error "consteval-only expressions" }
+  if (^^char == ^^char);  // { dg-error "consteval-only expressions" }
+  while (^^char == ^^char);  // { dg-error "consteval-only expressions" }
+  do {} while (^^char == ^^char);  // { dg-error "consteval-only expressions" }
+  consteval {
+    if (q != ^^char);
+    if (^^char == ^^char);
+    while (^^char != ^^char);
+    do {} while (^^char != ^^char);
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr12.C b/gcc/testsuite/g++.dg/reflect/expr12.C
new file mode 100644 (file)
index 0000000..a59a60f
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections in consteval if.
+
+void
+f ()
+{
+  constexpr auto q = ^^float;
+  if consteval
+    {
+      ^^void;
+      q;
+      auto r = ^^int;
+      if (q != ^^char);
+      if (^^char == ^^char);
+      while (^^char != ^^char);
+      do {} while (^^char != ^^char);
+    }
+
+  if not consteval
+    {
+      ^^void;  // { dg-error "consteval-only expressions" }
+      q;  // { dg-error "consteval-only expressions" }
+      auto r = ^^int;  // { dg-error "consteval-only variable" }
+      if (q != ^^char);  // { dg-error "consteval-only expressions" }
+      if (^^char == ^^char);  // { dg-error "consteval-only expressions" }
+      while (^^char != ^^char);  // { dg-error "consteval-only expressions" }
+      do {} while (^^char != ^^char);  // { dg-error "consteval-only expressions" }
+    }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr13.C b/gcc/testsuite/g++.dg/reflect/expr13.C
new file mode 100644 (file)
index 0000000..6be2764
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <type_traits>
+
+template <auto I>
+struct X {};
+
+struct Y {
+  int name;
+};
+
+template <typename S>
+constexpr auto foo (S s) {
+  return X<^^S::name> {};
+}
+
+constexpr auto a = foo (Y { 42 });
+// TODO: This doesn't work: 'const struct X<^^Y::name>' is not the same as 'const struct X<^^Y::name>'
+//static_assert (std::is_same_v <decltype (a), const X <^^Y::name>>);
diff --git a/gcc/testsuite/g++.dg/reflect/expr14.C b/gcc/testsuite/g++.dg/reflect/expr14.C
new file mode 100644 (file)
index 0000000..cec7e66
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/123081
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<typename T>
+constexpr auto refl = ^^T;
+
+struct {
+       template<typename T>
+       requires(requires { typename[:refl<T>:]; })
+       void f(T) {}
+} a;
+
+int main() {
+       a.f([] {});
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr2.C b/gcc/testsuite/g++.dg/reflect/expr2.C
new file mode 100644 (file)
index 0000000..1cca886
--- /dev/null
@@ -0,0 +1,60 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on id-expression.
+
+template<typename T>
+void foo (T) { }
+
+template<typename T>
+void foo (T, T) { }
+
+void
+f (int p)
+{
+  constexpr auto r1 = ^^foo<int>;   // { dg-error "insufficient contextual information" }
+  constexpr auto r2 = ^^::foo<int>; // { dg-error "insufficient contextual information" }
+
+  constexpr auto r3 = ^^__func__;   // { dg-error "cannot be applied" }
+  constexpr auto r4 = ^^__FUNCTION__; // { dg-error "cannot be applied" }
+  constexpr auto r5 = ^^__PRETTY_FUNCTION__;  // { dg-error "cannot be applied" }
+
+  requires(int a) { ^^p; };
+  requires(int a) { ^^a; }; // { dg-error "cannot be applied to a local parameter of a requires-expression .a." }
+}
+
+// NTTPs and pack-index-expressions cannot appear as operands
+// of the reflection operator.
+
+struct S { int i; };
+enum E { EE };
+static constexpr int glob = 0;
+
+template<S s, int n, E e, double d, const int& r>
+void
+g ()
+{
+  constexpr auto r1 = ^^s;  // { dg-error "cannot be applied to a non-type template parameter .s." }
+  constexpr auto r2 = ^^n;  // { dg-error "cannot be applied to a non-type template parameter .n." }
+  constexpr auto r3 = ^^e;  // { dg-error "cannot be applied to a non-type template parameter .e." }
+  constexpr auto r4 = ^^d;  // { dg-error "cannot be applied to a non-type template parameter .d." }
+  constexpr auto r5 = ^^r;  // { dg-error "cannot be applied to a non-type template parameter .r." }
+}
+
+template<typename T, T t>
+void
+g2 ()
+{
+  constexpr auto r = ^^t; // { dg-error "cannot be applied to a non-type template parameter .t." }
+}
+
+void
+h ()
+{
+  constexpr S s{};
+  constexpr int n = 42;
+  constexpr E e{};
+  constexpr double d = 0.0;
+  g<s, n, e, d, glob>();
+
+  g2<int, 42>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr3.C b/gcc/testsuite/g++.dg/reflect/expr3.C
new file mode 100644 (file)
index 0000000..27295f1
--- /dev/null
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+int x = 42;
+template<typename T>
+constexpr T two = 2;
+
+template<typename T>
+constexpr T foo (T t) { return t; }
+
+void bar () { }
+
+struct S { };
+
+template<typename>
+struct ST { };
+
+template <int P1, const int &P2> void fn() {}
+
+static constexpr int p[2] = {1, 2};
+constexpr auto spec = ^^fn<p[0], p[1]>;
+
+void
+g ()
+{
+  int i1 = [: ^^x :];
+  int i2 = template [: ^^x :];    // { dg-error "reflection .x. not usable in a template splice" }
+  int i3 = [: ^^two<int> :];
+  int i4 = template [: ^^two<int> :]; // { dg-error "reflection .two<int>. not usable in a template splice" }
+  int i5 = [: ^^foo :](42);          // { dg-error "reflection .foo. not usable in a splice expression" }
+  int i6 = template [: ^^foo :](42);
+  int i7 = [: ^^foo<int> :](42);
+  int i8 = template [: ^^foo<int> :](42);   // { dg-error "reflection .foo<int>. not usable in a template splice" }
+  int i9 = [: ^^foo :]<int>(42);           // { dg-error "reflection .foo<int>. not usable in a splice expression with template arguments" }
+  int i10 = template [: ^^foo :]<int>(42);
+  int i11 = template [: ^^bar :]<int>(42);  // { dg-error "no matching function for call" }
+  int i12 = [: ^^two :]<int>;              // { dg-error "reflection .two<int>. not usable in a splice expression with template arguments" }
+  int i13 = template [: ^^two :]<int>;
+
+  [: ^^ST :]<int> c1;  // { dg-error "reflection .ST<int>. not usable in a splice expression with template arguments" }
+  [: ^^S :]<int> c2;   // { dg-error "not a template|reflection not usable in a splice expression with template arguments" }
+  [: ^^bar :]<int>();  // { dg-error "reflection .bar<int>. not usable in a splice expression with template arguments" }
+
+  auto x1 = [: ^^ST :]<int>{};   // { dg-error "reflection .ST<int>. not usable in a splice expression with template arguments" }
+  auto x2 = template [: ^^ST :]<int>{};        // { dg-error "expected a reflection of an expression" }
+  auto x3 = typename [: ^^ST :]<int>{};
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr4.C b/gcc/testsuite/g++.dg/reflect/expr4.C
new file mode 100644 (file)
index 0000000..b43812b
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+void oy (int);
+template<typename T>
+void oy (T);
+
+struct S {
+  void foo (int);
+  void foo (int, int);
+  void bar (int);
+
+  template<typename T>
+  void baz (T);
+  template<typename T>
+  void baz (T, T);
+
+  template<typename T>
+  void qux (T);
+
+  void sfoo (int);
+  void sfoo (int, int);
+  void sbar (int);
+
+  template<typename T>
+  void sbaz (T);
+  template<typename T>
+  void sbaz (T, T);
+
+  template<typename T>
+  void squx (T);
+
+  void lox (int);
+  template<typename T>
+  void lox (T);
+
+  template<typename T>
+  S &operator+(const T&);
+
+  template<typename T>
+  static bool B;
+};
+
+void
+g ()
+{
+  constexpr auto r1 = ^^S::foo;          // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r2 = ^^S::bar;
+  constexpr auto r3 = ^^S::baz;          // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r4 = ^^S::qux;
+  constexpr auto r5 = ^^S::sfoo;  // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r6 = ^^S::sbar;
+  constexpr auto r7 = ^^S::sbaz;  // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r8 = ^^S::squx;
+  constexpr auto r9 = ^^oy;      // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r10 = ^^S::lox;  // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r11 = ^^S::operator+;
+  constexpr auto r12 = ^^S::template operator+;
+  constexpr auto r13 = ^^S::B;
+  constexpr auto r14 = ^^S::template B;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr5.C b/gcc/testsuite/g++.dg/reflect/expr5.C
new file mode 100644 (file)
index 0000000..d3a0513
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A {
+  static void g();
+  static void g(int);
+  void h();
+  void h(int);
+  static void i();
+  void j();
+};
+
+void
+f ()
+{
+  constexpr auto r1 = ^^A::g; // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r2 = ^^A::h; // { dg-error "cannot take the reflection of an overload set" }
+  constexpr auto r3 = ^^A::i;
+  constexpr auto r4 = ^^A::j;
+
+  [: r3 :]();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr6.C b/gcc/testsuite/g++.dg/reflect/expr6.C
new file mode 100644 (file)
index 0000000..d7d0574
--- /dev/null
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Otherwise, if the id-expression denotes a local entity E for which
+// there is a lambda scope that intervenes between R and the point at
+// which E was introduced, R is ill-formed.
+
+static int s1;
+
+void
+f ()
+{
+  int l1;
+  static int s2;
+  constexpr auto rl1 = ^^l1;
+  [] -> decltype(^^l1) { return {}; }; // { dg-error "intervening lambda expression" }
+  [] -> decltype(^^s1, s2) {
+    int l2;
+
+    constexpr auto rl1_2 = ^^l1;  // { dg-error "intervening lambda expression" }
+    constexpr auto rl2 = ^^l2;
+
+    return s1;
+  };
+}
+
+void
+g ()
+{
+  int x;
+  [=]<auto r> {
+    static_assert(^^x == r);  // { dg-error "intervening lambda expression" }
+  }.operator()<^^x>();
+}
+
+void
+h ()
+{
+  int x = 42;
+  int y = 42;
+  [x_=x, y]() {
+    constexpr auto r1 = ^^x;  // { dg-error "intervening lambda expression" }
+    constexpr auto r2 = ^^x_; // { dg-error "local entity declared by init-capture" }
+    constexpr auto r3 = ^^y;  // { dg-error "intervening lambda expression" }
+
+    [x_]() {
+      constexpr auto r4 = ^^x_;        // { dg-error "local entity declared by init-capture" }
+    };
+  };
+}
diff --git a/gcc/testsuite/g++.dg/reflect/expr7.C b/gcc/testsuite/g++.dg/reflect/expr7.C
new file mode 100644 (file)
index 0000000..1764668
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test using enum.
+
+// TODO cannot take the reflection of a using-declarator
+enum class Color { R, G, B };
+struct S { using enum Color; };
+
+static_assert(^^S::R != ^^S::G);
+static_assert(^^S::R != ^^Color::R);
+static_assert([:^^S::R:] == Color::R);
diff --git a/gcc/testsuite/g++.dg/reflect/expr8.C b/gcc/testsuite/g++.dg/reflect/expr8.C
new file mode 100644 (file)
index 0000000..c507637
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+template<info R>
+void
+g ()
+{
+  int i0 = typename [:^^int:](42);
+  int i1 = (typename [:^^int:])(42);
+  int i2 = typename [:R:](42);
+  int i3 = (typename [:R:]) 42;
+}
+
+template void g<^^int>();
+
+struct X { X(int); operator int(); };
+
+template<info R>
+void
+f ()
+{
+  X x1 = typename [:R:](42);
+  X x2 = (typename [:R:]) 42;
+  int i1 = (typename [:R:]) x1;
+  int i2 = typename [:R:](x1);
+}
+
+template void f<^^X>();
diff --git a/gcc/testsuite/g++.dg/reflect/expr9.C b/gcc/testsuite/g++.dg/reflect/expr9.C
new file mode 100644 (file)
index 0000000..e27a23d
--- /dev/null
@@ -0,0 +1,73 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+void
+fn1 ()
+{
+  int x = 1;       // { dg-message ".x. declared here" }
+  constexpr auto r = ^^x;
+
+  [] -> decltype([:r:]) {
+    return {};
+  };
+
+  [] -> decltype(x) {
+    return [:r:];   // { dg-error "use of local variable" }
+  };
+}
+
+void
+fn2 ()
+{
+  static int x = 1;
+  constexpr auto r = ^^x;
+
+  [] -> decltype([:r:]) {
+    return [:r:];
+  };
+}
+
+void
+fn3 ()
+{
+  int x = 1;   // { dg-message ".x. declared here" }
+
+  [] -> int {
+    static constexpr auto r = ^^x;  // { dg-error "cannot be applied a local entity" }
+    return [:r:];
+  };
+}
+
+void
+fn4 ()
+{
+  static int x = 1;
+
+  [] -> int {
+    static constexpr auto r = ^^x;
+    return [:r:];
+  };
+}
+
+void
+fn5 (int x)   // { dg-message ".x. declared here" }
+{
+  constexpr auto r = ^^x;
+
+  [] -> decltype([:r:]) {
+    return {};
+  };
+
+  [] -> decltype(x) {
+    return [:r:];   // { dg-error "use of local variable" }
+  };
+}
+
+void
+fn6 (int x)   // { dg-message ".x. declared here" }
+{
+  [] -> int {
+    static constexpr auto r = ^^x;  // { dg-error "cannot be applied a local entity" }
+    return [:r:];
+  };
+}
diff --git a/gcc/testsuite/g++.dg/reflect/extract1.C b/gcc/testsuite/g++.dg/reflect/extract1.C
new file mode 100644 (file)
index 0000000..6eaf9ff
--- /dev/null
@@ -0,0 +1,183 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr auto rnptr = reflect_constant (nullptr_t{});
+static_assert (extract<nullptr_t>(rnptr) == nullptr_t{});
+static_assert (extract<const nullptr_t>(rnptr) == nullptr_t{});
+constexpr auto rt = reflect_constant (true);
+static_assert (extract<bool>(rt));
+static_assert (extract<const bool>(rt));
+constexpr auto rf = reflect_constant (false);
+static_assert (!extract<bool>(rf));
+static_assert (!extract<const bool>(rf));
+constexpr auto r1 = reflect_constant (1);
+static_assert (extract<int>(r1) == 1);
+static_assert (extract<const int>(r1) == 1);
+constexpr auto r1u = reflect_constant (1u);
+static_assert (extract<unsigned>(r1u) == 1u);
+static_assert (extract<const unsigned>(r1u) == 1u);
+constexpr auto rA = reflect_constant ('A');
+static_assert (extract<char>(rA) == 'A');
+static_assert (extract<const char>(rA) == 'A');
+constexpr auto rPIf = reflect_constant (3.14f);
+static_assert (extract<float>(rPIf) == float(3.14f));
+static_assert (extract<const float>(rPIf) == float(3.14f));
+constexpr auto rPI = reflect_constant (3.14);
+static_assert (extract<double>(rPI) == double(3.14));
+static_assert (extract<const double>(rPI) == double(3.14));
+constexpr auto r666 = reflect_constant (666L);
+static_assert (extract<long int>(r666) == 666L);
+static_assert (extract<const long int>(r666) == 666L);
+constexpr short int shrt = 42;
+static_assert (extract<short int>(constant_of (^^shrt)) == 42);
+static_assert (extract<const short int>(constant_of (^^shrt)) == 42);
+constexpr signed char sc = -1;
+static_assert (extract<signed char>(constant_of (^^sc)) == -1);
+static_assert (extract<const signed char>(constant_of (^^sc)) == -1);
+constexpr unsigned char uc = 255;
+static_assert (extract<unsigned char>(constant_of (^^uc)) == 255);
+static_assert (extract<const unsigned char>(constant_of (^^uc)) == 255);
+constexpr int *p = nullptr;
+constexpr info rp = ^^p;
+static_assert (extract<int *>(rp) == nullptr);
+static_assert (extract<int * const>(rp) == nullptr);
+static_assert (extract<const int *>(rp) == nullptr);
+static_assert (extract<const int *const>(rp) == nullptr);
+constexpr const int *cp = nullptr;
+constexpr info rcp = ^^cp;
+static_assert (extract<const int *>(rcp) == nullptr);
+static_assert (extract<const int *const>(rcp) == nullptr);
+constexpr void (*pfn0)() = nullptr;
+constexpr void (*pfn1)(int) = nullptr;
+constexpr info rpfn0 = ^^pfn0;
+constexpr info rpfn1 = ^^pfn1;
+static_assert (extract<void (*const)()>(rpfn0) == nullptr);
+static_assert (extract<void (*)()>(rpfn0) == nullptr);
+static_assert (extract<void (*)(int)>(rpfn1) == nullptr);
+static_assert (extract<void (*const)(int)>(rpfn1) == nullptr);
+constexpr int arr[] = { 1, 2, 3, 4, 5 };
+static_assert (extract<const int *>(^^arr) == [: reflect_constant_array (arr) :]);
+static_assert (extract<const int *const>(^^arr) == [: reflect_constant_array (arr) :]);
+static_assert (extract<const int *>(^^arr)[0] == 1);
+static_assert (extract<const int *>(^^arr)[1] == 2);
+static_assert (extract<const int *>(^^arr)[2] == 3);
+static_assert (extract<const int *>(^^arr)[3] == 4);
+static_assert (extract<const int *>(^^arr)[4] == 5);
+static_assert (extract<int>(reflect_constant (arr[0])) == 1);
+static_assert (extract<int>(reflect_constant (arr[1])) == 2);
+static_assert (extract<int>(reflect_constant (arr[2])) == 3);
+static_assert (extract<int>(reflect_constant (arr[3])) == 4);
+static_assert (extract<int>(reflect_constant (arr[4])) == 5);
+const auto lambda = []{};
+static_assert (extract<void (*)()>(^^lambda) == lambda);
+static_assert (extract<void (*const)()>(^^lambda) == lambda);
+
+enum E { A = 42 };
+enum struct EC { A = 42 };
+static_assert (extract<E>(reflect_constant (A)) == 42);
+static_assert (extract<EC>(reflect_constant (EC::A)) == EC::A);
+
+struct S { int m; };
+static_assert (extract<S>(reflect_constant (S{42})).m == 42);
+
+constexpr int foo () { return 42; }
+static_assert (extract<int>(reflect_constant (foo ())) == 42);
+
+constexpr int cxi = 42;
+static_assert (extract<const int *>(reflect_constant (&cxi)) == &cxi);
+
+const int ci = 42;
+void fn () {}
+struct C {
+  int k;
+  void fn ();
+};
+
+template<auto E>
+consteval bool
+check_val (info R)
+{
+  return extract<decltype (E)>(R) == E;
+}
+static_assert (check_val<42>(reflect_constant (42)));
+static_assert (check_val<EC::A>(^^EC::A));
+static_assert (check_val<E::A>(^^E::A));
+static_assert (check_val<42>(^^ci));
+static_assert (check_val<42>(^^cxi));
+static_assert (check_val<&fn>(^^fn));
+static_assert (check_val<&C::k>(^^C::k));
+static_assert (check_val<&C::fn>(^^C::fn));
+static_assert (check_val<42>([]() {
+  constexpr static int x = 42;
+  return ^^x;
+}()));
+
+template<int K> struct TC {
+  static constexpr int value = K;
+};
+
+TC<3> t;
+static_assert (check_val<3>(static_data_members_of
+                           (substitute (^^TC, {reflect_constant (3)}),
+                            access_context::unchecked ())[0]));
+
+template<typename T>
+consteval bool
+roundtrip (T value)
+{
+  return extract<T>(reflect_constant (value)) == value;
+}
+static_assert (roundtrip (42));
+static_assert (roundtrip (EC::A));
+static_assert (roundtrip (E::A));
+static_assert (roundtrip (ci));
+static_assert (roundtrip (cxi));
+static_assert (roundtrip (fn));
+static_assert (roundtrip (&C::k));
+static_assert (roundtrip (&C::fn));
+static_assert (roundtrip ([] {}));
+
+struct B {
+  static constexpr int k = 42;
+  int m;
+  int* p;
+
+  int fn ();
+  int fn2 () noexcept;
+  static int fn3 ();
+  static int fn4 () noexcept;
+  int fn5 (this B);
+  int fn6 (int) &;
+  int fn7 (int) &&;
+};
+static_assert (extract<const int>(^^B::k) == 42);
+static_assert (extract<const int &>(^^B::k) == 42);
+static_assert (extract<int (B::*)()>(^^B::fn) == &B::fn);
+static_assert (extract<int (B::*)() noexcept>(^^B::fn2) == &B::fn2);
+static_assert (extract<int (*)()>(^^B::fn3) == &B::fn3);
+static_assert (extract<int (*)() noexcept>(^^B::fn4) == &B::fn4);
+static_assert (extract<int (*)(B)>(^^B::fn5) == &B::fn5);
+static_assert (extract<int (B::*)(int) &>(^^B::fn6) == &B::fn6);
+static_assert (extract<int (B::*)(int) &&>(^^B::fn7) == &B::fn7);
+constexpr auto a = extract<int (B::*)()>(^^B::fn);
+constexpr auto a2 = extract<int (B::*)()noexcept>(^^B::fn2);
+constexpr auto a3 = extract<int (*)()>(^^B::fn3);
+constexpr auto a4 = extract<int (*)() noexcept>(^^B::fn4);
+constexpr auto a5 = extract<int (*)(B)>(^^B::fn5);
+constexpr auto a6 = extract<int (B::*)(int) &>(^^B::fn6);
+constexpr auto a7 = extract<int (B::*)(int) &&>(^^B::fn7);
+
+constexpr auto a8 = extract<int B::*>(^^B::m);
+constexpr auto a9 = extract<int const B::*>(^^B::m);
+constexpr auto a10 = extract<int* B::*>(^^B::p);
+constexpr auto a11 = extract<int* const B::*>(^^B::p);
+constexpr auto a12 = extract<int const* const B::*>(^^B::p);
+
+// FIXME removing noexcept should be allowed
+// constexpr auto a13 = extract<int (*)()>(^^B::fn4);
+// constexpr auto a14 = extract<int (B::*)()>(^^B::fn2);
diff --git a/gcc/testsuite/g++.dg/reflect/extract2.C b/gcc/testsuite/g++.dg/reflect/extract2.C
new file mode 100644 (file)
index 0000000..edb5382
--- /dev/null
@@ -0,0 +1,140 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<typename T>
+consteval bool
+can_extract (info r)
+{
+  try { extract<T>(r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+constexpr info null_reflection;
+static_assert (!can_extract<int>(null_reflection));
+
+constexpr auto rt = reflect_constant (true);
+static_assert (!can_extract<int>(rt));
+static_assert (!can_extract<char>(rt));
+static_assert (!can_extract<short>(rt));
+static_assert (!can_extract<long>(rt));
+static_assert (!can_extract<float>(rt));
+static_assert (!can_extract<bool *>(rt));
+constexpr auto rA = reflect_constant ('A');
+static_assert (!can_extract<bool>(rA));
+static_assert (!can_extract<int>(rA));
+static_assert (!can_extract<unsigned short>(rA));
+static_assert (!can_extract<long>(rA));
+static_assert (!can_extract<double>(rA));
+static_assert (!can_extract<int *>(rA));
+constexpr short int shrt = 42;
+constexpr info rshrt = constant_of (^^shrt);
+static_assert (!can_extract<int *>(rshrt));
+static_assert (!can_extract<bool>(rshrt));
+static_assert (!can_extract<signed char>(rshrt));
+static_assert (!can_extract<int>(rshrt));
+static_assert (!can_extract<double>(rshrt));
+static_assert (!can_extract<long>(rshrt));
+constexpr signed char sc = -1;
+constexpr info rsc = constant_of (^^sc);
+static_assert (!can_extract<int *>(rsc));
+static_assert (!can_extract<bool>(rsc));
+static_assert (!can_extract<unsigned char>(rsc));
+static_assert (!can_extract<int>(rsc));
+static_assert (!can_extract<double>(rsc));
+static_assert (!can_extract<long>(rsc));
+constexpr unsigned char uc = 255;
+constexpr info ruc = constant_of (^^uc);
+static_assert (!can_extract<int *>(ruc));
+static_assert (!can_extract<bool>(ruc));
+static_assert (!can_extract<signed char>(ruc));
+static_assert (!can_extract<int>(ruc));
+static_assert (!can_extract<double>(ruc));
+static_assert (!can_extract<long>(ruc));
+
+constexpr const int *p = nullptr;
+constexpr auto rp = ^^p;
+static_assert (!can_extract<int *>(rp));
+static_assert (!can_extract<char *>(rp));
+
+constexpr void (*pfn0)() = nullptr;
+constexpr void (*pfn1)(int) = nullptr;
+constexpr info rpfn0 = ^^pfn0;
+constexpr info rpfn1 = ^^pfn1;
+static_assert (!can_extract<void (*)(int)>(rpfn0));
+static_assert (!can_extract<void (*)()>(rpfn1));
+
+constexpr int arr[] = { 1, 2, 3, 4, 5 };
+static_assert (!can_extract<int *>(^^arr));
+static_assert (!can_extract<const double *>(^^arr));
+
+const auto lambda = []{};
+static_assert (!can_extract<void (*)(int)>(^^lambda));
+
+enum E { X = 42 };
+enum struct EC { Y = 42 };
+static_assert (!can_extract<int *>(reflect_constant (X)));
+static_assert (!can_extract<int>(reflect_constant (EC::Y)));
+
+struct S { int m; };
+static_assert (!can_extract<int>(reflect_constant (S{42})));
+
+constexpr int foo () { return 42; }
+static_assert (!can_extract<int *>(reflect_constant (foo ())));
+
+static constexpr int i = 0;
+static_assert (!can_extract<const int>(reflect_constant (&i)));
+static_assert (!can_extract<const int &>(reflect_constant (i)));
+static_assert (!can_extract<int &>(^^i));
+
+int j;
+static_assert (extract<int &>(^^j)); // { dg-error "non-constant|not usable" }
+
+consteval info
+bar ()
+{
+   constexpr int x = 10;
+   return ^^x;
+};
+
+constexpr info rbar = bar ();
+static_assert (!can_extract<int &>(rbar));
+
+struct B {
+  int k;
+  int bf : 16;
+};
+
+static_assert (!can_extract<int>(^^B::bf));
+static_assert (!can_extract<int &>(^^B::bf));
+static_assert (!can_extract<const int &>(^^B::bf));
+static_assert (!can_extract<int B::*>(^^B::bf));
+
+static union { int um; };
+static_assert (!can_extract<int>(^^um));
+static_assert (!can_extract<int&>(^^um));
+
+struct C {
+  int fn ();
+  int fn2 () noexcept;
+  static int fn3 ();
+  static int fn4 () noexcept;
+  int fn5 (this B);
+  int fn6 (int) &;
+  int fn7 (int) &&;
+};
+static_assert (!can_extract<void (C::*)()>(^^C::fn));
+static_assert (!can_extract<int (C::*)() noexcept>(^^C::fn));
+static_assert (!can_extract<int (C::*)()>(^^C::fn2));
+static_assert (!can_extract<int (C::*)()>(^^C::fn3));
+static_assert (!can_extract<int (C::*)()>(^^C::fn4));
+static_assert (!can_extract<int (*)() noexcept>(^^C::fn3));
+static_assert (!can_extract<int (*)()>(^^C::fn4));
+static_assert (!can_extract<int (*)()>(^^C::fn5));
+static_assert (!can_extract<int (C::*)(int) &&>(^^C::fn6));
+static_assert (!can_extract<int (C::*)(int) &>(^^C::fn7));
diff --git a/gcc/testsuite/g++.dg/reflect/extract3.C b/gcc/testsuite/g++.dg/reflect/extract3.C
new file mode 100644 (file)
index 0000000..f8c173c
--- /dev/null
@@ -0,0 +1,90 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<class, class> struct same_type;
+template<class T> struct same_type<T, T> {};
+
+static constexpr int i = 0;
+constexpr const int &r = i;
+static_assert (extract<const int &>(^^i) == i);
+static_assert (extract<const int &>(^^i) == 0);
+static_assert (&extract<const int &>(^^i) == &i);
+same_type<decltype(extract<const int &>(^^i)), const int &> st1;
+same_type<decltype(&extract<const int &>(^^i)), const int *> st2;
+const int& p = extract<const int &>(^^i);
+static_assert (extract<const int &>(^^r) == 0);
+static_assert (extract<const int &>(^^r) == i);
+
+static const int j = 0;
+const int &rj = j;
+static_assert (extract<const int &>(^^j) == j);
+static_assert (extract<const int &>(^^j) == 0);
+static_assert (&extract<const int &>(^^j) == &j);
+same_type<decltype(extract<const int &>(^^j)), const int &> st3;
+same_type<decltype(&extract<const int &>(^^j)), const int *> st4;
+const int &q = extract<const int &>(^^j);
+static_assert (extract<const int &>(^^rj) == 0);
+static_assert (extract<const int &>(^^rj) == j);
+static_assert (&extract<const int &>(^^rj) == &j);
+
+int k = 1;
+static_assert (&extract<int &>(^^k) == &k);
+static_assert (&extract<const int &>(^^k) == &k);
+
+int arr[5] {};
+static_assert (&extract<int (&)[5]>(^^arr) == &arr);
+static_assert (&extract<const int (&)[5]>(^^arr) == &arr);
+
+struct S { int m; };
+constexpr S s{42};
+constexpr const S &rs = s;
+static_assert (extract<const S &>(^^s).m == 42);
+static_assert (&extract<const S &>(^^s) == &s);
+same_type<decltype(extract<const S &>(^^s)), const S &> st5;
+same_type<decltype(&extract<const S &>(^^s)), const S *> st6;
+const S &ps = extract<const S &>(^^s);
+static_assert (extract<const S &>(^^rs).m == 42);
+static_assert (extract<const S &>(reflect_constant (S{42})).m == 42);
+same_type<decltype(extract<const S &>(reflect_constant (S{42}))), const S &> st7;
+same_type<decltype(&extract<const S &>(reflect_constant (S{42}))), const S *> st8;
+
+S sr{42};
+static_assert (&extract<S&>(^^sr) == &sr);
+static_assert (&extract<const S&>(^^sr) == &sr);
+static_assert (&extract<S&>(^^sr).m == &sr.m);
+int &srm = sr.m;
+static_assert (&extract<int&>(^^srm) == &sr.m);
+
+consteval bool foo() {
+   int i = 5;
+   return &extract<int&>(^^i) == &i;
+}
+static_assert (foo ());
+
+consteval int
+bar (int arg)
+{
+  int val = 3;
+  int &ref = extract<int &>(^^val);
+  ref = 4;
+  return val + extract<int>(^^arg);
+}
+static_assert (bar (5) == 9);
+
+consteval const int &
+baz ()
+{
+  return j;
+}
+
+void
+doit ()
+{
+  constexpr auto r = reflect_object (baz ());
+  static_assert (extract<const int &>(r) == 0);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/extract4.C b/gcc/testsuite/g++.dg/reflect/extract4.C
new file mode 100644 (file)
index 0000000..890caaa
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  int k;
+};
+
+// This one verifies that we called mark_used.
+constexpr auto a = extract<int S::*>(^^S::k);
+static_assert (extract<int S::*>(^^S::k) == &S::k);
+
+consteval int
+fn1 ()
+{
+  return extract<int(*)(int)>(reflect_constant ([](int id) { return id; }))(42);
+}
+static_assert (fn1 () == 42);
+
+constexpr auto l = [](int id) { return id; };
+static_assert (extract<int(*)(int)>(^^l)(42) == 42);
+static_assert (extract<decltype(l)>(^^l)(42) == 42);
+
+constexpr auto gl = [](auto a) { return constant_of (a); };
+constexpr int i = 42;
+static_assert (extract<decltype(gl)>(^^gl)(^^i) == reflect_constant (42));
diff --git a/gcc/testsuite/g++.dg/reflect/extract5.C b/gcc/testsuite/g++.dg/reflect/extract5.C
new file mode 100644 (file)
index 0000000..1e5fbde
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+consteval int
+foo ()
+{
+  int arg = 4;
+  return std::meta::extract<int>(^^arg);
+}
+
+static_assert (foo () == 4);
+
+consteval int
+bar (int arg)
+{
+  return std::meta::extract<int>(^^arg);
+}
+
+static_assert (bar (4) == 4);
+
+consteval int
+baz ()
+{
+  constexpr int arg = 4;
+  return std::meta::extract<int>(^^arg);
+}
+
+static_assert (baz () == 4);
diff --git a/gcc/testsuite/g++.dg/reflect/extract6.C b/gcc/testsuite/g++.dg/reflect/extract6.C
new file mode 100644 (file)
index 0000000..15c46b8
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+[[=1, =1, =2, =1.0f]] void fn ();
+struct [[=3, =3, =4, =2.0f]] S;
+
+template<info R>
+[[=[:constant_of (annotations_of (R)[0]):]]] void TFn();
+template<info R>
+struct [[=[:constant_of (annotations_of (R)[0]):]]] TCls {};
+
+static_assert (extract<int>(annotations_of (^^TFn<^^::fn>)[0]) == 1);
+static_assert (extract<int>(annotations_of (^^TCls<^^::S>)[0]) == 3); // { dg-error "non-constant" }
+static_assert (extract<int>(annotations_of (^^fn)[0]) == 1);
+// { dg-error "call to non-.constexpr." "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/reflect/extract7.C b/gcc/testsuite/g++.dg/reflect/extract7.C
new file mode 100644 (file)
index 0000000..ed4f464
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+void fn();
+static_assert(annotations_of(^^fn).size() == 0);
+[[=1, =2]] void fn();
+static_assert(annotations_of(^^fn).size() == 2);
+[[=3]] void fn();
+static_assert(annotations_of(^^fn).size() == 3);
+[[=4, =5]] void fn();
+static_assert(annotations_of(^^fn).size() == 5);
+[[=6]] void fn();
+static_assert(annotations_of(^^fn).size() == 6);
+void fn();
+static_assert(annotations_of(^^fn).size() == 6);
+
+static_assert(extract<int>(annotations_of(^^fn)[0]) == 1);
+static_assert(extract<int>(annotations_of(^^fn)[1]) == 2);
+static_assert(extract<int>(annotations_of(^^fn)[2]) == 3);
+static_assert(extract<int>(annotations_of(^^fn)[3]) == 4);
+static_assert(extract<int>(annotations_of(^^fn)[4]) == 5);
+static_assert(extract<int>(annotations_of(^^fn)[5]) == 6);
diff --git a/gcc/testsuite/g++.dg/reflect/extract8.C b/gcc/testsuite/g++.dg/reflect/extract8.C
new file mode 100644 (file)
index 0000000..2f9773b
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::extract.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<auto E>
+consteval bool
+check_val (info R)
+{
+  return extract<decltype (E)>(R) == E; // { dg-error "accessing .x. outside its lifetime" }
+}
+constexpr auto r = (check_val<42>([]() {
+  constexpr int x = 42;
+  return ^^x;
+}()));
diff --git a/gcc/testsuite/g++.dg/reflect/extract9.C b/gcc/testsuite/g++.dg/reflect/extract9.C
new file mode 100644 (file)
index 0000000..1f509b0
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// US 112-172
+
+#include <meta>
+using namespace std::meta;
+
+struct B { };
+struct D : B { };
+
+template<typename T>
+consteval bool
+can_extract (info r)
+{
+  try { extract<T>(r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+constexpr B arrb[] = { {}, {}, {} };
+constexpr D arrd[] = { {}, {}, {} };
+static_assert (can_extract<const D *>(^^arrd));
+static_assert (can_extract<const B *>(^^arrb));
+static_assert (!can_extract<const B *>(^^arrd));
+static_assert (!can_extract<const D *>(^^arrb));
diff --git a/gcc/testsuite/g++.dg/reflect/feat1.C b/gcc/testsuite/g++.dg/reflect/feat1.C
new file mode 100644 (file)
index 0000000..a84946d
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test feature test macros.
+
+#ifndef __cpp_impl_reflection
+#  error "__cpp_impl_reflection"
+#elif __cpp_impl_reflection != 202506
+#  error "__cpp_impl_reflection != 202506"
+#endif
+
+#include <meta>
+
+#ifndef __cpp_lib_reflection
+#  error "__cpp_lib_reflection"
+#elif __cpp_lib_reflection != 202506
+#  error "__cpp_lib_reflection != 202506"
+#endif
diff --git a/gcc/testsuite/g++.dg/reflect/feat2.C b/gcc/testsuite/g++.dg/reflect/feat2.C
new file mode 100644 (file)
index 0000000..902732b
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test feature test macros.
+
+#include <version>
+
+#ifndef __cpp_lib_reflection
+#  error "__cpp_lib_reflection"
+#elif __cpp_lib_reflection != 202506
+#  error "__cpp_lib_reflection != 202506"
+#endif
diff --git a/gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_c_language_linkage1.C
new file mode 100644 (file)
index 0000000..184277c
--- /dev/null
@@ -0,0 +1,160 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_c_language_linkage.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_c_language_linkage (null_reflection));
+static_assert (!has_c_language_linkage (^^::));
+static_assert (!has_c_language_linkage (^^ns));
+static_assert (!has_c_language_linkage (^^std));
+static_assert (!has_c_language_linkage (^^std::meta));
+static_assert (!has_c_language_linkage (^^ns));
+static_assert (!has_c_language_linkage (^^ns_alias));
+static_assert (!has_c_language_linkage (reflect_constant (3)));
+static_assert (!has_c_language_linkage (^^cls));
+static_assert (!has_c_language_linkage (^^cls::dm));
+static_assert (!has_c_language_linkage (^^cls::ref_dm));
+static_assert (!has_c_language_linkage (^^cls::static_dm));
+static_assert (!has_c_language_linkage (^^cls::mem_fun));
+static_assert (!has_c_language_linkage (^^cls::static_mem_fun));
+static_assert (!has_c_language_linkage (^^cls::type));
+static_assert (!has_c_language_linkage (^^cls_var));
+static_assert (!has_c_language_linkage (^^onion));
+static_assert (!has_c_language_linkage (^^anon));
+static_assert (!has_c_language_linkage (^^fun));
+static_assert (!has_c_language_linkage (^^alias));
+static_assert (!has_c_language_linkage (^^var));
+static_assert (!has_c_language_linkage (^^ref));
+static_assert (!has_c_language_linkage (^^rref));
+static_assert (!has_c_language_linkage (^^ptr));
+static_assert (!has_c_language_linkage (^^cls_tmpl));
+static_assert (!has_c_language_linkage (^^cls_tmpl<int>));
+static_assert (!has_c_language_linkage (^^incomplete_cls<int>));
+static_assert (!has_c_language_linkage (^^fun_tmpl));
+static_assert (!has_c_language_linkage (^^fun_tmpl<int>));
+static_assert (!has_c_language_linkage (^^conc));
+static_assert (!has_c_language_linkage (substitute (^^conc, { ^^int })));
+static_assert (!has_c_language_linkage (^^var_tmpl));
+static_assert (!has_c_language_linkage (^^var_tmpl<int>));
+static_assert (!has_c_language_linkage (^^cls_tmpl_alias));
+static_assert (!has_c_language_linkage (^^cls_tmpl_alias<int>));
+static_assert (!has_c_language_linkage (^^Enum));
+static_assert (!has_c_language_linkage (^^Enum::A));
+static_assert (!has_c_language_linkage (^^Enum_class));
+static_assert (!has_c_language_linkage (^^Enum_class::A));
+static_assert (!has_c_language_linkage (^^decomp));
+static_assert (!has_c_language_linkage (^^decomp_ref));
+static_assert (!has_c_language_linkage (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "a" });
+static_assert (!has_c_language_linkage (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_c_language_linkage (^^T));
+  static_assert (!has_c_language_linkage (R));
+  static_assert (!has_c_language_linkage (R2));
+  static_assert (!has_c_language_linkage (R3));
+}
+
+void
+g (int p, cls c)
+{
+  int v;
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!has_c_language_linkage (^^p));
+  static_assert (!has_c_language_linkage (^^c));
+  static_assert (!has_c_language_linkage (^^v));
+}
+
+static int var2;
+static int baz () { return 0; }
+
+static_assert (!has_c_language_linkage (^^var2));
+static_assert (!has_c_language_linkage (^^baz));
+
+namespace {
+  void qux () {}
+  int var3;
+  namespace NN {
+    int var4;
+  }
+  struct S2 {};
+}
+
+namespace NM {
+  int var5;
+  struct S3 {};
+}
+
+extern "C" {
+  void corge (int);
+  static void freddy () {}
+  typedef void plugh (int);
+}
+static void boo () {}
+
+int
+main ()
+{
+}
+
+extern "C" int garply (long, ...);
+
+const int ci = 42;
+extern const int ci2 = 42;
+
+static_assert (!has_c_language_linkage (^^qux));
+static_assert (!has_c_language_linkage (^^var3));
+static_assert (!has_c_language_linkage (^^NN));
+static_assert (!has_c_language_linkage (^^NN::var4));
+static_assert (!has_c_language_linkage (^^NM::var5));
+static_assert (!has_c_language_linkage (^^S2));
+static_assert (!has_c_language_linkage (^^NM::S3));
+static_assert (has_c_language_linkage (^^corge));
+static_assert (has_c_language_linkage (^^main));
+static_assert (has_c_language_linkage (^^garply));
+static_assert (!has_c_language_linkage (^^ci));
+static_assert (!has_c_language_linkage (^^ci2));
+static_assert (has_c_language_linkage (^^freddy));
+static_assert (!has_c_language_linkage (^^boo));
+// TODO: We don't have TYPE_LANGUAGE nor DECL_LANGUAGE on TYPE_DECLs.
+//static_assert (has_c_language_linkage (^^plugh));
diff --git a/gcc/testsuite/g++.dg/reflect/has_default_argument1.C b/gcc/testsuite/g++.dg/reflect/has_default_argument1.C
new file mode 100644 (file)
index 0000000..4d86824
--- /dev/null
@@ -0,0 +1,132 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_default_argument.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_default_argument (null_reflection));
+static_assert (!has_default_argument (^^::));
+static_assert (!has_default_argument (^^ns));
+static_assert (!has_default_argument (^^ns_alias));
+static_assert (!has_default_argument (reflect_constant (3)));
+static_assert (!has_default_argument (^^cls));
+static_assert (!has_default_argument (^^cls::dm));
+static_assert (!has_default_argument (^^cls::ref_dm));
+static_assert (!has_default_argument (^^cls::static_dm));
+static_assert (!has_default_argument (^^cls::mem_fun));
+static_assert (!has_default_argument (^^cls::static_mem_fun));
+static_assert (!has_default_argument (^^cls::type));
+static_assert (!has_default_argument (^^cls_var));
+static_assert (!has_default_argument (^^onion));
+static_assert (!has_default_argument (^^anon));
+static_assert (!has_default_argument (^^fun));
+static_assert (!has_default_argument (^^alias));
+static_assert (!has_default_argument (^^var));
+static_assert (!has_default_argument (^^ref));
+static_assert (!has_default_argument (^^rref));
+static_assert (!has_default_argument (^^ptr));
+static_assert (!has_default_argument (^^cls_tmpl));
+static_assert (!has_default_argument (^^cls_tmpl<int>));
+static_assert (!has_default_argument (^^incomplete_cls<int>));
+static_assert (!has_default_argument (^^fun_tmpl));
+static_assert (!has_default_argument (^^fun_tmpl<int>));
+static_assert (!has_default_argument (^^conc));
+static_assert (!has_default_argument (substitute (^^conc, { ^^int })));
+static_assert (!has_default_argument (^^var_tmpl));
+static_assert (!has_default_argument (^^var_tmpl<int>));
+static_assert (!has_default_argument (^^cls_tmpl_alias));
+static_assert (!has_default_argument (^^cls_tmpl_alias<int>));
+static_assert (!has_default_argument (^^Enum));
+static_assert (!has_default_argument (^^Enum::A));
+static_assert (!has_default_argument (^^Enum_class));
+static_assert (!has_default_argument (^^Enum_class::A));
+static_assert (!has_default_argument (^^decomp));
+static_assert (!has_default_argument (^^decomp_ref));
+static_assert (!has_default_argument (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "n" });
+static_assert (!has_default_argument (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!has_default_argument (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_default_argument (^^T));
+  static_assert (!has_default_argument (R));
+  static_assert (!has_default_argument (R2));
+  static_assert (!has_default_argument (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^p, ^^c>();
+  static_assert (!has_default_argument (^^p));
+  static_assert (!has_default_argument (^^c));
+}
+
+void h (int a, int b);
+static_assert (!has_default_argument (parameters_of (^^h)[0]));
+static_assert (!has_default_argument (parameters_of (^^h)[1]));
+constexpr auto ha = parameters_of (^^h)[0];
+constexpr auto hb = parameters_of (^^h)[1];
+void h (int c, int d = 42);
+static_assert (!has_default_argument (parameters_of (^^h)[0]));
+static_assert (has_default_argument (parameters_of (^^h)[1]));
+static_assert (!has_default_argument (ha));
+static_assert (has_default_argument (hb));
+void h (int c = 5, int d);
+static_assert (has_default_argument (parameters_of (^^h)[0]));
+static_assert (has_default_argument (parameters_of (^^h)[1]));
+static_assert (has_default_argument (ha));
+static_assert (has_default_argument (hb));
+
+void
+h (int e, int f)
+{
+  static_assert (has_default_argument (parameters_of (^^h)[0]));
+  static_assert (has_default_argument (parameters_of (^^h)[1]));
+  static_assert (has_default_argument (ha));
+  static_assert (has_default_argument (hb));
+  static_assert (!has_default_argument (^^e));
+  static_assert (!has_default_argument (^^f));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/has_default_argument2.C b/gcc/testsuite/g++.dg/reflect/has_default_argument2.C
new file mode 100644 (file)
index 0000000..2edec19
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_default_argument.
+
+#include <meta>
+
+void foo (int a, const int b = 42);
+constexpr auto parm1info = std::meta::parameters_of (^^foo)[0];
+constexpr auto parm2info = std::meta::parameters_of (^^foo)[1];
+static_assert (!std::meta::has_default_argument (parm1info));
+static_assert ( std::meta::has_default_argument (parm2info));
+void foo (int = 14, const int);
+static_assert ( std::meta::has_default_argument (parm1info));
+static_assert ( std::meta::has_default_argument (parm2info));
+static_assert (std::meta::type_of (parm1info) == ^^int);
+static_assert (std::meta::type_of (parm2info) == ^^int);
+
+void
+foo (int c, const int d)
+{
+  constexpr auto p = std::meta::parameters_of (^^foo)[1];
+  static_assert (p == parm2info);
+  static_assert (std::meta::has_default_argument (p));
+  static_assert (std::meta::type_of (p) == ^^int);
+  static_assert (std::meta::type_of (std::meta::variable_of (p)) == ^^const int);
+  static_assert (std::meta::type_of (^^d) == ^^const int);
+
+  static_assert ( std::meta::has_default_argument (parm1info));
+  static_assert ( std::meta::has_default_argument (parm2info));
+  static_assert (std::meta::type_of (parm1info) == ^^int);
+  static_assert (std::meta::type_of (parm2info) == ^^int);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C b/gcc/testsuite/g++.dg/reflect/has_default_member_initializer1.C
new file mode 100644 (file)
index 0000000..ab48ffe
--- /dev/null
@@ -0,0 +1,133 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_default_member_initializer.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  int dm2 = 42;
+  int &ref_dm2;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+  cls () : ref_dm2 (dm2) {}
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_default_member_initializer (null_reflection));
+static_assert (!has_default_member_initializer (^^::));
+static_assert (!has_default_member_initializer (^^ns));
+static_assert (!has_default_member_initializer (^^ns_alias));
+static_assert (!has_default_member_initializer (reflect_constant (3)));
+static_assert (!has_default_member_initializer (^^cls));
+static_assert (!has_default_member_initializer (^^cls::dm));
+static_assert (has_default_member_initializer (^^cls::ref_dm));
+static_assert (has_default_member_initializer (^^cls::dm2));
+static_assert (!has_default_member_initializer (^^cls::ref_dm2));
+static_assert (!has_default_member_initializer (^^cls::static_dm));
+static_assert (!has_default_member_initializer (^^cls::mem_fun));
+static_assert (!has_default_member_initializer (^^cls::static_mem_fun));
+static_assert (!has_default_member_initializer (^^cls::type));
+static_assert (!has_default_member_initializer (^^cls::E));
+static_assert (!has_default_member_initializer (^^cls::B));
+static_assert (!has_default_member_initializer (^^cls::C));
+static_assert (!has_default_member_initializer (^^cls::D));
+static_assert (!has_default_member_initializer (^^cls::F));
+static_assert (!has_default_member_initializer (^^cls::F::G));
+static_assert (!has_default_member_initializer (^^cls::F::H));
+static_assert (!has_default_member_initializer (^^cls::S));
+static_assert (!has_default_member_initializer (^^cls::U));
+static_assert (!has_default_member_initializer (^^cls::foo));
+static_assert (!has_default_member_initializer (^^cls::foo <0>));
+static_assert (!has_default_member_initializer (^^cls::bar));
+static_assert (!has_default_member_initializer (^^cls::bar <42>));
+static_assert (!has_default_member_initializer (^^cls_var));
+static_assert (!has_default_member_initializer (^^onion));
+static_assert (!has_default_member_initializer (^^anon));
+static_assert (!has_default_member_initializer (^^fun));
+static_assert (!has_default_member_initializer (^^alias));
+static_assert (!has_default_member_initializer (^^var));
+static_assert (!has_default_member_initializer (^^ref));
+static_assert (!has_default_member_initializer (^^rref));
+static_assert (!has_default_member_initializer (^^ptr));
+static_assert (!has_default_member_initializer (^^cls_tmpl));
+static_assert (!has_default_member_initializer (^^cls_tmpl<int>));
+static_assert (!has_default_member_initializer (^^incomplete_cls<int>));
+static_assert (!has_default_member_initializer (^^fun_tmpl));
+static_assert (!has_default_member_initializer (^^fun_tmpl<int>));
+static_assert (!has_default_member_initializer (^^conc));
+static_assert (!has_default_member_initializer (substitute (^^conc, { ^^int })));
+static_assert (!has_default_member_initializer (^^var_tmpl));
+static_assert (!has_default_member_initializer (^^var_tmpl<int>));
+static_assert (!has_default_member_initializer (^^cls_tmpl_alias));
+static_assert (!has_default_member_initializer (^^cls_tmpl_alias<int>));
+static_assert (!has_default_member_initializer (^^Enum));
+static_assert (!has_default_member_initializer (^^Enum::A));
+static_assert (!has_default_member_initializer (^^Enum_class));
+static_assert (!has_default_member_initializer (^^Enum_class::A));
+static_assert (!has_default_member_initializer (^^decomp));
+static_assert (!has_default_member_initializer (^^decomp_ref));
+static_assert (!has_default_member_initializer (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "a" });
+static_assert (!has_default_member_initializer (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!has_default_member_initializer (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+void
+foo (int x, int y = 10)
+{
+  static_assert (!has_default_member_initializer (^^x));
+  static_assert (!has_default_member_initializer (parameters_of (^^foo)[0]));
+  static_assert (!has_default_member_initializer (parameters_of (^^foo)[1]));
+  int v;
+  static_assert (!has_default_member_initializer (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!has_default_member_initializer (^^S));
+  static_assert (!has_default_member_initializer (^^E));
+  static_assert (!has_default_member_initializer (^^F));
+  static_assert (!has_default_member_initializer (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C b/gcc/testsuite/g++.dg/reflect/has_ellipsis_parameter1.C
new file mode 100644 (file)
index 0000000..e749ce5
--- /dev/null
@@ -0,0 +1,148 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_ellipsis_parameter.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  void mem_fun2 (int, ...);
+  void mem_fun3 (...);
+  void mem_fun4 (int);
+  static void static_mem_fun ();
+  static void static_mem_fun2 (int, long, ...);
+  static void static_mem_fun3 (...);
+  static void static_mem_fun4 (long);
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+void fun2 (int, ...);
+void fun3 (...);
+void fun4 (int, int);
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+using funt = int ();
+using funt2 = int (int, ...);
+using funt3 = int (...);
+using funt4 = int (int, long);
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> void fun_tmpl2 (int, ...);
+template<typename> void fun_tmpl3 (...);
+template<typename> void fun_tmpl4 (long, int);
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+using inc_arr = int[];
+using com_arr = int[42];
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_ellipsis_parameter (null_reflection));
+static_assert (!has_ellipsis_parameter (^^::));
+static_assert (!has_ellipsis_parameter (^^ns));
+static_assert (!has_ellipsis_parameter (^^ns_alias));
+static_assert (!has_ellipsis_parameter (reflect_constant (3)));
+static_assert (!has_ellipsis_parameter (^^cls));
+static_assert (!has_ellipsis_parameter (^^cls::dm));
+static_assert (!has_ellipsis_parameter (^^cls::ref_dm));
+static_assert (!has_ellipsis_parameter (^^cls::static_dm));
+static_assert (!has_ellipsis_parameter (^^cls::mem_fun));
+static_assert (has_ellipsis_parameter (^^cls::mem_fun2));
+static_assert (has_ellipsis_parameter (^^cls::mem_fun3));
+static_assert (!has_ellipsis_parameter (^^cls::mem_fun4));
+static_assert (!has_ellipsis_parameter (^^cls::static_mem_fun));
+static_assert (has_ellipsis_parameter (^^cls::static_mem_fun2));
+static_assert (has_ellipsis_parameter (^^cls::static_mem_fun3));
+static_assert (!has_ellipsis_parameter (^^cls::static_mem_fun4));
+static_assert (!has_ellipsis_parameter (^^cls::type));
+static_assert (!has_ellipsis_parameter (^^cls_var));
+static_assert (!has_ellipsis_parameter (^^onion));
+static_assert (!has_ellipsis_parameter (^^anon));
+static_assert (!has_ellipsis_parameter (^^fun));
+static_assert (has_ellipsis_parameter (^^fun2));
+static_assert (has_ellipsis_parameter (^^fun3));
+static_assert (!has_ellipsis_parameter (^^fun4));
+static_assert (!has_ellipsis_parameter (type_of (^^fun)));
+static_assert (has_ellipsis_parameter (type_of (^^fun2)));
+static_assert (has_ellipsis_parameter (type_of (^^fun3)));
+static_assert (!has_ellipsis_parameter (type_of (^^fun4)));
+static_assert (!has_ellipsis_parameter (^^alias));
+static_assert (!has_ellipsis_parameter (^^var));
+static_assert (!has_ellipsis_parameter (^^ref));
+static_assert (!has_ellipsis_parameter (^^rref));
+static_assert (!has_ellipsis_parameter (^^ptr));
+static_assert (!has_ellipsis_parameter (^^cls_tmpl));
+static_assert (!has_ellipsis_parameter (^^cls_tmpl<int>));
+static_assert (!has_ellipsis_parameter (^^incomplete_cls<int>));
+static_assert (!has_ellipsis_parameter (^^fun_tmpl));
+static_assert (!has_ellipsis_parameter (^^fun_tmpl<int>));
+static_assert (!has_ellipsis_parameter (^^fun_tmpl2));
+static_assert (has_ellipsis_parameter (^^fun_tmpl2<int>));
+static_assert (!has_ellipsis_parameter (^^fun_tmpl3));
+static_assert (has_ellipsis_parameter (^^fun_tmpl3<int>));
+static_assert (!has_ellipsis_parameter (^^fun_tmpl4));
+static_assert (!has_ellipsis_parameter (^^fun_tmpl4<int>));
+static_assert (!has_ellipsis_parameter (^^conc));
+static_assert (!has_ellipsis_parameter (substitute (^^conc, { ^^int })));
+static_assert (!has_ellipsis_parameter (^^var_tmpl));
+static_assert (!has_ellipsis_parameter (^^var_tmpl<int>));
+static_assert (!has_ellipsis_parameter (^^cls_tmpl_alias));
+static_assert (!has_ellipsis_parameter (^^cls_tmpl_alias<int>));
+static_assert (!has_ellipsis_parameter (^^Enum));
+static_assert (!has_ellipsis_parameter (^^Enum::A));
+static_assert (!has_ellipsis_parameter (^^Enum_class));
+static_assert (!has_ellipsis_parameter (^^Enum_class::A));
+static_assert (!has_ellipsis_parameter (^^decomp));
+static_assert (!has_ellipsis_parameter (^^decomp_ref));
+static_assert (!has_ellipsis_parameter (^^arr));
+static_assert (!has_ellipsis_parameter (^^inc_arr));
+static_assert (!has_ellipsis_parameter (^^com_arr));
+static_assert (!has_ellipsis_parameter (^^funt));
+static_assert (has_ellipsis_parameter (^^funt2));
+static_assert (has_ellipsis_parameter (^^funt3));
+static_assert (!has_ellipsis_parameter (^^funt4));
+
+constexpr auto dms = data_member_spec (^^int, { .name = u8"a" });
+static_assert (!has_ellipsis_parameter (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!has_ellipsis_parameter (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_ellipsis_parameter (^^T));
+  static_assert (!has_ellipsis_parameter (R));
+  static_assert (!has_ellipsis_parameter (R2));
+  static_assert (!has_ellipsis_parameter (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!has_ellipsis_parameter (^^p));
+  static_assert (!has_ellipsis_parameter (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/has_external_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_external_linkage1.C
new file mode 100644 (file)
index 0000000..e6e7911
--- /dev/null
@@ -0,0 +1,149 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_external_linkage.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_external_linkage (null_reflection));
+static_assert (has_external_linkage (^^::));
+static_assert (has_external_linkage (^^ns));
+static_assert (has_external_linkage (^^std));
+static_assert (has_external_linkage (^^std::meta));
+static_assert (has_external_linkage (^^ns_alias));
+static_assert (!has_external_linkage (reflect_constant (3)));
+static_assert (has_external_linkage (^^cls));
+static_assert (!has_external_linkage (^^cls::dm));
+static_assert (!has_external_linkage (^^cls::ref_dm));
+static_assert (has_external_linkage (^^cls::static_dm));
+static_assert (has_external_linkage (^^cls::mem_fun));
+static_assert (has_external_linkage (^^cls::static_mem_fun));
+static_assert (!has_external_linkage (^^cls::type));
+static_assert (has_external_linkage (^^cls_var));
+static_assert (has_external_linkage (^^onion));
+static_assert (!has_external_linkage (^^anon));
+static_assert (has_external_linkage (^^fun));
+static_assert (!has_external_linkage (^^alias));
+static_assert (has_external_linkage (^^var));
+static_assert (has_external_linkage (^^ref));
+static_assert (has_external_linkage (^^rref));
+static_assert (has_external_linkage (^^ptr));
+static_assert (has_external_linkage (^^cls_tmpl));
+static_assert (has_external_linkage (^^cls_tmpl<int>));
+static_assert (has_external_linkage (^^incomplete_cls<int>));
+static_assert (has_external_linkage (^^fun_tmpl));
+static_assert (has_external_linkage (^^fun_tmpl<int>));
+static_assert (has_external_linkage (^^conc));
+static_assert (!has_external_linkage (substitute (^^conc, { ^^int })));
+static_assert (has_external_linkage (^^var_tmpl));
+static_assert (has_external_linkage (^^var_tmpl<int>));
+static_assert (!has_external_linkage (^^cls_tmpl_alias));
+static_assert (!has_external_linkage (^^cls_tmpl_alias<int>));
+static_assert (has_external_linkage (^^Enum));
+static_assert (!has_external_linkage (^^Enum::A));
+static_assert (has_external_linkage (^^Enum_class));
+static_assert (!has_external_linkage (^^Enum_class::A));
+static_assert (!has_external_linkage (^^decomp));
+static_assert (!has_external_linkage (^^decomp_ref));
+static_assert (has_external_linkage (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_external_linkage (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_external_linkage (^^T));
+  static_assert (has_external_linkage (R));
+  static_assert (has_external_linkage (R2));
+  static_assert (has_external_linkage (R3));
+}
+
+void
+g (int p, cls c)
+{
+  int v;
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!has_external_linkage (^^p));
+  static_assert (!has_external_linkage (^^c));
+  static_assert (!has_external_linkage (^^v));
+}
+
+static int var2;
+static int baz () { return 0; }
+
+static_assert (!has_external_linkage (^^var2));
+static_assert (!has_external_linkage (^^baz));
+
+namespace {
+  void qux () {}
+  int var3;
+  namespace NN {
+    int var4;
+  }
+  struct S2 {};
+}
+
+namespace NM {
+  int var5;
+  struct S3 {};
+}
+
+extern "C" {
+  void corge (int);
+}
+
+int
+main ()
+{
+}
+
+const int ci = 42;
+extern const int ci2 = 42;
+
+static_assert (!has_external_linkage (^^qux));
+static_assert (!has_external_linkage (^^var3));
+static_assert (!has_external_linkage (^^NN));
+static_assert (!has_external_linkage (^^NN::var4));
+static_assert (has_external_linkage (^^NM::var5));
+static_assert (!has_external_linkage (^^S2));
+static_assert (has_external_linkage (^^NM::S3));
+static_assert (has_external_linkage (^^corge));
+static_assert (has_external_linkage (^^main));
+static_assert (!has_external_linkage (^^ci));
+static_assert (has_external_linkage (^^ci2));
diff --git a/gcc/testsuite/g++.dg/reflect/has_external_linkage2.C b/gcc/testsuite/g++.dg/reflect/has_external_linkage2.C
new file mode 100644 (file)
index 0000000..a0b8825
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -fmodules" }
+// Test std::meta::has_external_linkage.
+
+module;
+
+#include <meta>
+
+module has_external_linkage:counter;
+
+int counter = 0;
+
+static_assert (!std::meta::has_external_linkage (^^counter));
diff --git a/gcc/testsuite/g++.dg/reflect/has_identifier1.C b/gcc/testsuite/g++.dg/reflect/has_identifier1.C
new file mode 100644 (file)
index 0000000..f9c8c94
--- /dev/null
@@ -0,0 +1,241 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_identifier.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+
+struct S { };
+using T = int;
+using U = S;
+enum E { E1, E2 };
+enum { E3, E4 };
+typedef enum { E5, E6 } E7;
+union P { int a; };
+
+static_assert (!has_identifier (null_reflection));
+static_assert (!has_identifier (^^int));
+static_assert (has_identifier (^^T));
+static_assert (!has_identifier (^^::));
+static_assert (has_identifier (^^S));
+static_assert (has_identifier (^^U));
+static_assert (has_identifier (^^P));
+static_assert (!has_identifier (^^const S));
+static_assert (!has_identifier (^^const volatile U));
+static_assert (!has_identifier (^^P volatile));
+static_assert (has_identifier (^^std));
+static_assert (has_identifier (^^std::meta));
+static_assert (!has_identifier (^^int *));
+static_assert (!has_identifier (^^int));
+static_assert (!has_identifier (^^unsigned long long));
+static_assert (!has_identifier (^^long &&));
+static_assert (has_identifier (^^E1));
+static_assert (has_identifier (^^E));
+static_assert (!has_identifier (^^E const));
+static_assert (!has_identifier (^^volatile E));
+static_assert (!has_identifier (^^const E volatile));
+static_assert (!has_identifier (parent_of (^^E3)));
+static_assert (has_identifier (parent_of (^^E5)));
+static_assert (has_identifier (^^E7));
+static_assert (has_identifier (dealias (^^E7)));
+[[=1]] int w;
+static_assert (!has_identifier (annotations_of (^^w)[0]));
+static_assert (!has_identifier (data_member_spec (^^int, { .bit_width = 0 })));
+static_assert (!has_identifier (data_member_spec (^^long, { .bit_width = 6 })));
+static_assert (has_identifier (data_member_spec (^^long, { .name = "dms", .bit_width = 6 })));
+static_assert (has_identifier (data_member_spec (^^long, { .name = u8"dms", .alignment = 2 * alignof (long) })));
+
+namespace N {}
+namespace NA = N;
+static_assert (has_identifier (^^N));
+static_assert (has_identifier (^^NA));
+
+namespace {
+  int a;
+  namespace M {}
+  static_assert (has_identifier (^^a));
+  static_assert (!has_identifier (parent_of (^^a)));
+  static_assert (has_identifier (^^M));
+  static_assert (!has_identifier (parent_of (^^M)));
+  static_assert (!has_identifier (parent_of (parent_of (^^M))));
+}
+
+typedef struct {
+  int a;
+  static_assert (has_identifier (^^a));
+  static_assert (!has_identifier (parent_of (^^a)));
+} SV;
+static_assert (has_identifier (^^SV));
+static_assert (has_identifier (parent_of (^^SV::a)));
+static_assert (has_identifier (dealias (^^SV)));
+
+template <int N>
+struct ST
+{
+  static_assert (has_identifier (^^ST));
+  static_assert (!has_identifier (^^ST <N>));
+};
+
+struct V
+{
+  V () { int a; static_assert (!has_identifier (parent_of (^^a))); }
+  V (int, long) { int a; static_assert (!has_identifier (parent_of (^^a))); }
+  template <typename T>
+  V (long, T &) { int a; static_assert (!has_identifier (parent_of (^^a))); }
+  ~V () { int a; static_assert (!has_identifier (parent_of (^^a))); }
+  V &operator = (const V &) { int a; static_assert (!has_identifier (parent_of (^^a))); return *this; }
+  V &operator + (const V &) { int a; static_assert (!has_identifier (parent_of (^^a))); return *this; }
+  template <typename T>
+  V &operator * (const T &) { int a; static_assert (!has_identifier (parent_of (^^a))); return *this; }
+  operator int () { int a; static_assert (!has_identifier (parent_of (^^a))); return *this; }
+  void foo () { int a; static_assert (has_identifier (parent_of (^^a))); }
+  template <int N>
+  void bar () { int a; static_assert (has_identifier (parent_of (^^a))); }
+};
+
+struct W
+{
+  template <typename T>
+  explicit operator T () { int a; static_assert (!has_identifier (parent_of (^^a))); }
+};
+
+int
+operator ""_a (const char *)
+{
+  int a;
+  static_assert (has_identifier (parent_of (^^a)));
+  return 0;
+}
+
+int v;
+static_assert (!has_identifier (^^V::operator =));
+static_assert (!has_identifier (^^V::operator +));
+static_assert (!has_identifier (^^V::operator *));
+static_assert (!has_identifier (^^V::operator *<int>));
+static_assert (!has_identifier (^^V::operator int));
+static_assert (has_identifier (^^V::foo));
+static_assert (has_identifier (^^V::bar));
+static_assert (!has_identifier (^^V::bar <0>));
+
+void foo (int);
+static_assert (has_identifier (^^foo));
+
+int arr[3];
+
+void
+foo (int a)
+{
+  auto [b, c, d] = arr;
+  static_assert (has_identifier (^^foo));
+  static_assert (has_identifier (^^a));
+  static_assert (has_identifier (^^b));
+  static_assert (has_identifier (^^c));
+  static_assert (has_identifier (^^d));
+}
+
+template <int N>
+void
+bar (int a)
+{
+  auto [...b, c] = arr;
+  static_assert (has_identifier (^^foo));
+  static_assert (has_identifier (^^a));
+  static_assert (has_identifier (^^c));
+}
+
+void
+baz ()
+{
+  auto a = [] {
+    int a;
+    static_assert (has_identifier (^^a));
+    static_assert (!has_identifier (parent_of (^^a)));
+    static_assert (!has_identifier (parent_of (parent_of (^^a))));
+    static_assert (has_identifier (parent_of (parent_of (parent_of (^^a)))));
+  };
+  using t = decltype (a);
+  static_assert (has_identifier (^^t));
+  static_assert (!has_identifier (dealias (^^t)));
+}
+
+void qux (int, int b, int c, int d, int);
+constexpr auto p0 = parameters_of (^^qux)[0];
+constexpr auto p1 = parameters_of (^^qux)[1];
+constexpr auto p2 = parameters_of (^^qux)[2];
+constexpr auto p3 = parameters_of (^^qux)[3];
+constexpr auto p4 = parameters_of (^^qux)[4];
+static_assert (!has_identifier (p0));
+static_assert (has_identifier (p1));
+static_assert (has_identifier (p2));
+static_assert (has_identifier (p3));
+static_assert (!has_identifier (p4));
+void qux (int a, int, int c, int e, int);
+static_assert (has_identifier (p0));
+static_assert (has_identifier (p1));
+static_assert (has_identifier (p2));
+static_assert (!has_identifier (p3));
+static_assert (!has_identifier (p4));
+
+void
+qux (int a, int, int, int e, int)
+{
+  static_assert (has_identifier (p0));
+  static_assert (has_identifier (p1));
+  static_assert (has_identifier (p2));
+  static_assert (!has_identifier (p3));
+  static_assert (!has_identifier (p4));
+  static_assert (has_identifier (variable_of (p0)));
+  static_assert (!has_identifier (variable_of (p1)));
+  static_assert (!has_identifier (variable_of (p2)));
+  static_assert (has_identifier (variable_of (p3)));
+  static_assert (!has_identifier (variable_of (p4)));
+}
+
+void qux (int f, int, int, int, int g);
+static_assert (!has_identifier (p0));
+static_assert (has_identifier (p1));
+static_assert (has_identifier (p2));
+static_assert (!has_identifier (p3));
+static_assert (has_identifier (p4));
+
+template <typename... T>
+void
+freddy (int a, T... b)
+{
+}
+
+static_assert (has_identifier (parameters_of (^^freddy <int, long, char>)[0]));
+static_assert (!has_identifier (parameters_of (^^freddy <int, long, char>)[1]));
+
+struct {
+  int a;
+} s;
+
+static_assert (has_identifier (^^s));
+static_assert (!has_identifier (type_of (^^s)));
+
+void
+corge ()
+{
+  __extension__ constexpr bool b = has_identifier (({ struct S2 { }; ^^S2; }));
+}
+
+typedef struct {
+  int b;
+} TN;
+
+static_assert (has_identifier (parent_of (^^TN::b)));
+static_assert (has_identifier (^^TN));
+static_assert (has_identifier (dealias (^^TN)));
+
+typedef enum {
+  E8,
+  E9 = has_identifier (parent_of (^^E8)) ? 2 : 3,
+} E10;
+static_assert (E9 == 3);
+static_assert (has_identifier (parent_of (^^E8)));
+static_assert (has_identifier (^^E10));
+static_assert (has_identifier (dealias (^^E10)));
diff --git a/gcc/testsuite/g++.dg/reflect/has_identifier2.C b/gcc/testsuite/g++.dg/reflect/has_identifier2.C
new file mode 100644 (file)
index 0000000..49f0092
--- /dev/null
@@ -0,0 +1,57 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_identifier.
+
+#include <meta>
+
+using namespace std::meta;
+
+namespace N
+{
+  consteval bool
+  has_identifier (info r) { return std::meta::has_identifier (r); }
+  consteval std::vector<info>
+  parameters_of (info r) { return std::meta::parameters_of (r); }
+  consteval info
+  variable_of (info r) { return std::meta::variable_of (r); }
+}
+
+void qux (int, int b, int c, int d, int);
+constexpr auto p0 = N::parameters_of (^^qux)[0];
+constexpr auto p1 = N::parameters_of (^^qux)[1];
+constexpr auto p2 = N::parameters_of (^^qux)[2];
+constexpr auto p3 = N::parameters_of (^^qux)[3];
+constexpr auto p4 = N::parameters_of (^^qux)[4];
+static_assert (!N::has_identifier (p0));
+static_assert (N::has_identifier (p1));
+static_assert (N::has_identifier (p2));
+static_assert (N::has_identifier (p3));
+static_assert (!N::has_identifier (p4));
+void qux (int a, int, int c, int e, int);
+static_assert (N::has_identifier (p0));
+static_assert (N::has_identifier (p1));
+static_assert (N::has_identifier (p2));
+static_assert (!N::has_identifier (p3));
+static_assert (!N::has_identifier (p4));
+
+void
+qux (int a, int, int, int e, int)
+{
+  static_assert (N::has_identifier (p0));
+  static_assert (N::has_identifier (p1));
+  static_assert (N::has_identifier (p2));
+  static_assert (!N::has_identifier (p3));
+  static_assert (!N::has_identifier (p4));
+  static_assert (N::has_identifier (N::variable_of (p0)));
+  static_assert (!N::has_identifier (N::variable_of (p1)));
+  static_assert (!N::has_identifier (N::variable_of (p2)));
+  static_assert (N::has_identifier (N::variable_of (p3)));
+  static_assert (!N::has_identifier (N::variable_of (p4)));
+}
+
+void qux (int f, int, int, int, int g);
+static_assert (!N::has_identifier (p0));
+static_assert (N::has_identifier (p1));
+static_assert (N::has_identifier (p2));
+static_assert (!N::has_identifier (p3));
+static_assert (N::has_identifier (p4));
diff --git a/gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_internal_linkage1.C
new file mode 100644 (file)
index 0000000..7936543
--- /dev/null
@@ -0,0 +1,149 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_internal_linkage.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_internal_linkage (null_reflection));
+static_assert (!has_internal_linkage (^^::));
+static_assert (!has_internal_linkage (^^ns));
+static_assert (!has_internal_linkage (^^std));
+static_assert (!has_internal_linkage (^^std::meta));
+static_assert (!has_internal_linkage (^^ns_alias));
+static_assert (!has_internal_linkage (reflect_constant (3)));
+static_assert (!has_internal_linkage (^^cls));
+static_assert (!has_internal_linkage (^^cls::dm));
+static_assert (!has_internal_linkage (^^cls::ref_dm));
+static_assert (!has_internal_linkage (^^cls::static_dm));
+static_assert (!has_internal_linkage (^^cls::mem_fun));
+static_assert (!has_internal_linkage (^^cls::static_mem_fun));
+static_assert (!has_internal_linkage (^^cls::type));
+static_assert (!has_internal_linkage (^^cls_var));
+static_assert (!has_internal_linkage (^^onion));
+static_assert (!has_internal_linkage (^^anon));
+static_assert (!has_internal_linkage (^^fun));
+static_assert (!has_internal_linkage (^^alias));
+static_assert (!has_internal_linkage (^^var));
+static_assert (!has_internal_linkage (^^ref));
+static_assert (!has_internal_linkage (^^rref));
+static_assert (!has_internal_linkage (^^ptr));
+static_assert (!has_internal_linkage (^^cls_tmpl));
+static_assert (!has_internal_linkage (^^cls_tmpl<int>));
+static_assert (!has_internal_linkage (^^incomplete_cls<int>));
+static_assert (!has_internal_linkage (^^fun_tmpl));
+static_assert (!has_internal_linkage (^^fun_tmpl<int>));
+static_assert (!has_internal_linkage (^^conc));
+static_assert (!has_internal_linkage (substitute (^^conc, { ^^int })));
+static_assert (!has_internal_linkage (^^var_tmpl));
+static_assert (!has_internal_linkage (^^var_tmpl<int>));
+static_assert (!has_internal_linkage (^^cls_tmpl_alias));
+static_assert (!has_internal_linkage (^^cls_tmpl_alias<int>));
+static_assert (!has_internal_linkage (^^Enum));
+static_assert (!has_internal_linkage (^^Enum::A));
+static_assert (!has_internal_linkage (^^Enum_class));
+static_assert (!has_internal_linkage (^^Enum_class::A));
+static_assert (!has_internal_linkage (^^decomp));
+static_assert (!has_internal_linkage (^^decomp_ref));
+static_assert (!has_internal_linkage (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_internal_linkage (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_internal_linkage (^^T));
+  static_assert (!has_internal_linkage (R));
+  static_assert (!has_internal_linkage (R2));
+  static_assert (!has_internal_linkage (R3));
+}
+
+void
+g (int p, cls c)
+{
+  int v;
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!has_internal_linkage (^^p));
+  static_assert (!has_internal_linkage (^^c));
+  static_assert (!has_internal_linkage (^^v));
+}
+
+static int var2;
+static int baz () { return 0; }
+
+static_assert (has_internal_linkage (^^var2));
+static_assert (has_internal_linkage (^^baz));
+
+namespace {
+  void qux () {}
+  int var3;
+  namespace NN {
+    int var4;
+  }
+  struct S2 {};
+}
+
+namespace NM {
+  int var5;
+  struct S3 {};
+}
+
+extern "C" {
+  void corge (int);
+}
+
+int
+main ()
+{
+}
+
+const int ci = 42;
+extern const int ci2 = 42;
+
+static_assert (has_internal_linkage (^^qux));
+static_assert (has_internal_linkage (^^var3));
+static_assert (has_internal_linkage (^^NN));
+static_assert (has_internal_linkage (^^NN::var4));
+static_assert (!has_internal_linkage (^^NM::var5));
+static_assert (has_internal_linkage (^^S2));
+static_assert (!has_internal_linkage (^^NM::S3));
+static_assert (!has_internal_linkage (^^corge));
+static_assert (!has_internal_linkage (^^main));
+static_assert (has_internal_linkage (^^ci));
+static_assert (!has_internal_linkage (^^ci2));
diff --git a/gcc/testsuite/g++.dg/reflect/has_internal_linkage2.C b/gcc/testsuite/g++.dg/reflect/has_internal_linkage2.C
new file mode 100644 (file)
index 0000000..4bfbdb7
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -fmodules" }
+// Test std::meta::has_internal_linkage.
+
+module;
+
+#include <meta>
+
+module has_internal_linkage:counter;
+
+int counter = 0;
+
+static_assert (!std::meta::has_internal_linkage (^^counter));
diff --git a/gcc/testsuite/g++.dg/reflect/has_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_linkage1.C
new file mode 100644 (file)
index 0000000..3eeb1c5
--- /dev/null
@@ -0,0 +1,149 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_linkage.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_linkage (null_reflection));
+static_assert (has_linkage (^^::));
+static_assert (has_linkage (^^ns));
+static_assert (has_linkage (^^std));
+static_assert (has_linkage (^^std::meta));
+static_assert (has_linkage (^^ns_alias));
+static_assert (!has_linkage (reflect_constant (3)));
+static_assert (has_linkage (^^cls));
+static_assert (!has_linkage (^^cls::dm));
+static_assert (!has_linkage (^^cls::ref_dm));
+static_assert (has_linkage (^^cls::static_dm));
+static_assert (has_linkage (^^cls::mem_fun));
+static_assert (has_linkage (^^cls::static_mem_fun));
+static_assert (!has_linkage (^^cls::type));
+static_assert (has_linkage (^^cls_var));
+static_assert (has_linkage (^^onion));
+static_assert (!has_linkage (^^anon));
+static_assert (has_linkage (^^fun));
+static_assert (!has_linkage (^^alias));
+static_assert (has_linkage (^^var));
+static_assert (has_linkage (^^ref));
+static_assert (has_linkage (^^rref));
+static_assert (has_linkage (^^ptr));
+static_assert (has_linkage (^^cls_tmpl));
+static_assert (has_linkage (^^cls_tmpl<int>));
+static_assert (has_linkage (^^incomplete_cls<int>));
+static_assert (has_linkage (^^fun_tmpl));
+static_assert (has_linkage (^^fun_tmpl<int>));
+static_assert (has_linkage (^^conc));
+static_assert (!has_linkage (substitute (^^conc, { ^^int })));
+static_assert (has_linkage (^^var_tmpl));
+static_assert (has_linkage (^^var_tmpl<int>));
+static_assert (!has_linkage (^^cls_tmpl_alias));
+static_assert (!has_linkage (^^cls_tmpl_alias<int>));
+static_assert (has_linkage (^^Enum));
+static_assert (!has_linkage (^^Enum::A));
+static_assert (has_linkage (^^Enum_class));
+static_assert (!has_linkage (^^Enum_class::A));
+static_assert (!has_linkage (^^decomp));
+static_assert (!has_linkage (^^decomp_ref));
+static_assert (has_linkage (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_linkage (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_linkage (^^T));
+  static_assert (has_linkage (R));
+  static_assert (has_linkage (R2));
+  static_assert (has_linkage (R3));
+}
+
+void
+g (int p, cls c)
+{
+  int v;
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!has_linkage (^^p));
+  static_assert (!has_linkage (^^c));
+  static_assert (!has_linkage (^^v));
+}
+
+static int var2;
+static int baz () { return 0; }
+
+static_assert (has_linkage (^^var2));
+static_assert (has_linkage (^^baz));
+
+namespace {
+  void qux () {}
+  int var3;
+  namespace NN {
+    int var4;
+  }
+  struct S2 {};
+}
+
+namespace NM {
+  int var5;
+  struct S3 {};
+}
+
+extern "C" {
+  void corge (int);
+}
+
+int
+main ()
+{
+}
+
+const int ci = 42;
+extern const int ci2 = 42;
+
+static_assert (has_linkage (^^qux));
+static_assert (has_linkage (^^var3));
+static_assert (has_linkage (^^NN));
+static_assert (has_linkage (^^NN::var4));
+static_assert (has_linkage (^^NM::var5));
+static_assert (has_linkage (^^S2));
+static_assert (has_linkage (^^NM::S3));
+static_assert (has_linkage (^^corge));
+static_assert (has_linkage (^^main));
+static_assert (has_linkage (^^ci));
+static_assert (has_linkage (^^ci2));
diff --git a/gcc/testsuite/g++.dg/reflect/has_module_linkage1.C b/gcc/testsuite/g++.dg/reflect/has_module_linkage1.C
new file mode 100644 (file)
index 0000000..bc8887d
--- /dev/null
@@ -0,0 +1,149 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -fmodules" }
+// Test std::meta::has_module_linkage.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_module_linkage (null_reflection));
+static_assert (!has_module_linkage (^^::));
+static_assert (!has_module_linkage (^^ns));
+static_assert (!has_module_linkage (^^std));
+static_assert (!has_module_linkage (^^std::meta));
+static_assert (!has_module_linkage (^^ns_alias));
+static_assert (!has_module_linkage (reflect_constant (3)));
+static_assert (!has_module_linkage (^^cls));
+static_assert (!has_module_linkage (^^cls::dm));
+static_assert (!has_module_linkage (^^cls::ref_dm));
+static_assert (!has_module_linkage (^^cls::static_dm));
+static_assert (!has_module_linkage (^^cls::mem_fun));
+static_assert (!has_module_linkage (^^cls::static_mem_fun));
+static_assert (!has_module_linkage (^^cls::type));
+static_assert (!has_module_linkage (^^cls_var));
+static_assert (!has_module_linkage (^^onion));
+static_assert (!has_module_linkage (^^anon));
+static_assert (!has_module_linkage (^^fun));
+static_assert (!has_module_linkage (^^alias));
+static_assert (!has_module_linkage (^^var));
+static_assert (!has_module_linkage (^^ref));
+static_assert (!has_module_linkage (^^rref));
+static_assert (!has_module_linkage (^^ptr));
+static_assert (!has_module_linkage (^^cls_tmpl));
+static_assert (!has_module_linkage (^^cls_tmpl<int>));
+static_assert (!has_module_linkage (^^incomplete_cls<int>));
+static_assert (!has_module_linkage (^^fun_tmpl));
+static_assert (!has_module_linkage (^^fun_tmpl<int>));
+static_assert (!has_module_linkage (^^conc));
+static_assert (!has_module_linkage (substitute (^^conc, { ^^int })));
+static_assert (!has_module_linkage (^^var_tmpl));
+static_assert (!has_module_linkage (^^var_tmpl<int>));
+static_assert (!has_module_linkage (^^cls_tmpl_alias));
+static_assert (!has_module_linkage (^^cls_tmpl_alias<int>));
+static_assert (!has_module_linkage (^^Enum));
+static_assert (!has_module_linkage (^^Enum::A));
+static_assert (!has_module_linkage (^^Enum_class));
+static_assert (!has_module_linkage (^^Enum_class::A));
+static_assert (!has_module_linkage (^^decomp));
+static_assert (!has_module_linkage (^^decomp_ref));
+static_assert (!has_module_linkage (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_module_linkage (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_module_linkage (^^T));
+  static_assert (!has_module_linkage (R));
+  static_assert (!has_module_linkage (R2));
+  static_assert (!has_module_linkage (R3));
+}
+
+void
+g (int p, cls c)
+{
+  int v;
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!has_module_linkage (^^p));
+  static_assert (!has_module_linkage (^^c));
+  static_assert (!has_module_linkage (^^v));
+}
+
+static int var2;
+static int baz () { return 0; }
+
+static_assert (!has_module_linkage (^^var2));
+static_assert (!has_module_linkage (^^baz));
+
+namespace {
+  void qux () {}
+  int var3;
+  namespace NN {
+    int var4;
+  }
+  struct S2 {};
+}
+
+namespace NM {
+  int var5;
+  struct S3 {};
+}
+
+extern "C" {
+  void corge (int);
+}
+
+int
+main ()
+{
+}
+
+const int ci = 42;
+extern const int ci2 = 42;
+
+static_assert (!has_module_linkage (^^qux));
+static_assert (!has_module_linkage (^^var3));
+static_assert (!has_module_linkage (^^NN));
+static_assert (!has_module_linkage (^^NN::var4));
+static_assert (!has_module_linkage (^^NM::var5));
+static_assert (!has_module_linkage (^^S2));
+static_assert (!has_module_linkage (^^NM::S3));
+static_assert (!has_module_linkage (^^corge));
+static_assert (!has_module_linkage (^^main));
+static_assert (!has_module_linkage (^^ci));
+static_assert (!has_module_linkage (^^ci2));
diff --git a/gcc/testsuite/g++.dg/reflect/has_module_linkage2.C b/gcc/testsuite/g++.dg/reflect/has_module_linkage2.C
new file mode 100644 (file)
index 0000000..fe0d14a
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -fmodules" }
+// Test std::meta::has_module_linkage.
+
+module;
+
+#include <meta>
+
+module has_module_linkage:counter;
+
+int counter = 0;
+
+static_assert (std::meta::has_module_linkage (^^counter));
diff --git a/gcc/testsuite/g++.dg/reflect/has_parent1.C b/gcc/testsuite/g++.dg/reflect/has_parent1.C
new file mode 100644 (file)
index 0000000..8d5dd73
--- /dev/null
@@ -0,0 +1,138 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_parent.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_parent (null_reflection));
+static_assert (!has_parent (^^::));
+static_assert (has_parent (^^ns));
+static_assert (has_parent (^^ns_alias));
+static_assert (!has_parent (reflect_constant (3)));
+static_assert (has_parent (^^cls));
+static_assert (has_parent (^^cls::dm));
+static_assert (has_parent (^^cls::ref_dm));
+static_assert (has_parent (^^cls::static_dm));
+static_assert (has_parent (^^cls::mem_fun));
+static_assert (has_parent (^^cls::static_mem_fun));
+static_assert (has_parent (^^cls::type));
+static_assert (has_parent (^^cls_var));
+static_assert (has_parent (^^onion));
+static_assert (has_parent (^^anon));
+static_assert (has_parent (^^fun));
+static_assert (has_parent (^^alias));
+static_assert (has_parent (^^var));
+static_assert (has_parent (^^ref));
+static_assert (has_parent (^^rref));
+static_assert (has_parent (^^ptr));
+static_assert (has_parent (^^cls_tmpl));
+static_assert (has_parent (^^cls_tmpl<int>));
+static_assert (has_parent (^^incomplete_cls<int>));
+static_assert (has_parent (^^fun_tmpl));
+static_assert (has_parent (^^fun_tmpl<int>));
+static_assert (has_parent (^^conc));
+static_assert (!has_parent (substitute (^^conc, { ^^int })));
+static_assert (has_parent (^^var_tmpl));
+static_assert (has_parent (^^var_tmpl<int>));
+static_assert (has_parent (^^cls_tmpl_alias));
+static_assert (has_parent (^^cls_tmpl_alias<int>));
+static_assert (has_parent (^^Enum));
+static_assert (has_parent (^^Enum::A));
+static_assert (has_parent (^^Enum_class));
+static_assert (has_parent (^^Enum_class::A));
+static_assert (has_parent (^^decomp));
+static_assert (has_parent (^^decomp_ref));
+static_assert (has_parent (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_parent (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (has_parent (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_parent (^^T));
+  static_assert (has_parent (R));
+  static_assert (has_parent (R2));
+  static_assert (has_parent (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (has_parent (^^p));
+  static_assert (has_parent (^^c));
+  static_assert (has_parent (parameters_of (^^g)[0]));
+}
+
+int
+main ()
+{
+}
+
+namespace N
+{
+  extern "C" void foo (int);
+  void baz (int);
+}
+extern "C" void bar ();
+
+static_assert (!has_parent (^^main));
+static_assert (!has_parent (^^N::foo));
+static_assert (!has_parent (^^bar));
+static_assert (has_parent (^^N::baz));
+
+enum F {
+  F1,
+  F2 = has_parent (^^F1),
+  F3 = has_parent (^^F2) + 1,
+};
+static_assert (F2 == 1 && F3 == 2);
+
+void
+qux ()
+{
+  auto a = [] () { int b; static_assert (has_parent (^^b)); };
+  static_assert (has_parent (^^a));
+  static_assert (has_parent (type_of (^^a)));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/has_template_arguments1.C b/gcc/testsuite/g++.dg/reflect/has_template_arguments1.C
new file mode 100644 (file)
index 0000000..0062f0f
--- /dev/null
@@ -0,0 +1,111 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_template_arguments.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+using U = cls_tmpl<int>;
+typedef cls_tmpl<int> TYPE;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_template_arguments (^^int));
+static_assert (!has_template_arguments (null_reflection));
+static_assert (!has_template_arguments (^^::));
+static_assert (!has_template_arguments (^^ns));
+static_assert (!has_template_arguments (^^ns_alias));
+static_assert (!has_template_arguments (reflect_constant (3)));
+static_assert (!has_template_arguments (^^cls));
+static_assert (!has_template_arguments (^^cls::dm));
+static_assert (!has_template_arguments (^^cls::ref_dm));
+static_assert (!has_template_arguments (^^cls::static_dm));
+static_assert (!has_template_arguments (^^cls::mem_fun));
+static_assert (!has_template_arguments (^^cls::static_mem_fun));
+static_assert (!has_template_arguments (^^cls::type));
+static_assert (!has_template_arguments (^^cls_var));
+static_assert (!has_template_arguments (^^onion));
+static_assert (!has_template_arguments (^^anon));
+static_assert (!has_template_arguments (^^fun));
+static_assert (!has_template_arguments (^^alias));
+static_assert (!has_template_arguments (^^var));
+static_assert (!has_template_arguments (^^ref));
+static_assert (!has_template_arguments (^^rref));
+static_assert (!has_template_arguments (^^ptr));
+static_assert (!has_template_arguments (^^cls_tmpl));
+static_assert (has_template_arguments (^^cls_tmpl<int>));
+static_assert (has_template_arguments (^^incomplete_cls<int>));
+static_assert (!has_template_arguments (^^fun_tmpl));
+static_assert (has_template_arguments (^^fun_tmpl<int>));
+static_assert (!has_template_arguments (^^conc));
+static_assert (!has_template_arguments (substitute (^^conc, { ^^int })));
+static_assert (!has_template_arguments (^^var_tmpl));
+static_assert (has_template_arguments (^^var_tmpl<int>));
+static_assert (!has_template_arguments (^^cls_tmpl_alias));
+static_assert (has_template_arguments (^^cls_tmpl_alias<int>));
+static_assert (!has_template_arguments (^^Enum));
+static_assert (!has_template_arguments (^^Enum::A));
+static_assert (!has_template_arguments (^^Enum_class));
+static_assert (!has_template_arguments (^^Enum_class::A));
+static_assert (!has_template_arguments (^^decomp));
+static_assert (!has_template_arguments (^^decomp_ref));
+static_assert (!has_template_arguments (^^arr));
+static_assert (!has_template_arguments (^^U));
+static_assert (!has_template_arguments (^^TYPE));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_template_arguments (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!has_template_arguments (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_template_arguments (^^T));
+  static_assert (!has_template_arguments (R));
+  static_assert (has_template_arguments (R2));
+  static_assert (has_template_arguments (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^var_tmpl<int>, ^^cls_tmpl<int>>();
+  static_assert (!has_template_arguments (^^p));
+  static_assert (!has_template_arguments (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/has_template_arguments2.C b/gcc/testsuite/g++.dg/reflect/has_template_arguments2.C
new file mode 100644 (file)
index 0000000..db22eb4
--- /dev/null
@@ -0,0 +1,75 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_template_arguments.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template <typename P1, auto P2, template <typename...> class P3>
+struct class_tmpl {
+  template <typename> struct inner {};
+};
+static_assert (!has_template_arguments (^^class_tmpl));
+static_assert (has_template_arguments (^^class_tmpl<int, 9, std::vector>));
+
+template <typename P1, auto P2, template <typename...> class P3>
+void fn_tmpl ();
+static_assert (!has_template_arguments (^^fn_tmpl));
+static_assert (has_template_arguments (^^fn_tmpl<int, 9, std::vector>));
+
+template <typename P1, auto P2, template <typename...> class P3>
+int var_tmpl = 0;
+static_assert (!has_template_arguments (^^var_tmpl));
+static_assert (has_template_arguments (^^var_tmpl<int, 9, std::vector>));
+
+template <typename P1, auto P2, template <typename...> class P3>
+using alias = int;
+static_assert (!has_template_arguments (^^alias));
+static_assert (has_template_arguments (^^alias<int, 9, std::vector>));
+
+template <typename T>
+using dep_alias = class_tmpl<int, 9, std::vector>::template inner<T>;
+static_assert (!has_template_arguments (^^dep_alias));
+static_assert (has_template_arguments (^^dep_alias<int>));
+
+struct Der : class_tmpl<int, 9, std::vector> {};
+static_assert (!has_template_arguments (^^Der));
+
+template <typename T, T> struct A {};
+static_assert (!has_template_arguments (^^A));
+static_assert (has_template_arguments (^^A<int, 5>));
+
+template <typename... Ts> struct B {};
+static_assert (!has_template_arguments (^^B));
+static_assert (has_template_arguments (^^B<int, bool>));
+
+struct S {
+  int mem;
+  bool operator==(const S&) const = default;
+};
+template <auto... Vs> struct auto_pack {};
+static_assert (!has_template_arguments (^^auto_pack));
+static_assert (has_template_arguments (^^auto_pack<4, S{3}>));
+
+template <float> struct float_targ {};
+constexpr float F = 4.5f;
+static_assert (!has_template_arguments (^^float_targ));
+static_assert (has_template_arguments (^^float_targ<F>));
+
+template <const float *> struct ptr_targ {};
+constexpr float Fs[] = {4.5, 5.5, 6.5};
+static_assert (!has_template_arguments (^^ptr_targ));
+static_assert (has_template_arguments (^^ptr_targ<Fs>));
+static_assert (has_template_arguments (^^ptr_targ<nullptr>));
+
+template <const int &> struct ref_targ {};
+const int I = 5;
+using T = ref_targ<I>;
+static_assert (!has_template_arguments (^^ref_targ));
+static_assert (has_template_arguments (dealias(^^T)));
+
+template <std::meta::info> struct refl_targ {};
+static_assert (!has_template_arguments (^^refl_targ));
+static_assert (has_template_arguments (^^refl_targ<^^int>));
diff --git a/gcc/testsuite/g++.dg/reflect/has_template_arguments3.C b/gcc/testsuite/g++.dg/reflect/has_template_arguments3.C
new file mode 100644 (file)
index 0000000..c36027e
--- /dev/null
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_template_arguments.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+struct S {
+  template<typename T>
+  struct N { };
+};
+
+template<typename T>
+struct TS {
+  template<typename U>
+  struct N { };
+};
+
+static_assert (!has_template_arguments (^^S::N));
+static_assert (has_template_arguments (^^S::N<int>));
+static_assert (!has_template_arguments (^^TS<int>::N));
+static_assert (has_template_arguments (^^TS<int>::N<int>));
+
+template<typename T>
+struct A { };
+
+template<typename T>
+struct A<T*> { };
+
+template<>
+struct A<int> { };
+
+static_assert (!has_template_arguments (^^A));
+static_assert (has_template_arguments (^^A<int>));
+static_assert (has_template_arguments (^^A<int *>));
+
+template<typename = int>
+struct B { };
+static_assert (has_template_arguments (^^B<>));
+
+struct C {
+  using Alias = A<int>;
+};
+
+static_assert (has_template_arguments (dealias (^^C::Alias)));
+static_assert (!has_template_arguments (^^C::Alias));
diff --git a/gcc/testsuite/g++.dg/reflect/has_template_arguments4.C b/gcc/testsuite/g++.dg/reflect/has_template_arguments4.C
new file mode 100644 (file)
index 0000000..42f1461
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_template_arguments.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  template<typename T>
+  void fn (T) { }
+};
+
+template<typename T>
+struct TS {
+  template<typename U>
+  void fn (T) { }
+};
+
+static_assert (!has_template_arguments (^^S::fn));
+static_assert (has_template_arguments (^^S::fn<int>));
+static_assert (!has_template_arguments (^^TS<int>::fn));
+static_assert (has_template_arguments (^^TS<int>::fn<int>));
diff --git a/gcc/testsuite/g++.dg/reflect/identifier_of1.C b/gcc/testsuite/g++.dg/reflect/identifier_of1.C
new file mode 100644 (file)
index 0000000..c51d864
--- /dev/null
@@ -0,0 +1,181 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::identifier_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct C { };
+
+constexpr std::string_view sv = identifier_of (^^C);
+static_assert (sv == "C");
+static_assert (sv.data ()[0] == 'C');
+static_assert (sv.data ()[1] == '\0');
+
+struct S { };
+using T = int;
+using U = S;
+enum E { E1, E2 };
+enum { E3, E4 };
+typedef enum { E5, E6 } E7;
+
+static_assert (identifier_of (^^T) == std::string_view ("T"));
+static_assert (identifier_of (^^S) == std::string_view ("S"));
+static_assert (identifier_of (^^U) == std::string_view ("U"));
+static_assert (identifier_of (^^std) == std::string_view ("std"));
+static_assert (identifier_of (^^std::meta) == std::string_view ("meta"));
+static_assert (identifier_of (^^E1) == std::string_view ("E1"));
+static_assert (identifier_of (^^E) == std::string_view ("E"));
+static_assert (identifier_of (parent_of (^^E5)) == std::string_view ("E7"));
+static_assert (identifier_of (^^E7) == std::string_view ("E7"));
+static_assert (identifier_of (dealias (^^E7)) == std::string_view ("E7"));
+static_assert (identifier_of (data_member_spec (^^long, { .name = "foo", .bit_width = 6 })) == std::string_view ("foo"));
+static_assert (identifier_of (data_member_spec (^^long, { .name = "extremely_long_string_used_as_identifier" })) == std::string_view ("extremely_long_string_used_as_identifier"));
+
+namespace N {}
+namespace NA = N;
+static_assert (identifier_of (^^N) == std::string_view ("N"));
+static_assert (identifier_of (^^NA) == std::string_view ("NA"));
+
+namespace {
+  int a;
+  namespace M {}
+  static_assert (identifier_of (^^a) == std::string_view ("a"));
+  static_assert (identifier_of (^^M) == std::string_view ("M"));
+}
+
+typedef struct {
+  int a;
+  static_assert (identifier_of (^^a) == std::string_view ("a"));
+} SV;
+static_assert (identifier_of (^^SV) == std::string_view ("SV"));
+static_assert (identifier_of (parent_of (^^SV::a)) == std::string_view ("SV"));
+static_assert (identifier_of (dealias (^^SV)) == std::string_view ("SV"));
+
+template <int N>
+struct ST
+{
+  static_assert (identifier_of (^^ST) == std::string_view ("ST"));
+};
+static_assert (identifier_of (^^ST) == std::string_view ("ST"));
+
+struct V
+{
+  void foo () { int a; static_assert (identifier_of (parent_of (^^a)) == std::string_view ("foo")); }
+  template <int N>
+  void bar () { int a; static_assert (identifier_of (parent_of (^^a)) == std::string_view ("bar")); }
+};
+static_assert (identifier_of (^^V::foo) == std::string_view ("foo"));
+static_assert (identifier_of (^^V::bar) == std::string_view ("bar"));
+
+int
+operator ""_a (const char *)
+{
+  int a;
+  static_assert (identifier_of (parent_of (^^a)) == std::string_view ("_a"));
+  return 0;
+}
+
+int v;
+static_assert (identifier_of (^^v) == std::string_view ("v"));
+template<typename T>
+T vtempl;
+static_assert (identifier_of (^^vtempl) == std::string_view ("vtempl"));
+
+void foo (int);
+static_assert (identifier_of (^^foo) == std::string_view ("foo"));
+
+int arr[3];
+
+void
+foo (int a)
+{
+  auto [b, c, d] = arr;
+  static_assert (identifier_of (^^foo) == std::string_view ("foo"));
+  static_assert (identifier_of (^^a) == std::string_view ("a"));
+  static_assert (identifier_of (^^b) == std::string_view ("b"));
+  static_assert (identifier_of (^^c) == std::string_view ("c"));
+  static_assert (identifier_of (^^d) == std::string_view ("d"));
+}
+
+template <int N>
+void
+bar (int a)
+{
+  auto [...b, c] = arr;
+  static_assert (identifier_of (^^a) == std::string_view ("a"));
+  static_assert (identifier_of (^^c) == std::string_view ("c"));
+}
+static_assert (identifier_of (^^bar) == std::string_view ("bar"));
+
+void
+baz ()
+{
+  auto a = [] {
+    int a;
+    static_assert (identifier_of (^^a) == std::string_view ("a"));
+    static_assert (identifier_of (parent_of (parent_of (parent_of (^^a)))) == std::string_view ("baz"));
+  };
+  using t = decltype (a);
+  static_assert (identifier_of (^^t) == std::string_view ("t"));
+}
+
+void qux (int, int b, int c, int d, int);
+constexpr auto p0 = parameters_of (^^qux)[0];
+constexpr auto p1 = parameters_of (^^qux)[1];
+constexpr auto p2 = parameters_of (^^qux)[2];
+constexpr auto p3 = parameters_of (^^qux)[3];
+constexpr auto p4 = parameters_of (^^qux)[4];
+static_assert (identifier_of (p1) == std::string_view ("b"));
+static_assert (identifier_of (p2) == std::string_view ("c"));
+static_assert (identifier_of (p3) == std::string_view ("d"));
+void qux (int a, int, int c, int e, int);
+static_assert (identifier_of (p0) == std::string_view ("a"));
+static_assert (identifier_of (p1) == std::string_view ("b"));
+static_assert (identifier_of (p2) == std::string_view ("c"));
+
+void
+qux (int a, int, int, int e, int)
+{
+  static_assert (identifier_of (p0) == std::string_view ("a"));
+  static_assert (identifier_of (p1) == std::string_view ("b"));
+  static_assert (identifier_of (p2) == std::string_view ("c"));
+  static_assert (identifier_of (variable_of (p0)) == std::string_view ("a"));
+  static_assert (identifier_of (variable_of (p3)) == std::string_view ("e"));
+}
+
+void qux (int f, int, int, int, int g);
+static_assert (identifier_of (p1) == std::string_view ("b"));
+static_assert (identifier_of (p2) == std::string_view ("c"));
+static_assert (identifier_of (p4) == std::string_view ("g"));
+
+template <typename... T>
+void
+freddy (int a, T... b)
+{
+}
+
+static_assert (identifier_of (parameters_of (^^freddy <int, long, char>)[0]) == std::string_view ("a"));
+
+struct {
+  int a;
+} s;
+
+static_assert (identifier_of (^^s) == std::string_view ("s"));
+
+typedef struct {
+  int b;
+} TN;
+
+static_assert (identifier_of (parent_of (^^TN::b)) == std::string_view ("TN"));
+static_assert (identifier_of (^^TN) == std::string_view ("TN"));
+static_assert (identifier_of (dealias (^^TN)) == std::string_view ("TN"));
+
+typedef enum {
+  E8,
+  E9
+} E10;
+static_assert (identifier_of (parent_of (^^E8)) == std::string_view ("E10"));
+static_assert (identifier_of (^^E10) == std::string_view ("E10"));
+static_assert (identifier_of (dealias (^^E10)) == std::string_view ("E10"));
diff --git a/gcc/testsuite/g++.dg/reflect/identifier_of2.C b/gcc/testsuite/g++.dg/reflect/identifier_of2.C
new file mode 100644 (file)
index 0000000..115382f
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-freflection -fexec-charset=IBM1047" }
+// Test std::meta::identifier_of.
+
+#include "identifier_of1.C"
diff --git a/gcc/testsuite/g++.dg/reflect/init1.C b/gcc/testsuite/g++.dg/reflect/init1.C
new file mode 100644 (file)
index 0000000..7de12a4
--- /dev/null
@@ -0,0 +1,59 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test various forms of initialization with reflections.
+
+#include <initializer_list>
+
+using info = decltype(^^int);
+
+struct S { int i; };
+struct X {
+  consteval operator info() { return ^^int; }
+};
+
+struct Y {
+  info i = ^^int;
+};
+
+constexpr Y y;
+
+struct W {
+  consteval W() { }
+  decltype(^^::) i = ^^W::i;
+};
+
+constinit info r = ^^int;
+constinit info *p = &r;
+
+consteval void
+f ()
+{
+  constexpr auto refl = ^^S;
+  auto a1 = refl;
+  auto a2(refl);
+  auto a3 = { refl };
+  auto a4{refl};
+
+  constexpr decltype(refl) arr[] = { refl };
+  constexpr auto ra = arr[0];
+  typename [: ra :] s = { .i = 42 };
+
+  constexpr static auto srefl = ^^S;
+  constexpr static auto *p = &srefl;
+  constexpr auto *const *q = &p;
+  typename [: **q :] s2 = { .i = 42 };
+}
+
+void
+g ()
+{
+  f ();
+}
+
+void
+h ()
+{
+  X x;
+  typename [: x :] i = 42;
+  typename [: X{} :] j = i;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init10.C b/gcc/testsuite/g++.dg/reflect/init10.C
new file mode 100644 (file)
index 0000000..115c3ee
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test member list initializers.
+
+using info = decltype(^^int);
+
+struct A {
+  info i;
+  consteval A() : i{^^void} {}
+};
+
+A a1;  // { dg-error "consteval-only variable .a1." }
+constinit A a2;
+constexpr A a3;
+
+struct B {
+ info i;
+ info j;
+ consteval B() : i{}, j{i} {}
+};
+
+B b1;  // { dg-error "consteval-only variable .b1." }
+constinit B b2;
+constexpr B b3;
diff --git a/gcc/testsuite/g++.dg/reflect/init11.C b/gcc/testsuite/g++.dg/reflect/init11.C
new file mode 100644 (file)
index 0000000..7173023
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test invalid reflections in member init lists.
+
+using info = decltype(^^void);
+
+struct A {
+  info i;
+  constexpr A() : i{^^void} {}  // { dg-error "consteval-only" }
+};
+
+struct B {
+  info i;
+  B() : i{^^void} {}  // { dg-error "consteval-only" }
+};
+
+struct C {
+  info i;
+  constexpr C() : i{} {}  // { dg-error "function of consteval-only type must be declared .consteval." }
+};
+
+struct D {
+  info i;
+  D() : i{} {}  // { dg-error "function of consteval-only type must be declared .consteval." }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/init12.C b/gcc/testsuite/g++.dg/reflect/init12.C
new file mode 100644 (file)
index 0000000..8ec456d
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test consteval-only type smuggling.
+
+using info = decltype(^^int);
+
+template<typename T>
+constexpr const void *
+foo (const T *__location)
+{
+  const void *__loc = __location;
+  return __loc;
+}
+
+template<typename T>
+constexpr const void *
+bar (const T *__location)
+{
+  const void *__loc = __location;
+  return __loc;
+}
+
+void
+g ()
+{
+  constexpr static auto r = ^^int;
+  constexpr auto x = foo<info>(&r); // { dg-error "pointer into an object of consteval-only type" }
+  constexpr auto y = bar<info>(nullptr);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init13.C b/gcc/testsuite/g++.dg/reflect/init13.C
new file mode 100644 (file)
index 0000000..6b9277a
--- /dev/null
@@ -0,0 +1,55 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+constexpr info A {};
+constexpr info B = ^^::;
+inline constexpr info C = ^^::;
+
+template<typename T>
+struct S {
+  static constexpr info B {^^T};
+
+  void wow () {
+    constexpr info D {^^T};
+  }
+};
+
+consteval void
+foo ()
+{
+  info A = ^^::;
+  constexpr info B = ^^::;
+}
+
+constexpr void
+bar ()
+{
+  constexpr info A = ^^::;
+  static constexpr info B = ^^::;
+}
+
+constexpr void
+tux ()
+{
+  if consteval {
+    constexpr info A = ^^::;
+    static constexpr info B = ^^::;
+  }
+}
+
+void
+qux ()
+{
+  constexpr info A {};
+  constexpr info B = ^^::;
+  static constexpr info C = ^^::;
+  foo ();
+  consteval { bar (); }
+  consteval { tux (); }
+  tux ();
+  bar ();
+}
+
+template struct S<int>;
diff --git a/gcc/testsuite/g++.dg/reflect/init14.C b/gcc/testsuite/g++.dg/reflect/init14.C
new file mode 100644 (file)
index 0000000..e0e95d4
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<typename T>
+struct S {
+  static constexpr auto s = ^^T;
+  void foo () { constexpr auto s = ^^T; }
+};
+template struct S<int>;
+
+constexpr void
+bud ()
+{
+  if consteval { static constexpr auto a = ^^::; }
+}
+auto bar () { return &bud; }
diff --git a/gcc/testsuite/g++.dg/reflect/init15.C b/gcc/testsuite/g++.dg/reflect/init15.C
new file mode 100644 (file)
index 0000000..1e98363
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+consteval info identity(info i) { return i; }
+consteval int something_of(info) { return 10; }
+consteval void do_something(info) {}
+
+void fox() {
+  if not consteval {
+    constexpr info X {};
+    constexpr info A = ^^::;
+    constexpr info B = identity(A);
+    static constexpr info D = ^^::;
+
+    static_assert(X == info{});
+    static_assert(A == ^^::);
+    static_assert(B == ^^::);
+    static_assert(D == ^^::);
+
+    consteval {
+      do_something(X);
+      do_something(A);
+      int H = something_of(A);
+      constexpr int I = something_of(A);
+    }
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init16.C b/gcc/testsuite/g++.dg/reflect/init16.C
new file mode 100644 (file)
index 0000000..621b1c5
--- /dev/null
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+consteval info identity(info i) {
+    return i;
+}
+
+consteval int something_of(info) {
+    return 10;
+}
+
+consteval void do_something(info) {}
+
+template <info>
+void do_something_runtime() {}
+
+void fox() {
+    if not consteval {
+        constexpr info X {};
+        constexpr info A = ^^::;
+        constexpr info B = identity(A);
+        static constexpr info D = ^^::;
+
+        static_assert(X == info{});
+        static_assert(A == ^^::);
+        static_assert(B == ^^::);
+        static_assert(D == ^^::);
+
+        consteval {
+            do_something(X);
+            do_something(A);
+            int H = something_of(A);
+            constexpr int I = something_of(A);
+        }
+
+        do_something(X);
+        do_something(A);
+        do_something_runtime<X>();
+        do_something_runtime<A>();
+        int C = something_of(A);
+        constexpr int E = something_of(A);
+        identity(A); // { dg-error "consteval-only expressions" }
+        identity(B); // { dg-error "consteval-only expressions" }
+    }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init17.C b/gcc/testsuite/g++.dg/reflect/init17.C
new file mode 100644 (file)
index 0000000..c0bb11e
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+consteval int
+foo (info i)
+{
+  return 42;
+}
+
+consteval info
+bar ()
+{
+  return __extension__ ({ constexpr auto a = ^^int; a; });
+}
+
+struct S {
+  info i;
+};
+
+void
+g ()
+{
+  __extension__ constexpr int i = foo (({ constexpr auto a = ^^int; a; }));
+  __extension__ static constexpr info r = ({ constexpr auto a = ^^int; a; });
+  constexpr info o = bar ();
+  __extension__ constexpr auto sz = sizeof (({ constexpr auto a = ^^int; a; }));
+  __extension__ constexpr S s{({ constexpr auto a = ^^int; a; })};
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init2.C b/gcc/testsuite/g++.dg/reflect/init2.C
new file mode 100644 (file)
index 0000000..4c248fd
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test various forms of initialization with reflections.  Invalid.
+
+consteval void
+f ()
+{
+  constexpr static auto srefl = ^^int;
+  constexpr auto *p = &srefl;
+  constexpr auto **q = &p;  // { dg-error "unable to deduce" }
+  // { dg-message "types .auto\\*. and .std::meta::info\\* const." "" { target *-*-* } .-1 }
+}
+
+void
+g ()
+{
+  f ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init3.C b/gcc/testsuite/g++.dg/reflect/init3.C
new file mode 100644 (file)
index 0000000..d531360
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template <auto R = ^^::> class S {};
+S s;
+
+template <auto R = ^^int> class S2 {};
+S2 s2;
diff --git a/gcc/testsuite/g++.dg/reflect/init4.C b/gcc/testsuite/g++.dg/reflect/init4.C
new file mode 100644 (file)
index 0000000..6d9a39b
--- /dev/null
@@ -0,0 +1,63 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that we properly detect compounded consteval-only types.
+
+using info = decltype(^^int);
+constexpr static info glob = ^^::;
+constexpr info array[3] = { glob, glob, glob };
+consteval info foo () { return ^^::; }
+
+struct A {
+  info i = ^^int;
+};
+constexpr A a;
+
+struct B {
+  A a;
+};
+constexpr B b;
+
+struct C {
+  const info *i = &glob;
+};
+constexpr C c;
+
+struct D {
+  int i;
+  C c;
+  consteval D() : c{}, i{42} { }
+};
+constexpr D d;
+
+struct E {
+  info arr[2];
+  consteval E() : arr{glob, glob} { }
+};
+constexpr E e;
+
+struct F {
+  const info &r;
+  consteval F() : r{glob} { }
+};
+constexpr F f;
+
+struct G {
+  B b;
+};
+constexpr G g;
+
+struct H {
+  info (*fp)();
+};
+constexpr H h{foo}; // { dg-error "address of immediate function" }
+
+union U {
+  int n;
+  info i;
+};
+constexpr U u{.i = glob };
+
+struct I {
+  info i;
+};
+constexpr info I::*pmi = &I::i;
diff --git a/gcc/testsuite/g++.dg/reflect/init5.C b/gcc/testsuite/g++.dg/reflect/init5.C
new file mode 100644 (file)
index 0000000..dd9f07b
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+struct Base { };
+struct Derived : Base {
+  info k;
+  consteval Derived() : Base(), k(^^int) {}
+};
+consteval const Base &fn1() {
+  static constexpr Derived d;
+  return d;
+}
+constexpr auto &ref = fn1(); // { dg-error "reference into an object of consteval-only type" }
+
+consteval void *fn2() {
+  static constexpr auto v = ^^int;
+  return (void *)&v;
+}
+constexpr const void *ptr = fn2(); // { dg-error "pointer into an object of consteval-only type" }
diff --git a/gcc/testsuite/g++.dg/reflect/init6.C b/gcc/testsuite/g++.dg/reflect/init6.C
new file mode 100644 (file)
index 0000000..3febb88
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+struct S {
+  info i;
+};
+
+struct N {
+  info i = ^^void;
+};
+
+S s1;  // { dg-error "consteval-only variable" }
+constinit S s2{};
+constexpr S s3{^^int};
+
+N n1;  // { dg-error "consteval-only variable" }
+constinit N n2;
+constexpr N n3;
+
+template<typename T>
+struct X {
+  T t;
+};
+
+X<info> x1;  // { dg-error "consteval-only variable" }
+constinit X<info> x2{};
+constexpr X<info> x3{^^int};
+
+void
+g ()
+{
+  static constexpr S s{^^void};
+  static constexpr X<info> x{^^void};
+  static constexpr N n;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init7.C b/gcc/testsuite/g++.dg/reflect/init7.C
new file mode 100644 (file)
index 0000000..3f8405b
--- /dev/null
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that we properly detect using consteval-only variables without
+// constexpr/constinit.
+
+using info = decltype(^^int);
+
+info r1 = ^^int;  // { dg-error "consteval-only variable .r1. not declared .constexpr. used outside a constant-evaluated context" }
+const info r2 = ^^int;  // { dg-error "consteval-only variable .r2. not declared .constexpr. used outside a constant-evaluated context" }
+
+constexpr info r3 = ^^int;
+constinit info r4 = ^^int;
+const info *const p1 = &r3;  // { dg-error "consteval-only variable .p1. not declared .constexpr. used outside a constant-evaluated context" }
+info *p2;  // { dg-error "consteval-only variable .p2. not declared .constexpr. used outside a constant-evaluated context" }
+const info &q = r3;  // { dg-error "consteval-only variable .q. not declared .constexpr. used outside a constant-evaluated context" }
+
+void
+g ()
+{
+  info l1 = ^^int;  // { dg-error "consteval-only variable .l1. not declared .constexpr. used outside a constant-evaluated context" }
+  const info l2 = ^^int;  // { dg-error "consteval-only variable .l2. not declared .constexpr. used outside a constant-evaluated context" }
+  constexpr info l3 = ^^int;
+  static info l4 = ^^int;  // { dg-error "consteval-only variable .l4. not declared .constexpr. used outside a constant-evaluated context" }
+  static const info l5 = ^^int;  // { dg-error "consteval-only variable .l5. not declared .constexpr. used outside a constant-evaluated context" }
+  static constexpr info l6 = ^^int;
+  static constinit info l7 = ^^int;
+}
+
+consteval void
+f ()
+{
+  info l1 = ^^int;
+  const info l2 = ^^int;
+  constexpr info l3 = ^^int;
+  // Are these really OK?  Only if we don't call this function, I suppose.
+  // See error8.C for that scenario.
+  static info l4 = ^^int;
+  static const info l5 = ^^int;
+  static constexpr info l6 = ^^int;
+  static constinit info l7 = ^^int;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/init8.C b/gcc/testsuite/g++.dg/reflect/init8.C
new file mode 100644 (file)
index 0000000..b044c5b
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test member list initializers.
+
+using info = decltype(^^int);
+
+struct A {
+  info i;
+  consteval A() : i{^^void} {}
+};
+
+static_assert (A{}.i == ^^void);
+constexpr A a;
+static_assert (a.i == ^^void);
+constexpr A a2;
+static_assert (a2.i == ^^void);
diff --git a/gcc/testsuite/g++.dg/reflect/init9.C b/gcc/testsuite/g++.dg/reflect/init9.C
new file mode 100644 (file)
index 0000000..c088a2d
--- /dev/null
@@ -0,0 +1,53 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test returning consteval-only exprs.
+
+using info = decltype(^^int);
+
+info foo (); // { dg-error "function of consteval-only type must be declared .consteval." }
+constexpr info bar (); // { dg-error "function of consteval-only type must be declared .consteval." }
+void baz (info); // { dg-error "function of consteval-only type must be declared .consteval." }
+
+consteval info
+ok1 ()
+{
+  return ^^int;
+}
+
+consteval info
+ok2 ()
+{
+  constexpr info r = ^^int;
+  return r;
+}
+
+consteval auto
+ok3 (info i)
+{
+  return i;
+}
+
+constexpr info
+bad1 () // { dg-error "function of consteval-only type must be declared .consteval." }
+{
+  return ^^int;  // { dg-error "consteval-only expressions" }
+}
+
+info
+bad2 () // { dg-error "function of consteval-only type must be declared .consteval." }
+{
+  return ^^int;  // { dg-error "consteval-only expressions" }
+}
+
+constexpr auto
+bad3 (info i) // { dg-error "function of consteval-only type must be declared .consteval." }
+{
+  return i;  // { dg-error "consteval-only expressions" }
+}
+
+template<info R>
+info
+bad4 () // { dg-error "function of consteval-only type must be declared .consteval." }
+{
+  return R;  // { dg-error "consteval-only expressions" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_accessible1.C b/gcc/testsuite/g++.dg/reflect/is_accessible1.C
new file mode 100644 (file)
index 0000000..87f12d5
--- /dev/null
@@ -0,0 +1,131 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_accessible.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+constexpr access_context gctx = access_context::current ();
+
+static_assert (is_accessible (null_reflection, gctx));
+static_assert (is_accessible (^^::, gctx));
+static_assert (is_accessible (^^ns, gctx));
+static_assert (is_accessible (^^ns_alias, gctx));
+static_assert (is_accessible (reflect_constant (3), gctx));
+static_assert (is_accessible (^^cls, gctx));
+static_assert (is_accessible (^^cls::dm, gctx));
+static_assert (is_accessible (^^cls::ref_dm, gctx));
+static_assert (is_accessible (^^cls::static_dm, gctx));
+static_assert (is_accessible (^^cls::mem_fun, gctx));
+static_assert (is_accessible (^^cls::static_mem_fun, gctx));
+static_assert (is_accessible (^^cls::type, gctx));
+static_assert (is_accessible (^^cls::E, gctx));
+static_assert (is_accessible (^^cls::B, gctx));
+static_assert (is_accessible (^^cls::C, gctx));
+static_assert (is_accessible (^^cls::D, gctx));
+static_assert (is_accessible (^^cls::F, gctx));
+static_assert (is_accessible (^^cls::F::G, gctx));
+static_assert (is_accessible (^^cls::F::H, gctx));
+static_assert (is_accessible (^^cls::S, gctx));
+static_assert (is_accessible (^^cls::U, gctx));
+static_assert (is_accessible (^^cls::foo, gctx));
+static_assert (is_accessible (^^cls::foo <0>, gctx));
+static_assert (is_accessible (^^cls::bar, gctx));
+static_assert (is_accessible (^^cls::bar <42>, gctx));
+static_assert (is_accessible (^^cls_var, gctx));
+static_assert (is_accessible (^^onion, gctx));
+static_assert (is_accessible (^^anon, gctx));
+static_assert (is_accessible (^^fun, gctx));
+static_assert (is_accessible (^^alias, gctx));
+static_assert (is_accessible (^^var, gctx));
+static_assert (is_accessible (^^ref, gctx));
+static_assert (is_accessible (^^rref, gctx));
+static_assert (is_accessible (^^ptr, gctx));
+static_assert (is_accessible (^^cls_tmpl, gctx));
+static_assert (is_accessible (^^cls_tmpl<int>, gctx));
+static_assert (is_accessible (^^incomplete_cls<int>, gctx));
+static_assert (is_accessible (^^fun_tmpl, gctx));
+static_assert (is_accessible (^^fun_tmpl<int>, gctx));
+static_assert (is_accessible (^^conc, gctx));
+static_assert (is_accessible (substitute (^^conc, { ^^int }), gctx));
+static_assert (is_accessible (^^var_tmpl, gctx));
+static_assert (is_accessible (^^var_tmpl<int>, gctx));
+static_assert (is_accessible (^^cls_tmpl_alias, gctx));
+static_assert (is_accessible (^^cls_tmpl_alias<int>, gctx));
+static_assert (is_accessible (^^Enum, gctx));
+static_assert (is_accessible (^^Enum::A, gctx));
+static_assert (is_accessible (^^Enum_class, gctx));
+static_assert (is_accessible (^^Enum_class::A, gctx));
+static_assert (is_accessible (^^decomp, gctx));
+static_assert (is_accessible (^^decomp_ref, gctx));
+static_assert (is_accessible (^^arr, gctx));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (is_accessible (dms, gctx));
+
+struct Base {};
+struct Derived : Base {};
+struct Derived2 : private Base {};
+static_assert (is_accessible (bases_of (^^Derived, gctx)[0], gctx));
+static_assert (!is_accessible (bases_of (^^Derived2, access_context::unchecked ())[0], gctx));
+
+void
+foo (int x)
+{
+  static_assert (is_accessible (^^x, gctx));
+  static_assert (is_accessible (parameters_of (^^foo)[0], gctx));
+  int v;
+  static_assert (is_accessible (^^v, gctx));
+  struct S {};
+  enum E { F, G };
+  static_assert (is_accessible (^^S, gctx));
+  static_assert (is_accessible (^^E, gctx));
+  static_assert (is_accessible (^^F, gctx));
+  static_assert (is_accessible (^^G, gctx));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_accessible2.C b/gcc/testsuite/g++.dg/reflect/is_accessible2.C
new file mode 100644 (file)
index 0000000..8e69c18
--- /dev/null
@@ -0,0 +1,470 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_accessible.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+
+struct D : A, protected B, private C {
+  static consteval access_context foo () { return access_context::current (); }
+  int d;
+public:
+  struct E {};
+  enum F { F1 };
+  int bar () { return 0; }
+  template <typename T>
+  void baz () { }
+  using g = int;
+  static constexpr int j = 42;
+protected:
+  int e;
+  struct G {};
+  enum H { H1 };
+  int qux () { return 0; }
+  template <typename T>
+  void freddy () { }
+  using h = int;
+  static constexpr int k = 42;
+private:
+  int f;
+  struct I {};
+  enum J { J1 };
+  int corge () { return 0; }
+  template <typename T>
+  void garply () {}
+  using i = int;
+  static constexpr int l = 42;
+  friend struct K;
+  friend void plugh ();
+public:
+  void waldo ()
+  {
+    constexpr auto ctx = access_context::current ();
+    static_assert (is_accessible (^^d, ctx));
+    static_assert (is_accessible (^^E, ctx));
+    static_assert (is_accessible (^^F, ctx));
+    static_assert (is_accessible (^^F1, ctx));
+    static_assert (is_accessible (^^bar, ctx));
+    static_assert (is_accessible (^^baz, ctx));
+    static_assert (is_accessible (^^g, ctx));
+    static_assert (is_accessible (^^j, ctx));
+    static_assert (is_accessible (^^e, ctx));
+    static_assert (is_accessible (^^G, ctx));
+    static_assert (is_accessible (^^H, ctx));
+    static_assert (is_accessible (^^H1, ctx));
+    static_assert (is_accessible (^^qux, ctx));
+    static_assert (is_accessible (^^freddy, ctx));
+    static_assert (is_accessible (^^h, ctx));
+    static_assert (is_accessible (^^k, ctx));
+    static_assert (is_accessible (^^f, ctx));
+    static_assert (is_accessible (^^I, ctx));
+    static_assert (is_accessible (^^J, ctx));
+    static_assert (is_accessible (^^J1, ctx));
+    static_assert (is_accessible (^^corge, ctx));
+    static_assert (is_accessible (^^garply, ctx));
+    static_assert (is_accessible (^^i, ctx));
+    static_assert (is_accessible (^^l, ctx));
+    static_assert (is_accessible (^^waldo, ctx));
+  }
+  static constexpr info rd = ^^d;
+  static constexpr info rE = ^^E;
+  static constexpr info rF = ^^F;
+  static constexpr info rF1 = ^^F1;
+  static constexpr info rbar = ^^bar;
+  static constexpr info rbaz = ^^baz;
+  static constexpr info rg = ^^g;
+  static constexpr info rj = ^^j;
+  static constexpr info re = ^^e;
+  static constexpr info rG = ^^G;
+  static constexpr info rH = ^^H;
+  static constexpr info rH1 = ^^H1;
+  static constexpr info rqux = ^^qux;
+  static constexpr info rfreddy = ^^freddy;
+  static constexpr info rh = ^^h;
+  static constexpr info rk = ^^k;
+  static constexpr info rf = ^^f;
+  static constexpr info rI = ^^I;
+  static constexpr info rJ = ^^J;
+  static constexpr info rJ1 = ^^J1;
+  static constexpr info rcorge = ^^corge;
+  static constexpr info rgarply = ^^garply;
+  static constexpr info ri = ^^i;
+  static constexpr info rl = ^^l;
+  static constexpr info rwaldo = ^^waldo;
+};
+
+constexpr auto gctx = access_context::current ();
+static_assert (is_accessible (D::rd, gctx));
+static_assert (is_accessible (D::rE, gctx));
+static_assert (is_accessible (D::rF, gctx));
+static_assert (is_accessible (D::rF1, gctx));
+static_assert (is_accessible (D::rbar, gctx));
+static_assert (is_accessible (D::rbaz, gctx));
+static_assert (is_accessible (D::rg, gctx));
+static_assert (is_accessible (D::rj, gctx));
+static_assert (!is_accessible (D::re, gctx));
+static_assert (!is_accessible (D::rG, gctx));
+static_assert (!is_accessible (D::rH, gctx));
+static_assert (!is_accessible (D::rH1, gctx));
+static_assert (!is_accessible (D::rqux, gctx));
+static_assert (!is_accessible (D::rfreddy, gctx));
+static_assert (!is_accessible (D::rh, gctx));
+static_assert (!is_accessible (D::rk, gctx));
+static_assert (!is_accessible (D::rf, gctx));
+static_assert (!is_accessible (D::rI, gctx));
+static_assert (!is_accessible (D::rJ, gctx));
+static_assert (!is_accessible (D::rJ1, gctx));
+static_assert (!is_accessible (D::rcorge, gctx));
+static_assert (!is_accessible (D::rgarply, gctx));
+static_assert (!is_accessible (D::ri, gctx));
+static_assert (!is_accessible (D::rl, gctx));
+static_assert (is_accessible (D::rwaldo, gctx));
+static_assert (is_accessible (D::rd, D::foo ()));
+static_assert (is_accessible (D::rE, D::foo ()));
+static_assert (is_accessible (D::rF, D::foo ()));
+static_assert (is_accessible (D::rF1, D::foo ()));
+static_assert (is_accessible (D::rbar, D::foo ()));
+static_assert (is_accessible (D::rbaz, D::foo ()));
+static_assert (is_accessible (D::rg, D::foo ()));
+static_assert (is_accessible (D::rj, D::foo ()));
+static_assert (is_accessible (D::re, D::foo ()));
+static_assert (is_accessible (D::rG, D::foo ()));
+static_assert (is_accessible (D::rH, D::foo ()));
+static_assert (is_accessible (D::rH1, D::foo ()));
+static_assert (is_accessible (D::rqux, D::foo ()));
+static_assert (is_accessible (D::rfreddy, D::foo ()));
+static_assert (is_accessible (D::rh, D::foo ()));
+static_assert (is_accessible (D::rk, D::foo ()));
+static_assert (is_accessible (D::rf, D::foo ()));
+static_assert (is_accessible (D::rI, D::foo ()));
+static_assert (is_accessible (D::rJ, D::foo ()));
+static_assert (is_accessible (D::rJ1, D::foo ()));
+static_assert (is_accessible (D::rcorge, D::foo ()));
+static_assert (is_accessible (D::rgarply, D::foo ()));
+static_assert (is_accessible (D::ri, D::foo ()));
+static_assert (is_accessible (D::rl, D::foo ()));
+static_assert (is_accessible (D::rwaldo, D::foo ()));
+constexpr auto uctx = access_context::unchecked ();
+static_assert (is_accessible (D::rd, uctx));
+static_assert (is_accessible (D::rE, uctx));
+static_assert (is_accessible (D::rF, uctx));
+static_assert (is_accessible (D::rF1, uctx));
+static_assert (is_accessible (D::rbar, uctx));
+static_assert (is_accessible (D::rbaz, uctx));
+static_assert (is_accessible (D::rg, uctx));
+static_assert (is_accessible (D::rj, uctx));
+static_assert (is_accessible (D::re, uctx));
+static_assert (is_accessible (D::rG, uctx));
+static_assert (is_accessible (D::rH, uctx));
+static_assert (is_accessible (D::rH1, uctx));
+static_assert (is_accessible (D::rqux, uctx));
+static_assert (is_accessible (D::rfreddy, uctx));
+static_assert (is_accessible (D::rh, uctx));
+static_assert (is_accessible (D::rk, uctx));
+static_assert (is_accessible (D::rf, uctx));
+static_assert (is_accessible (D::rI, uctx));
+static_assert (is_accessible (D::rJ, uctx));
+static_assert (is_accessible (D::rJ1, uctx));
+static_assert (is_accessible (D::rcorge, uctx));
+static_assert (is_accessible (D::rgarply, uctx));
+static_assert (is_accessible (D::ri, uctx));
+static_assert (is_accessible (D::rl, uctx));
+static_assert (is_accessible (D::rwaldo, uctx));
+
+struct K {
+  static constexpr auto ctx = access_context::current ();
+  static_assert (is_accessible (D::rd, ctx));
+  static_assert (is_accessible (D::rE, ctx));
+  static_assert (is_accessible (D::rF, ctx));
+  static_assert (is_accessible (D::rF1, ctx));
+  static_assert (is_accessible (D::rbar, ctx));
+  static_assert (is_accessible (D::rbaz, ctx));
+  static_assert (is_accessible (D::rg, ctx));
+  static_assert (is_accessible (D::rj, ctx));
+  static_assert (is_accessible (D::re, ctx));
+  static_assert (is_accessible (D::rG, ctx));
+  static_assert (is_accessible (D::rH, ctx));
+  static_assert (is_accessible (D::rH1, ctx));
+  static_assert (is_accessible (D::rqux, ctx));
+  static_assert (is_accessible (D::rfreddy, ctx));
+  static_assert (is_accessible (D::rh, ctx));
+  static_assert (is_accessible (D::rk, ctx));
+  static_assert (is_accessible (D::rf, ctx));
+  static_assert (is_accessible (D::rI, ctx));
+  static_assert (is_accessible (D::rJ, ctx));
+  static_assert (is_accessible (D::rJ1, ctx));
+  static_assert (is_accessible (D::rcorge, ctx));
+  static_assert (is_accessible (D::rgarply, ctx));
+  static_assert (is_accessible (D::ri, ctx));
+  static_assert (is_accessible (D::rl, ctx));
+  static_assert (is_accessible (D::rwaldo, ctx));
+  static constexpr auto uctx = access_context::unprivileged ();
+  static_assert (is_accessible (D::rd, uctx));
+  static_assert (is_accessible (D::rE, uctx));
+  static_assert (is_accessible (D::rF, uctx));
+  static_assert (is_accessible (D::rF1, uctx));
+  static_assert (is_accessible (D::rbar, uctx));
+  static_assert (is_accessible (D::rbaz, uctx));
+  static_assert (is_accessible (D::rg, uctx));
+  static_assert (is_accessible (D::rj, uctx));
+  static_assert (!is_accessible (D::re, uctx));
+  static_assert (!is_accessible (D::rG, uctx));
+  static_assert (!is_accessible (D::rH, uctx));
+  static_assert (!is_accessible (D::rH1, uctx));
+  static_assert (!is_accessible (D::rqux, uctx));
+  static_assert (!is_accessible (D::rfreddy, uctx));
+  static_assert (!is_accessible (D::rh, uctx));
+  static_assert (!is_accessible (D::rk, uctx));
+  static_assert (!is_accessible (D::rf, uctx));
+  static_assert (!is_accessible (D::rI, uctx));
+  static_assert (!is_accessible (D::rJ, uctx));
+  static_assert (!is_accessible (D::rJ1, uctx));
+  static_assert (!is_accessible (D::rcorge, uctx));
+  static_assert (!is_accessible (D::rgarply, uctx));
+  static_assert (!is_accessible (D::ri, uctx));
+  static_assert (!is_accessible (D::rl, uctx));
+  static_assert (is_accessible (D::rwaldo, uctx));
+};
+
+void
+plugh ()
+{
+  static constexpr auto ctx = access_context::current ();
+  static_assert (is_accessible (D::rd, ctx));
+  static_assert (is_accessible (D::rE, ctx));
+  static_assert (is_accessible (D::rF, ctx));
+  static_assert (is_accessible (D::rF1, ctx));
+  static_assert (is_accessible (D::rbar, ctx));
+  static_assert (is_accessible (D::rbaz, ctx));
+  static_assert (is_accessible (D::rg, ctx));
+  static_assert (is_accessible (D::rj, ctx));
+  static_assert (is_accessible (D::re, ctx));
+  static_assert (is_accessible (D::rG, ctx));
+  static_assert (is_accessible (D::rH, ctx));
+  static_assert (is_accessible (D::rH1, ctx));
+  static_assert (is_accessible (D::rqux, ctx));
+  static_assert (is_accessible (D::rfreddy, ctx));
+  static_assert (is_accessible (D::rh, ctx));
+  static_assert (is_accessible (D::rk, ctx));
+  static_assert (is_accessible (D::rf, ctx));
+  static_assert (is_accessible (D::rI, ctx));
+  static_assert (is_accessible (D::rJ, ctx));
+  static_assert (is_accessible (D::rJ1, ctx));
+  static_assert (is_accessible (D::rcorge, ctx));
+  static_assert (is_accessible (D::rgarply, ctx));
+  static_assert (is_accessible (D::ri, ctx));
+  static_assert (is_accessible (D::rl, ctx));
+  static_assert (is_accessible (D::rwaldo, ctx));
+}
+
+void
+xyzzy ()
+{
+  static constexpr auto ctx = access_context::current ();
+  static_assert (is_accessible (D::rd, ctx));
+  static_assert (is_accessible (D::rE, ctx));
+  static_assert (is_accessible (D::rF, ctx));
+  static_assert (is_accessible (D::rF1, ctx));
+  static_assert (is_accessible (D::rbar, ctx));
+  static_assert (is_accessible (D::rbaz, ctx));
+  static_assert (is_accessible (D::rg, ctx));
+  static_assert (is_accessible (D::rj, ctx));
+  static_assert (!is_accessible (D::re, ctx));
+  static_assert (!is_accessible (D::rG, ctx));
+  static_assert (!is_accessible (D::rH, ctx));
+  static_assert (!is_accessible (D::rH1, ctx));
+  static_assert (!is_accessible (D::rqux, ctx));
+  static_assert (!is_accessible (D::rfreddy, ctx));
+  static_assert (!is_accessible (D::rh, ctx));
+  static_assert (!is_accessible (D::rk, ctx));
+  static_assert (!is_accessible (D::rf, ctx));
+  static_assert (!is_accessible (D::rI, ctx));
+  static_assert (!is_accessible (D::rJ, ctx));
+  static_assert (!is_accessible (D::rJ1, ctx));
+  static_assert (!is_accessible (D::rcorge, ctx));
+  static_assert (!is_accessible (D::rgarply, ctx));
+  static_assert (!is_accessible (D::ri, ctx));
+  static_assert (!is_accessible (D::rl, ctx));
+  static_assert (is_accessible (D::rwaldo, ctx));
+}
+
+struct L : public D
+{
+  static constexpr auto ctx = access_context::current ();
+  static_assert (is_accessible (D::rd, ctx));
+  static_assert (is_accessible (D::rE, ctx));
+  static_assert (is_accessible (D::rF, ctx));
+  static_assert (is_accessible (D::rF1, ctx));
+  static_assert (is_accessible (D::rbar, ctx));
+  static_assert (is_accessible (D::rbaz, ctx));
+  static_assert (is_accessible (D::rg, ctx));
+  static_assert (is_accessible (D::rj, ctx));
+  static_assert (!is_accessible (D::re, ctx));
+  static_assert (is_accessible (D::rG, ctx));
+  static_assert (is_accessible (D::rH, ctx));
+  static_assert (is_accessible (D::rH1, ctx));
+  static_assert (!is_accessible (D::rqux, ctx));
+  static_assert (!is_accessible (D::rfreddy, ctx));
+  static_assert (is_accessible (D::rh, ctx));
+  static_assert (is_accessible (D::rk, ctx));
+  static_assert (!is_accessible (D::rf, ctx));
+  static_assert (!is_accessible (D::rI, ctx));
+  static_assert (!is_accessible (D::rJ, ctx));
+  static_assert (!is_accessible (D::rJ1, ctx));
+  static_assert (!is_accessible (D::rcorge, ctx));
+  static_assert (!is_accessible (D::rgarply, ctx));
+  static_assert (!is_accessible (D::ri, ctx));
+  static_assert (!is_accessible (D::rl, ctx));
+  static_assert (is_accessible (D::rwaldo, ctx));
+  friend void thud ();
+};
+
+consteval {
+  constexpr auto ctx = L::ctx.via (^^L);
+  static_assert (is_accessible (D::rd, ctx));
+  static_assert (is_accessible (D::rE, ctx));
+  static_assert (is_accessible (D::rF, ctx));
+  static_assert (is_accessible (D::rF1, ctx));
+  static_assert (is_accessible (D::rbar, ctx));
+  static_assert (is_accessible (D::rbaz, ctx));
+  static_assert (is_accessible (D::rg, ctx));
+  static_assert (is_accessible (D::rj, ctx));
+  static_assert (is_accessible (D::re, ctx));
+  static_assert (is_accessible (D::rG, ctx));
+  static_assert (is_accessible (D::rH, ctx));
+  static_assert (is_accessible (D::rH1, ctx));
+  static_assert (is_accessible (D::rqux, ctx));
+  static_assert (is_accessible (D::rfreddy, ctx));
+  static_assert (is_accessible (D::rh, ctx));
+  static_assert (is_accessible (D::rk, ctx));
+  static_assert (!is_accessible (D::rf, ctx));
+  static_assert (!is_accessible (D::rI, ctx));
+  static_assert (!is_accessible (D::rJ, ctx));
+  static_assert (!is_accessible (D::rJ1, ctx));
+  static_assert (!is_accessible (D::rcorge, ctx));
+  static_assert (!is_accessible (D::rgarply, ctx));
+  static_assert (!is_accessible (D::ri, ctx));
+  static_assert (!is_accessible (D::rl, ctx));
+  static_assert (is_accessible (D::rwaldo, ctx));
+}
+
+void
+thud ()
+{
+  static constexpr auto ctx = access_context::current ();
+  static_assert (is_accessible (D::rd, ctx));
+  static_assert (is_accessible (D::rE, ctx));
+  static_assert (is_accessible (D::rF, ctx));
+  static_assert (is_accessible (D::rF1, ctx));
+  static_assert (is_accessible (D::rbar, ctx));
+  static_assert (is_accessible (D::rbaz, ctx));
+  static_assert (is_accessible (D::rg, ctx));
+  static_assert (is_accessible (D::rj, ctx));
+  static_assert (!is_accessible (D::re, ctx));
+  // TODO: clang++ disagrees with GCC on the D::r{G,H,H12,h,k} cases.
+  static_assert (is_accessible (D::rG, ctx));
+  static_assert (is_accessible (D::rH, ctx));
+  static_assert (is_accessible (D::rH1, ctx));
+  static_assert (!is_accessible (D::rqux, ctx));
+  static_assert (!is_accessible (D::rfreddy, ctx));
+  static_assert (is_accessible (D::rh, ctx));
+  static_assert (is_accessible (D::rk, ctx));
+  static_assert (!is_accessible (D::rf, ctx));
+  static_assert (!is_accessible (D::rI, ctx));
+  static_assert (!is_accessible (D::rJ, ctx));
+  static_assert (!is_accessible (D::rJ1, ctx));
+  static_assert (!is_accessible (D::rcorge, ctx));
+  static_assert (!is_accessible (D::rgarply, ctx));
+  static_assert (!is_accessible (D::ri, ctx));
+  static_assert (!is_accessible (D::rl, ctx));
+  static_assert (is_accessible (D::rwaldo, ctx));
+  static constexpr auto ctx2 = access_context::current ().via (^^L);
+  static_assert (is_accessible (D::rd, ctx2));
+  static_assert (is_accessible (D::rE, ctx2));
+  static_assert (is_accessible (D::rF, ctx2));
+  static_assert (is_accessible (D::rF1, ctx2));
+  static_assert (is_accessible (D::rbar, ctx2));
+  static_assert (is_accessible (D::rbaz, ctx2));
+  static_assert (is_accessible (D::rg, ctx2));
+  static_assert (is_accessible (D::rj, ctx2));
+  static_assert (is_accessible (D::re, ctx2));
+  static_assert (is_accessible (D::rG, ctx2));
+  static_assert (is_accessible (D::rH, ctx2));
+  static_assert (is_accessible (D::rH1, ctx2));
+  static_assert (is_accessible (D::rqux, ctx2));
+  static_assert (is_accessible (D::rfreddy, ctx2));
+  static_assert (is_accessible (D::rh, ctx2));
+  static_assert (is_accessible (D::rk, ctx2));
+  static_assert (!is_accessible (D::rf, ctx2));
+  static_assert (!is_accessible (D::rI, ctx2));
+  static_assert (!is_accessible (D::rJ, ctx2));
+  static_assert (!is_accessible (D::rJ1, ctx2));
+  static_assert (!is_accessible (D::rcorge, ctx2));
+  static_assert (!is_accessible (D::rgarply, ctx2));
+  static_assert (!is_accessible (D::ri, ctx2));
+  static_assert (!is_accessible (D::rl, ctx2));
+  static_assert (is_accessible (D::rwaldo, ctx2));
+}
+
+struct M : D
+{
+  static constexpr auto ctx = access_context::current ();
+  static_assert (is_accessible (^^D::A::a, ctx));
+  static_assert (is_accessible (^^D::B::b, ctx));
+  static_assert (is_accessible (^^::C::c, ctx));
+};
+
+consteval {
+  constexpr auto ctx = M::ctx.via (^^M);
+  static_assert (!is_accessible (^^::C::c, ctx));
+}
+
+static union { int a; };
+
+static_assert (is_accessible (^^a, gctx));
+static_assert (is_accessible (^^a, D::foo ()));
+static_assert (is_accessible (^^a, uctx));
+
+struct N
+{
+  union { int a; };
+protected:
+  union { int b; };
+private:
+  union { int c; };
+public:
+  static constexpr auto ctx = access_context::current ();
+  static constexpr info ra = ^^a;
+  static constexpr info rb = ^^b;
+  static constexpr info rc = ^^c;
+};
+
+struct O : public N
+{
+  static constexpr auto ctx = access_context::current ();
+};
+
+static_assert (is_accessible (N::ra, gctx));
+// TODO: clang++ disagrees with g++ on the N::r{b,c} cases with gctx and O::ctx.
+static_assert (!is_accessible (N::rb, gctx));
+static_assert (!is_accessible (N::rc, gctx));
+static_assert (is_accessible (N::ra, N::ctx));
+// TODO: This case ICEs.
+//static_assert (is_accessible (N::rb, N::ctx));
+static_assert (is_accessible (N::rc, N::ctx));
+static_assert (is_accessible (N::ra, N::ctx.via (^^N)));
+static_assert (is_accessible (N::rb, N::ctx.via (^^N)));
+static_assert (is_accessible (N::rc, N::ctx.via (^^N)));
+static_assert (is_accessible (N::ra, O::ctx));
+static_assert (!is_accessible (N::rb, O::ctx));
+static_assert (!is_accessible (N::rc, O::ctx));
+static_assert (is_accessible (N::ra, O::ctx.via (^^O)));
+static_assert (is_accessible (N::rb, O::ctx.via (^^O)));
+static_assert (!is_accessible (N::rc, O::ctx.via (^^O)));
+static_assert (is_accessible (^^A::a, O::ctx));
+static_assert (!is_accessible (^^A::a, O::ctx.via (^^O)));
diff --git a/gcc/testsuite/g++.dg/reflect/is_alias_template1.C b/gcc/testsuite/g++.dg/reflect/is_alias_template1.C
new file mode 100644 (file)
index 0000000..8db2b7e
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_alias_template.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_alias_template (null_reflection));
+static_assert (!is_alias_template (^^::));
+static_assert (!is_alias_template (^^ns));
+static_assert (!is_alias_template (^^ns_alias));
+static_assert (!is_alias_template (reflect_constant (3)));
+static_assert (!is_alias_template (^^cls));
+static_assert (!is_alias_template (^^cls::dm));
+static_assert (!is_alias_template (^^cls::ref_dm));
+static_assert (!is_alias_template (^^cls::static_dm));
+static_assert (!is_alias_template (^^cls::mem_fun));
+static_assert (!is_alias_template (^^cls::static_mem_fun));
+static_assert (!is_alias_template (^^cls::type));
+static_assert (!is_alias_template (^^cls_var));
+static_assert (!is_alias_template (^^onion));
+static_assert (!is_alias_template (^^anon));
+static_assert (!is_alias_template (^^fun));
+static_assert (!is_alias_template (^^alias));
+static_assert (!is_alias_template (^^var));
+static_assert (!is_alias_template (^^ref));
+static_assert (!is_alias_template (^^rref));
+static_assert (!is_alias_template (^^ptr));
+static_assert (!is_alias_template (^^cls_tmpl));
+static_assert (!is_alias_template (^^cls_tmpl<int>));
+static_assert (!is_alias_template (^^incomplete_cls<int>));
+static_assert (!is_alias_template (^^fun_tmpl));
+static_assert (!is_alias_template (^^fun_tmpl<int>));
+static_assert (!is_alias_template (^^conc));
+static_assert (!is_alias_template (substitute (^^conc, { ^^int })));
+static_assert (!is_alias_template (^^var_tmpl));
+static_assert (!is_alias_template (^^var_tmpl<int>));
+static_assert (is_alias_template (^^cls_tmpl_alias));
+static_assert (!is_alias_template (^^cls_tmpl_alias<int>));
+static_assert (!is_alias_template (^^Enum));
+static_assert (!is_alias_template (^^Enum::A));
+static_assert (!is_alias_template (^^Enum_class));
+static_assert (!is_alias_template (^^Enum_class::A));
+static_assert (!is_alias_template (^^decomp));
+static_assert (!is_alias_template (^^decomp_ref));
+static_assert (!is_alias_template (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_alias_template (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_alias_template (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_alias_template (^^T));
+  static_assert (!is_alias_template (R));
+  static_assert (!is_alias_template (R2));
+  static_assert (is_alias_template (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls_tmpl_alias>();
+  static_assert (!is_alias_template (^^p));
+  static_assert (!is_alias_template (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_assignment1.C b/gcc/testsuite/g++.dg/reflect/is_assignment1.C
new file mode 100644 (file)
index 0000000..a598770
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_assignment.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator = (const S &);
+  S &operator += (const S &);
+  void bar ();
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (is_assignment (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &);
+};
+
+struct U {
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (is_assignment (parent_of (^^a)));
+    return *this;
+  }
+};
+
+static_assert (!is_assignment (null_reflection));
+static_assert (!is_assignment (^^int));
+static_assert (!is_assignment (^^::));
+static_assert (!is_assignment (^^foo));
+static_assert (!is_assignment (^^S::bar));
+static_assert (is_assignment (^^S::operator =));
+static_assert (!is_assignment (^^S::operator +=));
+static_assert (!is_assignment (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_bit_field1.C b/gcc/testsuite/g++.dg/reflect/is_bit_field1.C
new file mode 100644 (file)
index 0000000..091ac4d
--- /dev/null
@@ -0,0 +1,144 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_bit_field.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_bit_field (null_reflection));
+static_assert (!is_bit_field (^^::));
+static_assert (!is_bit_field (^^ns));
+static_assert (!is_bit_field (^^ns_alias));
+static_assert (!is_bit_field (reflect_constant (3)));
+static_assert (!is_bit_field (^^cls));
+static_assert (!is_bit_field (^^cls::dm));
+static_assert (!is_bit_field (^^cls::ref_dm));
+static_assert (!is_bit_field (^^cls::static_dm));
+static_assert (!is_bit_field (^^cls::mem_fun));
+static_assert (!is_bit_field (^^cls::static_mem_fun));
+static_assert (!is_bit_field (^^cls::type));
+static_assert (!is_bit_field (^^cls::E));
+static_assert (!is_bit_field (^^cls::B));
+static_assert (!is_bit_field (^^cls::C));
+static_assert (!is_bit_field (^^cls::D));
+static_assert (!is_bit_field (^^cls::F));
+static_assert (!is_bit_field (^^cls::F::G));
+static_assert (!is_bit_field (^^cls::F::H));
+static_assert (!is_bit_field (^^cls::S));
+static_assert (!is_bit_field (^^cls::U));
+static_assert (!is_bit_field (^^cls::foo));
+static_assert (!is_bit_field (^^cls::foo <0>));
+static_assert (!is_bit_field (^^cls::bar));
+static_assert (!is_bit_field (^^cls::bar <42>));
+static_assert (!is_bit_field (^^cls_var));
+static_assert (!is_bit_field (^^onion));
+static_assert (!is_bit_field (^^anon));
+static_assert (!is_bit_field (^^fun));
+static_assert (!is_bit_field (^^alias));
+static_assert (!is_bit_field (^^var));
+static_assert (!is_bit_field (^^ref));
+static_assert (!is_bit_field (^^rref));
+static_assert (!is_bit_field (^^ptr));
+static_assert (!is_bit_field (^^cls_tmpl));
+static_assert (!is_bit_field (^^cls_tmpl<int>));
+static_assert (!is_bit_field (^^incomplete_cls<int>));
+static_assert (!is_bit_field (^^fun_tmpl));
+static_assert (!is_bit_field (^^fun_tmpl<int>));
+static_assert (!is_bit_field (^^conc));
+static_assert (!is_bit_field (substitute (^^conc, { ^^int })));
+static_assert (!is_bit_field (^^var_tmpl));
+static_assert (!is_bit_field (^^var_tmpl<int>));
+static_assert (!is_bit_field (^^cls_tmpl_alias));
+static_assert (!is_bit_field (^^cls_tmpl_alias<int>));
+static_assert (!is_bit_field (^^Enum));
+static_assert (!is_bit_field (^^Enum::A));
+static_assert (!is_bit_field (^^Enum_class));
+static_assert (!is_bit_field (^^Enum_class::A));
+static_assert (!is_bit_field (^^decomp));
+static_assert (!is_bit_field (^^decomp_ref));
+static_assert (!is_bit_field (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_bit_field (dms));
+constexpr auto dms2 = data_member_spec (^^int, { .bit_width = 6 });
+static_assert (is_bit_field (dms2));
+constexpr auto dms3 = data_member_spec (^^int, { .name = "dms", .bit_width = 15 });
+static_assert (is_bit_field (dms3));
+
+constexpr auto ctx = access_context::current ();
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_bit_field (bases_of (^^Derived, ctx)[0]));
+
+struct S {
+  int bf : 4;
+  long long bf2 : 36;
+  int : 4;
+  int : 0;
+};
+static_assert (is_bit_field (^^S::bf));
+static_assert (is_bit_field (^^S::bf2));
+static_assert (is_bit_field (members_of (^^S, ctx)[2]));
+static_assert (is_bit_field (members_of (^^S, ctx)[3]));
+
+void
+foo (int x)
+{
+  static_assert (!is_bit_field (^^x));
+  static_assert (!is_bit_field (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_bit_field (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_bit_field (^^S));
+  static_assert (!is_bit_field (^^E));
+  static_assert (!is_bit_field (^^F));
+  static_assert (!is_bit_field (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_class_member1.C b/gcc/testsuite/g++.dg/reflect/is_class_member1.C
new file mode 100644 (file)
index 0000000..99c5267
--- /dev/null
@@ -0,0 +1,128 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_class_member.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_class_member (null_reflection));
+static_assert (!is_class_member (^^::));
+static_assert (!is_class_member (^^ns));
+static_assert (!is_class_member (^^ns_alias));
+static_assert (!is_class_member (reflect_constant (3)));
+static_assert (!is_class_member (^^cls));
+static_assert (is_class_member (^^cls::~cls));
+static_assert (is_class_member (^^cls::dm));
+static_assert (is_class_member (^^cls::ref_dm));
+static_assert (is_class_member (^^cls::static_dm));
+static_assert (is_class_member (^^cls::mem_fun));
+static_assert (is_class_member (^^cls::static_mem_fun));
+static_assert (is_class_member (^^cls::type));
+static_assert (is_class_member (^^cls::E));
+static_assert (is_class_member (^^cls::B));
+static_assert (is_class_member (^^cls::C));
+static_assert (is_class_member (^^cls::D));
+static_assert (is_class_member (^^cls::F));
+static_assert (!is_class_member (^^cls::F::G));
+static_assert (!is_class_member (^^cls::F::H));
+static_assert (is_class_member (^^cls::S));
+static_assert (is_class_member (^^cls::U));
+static_assert (is_class_member (^^cls::foo));
+static_assert (is_class_member (^^cls::foo <0>));
+static_assert (is_class_member (^^cls::bar));
+static_assert (is_class_member (^^cls::bar <42>));
+static_assert (!is_class_member (^^cls_var));
+static_assert (!is_class_member (^^onion));
+static_assert (is_class_member (^^anon));
+static_assert (!is_class_member (^^fun));
+static_assert (!is_class_member (^^alias));
+static_assert (!is_class_member (^^var));
+static_assert (!is_class_member (^^ref));
+static_assert (!is_class_member (^^rref));
+static_assert (!is_class_member (^^ptr));
+static_assert (!is_class_member (^^cls_tmpl));
+static_assert (!is_class_member (^^cls_tmpl<int>));
+static_assert (!is_class_member (^^incomplete_cls<int>));
+static_assert (!is_class_member (^^fun_tmpl));
+static_assert (!is_class_member (^^fun_tmpl<int>));
+static_assert (!is_class_member (^^conc));
+static_assert (!is_class_member (substitute (^^conc, { ^^int })));
+static_assert (!is_class_member (^^var_tmpl));
+static_assert (!is_class_member (^^var_tmpl<int>));
+static_assert (!is_class_member (^^cls_tmpl_alias));
+static_assert (!is_class_member (^^cls_tmpl_alias<int>));
+static_assert (!is_class_member (^^Enum));
+static_assert (!is_class_member (^^Enum::A));
+static_assert (!is_class_member (^^Enum_class));
+static_assert (!is_class_member (^^Enum_class::A));
+static_assert (!is_class_member (^^decomp));
+static_assert (!is_class_member (^^decomp_ref));
+static_assert (!is_class_member (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_class_member (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_class_member (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_class_member (^^x));
+  static_assert (!is_class_member (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_class_member (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_class_member (^^S));
+  static_assert (!is_class_member (^^E));
+  static_assert (!is_class_member (^^F));
+  static_assert (!is_class_member (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_class_template1.C b/gcc/testsuite/g++.dg/reflect/is_class_template1.C
new file mode 100644 (file)
index 0000000..3cc420d
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_class_template.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_class_template (null_reflection));
+static_assert (!is_class_template (^^::));
+static_assert (!is_class_template (^^ns));
+static_assert (!is_class_template (^^ns_alias));
+static_assert (!is_class_template (reflect_constant (3)));
+static_assert (!is_class_template (^^cls));
+static_assert (!is_class_template (^^cls::dm));
+static_assert (!is_class_template (^^cls::ref_dm));
+static_assert (!is_class_template (^^cls::static_dm));
+static_assert (!is_class_template (^^cls::mem_fun));
+static_assert (!is_class_template (^^cls::static_mem_fun));
+static_assert (!is_class_template (^^cls::type));
+static_assert (!is_class_template (^^cls_var));
+static_assert (!is_class_template (^^onion));
+static_assert (!is_class_template (^^anon));
+static_assert (!is_class_template (^^fun));
+static_assert (!is_class_template (^^alias));
+static_assert (!is_class_template (^^var));
+static_assert (!is_class_template (^^ref));
+static_assert (!is_class_template (^^rref));
+static_assert (!is_class_template (^^ptr));
+static_assert (is_class_template (^^cls_tmpl));
+static_assert (!is_class_template (^^cls_tmpl<int>));
+static_assert (!is_class_template (^^incomplete_cls<int>));
+static_assert (!is_class_template (^^fun_tmpl));
+static_assert (!is_class_template (^^fun_tmpl<int>));
+static_assert (!is_class_template (^^conc));
+static_assert (!is_class_template (substitute (^^conc, { ^^int })));
+static_assert (!is_class_template (^^var_tmpl));
+static_assert (!is_class_template (^^var_tmpl<int>));
+static_assert (!is_class_template (^^cls_tmpl_alias));
+static_assert (!is_class_template (^^cls_tmpl_alias<int>));
+static_assert (!is_class_template (^^Enum));
+static_assert (!is_class_template (^^Enum::A));
+static_assert (!is_class_template (^^Enum_class));
+static_assert (!is_class_template (^^Enum_class::A));
+static_assert (!is_class_template (^^decomp));
+static_assert (!is_class_template (^^decomp_ref));
+static_assert (!is_class_template (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_class_template (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_class_template (bases_of (^^Derived, access_context::unprivileged ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_class_template (^^T));
+  static_assert (!is_class_template (R));
+  static_assert (!is_class_template (R2));
+  static_assert (is_class_template (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls_tmpl>();
+  static_assert (!is_class_template (^^p));
+  static_assert (!is_class_template (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_complete_type1.C b/gcc/testsuite/g++.dg/reflect/is_complete_type1.C
new file mode 100644 (file)
index 0000000..6d89aea
--- /dev/null
@@ -0,0 +1,109 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_complete_type.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+using inc_arr = int[];
+using com_arr = int[42];
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_complete_type (null_reflection));
+static_assert (!is_complete_type (^^::));
+static_assert (!is_complete_type (^^ns));
+static_assert (!is_complete_type (^^ns_alias));
+static_assert (!is_complete_type (reflect_constant (3)));
+static_assert (is_complete_type (^^cls));
+static_assert (!is_complete_type (^^cls::dm));
+static_assert (!is_complete_type (^^cls::ref_dm));
+static_assert (!is_complete_type (^^cls::static_dm));
+static_assert (!is_complete_type (^^cls::mem_fun));
+static_assert (!is_complete_type (^^cls::static_mem_fun));
+static_assert (is_complete_type (^^cls::type));
+static_assert (!is_complete_type (^^cls_var));
+static_assert (is_complete_type (^^onion));
+static_assert (!is_complete_type (^^anon));
+static_assert (!is_complete_type (^^fun));
+static_assert (is_complete_type (^^alias));
+static_assert (!is_complete_type (^^var));
+static_assert (!is_complete_type (^^ref));
+static_assert (!is_complete_type (^^rref));
+static_assert (!is_complete_type (^^ptr));
+static_assert (!is_complete_type (^^cls_tmpl));
+static_assert (is_complete_type (^^cls_tmpl<int>));
+static_assert (!is_complete_type (^^incomplete_cls<int>));
+static_assert (!is_complete_type (^^fun_tmpl));
+static_assert (!is_complete_type (^^fun_tmpl<int>));
+static_assert (!is_complete_type (^^conc));
+static_assert (!is_complete_type (substitute (^^conc, { ^^int })));
+static_assert (!is_complete_type (^^var_tmpl));
+static_assert (!is_complete_type (^^var_tmpl<int>));
+static_assert (!is_complete_type (^^cls_tmpl_alias));
+static_assert (is_complete_type (^^cls_tmpl_alias<int>));
+static_assert (is_complete_type (^^Enum));
+static_assert (!is_complete_type (^^Enum::A));
+static_assert (is_complete_type (^^Enum_class));
+static_assert (!is_complete_type (^^Enum_class::A));
+static_assert (!is_complete_type (^^decomp));
+static_assert (!is_complete_type (^^decomp_ref));
+static_assert (!is_complete_type (^^arr));
+static_assert (!is_complete_type (^^inc_arr));
+static_assert (is_complete_type (^^com_arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_complete_type (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_complete_type (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (is_complete_type (^^T));
+  static_assert (!is_complete_type (R));
+  static_assert (!is_complete_type (R2));
+  static_assert (is_complete_type (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_complete_type (^^p));
+  static_assert (!is_complete_type (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_complete_type2.C b/gcc/testsuite/g++.dg/reflect/is_complete_type2.C
new file mode 100644 (file)
index 0000000..f637a31
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_complete_type.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S;
+
+namespace N
+{
+  consteval bool
+  is_complete_type (info r) { return std::meta::is_complete_type (r); }
+}
+
+static_assert (!is_complete_type (^^S));
+static_assert (!N::is_complete_type (^^S));
+
+consteval {
+  define_aggregate (^^S, {});
+}
+
+static_assert (is_complete_type (^^S));
+static_assert (N::is_complete_type (^^S));
diff --git a/gcc/testsuite/g++.dg/reflect/is_concept1.C b/gcc/testsuite/g++.dg/reflect/is_concept1.C
new file mode 100644 (file)
index 0000000..240931c
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_concept.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_concept (null_reflection));
+static_assert (!is_concept (^^::));
+static_assert (!is_concept (^^ns));
+static_assert (!is_concept (^^ns_alias));
+static_assert (!is_concept (reflect_constant (3)));
+static_assert (!is_concept (^^cls));
+static_assert (!is_concept (^^cls::dm));
+static_assert (!is_concept (^^cls::ref_dm));
+static_assert (!is_concept (^^cls::static_dm));
+static_assert (!is_concept (^^cls::mem_fun));
+static_assert (!is_concept (^^cls::static_mem_fun));
+static_assert (!is_concept (^^cls::type));
+static_assert (!is_concept (^^cls_var));
+static_assert (!is_concept (^^onion));
+static_assert (!is_concept (^^anon));
+static_assert (!is_concept (^^fun));
+static_assert (!is_concept (^^alias));
+static_assert (!is_concept (^^var));
+static_assert (!is_concept (^^ref));
+static_assert (!is_concept (^^rref));
+static_assert (!is_concept (^^ptr));
+static_assert (!is_concept (^^cls_tmpl));
+static_assert (!is_concept (^^cls_tmpl<int>));
+static_assert (!is_concept (^^incomplete_cls<int>));
+static_assert (!is_concept (^^fun_tmpl));
+static_assert (!is_concept (^^fun_tmpl<int>));
+static_assert (is_concept (^^conc));
+static_assert (!is_concept (substitute (^^conc, { ^^int })));
+static_assert (!is_concept (^^var_tmpl));
+static_assert (!is_concept (^^var_tmpl<int>));
+static_assert (!is_concept (^^cls_tmpl_alias));
+static_assert (!is_concept (^^cls_tmpl_alias<int>));
+static_assert (!is_concept (^^Enum));
+static_assert (!is_concept (^^Enum::A));
+static_assert (!is_concept (^^Enum_class));
+static_assert (!is_concept (^^Enum_class::A));
+static_assert (!is_concept (^^decomp));
+static_assert (!is_concept (^^decomp_ref));
+static_assert (!is_concept (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_concept (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_concept (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_concept (^^T));
+  static_assert (!is_concept (R));
+  static_assert (!is_concept (R2));
+  static_assert (is_concept (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^conc>();
+  static_assert (!is_concept (^^p));
+  static_assert (!is_concept (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_const1.C b/gcc/testsuite/g++.dg/reflect/is_const1.C
new file mode 100644 (file)
index 0000000..5be1f56
--- /dev/null
@@ -0,0 +1,116 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_const.
+
+#include <meta>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+static_assert (!is_const (std::meta::reflect_constant (42)));
+static_assert (!is_const (std::meta::reflect_object (arr[1])));
+static_assert (!is_const (^^arr));
+static_assert (!is_const (^^a3));
+static_assert (!is_const (^^fn));
+static_assert (!is_const (^^fn2));
+static_assert (!is_const (^^Enum::A));
+static_assert (!is_const (^^Alias));
+static_assert (!is_const (^^S));
+static_assert (!is_const (^^S::mem));
+static_assert (!is_const (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!is_const (^^TCls));
+static_assert (!is_const (^^TFn));
+static_assert (!is_const (^^TVar));
+static_assert (!is_const (^^Concept));
+static_assert (!is_const (^^NSAlias));
+static_assert (!is_const (^^NS));
+static_assert (!is_const (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (!is_const (std::meta::data_member_spec (^^int, { .name = "member" })));
+
+int
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (!is_const (^^a));
+  static_assert (is_const (^^b));
+  static_assert (!is_const (^^c));
+  static_assert (!is_const (^^d));
+  static_assert (!is_const (^^e));
+  static_assert (!is_const (parameters_of (^^foo)[0]));
+  static_assert (!is_const (parameters_of (^^foo)[1]));
+  static_assert (!is_const (parameters_of (^^foo)[2]));
+  static_assert (!is_const (parameters_of (^^foo)[3]));
+  static_assert (!is_const (parameters_of (^^foo)[4]));
+  return 0;
+}
+
+static_assert (!is_const (std::meta::reflect_constant (42)));
+static_assert (!is_const (std::meta::reflect_constant (42.0)));
+static_assert (is_const (std::meta::reflect_constant (U { 42 })));
+static_assert (!is_const (std::meta::reflect_object (arr[1])));
+static_assert (!is_const (^^arr));
+static_assert (!is_const (^^fn));
+static_assert (!is_const (^^Enum::A));
+static_assert (!is_const (^^A));
+static_assert (!is_const (^^S::mem));
+
+const int ci = 42;
+static_assert (is_const (^^ci));
+using uci = const int;
+static_assert (is_const (^^uci));
+constexpr long cl = 42L;
+static_assert (is_const (^^cl));
+extern const volatile short cv = 2;
+static_assert (is_const (^^cv));
+struct V { const int a; static const int b; };
+static_assert (is_const (^^V::a));
+static_assert (is_const (^^V::b));
+
+const int arr2[] = {3, 4, 5};
+const int arr3[2][2][2] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};
+struct W {
+  void foo () volatile {}
+  void bar () const {}
+};
+static_assert (is_const (^^arr2));
+static_assert (is_const (^^arr3));
+static_assert (!is_const (^^W::foo));
+static_assert (is_const (^^W::bar));
+static_assert (!is_const (^^int));
+static_assert (is_const (^^const int));
+static_assert (!is_const (^^volatile int));
+static_assert (is_const (^^const volatile int));
+static_assert (!is_const (^^int [2]));
+static_assert (is_const (^^const int [2]));
+static_assert (!is_const (^^volatile int [2]));
+static_assert (is_const (^^const volatile int [2]));
+static_assert (!is_const (^^int (int)));
+static_assert (is_const (^^int (int) const));
+static_assert (!is_const (^^int (int) volatile));
+static_assert (is_const (^^int (int) const volatile));
diff --git a/gcc/testsuite/g++.dg/reflect/is_consteval_only1.C b/gcc/testsuite/g++.dg/reflect/is_consteval_only1.C
new file mode 100644 (file)
index 0000000..268aaaa
--- /dev/null
@@ -0,0 +1,83 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_consteval_only.
+
+#include <meta>
+using namespace std::meta;
+
+struct A {
+  info i;
+};
+struct B : A { };
+struct C : virtual A { };
+struct D : B { };
+struct E { };
+struct F : E {
+  info i;
+};
+template<typename T>
+struct G {
+  T t;
+  using size_type = int;
+};
+struct H {
+  G<info>::size_type sz;
+};
+struct I {
+  std::initializer_list<std::meta::info>::size_type sz;
+};
+template<typename T>
+struct J : T { };
+
+template<typename T>
+using U = J<T>;
+
+template<typename T>
+struct K {
+  J<T> j;
+};
+
+template<typename T>
+struct L {
+  U<T> u;
+};
+
+template<typename T>
+struct M : J<T> { };
+
+template<typename>
+struct N { };
+
+static_assert (is_consteval_only_type (^^A));
+static_assert (is_consteval_only_type (^^B));
+static_assert (is_consteval_only_type (^^C));
+static_assert (is_consteval_only_type (^^D));
+static_assert (!is_consteval_only_type (^^E));
+static_assert (is_consteval_only_type (^^F));
+static_assert (!is_consteval_only_type (^^G<int>));
+static_assert (is_consteval_only_type (^^G<info>));
+static_assert (!is_consteval_only_type (^^H));
+static_assert (!is_consteval_only_type (^^I));
+static_assert (!is_consteval_only_type (^^J<E>));
+static_assert (is_consteval_only_type (^^J<A>));
+static_assert (!is_consteval_only_type (^^U<E>));
+static_assert (is_consteval_only_type (^^U<A>));
+static_assert (!is_consteval_only_type (^^K<E>));
+static_assert (is_consteval_only_type (^^K<A>));
+static_assert (!is_consteval_only_type (^^L<E>));
+static_assert (is_consteval_only_type (^^L<A>));
+static_assert (!is_consteval_only_type (^^M<E>));
+static_assert (is_consteval_only_type (^^M<A>));
+static_assert (!is_consteval_only_type (^^N<E>));
+static_assert (!is_consteval_only_type (^^N<A>));
+
+static_assert (is_consteval_only_type (^^std::meta::exception));
+static_assert (is_consteval_only_type (^^std::meta::access_context));
+static_assert (!is_consteval_only_type (^^std::meta::member_offset));
+static_assert (is_consteval_only_type (^^std::meta::data_member_options));
+static_assert (is_consteval_only_type (type_of (^^std::meta::data_member_options::name)));
+
+struct O;
+static_assert (!is_consteval_only_type (^^O));
+struct O { info i; };
+static_assert (is_consteval_only_type (^^O));
diff --git a/gcc/testsuite/g++.dg/reflect/is_constructible_type1.C b/gcc/testsuite/g++.dg/reflect/is_constructible_type1.C
new file mode 100644 (file)
index 0000000..0b9d3e0
--- /dev/null
@@ -0,0 +1,674 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_constructible_type.
+
+#include <meta>
+
+using namespace std::meta;
+
+class ClassType { };
+class DerivedType : public ClassType { };
+enum EnumType { e0 };
+struct ThrowDefaultClass { ThrowDefaultClass () noexcept (false); };
+struct ThrowCopyConsClass { ThrowCopyConsClass (const ThrowCopyConsClass &) noexcept (false); };
+struct ThrowMoveConsClass { ThrowMoveConsClass (ThrowMoveConsClass &&) noexcept (false); };
+struct NoexceptDefaultClass { NoexceptDefaultClass () noexcept (true); };
+struct ExceptDefaultClass { ExceptDefaultClass () noexcept (false); };
+struct NoexceptCopyConsClass { NoexceptCopyConsClass (const NoexceptCopyConsClass &) noexcept (true); };
+struct ExceptCopyConsClass { ExceptCopyConsClass (const ExceptCopyConsClass &) noexcept (false); };
+struct NoexceptMoveConsClass { NoexceptMoveConsClass (NoexceptMoveConsClass &&) noexcept (true); NoexceptMoveConsClass &operator= (NoexceptMoveConsClass &&) = default; };
+struct ExceptMoveConsClass { ExceptMoveConsClass (ExceptMoveConsClass &&) noexcept (false); };
+struct NoexceptCopyAssignClass { NoexceptCopyAssignClass &operator= (const NoexceptCopyAssignClass &) noexcept (true); };
+struct ExceptCopyAssignClass { ExceptCopyAssignClass &operator= (const ExceptCopyAssignClass &) noexcept (false); };
+struct NoexceptMoveAssignClass { NoexceptMoveAssignClass (NoexceptMoveAssignClass &&) = default; NoexceptMoveAssignClass &operator= (NoexceptMoveAssignClass &&) noexcept (true); };
+struct ExceptMoveAssignClass { ExceptMoveAssignClass &operator= (ExceptMoveAssignClass &&) noexcept (false); };
+struct DeletedCopyAssignClass { DeletedCopyAssignClass & operator= (const DeletedCopyAssignClass &) = delete; };
+struct DeletedMoveAssignClass { DeletedMoveAssignClass &operator= (DeletedMoveAssignClass &&) = delete; };
+struct NType { int i; int j; virtual ~NType (); };
+struct TType { int i; private: int j; };
+struct SLType { int i; int j; ~SLType (); };
+struct PODType { int i; int j; };
+struct Empty {};
+struct B { int i; B () {} };
+struct D : B {};
+enum E { ee1 };
+enum E2 { ee2 };
+enum class SE { e1 };
+enum class SE2 { e2 };
+enum OpE : int;
+enum class OpSE : bool;
+union U { int i; Empty b; };
+struct Abstract { virtual ~Abstract () = 0; };
+struct AbstractDelDtor { ~AbstractDelDtor () = delete; virtual void foo () = 0; };
+struct Ukn;
+template <class To>
+struct ImplicitTo { operator To (); };
+template <class To>
+struct DelImplicitTo { operator To () = delete; };
+template <class To>
+struct ExplicitTo { explicit operator To (); };
+struct Ellipsis { Ellipsis (...) {} };
+struct DelEllipsis { DelEllipsis (...) = delete; };
+struct Any { template <class T> Any (T &&) {} };
+struct nAny { template <class... T> nAny (T &&...) {} };
+struct DelnAny { template <class... T> DelnAny (T &&...) = delete; };
+template <class... Args>
+struct FromArgs { FromArgs (Args...); };
+struct DelDef { DelDef () = delete; };
+struct DelCopy { DelCopy (const DelCopy &) = delete; };
+struct DelDtor {
+  DelDtor () = default;
+  DelDtor (const DelDtor &) = default;
+  DelDtor (DelDtor &&) = default;
+  DelDtor (int);
+  DelDtor (int, B, U);
+  ~DelDtor () = delete;
+};
+struct Nontrivial {
+  Nontrivial ();
+  Nontrivial (const Nontrivial &);
+  Nontrivial &operator= (const Nontrivial &);
+  ~Nontrivial ();
+};
+union NontrivialUnion { int i; Nontrivial n; };
+struct UnusualCopy { UnusualCopy (UnusualCopy &); };
+
+static_assert (is_constructible_type (^^int, { ^^int }));
+static_assert (is_constructible_type (^^std::nullptr_t, { ^^std::nullptr_t }));
+static_assert (is_constructible_type (^^E, { ^^E }));
+static_assert (is_constructible_type (^^SE, { ^^SE }));
+static_assert (is_constructible_type (^^OpE, { ^^OpE }));
+static_assert (is_constructible_type (^^OpSE, { ^^OpSE }));
+static_assert (is_constructible_type (^^Empty, { ^^Empty }));
+static_assert (is_constructible_type (^^B, { ^^B }));
+static_assert (is_constructible_type (^^U, { ^^U }));
+static_assert (is_constructible_type (^^int B::*, { ^^int B::* }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^Ellipsis }));
+static_assert (is_constructible_type (^^int *, { ^^int * }));
+static_assert (is_constructible_type (^^void *, { ^^void * }));
+static_assert (is_constructible_type (^^Any, { ^^Any }));
+static_assert (is_constructible_type (^^nAny, { ^^nAny }));
+static_assert (is_constructible_type (^^std::initializer_list <int>, { ^^std::initializer_list <int> }));
+static_assert (is_constructible_type (^^DelDef, { ^^DelDef }));
+static_assert (!is_constructible_type (^^void, { ^^void }));
+static_assert (!is_constructible_type (^^Abstract, { ^^Abstract }));
+static_assert (!is_constructible_type (^^int [], { ^^int [] }));
+static_assert (!is_constructible_type (^^int [1], { ^^int [1] }));
+static_assert (!is_constructible_type (^^DelCopy, { ^^const DelCopy & }));
+static_assert (!is_constructible_type (^^DelCopy, { ^^DelCopy && }));
+static_assert (!is_constructible_type (^^DelCopy, { ^^DelCopy }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^void }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^int }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^DelDtor }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^DelDtor && }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^const DelDtor & }));
+static_assert (is_constructible_type (^^DelEllipsis, { ^^const DelEllipsis & }));
+static_assert (is_constructible_type (^^DelEllipsis, { ^^DelEllipsis && }));
+static_assert (is_constructible_type (^^DelEllipsis, { ^^DelEllipsis }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^void }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^B }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^Empty }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^E }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^SE }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^OpE }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^OpSE }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^void () }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^void () const }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^int [1] }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^int [] }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^int * }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^void * }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^int B::* }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^int D::* }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^Abstract }));
+static_assert (!is_constructible_type (^^int, { ^^DelImplicitTo <int> }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^DelImplicitTo <std::nullptr_t> }));
+static_assert (!is_constructible_type (^^int &, { ^^DelImplicitTo <const int &> }));
+static_assert (!is_constructible_type (^^int, { ^^void }));
+static_assert (!is_constructible_type (^^void, { ^^int }));
+static_assert (is_constructible_type (^^void *, { ^^int * }));
+static_assert (!is_constructible_type (^^int *, { ^^void * }));
+static_assert (is_constructible_type (^^int *, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^int * }));
+static_assert (!is_constructible_type (^^Empty, { ^^E }));
+static_assert (!is_constructible_type (^^Empty, { ^^SE }));
+static_assert (!is_constructible_type (^^Empty, { ^^OpE }));
+static_assert (!is_constructible_type (^^Empty, { ^^OpSE }));
+static_assert (!is_constructible_type (^^Empty, { ^^void }));
+static_assert (!is_constructible_type (^^Empty, { ^^void * }));
+static_assert (!is_constructible_type (^^Empty, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^Empty, { ^^int [] }));
+static_assert (!is_constructible_type (^^Empty, { ^^int [3] }));
+static_assert (!is_constructible_type (^^Empty, { ^^int }));
+static_assert (!is_constructible_type (^^Abstract, { ^^int }));
+static_assert (!is_constructible_type (^^Abstract, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^Abstract }));
+static_assert (!is_constructible_type (^^Abstract, { ^^int [] }));
+static_assert (is_constructible_type (^^B, { ^^D }));
+static_assert (!is_constructible_type (^^int [], { ^^int [1] }));
+static_assert (!is_constructible_type (^^int [1], { ^^int [] }));
+static_assert (!is_constructible_type (^^int [], { ^^Empty }));
+static_assert (!is_constructible_type (^^int [], { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^int [1], { ^^Abstract }));
+static_assert (is_constructible_type (^^const int *, { ^^int * }));
+static_assert (is_constructible_type (^^const void *, { ^^void * }));
+static_assert (is_constructible_type (^^const void *, { ^^int * }));
+static_assert (!is_constructible_type (^^int *, { ^^const void * }));
+static_assert (is_constructible_type (^^int, { ^^E }));
+static_assert (!is_constructible_type (^^E, { ^^int }));
+static_assert (!is_constructible_type (^^E, { ^^E2 }));
+static_assert (is_constructible_type (^^E, { ^^E }));
+static_assert (is_constructible_type (^^bool, { ^^E }));
+static_assert (!is_constructible_type (^^E, { ^^bool }));
+static_assert (is_constructible_type (^^double, { ^^E }));
+static_assert (!is_constructible_type (^^E, { ^^double }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^E }));
+static_assert (!is_constructible_type (^^E, { ^^std::nullptr_t }));
+static_assert (is_constructible_type (^^int, { ^^OpE }));
+static_assert (!is_constructible_type (^^OpE, { ^^int }));
+static_assert (!is_constructible_type (^^OpE, { ^^E2 }));
+static_assert (is_constructible_type (^^OpE, { ^^OpE }));
+static_assert (is_constructible_type (^^bool, { ^^OpE }));
+static_assert (!is_constructible_type (^^OpE, { ^^bool }));
+static_assert (is_constructible_type (^^double, { ^^OpE }));
+static_assert (!is_constructible_type (^^OpE, { ^^double }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^OpE }));
+static_assert (!is_constructible_type (^^OpE, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^int, { ^^SE }));
+static_assert (!is_constructible_type (^^SE, { ^^int }));
+static_assert (!is_constructible_type (^^E, { ^^SE }));
+static_assert (!is_constructible_type (^^SE, { ^^SE2 }));
+static_assert (is_constructible_type (^^SE, { ^^SE }));
+static_assert (!is_constructible_type (^^bool, { ^^SE }));
+static_assert (!is_constructible_type (^^SE, { ^^bool }));
+static_assert (!is_constructible_type (^^double, { ^^SE }));
+static_assert (!is_constructible_type (^^SE, { ^^double }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^SE }));
+static_assert (!is_constructible_type (^^SE, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^int, { ^^OpSE }));
+static_assert (!is_constructible_type (^^OpSE, { ^^int }));
+static_assert (!is_constructible_type (^^OpE, { ^^OpSE }));
+static_assert (!is_constructible_type (^^OpSE, { ^^SE2 }));
+static_assert (is_constructible_type (^^OpSE, { ^^OpSE }));
+static_assert (!is_constructible_type (^^bool, { ^^OpSE }));
+static_assert (!is_constructible_type (^^OpSE, { ^^bool }));
+static_assert (!is_constructible_type (^^double, { ^^OpSE }));
+static_assert (!is_constructible_type (^^OpSE, { ^^double }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^OpSE }));
+static_assert (!is_constructible_type (^^OpSE, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^D *, { ^^B * }));
+static_assert (!is_constructible_type (^^const volatile D *, { ^^B * }));
+static_assert (!is_constructible_type (^^D *, { ^^const volatile B * }));
+static_assert (!is_constructible_type (^^D *, { ^^B * const }));
+static_assert (!is_constructible_type (^^const volatile D *, { ^^B * const }));
+static_assert (!is_constructible_type (^^D *, { ^^const volatile B * const }));
+static_assert (!is_constructible_type (^^D *, { ^^B * & }));
+static_assert (!is_constructible_type (^^const volatile D *, { ^^B * & }));
+static_assert (!is_constructible_type (^^D *, { ^^const volatile B * & }));
+static_assert (!is_constructible_type (^^int B::*, { ^^int D::* }));
+static_assert (!is_constructible_type (^^const volatile int B::*, { ^^int D::* }));
+static_assert (!is_constructible_type (^^int B::*, { ^^const volatile int D::* }));
+static_assert (!is_constructible_type (^^int B::*, { ^^int D::* const }));
+static_assert (!is_constructible_type (^^const volatile int B::*, { ^^int D::* const }));
+static_assert (!is_constructible_type (^^int B::*, { ^^const volatile int D::* const }));
+static_assert (!is_constructible_type (^^int B::*, { ^^int D::* & }));
+static_assert (!is_constructible_type (^^const volatile int B::*, { ^^int D::* & }));
+static_assert (!is_constructible_type (^^int B::*, { ^^const volatile int D::* & }));
+static_assert (!is_constructible_type (^^int B::*, { ^^int D::* const & }));
+static_assert (!is_constructible_type (^^const volatile int B::*, { ^^int D::* const & }));
+static_assert (!is_constructible_type (^^int B::*, { ^^const volatile int D::* const & }));
+static_assert (!is_constructible_type (^^int &&, { ^^int & }));
+static_assert (!is_constructible_type (^^const int &&, { ^^int & }));
+static_assert (is_constructible_type (^^B &, { ^^D & }));
+static_assert (is_constructible_type (^^B &&, { ^^D && }));
+static_assert (is_constructible_type (^^const B &, { ^^D & }));
+static_assert (is_constructible_type (^^const B &&, { ^^D && }));
+static_assert (!is_constructible_type (^^B &, { ^^const D & }));
+static_assert (!is_constructible_type (^^B &&, { ^^const D && }));
+static_assert (!is_constructible_type (^^D &, { ^^B & }));
+static_assert (is_constructible_type (^^D &&, { ^^B && }));
+static_assert (!is_constructible_type (^^D &, { ^^const B & }));
+static_assert (is_constructible_type (^^D &&, { ^^const B && }));
+static_assert (is_constructible_type (^^const D &, { ^^B & }));
+static_assert (is_constructible_type (^^const D &&, { ^^B && }));
+static_assert (!is_constructible_type (^^B &&, { ^^B & }));
+static_assert (!is_constructible_type (^^B &&, { ^^D & }));
+static_assert (is_constructible_type (^^B &&, { ^^ImplicitTo <D &&> }));
+static_assert (is_constructible_type (^^B &&, { ^^ImplicitTo <D &&> & }));
+static_assert (is_constructible_type (^^int &&, { ^^double & }));
+static_assert (is_constructible_type (^^const int &, { ^^ImplicitTo <int &> & }));
+static_assert (is_constructible_type (^^const int &, { ^^ImplicitTo <int &> }));
+static_assert (is_constructible_type (^^const int &, { ^^ExplicitTo <int &> & }));
+static_assert (is_constructible_type (^^const int &, { ^^ExplicitTo <int &> }));
+static_assert (!is_constructible_type (^^B &&, { ^^ExplicitTo <D &&> }));
+static_assert (!is_constructible_type (^^B &&, { ^^ExplicitTo <D &&> & }));
+static_assert (!is_constructible_type (^^B &, { ^^B && }));
+static_assert (!is_constructible_type (^^D &, { ^^B && }));
+static_assert (!is_constructible_type (^^B &, { ^^D && }));
+static_assert (is_constructible_type (^^void (&) (), { ^^void (&) () }));
+static_assert (is_constructible_type (^^void (&&) (), { ^^void (&&) () }));
+static_assert (is_constructible_type (^^void (&&) (), { ^^void () }));
+static_assert (!is_constructible_type (^^void, { }));
+static_assert (!is_constructible_type (^^void, { ^^int }));
+static_assert (!is_constructible_type (^^void, { ^^int, ^^double }));
+static_assert (!is_constructible_type (^^int &, {}));
+static_assert (!is_constructible_type (^^const int &, {}));
+static_assert (!is_constructible_type (^^int &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const int &, { ^^int, ^^int }));
+static_assert (is_constructible_type (^^void (&) (), { ^^void () }));
+static_assert (is_constructible_type (^^void (&) (), { ^^void (&&) () }));
+static_assert (is_constructible_type (^^int &, { ^^int & }));
+static_assert (!is_constructible_type (^^int &, { ^^const int & }));
+static_assert (!is_constructible_type (^^int &, { ^^int }));
+static_assert (!is_constructible_type (^^int &, { ^^int && }));
+static_assert (!is_constructible_type (^^int &, { ^^const int && }));
+static_assert (is_constructible_type (^^const int &, { ^^int & }));
+static_assert (is_constructible_type (^^const int &, { ^^int }));
+static_assert (is_constructible_type (^^const int &, { ^^const int }));
+static_assert (is_constructible_type (^^const int &, { ^^int && }));
+static_assert (is_constructible_type (^^const int &, { ^^const int && }));
+static_assert (is_constructible_type (^^volatile int &, { ^^int & }));
+static_assert (!is_constructible_type (^^volatile int &, { ^^const int & }));
+static_assert (!is_constructible_type (^^volatile int &, { ^^int }));
+static_assert (!is_constructible_type (^^volatile int &, { ^^int && }));
+static_assert (!is_constructible_type (^^volatile int &, { ^^const int && }));
+static_assert (is_constructible_type (^^const volatile int &, { ^^int & }));
+static_assert (!is_constructible_type (^^const volatile int &, { ^^int }));
+static_assert (!is_constructible_type (^^const volatile int &, { ^^const int }));
+static_assert (!is_constructible_type (^^const volatile int &, { ^^int && }));
+static_assert (!is_constructible_type (^^const volatile int &, { ^^const int && }));
+static_assert (is_constructible_type (^^int &&, { ^^int }));
+static_assert (is_constructible_type (^^int &&, { ^^int && }));
+static_assert (!is_constructible_type (^^int &&, { ^^const int && }));
+static_assert (!is_constructible_type (^^int &&, { ^^int & }));
+static_assert (!is_constructible_type (^^int &&, { ^^const int & }));
+static_assert (is_constructible_type (^^int &&, { ^^double & }));
+static_assert (is_constructible_type (^^const int &&, { ^^int }));
+static_assert (is_constructible_type (^^const int &&, { ^^int && }));
+static_assert (is_constructible_type (^^const int &&, { ^^const int }));
+static_assert (is_constructible_type (^^const int &&, { ^^const int && }));
+static_assert (!is_constructible_type (^^int &&, { ^^const int & }));
+static_assert (!is_constructible_type (^^const int &&, { ^^int & }));
+static_assert (!is_constructible_type (^^const int &&, { ^^const int & }));
+static_assert (is_constructible_type (^^volatile int &&, { ^^int }));
+static_assert (is_constructible_type (^^volatile int &&, { ^^int && }));
+static_assert (!is_constructible_type (^^volatile int &&, { ^^const int && }));
+static_assert (!is_constructible_type (^^volatile int &&, { ^^int & }));
+static_assert (!is_constructible_type (^^volatile int &&, { ^^const int & }));
+static_assert (is_constructible_type (^^volatile int &&, { ^^double & }));
+static_assert (is_constructible_type (^^volatile const int &&, { ^^int }));
+static_assert (is_constructible_type (^^const volatile int &&, { ^^int && }));
+static_assert (is_constructible_type (^^const volatile int &&, { ^^const int }));
+static_assert (is_constructible_type (^^const volatile int &&, { ^^const int && }));
+static_assert (!is_constructible_type (^^volatile int &&, { ^^const int & }));
+static_assert (!is_constructible_type (^^const volatile int &&, { ^^int & }));
+static_assert (!is_constructible_type (^^const volatile int &&, { ^^const int & }));
+static_assert (is_constructible_type (^^Empty &, { ^^Empty & }));
+static_assert (!is_constructible_type (^^Empty &, { ^^const Empty & }));
+static_assert (!is_constructible_type (^^Empty &, { ^^Empty }));
+static_assert (!is_constructible_type (^^Empty &, { ^^Empty && }));
+static_assert (!is_constructible_type (^^Empty &, { ^^const Empty && }));
+static_assert (is_constructible_type (^^const Empty &, { ^^Empty & }));
+static_assert (is_constructible_type (^^const Empty &, { ^^Empty }));
+static_assert (is_constructible_type (^^const Empty &, { ^^const Empty }));
+static_assert (is_constructible_type (^^const Empty &, { ^^Empty && }));
+static_assert (is_constructible_type (^^const Empty &, { ^^const Empty && }));
+static_assert (is_constructible_type (^^volatile Empty &, { ^^Empty & }));
+static_assert (!is_constructible_type (^^volatile Empty &, { ^^const Empty & }));
+static_assert (!is_constructible_type (^^volatile Empty &, { ^^Empty }));
+static_assert (!is_constructible_type (^^volatile Empty &, { ^^Empty && }));
+static_assert (!is_constructible_type (^^volatile Empty &, { ^^const Empty && }));
+static_assert (is_constructible_type (^^const volatile Empty &, { ^^Empty & }));
+static_assert (!is_constructible_type (^^const volatile Empty &, { ^^Empty }));
+static_assert (!is_constructible_type (^^const volatile Empty &, { ^^const Empty }));
+static_assert (!is_constructible_type (^^const volatile Empty &, { ^^Empty && }));
+static_assert (!is_constructible_type (^^const volatile Empty &, { ^^const Empty && }));
+static_assert (is_constructible_type (^^Empty &&, { ^^Empty }));
+static_assert (is_constructible_type (^^Empty &&, { ^^Empty && }));
+static_assert (!is_constructible_type (^^Empty &&, { ^^const Empty && }));
+static_assert (!is_constructible_type (^^Empty &&, { ^^Empty & }));
+static_assert (!is_constructible_type (^^Empty &&, { ^^const Empty & }));
+static_assert (!is_constructible_type (^^Empty &&, { ^^double & }));
+static_assert (!is_constructible_type (^^Empty &&, { ^^const double & }));
+static_assert (is_constructible_type (^^const Empty &&, { ^^Empty }));
+static_assert (is_constructible_type (^^const Empty &&, { ^^Empty && }));
+static_assert (is_constructible_type (^^const Empty &&, { ^^const Empty }));
+static_assert (is_constructible_type (^^const Empty &&, { ^^const Empty && }));
+static_assert (!is_constructible_type (^^Empty &&, { ^^const Empty & }));
+static_assert (!is_constructible_type (^^const Empty &&, { ^^Empty & }));
+static_assert (!is_constructible_type (^^const Empty &&, { ^^const Empty & }));
+static_assert (is_constructible_type (^^volatile Empty &&, { ^^Empty }));
+static_assert (is_constructible_type (^^volatile Empty &&, { ^^Empty && }));
+static_assert (!is_constructible_type (^^volatile Empty &&, { ^^const Empty && }));
+static_assert (!is_constructible_type (^^volatile Empty &&, { ^^Empty & }));
+static_assert (!is_constructible_type (^^volatile Empty &&, { ^^const Empty & }));
+static_assert (!is_constructible_type (^^volatile Empty &&, { ^^double & }));
+static_assert (!is_constructible_type (^^volatile Empty &&, { ^^const double & }));
+static_assert (is_constructible_type (^^const volatile Empty &&, { ^^Empty }));
+static_assert (is_constructible_type (^^const volatile Empty &&, { ^^Empty && }));
+static_assert (is_constructible_type (^^const volatile Empty &&, { ^^const Empty }));
+static_assert (is_constructible_type (^^const volatile Empty &&, { ^^const Empty && }));
+static_assert (!is_constructible_type (^^volatile Empty &&, { ^^const Empty & }));
+static_assert (!is_constructible_type (^^const volatile Empty &&, { ^^Empty & }));
+static_assert (!is_constructible_type (^^const volatile Empty &&, { ^^const Empty & }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^int }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^Empty }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^std::nullptr_t }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^int [] }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^int [1] }));
+static_assert (!is_constructible_type (^^Ellipsis, { ^^void }));
+static_assert (is_constructible_type (^^int (&) [1], { ^^int (&) [1] }));
+static_assert (is_constructible_type (^^const int (&) [1], { ^^int (&) [1] }));
+static_assert (is_constructible_type (^^volatile int (&) [1], { ^^int (&) [1] }));
+static_assert (is_constructible_type (^^const volatile int (&) [1], { ^^int (&) [1] }));
+static_assert (!is_constructible_type (^^int (&) [1], { ^^const int (&) [1] }));
+static_assert (!is_constructible_type (^^const int (&) [1], { ^^volatile int (&) [1] }));
+static_assert (is_constructible_type (^^int (&) [], { ^^int (&) [] }));
+static_assert (!is_constructible_type (^^int (&) [1], { ^^int (&) [2] }));
+static_assert (!is_constructible_type (^^int (&) [1], { ^^int & }));
+static_assert (!is_constructible_type (^^int &, { ^^int (&) [1] }));
+static_assert (!is_constructible_type (^^U, { ^^Empty }));
+static_assert (!is_constructible_type (^^void (), { ^^void () }));
+static_assert (!is_constructible_type (^^void (), { ^^int }));
+static_assert (!is_constructible_type (^^void (), { ^^Abstract }));
+static_assert (!is_constructible_type (^^void (), { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^void (), { ^^Empty }));
+static_assert (!is_constructible_type (^^void (), { ^^U }));
+static_assert (!is_constructible_type (^^void (), { ^^E }));
+static_assert (!is_constructible_type (^^void (), { ^^SE }));
+static_assert (!is_constructible_type (^^void (), { ^^OpE }));
+static_assert (!is_constructible_type (^^void (), { ^^OpSE }));
+static_assert (!is_constructible_type (^^void (), { ^^int [] }));
+static_assert (!is_constructible_type (^^void (), { ^^int [1] }));
+static_assert (!is_constructible_type (^^void () const, { ^^void () volatile }));
+static_assert (!is_constructible_type (^^void () const, { ^^int }));
+static_assert (!is_constructible_type (^^void () const, { ^^Abstract }));
+static_assert (!is_constructible_type (^^void () const, { ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^void () const, { ^^Empty }));
+static_assert (!is_constructible_type (^^void () const, { ^^U }));
+static_assert (!is_constructible_type (^^void () const, { ^^E }));
+static_assert (!is_constructible_type (^^void () const, { ^^SE }));
+static_assert (!is_constructible_type (^^void () const, { ^^OpE }));
+static_assert (!is_constructible_type (^^void () const, { ^^OpSE }));
+static_assert (!is_constructible_type (^^void () const, { ^^int [] }));
+static_assert (!is_constructible_type (^^void () const, { ^^int [1] }));
+static_assert (!is_constructible_type (^^void (int), { ^^void () }));
+static_assert (!is_constructible_type (^^int, { ^^void () }));
+static_assert (!is_constructible_type (^^Abstract, { ^^void () }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^void () }));
+static_assert (!is_constructible_type (^^Empty, { ^^void () }));
+static_assert (!is_constructible_type (^^U, { ^^void () }));
+static_assert (!is_constructible_type (^^E, { ^^void () }));
+static_assert (!is_constructible_type (^^SE, { ^^void () }));
+static_assert (!is_constructible_type (^^OpE, { ^^void () }));
+static_assert (!is_constructible_type (^^OpSE, { ^^void () }));
+static_assert (!is_constructible_type (^^int [], { ^^void () }));
+static_assert (!is_constructible_type (^^int [1], { ^^void () }));
+static_assert (!is_constructible_type (^^void (int) const, { ^^void () const }));
+static_assert (!is_constructible_type (^^int, { ^^void () const }));
+static_assert (!is_constructible_type (^^Abstract, { ^^void () const }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^void () const }));
+static_assert (!is_constructible_type (^^Empty, { ^^void () const }));
+static_assert (!is_constructible_type (^^U, { ^^void () const }));
+static_assert (!is_constructible_type (^^E, { ^^void () const }));
+static_assert (!is_constructible_type (^^SE, { ^^void () const }));
+static_assert (!is_constructible_type (^^OpE, { ^^void () const }));
+static_assert (!is_constructible_type (^^OpSE, { ^^void () const }));
+static_assert (!is_constructible_type (^^int [], { ^^void () const }));
+static_assert (!is_constructible_type (^^int [1], { ^^void () const }));
+static_assert (!is_constructible_type (^^void, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^void, { ^^Empty, ^^B }));
+static_assert (!is_constructible_type (^^void, { ^^Empty, ^^Empty }));
+static_assert (!is_constructible_type (^^void, { ^^U, ^^Empty }));
+static_assert (!is_constructible_type (^^void, { ^^U, ^^U }));
+static_assert (!is_constructible_type (^^void, { ^^std::nullptr_t, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^void, { ^^int [1], ^^int [1] }));
+static_assert (!is_constructible_type (^^void, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^void, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^void, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^void, { ^^void (), ^^void () }));
+static_assert (!is_constructible_type (^^void, { ^^void () const, ^^void () volatile }));
+static_assert (!is_constructible_type (^^int, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const int, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^int, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const int, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^int, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const int, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^bool, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const bool, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const std::nullptr_t, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const std::nullptr_t, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^std::nullptr_t, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const std::nullptr_t, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^E, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const E, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^E, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const E, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^E, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const E, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^SE, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const SE, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^SE, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const SE, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^SE, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const SE, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^OpE, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const OpE, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^OpE, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const OpE, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^OpE, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const OpE, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^OpSE, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const OpSE, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^OpSE, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const OpSE, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^OpSE, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const OpSE, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^Empty, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const Empty, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^Empty, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const Empty, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^Empty, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const Empty, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^U, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const U, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^U, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const U, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^U, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const U, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^B, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const B, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^B, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const B, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^B, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const B, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^Any, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const Any, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^Any, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const Any, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^Any, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const Any, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^nAny, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const nAny, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^nAny, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const nAny, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^FromArgs <>, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const FromArgs <>, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^FromArgs <>, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const FromArgs <>, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^FromArgs <>, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const FromArgs <>, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^Abstract, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const Abstract, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^Abstract, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const Abstract, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^Abstract, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const Abstract, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^AbstractDelDtor, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const AbstractDelDtor, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^AbstractDelDtor, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const AbstractDelDtor, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^AbstractDelDtor, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const AbstractDelDtor, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^int [1], { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const int [1], { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^int [1], { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const int [1], { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^int [1], { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^const int [1], { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^int &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^int &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^int &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^int &, { ^^int &, ^^int & }));
+static_assert (!is_constructible_type (^^int &, { ^^void, ^^int & }));
+static_assert (!is_constructible_type (^^int &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^std::nullptr_t &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^std::nullptr_t &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^std::nullptr_t &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^E &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^E &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^E &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^SE &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^SE &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^SE &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^OpE &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^OpE &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^OpE &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^OpSE &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^OpSE &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^OpSE &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^Empty &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^Empty &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^Empty &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^U &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^U &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^U &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^B &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^B &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^B &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^Any &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^Any &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^Any &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^nAny &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^nAny &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^FromArgs <> &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^FromArgs <> &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^FromArgs <> &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^Abstract &, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^Abstract &, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^Abstract &, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^int (&) [1], { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^int (&) [1], { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^int (&) [1], { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^void (), { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^void (), { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^void (), { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^void (), { ^^void (), ^^int }));
+static_assert (!is_constructible_type (^^void (), { ^^void (), ^^void () }));
+static_assert (!is_constructible_type (^^void () const, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^void () const, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^void () const, { ^^void, ^^void }));
+static_assert (!is_constructible_type (^^void () const, { ^^void () volatile, ^^int }));
+static_assert (!is_constructible_type (^^void () const, { ^^void () volatile const, ^^void () const }));
+static_assert (!is_constructible_type (^^FromArgs <int>, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const FromArgs <int>, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^FromArgs <int>, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const FromArgs <int>, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^FromArgs <int, int>, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^const FromArgs <int, int>, { ^^void, ^^int }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^int, ^^B, ^^U }));
+static_assert (!is_constructible_type (^^const DelDtor, { ^^int, ^^B, ^^U }));
+static_assert (!is_constructible_type (^^DelDtor, { ^^int }));
+static_assert (!is_constructible_type (^^const DelDtor, { ^^int }));
+static_assert (!is_constructible_type (^^DelDtor, {}));
+static_assert (!is_constructible_type (^^const DelDtor, {}));
+static_assert (!is_constructible_type (^^DelDtor, { ^^void *, ^^void (&) () }));
+static_assert (!is_constructible_type (^^const DelDtor, { ^^void *, ^^void (&) () }));
+static_assert (!is_constructible_type (^^AbstractDelDtor, {}));
+static_assert (!is_constructible_type (^^const AbstractDelDtor, {}));
+static_assert (!is_constructible_type (^^DelEllipsis, {}));
+static_assert (!is_constructible_type (^^const DelEllipsis, {}));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^double }));
+static_assert (!is_constructible_type (^^const DelEllipsis, { ^^double }));
+static_assert (!is_constructible_type (^^DelEllipsis, { ^^double, ^^int & }));
+static_assert (!is_constructible_type (^^const DelEllipsis, { ^^double, ^^int & }));
+static_assert (!is_constructible_type (^^DelnAny, {}));
+static_assert (!is_constructible_type (^^const DelnAny, {}));
+static_assert (!is_constructible_type (^^DelnAny, { ^^int }));
+static_assert (!is_constructible_type (^^const DelnAny, { ^^int }));
+static_assert (!is_constructible_type (^^DelnAny, { ^^int, ^^void * }));
+static_assert (!is_constructible_type (^^const DelnAny, { ^^int, ^^void * }));
+static_assert (!is_constructible_type (^^DelnAny, { ^^Empty, ^^B, ^^D }));
+static_assert (!is_constructible_type (^^const DelnAny, { ^^Empty, ^^B, ^^D }));
+static_assert (!is_constructible_type (^^NontrivialUnion, {}));
+static_assert (!is_constructible_type (^^NontrivialUnion, { ^^const NontrivialUnion & }));
+static_assert (!is_constructible_type (^^UnusualCopy, {}));
+static_assert (!is_constructible_type (^^UnusualCopy, { ^^UnusualCopy }));
+static_assert (!is_constructible_type (^^UnusualCopy, { ^^UnusualCopy && }));
+static_assert (!is_constructible_type (^^UnusualCopy, { ^^const UnusualCopy & }));
+static_assert (is_constructible_type (^^UnusualCopy, { ^^UnusualCopy & }));
+static_assert (is_constructible_type (^^FromArgs <int, char>, { ^^int, ^^char }));
+static_assert (is_constructible_type (^^const FromArgs <int, char>, { ^^int, ^^char }));
+static_assert (is_constructible_type (^^FromArgs <int, char>, { ^^int, ^^int }));
+static_assert (is_constructible_type (^^const FromArgs <int, char>, { ^^int, ^^int }));
+static_assert (is_constructible_type (^^nAny, { ^^int, ^^int }));
+static_assert (is_constructible_type (^^const nAny, { ^^int, ^^int }));
+static_assert (is_constructible_type (^^FromArgs <int, char>, { ^^ImplicitTo <int>, ^^ImplicitTo <char> }));
+static_assert (is_constructible_type (^^const FromArgs <int, char>, { ^^ImplicitTo <int>, ^^ImplicitTo <char> }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^int, ^^char }));
+static_assert (is_constructible_type (^^const Ellipsis, { ^^int, ^^char }));
+static_assert (is_constructible_type (^^Ellipsis, { ^^B, ^^U, ^^int & }));
+static_assert (is_constructible_type (^^const Ellipsis, { ^^B, ^^U, ^^int & }));
+static_assert (is_constructible_type (^^nAny, { ^^B, ^^U, ^^int & }));
+static_assert (is_constructible_type (^^const nAny, { ^^B, ^^U, ^^int & }));
+static_assert (is_constructible_type (^^FromArgs <std::initializer_list <int>, std::initializer_list <B>>, { ^^std::initializer_list <int>, ^^std::initializer_list <B> }));
+static_assert (is_constructible_type (^^const FromArgs <std::initializer_list <int>, std::initializer_list <B>>, { ^^std::initializer_list <int>, ^^std::initializer_list <B> }));
+static_assert (is_constructible_type (^^FromArgs <std::initializer_list <int>, std::initializer_list <B>>, { ^^std::initializer_list <int> &, ^^std::initializer_list <B> & }));
+static_assert (!is_constructible_type (^^FromArgs <std::initializer_list <int> &, std::initializer_list <B> &>, { ^^std::initializer_list <int>, ^^std::initializer_list <B> }));
+static_assert (!is_constructible_type (^^FromArgs <std::initializer_list <int>>, { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const FromArgs <std::initializer_list <int>>, { ^^int, ^^int }));
+static_assert (is_constructible_type (^^B [2], { ^^B, ^^B }));
+static_assert (is_constructible_type (^^const B [2], { ^^B, ^^B }));
+static_assert (is_constructible_type (^^U [2], { ^^U, ^^U }));
+static_assert (is_constructible_type (^^const U [2], { ^^U, ^^U }));
+static_assert (!is_constructible_type (^^E, { ^^E, ^^E }));
+static_assert (!is_constructible_type (^^const E, { ^^E, ^^E }));
+static_assert (!is_constructible_type (^^SE, { ^^SE, ^^SE }));
+static_assert (!is_constructible_type (^^const SE, { ^^SE, ^^SE }));
+static_assert (!is_constructible_type (^^E, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^const E, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^SE, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^const SE, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^E, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^const E, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^SE, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^const SE, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^OpE, { ^^OpE, ^^OpE }));
+static_assert (!is_constructible_type (^^const OpE, { ^^OpE, ^^OpE }));
+static_assert (!is_constructible_type (^^OpSE, { ^^OpSE, ^^OpSE }));
+static_assert (!is_constructible_type (^^const OpSE, { ^^OpSE, ^^OpSE }));
+static_assert (!is_constructible_type (^^OpE, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^const OpE, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^OpSE, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^const OpSE, { ^^B, ^^std::nullptr_t }));
+static_assert (!is_constructible_type (^^OpE, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^const OpE, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^OpSE, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^const OpSE, { ^^int [], ^^int [] }));
+static_assert (!is_constructible_type (^^int [], { ^^int, ^^int }));
+static_assert (!is_constructible_type (^^const int [], { ^^int, ^^int }));
+static_assert (is_constructible_type (^^int &, { ^^ImplicitTo <int &> }));
+static_assert (is_constructible_type (^^const int &, { ^^ImplicitTo <int &&> }));
+static_assert (is_constructible_type (^^int &&, { ^^ImplicitTo <int &&> }));
+static_assert (is_constructible_type (^^const int &, { ^^ImplicitTo <int> }));
+static_assert (!is_constructible_type (^^const int &, { ^^ExplicitTo <int> }));
+static_assert (!is_constructible_type (^^int &&, { ^^ExplicitTo <int> }));
+static_assert (is_constructible_type (^^int &, { ^^ExplicitTo <int &> }));
+static_assert (is_constructible_type (^^int &&, { ^^ExplicitTo <int &&> }));
+static_assert (!is_constructible_type (^^const int &, { ^^ExplicitTo <int &&> }));
+static_assert (!is_constructible_type (^^const int &, { ^^ExplicitTo <double &&> }));
+static_assert (!is_constructible_type (^^int &&, { ^^ExplicitTo <double &&> }));
+static_assert (is_constructible_type (^^void (&&) (), { ^^void (&) () }));
diff --git a/gcc/testsuite/g++.dg/reflect/is_constructible_type2.C b/gcc/testsuite/g++.dg/reflect/is_constructible_type2.C
new file mode 100644 (file)
index 0000000..f309730
--- /dev/null
@@ -0,0 +1,137 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_constructible_type.
+
+#include <array>
+#include <list>
+#include <meta>
+#include <ranges>
+#include <span>
+#include <vector>
+
+using namespace std::meta;
+
+template <class... Args>
+struct FromArgs { FromArgs (Args...); };
+
+static_assert (!is_constructible_type (^^FromArgs <int &, long &, const double &>, {}));
+static_assert (is_constructible_type (^^FromArgs <int &, long &, const double &>, { ^^int &, ^^long &, ^^const double & }));
+constexpr info arr1[6] = { ^^double, ^^int &, ^^unsigned long long &, ^^int *, ^^short &, ^^char & };
+static_assert (is_constructible_type (^^FromArgs <double, int &, unsigned long long &, int *, short &, char &>, arr1));
+constexpr std::span <const info> sp1 (arr1);
+static_assert (is_constructible_type (^^FromArgs <double, int &, unsigned long long &, int *, short &, char &>, sp1));
+static_assert (is_constructible_type (^^FromArgs <int &, unsigned long long &, int *>, sp1.subspan (1, 3)));
+static_assert (is_constructible_type (^^FromArgs <double, int &, unsigned long long &, int *, short &>, sp1.first (5)));
+static_assert (is_constructible_type (^^FromArgs <int *, unsigned long long &, int &>, sp1.subspan (1, 3) | std::views::reverse));
+static_assert (is_constructible_type (^^FromArgs <short &, int *, unsigned long long &, int &, double>, sp1.first (5) | std::views::reverse));
+static_assert (!is_constructible_type (^^FromArgs <double, int &, unsigned long long &, int *, short &>, sp1.first (5) | std::views::reverse));
+
+consteval bool
+foo ()
+{
+  auto a = std::vector <info> { ^^int &, ^^long &, ^^long long & };
+  if (!is_constructible_type (^^FromArgs <int &, long &, long long &>, a))
+    return false;
+  auto b = std::vector <info> { ^^short &, ^^double &, ^^float &, ^^char & };
+  if (!is_constructible_type (^^FromArgs <short &, double &, float &, char &>, b))
+    return false;
+  auto c = std::array { ^^long &, ^^short &, ^^char &, ^^int };
+  if (!is_constructible_type (^^FromArgs <long &, short &, char &, int>, c))
+    return false;
+  if (!is_constructible_type (^^FromArgs <long long &, long &, int &>, a | std::views::reverse))
+    return false;
+  if (!is_constructible_type (^^FromArgs <char &, float &, double &, short &>, b | std::views::reverse))
+    return false;
+  if (!is_constructible_type (^^FromArgs <int, char &, short &, long &>, c | std::views::reverse))
+    return false;
+  return true;
+}
+static_assert (foo ());
+
+struct G
+{
+  consteval const info *begin () const { return &arr1[0]; }
+  consteval const info *end () const { return &arr1[4]; }
+};
+static_assert (is_constructible_type (^^FromArgs <double, int &, unsigned long long &, int *>, G {}));
+
+struct H
+{
+  consteval const info *begin () const { return &arr1[1]; }
+  consteval const info *end () const { return &arr1[4]; }
+};
+static_assert (is_constructible_type (^^FromArgs <int &, unsigned long long &, int *>, H {}));
+
+struct I
+{
+  using difference_type = std::ptrdiff_t;
+  using value_type = info;
+  consteval info operator * () const {
+    if (p == 0) return arr1[2];
+    else if (p == 1) return arr1[0];
+    else if (p == 2) return arr1[1];
+    else return arr1[3];
+  }
+  constexpr I &operator ++ () { ++p; return *this; }
+  constexpr void operator ++ (int) { ++*this; }
+  constexpr bool operator == (const I &x) const { return p == x.p; }
+  int p;
+};
+
+struct J
+{
+  constexpr I begin () const { return I { 0 }; }
+  constexpr I end () const { return I { 4 }; }
+};
+static_assert (is_constructible_type (^^FromArgs <unsigned long long &, double, int &, int *>, J {}));
+
+struct K
+{
+  constexpr K () : q (new int) {}
+  constexpr K (const K &) : q (new int) {}
+  constexpr K &operator = (const K &) { return *this; }
+  constexpr ~K () { delete q; }
+  int *q;
+};
+
+template <typename T, T E>
+struct L
+{
+  using difference_type = std::ptrdiff_t;
+  using value_type = T;
+  constexpr T &operator * () const { return *p; }
+  constexpr L (T *x) : p (x), q (new int) {}
+  constexpr L (const L &x) : p (x.p), q (new int) {}
+  constexpr L &operator = (const L &x) { p = x.p; return *this; }
+  constexpr ~L () { delete q; }
+  constexpr L &operator ++ () { ++p; return *this; }
+  constexpr void operator ++ (int) { ++*this; }
+  constexpr bool operator == (const L &x) const { return p == x.p; }
+  constexpr bool operator == (const K &) const { return *p == E; }
+  T *p;
+  int *q;
+};
+
+template <typename T, T E>
+struct M
+{
+  constexpr M (T *x) : p (x), q (new int) {}
+  constexpr M (const M &x) : p (x.p), q (new int) {}
+  constexpr M &operator = (const M &x) { p = x.p; return *this; }
+  constexpr ~M () { delete q; }
+  constexpr L <T, E> begin () const { return L <T, E> (p); }
+  constexpr K end () const { return K (); }
+  T *p;
+  int *q;
+};
+
+consteval bool
+bar ()
+{
+  info a[] = { ^^int &, ^^short &, ^^long &, ^^unsigned &, ^^char &, ^^void, ^^int };
+  auto b = M <info, ^^void> (&a[0]);
+  if (!is_constructible_type (^^FromArgs <int &, short &, long &, unsigned &, char &>, b))
+    return false;
+  return true;
+}
+static_assert (bar ());
diff --git a/gcc/testsuite/g++.dg/reflect/is_constructor_template1.C b/gcc/testsuite/g++.dg/reflect/is_constructor_template1.C
new file mode 100644 (file)
index 0000000..1ca6cb5
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_constructor_template.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename U>
+  T(int, const U &);
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto constructor_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (is_template)).front ();
+
+static_assert (!is_constructor_template (null_reflection));
+static_assert (!is_constructor_template (^^int));
+static_assert (!is_constructor_template (^^::));
+static_assert (!is_constructor_template (^^foo));
+static_assert (!is_constructor_template (^^S::operator+));
+static_assert (!is_constructor_template (^^operator&&));
+static_assert (!is_constructor_template (^^operator||));
+static_assert (!is_constructor_template (^^operator||<int>));
+static_assert (!is_constructor_template (^^S::operator-));
+static_assert (!is_constructor_template (^^S::operator-<int>));
+static_assert (!is_constructor_template (^^S::operator int));
+static_assert (is_constructor_template (constructor_template));
+static_assert (!is_constructor_template (^^S::fn));
+static_assert (!is_constructor_template (^^operator""_a));
+static_assert (!is_constructor_template (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_constuctor1.C b/gcc/testsuite/g++.dg/reflect/is_constuctor1.C
new file mode 100644 (file)
index 0000000..121285c
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_constructor.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (!is_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_constructor (null_reflection));
+static_assert (!is_constructor (^^int));
+static_assert (!is_constructor (^^::));
+static_assert (!is_constructor (^^foo));
+static_assert (!is_constructor (^^S::bar));
+static_assert (!is_constructor (^^S::operator =));
+static_assert (!is_constructor (^^S::operator +=));
+static_assert (!is_constructor (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_conversion_function1.C b/gcc/testsuite/g++.dg/reflect/is_conversion_function1.C
new file mode 100644 (file)
index 0000000..ef2a8b8
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_conversion_function.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename T>
+  operator T();
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto conversion_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (is_template)).front ();
+
+static_assert (!is_conversion_function (null_reflection));
+static_assert (!is_conversion_function (^^int));
+static_assert (!is_conversion_function (^^::));
+static_assert (!is_conversion_function (^^foo));
+static_assert (!is_conversion_function (^^S::operator+));
+static_assert (!is_conversion_function (^^operator&&));
+static_assert (!is_conversion_function (^^operator||));
+static_assert (!is_conversion_function (^^operator||<int>));
+static_assert (!is_conversion_function (^^S::operator-));
+static_assert (!is_conversion_function (^^S::operator-<int>));
+static_assert (is_conversion_function (^^S::operator int));
+static_assert (!is_conversion_function (conversion_template));
+static_assert (!is_conversion_function (^^S::fn));
+static_assert (!is_conversion_function (^^operator""_a));
+static_assert (!is_conversion_function (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_conversion_function_template1.C b/gcc/testsuite/g++.dg/reflect/is_conversion_function_template1.C
new file mode 100644 (file)
index 0000000..fa0daa1
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_conversion_function_template.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename T>
+  operator T ();
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto conversion_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (is_template)).front ();
+
+static_assert (!is_conversion_function_template (null_reflection));
+static_assert (!is_conversion_function_template (^^int));
+static_assert (!is_conversion_function_template (^^::));
+static_assert (!is_conversion_function_template (^^foo));
+static_assert (!is_conversion_function_template (^^S::operator+));
+static_assert (!is_conversion_function_template (^^operator&&));
+static_assert (!is_conversion_function_template (^^operator||));
+static_assert (!is_conversion_function_template (^^S::operator-));
+static_assert (!is_conversion_function_template (^^S::operator int));
+static_assert (is_conversion_function_template (conversion_template));
+static_assert (!is_conversion_function_template (^^S::fn));
+static_assert (!is_conversion_function_template (^^operator""_a));
+static_assert (!is_conversion_function_template (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_copy_assignment1.C b/gcc/testsuite/g++.dg/reflect/is_copy_assignment1.C
new file mode 100644 (file)
index 0000000..761ec41
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_copy_assignment.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (is_copy_assignment (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (!is_copy_assignment (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_copy_assignment (null_reflection));
+static_assert (!is_copy_assignment (^^int));
+static_assert (!is_copy_assignment (^^::));
+static_assert (!is_copy_assignment (^^foo));
+static_assert (!is_copy_assignment (^^S::bar));
+static_assert (is_copy_assignment (^^S::operator =));
+static_assert (!is_copy_assignment (^^S::operator +=));
+static_assert (!is_copy_assignment (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_copy_constructor1.C b/gcc/testsuite/g++.dg/reflect/is_copy_constructor1.C
new file mode 100644 (file)
index 0000000..1e90f0e
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_copy_constructor.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (is_copy_constructor (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (!is_copy_constructor (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_copy_constructor (null_reflection));
+static_assert (!is_copy_constructor (^^int));
+static_assert (!is_copy_constructor (^^::));
+static_assert (!is_copy_constructor (^^foo));
+static_assert (!is_copy_constructor (^^S::bar));
+static_assert (!is_copy_constructor (^^S::operator =));
+static_assert (!is_copy_constructor (^^S::operator +=));
+static_assert (!is_copy_constructor (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_data_member_spec1.C b/gcc/testsuite/g++.dg/reflect/is_data_member_spec1.C
new file mode 100644 (file)
index 0000000..60cc31c
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_data_member_spec.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_data_member_spec (null_reflection));
+static_assert (!is_data_member_spec (^^::));
+static_assert (!is_data_member_spec (^^ns));
+static_assert (!is_data_member_spec (^^ns_alias));
+static_assert (!is_data_member_spec (reflect_constant (3)));
+static_assert (!is_data_member_spec (^^cls));
+static_assert (!is_data_member_spec (^^cls::dm));
+static_assert (!is_data_member_spec (^^cls::ref_dm));
+static_assert (!is_data_member_spec (^^cls::static_dm));
+static_assert (!is_data_member_spec (^^cls::mem_fun));
+static_assert (!is_data_member_spec (^^cls::static_mem_fun));
+static_assert (!is_data_member_spec (^^cls::type));
+static_assert (!is_data_member_spec (^^cls_var));
+static_assert (!is_data_member_spec (^^onion));
+static_assert (!is_data_member_spec (^^anon));
+static_assert (!is_data_member_spec (^^fun));
+static_assert (!is_data_member_spec (^^alias));
+static_assert (!is_data_member_spec (^^var));
+static_assert (!is_data_member_spec (^^ref));
+static_assert (!is_data_member_spec (^^rref));
+static_assert (!is_data_member_spec (^^ptr));
+static_assert (!is_data_member_spec (^^cls_tmpl));
+static_assert (!is_data_member_spec (^^cls_tmpl<int>));
+static_assert (!is_data_member_spec (^^incomplete_cls<int>));
+static_assert (!is_data_member_spec (^^fun_tmpl));
+static_assert (!is_data_member_spec (^^fun_tmpl<int>));
+static_assert (!is_data_member_spec (^^conc));
+static_assert (!is_data_member_spec (substitute (^^conc, { ^^int })));
+static_assert (!is_data_member_spec (^^var_tmpl));
+static_assert (!is_data_member_spec (^^var_tmpl<int>));
+static_assert (!is_data_member_spec (^^cls_tmpl_alias));
+static_assert (!is_data_member_spec (^^cls_tmpl_alias<int>));
+static_assert (!is_data_member_spec (^^Enum));
+static_assert (!is_data_member_spec (^^Enum::A));
+static_assert (!is_data_member_spec (^^Enum_class));
+static_assert (!is_data_member_spec (^^Enum_class::A));
+static_assert (!is_data_member_spec (^^decomp));
+static_assert (!is_data_member_spec (^^decomp_ref));
+static_assert (!is_data_member_spec (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (is_data_member_spec (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_data_member_spec (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_data_member_spec (^^T));
+  static_assert (!is_data_member_spec (R));
+  static_assert (!is_data_member_spec (R2));
+  static_assert (!is_data_member_spec (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_data_member_spec (^^p));
+  static_assert (!is_data_member_spec (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_default_constructor1.C b/gcc/testsuite/g++.dg/reflect/is_default_constructor1.C
new file mode 100644 (file)
index 0000000..72e376e
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_default_constructor.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (is_default_constructor (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (!is_default_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (is_default_constructor (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_default_constructor (null_reflection));
+static_assert (!is_default_constructor (^^int));
+static_assert (!is_default_constructor (^^::));
+static_assert (!is_default_constructor (^^foo));
+static_assert (!is_default_constructor (^^S::bar));
+static_assert (!is_default_constructor (^^S::operator =));
+static_assert (!is_default_constructor (^^S::operator +=));
+static_assert (!is_default_constructor (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_defaulted1.C b/gcc/testsuite/g++.dg/reflect/is_defaulted1.C
new file mode 100644 (file)
index 0000000..5ce5ee1
--- /dev/null
@@ -0,0 +1,169 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_defaulted.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_defaulted (null_reflection));
+static_assert (!is_defaulted (^^::));
+static_assert (!is_defaulted (^^ns));
+static_assert (!is_defaulted (^^ns_alias));
+static_assert (!is_defaulted (reflect_constant (3)));
+static_assert (!is_defaulted (^^cls));
+static_assert (!is_defaulted (^^cls::dm));
+static_assert (!is_defaulted (^^cls::ref_dm));
+static_assert (!is_defaulted (^^cls::static_dm));
+static_assert (!is_defaulted (^^cls::mem_fun));
+static_assert (!is_defaulted (^^cls::static_mem_fun));
+static_assert (!is_defaulted (^^cls::type));
+static_assert (!is_defaulted (^^cls::E));
+static_assert (!is_defaulted (^^cls::B));
+static_assert (!is_defaulted (^^cls::C));
+static_assert (!is_defaulted (^^cls::D));
+static_assert (!is_defaulted (^^cls::F));
+static_assert (!is_defaulted (^^cls::F::G));
+static_assert (!is_defaulted (^^cls::F::H));
+static_assert (!is_defaulted (^^cls::S));
+static_assert (!is_defaulted (^^cls::U));
+static_assert (!is_defaulted (^^cls::foo));
+static_assert (!is_defaulted (^^cls::foo <0>));
+static_assert (!is_defaulted (^^cls::bar));
+static_assert (!is_defaulted (^^cls::bar <42>));
+static_assert (!is_defaulted (^^cls_var));
+static_assert (!is_defaulted (^^onion));
+static_assert (!is_defaulted (^^anon));
+static_assert (!is_defaulted (^^fun));
+static_assert (!is_defaulted (^^alias));
+static_assert (!is_defaulted (^^var));
+static_assert (!is_defaulted (^^ref));
+static_assert (!is_defaulted (^^rref));
+static_assert (!is_defaulted (^^ptr));
+static_assert (!is_defaulted (^^cls_tmpl));
+static_assert (!is_defaulted (^^cls_tmpl<int>));
+static_assert (!is_defaulted (^^incomplete_cls<int>));
+static_assert (!is_defaulted (^^fun_tmpl));
+static_assert (!is_defaulted (^^fun_tmpl<int>));
+static_assert (!is_defaulted (^^conc));
+static_assert (!is_defaulted (substitute (^^conc, { ^^int })));
+static_assert (!is_defaulted (^^var_tmpl));
+static_assert (!is_defaulted (^^var_tmpl<int>));
+static_assert (!is_defaulted (^^cls_tmpl_alias));
+static_assert (!is_defaulted (^^cls_tmpl_alias<int>));
+static_assert (!is_defaulted (^^Enum));
+static_assert (!is_defaulted (^^Enum::A));
+static_assert (!is_defaulted (^^Enum_class));
+static_assert (!is_defaulted (^^Enum_class::A));
+static_assert (!is_defaulted (^^decomp));
+static_assert (!is_defaulted (^^decomp_ref));
+static_assert (!is_defaulted (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_defaulted (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_defaulted (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_defaulted (^^x));
+  static_assert (!is_defaulted (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_defaulted (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_defaulted (^^S));
+  static_assert (!is_defaulted (^^E));
+  static_assert (!is_defaulted (^^F));
+  static_assert (!is_defaulted (^^G));
+}
+
+void bar (int, long) = delete;
+void baz (int) = delete ("foobar");
+static_assert (!is_defaulted (^^bar));
+static_assert (!is_defaulted (^^baz));
+
+struct S
+{
+  bool operator == (const S &) const = default;
+  auto operator <=> (const S &) const = default;
+  S &operator = (const S &) = default;
+  int s;
+  void foo ();
+  template <int N>
+  void bar ();
+};
+
+struct V
+{
+  V (const V &);
+};
+
+static_assert (is_defaulted (^^S::operator <=>));
+static_assert (is_defaulted (^^S::operator <=>));
+static_assert (is_defaulted (^^S::operator =));
+static_assert (!is_defaulted (^^S::foo));
+static_assert (!is_defaulted (^^S::bar));
+static_assert (!is_defaulted (^^S::bar <42>));
+static_assert (is_defaulted (^^V::operator =));
+
+struct W
+{
+  ~W () = default;
+  int w;
+};
+static_assert (is_defaulted (^^W::~W));
+
+struct X
+{
+  int x;
+};
+static_assert (is_defaulted (^^X::~X));
diff --git a/gcc/testsuite/g++.dg/reflect/is_defaulted2.C b/gcc/testsuite/g++.dg/reflect/is_defaulted2.C
new file mode 100644 (file)
index 0000000..7aa45e7
--- /dev/null
@@ -0,0 +1,64 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_deleted.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template<typename F>
+consteval info
+select_mem(info clazz, F f)
+{
+  for (info x : members_of(clazz, access_context::unchecked()))
+    if (f(x))
+      return x;
+}
+
+struct ExplicitDef
+{
+  ExplicitDef() = default;
+  ExplicitDef(const ExplicitDef&) = default;
+  ExplicitDef(ExplicitDef&&) = default;
+
+  ExplicitDef& operator=(const ExplicitDef&) = default;
+  ExplicitDef& operator=(ExplicitDef&&) = default;
+  
+  ~ExplicitDef() = default;
+};
+
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_default_constructor)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_copy_constructor)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_move_constructor)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_copy_assignment)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_move_assignment)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_destructor)));
+
+struct ImplicitDef
+{
+};
+
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_default_constructor)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_copy_constructor)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_move_constructor)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_copy_assignment)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_move_assignment)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_destructor)));
+
+struct ExplicitRelOps
+{
+  bool operator==(const ExplicitRelOps&) const = default;
+  auto operator<=>(const ExplicitRelOps&) const = default;
+};
+static_assert (is_defaulted (^^ExplicitRelOps::operator==));
+static_assert (is_defaulted (^^ExplicitRelOps::operator<=>));
+
+struct ImplicitRelOps
+{
+  // operator== is implicitly declared
+  auto operator<=>(const ImplicitRelOps&) const = default;
+};
+static_assert (is_defaulted (^^ImplicitRelOps::operator==));
+static_assert (is_defaulted (^^ImplicitRelOps::operator<=>));
+
diff --git a/gcc/testsuite/g++.dg/reflect/is_deleted1.C b/gcc/testsuite/g++.dg/reflect/is_deleted1.C
new file mode 100644 (file)
index 0000000..c75a043
--- /dev/null
@@ -0,0 +1,154 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_deleted.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_deleted (null_reflection));
+static_assert (!is_deleted (^^::));
+static_assert (!is_deleted (^^ns));
+static_assert (!is_deleted (^^ns_alias));
+static_assert (!is_deleted (reflect_constant (3)));
+static_assert (!is_deleted (^^cls));
+static_assert (!is_deleted (^^cls::dm));
+static_assert (!is_deleted (^^cls::ref_dm));
+static_assert (!is_deleted (^^cls::static_dm));
+static_assert (!is_deleted (^^cls::mem_fun));
+static_assert (!is_deleted (^^cls::static_mem_fun));
+static_assert (!is_deleted (^^cls::type));
+static_assert (!is_deleted (^^cls::E));
+static_assert (!is_deleted (^^cls::B));
+static_assert (!is_deleted (^^cls::C));
+static_assert (!is_deleted (^^cls::D));
+static_assert (!is_deleted (^^cls::F));
+static_assert (!is_deleted (^^cls::F::G));
+static_assert (!is_deleted (^^cls::F::H));
+static_assert (!is_deleted (^^cls::S));
+static_assert (!is_deleted (^^cls::U));
+static_assert (!is_deleted (^^cls::foo));
+static_assert (!is_deleted (^^cls::foo <0>));
+static_assert (!is_deleted (^^cls::bar));
+static_assert (!is_deleted (^^cls::bar <42>));
+static_assert (!is_deleted (^^cls_var));
+static_assert (!is_deleted (^^onion));
+static_assert (!is_deleted (^^anon));
+static_assert (!is_deleted (^^fun));
+static_assert (!is_deleted (^^alias));
+static_assert (!is_deleted (^^var));
+static_assert (!is_deleted (^^ref));
+static_assert (!is_deleted (^^rref));
+static_assert (!is_deleted (^^ptr));
+static_assert (!is_deleted (^^cls_tmpl));
+static_assert (!is_deleted (^^cls_tmpl<int>));
+static_assert (!is_deleted (^^incomplete_cls<int>));
+static_assert (!is_deleted (^^fun_tmpl));
+static_assert (!is_deleted (^^fun_tmpl<int>));
+static_assert (!is_deleted (^^conc));
+static_assert (!is_deleted (substitute (^^conc, { ^^int })));
+static_assert (!is_deleted (^^var_tmpl));
+static_assert (!is_deleted (^^var_tmpl<int>));
+static_assert (!is_deleted (^^cls_tmpl_alias));
+static_assert (!is_deleted (^^cls_tmpl_alias<int>));
+static_assert (!is_deleted (^^Enum));
+static_assert (!is_deleted (^^Enum::A));
+static_assert (!is_deleted (^^Enum_class));
+static_assert (!is_deleted (^^Enum_class::A));
+static_assert (!is_deleted (^^decomp));
+static_assert (!is_deleted (^^decomp_ref));
+static_assert (!is_deleted (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = u8"dms" });
+static_assert (!is_deleted (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_deleted (bases_of (^^Derived, access_context::unprivileged ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_deleted (^^x));
+  static_assert (!is_deleted (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_deleted (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_deleted (^^S));
+  static_assert (!is_deleted (^^E));
+  static_assert (!is_deleted (^^F));
+  static_assert (!is_deleted (^^G));
+}
+
+void bar (int, long) = delete;
+void baz (int) = delete ("foobar");
+static_assert (is_deleted (^^bar));
+static_assert (is_deleted (^^baz));
+
+struct S
+{
+  S (const int &x) : s (x) {}
+  auto operator <=> (const S &) const = default;
+  const int &s;
+  void foo () = delete;
+  template <int N>
+  void bar () = delete;
+};
+S s1 = 42;
+S s2 = 43;
+auto s3 = s1 <=> s2; // { dg-error "use of deleted function" }
+static_assert (is_deleted (^^S::operator <=>));
+static_assert (is_deleted (^^S::foo));
+static_assert (!is_deleted (^^S::bar));
+
+struct W
+{
+  ~W () = delete;
+};
+static_assert (is_deleted (^^W::~W));
diff --git a/gcc/testsuite/g++.dg/reflect/is_deleted2.C b/gcc/testsuite/g++.dg/reflect/is_deleted2.C
new file mode 100644 (file)
index 0000000..2eff030
--- /dev/null
@@ -0,0 +1,89 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_deleted.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+struct Del {
+  Del() = delete;
+  Del(Del&&) = delete;
+  ~Del() = delete;
+};
+
+template<typename F>
+consteval info
+select_mem(info clazz, F f)
+{
+  for (info x : members_of(clazz, access_context::unchecked()))
+    if (f(x))
+      return x;
+}
+
+struct ExplicitDef
+{
+  ExplicitDef() = default;
+  ExplicitDef(const ExplicitDef&) = default;
+  ExplicitDef(ExplicitDef&&) = default;
+
+  ExplicitDef& operator=(const ExplicitDef&) = default;
+  ExplicitDef& operator=(ExplicitDef&&) = default;
+  
+  ~ExplicitDef() = default;
+
+  Del d;
+};
+
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_default_constructor)));
+static_assert (is_deleted (select_mem (^^ExplicitDef, is_default_constructor)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_copy_constructor)));
+static_assert (is_deleted (select_mem (^^ExplicitDef, is_copy_constructor)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_move_constructor)));
+static_assert (is_deleted (select_mem (^^ExplicitDef, is_move_constructor)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_copy_assignment)));
+static_assert (is_deleted (select_mem (^^ExplicitDef, is_copy_assignment)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_move_assignment)));
+static_assert (is_deleted (select_mem (^^ExplicitDef, is_move_assignment)));
+static_assert (is_defaulted (select_mem (^^ExplicitDef, is_destructor)));
+static_assert (is_deleted (select_mem (^^ExplicitDef, is_destructor)));
+
+struct ImplicitDef
+{
+  Del d;
+};
+
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_default_constructor)));
+static_assert (is_deleted (select_mem (^^ImplicitDef, is_default_constructor)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_copy_constructor)));
+static_assert (is_deleted (select_mem (^^ImplicitDef, is_copy_constructor)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_move_constructor)));
+static_assert (is_deleted (select_mem (^^ImplicitDef, is_move_constructor)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_copy_assignment)));
+static_assert (is_deleted (select_mem (^^ImplicitDef, is_copy_assignment)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_move_assignment)));
+static_assert (is_deleted (select_mem (^^ImplicitDef, is_move_assignment)));
+static_assert (is_defaulted (select_mem (^^ImplicitDef, is_destructor)));
+static_assert (is_deleted (select_mem (^^ImplicitDef, is_destructor)));
+
+template<typename T>
+concept check_rel_ops = requires(T t) {
+  t <=> t;
+  t == t;
+};
+
+struct RelOpsDel
+{
+  int& x;
+
+  // deleted because of reference member
+  auto operator<=>(const RelOpsDel&) const = default;
+};
+static_assert (is_deleted (^^RelOpsDel::operator<=>));
+static_assert (!check_rel_ops<RelOpsDel>);
+
+static_assert (is_defaulted (^^RelOpsDel::operator==));
+static_assert (is_deleted (^^RelOpsDel::operator==));
+static_assert (is_defaulted (^^RelOpsDel::operator<=>));
+static_assert (is_deleted (^^RelOpsDel::operator<=>));
diff --git a/gcc/testsuite/g++.dg/reflect/is_destructor1.C b/gcc/testsuite/g++.dg/reflect/is_destructor1.C
new file mode 100644 (file)
index 0000000..f431b5c
--- /dev/null
@@ -0,0 +1,124 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_destructor.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (is_destructor (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (!is_destructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (!is_destructor (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_destructor (null_reflection));
+static_assert (!is_destructor (^^int));
+static_assert (!is_destructor (^^::));
+static_assert (!is_destructor (^^foo));
+static_assert (!is_destructor (^^S::bar));
+static_assert (!is_destructor (^^S::operator =));
+static_assert (!is_destructor (^^S::operator +=));
+static_assert (!is_destructor (^^T::operator *=));
+
+struct W {};
+static_assert (is_destructor (^^W::~W));
+
+struct X 
+{
+  ~X () = default;
+};
+static_assert (is_destructor (^^X::~X));
+
+struct Y
+{
+  ~Y () = delete;
+};
+static_assert (is_destructor (^^Y::~Y));
+
+struct Z
+{
+  ~Z () {}
+};
+static_assert (is_destructor (^^Z::~Z));
+
+
diff --git a/gcc/testsuite/g++.dg/reflect/is_enumerable_type1.C b/gcc/testsuite/g++.dg/reflect/is_enumerable_type1.C
new file mode 100644 (file)
index 0000000..4af92bc
--- /dev/null
@@ -0,0 +1,106 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_enumerable_type.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+static_assert (!is_enumerable_type (null_reflection));
+static_assert (!is_enumerable_type (^^int));
+static_assert (!is_enumerable_type (^^::));
+static_assert (!is_enumerable_type (^^foo));
+
+class S;
+enum class E;
+typedef E TE;
+static_assert (!is_enumerable_type (^^S));
+static_assert (!is_enumerable_type (^^E));
+static_assert (!is_enumerable_type (^^TE));
+
+template<typename> struct cls_tmpl {};
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+static_assert (!is_enumerable_type (^^cls_tmpl));
+static_assert (is_enumerable_type (^^cls_tmpl<int>));
+static_assert (!is_enumerable_type (^^cls_tmpl_alias));
+static_assert (is_enumerable_type (^^cls_tmpl_alias<int>));
+
+class S {
+  void foo ()
+  {
+    static_assert (is_enumerable_type (^^S));
+  }
+  static_assert (!is_enumerable_type (^^S));
+};
+static_assert (is_enumerable_type (^^S));
+
+enum class E {
+  A = (is_enumerable_type (^^E) || is_enumerable_type (^^TE)) ? 1 : 2
+};
+static_assert (is_enumerable_type (^^E));
+static_assert (static_cast <int> (E::A) == 2);
+static_assert (is_enumerable_type (^^TE));
+
+enum F : int;
+using TF = F;
+static_assert (!is_enumerable_type (^^F));
+static_assert (!is_enumerable_type (^^TF));
+enum F : int {
+  B = (is_enumerable_type (^^F) || is_enumerable_type (^^TF)) ? 3 : 4
+};
+static_assert (is_enumerable_type (^^F));
+static_assert (B == 4);
+static_assert (is_enumerable_type (^^TF));
+
+enum G {
+  C = is_enumerable_type (^^G) ? 5 : 6
+};
+static_assert (is_enumerable_type (^^G));
+static_assert (C == 6);
+
+enum H : int;
+typedef H TH;
+static_assert (!is_enumerable_type (^^H));
+static_assert (!is_enumerable_type (^^TH));
+
+enum H : int {};
+static_assert (is_enumerable_type (^^H));
+static_assert (is_enumerable_type (^^TH));
+
+enum I : short;
+using TI = I;
+static_assert (!is_enumerable_type (^^I));
+static_assert (!is_enumerable_type (^^TI));
+enum I : short {};
+static_assert (is_enumerable_type (^^I));
+static_assert (is_enumerable_type (^^TI));
+
+template <typename T>
+void
+qux ()
+{
+  enum J : T;
+  using K = J;
+  // FIXME: No idea if this is supposed to be false or true.
+  // We certainly during instantiation don't differentiate between
+  // forward enum declarations and later definitions.
+  //  static_assert (!is_enumerable_type (^^J));
+  //  static_assert (!is_enumerable_type (^^K));
+  enum J : T {
+    D = (is_enumerable_type (^^J) || is_enumerable_type (^^K))
+       ? sizeof (T) * 2 : sizeof (T)
+  };
+  static_assert (is_enumerable_type (^^J));
+  static_assert (D == sizeof (T));
+  static_assert (is_enumerable_type (^^K));
+}
+
+void
+corge ()
+{
+  qux <int> ();
+  qux <unsigned char> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_enumerator1.C b/gcc/testsuite/g++.dg/reflect/is_enumerator1.C
new file mode 100644 (file)
index 0000000..538e2e4
--- /dev/null
@@ -0,0 +1,107 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_enumerator.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_enumerator (null_reflection));
+static_assert (!is_enumerator (^^::));
+static_assert (!is_enumerator (^^ns));
+static_assert (!is_enumerator (^^ns_alias));
+static_assert (!is_enumerator (reflect_constant (3)));
+static_assert (!is_enumerator (^^cls));
+static_assert (!is_enumerator (^^cls::dm));
+static_assert (!is_enumerator (^^cls::ref_dm));
+static_assert (!is_enumerator (^^cls::static_dm));
+static_assert (!is_enumerator (^^cls::mem_fun));
+static_assert (!is_enumerator (^^cls::static_mem_fun));
+static_assert (!is_enumerator (^^cls::type));
+static_assert (!is_enumerator (^^cls_var));
+static_assert (!is_enumerator (^^onion));
+static_assert (!is_enumerator (^^anon));
+static_assert (!is_enumerator (^^fun));
+static_assert (!is_enumerator (^^alias));
+static_assert (!is_enumerator (^^var));
+static_assert (!is_enumerator (^^ref));
+static_assert (!is_enumerator (^^rref));
+static_assert (!is_enumerator (^^ptr));
+static_assert (!is_enumerator (^^cls_tmpl));
+static_assert (!is_enumerator (^^cls_tmpl<int>));
+static_assert (!is_enumerator (^^incomplete_cls<int>));
+static_assert (!is_enumerator (^^fun_tmpl));
+static_assert (!is_enumerator (^^fun_tmpl<int>));
+static_assert (!is_enumerator (^^conc));
+static_assert (!is_enumerator (substitute (^^conc, { ^^int })));
+static_assert (!is_enumerator (^^var_tmpl));
+static_assert (!is_enumerator (^^var_tmpl<int>));
+static_assert (!is_enumerator (^^cls_tmpl_alias));
+static_assert (!is_enumerator (^^cls_tmpl_alias<int>));
+static_assert (!is_enumerator (^^Enum));
+static_assert (is_enumerator (^^Enum::A));
+static_assert (!is_enumerator (^^Enum_class));
+static_assert (is_enumerator (^^Enum_class::A));
+static_assert (!is_enumerator (^^decomp));
+static_assert (!is_enumerator (^^decomp_ref));
+static_assert (!is_enumerator (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_enumerator (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_enumerator (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_enumerator (^^T));
+  static_assert (!is_enumerator (R));
+  static_assert (is_enumerator (R2));
+  static_assert (is_enumerator (R3));
+}
+
+void
+g (int p, cls c, Enum e, Enum_class ec)
+{
+  f<int, ^^var, ^^Enum::A, ^^Enum_class::A>();
+  static_assert (!is_enumerator (^^p));
+  static_assert (!is_enumerator (^^c));
+  static_assert (!is_enumerator (^^e));
+  static_assert (!is_enumerator (^^ec));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_explicit1.C b/gcc/testsuite/g++.dg/reflect/is_explicit1.C
new file mode 100644 (file)
index 0000000..3afcc5b
--- /dev/null
@@ -0,0 +1,72 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_explicit.
+
+#include <meta>
+
+class Test {
+public:
+    explicit Test(int) 
+    {
+        int a;
+        static_assert (std::meta::is_explicit (std::meta::parent_of (^^a)));
+    }
+
+    Test(double) 
+    {
+        int a;
+        static_assert (!std::meta::is_explicit (std::meta::parent_of (^^a)));
+    }
+
+    explicit operator bool();
+
+    operator int();
+
+    template<typename T>
+    explicit operator double();
+    
+    void member_function();
+
+    virtual void virtual_function();
+
+    template <typename T>
+    void template_function(T param);
+};
+
+void function();
+
+static_assert (std::meta::is_explicit (^^Test::Test)); // { dg-error "cannot take the reflection of an overload set" }
+static_assert (!std::meta::is_explicit (^^Test::~Test));
+
+static_assert (std::meta::is_explicit (^^Test::operator bool));
+static_assert (!std::meta::is_explicit (^^Test::operator int));
+static_assert (!std::meta::is_explicit (^^Test::operator double));
+
+static_assert (!std::meta::is_explicit (^^Test::member_function));
+static_assert (!std::meta::is_explicit (^^Test::virtual_function));
+static_assert (!std::meta::is_explicit (^^Test::template_function));
+static_assert (!std::meta::is_explicit (^^Test::template_function<int>));
+
+static_assert (!std::meta::is_explicit (^^function));
+static_assert (!std::meta::is_explicit (^^Test));
+static_assert (!std::meta::is_explicit (^^::));
+
+class Base {
+public:
+    explicit operator int();
+};
+
+class Derived : public Base {
+public:
+    explicit operator double();
+
+    operator bool();
+};
+
+static_assert (std::meta::is_explicit (^^Derived::operator int));
+static_assert (std::meta::is_explicit (^^Derived::operator double));
+static_assert (!std::meta::is_explicit (^^Derived::operator bool));
+
+class EmptyClass {};
+static_assert (!std::meta::is_explicit (^^EmptyClass::EmptyClass)); // { dg-error "cannot take the reflection of an overload set" }
+
diff --git a/gcc/testsuite/g++.dg/reflect/is_explicit2.C b/gcc/testsuite/g++.dg/reflect/is_explicit2.C
new file mode 100644 (file)
index 0000000..97f8297
--- /dev/null
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_explicit.
+
+#include <meta>
+using namespace std::meta;
+
+template<typename Fn>
+consteval info select(info clazz, Fn f)
+{
+  for (auto x : members_of(clazz, access_context::unchecked()))
+   if (f(x))
+     return x;
+}
+
+struct Implicit {
+  template<typename T>
+  Implicit(T&& t);
+
+  template<typename T>
+  operator T();
+};
+
+static_assert (!is_explicit (select(^^Implicit, is_constructor_template)));
+static_assert (!is_explicit (select(^^Implicit, is_conversion_function_template)));
+
+struct Explicit {
+  template<typename T>
+  explicit Explicit(T&& t);
+
+  template<typename T>
+  explicit operator T();
+};
+
+static_assert (!is_explicit (select(^^Explicit, is_constructor_template)));
+static_assert (!is_explicit (select(^^Explicit, is_conversion_function_template)));
+
+struct CondExplicit {
+  template<typename T>
+  explicit(sizeof(T) > 4) CondExplicit(T&& t);
+
+  template<typename T>
+  explicit(sizeof(T) > 4) operator T();
+};
+
+static_assert (!is_explicit (select(^^CondExplicit, is_constructor_template)));
+static_assert (!is_explicit (select(^^CondExplicit, is_conversion_function_template)));
diff --git a/gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C b/gcc/testsuite/g++.dg/reflect/is_explicit_object_parameter1.C
new file mode 100644 (file)
index 0000000..38e7e07
--- /dev/null
@@ -0,0 +1,165 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_explicit_object_parameter.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_explicit_object_parameter (null_reflection));
+static_assert (!is_explicit_object_parameter (^^::));
+static_assert (!is_explicit_object_parameter (^^ns));
+static_assert (!is_explicit_object_parameter (^^ns_alias));
+static_assert (!is_explicit_object_parameter (reflect_constant (3)));
+static_assert (!is_explicit_object_parameter (^^cls));
+static_assert (!is_explicit_object_parameter (^^cls::dm));
+static_assert (!is_explicit_object_parameter (^^cls::ref_dm));
+static_assert (!is_explicit_object_parameter (^^cls::static_dm));
+static_assert (!is_explicit_object_parameter (^^cls::mem_fun));
+static_assert (!is_explicit_object_parameter (^^cls::static_mem_fun));
+static_assert (!is_explicit_object_parameter (^^cls::type));
+static_assert (!is_explicit_object_parameter (^^cls_var));
+static_assert (!is_explicit_object_parameter (^^onion));
+static_assert (!is_explicit_object_parameter (^^anon));
+static_assert (!is_explicit_object_parameter (^^fun));
+static_assert (!is_explicit_object_parameter (^^alias));
+static_assert (!is_explicit_object_parameter (^^var));
+static_assert (!is_explicit_object_parameter (^^ref));
+static_assert (!is_explicit_object_parameter (^^rref));
+static_assert (!is_explicit_object_parameter (^^ptr));
+static_assert (!is_explicit_object_parameter (^^cls_tmpl));
+static_assert (!is_explicit_object_parameter (^^cls_tmpl<int>));
+static_assert (!is_explicit_object_parameter (^^incomplete_cls<int>));
+static_assert (!is_explicit_object_parameter (^^fun_tmpl));
+static_assert (!is_explicit_object_parameter (^^fun_tmpl<int>));
+static_assert (!is_explicit_object_parameter (^^conc));
+static_assert (!is_explicit_object_parameter (substitute (^^conc, { ^^int })));
+static_assert (!is_explicit_object_parameter (^^var_tmpl));
+static_assert (!is_explicit_object_parameter (^^var_tmpl<int>));
+static_assert (!is_explicit_object_parameter (^^cls_tmpl_alias));
+static_assert (!is_explicit_object_parameter (^^cls_tmpl_alias<int>));
+static_assert (!is_explicit_object_parameter (^^Enum));
+static_assert (!is_explicit_object_parameter (^^Enum::A));
+static_assert (!is_explicit_object_parameter (^^Enum_class));
+static_assert (!is_explicit_object_parameter (^^Enum_class::A));
+static_assert (!is_explicit_object_parameter (^^decomp));
+static_assert (!is_explicit_object_parameter (^^decomp_ref));
+static_assert (!is_explicit_object_parameter (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_explicit_object_parameter (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_explicit_object_parameter (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_explicit_object_parameter (^^T));
+  static_assert (!is_explicit_object_parameter (R));
+  static_assert (!is_explicit_object_parameter (R2));
+  static_assert (!is_explicit_object_parameter (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^p, ^^c> ();
+  static_assert (!is_explicit_object_parameter (^^p));
+  static_assert (!is_explicit_object_parameter (^^c));
+}
+
+struct S {
+  template<typename T, info R, info R2, info R3>
+  static void
+  f ()
+  {
+    static_assert (!is_explicit_object_parameter (^^T));
+    static_assert (!is_explicit_object_parameter (R));
+    static_assert (is_explicit_object_parameter (R2));
+    static_assert (!is_explicit_object_parameter (R3));
+  }
+
+  void
+  g (this const S &a, int b)
+  {
+    f<int, ^^var, parameters_of (^^S::g)[0], parameters_of (^^S::g)[1]> ();
+    static_assert (is_explicit_object_parameter (parameters_of (^^S::g)[0]));
+    static_assert (!is_explicit_object_parameter (parameters_of (^^S::g)[1]));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::g)[0])));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::g)[1])));
+    static_assert (!is_explicit_object_parameter (^^a));
+    static_assert (!is_explicit_object_parameter (^^b));
+  }
+
+  template<int N>
+  void
+  h (this S *a, long b)
+  {
+    static_assert (is_explicit_object_parameter (parameters_of (^^S::h <N>)[0]));
+    static_assert (!is_explicit_object_parameter (parameters_of (^^S::h <N>)[0]));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::h <N>)[0])));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::h <N>)[0])));
+    static_assert (!is_explicit_object_parameter (^^a));
+    static_assert (!is_explicit_object_parameter (^^b));
+  }
+
+  void
+  i (const S &a, int b)
+  {
+    ::f<int, ^^var, parameters_of (^^S::i)[0], parameters_of (^^S::i)[1]> ();
+    static_assert (!is_explicit_object_parameter (parameters_of (^^S::i)[0]));
+    static_assert (!is_explicit_object_parameter (parameters_of (^^S::i)[1]));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::i)[0])));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::i)[1])));
+    static_assert (!is_explicit_object_parameter (^^a));
+    static_assert (!is_explicit_object_parameter (^^b));
+  }
+
+  template<typename T>
+  void
+  j (const S *, int b)
+  {
+    ::f<int, ^^var, parameters_of (^^S::j <T>)[0], parameters_of (^^S::j <T>)[1]> ();
+    static_assert (!is_explicit_object_parameter (parameters_of (^^S::j <T>)[0]));
+    static_assert (!is_explicit_object_parameter (parameters_of (^^S::j <T>)[1]));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::j <T>)[0])));
+    static_assert (!is_explicit_object_parameter (variable_of (parameters_of (^^S::j <T>)[1])));
+    static_assert (!is_explicit_object_parameter (^^b));
+  }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/is_final1.C b/gcc/testsuite/g++.dg/reflect/is_final1.C
new file mode 100644 (file)
index 0000000..ed10c71
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_final.
+
+#include <meta>
+
+struct A {
+  virtual void foo();
+
+  virtual void bar() final;
+
+  virtual ~A() = default;
+};
+
+struct B final : A {
+  void foo() override;
+
+  ~B() final = default;
+};
+
+struct C : A {
+  void foo() final;
+};
+
+struct D final : A {
+  static_assert (is_final (^^D));
+};
+
+static_assert (!std::meta::is_final (^^A));
+static_assert (std::meta::is_final (^^B));
+static_assert (!std::meta::is_final (^^C));
+
+static_assert (!std::meta::is_final (^^A::foo));
+static_assert (!std::meta::is_final (^^B::foo));
+static_assert (std::meta::is_final (^^C::foo));
+
+static_assert (std::meta::is_final (^^A::bar));
+static_assert (std::meta::is_final (^^B::bar));
+static_assert (std::meta::is_final (^^C::bar));
+
+static_assert (!std::meta::is_final (^^A::~A));
+static_assert (std::meta::is_final (^^B::~B));
+static_assert (!std::meta::is_final (^^C::~C));
+
+A a;
+B b;
+C c;
+
+static_assert (!std::meta::is_final (^^::));
+static_assert (!std::meta::is_final (^^a));
+static_assert (!std::meta::is_final (^^b));
+static_assert (!std::meta::is_final (^^c));
+
+static_assert (!std::meta::is_final (std::meta::type_of (^^a)));
+static_assert (std::meta::is_final (std::meta::type_of (^^b)));
+static_assert (!std::meta::is_final (std::meta::type_of (^^c)));
diff --git a/gcc/testsuite/g++.dg/reflect/is_function1.C b/gcc/testsuite/g++.dg/reflect/is_function1.C
new file mode 100644 (file)
index 0000000..ff635b8
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_function (null_reflection));
+static_assert (!is_function (^^::));
+static_assert (!is_function (^^ns));
+static_assert (!is_function (^^ns_alias));
+static_assert (!is_function (reflect_constant (3)));
+static_assert (!is_function (^^cls));
+static_assert (!is_function (^^cls::dm));
+static_assert (!is_function (^^cls::ref_dm));
+static_assert (!is_function (^^cls::static_dm));
+static_assert (is_function (^^cls::mem_fun));
+static_assert (is_function (^^cls::static_mem_fun));
+static_assert (!is_function (^^cls::type));
+static_assert (!is_function (^^cls_var));
+static_assert (!is_function (^^onion));
+static_assert (!is_function (^^anon));
+static_assert (is_function (^^fun));
+static_assert (!is_function (^^alias));
+static_assert (!is_function (^^var));
+static_assert (!is_function (^^ref));
+static_assert (!is_function (^^rref));
+static_assert (!is_function (^^ptr));
+static_assert (!is_function (^^cls_tmpl));
+static_assert (!is_function (^^cls_tmpl<int>));
+static_assert (!is_function (^^incomplete_cls<int>));
+static_assert (!is_function (^^fun_tmpl));
+static_assert (is_function (^^fun_tmpl<int>));
+static_assert (!is_function (^^conc));
+static_assert (!is_function (substitute (^^conc, { ^^int })));
+static_assert (!is_function (^^var_tmpl));
+static_assert (!is_function (^^var_tmpl<int>));
+static_assert (!is_function (^^cls_tmpl_alias));
+static_assert (!is_function (^^cls_tmpl_alias<int>));
+static_assert (!is_function (^^Enum));
+static_assert (!is_function (^^Enum::A));
+static_assert (!is_function (^^Enum_class));
+static_assert (!is_function (^^Enum_class::A));
+static_assert (!is_function (^^decomp));
+static_assert (!is_function (^^decomp_ref));
+static_assert (!is_function (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_function (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_function (bases_of (^^Derived, access_context::unprivileged ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_function (^^T));
+  static_assert (!is_function (R));
+  static_assert (!is_function (R2));
+  static_assert (is_function (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^fun>();
+  static_assert (!is_function (^^p));
+  static_assert (!is_function (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_function2.C b/gcc/testsuite/g++.dg/reflect/is_function2.C
new file mode 100644 (file)
index 0000000..8bb0769
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  template<typename T>
+  void ovl (T) { }
+
+  template<typename T>
+  void static_ovl (T) { }
+};
+
+static_assert (!is_function (^^S::ovl));
+static_assert (is_function (^^S::ovl<int>));
+static_assert (!is_function (^^S::static_ovl));
+static_assert (is_function (^^S::static_ovl<int>));
+
+static_assert (!is_function (^^void()));
+
+template<info R1, info R2>
+void
+f ()
+{
+  static_assert (!is_function (R1));
+  static_assert (is_function (R2));
+}
+
+template<typename T>
+void
+g ()
+{
+  f<^^S::ovl, ^^S::ovl<T>>();
+  f<^^S::static_ovl, ^^S::static_ovl<T>>();
+}
+
+void
+h ()
+{
+  g<int>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_function3.C b/gcc/testsuite/g++.dg/reflect/is_function3.C
new file mode 100644 (file)
index 0000000..1613e1b
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  S();
+  ~S();
+};
+
+static_assert (is_function (^^S::S)); // { dg-error "cannot take the reflection of an overload set" }
+static_assert (is_function (^^S::~S));
diff --git a/gcc/testsuite/g++.dg/reflect/is_function_parameter1.C b/gcc/testsuite/g++.dg/reflect/is_function_parameter1.C
new file mode 100644 (file)
index 0000000..c5116c4
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function_parameter.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_function_parameter (null_reflection));
+static_assert (!is_function_parameter (^^::));
+static_assert (!is_function_parameter (^^ns));
+static_assert (!is_function_parameter (^^ns_alias));
+static_assert (!is_function_parameter (reflect_constant (3)));
+static_assert (!is_function_parameter (^^cls));
+static_assert (!is_function_parameter (^^cls::dm));
+static_assert (!is_function_parameter (^^cls::ref_dm));
+static_assert (!is_function_parameter (^^cls::static_dm));
+static_assert (!is_function_parameter (^^cls::mem_fun));
+static_assert (!is_function_parameter (^^cls::static_mem_fun));
+static_assert (!is_function_parameter (^^cls::type));
+static_assert (!is_function_parameter (^^cls_var));
+static_assert (!is_function_parameter (^^onion));
+static_assert (!is_function_parameter (^^anon));
+static_assert (!is_function_parameter (^^fun));
+static_assert (!is_function_parameter (^^alias));
+static_assert (!is_function_parameter (^^var));
+static_assert (!is_function_parameter (^^ref));
+static_assert (!is_function_parameter (^^rref));
+static_assert (!is_function_parameter (^^ptr));
+static_assert (!is_function_parameter (^^cls_tmpl));
+static_assert (!is_function_parameter (^^cls_tmpl<int>));
+static_assert (!is_function_parameter (^^incomplete_cls<int>));
+static_assert (!is_function_parameter (^^fun_tmpl));
+static_assert (!is_function_parameter (^^fun_tmpl<int>));
+static_assert (!is_function_parameter (^^conc));
+static_assert (!is_function_parameter (substitute (^^conc, { ^^int })));
+static_assert (!is_function_parameter (^^var_tmpl));
+static_assert (!is_function_parameter (^^var_tmpl<int>));
+static_assert (!is_function_parameter (^^cls_tmpl_alias));
+static_assert (!is_function_parameter (^^cls_tmpl_alias<int>));
+static_assert (!is_function_parameter (^^Enum));
+static_assert (!is_function_parameter (^^Enum::A));
+static_assert (!is_function_parameter (^^Enum_class));
+static_assert (!is_function_parameter (^^Enum_class::A));
+static_assert (!is_function_parameter (^^decomp));
+static_assert (!is_function_parameter (^^decomp_ref));
+static_assert (!is_function_parameter (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_function_parameter (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_function_parameter (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_function_parameter (^^T));
+  static_assert (!is_function_parameter (R));
+  static_assert (!is_function_parameter (R2));
+  static_assert (!is_function_parameter (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^p, ^^c>();
+  static_assert (!is_function_parameter (^^p));
+  static_assert (!is_function_parameter (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_function_parameter2.C b/gcc/testsuite/g++.dg/reflect/is_function_parameter2.C
new file mode 100644 (file)
index 0000000..e627df1
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function_parameter.
+
+#include <meta>
+
+using namespace std::meta;
+
+void fn (int a, bool &b, std::string *, ...);
+
+static_assert (is_function_parameter (parameters_of(^^fn)[0]));
+static_assert (is_function_parameter (parameters_of(^^fn)[1]));
+static_assert (is_function_parameter (parameters_of(^^fn)[2]));
diff --git a/gcc/testsuite/g++.dg/reflect/is_function_template1.C b/gcc/testsuite/g++.dg/reflect/is_function_template1.C
new file mode 100644 (file)
index 0000000..bdefc7e
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function_template.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_function_template (null_reflection));
+static_assert (!is_function_template (^^::));
+static_assert (!is_function_template (^^ns));
+static_assert (!is_function_template (^^ns_alias));
+static_assert (!is_function_template (reflect_constant (3)));
+static_assert (!is_function_template (^^cls));
+static_assert (!is_function_template (^^cls::dm));
+static_assert (!is_function_template (^^cls::ref_dm));
+static_assert (!is_function_template (^^cls::static_dm));
+static_assert (!is_function_template (^^cls::mem_fun));
+static_assert (!is_function_template (^^cls::static_mem_fun));
+static_assert (!is_function_template (^^cls::type));
+static_assert (!is_function_template (^^cls_var));
+static_assert (!is_function_template (^^onion));
+static_assert (!is_function_template (^^anon));
+static_assert (!is_function_template (^^fun));
+static_assert (!is_function_template (^^alias));
+static_assert (!is_function_template (^^var));
+static_assert (!is_function_template (^^ref));
+static_assert (!is_function_template (^^rref));
+static_assert (!is_function_template (^^ptr));
+static_assert (!is_function_template (^^cls_tmpl));
+static_assert (!is_function_template (^^cls_tmpl<int>));
+static_assert (!is_function_template (^^incomplete_cls<int>));
+static_assert (is_function_template (^^fun_tmpl));
+static_assert (!is_function_template (^^fun_tmpl<int>));
+static_assert (!is_function_template (^^conc));
+static_assert (!is_function_template (substitute (^^conc, { ^^int })));
+static_assert (!is_function_template (^^var_tmpl));
+static_assert (!is_function_template (^^var_tmpl<int>));
+static_assert (!is_function_template (^^cls_tmpl_alias));
+static_assert (!is_function_template (^^cls_tmpl_alias<int>));
+static_assert (!is_function_template (^^Enum));
+static_assert (!is_function_template (^^Enum::A));
+static_assert (!is_function_template (^^Enum_class));
+static_assert (!is_function_template (^^Enum_class::A));
+static_assert (!is_function_template (^^decomp));
+static_assert (!is_function_template (^^decomp_ref));
+static_assert (!is_function_template (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_function_template (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_function_template (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_function_template (^^T));
+  static_assert (!is_function_template (R));
+  static_assert (!is_function_template (R2));
+  static_assert (is_function_template (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^fun_tmpl>();
+  static_assert (!is_function_template (^^p));
+  static_assert (!is_function_template (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_function_template2.C b/gcc/testsuite/g++.dg/reflect/is_function_template2.C
new file mode 100644 (file)
index 0000000..e104cf5
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function_template.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  template<typename T>
+  void ovl (T) { }
+
+  template<typename T>
+  void static_ovl (T) { }
+};
+
+static_assert (is_function_template (^^S::ovl));
+static_assert (!is_function_template (^^S::ovl<int>));
+static_assert (is_function_template (^^S::static_ovl));
+static_assert (!is_function_template (^^S::static_ovl<int>));
+
+static_assert (!is_function_template (^^void()));
+
+template<info R1, info R2>
+void
+f ()
+{
+  static_assert (is_function_template (R1));
+  static_assert (!is_function_template (R2));
+}
+
+template<typename T>
+void
+g ()
+{
+  f<^^S::ovl, ^^S::ovl<T>>();
+  f<^^S::static_ovl, ^^S::static_ovl<T>>();
+}
+
+void
+h ()
+{
+  g<int>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_function_type1.C b/gcc/testsuite/g++.dg/reflect/is_function_type1.C
new file mode 100644 (file)
index 0000000..f8d07e3
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_function_type.
+
+#include <meta>
+using namespace std::meta;
+
+struct cls {
+  void mem_fun ();
+  static void static_mem_fun ();
+};
+int fun (bool, char) noexcept { return 0; }
+
+static_assert (is_function_type (type_of (^^cls::mem_fun)));
+static_assert (is_function_type (type_of (^^cls::static_mem_fun)));
+static_assert (is_function_type (type_of (^^::fun)));
+static_assert (!is_function_type (^^void(*)(short)));
+static_assert (is_function_type (remove_pointer (^^void(*)(short))));
+static_assert (!is_function_type (remove_pointer (^^void(**)(short))));
+static_assert (is_function_type (remove_pointer (remove_pointer (^^void(**)(short)))));
+static_assert (!is_function_type (^^void(&)()));
+static_assert (is_function_type (remove_reference (^^void(&)())));
+using U = void(*)(void);
+static_assert (!is_function_type (^^U[3]));
+static_assert (is_function_type (remove_pointer (remove_extent (^^U[3]))));
+static_assert (!is_function_type (remove_pointer (^^int (cls::*)())));
diff --git a/gcc/testsuite/g++.dg/reflect/is_literal_operator1.C b/gcc/testsuite/g++.dg/reflect/is_literal_operator1.C
new file mode 100644 (file)
index 0000000..0d180ae
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_literal_operator.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename T>
+  operator T();
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto conversion_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (std::meta::is_template)).front ();
+
+static_assert (!is_literal_operator (null_reflection));
+static_assert (!is_literal_operator (^^int));
+static_assert (!is_literal_operator (^^::));
+static_assert (!is_literal_operator (^^foo));
+static_assert (!is_literal_operator (^^S::operator+));
+static_assert (!is_literal_operator (^^operator&&));
+static_assert (!is_literal_operator (^^operator||));
+static_assert (!is_literal_operator (^^operator||<int>));
+static_assert (!is_literal_operator (^^S::operator-));
+static_assert (!is_literal_operator (^^S::operator-<int>));
+static_assert (!is_literal_operator (^^S::operator int));
+static_assert (!is_literal_operator (conversion_template));
+static_assert (!is_literal_operator (^^S::fn));
+static_assert (is_literal_operator (^^operator""_a));
+static_assert (!is_literal_operator (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_literal_operator_template1.C b/gcc/testsuite/g++.dg/reflect/is_literal_operator_template1.C
new file mode 100644 (file)
index 0000000..a6bd410
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_literal_operator_template.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename T>
+  operator T();
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto conversion_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (is_template)).front ();
+
+static_assert (!is_literal_operator_template (null_reflection));
+static_assert (!is_literal_operator_template (^^int));
+static_assert (!is_literal_operator_template (^^::));
+static_assert (!is_literal_operator_template (^^foo));
+static_assert (!is_literal_operator_template (^^S::operator+));
+static_assert (!is_literal_operator_template (^^operator&&));
+static_assert (!is_literal_operator_template (^^operator||));
+static_assert (!is_literal_operator_template (^^operator||<int>));
+static_assert (!is_literal_operator_template (^^S::operator-));
+static_assert (!is_literal_operator_template (^^S::operator-<int>));
+static_assert (!is_literal_operator_template (^^S::operator int));
+static_assert (!is_literal_operator_template (conversion_template));
+static_assert (!is_literal_operator_template (^^S::fn));
+static_assert (!is_literal_operator_template (^^operator""_a));
+static_assert (is_literal_operator_template (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_lrvalue_reference_qualified1.C b/gcc/testsuite/g++.dg/reflect/is_lrvalue_reference_qualified1.C
new file mode 100644 (file)
index 0000000..d97a2d0
--- /dev/null
@@ -0,0 +1,93 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_[lr]value_reference_qualified.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  void fn1 ();
+  void fn2 () &;
+  void fn3 () &&;
+  static void fn4 ();
+  /* Static member functions cannot have ref-qualifiers.  */
+  template<typename>
+  void fn5 ();
+  template<typename>
+  void fn6 () &;
+  template<typename>
+  void fn7 () &&;
+};
+
+void foo ();
+template<typename>
+void bar ();
+/* Non-member functions cannot have ref-qualifiers.  */
+
+static_assert (!is_lvalue_reference_qualified (^^S::fn1));
+static_assert (!is_rvalue_reference_qualified (^^S::fn1));
+
+static_assert (is_lvalue_reference_qualified (^^S::fn2));
+static_assert (!is_rvalue_reference_qualified (^^S::fn2));
+
+static_assert (!is_lvalue_reference_qualified (^^S::fn3));
+static_assert (is_rvalue_reference_qualified (^^S::fn3));
+
+static_assert (!is_lvalue_reference_qualified (^^S::fn4));
+static_assert (!is_rvalue_reference_qualified (^^S::fn4));
+
+static_assert (!is_lvalue_reference_qualified (^^S::fn5<int>));
+static_assert (!is_rvalue_reference_qualified (^^S::fn5<int>));
+
+static_assert (is_lvalue_reference_qualified (^^S::fn6<int>));
+static_assert (!is_rvalue_reference_qualified (^^S::fn6<int>));
+
+static_assert (!is_lvalue_reference_qualified (^^S::fn7<int>));
+static_assert (is_rvalue_reference_qualified (^^S::fn7<int>));
+
+static_assert (!is_lvalue_reference_qualified (^^::foo));
+static_assert (!is_rvalue_reference_qualified (^^::foo));
+
+static_assert (!is_lvalue_reference_qualified (^^::bar<int>));
+static_assert (!is_rvalue_reference_qualified (^^::bar<int>));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^S::fn1)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^S::fn1)));
+
+static_assert (is_lvalue_reference_qualified (type_of (^^S::fn2)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^S::fn2)));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^S::fn3)));
+static_assert (is_rvalue_reference_qualified (type_of (^^S::fn3)));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^S::fn4)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^S::fn4)));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^S::fn5<int>)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^S::fn5<int>)));
+
+static_assert (is_lvalue_reference_qualified (type_of (^^S::fn6<int>)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^S::fn6<int>)));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^S::fn7<int>)));
+static_assert (is_rvalue_reference_qualified (type_of (^^S::fn7<int>)));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^::foo)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^::foo)));
+
+static_assert (!is_lvalue_reference_qualified (type_of (^^::bar<int>)));
+static_assert (!is_rvalue_reference_qualified (type_of (^^::bar<int>)));
+
+static_assert (!is_lvalue_reference_qualified (^^void (int)));
+static_assert (!is_rvalue_reference_qualified (^^void (int)));
+
+static_assert (is_lvalue_reference_qualified (^^void (int) &));
+static_assert (!is_rvalue_reference_qualified (^^void (int) &));
+
+static_assert (!is_lvalue_reference_qualified (^^void (int) &&));
+static_assert (is_rvalue_reference_qualified (^^void (int) &&));
+
+static_assert (!is_lvalue_reference_qualified (std::meta::info {}));
+static_assert (!is_lvalue_reference_qualified (^^int));
+static_assert (!is_lvalue_reference_qualified (^^::));
diff --git a/gcc/testsuite/g++.dg/reflect/is_move_assignment1.C b/gcc/testsuite/g++.dg/reflect/is_move_assignment1.C
new file mode 100644 (file)
index 0000000..6153b10
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_move_assignment.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (is_move_assignment (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (!is_move_assignment (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_move_assignment (null_reflection));
+static_assert (!is_move_assignment (^^int));
+static_assert (!is_move_assignment (^^::));
+static_assert (!is_move_assignment (^^foo));
+static_assert (!is_move_assignment (^^S::bar));
+static_assert (!is_move_assignment (^^S::operator =));
+static_assert (!is_move_assignment (^^S::operator +=));
+static_assert (!is_move_assignment (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_move_constructor1.C b/gcc/testsuite/g++.dg/reflect/is_move_constructor1.C
new file mode 100644 (file)
index 0000000..d60253f
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_move_constructor.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (is_move_constructor (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (!is_move_constructor (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (!is_move_constructor (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_move_constructor (null_reflection));
+static_assert (!is_move_constructor (^^int));
+static_assert (!is_move_constructor (^^::));
+static_assert (!is_move_constructor (^^foo));
+static_assert (!is_move_constructor (^^S::bar));
+static_assert (!is_move_constructor (^^S::operator =));
+static_assert (!is_move_constructor (^^S::operator +=));
+static_assert (!is_move_constructor (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_mutable_member1.C b/gcc/testsuite/g++.dg/reflect/is_mutable_member1.C
new file mode 100644 (file)
index 0000000..7db9ace
--- /dev/null
@@ -0,0 +1,133 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_mutable_member.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  mutable int dm2;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+  mutable S dm3;
+} cls_var;
+union onion { };
+static union { int anon; };
+static union { mutable int anon2; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_mutable_member (null_reflection));
+static_assert (!is_mutable_member (^^::));
+static_assert (!is_mutable_member (^^ns));
+static_assert (!is_mutable_member (^^ns_alias));
+static_assert (!is_mutable_member (reflect_constant (3)));
+static_assert (!is_mutable_member (^^cls));
+static_assert (!is_mutable_member (^^cls::dm));
+static_assert (is_mutable_member (^^cls::dm2));
+static_assert (is_mutable_member (^^cls::dm3));
+static_assert (!is_mutable_member (^^cls::ref_dm));
+static_assert (!is_mutable_member (^^cls::static_dm));
+static_assert (!is_mutable_member (^^cls::mem_fun));
+static_assert (!is_mutable_member (^^cls::static_mem_fun));
+static_assert (!is_mutable_member (^^cls::type));
+static_assert (!is_mutable_member (^^cls::E));
+static_assert (!is_mutable_member (^^cls::B));
+static_assert (!is_mutable_member (^^cls::C));
+static_assert (!is_mutable_member (^^cls::D));
+static_assert (!is_mutable_member (^^cls::F));
+static_assert (!is_mutable_member (^^cls::F::G));
+static_assert (!is_mutable_member (^^cls::F::H));
+static_assert (!is_mutable_member (^^cls::S));
+static_assert (!is_mutable_member (^^cls::U));
+static_assert (!is_mutable_member (^^cls::foo));
+static_assert (!is_mutable_member (^^cls::foo <0>));
+static_assert (!is_mutable_member (^^cls::bar));
+static_assert (!is_mutable_member (^^cls::bar <42>));
+static_assert (!is_mutable_member (^^cls_var));
+static_assert (!is_mutable_member (^^onion));
+static_assert (!is_mutable_member (^^anon));
+static_assert (is_mutable_member (^^anon2));
+static_assert (!is_mutable_member (^^fun));
+static_assert (!is_mutable_member (^^alias));
+static_assert (!is_mutable_member (^^var));
+static_assert (!is_mutable_member (^^ref));
+static_assert (!is_mutable_member (^^rref));
+static_assert (!is_mutable_member (^^ptr));
+static_assert (!is_mutable_member (^^cls_tmpl));
+static_assert (!is_mutable_member (^^cls_tmpl<int>));
+static_assert (!is_mutable_member (^^incomplete_cls<int>));
+static_assert (!is_mutable_member (^^fun_tmpl));
+static_assert (!is_mutable_member (^^fun_tmpl<int>));
+static_assert (!is_mutable_member (^^conc));
+static_assert (!is_mutable_member (substitute (^^conc, { ^^int })));
+static_assert (!is_mutable_member (^^var_tmpl));
+static_assert (!is_mutable_member (^^var_tmpl<int>));
+static_assert (!is_mutable_member (^^cls_tmpl_alias));
+static_assert (!is_mutable_member (^^cls_tmpl_alias<int>));
+static_assert (!is_mutable_member (^^Enum));
+static_assert (!is_mutable_member (^^Enum::A));
+static_assert (!is_mutable_member (^^Enum_class));
+static_assert (!is_mutable_member (^^Enum_class::A));
+static_assert (!is_mutable_member (^^decomp));
+static_assert (!is_mutable_member (^^decomp_ref));
+static_assert (!is_mutable_member (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_mutable_member (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_mutable_member (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_mutable_member (^^x));
+  static_assert (!is_mutable_member (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_mutable_member (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_mutable_member (^^S));
+  static_assert (!is_mutable_member (^^E));
+  static_assert (!is_mutable_member (^^F));
+  static_assert (!is_mutable_member (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_namespace1.C b/gcc/testsuite/g++.dg/reflect/is_namespace1.C
new file mode 100644 (file)
index 0000000..794c6eb
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_namespace.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_namespace (null_reflection));
+static_assert (is_namespace (^^::));
+static_assert (is_namespace (^^ns));
+static_assert (is_namespace (^^ns_alias));
+static_assert (!is_namespace (reflect_constant (3)));
+static_assert (!is_namespace (^^cls));
+static_assert (!is_namespace (^^cls::dm));
+static_assert (!is_namespace (^^cls::ref_dm));
+static_assert (!is_namespace (^^cls::static_dm));
+static_assert (!is_namespace (^^cls::mem_fun));
+static_assert (!is_namespace (^^cls::static_mem_fun));
+static_assert (!is_namespace (^^cls::type));
+static_assert (!is_namespace (^^cls_var));
+static_assert (!is_namespace (^^onion));
+static_assert (!is_namespace (^^anon));
+static_assert (!is_namespace (^^fun));
+static_assert (!is_namespace (^^alias));
+static_assert (!is_namespace (^^var));
+static_assert (!is_namespace (^^ref));
+static_assert (!is_namespace (^^rref));
+static_assert (!is_namespace (^^ptr));
+static_assert (!is_namespace (^^cls_tmpl));
+static_assert (!is_namespace (^^cls_tmpl<int>));
+static_assert (!is_namespace (^^incomplete_cls<int>));
+static_assert (!is_namespace (^^fun_tmpl));
+static_assert (!is_namespace (^^fun_tmpl<int>));
+static_assert (!is_namespace (^^conc));
+static_assert (!is_namespace (substitute (^^conc, { ^^int })));
+static_assert (!is_namespace (^^var_tmpl));
+static_assert (!is_namespace (^^var_tmpl<int>));
+static_assert (!is_namespace (^^cls_tmpl_alias));
+static_assert (!is_namespace (^^cls_tmpl_alias<int>));
+static_assert (!is_namespace (^^Enum));
+static_assert (!is_namespace (^^Enum::A));
+static_assert (!is_namespace (^^Enum_class));
+static_assert (!is_namespace (^^Enum_class::A));
+static_assert (!is_namespace (^^decomp));
+static_assert (!is_namespace (^^decomp_ref));
+static_assert (!is_namespace (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_namespace (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_namespace (bases_of (^^Derived, access_context::unprivileged ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_namespace (^^T));
+  static_assert (!is_namespace (R));
+  static_assert (is_namespace (R2));
+  static_assert (!is_namespace (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_namespace (^^p));
+  static_assert (!is_namespace (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C b/gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C
new file mode 100644 (file)
index 0000000..f77c507
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_namespace_alias.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_namespace_alias (null_reflection));
+static_assert (!is_namespace_alias (^^::));
+static_assert (!is_namespace_alias (^^ns));
+static_assert (is_namespace_alias (^^ns_alias));
+static_assert (!is_namespace_alias (reflect_constant (3)));
+static_assert (!is_namespace_alias (^^cls));
+static_assert (!is_namespace_alias (^^cls::dm));
+static_assert (!is_namespace_alias (^^cls::ref_dm));
+static_assert (!is_namespace_alias (^^cls::static_dm));
+static_assert (!is_namespace_alias (^^cls::mem_fun));
+static_assert (!is_namespace_alias (^^cls::static_mem_fun));
+static_assert (!is_namespace_alias (^^cls::type));
+static_assert (!is_namespace_alias (^^cls_var));
+static_assert (!is_namespace_alias (^^onion));
+static_assert (!is_namespace_alias (^^anon));
+static_assert (!is_namespace_alias (^^fun));
+static_assert (!is_namespace_alias (^^alias));
+static_assert (!is_namespace_alias (^^var));
+static_assert (!is_namespace_alias (^^ref));
+static_assert (!is_namespace_alias (^^rref));
+static_assert (!is_namespace_alias (^^ptr));
+static_assert (!is_namespace_alias (^^cls_tmpl));
+static_assert (!is_namespace_alias (^^cls_tmpl<int>));
+static_assert (!is_namespace_alias (^^incomplete_cls<int>));
+static_assert (!is_namespace_alias (^^fun_tmpl));
+static_assert (!is_namespace_alias (^^fun_tmpl<int>));
+static_assert (!is_namespace_alias (^^conc));
+static_assert (!is_namespace_alias (substitute (^^conc, { ^^int })));
+static_assert (!is_namespace_alias (^^var_tmpl));
+static_assert (!is_namespace_alias (^^var_tmpl<int>));
+static_assert (!is_namespace_alias (^^cls_tmpl_alias));
+static_assert (!is_namespace_alias (^^cls_tmpl_alias<int>));
+static_assert (!is_namespace_alias (^^Enum));
+static_assert (!is_namespace_alias (^^Enum::A));
+static_assert (!is_namespace_alias (^^Enum_class));
+static_assert (!is_namespace_alias (^^Enum_class::A));
+static_assert (!is_namespace_alias (^^decomp));
+static_assert (!is_namespace_alias (^^decomp_ref));
+static_assert (!is_namespace_alias (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_namespace_alias (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_namespace_alias (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_namespace_alias (^^T));
+  static_assert (!is_namespace_alias (R));
+  static_assert (!is_namespace_alias (R2));
+  static_assert (is_namespace_alias (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^ns_alias>();
+  static_assert (!is_namespace_alias (^^p));
+  static_assert (!is_namespace_alias (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_namespace_member1.C b/gcc/testsuite/g++.dg/reflect/is_namespace_member1.C
new file mode 100644 (file)
index 0000000..3a00357
--- /dev/null
@@ -0,0 +1,147 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_namespace_member.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+namespace NN
+{
+  int a;
+  int &b = a;
+  int &&c = 42;
+  int *d = &a;
+  namespace ns {}
+  namespace ns_alias = ns;
+  enum E { F };
+}
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_namespace_member (null_reflection));
+static_assert (!is_namespace_member (^^::));
+static_assert (is_namespace_member (^^ns));
+static_assert (is_namespace_member (^^ns_alias));
+static_assert (!is_namespace_member (reflect_constant (3)));
+static_assert (is_namespace_member (^^cls));
+static_assert (!is_namespace_member (^^cls::dm));
+static_assert (!is_namespace_member (^^cls::ref_dm));
+static_assert (!is_namespace_member (^^cls::static_dm));
+static_assert (!is_namespace_member (^^cls::mem_fun));
+static_assert (!is_namespace_member (^^cls::static_mem_fun));
+static_assert (!is_namespace_member (^^cls::type));
+static_assert (!is_namespace_member (^^cls::E));
+static_assert (!is_namespace_member (^^cls::B));
+static_assert (!is_namespace_member (^^cls::C));
+static_assert (!is_namespace_member (^^cls::D));
+static_assert (!is_namespace_member (^^cls::F));
+static_assert (!is_namespace_member (^^cls::F::G));
+static_assert (!is_namespace_member (^^cls::F::H));
+static_assert (!is_namespace_member (^^cls::S));
+static_assert (!is_namespace_member (^^cls::U));
+static_assert (!is_namespace_member (^^cls::foo));
+static_assert (!is_namespace_member (^^cls::foo <0>));
+static_assert (!is_namespace_member (^^cls::bar));
+static_assert (!is_namespace_member (^^cls::bar <42>));
+static_assert (is_namespace_member (^^cls_var));
+static_assert (is_namespace_member (^^onion));
+static_assert (!is_namespace_member (^^anon));
+static_assert (is_namespace_member (^^fun));
+static_assert (is_namespace_member (^^alias));
+static_assert (is_namespace_member (^^var));
+static_assert (is_namespace_member (^^ref));
+static_assert (is_namespace_member (^^rref));
+static_assert (is_namespace_member (^^ptr));
+static_assert (is_namespace_member (^^cls_tmpl));
+static_assert (is_namespace_member (^^cls_tmpl<int>));
+static_assert (is_namespace_member (^^incomplete_cls<int>));
+static_assert (is_namespace_member (^^fun_tmpl));
+static_assert (is_namespace_member (^^fun_tmpl<int>));
+static_assert (is_namespace_member (^^conc));
+static_assert (!is_namespace_member (substitute (^^conc, { ^^int })));
+static_assert (is_namespace_member (^^var_tmpl));
+static_assert (is_namespace_member (^^var_tmpl<int>));
+static_assert (is_namespace_member (^^cls_tmpl_alias));
+static_assert (is_namespace_member (^^cls_tmpl_alias<int>));
+static_assert (is_namespace_member (^^Enum));
+static_assert (is_namespace_member (^^Enum::A));
+static_assert (is_namespace_member (^^A));
+static_assert (is_namespace_member (^^Enum_class));
+static_assert (!is_namespace_member (^^Enum_class::A));
+static_assert (is_namespace_member (^^decomp));
+static_assert (is_namespace_member (^^decomp_ref));
+static_assert (is_namespace_member (^^arr));
+static_assert (is_namespace_member (^^NN::a));
+static_assert (is_namespace_member (^^NN::a));
+static_assert (is_namespace_member (^^NN::b));
+static_assert (is_namespace_member (^^NN::c));
+static_assert (is_namespace_member (^^NN::d));
+static_assert (is_namespace_member (^^NN::ns));
+static_assert (is_namespace_member (^^NN::ns_alias));
+static_assert (is_namespace_member (^^NN::E));
+static_assert (is_namespace_member (^^NN::F));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_namespace_member (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_namespace_member (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_namespace_member (^^x));
+  static_assert (!is_namespace_member (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_namespace_member (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_namespace_member (^^S));
+  static_assert (!is_namespace_member (^^E));
+  static_assert (!is_namespace_member (^^F));
+  static_assert (!is_namespace_member (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_noexcept1.C b/gcc/testsuite/g++.dg/reflect/is_noexcept1.C
new file mode 100644 (file)
index 0000000..c4bacec
--- /dev/null
@@ -0,0 +1,180 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_noexcept.
+
+#include <meta>
+
+// Basic noexcept specifications
+void noexcept_function () noexcept;
+void noexcept_true_function () noexcept(true);
+void noexcept_false_function () noexcept(false);
+void not_noexcept_function ();
+
+static_assert(std::meta::is_noexcept (^^noexcept_function));
+static_assert(std::meta::is_noexcept (^^noexcept_true_function));
+static_assert(!std::meta::is_noexcept (^^noexcept_false_function));
+static_assert(!std::meta::is_noexcept (^^not_noexcept_function));
+
+// throw()
+void throw_function () throw();
+// void func () throw(int) -->  error: ISO C++17 does not allow dynamic exception specifications
+
+static_assert (std::meta::is_noexcept (^^throw_function));
+
+// Template functions
+template <class T>
+void noexcept_template_function(T param) noexcept(true);
+
+// Note 2 from P2996: If r represents a function template that is declared noexcept,
+// is_noexcept(r) is still false because in general such queries
+// for templates cannot be answered.
+static_assert (!std::meta::is_noexcept (^^noexcept_template_function));
+// Note 5 from P2996: A template specialization is not a template.
+static_assert (std::meta::is_noexcept (^^noexcept_template_function<bool>));
+
+template <class T>
+void template_function(T param);
+
+static_assert (!std::meta::is_noexcept (^^template_function));
+static_assert (!std::meta::is_noexcept (^^template_function<int>));
+
+template<bool B>
+void conditional_noexcept() noexcept(B);
+
+static_assert (!std::meta::is_noexcept (^^conditional_noexcept));
+static_assert (std::meta::is_noexcept (^^conditional_noexcept<true>));
+static_assert (!std::meta::is_noexcept (^^conditional_noexcept<false>));
+
+struct S {
+  void noexcept_method() noexcept;
+  void noexcept_true_method() noexcept(true);
+  void noexcept_false_method() noexcept(false);
+  void not_noexcept_method();
+
+  virtual void noexcept_virtual_method() noexcept {}
+  virtual void noexcept_true_virtual_method() noexcept(true) {}
+  virtual void noexcept_false_virtual_method() noexcept(false) {}
+  virtual void not_noexcept_virtual_method() {}
+
+  template <typename T>
+  void noexcept_template_method() noexcept;
+  template <typename T>
+  void noexcept_true_template_method() noexcept(true);
+  template <typename T>
+  void noexcept_false_template_method() noexcept(false);
+  template <typename T>
+  void noexcept_cond_template_method() noexcept(sizeof(T) > 4);
+  template <typename T>
+  void not_noexcept_template_method();
+};
+
+// Methods
+static_assert (std::meta::is_noexcept (^^S::noexcept_method));
+static_assert (std::meta::is_noexcept (^^S::noexcept_true_method));
+static_assert (!std::meta::is_noexcept (^^S::noexcept_false_method));
+static_assert (!std::meta::is_noexcept (^^S::not_noexcept_method));
+
+// Virtual methods
+static_assert (std::meta::is_noexcept (^^S::noexcept_virtual_method));
+static_assert (std::meta::is_noexcept (^^S::noexcept_true_virtual_method));
+static_assert (!std::meta::is_noexcept (^^S::noexcept_false_virtual_method));
+static_assert (!std::meta::is_noexcept (^^S::not_noexcept_virtual_method));
+
+// Template methods
+static_assert (!std::meta::is_noexcept (^^S::noexcept_template_method));
+static_assert (!std::meta::is_noexcept (^^S::noexcept_true_template_method));
+static_assert (!std::meta::is_noexcept (^^S::noexcept_false_template_method));
+static_assert (!std::meta::is_noexcept (^^S::noexcept_cond_template_method));
+static_assert (!std::meta::is_noexcept (^^S::not_noexcept_template_method));
+
+static_assert (std::meta::is_noexcept (^^S::noexcept_template_method<int>));
+static_assert (std::meta::is_noexcept (^^S::noexcept_true_template_method<int>));
+static_assert (!std::meta::is_noexcept (^^S::noexcept_false_template_method<int>));
+static_assert (!std::meta::is_noexcept (^^S::not_noexcept_template_method<int>));
+
+struct SS : public S {
+
+};
+
+// Inherited methods
+static_assert (std::meta::is_noexcept (^^SS::noexcept_method));
+static_assert (std::meta::is_noexcept (^^SS::noexcept_true_method));
+static_assert (!std::meta::is_noexcept (^^SS::noexcept_false_method));
+static_assert (!std::meta::is_noexcept (^^SS::not_noexcept_method));
+
+// Function types
+static_assert (std::meta::is_noexcept (^^void() noexcept));
+static_assert (!std::meta::is_noexcept (^^void()));
+
+using not_noexcept_func_type = void();
+using noexcept_func_type = void() noexcept;
+
+static_assert (!std::meta::is_noexcept (^^not_noexcept_func_type));
+static_assert (std::meta::is_noexcept (^^noexcept_func_type));
+
+template<typename T, bool B>
+using conditional_noexcept_func_type = void(T) noexcept(B);
+
+static_assert (!std::meta::is_noexcept (^^conditional_noexcept_func_type));
+static_assert (!std::meta::is_noexcept (^^conditional_noexcept_func_type<int, false>));
+static_assert (std::meta::is_noexcept (^^conditional_noexcept_func_type<int, true>));
+
+// Constructors
+struct T {
+    T() = default;
+
+    T(int) {
+      int a;
+      static_assert (!std::meta::is_noexcept (std::meta::parent_of (^^a)));
+    }
+
+    T(double) noexcept {
+      int a;
+      static_assert (std::meta::is_noexcept (std::meta::parent_of (^^a)));
+    }
+
+    T(bool) noexcept(true) {
+      int a;
+      static_assert (std::meta::is_noexcept (std::meta::parent_of (^^a)));
+    }
+
+    T(S) noexcept(false) {
+      int a;
+      static_assert (!std::meta::is_noexcept (std::meta::parent_of (^^a)));
+    }
+};
+
+static_assert (noexcept (T()));
+static_assert (!noexcept (T(123)));
+static_assert (noexcept (T(123.123)));
+static_assert (noexcept (T(true)));
+static_assert (!noexcept (T(S())));
+
+// Destructors
+struct U { };
+U u;
+static_assert (std::meta::is_noexcept (^^U::~U));
+static_assert (noexcept (u.~U()));
+
+struct V { ~V() = delete; };
+static_assert (std::meta::is_noexcept (^^V::~V));
+
+struct W { ~W() = default; };
+W w;
+static_assert (std::meta::is_noexcept (^^W::~W));
+static_assert (noexcept (w.~W()));
+
+struct X { ~X(); };
+X x;
+static_assert (std::meta::is_noexcept (^^X::~X));
+static_assert (noexcept (x.~X()));
+
+struct Y { ~Y() noexcept(true); };
+Y y;
+static_assert (std::meta::is_noexcept (^^Y::~Y));
+static_assert (noexcept (y.~Y()));
+
+struct Z { ~Z() noexcept(false); };
+Z z;
+static_assert(!std::meta::is_noexcept (^^Z::~Z));
+static_assert(!noexcept (z.~Z()));
diff --git a/gcc/testsuite/g++.dg/reflect/is_noexcept2.C b/gcc/testsuite/g++.dg/reflect/is_noexcept2.C
new file mode 100644 (file)
index 0000000..5bf90de
--- /dev/null
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_noexcept.  Negative cases.
+
+#include <meta>
+#include <functional>
+
+// Lambdas
+const auto noexcept_lambda = []() noexcept {};
+const auto not_noexcept_lambda = []{};
+
+static_assert (!std::meta::is_noexcept (^^noexcept_lambda));
+static_assert (!std::meta::is_noexcept (^^not_noexcept_lambda));
+
+// Template lamdas
+const auto noexcept_template_lambda = []<typename T>(T arg) noexcept {};
+const auto not_noexcept_template_lambda = []<typename T>(T arg) {};
+
+static_assert (!std::meta::is_noexcept (^^noexcept_template_lambda));
+static_assert (!std::meta::is_noexcept (^^not_noexcept_template_lambda));
+
+void noexcept_function () noexcept;
+void not_noexcept_function ();
+
+// Function pointers
+void (*noexcept_function_pointer)() noexcept = noexcept_function;
+void (*not_noexcept_function_pointer)() = not_noexcept_function;
+
+static_assert (!std::meta::is_noexcept (^^noexcept_function_pointer));
+static_assert (!std::meta::is_noexcept (^^not_noexcept_function_pointer));
+
+// Function reference
+void (&noexcept_function_reference)() noexcept = noexcept_function;
+void (&not_noexcept_function_reference)() = not_noexcept_function;
+
+static_assert (!std::meta::is_noexcept (^^noexcept_function_reference));
+static_assert (!std::meta::is_noexcept (^^not_noexcept_function_reference));
+
+struct S {
+};
+
+// Member function pointers
+void (S::*noexcept_member_pointer)() noexcept;
+void (S::*not_noexcept_member_pointer)();
+
+static_assert (!std::meta::is_noexcept (^^noexcept_member_pointer));
+static_assert (!std::meta::is_noexcept (^^not_noexcept_member_pointer));
+
+// Function pointer as a parameter in function
+void function_with_noexcept_function_pointer_as_input(void (*noexcept_function_pointer)() noexcept) {
+  static_assert (!std::meta::is_noexcept (^^noexcept_function_pointer));
+}
+
+void function_with_not_noexcept_function_pointer_as_input(void (*not_noexcept_function_pointer)()) {
+  static_assert (!std::meta::is_noexcept (^^not_noexcept_function_pointer));
+}
+
+// Misc
+std::function<void(int)> f;
+int n = 42;
+
+static_assert (!std::meta::is_noexcept (^^f));
+static_assert (!std::meta::is_noexcept (^^n));
+static_assert (!std::meta::is_noexcept (^^S));
+static_assert (!std::meta::is_noexcept (^^::));
diff --git a/gcc/testsuite/g++.dg/reflect/is_noexcept3.C b/gcc/testsuite/g++.dg/reflect/is_noexcept3.C
new file mode 100644 (file)
index 0000000..556fa7f
--- /dev/null
@@ -0,0 +1,175 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_noexcept.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S1 {
+  void foo () noexcept {
+    static_assert (is_noexcept (^^foo));
+  }
+
+  void bar () {
+    static_assert (!is_noexcept (^^bar));
+  }
+};
+
+template<typename>
+struct S2 {
+  void foo () noexcept {
+    static_assert (is_noexcept (^^foo));
+  }
+
+  void bar () {
+    static_assert (!is_noexcept (^^bar));
+  }
+
+  template<typename>
+  void tfoo () noexcept {
+    static_assert (is_noexcept (^^tfoo<int>));
+  }
+
+  template<typename>
+  void tbar () {
+    static_assert (!is_noexcept (^^tbar<int>));
+  }
+};
+
+S2<int> s2;
+
+void fn1 ();
+void fn2 () noexcept;
+void fn3 () noexcept(false);
+
+static_assert (!is_noexcept (type_of (^^::fn1)));
+static_assert (is_noexcept (type_of (^^::fn2)));
+static_assert (!is_noexcept (type_of (^^::fn3)));
+
+static_assert (!is_noexcept (reflect_constant (&::fn1)));
+static_assert (!is_noexcept (reflect_constant (&::fn2)));
+static_assert (!is_noexcept (reflect_constant (&::fn3)));
+
+static_assert (!is_noexcept (type_of (reflect_constant (&::fn1))));
+static_assert (!is_noexcept (type_of (reflect_constant (&::fn2))));
+static_assert (!is_noexcept (type_of (reflect_constant (&::fn3))));
+
+template<typename>
+void tfn1 ();
+template<typename>
+void tfn2 () noexcept;
+template<typename>
+void tfn3 () noexcept(false);
+
+static_assert (!is_noexcept (type_of (^^::tfn1<int>)));
+static_assert (is_noexcept (type_of (^^::tfn2<int>)));
+static_assert (!is_noexcept (type_of (^^::tfn3<int>)));
+
+static_assert (!is_noexcept (reflect_constant (^^::tfn1<int>)));
+static_assert (!is_noexcept (reflect_constant (^^::tfn2<int>)));
+static_assert (!is_noexcept (reflect_constant (^^::tfn3<int>)));
+
+static_assert (!is_noexcept (type_of (reflect_constant (^^::tfn1<int>))));
+static_assert (!is_noexcept (type_of (reflect_constant (^^::tfn2<int>))));
+static_assert (!is_noexcept (type_of (reflect_constant (^^::tfn3<int>))));
+
+struct S {
+  void memfn1 ();
+  void memfn2 () noexcept;
+  void memfn3 () noexcept(false);
+
+  virtual void vmemfn1 () {}
+  virtual void vmemfn2 () noexcept {}
+  virtual void vmemfn3 () noexcept(false) {}
+
+  template<typename>
+  void tmemfn1 ();
+  template<typename>
+  void tmemfn2 () noexcept;
+  template<typename>
+  void tmemfn3 () noexcept(false);
+};
+
+static_assert (!is_noexcept (type_of (^^S::memfn1)));
+static_assert (is_noexcept (type_of (^^S::memfn2)));
+static_assert (!is_noexcept (type_of (^^S::memfn3)));
+
+static_assert (!is_noexcept (type_of (^^S::vmemfn1)));
+static_assert (is_noexcept (type_of (^^S::vmemfn2)));
+static_assert (!is_noexcept (type_of (^^S::vmemfn3)));
+
+static_assert (!is_noexcept (type_of (^^S::tmemfn1<int>)));
+static_assert (is_noexcept (type_of (^^S::tmemfn2<int>)));
+static_assert (!is_noexcept (type_of (^^S::tmemfn3<int>)));
+
+static_assert (!is_noexcept (reflect_constant (&S::memfn1)));
+static_assert (!is_noexcept (reflect_constant (&S::memfn2)));
+static_assert (!is_noexcept (reflect_constant (&S::memfn3)));
+
+static_assert (!is_noexcept (type_of (reflect_constant (&S::memfn1))));
+static_assert (!is_noexcept (type_of (reflect_constant (&S::memfn2))));
+static_assert (!is_noexcept (type_of (reflect_constant (&S::memfn3))));
+
+static_assert (!is_noexcept (reflect_constant (&S::vmemfn1)));
+static_assert (!is_noexcept (reflect_constant (&S::vmemfn2)));
+static_assert (!is_noexcept (reflect_constant (&S::vmemfn3)));
+
+static_assert (!is_noexcept (type_of (reflect_constant (&S::vmemfn1))));
+static_assert (!is_noexcept (type_of (reflect_constant (&S::vmemfn2))));
+static_assert (!is_noexcept (type_of (reflect_constant (&S::vmemfn3))));
+
+static_assert (!is_noexcept (reflect_constant (&S::tmemfn1<int>)));
+static_assert (!is_noexcept (reflect_constant (&S::tmemfn2<int>)));
+static_assert (!is_noexcept (reflect_constant (&S::tmemfn3<int>)));
+
+static_assert (!is_noexcept (type_of (reflect_constant (&S::tmemfn1<int>))));
+static_assert (!is_noexcept (type_of (reflect_constant (&S::tmemfn2<int>))));
+static_assert (!is_noexcept (type_of (reflect_constant (&S::tmemfn3<int>))));
+
+constexpr auto noexcept_lambda = []() noexcept {};
+constexpr auto not_noexcept_lambda = []{};
+static_assert (!is_noexcept (type_of (^^noexcept_lambda)));
+static_assert (!is_noexcept (type_of (^^not_noexcept_lambda)));
+
+constexpr auto noexcept_generic_lambda = []<typename T>() noexcept {};
+constexpr auto not_noexcept_generic_lambda = []<typename T>() {};
+static_assert (!is_noexcept (type_of (^^noexcept_generic_lambda)));
+static_assert (!is_noexcept (type_of (^^not_noexcept_generic_lambda)));
+
+struct T {
+  static const int static_mem = 1;
+  int non_static_mem = 2;
+};
+
+template <typename>
+struct TT {};
+
+enum class EC { X };
+enum E { X };
+
+static auto static_x = 1;
+auto non_static_x = static_x;
+auto t = T();
+auto template_t = TT<int>();
+int c_array[] = {1, 2};
+auto [sb1, sb2] = c_array;
+
+static_assert (!is_noexcept (^^static_x));
+static_assert (!is_noexcept (type_of (^^static_x)));
+static_assert (!is_noexcept (^^non_static_x));
+static_assert (!is_noexcept (type_of (^^non_static_x)));
+static_assert (!is_noexcept (^^T::static_mem));
+static_assert (!is_noexcept (type_of (^^T::static_mem)));
+static_assert (!is_noexcept (^^sb1));
+static_assert (!is_noexcept (^^T::non_static_mem));
+static_assert (!is_noexcept (type_of (^^T::non_static_mem)));
+static_assert (!is_noexcept (^^TT));
+static_assert (!is_noexcept (^^template_t));
+static_assert (!is_noexcept (type_of (^^template_t)));
+static_assert (!is_noexcept (^^EC));
+static_assert (!is_noexcept (^^EC::X));
+static_assert (!is_noexcept (type_of (^^EC::X)));
+static_assert (!is_noexcept (^^E));
+static_assert (!is_noexcept (^^X));
+static_assert (!is_noexcept (type_of (^^X)));
diff --git a/gcc/testsuite/g++.dg/reflect/is_noexcept4.C b/gcc/testsuite/g++.dg/reflect/is_noexcept4.C
new file mode 100644 (file)
index 0000000..9b4b2b8
--- /dev/null
@@ -0,0 +1,120 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_noexcept.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template<bool Noex>
+struct Mem {
+  Mem() noexcept(Noex);
+  Mem(Mem const&) noexcept(Noex);
+  Mem(Mem&&) noexcept(Noex);
+  Mem& operator=(Mem const&) noexcept(Noex);
+  Mem& operator=(Mem&&) noexcept(Noex);
+  ~Mem() noexcept(Noex);
+
+  bool operator==(const Mem&) const noexcept(Noex);
+  std::strong_ordering operator<=>(const Mem&) const noexcept(Noex);
+};
+
+template<typename F>
+consteval info
+select_mem(info clazz, F f)
+{
+  for (info x : members_of(clazz, access_context::unchecked()))
+    if (f(x))
+      return x;
+}
+
+template<bool Noex>
+struct ExplicitDef
+{
+  ExplicitDef() = default;
+  ExplicitDef(const ExplicitDef&) = default;
+  ExplicitDef(ExplicitDef&&) = default;
+
+  ExplicitDef& operator=(const ExplicitDef&) = default;
+  ExplicitDef& operator=(ExplicitDef&&) = default;
+
+  ~ExplicitDef() = default;
+
+  Mem<Noex> d;
+};
+
+static_assert (is_noexcept (select_mem (^^ExplicitDef<true>, is_default_constructor)));
+static_assert (is_noexcept (select_mem (^^ExplicitDef<true>, is_copy_constructor)));
+static_assert (is_noexcept (select_mem (^^ExplicitDef<true>, is_move_constructor)));
+static_assert (is_noexcept (select_mem (^^ExplicitDef<true>, is_copy_assignment)));
+static_assert (is_noexcept (select_mem (^^ExplicitDef<true>, is_move_assignment)));
+static_assert (is_noexcept (select_mem (^^ExplicitDef<true>, is_destructor)));
+
+static_assert (!is_noexcept (select_mem (^^ExplicitDef<false>, is_default_constructor)));
+static_assert (!is_noexcept (select_mem (^^ExplicitDef<false>, is_copy_constructor)));
+static_assert (!is_noexcept (select_mem (^^ExplicitDef<false>, is_move_constructor)));
+static_assert (!is_noexcept (select_mem (^^ExplicitDef<false>, is_copy_assignment)));
+static_assert (!is_noexcept (select_mem (^^ExplicitDef<false>, is_move_assignment)));
+static_assert (!is_noexcept (select_mem (^^ExplicitDef<false>, is_destructor)));
+
+template<bool Noex>
+struct ImplicitDef
+{
+  Mem<Noex> d;
+};
+
+static_assert (is_noexcept (select_mem (^^ImplicitDef<true>, is_default_constructor)));
+static_assert (is_noexcept (select_mem (^^ImplicitDef<true>, is_copy_constructor)));
+static_assert (is_noexcept (select_mem (^^ImplicitDef<true>, is_move_constructor)));
+static_assert (is_noexcept (select_mem (^^ImplicitDef<true>, is_copy_assignment)));
+static_assert (is_noexcept (select_mem (^^ImplicitDef<true>, is_move_assignment)));
+static_assert (is_noexcept (select_mem (^^ImplicitDef<true>, is_destructor)));
+
+static_assert (!is_noexcept (select_mem (^^ImplicitDef<false>, is_default_constructor)));
+static_assert (!is_noexcept (select_mem (^^ImplicitDef<false>, is_copy_constructor)));
+static_assert (!is_noexcept (select_mem (^^ImplicitDef<false>, is_move_constructor)));
+static_assert (!is_noexcept (select_mem (^^ImplicitDef<false>, is_copy_assignment)));
+static_assert (!is_noexcept (select_mem (^^ImplicitDef<false>, is_move_assignment)));
+static_assert (!is_noexcept (select_mem (^^ImplicitDef<false>, is_destructor)));
+
+template<bool Noex>
+struct ExplicitRelOps
+{
+  bool operator==(const ExplicitRelOps&) const = default;
+  auto operator<=>(const ExplicitRelOps&) const = default;
+
+  Mem<Noex> d;
+};
+static_assert (is_noexcept (^^ExplicitRelOps<true>::operator==));
+static_assert (is_noexcept (^^ExplicitRelOps<true>::operator<=>));
+
+ExplicitRelOps<true> x1;
+static_assert (noexcept (x1 == x1));
+static_assert (noexcept (x1 <=> x1));
+static_assert (is_noexcept (^^ExplicitRelOps<true>::operator==));
+static_assert (is_noexcept (^^ExplicitRelOps<true>::operator<=>));
+
+static_assert (!is_noexcept (^^ExplicitRelOps<false>::operator==));
+static_assert (!is_noexcept (^^ExplicitRelOps<false>::operator<=>));
+
+template<bool Noex>
+struct ImplicitRelOps
+{
+  // operator== is implicitly declared
+  auto operator<=>(const ImplicitRelOps&) const = default;
+
+  Mem<Noex> d;
+};
+
+static_assert (is_noexcept (^^ImplicitRelOps<true>::operator==));
+static_assert (is_noexcept (^^ImplicitRelOps<true>::operator<=>));
+
+ImplicitRelOps<true> x2;
+static_assert (noexcept (x2 == x2));
+static_assert (noexcept (x2 <=> x2));
+static_assert (is_noexcept (^^ImplicitRelOps<true>::operator==));
+static_assert (is_noexcept (^^ImplicitRelOps<true>::operator<=>));
+
+static_assert (!is_noexcept (^^ImplicitRelOps<false>::operator==));
+static_assert (!is_noexcept (^^ImplicitRelOps<false>::operator<=>));
diff --git a/gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C b/gcc/testsuite/g++.dg/reflect/is_nonstatic_data_member1.C
new file mode 100644 (file)
index 0000000..13137d8
--- /dev/null
@@ -0,0 +1,127 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_nonstatic_data_member.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_nonstatic_data_member (null_reflection));
+static_assert (!is_nonstatic_data_member (^^::));
+static_assert (!is_nonstatic_data_member (^^ns));
+static_assert (!is_nonstatic_data_member (^^ns_alias));
+static_assert (!is_nonstatic_data_member (reflect_constant (3)));
+static_assert (!is_nonstatic_data_member (^^cls));
+static_assert (is_nonstatic_data_member (^^cls::dm));
+static_assert (is_nonstatic_data_member (^^cls::ref_dm));
+static_assert (!is_nonstatic_data_member (^^cls::static_dm));
+static_assert (!is_nonstatic_data_member (^^cls::mem_fun));
+static_assert (!is_nonstatic_data_member (^^cls::static_mem_fun));
+static_assert (!is_nonstatic_data_member (^^cls::type));
+static_assert (!is_nonstatic_data_member (^^cls::E));
+static_assert (!is_nonstatic_data_member (^^cls::B));
+static_assert (!is_nonstatic_data_member (^^cls::C));
+static_assert (!is_nonstatic_data_member (^^cls::D));
+static_assert (!is_nonstatic_data_member (^^cls::F));
+static_assert (!is_nonstatic_data_member (^^cls::F::G));
+static_assert (!is_nonstatic_data_member (^^cls::F::H));
+static_assert (!is_nonstatic_data_member (^^cls::S));
+static_assert (!is_nonstatic_data_member (^^cls::U));
+static_assert (!is_nonstatic_data_member (^^cls::foo));
+static_assert (!is_nonstatic_data_member (^^cls::foo <0>));
+static_assert (!is_nonstatic_data_member (^^cls::bar));
+static_assert (!is_nonstatic_data_member (^^cls::bar <42>));
+static_assert (!is_nonstatic_data_member (^^cls_var));
+static_assert (!is_nonstatic_data_member (^^onion));
+static_assert (is_nonstatic_data_member (^^anon));
+static_assert (!is_nonstatic_data_member (^^fun));
+static_assert (!is_nonstatic_data_member (^^alias));
+static_assert (!is_nonstatic_data_member (^^var));
+static_assert (!is_nonstatic_data_member (^^ref));
+static_assert (!is_nonstatic_data_member (^^rref));
+static_assert (!is_nonstatic_data_member (^^ptr));
+static_assert (!is_nonstatic_data_member (^^cls_tmpl));
+static_assert (!is_nonstatic_data_member (^^cls_tmpl<int>));
+static_assert (!is_nonstatic_data_member (^^incomplete_cls<int>));
+static_assert (!is_nonstatic_data_member (^^fun_tmpl));
+static_assert (!is_nonstatic_data_member (^^fun_tmpl<int>));
+static_assert (!is_nonstatic_data_member (^^conc));
+static_assert (!is_nonstatic_data_member (substitute (^^conc, { ^^int })));
+static_assert (!is_nonstatic_data_member (^^var_tmpl));
+static_assert (!is_nonstatic_data_member (^^var_tmpl<int>));
+static_assert (!is_nonstatic_data_member (^^cls_tmpl_alias));
+static_assert (!is_nonstatic_data_member (^^cls_tmpl_alias<int>));
+static_assert (!is_nonstatic_data_member (^^Enum));
+static_assert (!is_nonstatic_data_member (^^Enum::A));
+static_assert (!is_nonstatic_data_member (^^Enum_class));
+static_assert (!is_nonstatic_data_member (^^Enum_class::A));
+static_assert (!is_nonstatic_data_member (^^decomp));
+static_assert (!is_nonstatic_data_member (^^decomp_ref));
+static_assert (!is_nonstatic_data_member (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_nonstatic_data_member (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_nonstatic_data_member (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_nonstatic_data_member (^^x));
+  static_assert (!is_nonstatic_data_member (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_nonstatic_data_member (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_nonstatic_data_member (^^S));
+  static_assert (!is_nonstatic_data_member (^^E));
+  static_assert (!is_nonstatic_data_member (^^F));
+  static_assert (!is_nonstatic_data_member (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_object1.C b/gcc/testsuite/g++.dg/reflect/is_object1.C
new file mode 100644 (file)
index 0000000..e7ee628
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_object.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_object (null_reflection));
+static_assert (!is_object (^^::));
+static_assert (!is_object (^^ns));
+static_assert (!is_object (^^ns_alias));
+static_assert (!is_object (reflect_constant (3)));
+static_assert (!is_object (^^cls));
+static_assert (!is_object (^^cls::dm));
+static_assert (!is_object (^^cls::ref_dm));
+static_assert (!is_object (^^cls::static_dm));
+static_assert (!is_object (^^cls::mem_fun));
+static_assert (!is_object (^^cls::static_mem_fun));
+static_assert (!is_object (^^cls::type));
+static_assert (!is_object (^^cls_var));
+static_assert (!is_object (^^onion));
+static_assert (!is_object (^^anon));
+static_assert (!is_object (^^fun));
+static_assert (!is_object (^^alias));
+static_assert (!is_object (^^var));
+static_assert (!is_object (^^ref));
+static_assert (!is_object (^^rref));
+static_assert (!is_object (^^ptr));
+static_assert (!is_object (^^cls_tmpl));
+static_assert (!is_object (^^cls_tmpl<int>));
+static_assert (!is_object (^^incomplete_cls<int>));
+static_assert (!is_object (^^fun_tmpl));
+static_assert (!is_object (^^fun_tmpl<int>));
+static_assert (!is_object (^^conc));
+static_assert (!is_object (substitute (^^conc, { ^^int })));
+static_assert (!is_object (^^var_tmpl));
+static_assert (!is_object (^^var_tmpl<int>));
+static_assert (!is_object (^^cls_tmpl_alias));
+static_assert (!is_object (^^cls_tmpl_alias<int>));
+static_assert (!is_object (^^Enum));
+static_assert (!is_object (^^Enum::A));
+static_assert (!is_object (^^Enum_class));
+static_assert (!is_object (^^Enum_class::A));
+static_assert (!is_object (^^decomp));
+static_assert (!is_object (^^decomp_ref));
+static_assert (!is_object (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_object (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_object (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_object (^^T));
+  static_assert (!is_object (R));
+  static_assert (!is_object (R2));
+  static_assert (!is_object (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_object (^^p));
+  static_assert (!is_object (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_object2.C b/gcc/testsuite/g++.dg/reflect/is_object2.C
new file mode 100644 (file)
index 0000000..c61f986
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_object.
+
+#include <meta>
+using namespace std::meta;
+
+void f();
+
+template <void (&F)()>
+consteval void tfn() { }
+
+static_assert (!is_object (template_arguments_of (^^tfn<f>)[0]));
+static_assert (!is_object (^^f));
+static_assert (template_arguments_of (^^tfn<f>)[0] == ^^f);
diff --git a/gcc/testsuite/g++.dg/reflect/is_operator_function1.C b/gcc/testsuite/g++.dg/reflect/is_operator_function1.C
new file mode 100644 (file)
index 0000000..69084c5
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_operator_function.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename T>
+  operator T();
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto conversion_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (is_template)).front ();
+
+static_assert (!is_operator_function (null_reflection));
+static_assert (!is_operator_function (^^int));
+static_assert (!is_operator_function (^^::));
+static_assert (!is_operator_function (^^foo));
+static_assert (is_operator_function (^^S::operator+));
+static_assert (is_operator_function (^^operator&&));
+static_assert (!is_operator_function (^^operator||));
+static_assert (is_operator_function (^^operator||<int>));
+static_assert (!is_operator_function (^^S::operator-));
+static_assert (is_operator_function (^^S::operator-<int>));
+static_assert (!is_operator_function (^^S::operator int));
+static_assert (!is_operator_function (conversion_template));
+static_assert (!is_operator_function (^^S::fn));
+static_assert (!is_operator_function (^^operator""_a));
+static_assert (!is_operator_function (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_operator_function_template1.C b/gcc/testsuite/g++.dg/reflect/is_operator_function_template1.C
new file mode 100644 (file)
index 0000000..12def21
--- /dev/null
@@ -0,0 +1,57 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_operator_function_template.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S &operator+(const S&);
+
+  template <typename T>
+  S &operator-(const S&);
+
+  operator int();
+
+  void fn();
+};
+
+struct T {
+  template <typename T>
+  operator T ();
+};
+
+bool operator&&(const S&, const S&);
+
+template <typename T>
+bool operator||(const S&, const T&);
+
+int operator""_a(const char *);
+
+template<char...>
+int operator""_b();
+
+constexpr auto conversion_template
+  = (members_of (^^T, access_context::current ()) | std::views::filter (is_template)).front ();
+
+static_assert (!is_operator_function_template (null_reflection));
+static_assert (!is_operator_function_template (^^int));
+static_assert (!is_operator_function_template (^^::));
+static_assert (!is_operator_function_template (^^foo));
+static_assert (!is_operator_function_template (^^S::operator+));
+static_assert (!is_operator_function_template (^^operator&&));
+static_assert (is_operator_function_template (^^operator||));
+static_assert (!is_operator_function_template (^^operator||<int>));
+static_assert (is_operator_function_template (^^S::operator-));
+static_assert (!is_operator_function_template (^^S::operator-<int>));
+static_assert (is_operator_function_template (template_of (^^S::operator-<int>)));
+static_assert (!is_operator_function_template (^^S::operator int));
+static_assert (!is_operator_function_template (conversion_template));
+static_assert (!is_operator_function_template (^^S::fn));
+static_assert (!is_operator_function_template (^^operator""_a));
+static_assert (!is_operator_function_template (^^operator""_b));
diff --git a/gcc/testsuite/g++.dg/reflect/is_override1.C b/gcc/testsuite/g++.dg/reflect/is_override1.C
new file mode 100644 (file)
index 0000000..e55cb7f
--- /dev/null
@@ -0,0 +1,154 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_override.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_override (null_reflection));
+static_assert (!is_override (^^::));
+static_assert (!is_override (^^ns));
+static_assert (!is_override (^^ns_alias));
+static_assert (!is_override (reflect_constant (3)));
+static_assert (!is_override (^^cls));
+static_assert (!is_override (^^cls::dm));
+static_assert (!is_override (^^cls::ref_dm));
+static_assert (!is_override (^^cls::static_dm));
+static_assert (!is_override (^^cls::mem_fun));
+static_assert (!is_override (^^cls::static_mem_fun));
+static_assert (!is_override (^^cls::type));
+static_assert (!is_override (^^cls_var));
+static_assert (!is_override (^^onion));
+static_assert (!is_override (^^anon));
+static_assert (!is_override (^^fun));
+static_assert (!is_override (^^alias));
+static_assert (!is_override (^^var));
+static_assert (!is_override (^^ref));
+static_assert (!is_override (^^rref));
+static_assert (!is_override (^^ptr));
+static_assert (!is_override (^^cls_tmpl));
+static_assert (!is_override (^^cls_tmpl<int>));
+static_assert (!is_override (^^incomplete_cls<int>));
+static_assert (!is_override (^^fun_tmpl));
+static_assert (!is_override (^^fun_tmpl<int>));
+static_assert (!is_override (^^conc));
+static_assert (!is_override (substitute (^^conc, { ^^int })));
+static_assert (!is_override (^^var_tmpl));
+static_assert (!is_override (^^var_tmpl<int>));
+static_assert (!is_override (^^cls_tmpl_alias));
+static_assert (!is_override (^^cls_tmpl_alias<int>));
+static_assert (!is_override (^^Enum));
+static_assert (!is_override (^^Enum::A));
+static_assert (!is_override (^^Enum_class));
+static_assert (!is_override (^^Enum_class::A));
+static_assert (!is_override (^^decomp));
+static_assert (!is_override (^^decomp_ref));
+static_assert (!is_override (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_override (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_override (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_override (^^T));
+  static_assert (!is_override (R));
+  static_assert (!is_override (R2));
+  static_assert (!is_override (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^conc>();
+  static_assert (!is_override (^^p));
+  static_assert (!is_override (^^c));
+}
+
+struct Base2 {
+  void foo ();
+  virtual void bar ();
+  virtual void baz ();
+  virtual void qux ();
+  virtual void corge () = 0;
+  virtual void garply ();
+  virtual ~Base2 ();
+};
+
+struct Derived2 : Base2 {
+  void foo ();
+  virtual void baz ();
+  virtual void qux () override;
+  virtual void corge ();
+  virtual void freddy ();
+};
+
+struct Derived3 : Derived2 {
+  void foo ();
+  virtual void qux () override;
+  virtual void corge ();
+  virtual void freddy ();
+};
+
+static_assert (!is_override (^^Base2::foo));
+static_assert (!is_override (^^Base2::bar));
+static_assert (!is_override (^^Base2::baz));
+static_assert (!is_override (^^Base2::qux));
+static_assert (!is_override (^^Base2::corge));
+static_assert (!is_override (^^Base2::garply));
+static_assert (!is_override (^^Base2::~Base2));
+static_assert (!is_override (^^Derived2::foo));
+static_assert (!is_override (^^Derived2::bar));
+static_assert (is_override (^^Derived2::baz));
+static_assert (is_override (^^Derived2::qux));
+static_assert (is_override (^^Derived2::corge));
+static_assert (!is_override (^^Derived2::garply));
+static_assert (!is_override (^^Derived2::freddy));
+static_assert (is_override (^^Derived2::~Derived2));
+static_assert (!is_override (^^Derived3::foo));
+static_assert (!is_override (^^Derived3::bar));
+static_assert (is_override (^^Derived3::baz));
+static_assert (is_override (^^Derived3::qux));
+static_assert (is_override (^^Derived3::corge));
+static_assert (!is_override (^^Derived3::garply));
+static_assert (is_override (^^Derived3::freddy));
+static_assert (is_override (^^Derived3::~Derived3));
diff --git a/gcc/testsuite/g++.dg/reflect/is_pure_virtual1.C b/gcc/testsuite/g++.dg/reflect/is_pure_virtual1.C
new file mode 100644 (file)
index 0000000..ed775d1
--- /dev/null
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_pure_virtual.
+
+#include <meta>
+
+using namespace std::meta;
+
+void func() {}
+
+struct B {
+  void nonvirt();
+  virtual void virt_no_override();
+  virtual void virt_implicit_override();
+  virtual void virt_explicit_override();
+  virtual void pure_virt() = 0;
+  virtual ~B() = 0;
+};
+
+struct D : B {
+  void nonvirt();
+  void virt_implicit_override();
+  void virt_explicit_override() override;
+  void pure_virt();
+  virtual ~D() = 0;
+};
+
+struct DD {
+  ~DD() = delete;
+};
+
+static_assert (!is_pure_virtual (^^func));
+
+static_assert (!is_pure_virtual (^^B::nonvirt));
+static_assert (!is_pure_virtual (^^B::virt_no_override));
+static_assert (!is_pure_virtual (^^B::virt_implicit_override));
+static_assert (!is_pure_virtual (^^B::virt_explicit_override));
+static_assert (is_pure_virtual (^^B::pure_virt));
+static_assert (is_pure_virtual (^^B::~B));
+
+static_assert (!is_pure_virtual (^^D::nonvirt));
+static_assert (!is_pure_virtual (^^D::virt_no_override));
+static_assert (!is_pure_virtual (^^D::virt_implicit_override));
+static_assert (!is_pure_virtual (^^D::virt_explicit_override));
+static_assert (!is_pure_virtual (^^D::pure_virt));
+static_assert (is_pure_virtual (^^D::~D));
+
+static_assert (!is_pure_virtual (^^DD::~DD));
diff --git a/gcc/testsuite/g++.dg/reflect/is_special_member_function1.C b/gcc/testsuite/g++.dg/reflect/is_special_member_function1.C
new file mode 100644 (file)
index 0000000..3b63259
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_special_member_function.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+void foo ();
+
+struct S {
+  S ()
+  {
+    int a;
+    static_assert (is_special_member_function (parent_of (^^a)));
+  }
+  S (int)
+  {
+    int a;
+    static_assert (!is_special_member_function (parent_of (^^a)));
+  }
+  S (const S &)
+  {
+    int a;
+    static_assert (is_special_member_function (parent_of (^^a)));
+  }
+  S (S &&)
+  {
+    int a;
+    static_assert (is_special_member_function (parent_of (^^a)));
+  }
+  S &operator = (const S &)
+  {
+    int a;
+    static_assert (is_special_member_function (parent_of (^^a)));
+    return *this;
+  }
+  S &operator += (const S &)
+  {
+    int a;
+    static_assert (!is_special_member_function (parent_of (^^a)));
+    return *this;
+  }
+  void bar ()
+  {
+    int a;
+    static_assert (!is_special_member_function (parent_of (^^a)));
+  }
+  ~S ()
+  {
+    int a;
+    static_assert (is_special_member_function (parent_of (^^a)));
+  }
+};
+
+struct T {
+  T &operator = (const S &)
+  {
+    int a;
+    static_assert (!is_special_member_function (parent_of (^^a)));
+    return *this;
+  }
+  T &operator *= (const S &)
+  {
+    int a;
+    static_assert (!is_special_member_function (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct U {
+  template <typename T>
+  U (T &)
+  {
+    T a;
+    static_assert (is_constructor (parent_of (^^a)));
+  }
+  U &operator = (U &&)
+  {
+    int a;
+    static_assert (is_special_member_function (parent_of (^^a)));
+    return *this;
+  }
+};
+
+struct V {
+  V (int a = 42, long b = 18)
+  {
+    static_assert (is_special_member_function (parent_of (^^a)));
+  }
+};
+
+static_assert (!is_special_member_function (null_reflection));
+static_assert (!is_special_member_function (^^int));
+static_assert (!is_special_member_function (^^::));
+static_assert (!is_special_member_function (^^foo));
+static_assert (!is_special_member_function (^^S::bar));
+static_assert (is_special_member_function (^^S::operator =));
+static_assert (!is_special_member_function (^^S::operator +=));
+static_assert (!is_special_member_function (^^T::operator *=));
diff --git a/gcc/testsuite/g++.dg/reflect/is_static_member1.C b/gcc/testsuite/g++.dg/reflect/is_static_member1.C
new file mode 100644 (file)
index 0000000..c87aedc
--- /dev/null
@@ -0,0 +1,127 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_static_member.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_static_member (null_reflection));
+static_assert (!is_static_member (^^::));
+static_assert (!is_static_member (^^ns));
+static_assert (!is_static_member (^^ns_alias));
+static_assert (!is_static_member (reflect_constant (3)));
+static_assert (!is_static_member (^^cls));
+static_assert (!is_static_member (^^cls::dm));
+static_assert (!is_static_member (^^cls::ref_dm));
+static_assert (is_static_member (^^cls::static_dm));
+static_assert (!is_static_member (^^cls::mem_fun));
+static_assert (is_static_member (^^cls::static_mem_fun));
+static_assert (!is_static_member (^^cls::type));
+static_assert (!is_static_member (^^cls::E));
+static_assert (!is_static_member (^^cls::B));
+static_assert (!is_static_member (^^cls::C));
+static_assert (!is_static_member (^^cls::D));
+static_assert (!is_static_member (^^cls::F));
+static_assert (!is_static_member (^^cls::F::G));
+static_assert (!is_static_member (^^cls::F::H));
+static_assert (!is_static_member (^^cls::S));
+static_assert (!is_static_member (^^cls::U));
+static_assert (!is_static_member (^^cls::foo));
+static_assert (!is_static_member (^^cls::foo <0>));
+static_assert (is_static_member (^^cls::bar));
+static_assert (is_static_member (^^cls::bar <42>));
+static_assert (!is_static_member (^^cls_var));
+static_assert (!is_static_member (^^onion));
+static_assert (!is_static_member (^^anon));
+static_assert (!is_static_member (^^fun));
+static_assert (!is_static_member (^^alias));
+static_assert (!is_static_member (^^var));
+static_assert (!is_static_member (^^ref));
+static_assert (!is_static_member (^^rref));
+static_assert (!is_static_member (^^ptr));
+static_assert (!is_static_member (^^cls_tmpl));
+static_assert (!is_static_member (^^cls_tmpl<int>));
+static_assert (!is_static_member (^^incomplete_cls<int>));
+static_assert (!is_static_member (^^fun_tmpl));
+static_assert (!is_static_member (^^fun_tmpl<int>));
+static_assert (!is_static_member (^^conc));
+static_assert (!is_static_member (substitute (^^conc, { ^^int })));
+static_assert (!is_static_member (^^var_tmpl));
+static_assert (!is_static_member (^^var_tmpl<int>));
+static_assert (!is_static_member (^^cls_tmpl_alias));
+static_assert (!is_static_member (^^cls_tmpl_alias<int>));
+static_assert (!is_static_member (^^Enum));
+static_assert (!is_static_member (^^Enum::A));
+static_assert (!is_static_member (^^Enum_class));
+static_assert (!is_static_member (^^Enum_class::A));
+static_assert (!is_static_member (^^decomp));
+static_assert (!is_static_member (^^decomp_ref));
+static_assert (!is_static_member (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_static_member (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_static_member (bases_of (^^Derived, access_context::unprivileged ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_static_member (^^x));
+  static_assert (!is_static_member (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_static_member (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_static_member (^^S));
+  static_assert (!is_static_member (^^E));
+  static_assert (!is_static_member (^^F));
+  static_assert (!is_static_member (^^G));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_string_literal1.C b/gcc/testsuite/g++.dg/reflect/is_string_literal1.C
new file mode 100644 (file)
index 0000000..443c6d6
--- /dev/null
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::is_string_literal.
+
+#include <meta>
+
+constexpr char a = '\0';
+constexpr wchar_t b = L'\0';
+constexpr char16_t c = u'\0';
+constexpr char32_t d = U'\0';
+constexpr char8_t e = u8'\0';
+constexpr char f[] = "foobar";
+static_assert (!std::is_string_literal (&a));
+static_assert (!std::is_string_literal (&b));
+static_assert (!std::is_string_literal (&c));
+static_assert (!std::is_string_literal (&d));
+static_assert (!std::is_string_literal (&e));
+static_assert (!std::is_string_literal (&f[0]));
+static_assert (!std::is_string_literal (f + 2));
+static_assert (!std::is_string_literal (&f[2] + 3));
+static_assert (std::is_string_literal ("abcd"));
+static_assert (std::is_string_literal (&"abcd"[4]));
+static_assert (std::is_string_literal ("abcd" + 2));
+static_assert (std::is_string_literal (&"abcd"[1] + 1));
+static_assert (std::is_string_literal (L"foobar"));
+static_assert (std::is_string_literal (&L"foobar"[4]));
+static_assert (std::is_string_literal (L"foobar" + 2));
+static_assert (std::is_string_literal (&L"foobar"[1] + 1));
+static_assert (std::is_string_literal (u"corge"));
+static_assert (std::is_string_literal (&u"corge"[4]));
+static_assert (std::is_string_literal (u"corge" + 2));
+static_assert (std::is_string_literal (&u"corge"[1] + 1));
+static_assert (std::is_string_literal (U"garply"));
+static_assert (std::is_string_literal (&U"garply"[4]));
+static_assert (std::is_string_literal (U"garply" + 2));
+static_assert (std::is_string_literal (&U"garply"[1] + 1));
+static_assert (std::is_string_literal (u8"Certe, inquam, pĂ©rtinax non ero tibĂ­que, si mihi probĂĄbis ea, quĂŠ dices, libĂ©nter assĂ©ntiar."));
+static_assert (std::is_string_literal (&u8"Certe, inquam, pĂ©rtinax non ero tibĂ­que, si mihi probĂĄbis ea, quĂŠ dices, libĂ©nter assĂ©ntiar."[4]));
+static_assert (std::is_string_literal (u8"Certe, inquam, pĂ©rtinax non ero tibĂ­que, si mihi probĂĄbis ea, quĂŠ dices, libĂ©nter assĂ©ntiar." + 2));
+static_assert (std::is_string_literal (&u8"Certe, inquam, pĂ©rtinax non ero tibĂ­que, si mihi probĂĄbis ea, quĂŠ dices, libĂ©nter assĂ©ntiar."[1] + 1));
diff --git a/gcc/testsuite/g++.dg/reflect/is_structured_binding1.C b/gcc/testsuite/g++.dg/reflect/is_structured_binding1.C
new file mode 100644 (file)
index 0000000..10bbeb1
--- /dev/null
@@ -0,0 +1,99 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+#include <meta>
+#include <tuple>
+
+struct S
+{
+  int a;
+  int b;
+  double c;
+};
+
+int
+main ()
+{
+  {
+    // The initializer for the structured binding declaration has array type.
+    const int struct_binding[] = { 1, 2, 3 };
+
+    auto [x, y, z] = struct_binding;
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+    static_assert (std::meta::is_structured_binding (^^z));
+  }
+
+  {
+    // The initializer for the structured binding declaration is tuple-like.
+    auto struct_binding = std::make_tuple (1, 2, 3);
+
+    auto [x, y, z] = struct_binding;
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+    static_assert (std::meta::is_structured_binding (^^z));
+  }
+
+  {
+    // The initializer for the structured binding declaration is a struct
+    auto struct_binding = S{ 1, 2, 3.14 };
+    auto [x, y, z] = struct_binding;
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+    static_assert (std::meta::is_structured_binding (^^z));
+  }
+
+  {
+    // const auto structured binding
+    const int struct_binding[] = { 10, 20 };
+    const auto [x, y] = struct_binding;
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+  }
+
+  {
+    // auto& structured binding
+    int struct_binding[] = { 30, 40 };
+    auto &[x, y] = struct_binding;
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+  }
+
+  {
+    // const auto& structured binding
+    const int struct_binding[] = { 50, 60 };
+    const auto &[x, y] = struct_binding;
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+  }
+
+  {
+    // auto&& with rvalue
+    auto &&[x, y] = std::make_tuple (90, 100);
+
+    static_assert (std::meta::is_structured_binding (^^x));
+    static_assert (std::meta::is_structured_binding (^^y));
+  }
+
+  {
+    // Negative cases
+    int var = 42;
+    const int const_var = 43;
+    int &ref_var = var;
+
+    S s{ 1, 2, 3.14 };
+
+    static_assert (!std::meta::is_structured_binding (^^var));
+    static_assert (!std::meta::is_structured_binding (^^const_var));
+    static_assert (!std::meta::is_structured_binding (^^ref_var));
+    static_assert (!std::meta::is_structured_binding (^^s));
+    static_assert (!std::meta::is_structured_binding (^^S));
+    static_assert (!std::meta::is_structured_binding (^^int));
+    static_assert (!std::meta::is_structured_binding (^^::));
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_structured_binding2.C b/gcc/testsuite/g++.dg/reflect/is_structured_binding2.C
new file mode 100644 (file)
index 0000000..14a401a
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct S
+{
+  int a, b;
+  explicit operator bool () const noexcept { return a == b; }
+};
+
+template <typename S>
+void
+bar ()
+{
+  if (auto [i, j] = S{ 7, 7 })
+    {
+      constexpr auto ri = ^^i;
+      constexpr auto rj = ^^j;
+
+      static_assert (std::meta::is_structured_binding (ri));
+      static_assert (std::meta::is_structured_binding (rj));
+
+      static_assert (std::meta::is_structured_binding (^^i));
+      static_assert (std::meta::is_structured_binding (^^j));
+
+      static_assert (!std::meta::is_structured_binding (^^S));
+    }
+}
+
+int
+main ()
+{
+  bar<S> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_template1.C b/gcc/testsuite/g++.dg/reflect/is_template1.C
new file mode 100644 (file)
index 0000000..7418010
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_template.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_template (null_reflection));
+static_assert (!is_template (^^::));
+static_assert (!is_template (^^ns));
+static_assert (!is_template (^^ns_alias));
+static_assert (!is_template (reflect_constant (3)));
+static_assert (!is_template (^^cls));
+static_assert (!is_template (^^cls::dm));
+static_assert (!is_template (^^cls::ref_dm));
+static_assert (!is_template (^^cls::static_dm));
+static_assert (!is_template (^^cls::mem_fun));
+static_assert (!is_template (^^cls::static_mem_fun));
+static_assert (!is_template (^^cls::type));
+static_assert (!is_template (^^cls_var));
+static_assert (!is_template (^^onion));
+static_assert (!is_template (^^anon));
+static_assert (!is_template (^^fun));
+static_assert (!is_template (^^alias));
+static_assert (!is_template (^^var));
+static_assert (!is_template (^^ref));
+static_assert (!is_template (^^rref));
+static_assert (!is_template (^^ptr));
+static_assert (is_template (^^cls_tmpl));
+static_assert (!is_template (^^cls_tmpl<int>));
+static_assert (!is_template (^^incomplete_cls<int>));
+static_assert (is_template (^^fun_tmpl));
+static_assert (!is_template (^^fun_tmpl<int>));
+static_assert (is_template (^^conc));
+static_assert (!is_template (substitute (^^conc, { ^^int })));
+static_assert (is_template (^^var_tmpl));
+static_assert (!is_template (^^var_tmpl<int>));
+static_assert (is_template (^^cls_tmpl_alias));
+static_assert (!is_template (^^cls_tmpl_alias<int>));
+static_assert (!is_template (^^Enum));
+static_assert (!is_template (^^Enum::A));
+static_assert (!is_template (^^Enum_class));
+static_assert (!is_template (^^Enum_class::A));
+static_assert (!is_template (^^decomp));
+static_assert (!is_template (^^decomp_ref));
+static_assert (!is_template (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_template (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_template (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_template (^^T));
+  static_assert (!is_template (R));
+  static_assert (!is_template (R2));
+  static_assert (is_template (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls_tmpl_alias>();
+  static_assert (!is_template (^^p));
+  static_assert (!is_template (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_template2.C b/gcc/testsuite/g++.dg/reflect/is_template2.C
new file mode 100644 (file)
index 0000000..51ce6bf
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_template.
+
+#include <meta>
+#include <vector>
+
+static_assert (std::meta::is_template (^^std::vector));
+static_assert (!std::meta::is_template (^^std::vector<int>));
diff --git a/gcc/testsuite/g++.dg/reflect/is_type1.C b/gcc/testsuite/g++.dg/reflect/is_type1.C
new file mode 100644 (file)
index 0000000..d2cdf77
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_type.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_type (null_reflection));
+static_assert (!is_type (^^::));
+static_assert (!is_type (^^ns));
+static_assert (!is_type (^^ns_alias));
+static_assert (!is_type (reflect_constant (3)));
+static_assert (is_type (^^cls));
+static_assert (!is_type (^^cls::dm));
+static_assert (!is_type (^^cls::ref_dm));
+static_assert (!is_type (^^cls::static_dm));
+static_assert (!is_type (^^cls::mem_fun));
+static_assert (!is_type (^^cls::static_mem_fun));
+static_assert (is_type (^^cls::type));
+static_assert (!is_type (^^cls_var));
+static_assert (is_type (^^onion));
+static_assert (!is_type (^^anon));
+static_assert (!is_type (^^fun));
+static_assert (is_type (^^alias));
+static_assert (!is_type (^^var));
+static_assert (!is_type (^^ref));
+static_assert (!is_type (^^rref));
+static_assert (!is_type (^^ptr));
+static_assert (!is_type (^^cls_tmpl));
+static_assert (is_type (^^cls_tmpl<int>));
+static_assert (is_type (^^incomplete_cls<int>));
+static_assert (!is_type (^^fun_tmpl));
+static_assert (!is_type (^^fun_tmpl<int>));
+static_assert (!is_type (^^conc));
+static_assert (!is_type (substitute (^^conc, { ^^int })));
+static_assert (!is_type (^^var_tmpl));
+static_assert (!is_type (^^var_tmpl<int>));
+static_assert (!is_type (^^cls_tmpl_alias));
+static_assert (is_type (^^cls_tmpl_alias<int>));
+static_assert (is_type (^^Enum));
+static_assert (!is_type (^^Enum::A));
+static_assert (is_type (^^Enum_class));
+static_assert (!is_type (^^Enum_class::A));
+static_assert (!is_type (^^decomp));
+static_assert (!is_type (^^decomp_ref));
+static_assert (!is_type (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_type (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_type (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (is_type (^^T));
+  static_assert (!is_type (R));
+  static_assert (!is_type (R2));
+  static_assert (is_type (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_type (^^p));
+  static_assert (!is_type (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_type_alias1.C b/gcc/testsuite/g++.dg/reflect/is_type_alias1.C
new file mode 100644 (file)
index 0000000..a404a5c
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_type_alias.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_type_alias (null_reflection));
+static_assert (!is_type_alias (^^::));
+static_assert (!is_type_alias (^^ns));
+static_assert (!is_type_alias (^^ns_alias));
+static_assert (!is_type_alias (reflect_constant (3)));
+static_assert (!is_type_alias (^^cls));
+static_assert (!is_type_alias (^^cls::dm));
+static_assert (!is_type_alias (^^cls::ref_dm));
+static_assert (!is_type_alias (^^cls::static_dm));
+static_assert (!is_type_alias (^^cls::mem_fun));
+static_assert (!is_type_alias (^^cls::static_mem_fun));
+static_assert (is_type_alias (^^cls::type));
+static_assert (!is_type_alias (^^cls_var));
+static_assert (!is_type_alias (^^onion));
+static_assert (!is_type_alias (^^anon));
+static_assert (!is_type_alias (^^fun));
+static_assert (is_type_alias (^^alias));
+static_assert (!is_type_alias (^^var));
+static_assert (!is_type_alias (^^ref));
+static_assert (!is_type_alias (^^rref));
+static_assert (!is_type_alias (^^ptr));
+static_assert (!is_type_alias (^^cls_tmpl));
+static_assert (!is_type_alias (^^cls_tmpl<int>));
+static_assert (!is_type_alias (^^incomplete_cls<int>));
+static_assert (!is_type_alias (^^fun_tmpl));
+static_assert (!is_type_alias (^^fun_tmpl<int>));
+static_assert (!is_type_alias (^^conc));
+static_assert (!is_type_alias (substitute (^^conc, { ^^int })));
+static_assert (!is_type_alias (^^var_tmpl));
+static_assert (!is_type_alias (^^var_tmpl<int>));
+static_assert (!is_type_alias (^^cls_tmpl_alias));
+static_assert (is_type_alias (^^cls_tmpl_alias<int>));
+static_assert (!is_type_alias (^^Enum));
+static_assert (!is_type_alias (^^Enum::A));
+static_assert (!is_type_alias (^^Enum_class));
+static_assert (!is_type_alias (^^Enum_class::A));
+static_assert (!is_type_alias (^^decomp));
+static_assert (!is_type_alias (^^decomp_ref));
+static_assert (!is_type_alias (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_type_alias (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_type_alias (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_type_alias (^^T));
+  static_assert (!is_type_alias (R));
+  static_assert (!is_type_alias (R2));
+  static_assert (!is_type_alias (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_type_alias (^^p));
+  static_assert (!is_type_alias (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_type_alias2.C b/gcc/testsuite/g++.dg/reflect/is_type_alias2.C
new file mode 100644 (file)
index 0000000..0fa0a46
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_type_alias.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<typename T>
+struct S { };
+
+using U = S<int>;
+
+template<typename T>
+using V = S<T*>;
+
+typedef int T;
+
+static_assert (!is_type_alias (^^S<int>));
+static_assert (is_type_alias (^^U));
+static_assert (!is_type_alias (^^V));
+static_assert (is_type_alias (^^V<int>));
+static_assert (is_type_alias (^^T));
+static_assert (!is_type_alias (^^wchar_t));
+static_assert (is_type_alias (^^size_t));
+
+using A = void(int, int);
+static_assert (is_type_alias (^^A));
+static_assert (!is_type_alias (dealias(^^A)));
diff --git a/gcc/testsuite/g++.dg/reflect/is_type_alias3.C b/gcc/testsuite/g++.dg/reflect/is_type_alias3.C
new file mode 100644 (file)
index 0000000..7f73fba
--- /dev/null
@@ -0,0 +1,77 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_type_alias.
+
+#include <meta>
+
+using namespace std::meta;
+
+typedef int I;
+static_assert (is_type_alias (^^I));
+static_assert (!is_type_alias (^^const I));
+static_assert (!is_type_alias (^^I const));
+static_assert (!is_type_alias (^^I &&));
+static_assert (^^I != ^^int);
+static_assert (^^const I == ^^const int);
+static_assert (^^I const == ^^const int);
+static_assert (^^I && == ^^int &&);
+
+typedef const int J;
+static_assert (is_type_alias (^^J));
+static_assert (!is_type_alias (^^const J));
+static_assert (!is_type_alias (^^J const));
+static_assert (!is_type_alias (^^J &));
+static_assert (^^J != ^^const int);
+static_assert (^^const J == ^^const int);
+static_assert (^^J const == ^^const int);
+static_assert (^^J & == ^^const int &);
+
+template <typename> struct cls_tmpl {};
+template <typename T> using cls_tmpl_alias = const cls_tmpl <T>;
+
+static_assert (is_type_alias (^^cls_tmpl_alias <int>));
+static_assert (!is_type_alias (^^const cls_tmpl_alias <int>));
+static_assert (!is_type_alias (^^cls_tmpl_alias <int> const));
+static_assert (!is_type_alias (^^cls_tmpl_alias <int> &&));
+static_assert (^^cls_tmpl_alias <int> != ^^const cls_tmpl <int>);
+static_assert (^^cls_tmpl_alias <int> != ^^const cls_tmpl_alias <int>);
+static_assert (^^const cls_tmpl_alias <int> == ^^const cls_tmpl <int>);
+static_assert (^^cls_tmpl_alias <int> const == ^^const cls_tmpl <int>);
+static_assert (^^cls_tmpl_alias <int> && == ^^const cls_tmpl <int> &&);
+
+namespace N1
+{
+  template <typename> struct cls_tmpl {};
+  template <typename T> using cls_tmpl_alias = const cls_tmpl <T>;
+
+  static_assert (is_type_alias (^^N1::cls_tmpl_alias <int>));
+  static_assert (!is_type_alias (^^const N1::cls_tmpl_alias <int>));
+  static_assert (!is_type_alias (^^N1::cls_tmpl_alias <int> const));
+  static_assert (!is_type_alias (^^N1::cls_tmpl_alias <int> &&));
+  static_assert (^^N1::cls_tmpl_alias <int> != ^^const N1::cls_tmpl <int>);
+  static_assert (^^N1::cls_tmpl_alias <int> != ^^const N1::cls_tmpl_alias <int>);
+  static_assert (^^const N1::cls_tmpl_alias <int> == ^^const N1::cls_tmpl <int>);
+  static_assert (^^N1::cls_tmpl_alias <int> const == ^^const N1::cls_tmpl <int>);
+  static_assert (^^N1::cls_tmpl_alias <int> && == ^^const N1::cls_tmpl <int> &&);
+  static_assert (is_type_alias (^^N1:: template cls_tmpl_alias <int>));
+  static_assert (!is_type_alias (^^const N1:: template cls_tmpl_alias <int>));
+  static_assert (!is_type_alias (^^N1:: template cls_tmpl_alias <int> const));
+  static_assert (!is_type_alias (^^N1:: template cls_tmpl_alias <int> &&));
+  static_assert (^^N1:: template cls_tmpl_alias <int> != ^^const N1:: template cls_tmpl <int>);
+  static_assert (^^N1:: template cls_tmpl_alias <int> != ^^const N1:: template cls_tmpl_alias <int>);
+  static_assert (^^const N1:: template cls_tmpl_alias <int> == ^^const N1:: template cls_tmpl <int>);
+  static_assert (^^N1:: template cls_tmpl_alias <int> const == ^^const N1:: template cls_tmpl <int>);
+  static_assert (^^N1:: template cls_tmpl_alias <int> && == ^^const N1:: template cls_tmpl <int> &&);
+}
+
+const I a = 42;
+static_assert (!is_type_alias (type_of (^^a)));
+static_assert (type_of (^^a) == ^^const int);
+
+J b = 42;
+static_assert (!is_type_alias (type_of (^^b)));
+static_assert (type_of (^^b) == ^^const int);
+
+cls_tmpl_alias <long> c;
+static_assert (!is_type_alias (type_of (^^c)));
+static_assert (type_of (^^c) == ^^const cls_tmpl <long>);
diff --git a/gcc/testsuite/g++.dg/reflect/is_user_declared1.C b/gcc/testsuite/g++.dg/reflect/is_user_declared1.C
new file mode 100644 (file)
index 0000000..0695fb4
--- /dev/null
@@ -0,0 +1,210 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_user_declared.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_user_declared (null_reflection));
+static_assert (!is_user_declared (^^::));
+static_assert (!is_user_declared (^^ns));
+static_assert (!is_user_declared (^^ns_alias));
+static_assert (!is_user_declared (reflect_constant (3)));
+static_assert (!is_user_declared (^^cls));
+static_assert (!is_user_declared (^^cls::dm));
+static_assert (!is_user_declared (^^cls::ref_dm));
+static_assert (!is_user_declared (^^cls::static_dm));
+static_assert (is_user_declared (^^cls::mem_fun));
+static_assert (is_user_declared (^^cls::static_mem_fun));
+static_assert (!is_user_declared (^^cls::type));
+static_assert (!is_user_declared (^^cls::E));
+static_assert (!is_user_declared (^^cls::B));
+static_assert (!is_user_declared (^^cls::C));
+static_assert (!is_user_declared (^^cls::D));
+static_assert (!is_user_declared (^^cls::F));
+static_assert (!is_user_declared (^^cls::F::G));
+static_assert (!is_user_declared (^^cls::F::H));
+static_assert (!is_user_declared (^^cls::S));
+static_assert (!is_user_declared (^^cls::U));
+static_assert (!is_user_declared (^^cls::foo));
+static_assert (is_user_declared (^^cls::foo <0>));
+static_assert (!is_user_declared (^^cls::bar));
+static_assert (is_user_declared (^^cls::bar <42>));
+static_assert (!is_user_declared (^^cls_var));
+static_assert (!is_user_declared (^^onion));
+static_assert (!is_user_declared (^^anon));
+static_assert (is_user_declared (^^fun));
+static_assert (!is_user_declared (^^alias));
+static_assert (!is_user_declared (^^var));
+static_assert (!is_user_declared (^^ref));
+static_assert (!is_user_declared (^^rref));
+static_assert (!is_user_declared (^^ptr));
+static_assert (!is_user_declared (^^cls_tmpl));
+static_assert (!is_user_declared (^^cls_tmpl<int>));
+static_assert (!is_user_declared (^^incomplete_cls<int>));
+static_assert (!is_user_declared (^^fun_tmpl));
+static_assert (is_user_declared (^^fun_tmpl<int>));
+static_assert (!is_user_declared (^^conc));
+static_assert (!is_user_declared (substitute (^^conc, { ^^int })));
+static_assert (!is_user_declared (^^var_tmpl));
+static_assert (!is_user_declared (^^var_tmpl<int>));
+static_assert (!is_user_declared (^^cls_tmpl_alias));
+static_assert (!is_user_declared (^^cls_tmpl_alias<int>));
+static_assert (!is_user_declared (^^Enum));
+static_assert (!is_user_declared (^^Enum::A));
+static_assert (!is_user_declared (^^Enum_class));
+static_assert (!is_user_declared (^^Enum_class::A));
+static_assert (!is_user_declared (^^decomp));
+static_assert (!is_user_declared (^^decomp_ref));
+static_assert (!is_user_declared (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_user_declared (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_user_declared (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_user_declared (^^x));
+  static_assert (!is_user_declared (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_user_declared (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_user_declared (^^S));
+  static_assert (!is_user_declared (^^E));
+  static_assert (!is_user_declared (^^F));
+  static_assert (!is_user_declared (^^G));
+}
+
+void bar (int, long) = delete;
+void baz (int) = delete ("foobar");
+static_assert (is_user_declared (^^bar));
+static_assert (is_user_declared (^^baz));
+
+struct S
+{
+  bool operator == (const S &) const = default;
+  auto operator <=> (const S &) const = default;
+  S &operator = (const S &) = default;
+  int s;
+  void foo ();
+  template <int N>
+  void bar ();
+};
+
+struct V
+{
+  V (const V &);
+};
+
+struct W
+{
+  W (const W &);
+  bool operator == (const W &) const;
+  auto operator <=> (const W &) const;
+  W &operator = (const W &) { return *this; }
+};
+
+struct X
+{
+  X (const X &);
+  bool operator == (const X &) const = delete;
+  auto operator <=> (const X &) const = delete;
+  X &operator = (const X &) = delete;
+  void foo () = delete;
+  template <int N>
+  void bar () = delete;
+};
+
+static_assert (is_user_declared (^^S::operator ==));
+static_assert (is_user_declared (^^S::operator <=>));
+static_assert (is_user_declared (^^S::operator =));
+static_assert (is_user_declared (^^S::foo));
+static_assert (!is_user_declared (^^S::bar));
+static_assert (is_user_declared (^^S::bar <42>));
+static_assert (!is_user_declared (^^V::operator =));
+static_assert (is_user_declared (^^W::operator ==));
+static_assert (is_user_declared (^^W::operator <=>));
+static_assert (is_user_declared (^^W::operator =));
+static_assert (is_user_declared (^^X::operator ==));
+static_assert (is_user_declared (^^X::operator <=>));
+static_assert (is_user_declared (^^X::operator =));
+static_assert (is_user_declared (^^X::foo));
+static_assert (!is_user_declared (^^X::bar));
+
+struct Y
+{
+  ~Y () = default;
+  int y;
+};
+static_assert (is_user_declared (^^Y::~Y));
+
+struct Z
+{
+  int z;
+};
+static_assert (!is_user_declared (^^Z::~Z));
+
+struct R
+{
+  ~R ();
+  int r;
+};
+static_assert (is_user_declared (^^R::~R));
+
+struct H
+{
+  ~H () = delete;
+  int h;
+};
+static_assert (is_user_declared (^^H::~H));
diff --git a/gcc/testsuite/g++.dg/reflect/is_user_declared2.C b/gcc/testsuite/g++.dg/reflect/is_user_declared2.C
new file mode 100644 (file)
index 0000000..959a89e
--- /dev/null
@@ -0,0 +1,91 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_deleted.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template<typename F>
+consteval info
+select_mem(info clazz, F f)
+{
+  for (info x : members_of(clazz, access_context::unchecked()))
+    if (f(x))
+      return x;
+}
+
+struct ExplicitDef
+{
+  ExplicitDef() = default;
+  ExplicitDef(const ExplicitDef&) = default;
+  ExplicitDef(ExplicitDef&&) = default;
+
+  ExplicitDef& operator=(const ExplicitDef&) = default;
+  ExplicitDef& operator=(ExplicitDef&&) = default;
+  
+  ~ExplicitDef() = default;
+};
+
+static_assert (is_user_declared (select_mem (^^ExplicitDef, is_default_constructor)));
+static_assert (is_user_declared (select_mem (^^ExplicitDef, is_copy_constructor)));
+static_assert (is_user_declared (select_mem (^^ExplicitDef, is_move_constructor)));
+static_assert (is_user_declared (select_mem (^^ExplicitDef, is_copy_assignment)));
+static_assert (is_user_declared (select_mem (^^ExplicitDef, is_move_assignment)));
+static_assert (is_user_declared (select_mem (^^ExplicitDef, is_destructor)));
+
+struct ExplicitDel
+{
+  ExplicitDel() = default;
+  ExplicitDel(const ExplicitDel&) = default;
+  ExplicitDel(ExplicitDel&&) = default;
+
+  ExplicitDel& operator=(const ExplicitDel&) = default;
+  ExplicitDel& operator=(ExplicitDel&&) = default;
+  
+  ~ExplicitDel() = default;
+};
+
+static_assert (is_user_declared (select_mem (^^ExplicitDel, is_default_constructor)));
+static_assert (is_user_declared (select_mem (^^ExplicitDel, is_copy_constructor)));
+static_assert (is_user_declared (select_mem (^^ExplicitDel, is_move_constructor)));
+static_assert (is_user_declared (select_mem (^^ExplicitDel, is_copy_assignment)));
+static_assert (is_user_declared (select_mem (^^ExplicitDel, is_move_assignment)));
+static_assert (is_user_declared (select_mem (^^ExplicitDel, is_destructor)));
+
+struct ImplicitDef
+{
+};
+
+static_assert (!is_user_declared (select_mem (^^ImplicitDef, is_default_constructor)));
+static_assert (!is_user_declared (select_mem (^^ImplicitDef, is_copy_constructor)));
+static_assert (!is_user_declared (select_mem (^^ImplicitDef, is_move_constructor)));
+static_assert (!is_user_declared (select_mem (^^ImplicitDef, is_copy_assignment)));
+static_assert (!is_user_declared (select_mem (^^ImplicitDef, is_move_assignment)));
+static_assert (!is_user_declared (select_mem (^^ImplicitDef, is_destructor)));
+
+struct ExplicitRelOps
+{
+  bool operator==(const ExplicitRelOps&) const = default;
+  auto operator<=>(const ExplicitRelOps&) const = default;
+};
+static_assert (is_user_declared (^^ExplicitRelOps::operator==));
+static_assert (is_user_declared (^^ExplicitRelOps::operator<=>));
+
+struct DelRelOps
+{
+  bool operator==(const DelRelOps&) const = delete;
+  auto operator<=>(const DelRelOps&) const = delete;
+};
+static_assert (is_user_declared (^^DelRelOps::operator==));
+static_assert (is_user_declared (^^DelRelOps::operator<=>));
+
+struct ImplicitRelOps
+{
+  // operator== is implicitly declared
+  auto operator<=>(const ImplicitRelOps&) const = default;
+};
+static_assert (!is_user_declared (^^ImplicitRelOps::operator==));
+static_assert (is_user_declared (^^ImplicitRelOps::operator<=>));
+
diff --git a/gcc/testsuite/g++.dg/reflect/is_user_provided1.C b/gcc/testsuite/g++.dg/reflect/is_user_provided1.C
new file mode 100644 (file)
index 0000000..8298ea5
--- /dev/null
@@ -0,0 +1,210 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_user_provided.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+  enum E {
+    B, C, D
+  };
+  enum class F {
+    G, H
+  };
+  struct S {};
+  union U {};
+  template <int N>
+  void foo ();
+  template <int N>
+  static void bar ();
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_user_provided (null_reflection));
+static_assert (!is_user_provided (^^::));
+static_assert (!is_user_provided (^^ns));
+static_assert (!is_user_provided (^^ns_alias));
+static_assert (!is_user_provided (reflect_constant (3)));
+static_assert (!is_user_provided (^^cls));
+static_assert (!is_user_provided (^^cls::dm));
+static_assert (!is_user_provided (^^cls::ref_dm));
+static_assert (!is_user_provided (^^cls::static_dm));
+static_assert (is_user_provided (^^cls::mem_fun));
+static_assert (is_user_provided (^^cls::static_mem_fun));
+static_assert (!is_user_provided (^^cls::type));
+static_assert (!is_user_provided (^^cls::E));
+static_assert (!is_user_provided (^^cls::B));
+static_assert (!is_user_provided (^^cls::C));
+static_assert (!is_user_provided (^^cls::D));
+static_assert (!is_user_provided (^^cls::F));
+static_assert (!is_user_provided (^^cls::F::G));
+static_assert (!is_user_provided (^^cls::F::H));
+static_assert (!is_user_provided (^^cls::S));
+static_assert (!is_user_provided (^^cls::U));
+static_assert (!is_user_provided (^^cls::foo));
+static_assert (is_user_provided (^^cls::foo <0>));
+static_assert (!is_user_provided (^^cls::bar));
+static_assert (is_user_provided (^^cls::bar <42>));
+static_assert (!is_user_provided (^^cls_var));
+static_assert (!is_user_provided (^^onion));
+static_assert (!is_user_provided (^^anon));
+static_assert (is_user_provided (^^fun));
+static_assert (!is_user_provided (^^alias));
+static_assert (!is_user_provided (^^var));
+static_assert (!is_user_provided (^^ref));
+static_assert (!is_user_provided (^^rref));
+static_assert (!is_user_provided (^^ptr));
+static_assert (!is_user_provided (^^cls_tmpl));
+static_assert (!is_user_provided (^^cls_tmpl<int>));
+static_assert (!is_user_provided (^^incomplete_cls<int>));
+static_assert (!is_user_provided (^^fun_tmpl));
+static_assert (is_user_provided (^^fun_tmpl<int>));
+static_assert (!is_user_provided (^^conc));
+static_assert (!is_user_provided (substitute (^^conc, { ^^int })));
+static_assert (!is_user_provided (^^var_tmpl));
+static_assert (!is_user_provided (^^var_tmpl<int>));
+static_assert (!is_user_provided (^^cls_tmpl_alias));
+static_assert (!is_user_provided (^^cls_tmpl_alias<int>));
+static_assert (!is_user_provided (^^Enum));
+static_assert (!is_user_provided (^^Enum::A));
+static_assert (!is_user_provided (^^Enum_class));
+static_assert (!is_user_provided (^^Enum_class::A));
+static_assert (!is_user_provided (^^decomp));
+static_assert (!is_user_provided (^^decomp_ref));
+static_assert (!is_user_provided (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_user_provided (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_user_provided (bases_of (^^Derived, access_context::current ())[0]));
+
+void
+foo (int x)
+{
+  static_assert (!is_user_provided (^^x));
+  static_assert (!is_user_provided (parameters_of (^^foo)[0]));
+  int v;
+  static_assert (!is_user_provided (^^v));
+  struct S {};
+  enum E { F, G };
+  static_assert (!is_user_provided (^^S));
+  static_assert (!is_user_provided (^^E));
+  static_assert (!is_user_provided (^^F));
+  static_assert (!is_user_provided (^^G));
+}
+
+void bar (int, long) = delete;
+void baz (int) = delete ("foobar");
+static_assert (!is_user_provided (^^bar));
+static_assert (!is_user_provided (^^baz));
+
+struct S
+{
+  bool operator == (const S &) const = default;
+  auto operator <=> (const S &) const = default;
+  S &operator = (const S &) = default;
+  int s;
+  void foo ();
+  template <int N>
+  void bar ();
+};
+
+struct V
+{
+  V (const V &);
+};
+
+struct W
+{
+  W (const W &);
+  bool operator == (const W &) const;
+  auto operator <=> (const W &) const;
+  W &operator = (const W &) { return *this; }
+};
+
+struct X
+{
+  X (const X &);
+  bool operator == (const X &) const = delete;
+  auto operator <=> (const X &) const = delete;
+  X &operator = (const X &) = delete;
+  void foo () = delete;
+  template <int N>
+  void bar () = delete;
+};
+
+static_assert (!is_user_provided (^^S::operator ==));
+static_assert (!is_user_provided (^^S::operator <=>));
+static_assert (!is_user_provided (^^S::operator =));
+static_assert (is_user_provided (^^S::foo));
+static_assert (!is_user_provided (^^S::bar));
+static_assert (is_user_provided (^^S::bar <42>));
+static_assert (!is_user_provided (^^V::operator =));
+static_assert (is_user_provided (^^W::operator ==));
+static_assert (is_user_provided (^^W::operator <=>));
+static_assert (is_user_provided (^^W::operator =));
+static_assert (!is_user_provided (^^X::operator ==));
+static_assert (!is_user_provided (^^X::operator <=>));
+static_assert (!is_user_provided (^^X::operator =));
+static_assert (!is_user_provided (^^X::foo));
+static_assert (!is_user_provided (^^X::bar));
+
+struct Y
+{
+  ~Y () = default;
+  int y;
+};
+static_assert (!is_user_provided (^^Y::~Y));
+
+struct Z
+{
+  int z;
+};
+static_assert (!is_user_provided (^^Z::~Z));
+
+struct R
+{
+  ~R ();
+  int r;
+};
+static_assert (is_user_provided (^^R::~R));
+
+struct H
+{
+  ~H () = delete;
+  int h;
+};
+static_assert (!is_user_provided (^^H::~H));
diff --git a/gcc/testsuite/g++.dg/reflect/is_user_provided2.C b/gcc/testsuite/g++.dg/reflect/is_user_provided2.C
new file mode 100644 (file)
index 0000000..03a3e6e
--- /dev/null
@@ -0,0 +1,91 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_deleted.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template<typename F>
+consteval info
+select_mem(info clazz, F f)
+{
+  for (info x : members_of(clazz, access_context::unchecked()))
+    if (f(x))
+      return x;
+}
+
+struct ExplicitDef
+{
+  ExplicitDef() = default;
+  ExplicitDef(const ExplicitDef&) = default;
+  ExplicitDef(ExplicitDef&&) = default;
+
+  ExplicitDef& operator=(const ExplicitDef&) = default;
+  ExplicitDef& operator=(ExplicitDef&&) = default;
+  
+  ~ExplicitDef() = default;
+};
+
+static_assert (!is_user_provided (select_mem (^^ExplicitDef, is_default_constructor)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDef, is_copy_constructor)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDef, is_move_constructor)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDef, is_copy_assignment)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDef, is_move_assignment)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDef, is_destructor)));
+
+struct ExplicitDel
+{
+  ExplicitDel() = default;
+  ExplicitDel(const ExplicitDel&) = default;
+  ExplicitDel(ExplicitDel&&) = default;
+
+  ExplicitDel& operator=(const ExplicitDel&) = default;
+  ExplicitDel& operator=(ExplicitDel&&) = default;
+  
+  ~ExplicitDel() = default;
+};
+
+static_assert (!is_user_provided (select_mem (^^ExplicitDel, is_default_constructor)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDel, is_copy_constructor)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDel, is_move_constructor)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDel, is_copy_assignment)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDel, is_move_assignment)));
+static_assert (!is_user_provided (select_mem (^^ExplicitDel, is_destructor)));
+
+struct ImplicitDef
+{
+};
+
+static_assert (!is_user_provided (select_mem (^^ImplicitDef, is_default_constructor)));
+static_assert (!is_user_provided (select_mem (^^ImplicitDef, is_copy_constructor)));
+static_assert (!is_user_provided (select_mem (^^ImplicitDef, is_move_constructor)));
+static_assert (!is_user_provided (select_mem (^^ImplicitDef, is_copy_assignment)));
+static_assert (!is_user_provided (select_mem (^^ImplicitDef, is_move_assignment)));
+static_assert (!is_user_provided (select_mem (^^ImplicitDef, is_destructor)));
+
+struct ExplicitRelOps
+{
+  bool operator==(const ExplicitRelOps&) const = default;
+  auto operator<=>(const ExplicitRelOps&) const = default;
+};
+static_assert (!is_user_provided (^^ExplicitRelOps::operator==));
+static_assert (!is_user_provided (^^ExplicitRelOps::operator<=>));
+
+struct DelRelOps
+{
+  bool operator==(const DelRelOps&) const = delete;
+  auto operator<=>(const DelRelOps&) const = delete;
+};
+static_assert (!is_user_provided (^^DelRelOps::operator==));
+static_assert (!is_user_provided (^^DelRelOps::operator<=>));
+
+struct ImplicitRelOps
+{
+  // operator== is implicitly declared
+  auto operator<=>(const ImplicitRelOps&) const = default;
+};
+static_assert (!is_user_provided (^^ImplicitRelOps::operator==));
+static_assert (!is_user_provided (^^ImplicitRelOps::operator<=>));
+
diff --git a/gcc/testsuite/g++.dg/reflect/is_variable1.C b/gcc/testsuite/g++.dg/reflect/is_variable1.C
new file mode 100644 (file)
index 0000000..4260a44
--- /dev/null
@@ -0,0 +1,104 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_variable.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_variable (null_reflection));
+static_assert (!is_variable (^^::));
+static_assert (!is_variable (^^ns));
+static_assert (!is_variable (^^ns_alias));
+static_assert (!is_variable (reflect_constant (3)));
+static_assert (!is_variable (^^cls));
+static_assert (!is_variable (^^cls::dm));
+static_assert (!is_variable (^^cls::ref_dm));
+static_assert (is_variable (^^cls::static_dm));
+static_assert (!is_variable (^^cls::mem_fun));
+static_assert (!is_variable (^^cls::static_mem_fun));
+static_assert (!is_variable (^^cls::type));
+static_assert (is_variable (^^cls_var));
+static_assert (!is_variable (^^onion));
+static_assert (!is_variable (^^anon));
+static_assert (!is_variable (^^fun));
+static_assert (!is_variable (^^alias));
+static_assert (is_variable (^^var));
+// ??? EDG says this is _not_ a variable.
+static_assert (is_variable (^^ref));
+static_assert (is_variable (^^rref));
+static_assert (is_variable (^^ptr));
+static_assert (!is_variable (^^cls_tmpl));
+static_assert (!is_variable (^^cls_tmpl<int>));
+static_assert (!is_variable (^^incomplete_cls<int>));
+static_assert (!is_variable (^^fun_tmpl));
+static_assert (!is_variable (^^fun_tmpl<int>));
+static_assert (!is_variable (^^conc));
+static_assert (!is_variable (substitute (^^conc, { ^^int })));
+static_assert (!is_variable (^^var_tmpl));
+static_assert (is_variable (^^var_tmpl<int>));
+static_assert (!is_variable (^^cls_tmpl_alias));
+static_assert (!is_variable (^^cls_tmpl_alias<int>));
+static_assert (!is_variable (^^Enum));
+static_assert (!is_variable (^^Enum::A));
+static_assert (!is_variable (^^Enum_class));
+static_assert (!is_variable (^^Enum_class::A));
+static_assert (!is_variable (^^decomp));
+static_assert (!is_variable (^^decomp_ref));
+static_assert (is_variable (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_variable (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_variable (^^T));
+  static_assert (is_variable (R));
+  static_assert (!is_variable (R2));
+  static_assert (!is_variable (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (is_variable (^^p));
+  static_assert (is_variable (^^c));
+  static_assert (!is_variable (parameters_of (^^g)[0]));
+  static_assert (!is_variable (parameters_of (^^g)[1]));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_variable_template1.C b/gcc/testsuite/g++.dg/reflect/is_variable_template1.C
new file mode 100644 (file)
index 0000000..0fa772b
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_variable_template.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!is_variable_template (null_reflection));
+static_assert (!is_variable_template (^^::));
+static_assert (!is_variable_template (^^ns));
+static_assert (!is_variable_template (^^ns_alias));
+static_assert (!is_variable_template (reflect_constant (3)));
+static_assert (!is_variable_template (^^cls));
+static_assert (!is_variable_template (^^cls::dm));
+static_assert (!is_variable_template (^^cls::ref_dm));
+static_assert (!is_variable_template (^^cls::static_dm));
+static_assert (!is_variable_template (^^cls::mem_fun));
+static_assert (!is_variable_template (^^cls::static_mem_fun));
+static_assert (!is_variable_template (^^cls::type));
+static_assert (!is_variable_template (^^cls_var));
+static_assert (!is_variable_template (^^onion));
+static_assert (!is_variable_template (^^anon));
+static_assert (!is_variable_template (^^fun));
+static_assert (!is_variable_template (^^alias));
+static_assert (!is_variable_template (^^var));
+static_assert (!is_variable_template (^^ref));
+static_assert (!is_variable_template (^^rref));
+static_assert (!is_variable_template (^^ptr));
+static_assert (!is_variable_template (^^cls_tmpl));
+static_assert (!is_variable_template (^^cls_tmpl<int>));
+static_assert (!is_variable_template (^^incomplete_cls<int>));
+static_assert (!is_variable_template (^^fun_tmpl));
+static_assert (!is_variable_template (^^fun_tmpl<int>));
+static_assert (!is_variable_template (^^conc));
+static_assert (!is_variable_template (substitute (^^conc, { ^^int })));
+static_assert (is_variable_template (^^var_tmpl));
+static_assert (!is_variable_template (^^var_tmpl<int>));
+static_assert (!is_variable_template (^^cls_tmpl_alias));
+static_assert (!is_variable_template (^^cls_tmpl_alias<int>));
+static_assert (!is_variable_template (^^Enum));
+static_assert (!is_variable_template (^^Enum::A));
+static_assert (!is_variable_template (^^Enum_class));
+static_assert (!is_variable_template (^^Enum_class::A));
+static_assert (!is_variable_template (^^decomp));
+static_assert (!is_variable_template (^^decomp_ref));
+static_assert (!is_variable_template (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_variable_template (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_variable_template (bases_of (^^Derived, access_context::unchecked ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_variable_template (^^T));
+  static_assert (!is_variable_template (R));
+  static_assert (!is_variable_template (R2));
+  static_assert (is_variable_template (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^var_tmpl>();
+  static_assert (!is_variable_template (^^p));
+  static_assert (!is_variable_template (^^c));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/is_virtual1.C b/gcc/testsuite/g++.dg/reflect/is_virtual1.C
new file mode 100644 (file)
index 0000000..bf12250
--- /dev/null
@@ -0,0 +1,60 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_virtual.
+
+#include <meta>
+
+using namespace std::meta;
+
+void func () {}
+
+struct B {
+  void nonvirt ();
+  virtual void virt_no_override ();
+  virtual void virt_implicit_override ();
+  virtual void virt_explicit_override ();
+  virtual void pure_virt () = 0;
+  virtual ~B ();
+};
+
+struct D : B {
+  void nonvirt ();
+  void virt_implicit_override ();
+  void virt_explicit_override () override;
+  void pure_virt ();
+  ~D ();
+};
+
+static_assert (!is_virtual (^^func));
+static_assert (!is_virtual (^^B::nonvirt));
+static_assert (is_virtual (^^B::virt_no_override));
+static_assert (is_virtual (^^B::virt_implicit_override));
+static_assert (is_virtual (^^B::virt_explicit_override));
+static_assert (is_virtual (^^B::pure_virt));
+static_assert (is_virtual (^^B::~B));
+
+static_assert (!is_virtual (^^D::nonvirt));
+static_assert (is_virtual (^^D::virt_no_override));
+static_assert (is_virtual (^^D::virt_implicit_override));
+static_assert (is_virtual (^^D::virt_explicit_override));
+static_assert (is_virtual (^^D::pure_virt));
+static_assert (is_virtual (^^D::~D));
+
+struct E {
+  ~E () = delete;
+};
+
+struct F {
+  virtual ~F () = delete;
+};
+
+static_assert (!is_virtual (^^E::~E));
+static_assert (is_virtual (^^F::~F));
+
+struct B1 {};
+struct B2 {};
+struct D2 : B1, virtual B2 { };
+constexpr auto ctx = access_context::unchecked ();
+
+static_assert (!is_virtual (bases_of (^^D2, ctx)[0]));
+static_assert (is_virtual (bases_of (^^D2, ctx)[1]));
diff --git a/gcc/testsuite/g++.dg/reflect/is_volatile1.C b/gcc/testsuite/g++.dg/reflect/is_volatile1.C
new file mode 100644 (file)
index 0000000..fec3461
--- /dev/null
@@ -0,0 +1,116 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_volatile.
+
+#include <meta>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+static_assert (!is_volatile (std::meta::reflect_constant (42)));
+static_assert (!is_volatile (std::meta::reflect_object (arr[1])));
+static_assert (!is_volatile (^^arr));
+static_assert (!is_volatile (^^a3));
+static_assert (!is_volatile (^^fn));
+static_assert (!is_volatile (^^fn2));
+static_assert (!is_volatile (^^Enum::A));
+static_assert (!is_volatile (^^Alias));
+static_assert (!is_volatile (^^S));
+static_assert (!is_volatile (^^S::mem));
+static_assert (!is_volatile (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!is_volatile (^^TCls));
+static_assert (!is_volatile (^^TFn));
+static_assert (!is_volatile (^^TVar));
+static_assert (!is_volatile (^^Concept));
+static_assert (!is_volatile (^^NSAlias));
+static_assert (!is_volatile (^^NS));
+static_assert (!is_volatile (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (!is_volatile (std::meta::data_member_spec (^^int, { .name = "member" })));
+
+int
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (!is_volatile (^^a));
+  static_assert (!is_volatile (^^b));
+  static_assert (!is_volatile (^^c));
+  static_assert (!is_volatile (^^d));
+  static_assert (!is_volatile (^^e));
+  static_assert (!is_const (parameters_of (^^foo)[0]));
+  static_assert (!is_const (parameters_of (^^foo)[1]));
+  static_assert (!is_const (parameters_of (^^foo)[2]));
+  static_assert (!is_const (parameters_of (^^foo)[3]));
+  static_assert (!is_const (parameters_of (^^foo)[4]));
+  return 0;
+}
+
+static_assert (!is_volatile (std::meta::reflect_constant (42)));
+static_assert (!is_volatile (std::meta::reflect_constant (42.0)));
+static_assert (!is_volatile (std::meta::reflect_constant (U { 42 })));
+static_assert (!is_volatile (std::meta::reflect_object (arr[1])));
+static_assert (!is_volatile (^^arr));
+static_assert (!is_volatile (^^fn));
+static_assert (!is_volatile (^^Enum::A));
+static_assert (!is_volatile (^^A));
+static_assert (!is_volatile (^^S::mem));
+
+volatile int vi = 42;
+static_assert (is_volatile (^^vi));
+using uvi = volatile int;
+static_assert (is_volatile (^^uvi));
+const volatile long vl = 42L;
+static_assert (is_volatile (^^vl));
+extern const volatile short cv = 2;
+static_assert (is_volatile (^^cv));
+struct V { volatile int a; static volatile int b; };
+static_assert (is_volatile (^^V::a));
+static_assert (is_volatile (^^V::b));
+
+volatile int arr2[] = {3, 4, 5};
+volatile int arr3[2][2][2] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};
+struct W {
+  void foo () volatile {}
+  void bar () const {}
+};
+static_assert (is_volatile (^^arr2));
+static_assert (is_volatile (^^arr3));
+static_assert (is_volatile (^^W::foo));
+static_assert (!is_volatile (^^W::bar));
+static_assert (!is_volatile (^^int));
+static_assert (!is_volatile (^^const int));
+static_assert (is_volatile (^^volatile int));
+static_assert (is_volatile (^^const volatile int));
+static_assert (!is_volatile (^^int [2]));
+static_assert (!is_volatile (^^const int [2]));
+static_assert (is_volatile (^^volatile int [2]));
+static_assert (is_volatile (^^const volatile int [2]));
+static_assert (!is_volatile (^^int (int)));
+static_assert (!is_volatile (^^int (int) const));
+static_assert (is_volatile (^^int (int) volatile));
+static_assert (is_volatile (^^int (int) const volatile));
diff --git a/gcc/testsuite/g++.dg/reflect/lex1.C b/gcc/testsuite/g++.dg/reflect/lex1.C
new file mode 100644 (file)
index 0000000..ec01d7a
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test lexical aspects of reflection.
+
+constexpr int sz = 2;
+
+void
+g ()
+{
+  int arr[10];
+  arr[::sz] = 42;
+  int arr2[:> = { 1, 2 };
+}
diff --git a/gcc/testsuite/g++.dg/reflect/lex2.C b/gcc/testsuite/g++.dg/reflect/lex2.C
new file mode 100644 (file)
index 0000000..8431c04
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+namespace colon_parsing {
+constexpr int x = 4;
+constexpr auto rx = ^^x;
+static_assert([:rx:] == 4);
+
+constexpr unsigned Idx = 1;
+constexpr int arr[] = {1, 2, 3};
+static_assert(arr[::colon_parsing::Idx] == 2);
+
+constexpr info rIdx = ^^Idx;
+static_assert([:::colon_parsing::rIdx:] == 1);
+
+struct WithIndexOperator {
+  bool operator[:>(int);  // Test interaction with ':>'-digraph (i.e., ']').
+};
+}
diff --git a/gcc/testsuite/g++.dg/reflect/mangle1.C b/gcc/testsuite/g++.dg/reflect/mangle1.C
new file mode 100644 (file)
index 0000000..49947b8
--- /dev/null
@@ -0,0 +1,253 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -O0" }
+
+#include <meta>
+#include <ranges>
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+[[=1]] void fn (int n);
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+  static int var;
+};
+template <auto> struct TCls {};
+template <auto> void TFn ();
+template <auto> int TVar;
+template <auto N> using TAlias = TCls <N>;
+template <auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+namespace NS2 {
+  int arr[] = {1, 2, 3};
+  auto [a1, a2, a3] = arr;
+  [[=1]] void fn (int n, long m);
+  enum Enum { A };
+  using Alias = decltype (^^int);
+  struct B {};
+  struct S : B {
+    int mem;
+    int : 0;
+    int : 3;
+    int : 5;
+    static int var;
+    template <typename T> static T TVar;
+  };
+  template <auto> struct TCls {};
+  template <auto> void TFn ();
+  template <auto> int TVar;
+  template <auto N> using TAlias = TCls <N>;
+  template <auto> concept Concept = requires { true; };
+  struct V { int a, b, c; };
+  S s;
+  namespace NS3 {
+    auto [a1, a2, a3] = arr;
+  }
+  namespace NSAlias = NS3;
+  enum { C };
+  template <typename T>
+  struct W : B, ::B {};
+  static union { int au; };
+  struct X {
+    union { int a; };
+    X &operator + (const X &);
+    operator int ();
+  };
+  template <typename T>
+  struct Y {
+    union { T a; };
+  };
+  struct Z {
+  };
+}
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+template <int N, typename T>
+void
+foo ()
+{
+}
+
+template <int N, std::meta::info I>
+void
+bar ()
+{
+}
+
+void
+baz (int x)
+{
+  int v = 42;
+  foo <1, std::meta::info> ();
+  foo <2, const std::meta::info> ();
+  bar <110, std::meta::info {}> (); // null reflection
+  bar <120, std::meta::reflect_constant (42)> (); // value
+  bar <121, std::meta::reflect_constant (42.0)> (); // value
+  bar <122, std::meta::reflect_constant (NS2::V { 1, 2, 3 })> (); // value
+  bar <130, std::meta::reflect_object (arr[1])> (); // object
+  bar <131, std::meta::reflect_object (NS2::arr[1])> (); // object
+  bar <132, std::meta::reflect_object (NS2::s.mem)> (); // object
+  bar <140, ^^arr> (); // variable
+  bar <141, ^^NS2::arr> (); // variable
+  bar <142, ^^x> (); // variable
+  bar <143, ^^v> (); // variable
+  bar <144, members_of (^^NS2::NS3, ctx)[0]> (); // variable
+  bar <145, ^^S::var> (); // variable
+  bar <146, ^^NS2::S::var> (); // variable
+  bar <147, ^^TVar <42>> (); // variable
+  bar <148, ^^TVar <42>> (); // variable
+  bar <149, ^^NS2::S::TVar <int>> (); // variable
+  bar <150, ^^a3> (); // structured binding
+  bar <151, ^^NS2::a3> (); // structured binding
+  bar <160, ^^fn> (); // function
+  bar <161, ^^NS2::fn> (); // function
+  bar <162, ^^TFn <42>> (); // function
+  bar <163, ^^NS2::TFn <0U>> (); // function
+  bar <164, ^^NS2::TFn <^^int>> (); // function
+  bar <165, ^^NS2::X::operator+> (); // function
+  bar <166, (members_of (^^NS2::Z, ctx) | std::views::filter (std::meta::is_default_constructor) | std::ranges::to <std::vector> ())[0]> (); // function
+  bar <167, (members_of (^^NS2::Z, ctx) | std::views::filter (std::meta::is_copy_constructor) | std::ranges::to <std::vector> ())[0]> (); // function
+  bar <168, (members_of (^^NS2::Z, ctx) | std::views::filter (std::meta::is_copy_assignment) | std::ranges::to <std::vector> ())[0]> (); // function
+  bar <169, (members_of (^^NS2::Z, ctx) | std::views::filter (std::meta::is_destructor) | std::ranges::to <std::vector> ())[0]> (); // function
+  bar <170, parameters_of (^^fn)[0]> (); // function parameter
+  bar <171, parameters_of (^^NS2::fn)[0]> (); // function parameter
+  bar <172, parameters_of (^^NS2::fn)[1]> (); // function parameter
+  bar <180, ^^Enum::A> (); // enumerator
+  bar <181, ^^NS2::Enum::A> (); // enumerator
+  bar <182, ^^NS2::C> (); // enumerator
+  bar <190, annotations_of (^^fn)[0]> (); // annotation
+  bar <200, ^^Alias> (); // type alias
+  bar <201, ^^NS2::Alias> (); // type alias
+  bar <202, ^^TAlias <42>> (); // type alias
+  bar <203, ^^NS2::TAlias <0U>> (); // type alias
+  bar <210, ^^S> (); // type
+  bar <211, ^^NS2::S> (); // type
+  bar <212, ^^const int> (); // type
+  bar <213, ^^decltype (nullptr)> (); // type
+  bar <214, ^^decltype (^^::)> (); // type
+  bar <215, ^^TCls <42>> (); // type
+  bar <216, ^^NS2::TCls <42>> (); // type
+  bar <220, ^^S::mem> (); // non-static data member
+  bar <221, ^^NS2::S::mem> (); // non-static data member
+  bar <222, ^^NS2::au> (); // non-static data member
+  bar <223, ^^NS2::X::a> (); // non-static data member
+  bar <224, ^^NS2::Y <int>::a> (); // non-static data member
+  bar <230, members_of (^^S, ctx)[1]> (); // unnamed bit-field
+  bar <231, members_of (^^NS2::S, ctx)[1]> (); // unnamed bit-field
+  bar <232, members_of (^^NS2::S, ctx)[2]> (); // unnamed bit-field
+  bar <233, members_of (^^NS2::S, ctx)[3]> (); // unnamed bit-field
+  bar <240, ^^TCls> (); // class template
+  bar <241, ^^NS2::TCls> (); // class template
+  bar <250, ^^TFn> (); // function template
+  bar <251, ^^NS2::TFn> (); // function template
+  bar <260, ^^TVar> (); // variable template
+  bar <261, ^^NS2::TVar> (); // variable template
+  bar <270, ^^TAlias> (); // alias template
+  bar <271, ^^NS2::TAlias> (); // alias template
+  bar <280, ^^Concept> (); // concept
+  bar <281, ^^NS2::Concept> (); // concept
+  bar <290, ^^NSAlias> (); // namespace alias
+  bar <291, ^^NS2::NSAlias> (); // namespace alias
+  bar <300, ^^NS> (); // namespace
+  bar <301, ^^NS2::NS3> (); // namespace
+  bar <310, ^^::> (); // global namespace
+  bar <320, bases_of (^^S, ctx)[0]> (); // direct base class relationship
+  bar <321, bases_of (^^NS2::S, ctx)[0]> (); // direct base class relationship
+  bar <322, bases_of (^^NS2::W <int>, ctx)[0]> (); // direct base class relationship
+  bar <323, bases_of (^^NS2::W <float>, ctx)[1]> (); // direct base class relationship
+  bar <330, data_member_spec (^^S, { .name = "member" })> (); // data member description
+  bar <331, data_member_spec (^^NS2::S, { .name = "m", .alignment = 16, .no_unique_address = true })> (); // data member description
+  bar <332, data_member_spec (^^unsigned short, { .name = "b", .bit_width = 5 })> (); // data member description
+  bar <333, data_member_spec (^^long, { .bit_width = 3 })> (); // data member description
+  bar <334, data_member_spec (^^int, { .bit_width = 0 })> (); // data member description
+  bar <340, ^^NS2::X::~X> (); // function
+}
+
+// { dg-final { scan-assembler "_Z3fooILi1EDmEvv" } }
+// { dg-final { scan-assembler "_Z3fooILi2EKDmEvv" } }
+// { dg-final { scan-assembler "_Z3barILi110ELDmnuEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi120ELDmvlLi42EEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi121ELDmvlLd4045000000000000EEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi122ELDmobL_Z29_ZTAXtlN3NS21VELi1ELi2ELi3EEEEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi130ELDmobixL_Z3arrEL\[ilx]1EEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi131ELDmobixL_ZN3NS23arrEEL\[ilx]1EEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi132ELDmobdtL_ZN3NS21sEE3memEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi140ELDmvr3arrEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi141ELDmvrN3NS23arrEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi142ELDmvrZ3baziE1xEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi143ELDmvrZ3baziE1vEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi144ELDmvrN3NS23NS324_ZN3NS23NS3DC2a12a22a3EEEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi145ELDmvrN1S3varEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi146ELDmvrN3NS21S3varEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi147ELDmvr4TVarILi42EEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi148ELDmvr4TVarILi42EEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi149ELDmvrN3NS21S4TVarIiEEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi150ELDmsb2a3EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi151ELDmsbN3NS22a3EEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi160ELDmfn2fniEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi161ELDmfnN3NS22fnEilEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi162ELDmfn3TFnITnDaLi42EEvvEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi163ELDmfnN3NS23TFnILj0EEEvvEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi164ELDmfnN3NS23TFnILDmtyiEEEvvEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi165ELDmfnN3NS21XplERKS1_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi166ELDmfnN3NS21ZC4EvEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi167ELDmfnN3NS21ZC4ERKS1_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi168ELDmfnN3NS21ZaSERKS1_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi169ELDmfnN3NS21ZD4EvEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi170ELDmpa_2fniEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi171ELDmpa_N3NS22fnEilEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi172ELDmpa0_N3NS22fnEilEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi180ELDmen4Enum1AEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi181ELDmen3NS24Enum1AEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi182ELDmen3NS2Uej1C1CEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi190ELDman_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi200ELDmta5AliasEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi201ELDmta3NS25AliasEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi202ELDmta6TAliasILi42EEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi203ELDmta3NS26TAliasILj0EEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi210ELDmty1SEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi211ELDmtyN3NS21SEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi212ELDmtyKiEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi213ELDmtyDnEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi214ELDmtyDmEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi215ELDmty4TClsILi42EEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi216ELDmtyN3NS24TClsILi42EEEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi220ELDmdm1S3memEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi221ELDmdm3NS21S3memEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi222ELDmdm3NS22auEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi223ELDmdm3NS21X1aEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi224ELDmdm3NS21YIiE1aEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi230ELDmun1S_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi231ELDmun3NS21S_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi232ELDmun3NS21S0_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi233ELDmun3NS21S1_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi240ELDmct4TClsEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi241ELDmct3NS24TClsEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi250ELDmft3TFnEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi251ELDmft3NS23TFnEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi260ELDmvt4TVarEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi261ELDmvt3NS24TVarEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi270ELDmat6TAliasEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi271ELDmat3NS26TAliasEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi280ELDmco7ConceptEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi281ELDmco3NS27ConceptEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi290ELDmna7NSAliasEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi291ELDmna3NS27NSAliasEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi300ELDmns2NSEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi301ELDmns3NS23NS3EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi310ELDmngEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi320ELDmba_1SEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi321ELDmba_N3NS21SEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi322ELDmba_N3NS21WIiEEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi323ELDmba0_N3NS21WIfEEEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi330ELDmds1S_6member___EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi331ELDmdsN3NS21SE_1m_16__nEEvv" } }
+// { dg-final { scan-assembler "_Z3barILi332ELDmdst_1b__5_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi333ELDmdsl___3_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi334ELDmdsi___0_EEvv" } }
+// { dg-final { scan-assembler "_Z3barILi340ELDmfnN3NS21XD4EvEEvv" } }
diff --git a/gcc/testsuite/g++.dg/reflect/member-visibility1.C b/gcc/testsuite/g++.dg/reflect/member-visibility1.C
new file mode 100644 (file)
index 0000000..ff10c51
--- /dev/null
@@ -0,0 +1,412 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Tests std::meta::is_public, std::meta::is_private, std::meta::is_protected
+#include <meta>
+
+class PublicBase {  };
+class ProtectedBase {  };
+class PrivateBase {  };
+class VirtualBase {  };
+class VirtualProtectedBase {  };
+
+class A : public PublicBase, protected ProtectedBase, private PrivateBase, 
+         virtual VirtualBase, protected virtual VirtualProtectedBase
+{
+  void test_bases_visibility()
+  {
+    constexpr auto ctx = std::meta::access_context::unchecked();
+    static_assert (std::meta::bases_of (^^A, ctx).size() == 5);
+
+    static_assert (std::meta::is_public (std::meta::bases_of (^^A, ctx)[0]));
+    static_assert (std::meta::is_protected (std::meta::bases_of (^^A, ctx)[1]));
+    static_assert (std::meta::is_private (std::meta::bases_of (^^A, ctx)[2]));
+    static_assert (std::meta::is_private (std::meta::bases_of (^^A, ctx)[3]));
+    static_assert (std::meta::is_protected (std::meta::bases_of (^^A, ctx)[4]));
+  }
+
+// private:
+  A(int)
+  {
+    int a;
+    static_assert (!std::meta::is_public (std::meta::parent_of (^^a)));
+    static_assert (!std::meta::is_protected (std::meta::parent_of (^^a)));
+    static_assert (std::meta::is_private (std::meta::parent_of (^^a)));
+  }
+
+protected:
+  A(bool)
+  {
+    int a;
+    static_assert (!std::meta::is_public (std::meta::parent_of (^^a)));
+    static_assert (std::meta::is_protected (std::meta::parent_of (^^a)));
+    static_assert (!std::meta::is_private (std::meta::parent_of (^^a)));
+  }
+
+  ~A() = default;
+
+public:
+  A()
+  {
+    int a;
+    static_assert (std::meta::is_public (std::meta::parent_of (^^a)));
+    static_assert (!std::meta::is_protected (std::meta::parent_of (^^a)));
+    static_assert (!std::meta::is_private (std::meta::parent_of (^^a)));
+  }
+
+  int public_field;
+  static int public_static_field;
+
+  int public_function();
+  static int public_static_function();
+  virtual void public_virtual_function() = 0;
+
+  template <typename T> 
+  void public_template_function();
+  template <typename T> 
+  static void public_static_template_function();
+
+  using public_type_alias = int;
+
+  struct PublicCls {};
+
+  enum PublicEnum {
+    B, C, D
+  };
+
+  enum class PublicEnumClass {
+    E, F
+  };
+
+  union PublicUnion {};
+
+protected:
+
+  int protected_field;
+  static int protected_static_field;
+
+  int protected_function();
+  static int protected_static_function();
+  virtual void protected_virtual_function() = 0;
+
+  template <typename T> 
+  void protected_template_function();
+  template <typename T> 
+  static void protected_static_template_function();
+
+  using protected_type_alias = int;
+
+  struct ProtectedCls {};
+
+  enum ProtectedEnum {
+    G, H
+  };
+
+  enum class ProtectedEnumClass {
+    I, J
+  };
+
+  union ProtectedUnion {};
+
+private:
+
+  int private_field;
+  static int private_static_field;
+
+  int private_function();
+  static int private_static_function();
+  virtual void private_virtual_function() = 0;
+
+  template <typename T> 
+  void private_template_function();
+  template <typename T> 
+  static void private_static_template_function();
+
+  using private_type_alias = int;
+
+  struct PrivateCls {};
+
+  enum PrivateEnum {
+    K, L
+  };
+
+  enum class PrivateEnumClass {
+    M, N
+  };
+
+  union PrivateUnion {};
+
+
+  void test_is_public()
+  {
+    // positive cases for public class members
+    static_assert (std::meta::is_public (^^public_field));
+    static_assert (std::meta::is_public (^^public_static_field));
+
+    static_assert (std::meta::is_public(^^public_function));
+    static_assert (std::meta::is_public (^^public_static_function));
+    static_assert (std::meta::is_public (^^public_virtual_function));
+
+    static_assert (std::meta::is_public (^^public_template_function));
+    static_assert (std::meta::is_public (^^public_template_function<int>));
+
+    static_assert (std::meta::is_public (^^public_static_template_function));
+    static_assert (std::meta::is_public (^^public_static_template_function<int>));
+
+    static_assert (std::meta::is_public (^^public_type_alias));
+    static_assert (std::meta::is_public (^^PublicCls));
+    static_assert (std::meta::is_public (^^PublicUnion));
+
+    static_assert (std::meta::is_public (^^PublicEnum));
+    static_assert (std::meta::is_public (^^PublicEnumClass)); 
+
+    static_assert (std::meta::is_public (^^B));
+    static_assert (std::meta::is_public (^^C));
+    static_assert (std::meta::is_public (^^D));
+
+    // negative test cases
+    static_assert (!std::meta::is_public (^^A));
+
+    // scoped enum values are not class members
+    static_assert (!std::meta::is_public (^^PublicEnumClass::E));
+    static_assert (!std::meta::is_public (^^PublicEnumClass::F));
+
+    static_assert (!std::meta::is_public (^^ProtectedEnumClass::I));
+    static_assert (!std::meta::is_public (^^ProtectedEnumClass::J));
+
+    static_assert (!std::meta::is_public (^^PrivateEnumClass::M));
+    static_assert (!std::meta::is_public (^^PrivateEnumClass::N));
+
+    // protected class members
+    static_assert (!std::meta::is_public (^^~A));
+
+    static_assert (!std::meta::is_public (^^protected_field));
+    static_assert (!std::meta::is_public (^^protected_static_field));
+
+    static_assert (!std::meta::is_public (^^protected_function));
+    static_assert (!std::meta::is_public (^^protected_static_function));
+    static_assert (!std::meta::is_public (^^protected_virtual_function));
+
+    static_assert (!std::meta::is_public (^^protected_template_function));
+    static_assert (!std::meta::is_public (^^protected_template_function<int>));
+
+    static_assert (!std::meta::is_public (^^protected_static_template_function));
+    static_assert (!std::meta::is_public (^^protected_static_template_function<int>));
+
+    static_assert (!std::meta::is_public (^^protected_type_alias)); 
+    static_assert (!std::meta::is_public (^^ProtectedCls));  
+    static_assert (!std::meta::is_public (^^ProtectedUnion));
+
+    static_assert (!std::meta::is_public (^^ProtectedEnum));
+    static_assert (!std::meta::is_public (^^ProtectedEnumClass)); 
+
+    static_assert (!std::meta::is_public (^^G));
+    static_assert (!std::meta::is_public (^^H));
+
+    // private class members
+    static_assert (!std::meta::is_public (^^private_field));
+    static_assert (!std::meta::is_public (^^private_static_field));
+
+    static_assert (!std::meta::is_public (^^private_function));
+    static_assert (!std::meta::is_public (^^private_static_function));
+    static_assert (!std::meta::is_public (^^private_virtual_function));
+
+    static_assert (!std::meta::is_public (^^private_template_function));
+    static_assert (!std::meta::is_public (^^private_template_function<int>));
+
+    static_assert (!std::meta::is_public (^^private_static_template_function));
+    static_assert (!std::meta::is_public (^^private_static_template_function<int>));
+
+    static_assert (!std::meta::is_public (^^private_type_alias)); 
+    static_assert (!std::meta::is_public (^^PrivateCls));  
+    static_assert (!std::meta::is_public (^^PrivateUnion));
+
+    static_assert (!std::meta::is_public (^^PrivateEnum));
+    static_assert (!std::meta::is_public (^^PrivateEnumClass)); 
+
+    static_assert (!std::meta::is_public (^^K));
+    static_assert (!std::meta::is_public (^^L));
+  }
+
+  void test_is_protected()
+  {
+    // positive cases for protected class members
+    static_assert (std::meta::is_protected (^^~A));
+
+    static_assert (std::meta::is_protected (^^protected_field));
+    static_assert (std::meta::is_protected (^^protected_static_field));
+
+    static_assert (std::meta::is_protected (^^protected_function));
+    static_assert (std::meta::is_protected (^^protected_static_function));
+    static_assert (std::meta::is_protected (^^protected_virtual_function));
+
+    static_assert (std::meta::is_protected (^^protected_template_function));
+    static_assert (std::meta::is_protected (^^protected_template_function<int>));
+
+    static_assert (std::meta::is_protected (^^protected_static_template_function));
+    static_assert (std::meta::is_protected (^^protected_static_template_function<int>));
+
+    static_assert (std::meta::is_protected (^^protected_type_alias)); 
+    static_assert (std::meta::is_protected (^^ProtectedCls));  
+    static_assert (std::meta::is_protected (^^ProtectedUnion));
+
+    static_assert (std::meta::is_protected (^^ProtectedEnum));
+    static_assert (std::meta::is_protected (^^ProtectedEnumClass)); 
+
+    static_assert (std::meta::is_protected (^^G));
+    static_assert (std::meta::is_protected (^^H));
+
+    // negative cases:
+    static_assert (!std::meta::is_protected (^^A));
+    // scoped enum values are not class members
+    static_assert (!std::meta::is_protected (^^PublicEnumClass::E));
+    static_assert (!std::meta::is_protected (^^PublicEnumClass::F));
+
+    static_assert (!std::meta::is_protected (^^ProtectedEnumClass::I));
+    static_assert (!std::meta::is_protected (^^ProtectedEnumClass::J));
+
+    static_assert (!std::meta::is_protected (^^PrivateEnumClass::M));
+    static_assert (!std::meta::is_protected (^^PrivateEnumClass::N));
+
+    // public class members
+    static_assert (!std::meta::is_protected (^^public_field));
+    static_assert (!std::meta::is_protected (^^public_static_field));
+
+    static_assert (!std::meta::is_protected (^^public_function));
+    static_assert (!std::meta::is_protected (^^public_static_function));
+    static_assert (!std::meta::is_protected (^^public_virtual_function));
+
+    static_assert (!std::meta::is_protected (^^public_template_function));
+    static_assert (!std::meta::is_protected (^^public_template_function<int>));
+
+    static_assert (!std::meta::is_protected (^^public_static_template_function));
+    static_assert (!std::meta::is_protected (^^public_static_template_function<int>));
+
+    static_assert (!std::meta::is_protected (^^public_type_alias)); 
+    static_assert (!std::meta::is_protected (^^PublicCls));  
+    static_assert (!std::meta::is_protected (^^PublicUnion));
+
+    static_assert (!std::meta::is_protected (^^PublicEnum));
+    static_assert (!std::meta::is_protected (^^PublicEnumClass)); 
+
+    static_assert (!std::meta::is_protected (^^B));
+    static_assert (!std::meta::is_protected (^^C));
+    static_assert (!std::meta::is_protected (^^D));
+
+
+    // private class members
+    static_assert (!std::meta::is_protected (^^private_field));
+    static_assert (!std::meta::is_protected (^^private_static_field));
+
+    static_assert (!std::meta::is_protected (^^private_function));
+    static_assert (!std::meta::is_protected (^^private_static_function));
+    static_assert (!std::meta::is_protected (^^private_virtual_function));
+
+    static_assert (!std::meta::is_protected (^^private_template_function));
+    static_assert (!std::meta::is_protected (^^private_template_function<int>));
+
+    static_assert (!std::meta::is_protected (^^private_static_template_function));
+    static_assert (!std::meta::is_protected (^^private_static_template_function<int>));
+
+    static_assert (!std::meta::is_protected (^^private_type_alias)); 
+    static_assert (!std::meta::is_protected (^^PrivateCls));  
+    static_assert (!std::meta::is_protected (^^PrivateUnion));
+
+    static_assert (!std::meta::is_protected (^^PrivateEnum));
+    static_assert (!std::meta::is_protected (^^PrivateEnumClass)); 
+
+    static_assert (!std::meta::is_protected (^^K));
+    static_assert (!std::meta::is_protected (^^L));
+  }
+
+  void test_is_private()
+  {
+    // positive test cases: private class members
+    static_assert (std::meta::is_private (^^private_field));
+    static_assert (std::meta::is_private (^^private_static_field));
+
+    static_assert (std::meta::is_private (^^private_function));
+    static_assert (std::meta::is_private (^^private_static_function));
+    static_assert (std::meta::is_private (^^private_virtual_function));
+
+    static_assert (std::meta::is_private (^^private_template_function));
+    static_assert (std::meta::is_private (^^private_template_function<int>));
+
+    static_assert (std::meta::is_private (^^private_static_template_function));
+    static_assert (std::meta::is_private (^^private_static_template_function<int>));
+
+    static_assert (std::meta::is_private (^^private_type_alias)); 
+    static_assert (std::meta::is_private (^^PrivateCls));  
+    static_assert (std::meta::is_private (^^PrivateUnion));
+
+    static_assert (std::meta::is_private (^^PrivateEnum));
+    static_assert (std::meta::is_private (^^PrivateEnumClass)); 
+
+    static_assert (std::meta::is_private (^^K));
+    static_assert (std::meta::is_private (^^L));
+
+    // negative cases:
+    static_assert (!std::meta::is_private (^^A));
+
+    // scoped enum values are not class members
+    static_assert (!std::meta::is_private (^^PublicEnumClass::E));
+    static_assert (!std::meta::is_private (^^PublicEnumClass::F));
+
+    static_assert (!std::meta::is_private (^^ProtectedEnumClass::I));
+    static_assert (!std::meta::is_private (^^ProtectedEnumClass::J));
+
+    static_assert (!std::meta::is_private (^^PrivateEnumClass::M));
+    static_assert (!std::meta::is_private (^^PrivateEnumClass::N));
+
+    // public class members
+    static_assert (!std::meta::is_private (^^public_field));
+    static_assert (!std::meta::is_private (^^public_static_field));
+
+    static_assert (!std::meta::is_private (^^public_function));
+    static_assert (!std::meta::is_private (^^public_static_function));
+    static_assert (!std::meta::is_private (^^public_virtual_function));
+
+    static_assert (!std::meta::is_private (^^public_template_function));
+    static_assert (!std::meta::is_private (^^public_template_function<int>));
+
+    static_assert (!std::meta::is_private (^^public_static_template_function));
+    static_assert (!std::meta::is_private (^^public_static_template_function<int>));
+
+    static_assert (!std::meta::is_private (^^public_type_alias)); 
+    static_assert (!std::meta::is_private (^^PublicCls));  
+    static_assert (!std::meta::is_private (^^PublicUnion));
+
+    static_assert (!std::meta::is_private (^^PublicEnum));
+    static_assert (!std::meta::is_private (^^PublicEnumClass)); 
+
+    static_assert (!std::meta::is_private (^^B));
+    static_assert (!std::meta::is_private (^^C));
+    static_assert (!std::meta::is_private (^^D));
+
+    // protected class members
+    static_assert (!std::meta::is_private (^^~A));
+
+    static_assert (!std::meta::is_private (^^protected_field));
+    static_assert (!std::meta::is_private (^^protected_static_field));
+
+    static_assert (!std::meta::is_private (^^protected_function));
+    static_assert (!std::meta::is_private (^^protected_static_function));
+    static_assert (!std::meta::is_private (^^protected_virtual_function));
+
+    static_assert (!std::meta::is_private (^^protected_template_function));
+    static_assert (!std::meta::is_private (^^protected_template_function<int>));
+
+    static_assert (!std::meta::is_private (^^protected_static_template_function));
+    static_assert (!std::meta::is_private (^^protected_static_template_function<int>));
+
+    static_assert (!std::meta::is_private (^^protected_type_alias)); 
+    static_assert (!std::meta::is_private (^^ProtectedCls));  
+    static_assert (!std::meta::is_private (^^ProtectedUnion));
+
+    static_assert (!std::meta::is_private (^^ProtectedEnum));
+    static_assert (!std::meta::is_private (^^ProtectedEnumClass)); 
+
+    static_assert (!std::meta::is_private (^^G));
+    static_assert (!std::meta::is_private (^^H));
+  }
+};
+
diff --git a/gcc/testsuite/g++.dg/reflect/member-visibility2.C b/gcc/testsuite/g++.dg/reflect/member-visibility2.C
new file mode 100644 (file)
index 0000000..66dc466
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Tests std::meta::is_public, std::meta::is_private, std::meta::is_protected
+#include <meta>
+
+// Test bit-fields
+struct S {
+  unsigned char b1 : 3;
+protected:
+  unsigned char    : 2;
+private:
+  unsigned char b2 : 6;
+};
+
+constexpr auto ctx = std::meta::access_context::unchecked();
+static_assert (std::meta::members_of (^^S, ctx).size() > 3);
+
+static_assert (std::meta::is_bit_field (std::meta::members_of (^^S, ctx)[0]));
+static_assert (std::meta::has_identifier (std::meta::members_of (^^S, ctx)[0]));
+static_assert (std::meta::is_public (std::meta::members_of (^^S, ctx)[0]));
+
+static_assert (std::meta::is_bit_field (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!std::meta::has_identifier (std::meta::members_of (^^S, ctx)[1]));
+static_assert (std::meta::is_protected (std::meta::members_of (^^S, ctx)[1]));
+
+static_assert (std::meta::is_bit_field (std::meta::members_of (^^S, ctx)[2]));
+static_assert (std::meta::has_identifier (std::meta::members_of (^^S, ctx)[2]));
+static_assert (std::meta::is_private (std::meta::members_of (^^S, ctx)[2]));
+
+// Test inheritance and change of access modifier
+class A {
+protected:
+  int protected_member;
+
+  void protected_function();
+
+  virtual void protected_virtual_function();
+
+  void test() {
+    static_assert (std::meta::is_protected (^^protected_member));
+    static_assert (std::meta::is_protected (^^protected_function));
+    static_assert (std::meta::is_protected (^^protected_virtual_function));
+  }
+};
+
+
+class B : public A {
+private:
+  void protected_virtual_function() override;
+
+  void test() {
+    static_assert (std::meta::is_protected (^^B::protected_member));
+    static_assert (std::meta::is_protected (^^B::protected_function));
+
+    static_assert (std::meta::is_protected (^^A::protected_virtual_function));
+    static_assert (std::meta::is_private (^^B::protected_virtual_function));
+  }
+};
+
+// TODO: add more tests for inheritance and change of access modification
+// TODO: add more tests for base access during multilevel inheritance
diff --git a/gcc/testsuite/g++.dg/reflect/member1.C b/gcc/testsuite/g++.dg/reflect/member1.C
new file mode 100644 (file)
index 0000000..e9d9a64
--- /dev/null
@@ -0,0 +1,99 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test various forms of member access.
+
+struct A {
+  int val;
+};
+
+struct B {
+  A a;
+};
+
+struct S {
+  int x;
+  static constexpr int sx = 42;
+  void fn (int) { }
+  template<typename T>
+  void tfn (T) { }
+  template<typename>
+  struct N { };
+  template<typename T>
+  static T var;
+  B b;
+};
+
+template<typename T>
+struct C {
+  int x;
+  static constexpr int sx = 42;
+  void fn (int) { }
+  template<typename U>
+  void tfn (U) { }
+  template<typename>
+  struct N { };
+  template<typename U>
+  static U var;
+  B b;
+};
+
+void
+f ()
+{
+  S s;
+  S *sp = &s;
+  C<int> c;
+  C<int> *cp = &c;
+
+  s.[: ^^S::x :] = 1;
+  sp->[: ^^S::x :] = 2;
+  s.[: ^^S::fn :](42);
+  sp->[: ^^S::fn :](42);
+  int a = s.[: ^^S::sx :];
+  a += sp->[: ^^S::sx :];
+  s.template [: ^^S::tfn :](42);
+  sp->template [: ^^S::tfn :](42);
+  s.template [: ^^S::tfn :]<int>(42);
+  sp->template [: ^^S::tfn :]<int>(42);
+  s.[: ^^S::var :]<int> = 1; // { dg-error "reflection .var<int>. not usable in a splice expression with template arguments" }
+  s.template [: ^^S::var :]<int> = 1;
+  sp->[: ^^S::var :]<int> = 1; // { dg-error "reflection .var<int>. not usable in a splice expression with template arguments" }
+  sp->template [: ^^S::var :]<int> = 1;
+  s.[: ^^S::b :].[: ^^B::a :].val;
+  sp->[: ^^S::b :].[: ^^B::a :].val;
+  [: ^^s :].[: ^^S::b :].[: ^^B::a :].val;
+  [: ^^sp :]->[: ^^S::b :].[: ^^B::a :].val;
+
+  c.[: ^^C<int>::x :] = 1;
+  cp->[: ^^C<int>::x :] = 1;
+  c.[: ^^C<int>::fn :](42);
+  cp->[: ^^C<int>::fn :](42);
+  a += c.[: ^^C<int>::sx :];
+  a += cp->[: ^^C<int>::sx :];
+  c.template [: ^^C<int>::tfn :](42);
+  cp->template [: ^^C<int>::tfn :](42);
+  c.template [: ^^C<int>::tfn :]<int>(42);
+  cp->template [: ^^C<int>::tfn :]<int>(42);
+  c.[: ^^C<int>::var :]<int> = 1; // { dg-error "reflection .var<int>. not usable in a splice expression with template arguments" }
+  c.template [: ^^C<int>::var :]<int> = 1;
+  cp->[: ^^C<int>::var :]<int> = 1; // { dg-error "reflection .var<int>. not usable in a splice expression with template arguments" }
+  cp->template [: ^^C<int>::var :]<int> = 1;
+  c.[: ^^C<int>::b :].[: ^^B::a :].val;
+  cp->[: ^^C<int>::b :].[: ^^B::a :].val;
+  [: ^^c :].[: ^^C<int>::b :].[: ^^B::a :].val;
+  [: ^^cp :]->[: ^^C<int>::b :].[: ^^B::a :].val;
+
+  [: ^^S :]::template N<int> n1;
+  [: ^^C<int> :]::template N<int> n2;
+  [: ^^C :]<int>::template N<int> n3;  // { dg-error "missing .template.|expected" }
+  typename [: ^^C :]<int>::template N<int> n4;
+
+  s->[: ^^S::x :] = 2; // { dg-error "non-pointer type" }
+  sp.[: ^^S::x :] = 2; // { dg-error "which is of pointer type" }
+  c.[: ^^C<char>::x :] = 1; // { dg-error "is not a base of" }
+  cp->[: ^^C<char>::x :] = 1; // { dg-error "is not a base of" }
+  s.template [: ^^S::N :].t;  // { dg-error "reflection .S::N. not usable in a template splice" }
+  S::template [: ^^S::N<int> :] e1;  // { dg-error "expected unqualified-id" }
+  C<int>::template [: ^^S::N<int> :] e2;  // { dg-error "expected unqualified-id" }
+  s.template [: ^^S::var<int> :] = 1;  // { dg-error "reflection .S::var<int>. not usable in a template splice" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member10.C b/gcc/testsuite/g++.dg/reflect/member10.C
new file mode 100644 (file)
index 0000000..649bab5
--- /dev/null
@@ -0,0 +1,42 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+/* ??? clang rejects all of these; I'm not entirely sure why.
+   [expr.prim.id.general]/2 says that the implicit transformation
+   whereby an id-expression denoting a NSDM becomes a class member
+   access doesn't apply to a splice-expression.  OK, so we reject
+   [:^^k:], but [:^^S:]::k doesn't seem to be the same case?  */
+
+// Non-dependent case
+struct S {
+  int k;
+
+  void fn2() { }
+
+  void fn() {
+    (void) [:^^k:];  // { dg-error "cannot implicitly reference" }
+    (void) [:^^S:]::k;
+    [:^^fn:]();  // { dg-error "cannot implicitly reference" }
+    [:^^S:]::fn2();
+  }
+};
+
+// Dependent case
+struct D {
+  int k;
+
+  void fn2() { }
+
+  template <typename T>
+  void fn() {
+    (void) [:^^T:]::k;
+    [:^^T:]::fn2();
+  }
+};
+
+void runner() {
+    D f = {4};
+    f.fn<D>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member11.C b/gcc/testsuite/g++.dg/reflect/member11.C
new file mode 100644 (file)
index 0000000..29cfa81
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Cf. <https://github.com/cplusplus/CWG/issues/784>
+
+class Base {
+private:
+  int m;
+public:
+  static constexpr auto rm = ^^m;
+};
+class Derived { static constexpr auto mp = &[:Base::rm:]; };
+
+class Base2 {
+protected:
+  int m;
+public:
+  static constexpr auto rm = ^^m;
+};
+class Derived2 { static constexpr auto mp = &[:Base2::rm:]; };
diff --git a/gcc/testsuite/g++.dg/reflect/member12.C b/gcc/testsuite/g++.dg/reflect/member12.C
new file mode 100644 (file)
index 0000000..bfee8a4
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  int a;
+  static int b;
+  void foo () {}
+  static void bar () {}
+};
+int S::b = 42;
+
+void
+baz ()
+{
+  S s {};
+  s.[:^^S::a:]++;
+  s.[:^^S::b:]++;
+  s.[:^^S::foo:] ();
+  s.[:^^S::bar:] ();
+}
+
+template <typename T>
+void
+qux ()
+{
+  S s {};
+  s.[:(T) ^^S::a:]++;
+  s.[:(T) ^^S::b:]++;
+  s.[:(T) ^^S::foo:] ();
+  s.[:(T) ^^S::bar:] ();
+}
+
+void
+corge ()
+{
+  qux <decltype (^^int)> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member13.C b/gcc/testsuite/g++.dg/reflect/member13.C
new file mode 100644 (file)
index 0000000..5a1a05b
--- /dev/null
@@ -0,0 +1,46 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  int a;
+  static int b;
+  void foo () {}
+  static void bar () {}
+  template <int N>
+  void baz () {}
+  template <int N>
+  static void qux () {}
+};
+int S::b = 42;
+
+struct V {
+  int a;
+  static int b;
+  void foo () {}
+  static void bar () {}
+  template <int N>
+  void baz () {}
+  template <int N>
+  static void qux () {}
+};
+int V::b = 42;
+static constexpr auto va = ^^V::a;
+static constexpr auto vb = ^^V::b;
+static constexpr auto vfoo = ^^V::foo;
+static constexpr auto vbar = ^^V::bar;
+
+void
+corge ()
+{
+  S s {};
+  s.[:^^V::a:]++;                      // { dg-error ".V. is not a base of .S." }
+  s.[:^^V::b:]++;                      // { dg-error ".V. is not a base of .S." }
+  s.[:^^V::foo:] ();                   // { dg-error ".V::foo\\\(\\\). is not a member of .S." }
+  s.[:^^V::bar:] ();                   // { dg-error ".V::bar\\\(\\\). is not a member of .S." }
+  s.[:va:]++;                          // { dg-error ".V. is not a base of .S." }
+  s.[:vb:]++;                          // { dg-error ".V. is not a base of .S." }
+  s.[:vfoo:] ();                       // { dg-error ".V::foo\\\(\\\). is not a member of .S." }
+  s.[:vbar:] ();                       // { dg-error ".V::bar\\\(\\\). is not a member of .S." }
+  s.template [:^^V::baz:] <42> ();     // { dg-error "is not a member of .S." }
+  s.template [:^^V::qux:] <42> ();     // { dg-error "is not a member of .S." }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member14.C b/gcc/testsuite/g++.dg/reflect/member14.C
new file mode 100644 (file)
index 0000000..491cdce
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+class A {
+  int a = 0;
+  consteval int foo () const { return 5; }
+public:
+  int b = 0;
+  consteval A () = default;
+  consteval A (int x, int y) : a (x), b (y) {}
+};
+
+constexpr auto ctx = std::meta::access_context::unchecked ();
+static_assert (identifier_of (members_of (^^A, ctx)[0]) == "a");
+static_assert (identifier_of (members_of (^^A, ctx)[1]) == "foo");
+static_assert (identifier_of (members_of(^^A, ctx)[2]) == "b");
+
+constexpr A c, d = { 42, 6 };
+// TODO, these don't work yet due to access failure.
+static_assert (c.[: members_of (^^A, ctx)[0] :] == 0);
+//static_assert (c.[: members_of (^^A, ctx)[1] :] () == 5);
+static_assert (c.[: members_of (^^A, ctx)[2] :] == 0);
+static_assert (d.[: members_of (^^A, ctx)[0] :] == 42);
+//static_assert (d.[: members_of (^^A, ctx)[1] :] () == 5);
+static_assert (d.[: members_of (^^A, ctx)[2] :] == 6);
diff --git a/gcc/testsuite/g++.dg/reflect/member15.C b/gcc/testsuite/g++.dg/reflect/member15.C
new file mode 100644 (file)
index 0000000..36f12d8
--- /dev/null
@@ -0,0 +1,177 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S { int _; long _; short _; };
+struct T { int _; int _; int _; };
+struct U { enum E { F, G, H, I } j, k; };
+struct V : S, T { int _; int _; };
+
+constexpr access_context uctx = access_context::unchecked ();
+
+void
+foo ()
+{
+  S s = { 1, 2, 3 };
+  s.[:members_of (^^S, uctx)[1]:] += 10;
+  s.[:members_of (^^S, uctx)[0]:] += 20;
+  s.[:members_of (^^S, uctx)[2]:] += 30;
+  auto [ sa, sb, sc ] = s;
+  if (sa != 21 || sb != 12 || sc != 33)
+    __builtin_abort ();
+  T t = { 4, 5, 6 };
+  t.[:members_of (^^T, uctx)[1]:] += 40;
+  t.[:members_of (^^T, uctx)[2]:] += 50;
+  t.[:members_of (^^T, uctx)[0]:] += 60;
+  auto [ ta, tb, tc ] = t;
+  if (ta != 64 || tb != 45 || tc != 56)
+    __builtin_abort ();
+  U u = { U::F, U::I };
+  u.[:nonstatic_data_members_of (^^U, uctx)[0]:] = u.[:^^U::E::G:];
+  u.[:nonstatic_data_members_of (^^U, uctx)[1]:] = u.[:^^U::H:];
+  if (u.j != U::G || u.k != U::E::H)
+    __builtin_abort ();
+  V v = {};
+  v.[:members_of (^^S, uctx)[1]:] = 1;
+  v.[:members_of (^^T, uctx)[2]:] = 2;
+  v.[:members_of (^^V, uctx)[0]:] = 3;
+}
+
+template <int N>
+void
+bar ()
+{
+  S s = { 1, 2, 3 };
+  s.[:members_of (^^S, uctx)[1]:] += 10;
+  s.[:members_of (^^S, uctx)[0]:] += 20;
+  s.[:members_of (^^S, uctx)[2]:] += 30;
+  auto [ sa, sb, sc ] = s;
+  if (sa != 21 || sb != 12 || sc != 33)
+    __builtin_abort ();
+  T t = { 4, 5, 6 };
+  t.[:members_of (^^T, uctx)[1]:] += 40;
+  t.[:members_of (^^T, uctx)[2]:] += 50;
+  t.[:members_of (^^T, uctx)[0]:] += 60;
+  auto [ ta, tb, tc ] = t;
+  if (ta != 64 || tb != 45 || tc != 56)
+    __builtin_abort ();
+  U u = { U::F, U::I };
+  u.[:nonstatic_data_members_of (^^U, uctx)[0]:] = u.[:^^U::E::G:];
+  u.[:nonstatic_data_members_of (^^U, uctx)[1]:] = u.[:^^U::H:];
+  if (u.j != U::G || u.k != U::E::H)
+    __builtin_abort ();
+  V v = {};
+  v.[:members_of (^^S, uctx)[1]:] = 1;
+  v.[:members_of (^^T, uctx)[2]:] = 2;
+  v.[:members_of (^^V, uctx)[0]:] = 3;
+}
+
+template <typename A, typename B, typename C, typename D>
+void
+baz ()
+{
+  A s = { 1, 2, 3 };
+  s.[:members_of (^^S, uctx)[1]:] += 10;
+  s.[:members_of (^^S, uctx)[0]:] += 20;
+  s.[:members_of (^^S, uctx)[2]:] += 30;
+  auto [ sa, sb, sc ] = s;
+  if (sa != 21 || sb != 12 || sc != 33)
+    __builtin_abort ();
+  B t = { 4, 5, 6 };
+  t.[:members_of (^^T, uctx)[1]:] += 40;
+  t.[:members_of (^^T, uctx)[2]:] += 50;
+  t.[:members_of (^^T, uctx)[0]:] += 60;
+  auto [ ta, tb, tc ] = t;
+  if (ta != 64 || tb != 45 || tc != 56)
+    __builtin_abort ();
+  C u = { U::F, U::I };
+  u.[:nonstatic_data_members_of (^^U, uctx)[0]:] = u.[:^^U::E::G:];
+  u.[:nonstatic_data_members_of (^^U, uctx)[1]:] = u.[:^^U::H:];
+  if (u.j != U::G || u.k != U::E::H)
+    __builtin_abort ();
+  D v = {};
+  v.[:members_of (^^S, uctx)[1]:] = 1;
+  v.[:members_of (^^T, uctx)[2]:] = 2;
+  v.[:members_of (^^V, uctx)[0]:] = 3;
+}
+
+template <typename A, typename B, typename C, typename D>
+void
+qux ()
+{
+  S s = { 1, 2, 3 };
+  s.[:members_of (^^A, uctx)[1]:] += 10;
+  s.[:members_of (^^A, uctx)[0]:] += 20;
+  s.[:members_of (^^A, uctx)[2]:] += 30;
+  auto [ sa, sb, sc ] = s;
+  if (sa != 21 || sb != 12 || sc != 33)
+    __builtin_abort ();
+  T t = { 4, 5, 6 };
+  t.[:members_of (^^B, uctx)[1]:] += 40;
+  t.[:members_of (^^B, uctx)[2]:] += 50;
+  t.[:members_of (^^B, uctx)[0]:] += 60;
+  auto [ ta, tb, tc ] = t;
+  if (ta != 64 || tb != 45 || tc != 56)
+    __builtin_abort ();
+  U u = { U::F, U::I };
+#if 0
+  // TODO: This doesn't work yet:
+  u.[:nonstatic_data_members_of (^^C, uctx)[0]:] = u.[:^^C::E::G:];
+#else
+  u.[:nonstatic_data_members_of (^^C, uctx)[0]:] = u.[:^^C::G:];
+#endif
+  u.[:nonstatic_data_members_of (^^C, uctx)[1]:] = u.[:^^C::H:];
+  if (u.j != U::G || u.k != U::E::H)
+    __builtin_abort ();
+  V v = {};
+  v.[:members_of (^^A, uctx)[1]:] = 1;
+  v.[:members_of (^^B, uctx)[2]:] = 2;
+  v.[:members_of (^^D, uctx)[0]:] = 3;
+}
+
+template <typename A, typename B, typename C, typename D>
+void
+fred ()
+{
+  A s = { 1, 2, 3 };
+  s.[:members_of (^^A, uctx)[1]:] += 10;
+  s.[:members_of (^^A, uctx)[0]:] += 20;
+  s.[:members_of (^^A, uctx)[2]:] += 30;
+  auto [ sa, sb, sc ] = s;
+  if (sa != 21 || sb != 12 || sc != 33)
+    __builtin_abort ();
+  B t = { 4, 5, 6 };
+  t.[:members_of (^^B, uctx)[1]:] += 40;
+  t.[:members_of (^^B, uctx)[2]:] += 50;
+  t.[:members_of (^^B, uctx)[0]:] += 60;
+  auto [ ta, tb, tc ] = t;
+  if (ta != 64 || tb != 45 || tc != 56)
+    __builtin_abort ();
+  C u = { U::F, U::I };
+#if 0
+  // TODO: This doesn't work yet:
+  u.[:nonstatic_data_members_of (^^C, uctx)[0]:] = u.[:^^C::E::G:];
+#else
+  u.[:nonstatic_data_members_of (^^C, uctx)[0]:] = u.[:^^C::G:];
+#endif
+  u.[:nonstatic_data_members_of (^^C, uctx)[1]:] = u.[:^^C::H:];
+  if (u.j != U::G || u.k != U::E::H)
+    __builtin_abort ();
+  D v = {};
+  v.[:members_of (^^A, uctx)[1]:] = 1;
+  v.[:members_of (^^B, uctx)[2]:] = 2;
+  v.[:members_of (^^D, uctx)[0]:] = 3;
+}
+
+int
+main ()
+{
+  foo ();
+  bar <42> ();
+  baz <S, T, U, V> ();
+  qux <S, T, U, V> ();
+  fred <S, T, U, V> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member16.C b/gcc/testsuite/g++.dg/reflect/member16.C
new file mode 100644 (file)
index 0000000..2679cdc
--- /dev/null
@@ -0,0 +1,86 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A { int a; };
+struct B : public A { int b; };
+struct C : public B { int c; };
+struct D : public A, B, C { int d; };  // { dg-warning "direct base 'A' inaccessible in 'D' due to ambiguity" }
+                                       // { dg-warning "direct base 'B' inaccessible in 'D' due to ambiguity" "" { target *-*-* } .-1 }
+struct E { int _; };
+struct F : public E { int _; };
+struct G : public F { int _; };
+struct H : public E, F, G { int _; };  // { dg-warning "direct base 'E' inaccessible in 'H' due to ambiguity" }
+                                       // { dg-warning "direct base 'F' inaccessible in 'H' due to ambiguity" "" { target *-*-* } .-1 }
+struct I { int i; };
+struct J { int _; };
+
+void
+foo (C &c, D &d, G &g, H &h)
+{
+  c.[: ^^A::a :] = 1;
+  c.[: ^^B::b :] = 2;
+  c.[: ^^C::c :] = 3;
+  d.[: ^^A::a :] = 4;                  // { dg-error "'A' is an ambiguous base of 'D'" }
+  d.[: ^^B::b :] = 5;                  // { dg-error "'B' is an ambiguous base of 'D'" }
+  d.[: ^^C::c :] = 6;
+  d.[: ^^D::d :] = 7;
+  d.[: ^^I::i :] = 8;                  // { dg-error "'I' is not a base of 'D'" }
+  g.[: ^^E::_ :] = 1;
+  g.[: ^^F::_ :] = 2;
+  g.[: ^^G::_ :] = 3;
+  h.[: ^^E::_ :] = 4;                  // { dg-error "'E' is an ambiguous base of 'H'" }
+  h.[: ^^F::_ :] = 5;                  // { dg-error "'F' is an ambiguous base of 'H'" }
+  h.[: ^^G::_ :] = 6;
+  h.[: ^^H::_ :] = 7;
+  h.[: ^^J::_ :] = 8;                  // { dg-error "'J' is not a base of 'H'" }
+}
+
+template <typename S, typename T, typename U, typename V>
+void
+bar (S &c, T &d, U &g, V &h)
+{
+  c.[: ^^A::a :] = 1;
+  c.[: ^^B::b :] = 2;
+  c.[: ^^C::c :] = 3;
+  d.[: ^^A::a :] = 4;                  // { dg-error "'A' is an ambiguous base of 'D'" }
+  d.[: ^^B::b :] = 5;                  // { dg-error "'B' is an ambiguous base of 'D'" }
+  d.[: ^^C::c :] = 6;
+  d.[: ^^D::d :] = 7;
+  d.[: ^^I::i :] = 8;                  // { dg-error "invalid use of non-static data member 'I::i'" }
+  g.[: ^^E::_ :] = 1;
+  g.[: ^^F::_ :] = 2;
+  g.[: ^^G::_ :] = 3;
+  h.[: ^^E::_ :] = 4;                  // { dg-error "'E' is an ambiguous base of 'H'" }
+  h.[: ^^F::_ :] = 5;                  // { dg-error "'F' is an ambiguous base of 'H'" }
+  h.[: ^^G::_ :] = 6;
+  h.[: ^^H::_ :] = 7;
+  h.[: ^^J::_ :] = 8;                  // { dg-error "invalid use of non-static data member 'J::_'" }
+}
+
+void
+baz (C &c, D &d, G &g, H &h)
+{
+  bar (c, d, g, h);
+}
+
+template <int N>
+void
+qux (C &c, D &d, G &g, H &h)
+{
+  c.[: ^^A::a :] = 1;
+  c.[: ^^B::b :] = 2;
+  c.[: ^^C::c :] = 3;
+  d.[: ^^A::a :] = 4;                  // { dg-error "'A' is an ambiguous base of 'D'" }
+  d.[: ^^B::b :] = 5;                  // { dg-error "'B' is an ambiguous base of 'D'" }
+  d.[: ^^C::c :] = 6;
+  d.[: ^^D::d :] = 7;
+  d.[: ^^I::i :] = 8;                  // { dg-error "'I' is not a base of 'D'" }
+  g.[: ^^E::_ :] = 1;
+  g.[: ^^F::_ :] = 2;
+  g.[: ^^G::_ :] = 3;
+  h.[: ^^E::_ :] = 4;                  // { dg-error "'E' is an ambiguous base of 'H'" }
+  h.[: ^^F::_ :] = 5;                  // { dg-error "'F' is an ambiguous base of 'H'" }
+  h.[: ^^G::_ :] = 6;
+  h.[: ^^H::_ :] = 7;
+  h.[: ^^J::_ :] = 8;                  // { dg-error "'J' is not a base of 'H'" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member17.C b/gcc/testsuite/g++.dg/reflect/member17.C
new file mode 100644 (file)
index 0000000..f5850c9
--- /dev/null
@@ -0,0 +1,402 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  constexpr int foo (int x) const { return 41 + x + s; }
+  constexpr int foo (long x) const { return 42 + x + s; }
+  constexpr int foo (long long x) const { return 43 + x + s; }
+  static constexpr int bar (int x) { return 72 + x; } 
+  static constexpr int bar (long x) { return 73 + x; } 
+  static constexpr int bar (long long x) { return 74 + x; } 
+  constexpr S (int x) : s (x) {}
+  int s;
+};
+struct T : public S {
+  constexpr int foo (int x) const { return 51 + x + s; }
+  constexpr int foo (long x) const { return 52 + x + s; }
+  constexpr int foo (long long x) const { return 53 + x + s; }
+  static constexpr int bar (int x) { return 82 + x; } 
+  static constexpr int bar (long x) { return 83 + x; } 
+  static constexpr int bar (long long x) { return 84 + x; } 
+  constexpr T (int x) : S (x) {}
+};
+
+constexpr access_context uctx = access_context::unchecked ();
+
+constexpr S s = 1;
+static_assert (s.foo (0) == 42);
+static_assert (s.foo (0L) == 43);
+static_assert (s.foo (0LL) == 44);
+static_assert (s.[:members_of (^^S, uctx)[0]:] (10) == 52);
+static_assert (s.[:members_of (^^S, uctx)[0]:] (20L) == 62);
+static_assert (s.[:members_of (^^S, uctx)[0]:] (30LL) == 72);
+static_assert (s.[:members_of (^^S, uctx)[1]:] (10) == 53);
+static_assert (s.[:members_of (^^S, uctx)[1]:] (20L) == 63);
+static_assert (s.[:members_of (^^S, uctx)[1]:] (30LL) == 73);
+static_assert (s.[:members_of (^^S, uctx)[2]:] (10) == 54);
+static_assert (s.[:members_of (^^S, uctx)[2]:] (20L) == 64);
+static_assert (s.[:members_of (^^S, uctx)[2]:] (30LL) == 74);
+static_assert (s.bar (0) == 72);
+static_assert (s.bar (0L) == 73);
+static_assert (s.bar (0LL) == 74);
+static_assert (s.[:members_of (^^S, uctx)[3]:] (10) == 82);
+static_assert (s.[:members_of (^^S, uctx)[3]:] (20L) == 92);
+static_assert (s.[:members_of (^^S, uctx)[3]:] (30LL) == 102);
+static_assert (s.[:members_of (^^S, uctx)[4]:] (10) == 83);
+static_assert (s.[:members_of (^^S, uctx)[4]:] (20L) == 93);
+static_assert (s.[:members_of (^^S, uctx)[4]:] (30LL) == 103);
+static_assert (s.[:members_of (^^S, uctx)[5]:] (10) == 84);
+static_assert (s.[:members_of (^^S, uctx)[5]:] (20L) == 94);
+static_assert (s.[:members_of (^^S, uctx)[5]:] (30LL) == 104);
+constexpr T t = 2;
+static_assert (t.foo (0) == 53);
+static_assert (t.foo (0L) == 54);
+static_assert (t.foo (0LL) == 55);
+static_assert (t.[:members_of (^^S, uctx)[0]:] (10) == 53);
+static_assert (t.[:members_of (^^S, uctx)[0]:] (20L) == 63);
+static_assert (t.[:members_of (^^S, uctx)[0]:] (30LL) == 73);
+static_assert (t.[:members_of (^^S, uctx)[1]:] (10) == 54);
+static_assert (t.[:members_of (^^S, uctx)[1]:] (20L) == 64);
+static_assert (t.[:members_of (^^S, uctx)[1]:] (30LL) == 74);
+static_assert (t.[:members_of (^^S, uctx)[2]:] (10) == 55);
+static_assert (t.[:members_of (^^S, uctx)[2]:] (20L) == 65);
+static_assert (t.[:members_of (^^S, uctx)[2]:] (30LL) == 75);
+static_assert (t.[:members_of (^^T, uctx)[0]:] (10) == 63);
+static_assert (t.[:members_of (^^T, uctx)[0]:] (20L) == 73);
+static_assert (t.[:members_of (^^T, uctx)[0]:] (30LL) == 83);
+static_assert (t.[:members_of (^^T, uctx)[1]:] (10) == 64);
+static_assert (t.[:members_of (^^T, uctx)[1]:] (20L) == 74);
+static_assert (t.[:members_of (^^T, uctx)[1]:] (30LL) == 84);
+static_assert (t.[:members_of (^^T, uctx)[2]:] (10) == 65);
+static_assert (t.[:members_of (^^T, uctx)[2]:] (20L) == 75);
+static_assert (t.[:members_of (^^T, uctx)[2]:] (30LL) == 85);
+static_assert (t.bar (0) == 82);
+static_assert (t.bar (0L) == 83);
+static_assert (t.bar (0LL) == 84);
+static_assert (t.[:members_of (^^S, uctx)[3]:] (10) == 82);
+static_assert (t.[:members_of (^^S, uctx)[3]:] (20L) == 92);
+static_assert (t.[:members_of (^^S, uctx)[3]:] (30LL) == 102);
+static_assert (t.[:members_of (^^S, uctx)[4]:] (10) == 83);
+static_assert (t.[:members_of (^^S, uctx)[4]:] (20L) == 93);
+static_assert (t.[:members_of (^^S, uctx)[4]:] (30LL) == 103);
+static_assert (t.[:members_of (^^S, uctx)[5]:] (10) == 84);
+static_assert (t.[:members_of (^^S, uctx)[5]:] (20L) == 94);
+static_assert (t.[:members_of (^^S, uctx)[5]:] (30LL) == 104);
+static_assert (t.[:members_of (^^T, uctx)[3]:] (10) == 92);
+static_assert (t.[:members_of (^^T, uctx)[3]:] (20L) == 102);
+static_assert (t.[:members_of (^^T, uctx)[3]:] (30LL) == 112);
+static_assert (t.[:members_of (^^T, uctx)[4]:] (10) == 93);
+static_assert (t.[:members_of (^^T, uctx)[4]:] (20L) == 103);
+static_assert (t.[:members_of (^^T, uctx)[4]:] (30LL) == 113);
+static_assert (t.[:members_of (^^T, uctx)[5]:] (10) == 94);
+static_assert (t.[:members_of (^^T, uctx)[5]:] (20L) == 104);
+static_assert (t.[:members_of (^^T, uctx)[5]:] (30LL) == 114);
+
+template <int N>
+void
+foo ()
+{
+  constexpr S s = 1;
+  static_assert (s.foo (0) == 42);
+  static_assert (s.foo (0L) == 43);
+  static_assert (s.foo (0LL) == 44);
+  static_assert (s.[:members_of (^^S, uctx)[0]:] (10) == 52);
+  static_assert (s.[:members_of (^^S, uctx)[0]:] (20L) == 62);
+  static_assert (s.[:members_of (^^S, uctx)[0]:] (30LL) == 72);
+  static_assert (s.[:members_of (^^S, uctx)[1]:] (10) == 53);
+  static_assert (s.[:members_of (^^S, uctx)[1]:] (20L) == 63);
+  static_assert (s.[:members_of (^^S, uctx)[1]:] (30LL) == 73);
+  static_assert (s.[:members_of (^^S, uctx)[2]:] (10) == 54);
+  static_assert (s.[:members_of (^^S, uctx)[2]:] (20L) == 64);
+  static_assert (s.[:members_of (^^S, uctx)[2]:] (30LL) == 74);
+  static_assert (s.bar (0) == 72);
+  static_assert (s.bar (0L) == 73);
+  static_assert (s.bar (0LL) == 74);
+  static_assert (s.[:members_of (^^S, uctx)[3]:] (10) == 82);
+  static_assert (s.[:members_of (^^S, uctx)[3]:] (20L) == 92);
+  static_assert (s.[:members_of (^^S, uctx)[3]:] (30LL) == 102);
+  static_assert (s.[:members_of (^^S, uctx)[4]:] (10) == 83);
+  static_assert (s.[:members_of (^^S, uctx)[4]:] (20L) == 93);
+  static_assert (s.[:members_of (^^S, uctx)[4]:] (30LL) == 103);
+  static_assert (s.[:members_of (^^S, uctx)[5]:] (10) == 84);
+  static_assert (s.[:members_of (^^S, uctx)[5]:] (20L) == 94);
+  static_assert (s.[:members_of (^^S, uctx)[5]:] (30LL) == 104);
+  constexpr T t = 2;
+  static_assert (t.foo (0) == 53);
+  static_assert (t.foo (0L) == 54);
+  static_assert (t.foo (0LL) == 55);
+  static_assert (t.[:members_of (^^S, uctx)[0]:] (10) == 53);
+  static_assert (t.[:members_of (^^S, uctx)[0]:] (20L) == 63);
+  static_assert (t.[:members_of (^^S, uctx)[0]:] (30LL) == 73);
+  static_assert (t.[:members_of (^^S, uctx)[1]:] (10) == 54);
+  static_assert (t.[:members_of (^^S, uctx)[1]:] (20L) == 64);
+  static_assert (t.[:members_of (^^S, uctx)[1]:] (30LL) == 74);
+  static_assert (t.[:members_of (^^S, uctx)[2]:] (10) == 55);
+  static_assert (t.[:members_of (^^S, uctx)[2]:] (20L) == 65);
+  static_assert (t.[:members_of (^^S, uctx)[2]:] (30LL) == 75);
+  static_assert (t.[:members_of (^^T, uctx)[0]:] (10) == 63);
+  static_assert (t.[:members_of (^^T, uctx)[0]:] (20L) == 73);
+  static_assert (t.[:members_of (^^T, uctx)[0]:] (30LL) == 83);
+  static_assert (t.[:members_of (^^T, uctx)[1]:] (10) == 64);
+  static_assert (t.[:members_of (^^T, uctx)[1]:] (20L) == 74);
+  static_assert (t.[:members_of (^^T, uctx)[1]:] (30LL) == 84);
+  static_assert (t.[:members_of (^^T, uctx)[2]:] (10) == 65);
+  static_assert (t.[:members_of (^^T, uctx)[2]:] (20L) == 75);
+  static_assert (t.[:members_of (^^T, uctx)[2]:] (30LL) == 85);
+  static_assert (t.bar (0) == 82);
+  static_assert (t.bar (0L) == 83);
+  static_assert (t.bar (0LL) == 84);
+  static_assert (t.[:members_of (^^S, uctx)[3]:] (10) == 82);
+  static_assert (t.[:members_of (^^S, uctx)[3]:] (20L) == 92);
+  static_assert (t.[:members_of (^^S, uctx)[3]:] (30LL) == 102);
+  static_assert (t.[:members_of (^^S, uctx)[4]:] (10) == 83);
+  static_assert (t.[:members_of (^^S, uctx)[4]:] (20L) == 93);
+  static_assert (t.[:members_of (^^S, uctx)[4]:] (30LL) == 103);
+  static_assert (t.[:members_of (^^S, uctx)[5]:] (10) == 84);
+  static_assert (t.[:members_of (^^S, uctx)[5]:] (20L) == 94);
+  static_assert (t.[:members_of (^^S, uctx)[5]:] (30LL) == 104);
+  static_assert (t.[:members_of (^^T, uctx)[3]:] (10) == 92);
+  static_assert (t.[:members_of (^^T, uctx)[3]:] (20L) == 102);
+  static_assert (t.[:members_of (^^T, uctx)[3]:] (30LL) == 112);
+  static_assert (t.[:members_of (^^T, uctx)[4]:] (10) == 93);
+  static_assert (t.[:members_of (^^T, uctx)[4]:] (20L) == 103);
+  static_assert (t.[:members_of (^^T, uctx)[4]:] (30LL) == 113);
+  static_assert (t.[:members_of (^^T, uctx)[5]:] (10) == 94);
+  static_assert (t.[:members_of (^^T, uctx)[5]:] (20L) == 104);
+  static_assert (t.[:members_of (^^T, uctx)[5]:] (30LL) == 114);
+}
+
+template <typename A, typename B>
+void
+bar ()
+{
+  constexpr A s = 1;
+  static_assert (s.foo (0) == 42);
+  static_assert (s.foo (0L) == 43);
+  static_assert (s.foo (0LL) == 44);
+  static_assert (s.[:members_of (^^S, uctx)[0]:] (10) == 52);
+  static_assert (s.[:members_of (^^S, uctx)[0]:] (20L) == 62);
+  static_assert (s.[:members_of (^^S, uctx)[0]:] (30LL) == 72);
+  static_assert (s.[:members_of (^^S, uctx)[1]:] (10) == 53);
+  static_assert (s.[:members_of (^^S, uctx)[1]:] (20L) == 63);
+  static_assert (s.[:members_of (^^S, uctx)[1]:] (30LL) == 73);
+  static_assert (s.[:members_of (^^S, uctx)[2]:] (10) == 54);
+  static_assert (s.[:members_of (^^S, uctx)[2]:] (20L) == 64);
+  static_assert (s.[:members_of (^^S, uctx)[2]:] (30LL) == 74);
+  static_assert (s.bar (0) == 72);
+  static_assert (s.bar (0L) == 73);
+  static_assert (s.bar (0LL) == 74);
+  static_assert (s.[:members_of (^^S, uctx)[3]:] (10) == 82);
+  static_assert (s.[:members_of (^^S, uctx)[3]:] (20L) == 92);
+  static_assert (s.[:members_of (^^S, uctx)[3]:] (30LL) == 102);
+  static_assert (s.[:members_of (^^S, uctx)[4]:] (10) == 83);
+  static_assert (s.[:members_of (^^S, uctx)[4]:] (20L) == 93);
+  static_assert (s.[:members_of (^^S, uctx)[4]:] (30LL) == 103);
+  static_assert (s.[:members_of (^^S, uctx)[5]:] (10) == 84);
+  static_assert (s.[:members_of (^^S, uctx)[5]:] (20L) == 94);
+  static_assert (s.[:members_of (^^S, uctx)[5]:] (30LL) == 104);
+  constexpr B t = 2;
+  static_assert (t.foo (0) == 53);
+  static_assert (t.foo (0L) == 54);
+  static_assert (t.foo (0LL) == 55);
+  static_assert (t.[:members_of (^^S, uctx)[0]:] (10) == 53);
+  static_assert (t.[:members_of (^^S, uctx)[0]:] (20L) == 63);
+  static_assert (t.[:members_of (^^S, uctx)[0]:] (30LL) == 73);
+  static_assert (t.[:members_of (^^S, uctx)[1]:] (10) == 54);
+  static_assert (t.[:members_of (^^S, uctx)[1]:] (20L) == 64);
+  static_assert (t.[:members_of (^^S, uctx)[1]:] (30LL) == 74);
+  static_assert (t.[:members_of (^^S, uctx)[2]:] (10) == 55);
+  static_assert (t.[:members_of (^^S, uctx)[2]:] (20L) == 65);
+  static_assert (t.[:members_of (^^S, uctx)[2]:] (30LL) == 75);
+  static_assert (t.[:members_of (^^T, uctx)[0]:] (10) == 63);
+  static_assert (t.[:members_of (^^T, uctx)[0]:] (20L) == 73);
+  static_assert (t.[:members_of (^^T, uctx)[0]:] (30LL) == 83);
+  static_assert (t.[:members_of (^^T, uctx)[1]:] (10) == 64);
+  static_assert (t.[:members_of (^^T, uctx)[1]:] (20L) == 74);
+  static_assert (t.[:members_of (^^T, uctx)[1]:] (30LL) == 84);
+  static_assert (t.[:members_of (^^T, uctx)[2]:] (10) == 65);
+  static_assert (t.[:members_of (^^T, uctx)[2]:] (20L) == 75);
+  static_assert (t.[:members_of (^^T, uctx)[2]:] (30LL) == 85);
+  static_assert (t.bar (0) == 82);
+  static_assert (t.bar (0L) == 83);
+  static_assert (t.bar (0LL) == 84);
+  static_assert (t.[:members_of (^^S, uctx)[3]:] (10) == 82);
+  static_assert (t.[:members_of (^^S, uctx)[3]:] (20L) == 92);
+  static_assert (t.[:members_of (^^S, uctx)[3]:] (30LL) == 102);
+  static_assert (t.[:members_of (^^S, uctx)[4]:] (10) == 83);
+  static_assert (t.[:members_of (^^S, uctx)[4]:] (20L) == 93);
+  static_assert (t.[:members_of (^^S, uctx)[4]:] (30LL) == 103);
+  static_assert (t.[:members_of (^^S, uctx)[5]:] (10) == 84);
+  static_assert (t.[:members_of (^^S, uctx)[5]:] (20L) == 94);
+  static_assert (t.[:members_of (^^S, uctx)[5]:] (30LL) == 104);
+  static_assert (t.[:members_of (^^T, uctx)[3]:] (10) == 92);
+  static_assert (t.[:members_of (^^T, uctx)[3]:] (20L) == 102);
+  static_assert (t.[:members_of (^^T, uctx)[3]:] (30LL) == 112);
+  static_assert (t.[:members_of (^^T, uctx)[4]:] (10) == 93);
+  static_assert (t.[:members_of (^^T, uctx)[4]:] (20L) == 103);
+  static_assert (t.[:members_of (^^T, uctx)[4]:] (30LL) == 113);
+  static_assert (t.[:members_of (^^T, uctx)[5]:] (10) == 94);
+  static_assert (t.[:members_of (^^T, uctx)[5]:] (20L) == 104);
+  static_assert (t.[:members_of (^^T, uctx)[5]:] (30LL) == 114);
+}
+
+template <typename A, typename B>
+void
+baz ()
+{
+  constexpr S s = 1;
+  static_assert (s.foo (0) == 42);
+  static_assert (s.foo (0L) == 43);
+  static_assert (s.foo (0LL) == 44);
+  static_assert (s.[:members_of (^^A, uctx)[0]:] (10) == 52);
+  static_assert (s.[:members_of (^^A, uctx)[0]:] (20L) == 62);
+  static_assert (s.[:members_of (^^A, uctx)[0]:] (30LL) == 72);
+  static_assert (s.[:members_of (^^A, uctx)[1]:] (10) == 53);
+  static_assert (s.[:members_of (^^A, uctx)[1]:] (20L) == 63);
+  static_assert (s.[:members_of (^^A, uctx)[1]:] (30LL) == 73);
+  static_assert (s.[:members_of (^^A, uctx)[2]:] (10) == 54);
+  static_assert (s.[:members_of (^^A, uctx)[2]:] (20L) == 64);
+  static_assert (s.[:members_of (^^A, uctx)[2]:] (30LL) == 74);
+  static_assert (s.bar (0) == 72);
+  static_assert (s.bar (0L) == 73);
+  static_assert (s.bar (0LL) == 74);
+  static_assert (s.[:members_of (^^A, uctx)[3]:] (10) == 82);
+  static_assert (s.[:members_of (^^A, uctx)[3]:] (20L) == 92);
+  static_assert (s.[:members_of (^^A, uctx)[3]:] (30LL) == 102);
+  static_assert (s.[:members_of (^^A, uctx)[4]:] (10) == 83);
+  static_assert (s.[:members_of (^^A, uctx)[4]:] (20L) == 93);
+  static_assert (s.[:members_of (^^A, uctx)[4]:] (30LL) == 103);
+  static_assert (s.[:members_of (^^A, uctx)[5]:] (10) == 84);
+  static_assert (s.[:members_of (^^A, uctx)[5]:] (20L) == 94);
+  static_assert (s.[:members_of (^^A, uctx)[5]:] (30LL) == 104);
+  constexpr T t = 2;
+  static_assert (t.foo (0) == 53);
+  static_assert (t.foo (0L) == 54);
+  static_assert (t.foo (0LL) == 55);
+  static_assert (t.[:members_of (^^A, uctx)[0]:] (10) == 53);
+  static_assert (t.[:members_of (^^A, uctx)[0]:] (20L) == 63);
+  static_assert (t.[:members_of (^^A, uctx)[0]:] (30LL) == 73);
+  static_assert (t.[:members_of (^^A, uctx)[1]:] (10) == 54);
+  static_assert (t.[:members_of (^^A, uctx)[1]:] (20L) == 64);
+  static_assert (t.[:members_of (^^A, uctx)[1]:] (30LL) == 74);
+  static_assert (t.[:members_of (^^A, uctx)[2]:] (10) == 55);
+  static_assert (t.[:members_of (^^A, uctx)[2]:] (20L) == 65);
+  static_assert (t.[:members_of (^^A, uctx)[2]:] (30LL) == 75);
+  static_assert (t.[:members_of (^^B, uctx)[0]:] (10) == 63);
+  static_assert (t.[:members_of (^^B, uctx)[0]:] (20L) == 73);
+  static_assert (t.[:members_of (^^B, uctx)[0]:] (30LL) == 83);
+  static_assert (t.[:members_of (^^B, uctx)[1]:] (10) == 64);
+  static_assert (t.[:members_of (^^B, uctx)[1]:] (20L) == 74);
+  static_assert (t.[:members_of (^^B, uctx)[1]:] (30LL) == 84);
+  static_assert (t.[:members_of (^^B, uctx)[2]:] (10) == 65);
+  static_assert (t.[:members_of (^^B, uctx)[2]:] (20L) == 75);
+  static_assert (t.[:members_of (^^B, uctx)[2]:] (30LL) == 85);
+  static_assert (t.bar (0) == 82);
+  static_assert (t.bar (0L) == 83);
+  static_assert (t.bar (0LL) == 84);
+  static_assert (t.[:members_of (^^A, uctx)[3]:] (10) == 82);
+  static_assert (t.[:members_of (^^A, uctx)[3]:] (20L) == 92);
+  static_assert (t.[:members_of (^^A, uctx)[3]:] (30LL) == 102);
+  static_assert (t.[:members_of (^^A, uctx)[4]:] (10) == 83);
+  static_assert (t.[:members_of (^^A, uctx)[4]:] (20L) == 93);
+  static_assert (t.[:members_of (^^A, uctx)[4]:] (30LL) == 103);
+  static_assert (t.[:members_of (^^A, uctx)[5]:] (10) == 84);
+  static_assert (t.[:members_of (^^A, uctx)[5]:] (20L) == 94);
+  static_assert (t.[:members_of (^^A, uctx)[5]:] (30LL) == 104);
+  static_assert (t.[:members_of (^^B, uctx)[3]:] (10) == 92);
+  static_assert (t.[:members_of (^^B, uctx)[3]:] (20L) == 102);
+  static_assert (t.[:members_of (^^B, uctx)[3]:] (30LL) == 112);
+  static_assert (t.[:members_of (^^B, uctx)[4]:] (10) == 93);
+  static_assert (t.[:members_of (^^B, uctx)[4]:] (20L) == 103);
+  static_assert (t.[:members_of (^^B, uctx)[4]:] (30LL) == 113);
+  static_assert (t.[:members_of (^^B, uctx)[5]:] (10) == 94);
+  static_assert (t.[:members_of (^^B, uctx)[5]:] (20L) == 104);
+  static_assert (t.[:members_of (^^B, uctx)[5]:] (30LL) == 114);
+}
+
+template <typename A, typename B>
+void
+qux ()
+{
+  constexpr A s = 1;
+  static_assert (s.foo (0) == 42);
+  static_assert (s.foo (0L) == 43);
+  static_assert (s.foo (0LL) == 44);
+  static_assert (s.[:members_of (^^A, uctx)[0]:] (10) == 52);
+  static_assert (s.[:members_of (^^A, uctx)[0]:] (20L) == 62);
+  static_assert (s.[:members_of (^^A, uctx)[0]:] (30LL) == 72);
+  static_assert (s.[:members_of (^^A, uctx)[1]:] (10) == 53);
+  static_assert (s.[:members_of (^^A, uctx)[1]:] (20L) == 63);
+  static_assert (s.[:members_of (^^A, uctx)[1]:] (30LL) == 73);
+  static_assert (s.[:members_of (^^A, uctx)[2]:] (10) == 54);
+  static_assert (s.[:members_of (^^A, uctx)[2]:] (20L) == 64);
+  static_assert (s.[:members_of (^^A, uctx)[2]:] (30LL) == 74);
+  static_assert (s.bar (0) == 72);
+  static_assert (s.bar (0L) == 73);
+  static_assert (s.bar (0LL) == 74);
+  static_assert (s.[:members_of (^^A, uctx)[3]:] (10) == 82);
+  static_assert (s.[:members_of (^^A, uctx)[3]:] (20L) == 92);
+  static_assert (s.[:members_of (^^A, uctx)[3]:] (30LL) == 102);
+  static_assert (s.[:members_of (^^A, uctx)[4]:] (10) == 83);
+  static_assert (s.[:members_of (^^A, uctx)[4]:] (20L) == 93);
+  static_assert (s.[:members_of (^^A, uctx)[4]:] (30LL) == 103);
+  static_assert (s.[:members_of (^^A, uctx)[5]:] (10) == 84);
+  static_assert (s.[:members_of (^^A, uctx)[5]:] (20L) == 94);
+  static_assert (s.[:members_of (^^A, uctx)[5]:] (30LL) == 104);
+  constexpr B t = 2;
+  static_assert (t.foo (0) == 53);
+  static_assert (t.foo (0L) == 54);
+  static_assert (t.foo (0LL) == 55);
+  static_assert (t.[:members_of (^^A, uctx)[0]:] (10) == 53);
+  static_assert (t.[:members_of (^^A, uctx)[0]:] (20L) == 63);
+  static_assert (t.[:members_of (^^A, uctx)[0]:] (30LL) == 73);
+  static_assert (t.[:members_of (^^A, uctx)[1]:] (10) == 54);
+  static_assert (t.[:members_of (^^A, uctx)[1]:] (20L) == 64);
+  static_assert (t.[:members_of (^^A, uctx)[1]:] (30LL) == 74);
+  static_assert (t.[:members_of (^^A, uctx)[2]:] (10) == 55);
+  static_assert (t.[:members_of (^^A, uctx)[2]:] (20L) == 65);
+  static_assert (t.[:members_of (^^A, uctx)[2]:] (30LL) == 75);
+  static_assert (t.[:members_of (^^B, uctx)[0]:] (10) == 63);
+  static_assert (t.[:members_of (^^B, uctx)[0]:] (20L) == 73);
+  static_assert (t.[:members_of (^^B, uctx)[0]:] (30LL) == 83);
+  static_assert (t.[:members_of (^^B, uctx)[1]:] (10) == 64);
+  static_assert (t.[:members_of (^^B, uctx)[1]:] (20L) == 74);
+  static_assert (t.[:members_of (^^B, uctx)[1]:] (30LL) == 84);
+  static_assert (t.[:members_of (^^B, uctx)[2]:] (10) == 65);
+  static_assert (t.[:members_of (^^B, uctx)[2]:] (20L) == 75);
+  static_assert (t.[:members_of (^^B, uctx)[2]:] (30LL) == 85);
+  static_assert (t.bar (0) == 82);
+  static_assert (t.bar (0L) == 83);
+  static_assert (t.bar (0LL) == 84);
+  static_assert (t.[:members_of (^^A, uctx)[3]:] (10) == 82);
+  static_assert (t.[:members_of (^^A, uctx)[3]:] (20L) == 92);
+  static_assert (t.[:members_of (^^A, uctx)[3]:] (30LL) == 102);
+  static_assert (t.[:members_of (^^A, uctx)[4]:] (10) == 83);
+  static_assert (t.[:members_of (^^A, uctx)[4]:] (20L) == 93);
+  static_assert (t.[:members_of (^^A, uctx)[4]:] (30LL) == 103);
+  static_assert (t.[:members_of (^^A, uctx)[5]:] (10) == 84);
+  static_assert (t.[:members_of (^^A, uctx)[5]:] (20L) == 94);
+  static_assert (t.[:members_of (^^A, uctx)[5]:] (30LL) == 104);
+  static_assert (t.[:members_of (^^B, uctx)[3]:] (10) == 92);
+  static_assert (t.[:members_of (^^B, uctx)[3]:] (20L) == 102);
+  static_assert (t.[:members_of (^^B, uctx)[3]:] (30LL) == 112);
+  static_assert (t.[:members_of (^^B, uctx)[4]:] (10) == 93);
+  static_assert (t.[:members_of (^^B, uctx)[4]:] (20L) == 103);
+  static_assert (t.[:members_of (^^B, uctx)[4]:] (30LL) == 113);
+  static_assert (t.[:members_of (^^B, uctx)[5]:] (10) == 94);
+  static_assert (t.[:members_of (^^B, uctx)[5]:] (20L) == 104);
+  static_assert (t.[:members_of (^^B, uctx)[5]:] (30LL) == 114);
+}
+
+void
+fred ()
+{
+  foo <42> ();
+  bar <S, T> ();
+  baz <S, T> ();
+  qux <S, T> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member18.C b/gcc/testsuite/g++.dg/reflect/member18.C
new file mode 100644 (file)
index 0000000..50aa954
--- /dev/null
@@ -0,0 +1,744 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  template <typename U>
+  constexpr int foo (int x, const U &) const { return 41 + x + s; }
+  template <typename U>
+  constexpr int foo (long x, const U &) const { return 42 + x + s; }
+  template <typename U>
+  constexpr int foo (long long x, const U &) const { return 43 + x + s; }
+  template <typename U>
+  static constexpr int bar (int x, const U &) { return 72 + x; } 
+  template <typename U>
+  static constexpr int bar (long x, const U &) { return 73 + x; } 
+  template <typename U>
+  static constexpr int bar (long long x, const U &) { return 74 + x; } 
+  constexpr S (int x) : s (x) {}
+  int s;
+};
+struct T : public S {
+  template <typename U>
+  constexpr int foo (int x, const U &) const { return 51 + x + s; }
+  template <typename U>
+  constexpr int foo (long x, const U &) const { return 52 + x + s; }
+  template <typename U>
+  constexpr int foo (long long x, const U &) const { return 53 + x + s; }
+  template <typename U>
+  static constexpr int bar (int x, const U &) { return 82 + x; } 
+  template <typename U>
+  static constexpr int bar (long x, const U &) { return 83 + x; } 
+  template <typename U>
+  static constexpr int bar (long long x, const U &) { return 84 + x; } 
+  constexpr T (int x) : S (x) {}
+};
+
+constexpr access_context uctx = access_context::unchecked ();
+
+constexpr S s = 1;
+static_assert (s.foo (0, 1.0f) == 42);
+static_assert (s.foo (0L, 1.0) == 43);
+static_assert (s.foo (0LL, 1.0L) == 44);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] (10, 1.0f) == 52);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] (20L, 1.0) == 62);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] (30LL, 1.0L) == 72);
+static_assert (s.template [:members_of (^^S, uctx)[1]:] (10, 1.0f) == 53);
+static_assert (s.template [:members_of (^^S, uctx)[1]:] (20L, 1.0) == 63);
+static_assert (s.template [:members_of (^^S, uctx)[1]:] (30LL, 1.0L) == 73);
+static_assert (s.template [:members_of (^^S, uctx)[2]:] (10, 1.0f) == 54);
+static_assert (s.template [:members_of (^^S, uctx)[2]:] (20L, 1.0) == 64);
+static_assert (s.template [:members_of (^^S, uctx)[2]:] (30LL, 1.0L) == 74);
+static_assert (s.foo <float> (0, 1.0f) == 42);
+static_assert (s.foo <double> (0L, 1.0) == 43);
+static_assert (s.foo <long double> (0LL, 1.0L) == 44);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] <float> (10, 1.0f) == 52);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] <double> (20L, 1.0) == 62);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] <long double> (30LL, 1.0L) == 72);
+static_assert (s.template [:members_of (^^S, uctx)[1]:] <float> (10, 1.0f) == 53);
+static_assert (s.template [:members_of (^^S, uctx)[1]:] <double> (20L, 1.0) == 63);
+static_assert (s.template [:members_of (^^S, uctx)[1]:] <long double> (30LL, 1.0L) == 73);
+static_assert (s.template [:members_of (^^S, uctx)[2]:] <float> (10, 1.0f) == 54);
+static_assert (s.template [:members_of (^^S, uctx)[2]:] <double> (20L, 1.0) == 64);
+static_assert (s.template [:members_of (^^S, uctx)[2]:] <long double> (30LL, 1.0L) == 74);
+static_assert (s.bar (0, 1.0f) == 72);
+static_assert (s.bar (0L, 1.0) == 73);
+static_assert (s.bar (0LL, 1.0L) == 74);
+static_assert (s.template [:members_of (^^S, uctx)[3]:] (10, 1.0f) == 82);
+static_assert (s.template [:members_of (^^S, uctx)[3]:] (20L, 1.0) == 92);
+static_assert (s.template [:members_of (^^S, uctx)[3]:] (30LL, 1.0L) == 102);
+static_assert (s.template [:members_of (^^S, uctx)[4]:] (10, 1.0f) == 83);
+static_assert (s.template [:members_of (^^S, uctx)[4]:] (20L, 1.0) == 93);
+static_assert (s.template [:members_of (^^S, uctx)[4]:] (30LL, 1.0L) == 103);
+static_assert (s.template [:members_of (^^S, uctx)[5]:] (10, 1.0f) == 84);
+static_assert (s.template [:members_of (^^S, uctx)[5]:] (20L, 1.0) == 94);
+static_assert (s.template [:members_of (^^S, uctx)[5]:] (30LL, 1.0L) == 104);
+static_assert (s.bar <float> (0, 1.0f) == 72);
+static_assert (s.bar <double> (0L, 1.0) == 73);
+static_assert (s.bar <long double> (0LL, 1.0L) == 74);
+static_assert (s.template [:members_of (^^S, uctx)[3]:] <float> (10, 1.0f) == 82);
+static_assert (s.template [:members_of (^^S, uctx)[3]:] <double> (20L, 1.0) == 92);
+static_assert (s.template [:members_of (^^S, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+static_assert (s.template [:members_of (^^S, uctx)[4]:] <float> (10, 1.0f) == 83);
+static_assert (s.template [:members_of (^^S, uctx)[4]:] <double> (20L, 1.0) == 93);
+static_assert (s.template [:members_of (^^S, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+static_assert (s.template [:members_of (^^S, uctx)[5]:] <float> (10, 1.0f) == 84);
+static_assert (s.template [:members_of (^^S, uctx)[5]:] <double> (20L, 1.0) == 94);
+static_assert (s.template [:members_of (^^S, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+constexpr T t = 2;
+static_assert (t.foo (0, 1.0f) == 53);
+static_assert (t.foo (0L, 1.0) == 54);
+static_assert (t.foo (0LL, 1.0L) == 55);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] (10, 1.0f) == 53);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] (20L, 1.0) == 63);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] (30LL, 1.0L) == 73);
+static_assert (t.template [:members_of (^^S, uctx)[1]:] (10, 1.0f) == 54);
+static_assert (t.template [:members_of (^^S, uctx)[1]:] (20L, 1.0) == 64);
+static_assert (t.template [:members_of (^^S, uctx)[1]:] (30LL, 1.0L) == 74);
+static_assert (t.template [:members_of (^^S, uctx)[2]:] (10, 1.0f) == 55);
+static_assert (t.template [:members_of (^^S, uctx)[2]:] (20L, 1.0) == 65);
+static_assert (t.template [:members_of (^^S, uctx)[2]:] (30LL, 1.0L) == 75);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] (10, 1.0f) == 63);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] (20L, 1.0) == 73);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] (30LL, 1.0L) == 83);
+static_assert (t.template [:members_of (^^T, uctx)[1]:] (10, 1.0f) == 64);
+static_assert (t.template [:members_of (^^T, uctx)[1]:] (20L, 1.0) == 74);
+static_assert (t.template [:members_of (^^T, uctx)[1]:] (30LL, 1.0L) == 84);
+static_assert (t.template [:members_of (^^T, uctx)[2]:] (10, 1.0f) == 65);
+static_assert (t.template [:members_of (^^T, uctx)[2]:] (20L, 1.0) == 75);
+static_assert (t.template [:members_of (^^T, uctx)[2]:] (30LL, 1.0L) == 85);
+static_assert (t.foo <float> (0, 1.0f) == 53);
+static_assert (t.foo <double> (0L, 1.0) == 54);
+static_assert (t.foo <long double> (0LL, 1.0L) == 55);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] <float> (10, 1.0f) == 53);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] <double> (20L, 1.0) == 63);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] <long double> (30LL, 1.0L) == 73);
+static_assert (t.template [:members_of (^^S, uctx)[1]:] <float> (10, 1.0f) == 54);
+static_assert (t.template [:members_of (^^S, uctx)[1]:] <double> (20L, 1.0) == 64);
+static_assert (t.template [:members_of (^^S, uctx)[1]:] <long double> (30LL, 1.0L) == 74);
+static_assert (t.template [:members_of (^^S, uctx)[2]:] <float> (10, 1.0f) == 55);
+static_assert (t.template [:members_of (^^S, uctx)[2]:] <double> (20L, 1.0) == 65);
+static_assert (t.template [:members_of (^^S, uctx)[2]:] <long double> (30LL, 1.0L) == 75);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] <float> (10, 1.0f) == 63);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] <double> (20L, 1.0) == 73);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] <long double> (30LL, 1.0L) == 83);
+static_assert (t.template [:members_of (^^T, uctx)[1]:] <float> (10, 1.0f) == 64);
+static_assert (t.template [:members_of (^^T, uctx)[1]:] <double> (20L, 1.0) == 74);
+static_assert (t.template [:members_of (^^T, uctx)[1]:] <long double> (30LL, 1.0L) == 84);
+static_assert (t.template [:members_of (^^T, uctx)[2]:] <float> (10, 1.0f) == 65);
+static_assert (t.template [:members_of (^^T, uctx)[2]:] <double> (20L, 1.0) == 75);
+static_assert (t.template [:members_of (^^T, uctx)[2]:] <long double> (30LL, 1.0L) == 85);
+static_assert (t.bar (0, 1.0f) == 82);
+static_assert (t.bar (0L, 1.0) == 83);
+static_assert (t.bar (0LL, 1.0L) == 84);
+static_assert (t.template [:members_of (^^S, uctx)[3]:] (10, 1.0f) == 82);
+static_assert (t.template [:members_of (^^S, uctx)[3]:] (20L, 1.0) == 92);
+static_assert (t.template [:members_of (^^S, uctx)[3]:] (30LL, 1.0L) == 102);
+static_assert (t.template [:members_of (^^S, uctx)[4]:] (10, 1.0f) == 83);
+static_assert (t.template [:members_of (^^S, uctx)[4]:] (20L, 1.0) == 93);
+static_assert (t.template [:members_of (^^S, uctx)[4]:] (30LL, 1.0L) == 103);
+static_assert (t.template [:members_of (^^S, uctx)[5]:] (10, 1.0f) == 84);
+static_assert (t.template [:members_of (^^S, uctx)[5]:] (20L, 1.0) == 94);
+static_assert (t.template [:members_of (^^S, uctx)[5]:] (30LL, 1.0L) == 104);
+static_assert (t.template [:members_of (^^T, uctx)[3]:] (10, 1.0f) == 92);
+static_assert (t.template [:members_of (^^T, uctx)[3]:] (20L, 1.0) == 102);
+static_assert (t.template [:members_of (^^T, uctx)[3]:] (30LL, 1.0L) == 112);
+static_assert (t.template [:members_of (^^T, uctx)[4]:] (10, 1.0f) == 93);
+static_assert (t.template [:members_of (^^T, uctx)[4]:] (20L, 1.0) == 103);
+static_assert (t.template [:members_of (^^T, uctx)[4]:] (30LL, 1.0L) == 113);
+static_assert (t.template [:members_of (^^T, uctx)[5]:] (10, 1.0f) == 94);
+static_assert (t.template [:members_of (^^T, uctx)[5]:] (20L, 1.0) == 104);
+static_assert (t.template [:members_of (^^T, uctx)[5]:] (30LL, 1.0L) == 114);
+static_assert (t.bar <float> (0, 1.0f) == 82);
+static_assert (t.bar <double> (0L, 1.0) == 83);
+static_assert (t.bar <long double> (0LL, 1.0L) == 84);
+static_assert (t.template [:members_of (^^S, uctx)[3]:] <float> (10, 1.0f) == 82);
+static_assert (t.template [:members_of (^^S, uctx)[3]:] <double> (20L, 1.0) == 92);
+static_assert (t.template [:members_of (^^S, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+static_assert (t.template [:members_of (^^S, uctx)[4]:] <float> (10, 1.0f) == 83);
+static_assert (t.template [:members_of (^^S, uctx)[4]:] <double> (20L, 1.0) == 93);
+static_assert (t.template [:members_of (^^S, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+static_assert (t.template [:members_of (^^S, uctx)[5]:] <float> (10, 1.0f) == 84);
+static_assert (t.template [:members_of (^^S, uctx)[5]:] <double> (20L, 1.0) == 94);
+static_assert (t.template [:members_of (^^S, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+static_assert (t.template [:members_of (^^T, uctx)[3]:] <float> (10, 1.0f) == 92);
+static_assert (t.template [:members_of (^^T, uctx)[3]:] <double> (20L, 1.0) == 102);
+static_assert (t.template [:members_of (^^T, uctx)[3]:] <long double> (30LL, 1.0L) == 112);
+static_assert (t.template [:members_of (^^T, uctx)[4]:] <float> (10, 1.0f) == 93);
+static_assert (t.template [:members_of (^^T, uctx)[4]:] <double> (20L, 1.0) == 103);
+static_assert (t.template [:members_of (^^T, uctx)[4]:] <long double> (30LL, 1.0L) == 113);
+static_assert (t.template [:members_of (^^T, uctx)[5]:] <float> (10, 1.0f) == 94);
+static_assert (t.template [:members_of (^^T, uctx)[5]:] <double> (20L, 1.0) == 104);
+static_assert (t.template [:members_of (^^T, uctx)[5]:] <long double> (30LL, 1.0L) == 114);
+
+template <int N>
+void
+foo ()
+{
+  constexpr S s = 1;
+  static_assert (s.foo (0, 1.0f) == 42);
+  static_assert (s.foo (0L, 1.0) == 43);
+  static_assert (s.foo (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] (30LL, 1.0L) == 74);
+  static_assert (s.foo <float> (0, 1.0f) == 42);
+  static_assert (s.foo <double> (0L, 1.0) == 43);
+  static_assert (s.foo <long double> (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <float> (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <double> (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <long double> (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] <float> (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] <double> (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] <float> (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] <double> (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (s.bar (0, 1.0f) == 72);
+  static_assert (s.bar (0L, 1.0) == 73);
+  static_assert (s.bar (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (s.bar <float> (0, 1.0f) == 72);
+  static_assert (s.bar <double> (0L, 1.0) == 73);
+  static_assert (s.bar <long double> (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  constexpr T t = 2;
+  static_assert (t.foo (0, 1.0f) == 53);
+  static_assert (t.foo (0L, 1.0) == 54);
+  static_assert (t.foo (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] (30LL, 1.0L) == 85);
+  static_assert (t.foo <float> (0, 1.0f) == 53);
+  static_assert (t.foo <double> (0L, 1.0) == 54);
+  static_assert (t.foo <long double> (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <float> (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <double> (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] <float> (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] <double> (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] <float> (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] <double> (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] <long double> (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <float> (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <double> (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <long double> (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] <float> (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] <double> (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] <long double> (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] <float> (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] <double> (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] <long double> (30LL, 1.0L) == 85);
+  static_assert (t.bar (0, 1.0f) == 82);
+  static_assert (t.bar (0L, 1.0) == 83);
+  static_assert (t.bar (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] (30LL, 1.0L) == 114);
+  static_assert (t.bar <float> (0, 1.0f) == 82);
+  static_assert (t.bar <double> (0L, 1.0) == 83);
+  static_assert (t.bar <long double> (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] <float> (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] <double> (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] <long double> (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] <float> (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] <double> (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] <long double> (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] <float> (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] <double> (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] <long double> (30LL, 1.0L) == 114);
+}
+
+template <typename A, typename B>
+void
+bar ()
+{
+  constexpr A s = 1;
+  static_assert (s.foo (0, 1.0f) == 42);
+  static_assert (s.foo (0L, 1.0) == 43);
+  static_assert (s.foo (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] (30LL, 1.0L) == 74);
+  static_assert (s.template foo <float> (0, 1.0f) == 42);
+  static_assert (s.template foo <double> (0L, 1.0) == 43);
+  static_assert (s.template foo <long double> (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <float> (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <double> (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <long double> (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] <float> (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] <double> (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^S, uctx)[1]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] <float> (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] <double> (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^S, uctx)[2]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (s.bar (0, 1.0f) == 72);
+  static_assert (s.bar (0L, 1.0) == 73);
+  static_assert (s.bar (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (s.template bar <float> (0, 1.0f) == 72);
+  static_assert (s.template bar <double> (0L, 1.0) == 73);
+  static_assert (s.template bar <long double> (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^S, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^S, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^S, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  constexpr B t = 2;
+  static_assert (t.foo (0, 1.0f) == 53);
+  static_assert (t.foo (0L, 1.0) == 54);
+  static_assert (t.foo (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] (30LL, 1.0L) == 85);
+  static_assert (t.template foo <float> (0, 1.0f) == 53);
+  static_assert (t.template foo <double> (0L, 1.0) == 54);
+  static_assert (t.template foo <long double> (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <float> (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <double> (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] <float> (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] <double> (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^S, uctx)[1]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] <float> (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] <double> (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^S, uctx)[2]:] <long double> (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <float> (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <double> (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <long double> (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] <float> (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] <double> (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^T, uctx)[1]:] <long double> (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] <float> (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] <double> (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^T, uctx)[2]:] <long double> (30LL, 1.0L) == 85);
+  static_assert (t.bar (0, 1.0f) == 82);
+  static_assert (t.bar (0L, 1.0) == 83);
+  static_assert (t.bar (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] (30LL, 1.0L) == 114);
+  static_assert (t.template bar <float> (0, 1.0f) == 82);
+  static_assert (t.template bar <double> (0L, 1.0) == 83);
+  static_assert (t.template bar <long double> (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^S, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^S, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^S, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] <float> (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] <double> (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^T, uctx)[3]:] <long double> (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] <float> (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] <double> (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^T, uctx)[4]:] <long double> (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] <float> (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] <double> (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^T, uctx)[5]:] <long double> (30LL, 1.0L) == 114);
+}
+
+template <typename A, typename B>
+void
+baz ()
+{
+  constexpr S s = 1;
+  static_assert (s.foo (0, 1.0f) == 42);
+  static_assert (s.foo (0L, 1.0) == 43);
+  static_assert (s.foo (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] (30LL, 1.0L) == 74);
+  static_assert (s.foo <float> (0, 1.0f) == 42);
+  static_assert (s.foo <double> (0L, 1.0) == 43);
+  static_assert (s.foo <long double> (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <float> (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <double> (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <long double> (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] <float> (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] <double> (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] <float> (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] <double> (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (s.bar (0, 1.0f) == 72);
+  static_assert (s.bar (0L, 1.0) == 73);
+  static_assert (s.bar (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (s.bar <float> (0, 1.0f) == 72);
+  static_assert (s.bar <double> (0L, 1.0) == 73);
+  static_assert (s.bar <long double> (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  constexpr T t = 2;
+  static_assert (t.foo (0, 1.0f) == 53);
+  static_assert (t.foo (0L, 1.0) == 54);
+  static_assert (t.foo (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] (30LL, 1.0L) == 85);
+  static_assert (t.foo <float> (0, 1.0f) == 53);
+  static_assert (t.foo <double> (0L, 1.0) == 54);
+  static_assert (t.foo <long double> (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <float> (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <double> (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] <float> (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] <double> (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] <float> (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] <double> (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] <long double> (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <float> (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <double> (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <long double> (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] <float> (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] <double> (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] <long double> (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] <float> (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] <double> (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] <long double> (30LL, 1.0L) == 85);
+  static_assert (t.bar (0, 1.0f) == 82);
+  static_assert (t.bar (0L, 1.0) == 83);
+  static_assert (t.bar (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] (30LL, 1.0L) == 114);
+  static_assert (t.bar <float> (0, 1.0f) == 82);
+  static_assert (t.bar <double> (0L, 1.0) == 83);
+  static_assert (t.bar <long double> (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] <float> (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] <double> (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] <long double> (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] <float> (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] <double> (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] <long double> (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] <float> (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] <double> (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] <long double> (30LL, 1.0L) == 114);
+}
+
+template <typename A, typename B>
+void
+qux ()
+{
+  constexpr A s = 1;
+  static_assert (s.foo (0, 1.0f) == 42);
+  static_assert (s.foo (0L, 1.0) == 43);
+  static_assert (s.foo (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] (30LL, 1.0L) == 74);
+  static_assert (s.template foo <float> (0, 1.0f) == 42);
+  static_assert (s.template foo <double> (0L, 1.0) == 43);
+  static_assert (s.template foo <long double> (0LL, 1.0L) == 44);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <float> (10, 1.0f) == 52);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <double> (20L, 1.0) == 62);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <long double> (30LL, 1.0L) == 72);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] <float> (10, 1.0f) == 53);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] <double> (20L, 1.0) == 63);
+  static_assert (s.template [:members_of (^^A, uctx)[1]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] <float> (10, 1.0f) == 54);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] <double> (20L, 1.0) == 64);
+  static_assert (s.template [:members_of (^^A, uctx)[2]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (s.bar (0, 1.0f) == 72);
+  static_assert (s.bar (0L, 1.0) == 73);
+  static_assert (s.bar (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (s.template bar <float> (0, 1.0f) == 72);
+  static_assert (s.template bar <double> (0L, 1.0) == 73);
+  static_assert (s.template bar <long double> (0LL, 1.0L) == 74);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (s.template [:members_of (^^A, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (s.template [:members_of (^^A, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (s.template [:members_of (^^A, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  constexpr B t = 2;
+  static_assert (t.foo (0, 1.0f) == 53);
+  static_assert (t.foo (0L, 1.0) == 54);
+  static_assert (t.foo (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] (30LL, 1.0L) == 85);
+  static_assert (t.template foo <float> (0, 1.0f) == 53);
+  static_assert (t.template foo <double> (0L, 1.0) == 54);
+  static_assert (t.template foo <long double> (0LL, 1.0L) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <float> (10, 1.0f) == 53);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <double> (20L, 1.0) == 63);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <long double> (30LL, 1.0L) == 73);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] <float> (10, 1.0f) == 54);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] <double> (20L, 1.0) == 64);
+  static_assert (t.template [:members_of (^^A, uctx)[1]:] <long double> (30LL, 1.0L) == 74);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] <float> (10, 1.0f) == 55);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] <double> (20L, 1.0) == 65);
+  static_assert (t.template [:members_of (^^A, uctx)[2]:] <long double> (30LL, 1.0L) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <float> (10, 1.0f) == 63);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <double> (20L, 1.0) == 73);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <long double> (30LL, 1.0L) == 83);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] <float> (10, 1.0f) == 64);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] <double> (20L, 1.0) == 74);
+  static_assert (t.template [:members_of (^^B, uctx)[1]:] <long double> (30LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] <float> (10, 1.0f) == 65);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] <double> (20L, 1.0) == 75);
+  static_assert (t.template [:members_of (^^B, uctx)[2]:] <long double> (30LL, 1.0L) == 85);
+  static_assert (t.bar (0, 1.0f) == 82);
+  static_assert (t.bar (0L, 1.0) == 83);
+  static_assert (t.bar (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] (30LL, 1.0L) == 114);
+  static_assert (t.template bar <float> (0, 1.0f) == 82);
+  static_assert (t.template bar <double> (0L, 1.0) == 83);
+  static_assert (t.template bar <long double> (0LL, 1.0L) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] <float> (10, 1.0f) == 82);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] <double> (20L, 1.0) == 92);
+  static_assert (t.template [:members_of (^^A, uctx)[3]:] <long double> (30LL, 1.0L) == 102);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] <float> (10, 1.0f) == 83);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] <double> (20L, 1.0) == 93);
+  static_assert (t.template [:members_of (^^A, uctx)[4]:] <long double> (30LL, 1.0L) == 103);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] <float> (10, 1.0f) == 84);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] <double> (20L, 1.0) == 94);
+  static_assert (t.template [:members_of (^^A, uctx)[5]:] <long double> (30LL, 1.0L) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] <float> (10, 1.0f) == 92);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] <double> (20L, 1.0) == 102);
+  static_assert (t.template [:members_of (^^B, uctx)[3]:] <long double> (30LL, 1.0L) == 112);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] <float> (10, 1.0f) == 93);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] <double> (20L, 1.0) == 103);
+  static_assert (t.template [:members_of (^^B, uctx)[4]:] <long double> (30LL, 1.0L) == 113);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] <float> (10, 1.0f) == 94);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] <double> (20L, 1.0) == 104);
+  static_assert (t.template [:members_of (^^B, uctx)[5]:] <long double> (30LL, 1.0L) == 114);
+}
+
+void
+fred ()
+{
+  foo <42> ();
+  bar <S, T> ();
+  baz <S, T> ();
+  qux <S, T> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member19.C b/gcc/testsuite/g++.dg/reflect/member19.C
new file mode 100644 (file)
index 0000000..8523ee5
--- /dev/null
@@ -0,0 +1,159 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  template <int N>
+  static constexpr int a = N;
+};
+struct T : public S {
+  template <int N>
+  static constexpr int a = N + 100;
+};
+
+constexpr access_context uctx = access_context::unchecked ();
+
+constexpr S s;
+static_assert (s.a <42> == 42);
+static_assert (s.a <43> == 43);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] <44> == 44);
+static_assert (s.template [:members_of (^^S, uctx)[0]:] <45> == 45);
+static_assert (s.template [:^^S::a:] <44> == 44);
+static_assert (s.template [:^^S::a:] <45> == 45);
+constexpr T t;
+static_assert (t.a <42> == 142);
+static_assert (t.a <43> == 143);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] <44> == 44);
+static_assert (t.template [:members_of (^^S, uctx)[0]:] <45> == 45);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] <44> == 144);
+static_assert (t.template [:members_of (^^T, uctx)[0]:] <45> == 145);
+static_assert (t.template [:^^S::a:] <44> == 44);
+static_assert (t.template [:^^S::a:] <45> == 45);
+static_assert (t.template [:^^T::a:] <44> == 144);
+static_assert (t.template [:^^T::a:] <45> == 145);
+
+template <int N>
+void
+foo ()
+{
+  constexpr S s;
+  static_assert (s.a <42> == 42);
+  static_assert (s.a <43> == 43);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <44> == 44);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <45> == 45);
+  static_assert (s.template [:^^S::a:] <44> == 44);
+  static_assert (s.template [:^^S::a:] <45> == 45);
+  constexpr T t;
+  static_assert (t.a <42> == 142);
+  static_assert (t.a <43> == 143);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <44> == 44);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <45> == 45);
+  static_assert (t.template [:^^S::a:] <44> == 44);
+  static_assert (t.template [:^^S::a:] <45> == 45);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <44> == 144);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <45> == 145);
+  static_assert (t.template [:^^T::a:] <44> == 144);
+  static_assert (t.template [:^^T::a:] <45> == 145);
+}
+
+template <typename A, typename B>
+void
+bar ()
+{
+  constexpr A s;
+  static_assert (s.template a <42> == 42);
+  static_assert (s.template a <43> == 43);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <44> == 44);
+  static_assert (s.template [:members_of (^^S, uctx)[0]:] <45> == 45);
+  static_assert (s.template [:^^S::a:] <44> == 44);
+  static_assert (s.template [:^^S::a:] <45> == 45);
+  constexpr B t;
+  static_assert (t.template a <42> == 142);
+  static_assert (t.template a <43> == 143);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <44> == 44);
+  static_assert (t.template [:members_of (^^S, uctx)[0]:] <45> == 45);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <44> == 144);
+  static_assert (t.template [:members_of (^^T, uctx)[0]:] <45> == 145);
+  static_assert (t.template [:^^S::a:] <44> == 44);
+  static_assert (t.template [:^^S::a:] <45> == 45);
+  static_assert (t.template [:^^T::a:] <44> == 144);
+  static_assert (t.template [:^^T::a:] <45> == 145);
+}
+
+template <typename A, typename B>
+void
+baz ()
+{
+  constexpr S s;
+  static_assert (s.a <42> == 42);
+  static_assert (s.a <43> == 43);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <44> == 44);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <45> == 45);
+#if 0
+  // TODO: This doesn't work yet.
+  static_assert (s.template [:^^A::a:] <44> == 44);
+  static_assert (s.template [:^^A::a:] <45> == 45);
+#endif
+  constexpr T t;
+  static_assert (t.a <42> == 142);
+  static_assert (t.a <43> == 143);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <44> == 44);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <45> == 45);
+#if 0
+  // TODO: This doesn't work yet.
+  static_assert (t.template [:^^A::a:] <44> == 44);
+  static_assert (t.template [:^^A::a:] <45> == 45);
+#endif
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <44> == 144);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <45> == 145);
+#if 0
+  // TODO: This doesn't work yet.
+  static_assert (t.template [:^^B::a:] <44> == 144);
+  static_assert (t.template [:^^B::a:] <45> == 145);
+#endif
+}
+
+template <typename A, typename B>
+void
+qux ()
+{
+  constexpr A s;
+  static_assert (s.template a <42> == 42);
+  static_assert (s.template a <43> == 43);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <44> == 44);
+  static_assert (s.template [:members_of (^^A, uctx)[0]:] <45> == 45);
+#if 0
+  // TODO: This doesn't work yet.
+  static_assert (s.template [:^^A::a:] <44> == 44);
+  static_assert (s.template [:^^A::a:] <45> == 45);
+#endif
+  constexpr B t;
+  static_assert (t.template a <42> == 142);
+  static_assert (t.template a <43> == 143);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <44> == 44);
+  static_assert (t.template [:members_of (^^A, uctx)[0]:] <45> == 45);
+#if 0
+  // TODO: This doesn't work yet.
+  static_assert (t.template [:^^A::a:] <44> == 44);
+  static_assert (t.template [:^^A::a:] <45> == 45);
+#endif
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <44> == 144);
+  static_assert (t.template [:members_of (^^B, uctx)[0]:] <45> == 145);
+#if 0
+  // TODO: This doesn't work yet.
+  static_assert (t.template [:^^B::a:] <44> == 144);
+  static_assert (t.template [:^^B::a:] <45> == 145);
+#endif
+}
+
+void
+fred ()
+{
+  foo <42> ();
+  bar <S, T> ();
+  baz <S, T> ();
+  qux <S, T> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member2.C b/gcc/testsuite/g++.dg/reflect/member2.C
new file mode 100644 (file)
index 0000000..adf7928
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct B { consteval char fn() const { return 'B'; } };
+struct D : B { consteval char fn() const { return 'D'; } };
+
+constexpr auto rBfn = ^^B::fn;
+constexpr auto rDfn = ^^D::fn;
+
+constexpr D d;
+constexpr auto rd = ^^d;
+
+static_assert([:rd:].[:rBfn:]() == 'B');
+static_assert([:rd:].[:rDfn:]() == 'D');
diff --git a/gcc/testsuite/g++.dg/reflect/member20.C b/gcc/testsuite/g++.dg/reflect/member20.C
new file mode 100644 (file)
index 0000000..1aa4b12
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template<decltype (^^::) R>
+void
+bar ()
+{
+  constexpr auto t = [: R :]; // { dg-error "use of local variable" }
+}
+
+void
+g (int p)
+{
+  int x = 42;
+  bar<^^p> ();
+  constexpr auto r = ^^x;
+  struct S {
+    void foo () {
+      [: ^^x :];    // { dg-error "use of local variable" }
+      [: r :];     // { dg-error "use of local variable" }
+      decltype ([: ^^x :]) a{};
+      decltype ([: r :]) b{};
+      constexpr auto rx = ^^x;
+    }
+  };
+}
diff --git a/gcc/testsuite/g++.dg/reflect/member3.C b/gcc/testsuite/g++.dg/reflect/member3.C
new file mode 100644 (file)
index 0000000..a9e698d
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test various forms of member access with this.
+
+struct S {
+  int i;
+  static constexpr int j = 42;
+  int foo () { return 42; }
+
+  void
+  f ()
+  {
+    static_assert([: ^^ j :] == 42);
+    static_assert([: ^^S :]::j == 42);
+    int q = this->[: ^^i :];
+    q += this->[: ^^S :]::i;
+    this->[: ^^foo :] ();
+    this->[: ^^S :]::foo ();
+  }
+};
+
+struct D {
+  int i;
+  static constexpr int j = 42;
+  int foo () { return 42; }
+
+  template<typename T>
+  void
+  f ()
+  {
+    static_assert([: ^^T :]::j == 42);
+    int q = this->[: ^^T :]::j;
+    this->[: ^^T :]::foo ();
+  }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/member4.C b/gcc/testsuite/g++.dg/reflect/member4.C
new file mode 100644 (file)
index 0000000..35c3ff4
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct C {
+  union {
+    int i;
+  };
+};
+
+struct D { int i; };
+
+auto c = C{.i=2};
+auto v = c.[:^^C::i:];    // { dg-error "not a base" }
+auto e = c.[: ^^D::i :];  // { dg-error "not a base" }
diff --git a/gcc/testsuite/g++.dg/reflect/member5.C b/gcc/testsuite/g++.dg/reflect/member5.C
new file mode 100644 (file)
index 0000000..9a53086
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A { };
+
+struct S {
+  int m(this S) { return 42; }
+  int n() const { return 42; }
+  enum { FOO } e;
+  A a;
+};
+
+auto p = &[: ^^S::m :];
+auto q = &[: ^^S::m :];
+
+auto rm = [: ^^S::m :];         // { dg-error "cannot implicitly reference a class member .int S::m\\(this S\\). through a splice" }
+auto rn = [: ^^S::n :];  // { dg-error "cannot implicitly reference a class member .int S::n\\(\\) const. through a splice" }
+auto re = [: ^^S::e :];  // { dg-error "cannot implicitly reference a class member .S::e. through a splice" }
+auto ra = [: ^^S::a :];  // { dg-error "cannot implicitly reference a class member .S::a. through a splice" }
diff --git a/gcc/testsuite/g++.dg/reflect/member6.C b/gcc/testsuite/g++.dg/reflect/member6.C
new file mode 100644 (file)
index 0000000..5d425ae
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  int i;
+};
+
+constexpr auto r = ^^S::i;
+/* A pointer to member is only formed when an explicit & is used and
+   its operand is a qualified-id or splice-expression not enclosed in
+   parentheses.  */
+auto p = &([: r :]);  // { dg-error "cannot implicitly reference a class member .S::i. through a splice" }
+auto q = &[: r :];
diff --git a/gcc/testsuite/g++.dg/reflect/member7.C b/gcc/testsuite/g++.dg/reflect/member7.C
new file mode 100644 (file)
index 0000000..3fc41bb
--- /dev/null
@@ -0,0 +1,78 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// From clang/test/Reflection/splice-exprs.cpp.
+
+using info = decltype(^^int);
+
+struct S {
+  int j;
+  int k;
+
+  consteval int getJ() const { return j; }
+
+  template <int N>
+  consteval int getJPlusN() const { return j + N; }
+
+  static consteval int eleven() { return 11; }
+
+  template <int N>
+  static consteval int constant() { return N; }
+};
+
+// Splicing dependent member references.
+template <info RMem>
+consteval int fn() {
+  S s = {11, 13};
+  return s.[:RMem:] + (&s)->[:RMem:];
+}
+static_assert(fn<^^S::j>() == 22);
+static_assert(fn<^^S::k>() == 26);
+
+// Splicing dependent member references with arrow syntax.
+template <info RMem>
+consteval int fn2() {
+  S s = {11, 13};
+  return s.*(&[:RMem:]) + (&s)->*(&[:RMem:]);
+}
+static_assert(fn<^^S::j>() == 22);
+static_assert(fn<^^S::k>() == 26);
+
+// Splicing member functions.
+constexpr info r_getJ = ^^S::getJ;
+static_assert(S{2, 4}.[:r_getJ:]() == 2);
+
+// Splicing static member functions.
+constexpr auto rEleven = ^^S::eleven;
+static_assert([:rEleven:]() == 11);
+
+// Splicing static member template function instantiation.
+constexpr auto rConst14 = ^^S::constant<14>;
+static_assert([:rConst14:]() == 14);
+
+// Splicing member function template instantiations.
+constexpr auto rgetJPlus5 = ^^S::getJPlusN<5>;
+static_assert(S{2, 4}.[:rgetJPlus5:]() == 7);
+
+// Splicing member function template instantiations with spliced objects.
+constexpr S instance {1, 4};
+constexpr info rInstance = ^^instance;
+static_assert([:rInstance:].[:rgetJPlus5:]() == 6);
+static_assert((&[:rInstance:])->[:rgetJPlus5:]() == 6);
+
+// Splicing dependent object in a member access expression.
+template <info RObj>
+consteval int fn3() {
+  return [:RObj:].k;
+}
+static_assert(fn3<^^instance>() == 4);
+
+// Passing address of a spliced operand as an argument.
+consteval int getMem(const S *s, int S::* mem) {
+  return s->*mem;
+}
+constexpr info rJ = ^^S::j;
+static_assert(getMem(&instance, &[:rJ:]) == 1);
+
+// Member access through a splice of a private member.
+class WithPrivateBase : S {} d;
+int dK = d.[:^^S::k:];
diff --git a/gcc/testsuite/g++.dg/reflect/member8.C b/gcc/testsuite/g++.dg/reflect/member8.C
new file mode 100644 (file)
index 0000000..4f96b55
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  int k;
+};
+
+struct Y {
+  int k;
+};
+struct X : S { };
+
+class D : S , X {} d;  // { dg-warning "direct base .S. inaccessible in .D. due to ambiguity" }
+int dK = d.[:^^S::k:]; // { dg-error ".S. is an ambiguous base of .D." }
+int dY = d.[:^^Y::k:]; // { dg-error ".Y. is not a base of .D." }
diff --git a/gcc/testsuite/g++.dg/reflect/member9.C b/gcc/testsuite/g++.dg/reflect/member9.C
new file mode 100644 (file)
index 0000000..5a6d983
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct B { consteval virtual int fn() const { return 1; } };
+struct D : B { consteval int fn() const override { return 2; } };
+
+constexpr D d;
+static_assert(d.[:^^D::fn:]() == 2);
+static_assert(d.D::fn() == 2);
+static_assert(d.[:^^B::fn:]() == 2);
+static_assert(d.[:^^B:]::fn() == 1);
+static_assert(d.B::fn() == 1);
+
+// Splicing member as intermediate component of a member-access expression.
+struct T { struct Inner { int v; } inner; };
+constexpr auto r_inner = ^^T::inner;
+constexpr T t = {{4}};
+static_assert(t.[:r_inner:].v == 4);
diff --git a/gcc/testsuite/g++.dg/reflect/members_of1.C b/gcc/testsuite/g++.dg/reflect/members_of1.C
new file mode 100644 (file)
index 0000000..2d52da0
--- /dev/null
@@ -0,0 +1,524 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::{,{,non}static_data_}members_of and
+// has_inaccessible_nonstatic_data_members.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+using std::views::filter;
+using std::ranges::to;
+using std::vector;
+using std::string_view;
+
+consteval bool
+check_special_members (const vector <info> &vec, int cnt, bool dct, bool cct, bool cas, bool mct, bool mas, bool dt)
+{
+  if ((vec | filter (is_special_member_function) | filter (is_defaulted) | to <vector> ()).size () != cnt)
+    throw 1;
+  if ((vec | filter (is_default_constructor) | to <vector> ()).size () != dct)
+    throw 2;
+  if ((vec | filter (is_copy_constructor) | to <vector> ()).size () != cct)
+    throw 3;
+  if ((vec | filter (is_copy_assignment) | to <vector> ()).size () != cas)
+    throw 4;
+  if ((vec | filter (is_move_constructor) | to <vector> ()).size () != mct)
+    throw 5;
+  if ((vec | filter (is_move_assignment) | to <vector> ()).size () != mas)
+    throw 6;
+  if ((vec | filter (is_destructor) | to <vector> ()).size () != dt)
+    throw 7;
+  return true;
+}
+
+namespace N1 {
+  struct A {
+    int a;
+    static int b;
+    enum E { E0 };
+    using c = int;
+    typedef long d;
+    consteval {
+    }
+  };
+  int A::b = 24;
+  consteval {
+  }
+}
+namespace N2 {
+  struct B {};
+  struct C { int : 5; };
+  struct D { D (int = 42); int d; };
+  struct E { E (int); int e; };
+  struct F { int f; F (const F &); };
+  struct G { G &operator = (const G &); int g; };
+  struct H { int h; H (H &&); };
+  struct I { I &operator = (I &&); int i; };
+  struct J { ~J (); };
+  struct K {
+    int a;
+    static int b;
+    enum E { E0 };
+    using c = int;
+    typedef long d;
+    template <typename T>
+    struct A {};
+    template <typename T>
+    static consteval bool foo (const T &) { return true; }
+    template <int N>
+    static constexpr int e = N;
+    template <typename T>
+    using f = const T &;
+    void bar () {}
+    auto baz ();
+    int g : 3;
+    long : 2;
+    int : 0;
+    consteval {
+      A <int> z = {};
+      static_assert (e <42> == 42);
+      f <int> w = 42;
+    }
+  protected:
+    int Xa;
+    static int Xb;
+    enum XE { XE0 };
+    using Xc = int;
+    typedef long Xd;
+    template <typename T>
+    struct XA {};
+    template <typename T>
+    static consteval bool Xfoo (const T &) { return true; }
+    template <int N>
+    static constexpr int Xe = N;
+    template <typename T>
+    using Xf = const T &;
+    void Xbar () {}
+    auto Xbaz ();
+    int Xg : 5;
+    long : 4;
+    int : 0;
+  private:
+    int Ya;
+    static int Yb;
+    enum YE { YE0 };
+    using Yc = int;
+    typedef long Yd;
+    template <typename T>
+    struct YA {};
+    template <typename T>
+    static consteval bool Yfoo (const T &) { return true; }
+    template <int N>
+    static constexpr int Ye = N;
+    template <typename T>
+    using Yf = const T &;
+    void Ybar () {}
+    auto Ybaz ();
+    int Yg : 7;
+    long : 6;
+    int : 0;
+  public:
+    static constexpr info rXa = ^^Xa;
+    static constexpr info rXb = ^^Xb;
+    static constexpr info rXE = ^^XE;
+    static constexpr info rXg = ^^Xg;
+    static constexpr info rYa = ^^Ya;
+    static constexpr info rYb = ^^Yb;
+    static constexpr info rYE = ^^YE;
+    static constexpr info rYg = ^^Yg;
+  };
+  namespace W {}
+  namespace X = W;
+  namespace W {}
+  namespace W {}
+  inline namespace Y { int a; }
+  template <typename T>
+  concept Z = requires { true; };
+}
+static_assert (N2::K::foo (42) && N2::K::foo (42UL));
+
+constexpr access_context gctx = access_context::current ();
+constexpr access_context uctx = access_context::unchecked ();
+
+static_assert (members_of (^^N1::A, gctx).size () == 11);
+static_assert (members_of (^^N1::A, gctx)[0] == ^^N1::A::a);
+static_assert (members_of (^^N1::A, gctx)[1] == ^^N1::A::b);
+static_assert (members_of (^^N1::A, gctx)[2] == ^^N1::A::E);
+static_assert (members_of (^^N1::A, gctx)[3] == ^^N1::A::c);
+static_assert (members_of (^^N1::A, gctx)[4] == ^^N1::A::d);
+static_assert (check_special_members (members_of (^^N1::A, gctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N1::A, gctx).size () == 1);
+static_assert (static_data_members_of (^^N1::A, gctx)[0] == ^^N1::A::b);
+static_assert (nonstatic_data_members_of (^^N1::A, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N1::A, gctx)[0] == ^^N1::A::a);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N1::A, gctx));
+
+static_assert (members_of (^^N1, gctx).size () == 1);
+static_assert (members_of (^^N1, gctx)[0] == ^^N1::A);
+
+static_assert (members_of (^^N2::B, gctx).size () == 6);
+static_assert (check_special_members (members_of (^^N2::B, gctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::B, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::B, gctx).size () == 0);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::B, gctx));
+
+static_assert (members_of (^^N2::C, gctx).size () == 7);
+static_assert (is_bit_field (members_of (^^N2::C, gctx)[0]));
+static_assert (!has_identifier (members_of (^^N2::C, gctx)[0]));
+static_assert (bit_size_of (members_of (^^N2::C, gctx)[0]) == 5);
+static_assert (type_of (members_of (^^N2::C, gctx)[0]) == ^^int);
+static_assert (check_special_members (members_of (^^N2::C, gctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::C, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::C, gctx).size () == 0);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::C, gctx));
+
+static_assert (members_of (^^N2::D, gctx).size () == 7);
+static_assert (is_default_constructor (members_of (^^N2::D, gctx)[0]));
+static_assert (members_of (^^N2::D, gctx)[1] == ^^N2::D::d);
+static_assert (check_special_members (members_of (^^N2::D, gctx), 5, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::D, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::D, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N2::D, gctx)[0] == ^^N2::D::d);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::D, gctx));
+
+static_assert (members_of (^^N2::E, gctx).size () == 7);
+static_assert (is_constructor (members_of (^^N2::E, gctx)[0]));
+static_assert (members_of (^^N2::E, gctx)[1] == ^^N2::E::e);
+static_assert (check_special_members (members_of (^^N2::E, gctx), 5, false, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::E, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::E, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N2::E, gctx)[0] == ^^N2::E::e);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::E, gctx));
+
+static_assert (members_of (^^N2::F, gctx).size () == 4);
+static_assert (members_of (^^N2::F, gctx)[0] == ^^N2::F::f);
+static_assert (is_copy_constructor (members_of (^^N2::F, gctx)[1]));
+static_assert (check_special_members (members_of (^^N2::F, gctx), 2, false, true, true, false, false, true));
+static_assert (static_data_members_of (^^N2::F, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::F, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N2::F, gctx)[0] == ^^N2::F::f);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::F, gctx));
+
+static_assert (members_of (^^N2::G, gctx).size () == 5);
+static_assert (is_copy_assignment (members_of (^^N2::G, gctx)[0]));
+static_assert (members_of (^^N2::G, gctx)[1] == ^^N2::G::g);
+static_assert (check_special_members (members_of (^^N2::G, gctx), 3, true, true, true, false, false, true));
+static_assert (static_data_members_of (^^N2::G, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::G, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N2::G, gctx)[0] == ^^N2::G::g);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::G, gctx));
+
+static_assert (members_of (^^N2::H, gctx).size () == 5);
+static_assert (members_of (^^N2::H, gctx)[0] == ^^N2::H::h);
+static_assert (is_move_constructor (members_of (^^N2::H, gctx)[1]));
+static_assert (check_special_members (members_of (^^N2::H, gctx), 3, false, true, true, true, false, true));
+static_assert (static_data_members_of (^^N2::H, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::H, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N2::H, gctx)[0] == ^^N2::H::h);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::H, gctx));
+
+static_assert (members_of (^^N2::I, gctx).size () == 6);
+static_assert (is_move_assignment (members_of (^^N2::I, gctx)[0]));
+static_assert (members_of (^^N2::I, gctx)[1] == ^^N2::I::i);
+static_assert (check_special_members (members_of (^^N2::I, gctx), 4, true, true, true, false, true, true));
+static_assert (static_data_members_of (^^N2::I, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::I, gctx).size () == 1);
+static_assert (nonstatic_data_members_of (^^N2::I, gctx)[0] == ^^N2::I::i);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::I, gctx));
+
+static_assert (members_of (^^N2::J, gctx).size () == 4);
+static_assert (is_destructor (members_of (^^N2::J, gctx)[0]));
+static_assert (check_special_members (members_of (^^N2::J, gctx), 3, true, true, true, false, false, true));
+static_assert (static_data_members_of (^^N2::J, gctx).size () == 0);
+static_assert (nonstatic_data_members_of (^^N2::J, gctx).size () == 0);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::J, gctx));
+
+static_assert (members_of (^^N2::K, gctx).size () == 27);
+static_assert (members_of (^^N2::K, gctx)[0] == ^^N2::K::a);
+static_assert (members_of (^^N2::K, gctx)[1] == ^^N2::K::b);
+static_assert (members_of (^^N2::K, gctx)[2] == ^^N2::K::E);
+static_assert (members_of (^^N2::K, gctx)[3] == ^^N2::K::c);
+static_assert (members_of (^^N2::K, gctx)[4] == ^^N2::K::d);
+static_assert (members_of (^^N2::K, gctx)[5] == ^^N2::K::A);
+static_assert (members_of (^^N2::K, gctx)[6] == ^^N2::K::foo);
+static_assert (members_of (^^N2::K, gctx)[7] == ^^N2::K::e);
+static_assert (members_of (^^N2::K, gctx)[8] == ^^N2::K::f);
+static_assert (members_of (^^N2::K, gctx)[9] == ^^N2::K::bar);
+static_assert (members_of (^^N2::K, gctx)[10] == ^^N2::K::g);
+static_assert (is_bit_field (members_of (^^N2::K, gctx)[11]));
+static_assert (!has_identifier (members_of (^^N2::K, gctx)[11]));
+static_assert (bit_size_of (members_of (^^N2::K, gctx)[11]) == 2);
+static_assert (type_of (members_of (^^N2::K, gctx)[11]) == ^^long);
+static_assert (is_bit_field (members_of (^^N2::K, gctx)[12]));
+static_assert (!has_identifier (members_of (^^N2::K, gctx)[12]));
+static_assert (bit_size_of (members_of (^^N2::K, gctx)[12]) == 0);
+static_assert (type_of (members_of (^^N2::K, gctx)[12]) == ^^int);
+static_assert (members_of (^^N2::K, gctx)[13] == ^^N2::K::rXa);
+static_assert (members_of (^^N2::K, gctx)[14] == ^^N2::K::rXb);
+static_assert (members_of (^^N2::K, gctx)[15] == ^^N2::K::rXE);
+static_assert (members_of (^^N2::K, gctx)[16] == ^^N2::K::rXg);
+static_assert (members_of (^^N2::K, gctx)[17] == ^^N2::K::rYa);
+static_assert (members_of (^^N2::K, gctx)[18] == ^^N2::K::rYb);
+static_assert (members_of (^^N2::K, gctx)[19] == ^^N2::K::rYE);
+static_assert (members_of (^^N2::K, gctx)[20] == ^^N2::K::rYg);
+static_assert (check_special_members (members_of (^^N2::K, gctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::K, gctx).size () == 9);
+static_assert (static_data_members_of (^^N2::K, gctx)[0] == ^^N2::K::b);
+static_assert (static_data_members_of (^^N2::K, gctx)[1] == ^^N2::K::rXa);
+static_assert (static_data_members_of (^^N2::K, gctx)[2] == ^^N2::K::rXb);
+static_assert (static_data_members_of (^^N2::K, gctx)[3] == ^^N2::K::rXE);
+static_assert (static_data_members_of (^^N2::K, gctx)[4] == ^^N2::K::rXg);
+static_assert (static_data_members_of (^^N2::K, gctx)[5] == ^^N2::K::rYa);
+static_assert (static_data_members_of (^^N2::K, gctx)[6] == ^^N2::K::rYb);
+static_assert (static_data_members_of (^^N2::K, gctx)[7] == ^^N2::K::rYE);
+static_assert (static_data_members_of (^^N2::K, gctx)[8] == ^^N2::K::rYg);
+static_assert (nonstatic_data_members_of (^^N2::K, gctx).size () == 2);
+static_assert (nonstatic_data_members_of (^^N2::K, gctx)[0] == ^^N2::K::a);
+static_assert (nonstatic_data_members_of (^^N2::K, gctx)[1] == ^^N2::K::g);
+static_assert (has_inaccessible_nonstatic_data_members (^^N2::K, gctx));
+static_assert (members_of (^^N2::K, uctx).size () == 53);
+static_assert (members_of (^^N2::K, uctx)[0] == ^^N2::K::a);
+static_assert (members_of (^^N2::K, uctx)[1] == ^^N2::K::b);
+static_assert (members_of (^^N2::K, uctx)[2] == ^^N2::K::E);
+static_assert (members_of (^^N2::K, uctx)[3] == ^^N2::K::c);
+static_assert (members_of (^^N2::K, uctx)[4] == ^^N2::K::d);
+static_assert (members_of (^^N2::K, uctx)[5] == ^^N2::K::A);
+static_assert (members_of (^^N2::K, uctx)[6] == ^^N2::K::foo);
+static_assert (members_of (^^N2::K, uctx)[7] == ^^N2::K::e);
+static_assert (members_of (^^N2::K, uctx)[8] == ^^N2::K::f);
+static_assert (members_of (^^N2::K, uctx)[9] == ^^N2::K::bar);
+static_assert (members_of (^^N2::K, uctx)[10] == ^^N2::K::g);
+static_assert (is_bit_field (members_of (^^N2::K, uctx)[11]));
+static_assert (!has_identifier (members_of (^^N2::K, uctx)[11]));
+static_assert (bit_size_of (members_of (^^N2::K, uctx)[11]) == 2);
+static_assert (type_of (members_of (^^N2::K, uctx)[11]) == ^^long);
+static_assert (is_bit_field (members_of (^^N2::K, uctx)[12]));
+static_assert (!has_identifier (members_of (^^N2::K, uctx)[12]));
+static_assert (bit_size_of (members_of (^^N2::K, uctx)[12]) == 0);
+static_assert (type_of (members_of (^^N2::K, uctx)[12]) == ^^int);
+static_assert (members_of (^^N2::K, uctx)[13] == N2::K::rXa);
+static_assert (members_of (^^N2::K, uctx)[14] == N2::K::rXb);
+static_assert (members_of (^^N2::K, uctx)[15] == N2::K::rXE);
+static_assert (identifier_of (members_of (^^N2::K, uctx)[16]) == string_view ("Xc"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[17]) == string_view ("Xd"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[18]) == string_view ("XA"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[19]) == string_view ("Xfoo"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[20]) == string_view ("Xe"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[21]) == string_view ("Xf"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[22]) == string_view ("Xbar"));
+static_assert (members_of (^^N2::K, uctx)[23] == N2::K::rXg);
+static_assert (is_bit_field (members_of (^^N2::K, uctx)[24]));
+static_assert (!has_identifier (members_of (^^N2::K, uctx)[24]));
+static_assert (bit_size_of (members_of (^^N2::K, uctx)[24]) == 4);
+static_assert (type_of (members_of (^^N2::K, uctx)[24]) == ^^long);
+static_assert (is_bit_field (members_of (^^N2::K, uctx)[25]));
+static_assert (!has_identifier (members_of (^^N2::K, uctx)[25]));
+static_assert (bit_size_of (members_of (^^N2::K, uctx)[25]) == 0);
+static_assert (type_of (members_of (^^N2::K, uctx)[25]) == ^^int);
+static_assert (members_of (^^N2::K, uctx)[26] == N2::K::rYa);
+static_assert (members_of (^^N2::K, uctx)[27] == N2::K::rYb);
+static_assert (members_of (^^N2::K, uctx)[28] == N2::K::rYE);
+static_assert (identifier_of (members_of (^^N2::K, uctx)[29]) == string_view ("Yc"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[30]) == string_view ("Yd"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[31]) == string_view ("YA"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[32]) == string_view ("Yfoo"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[33]) == string_view ("Ye"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[34]) == string_view ("Yf"));
+static_assert (identifier_of (members_of (^^N2::K, uctx)[35]) == string_view ("Ybar"));
+static_assert (members_of (^^N2::K, uctx)[36] == N2::K::rYg);
+static_assert (is_bit_field (members_of (^^N2::K, uctx)[37]));
+static_assert (!has_identifier (members_of (^^N2::K, uctx)[37]));
+static_assert (bit_size_of (members_of (^^N2::K, uctx)[37]) == 6);
+static_assert (type_of (members_of (^^N2::K, uctx)[37]) == ^^long);
+static_assert (is_bit_field (members_of (^^N2::K, uctx)[38]));
+static_assert (!has_identifier (members_of (^^N2::K, uctx)[38]));
+static_assert (bit_size_of (members_of (^^N2::K, uctx)[38]) == 0);
+static_assert (type_of (members_of (^^N2::K, uctx)[38]) == ^^int);
+static_assert (members_of (^^N2::K, uctx)[39] == ^^N2::K::rXa);
+static_assert (members_of (^^N2::K, uctx)[40] == ^^N2::K::rXb);
+static_assert (members_of (^^N2::K, uctx)[41] == ^^N2::K::rXE);
+static_assert (members_of (^^N2::K, uctx)[42] == ^^N2::K::rXg);
+static_assert (members_of (^^N2::K, uctx)[43] == ^^N2::K::rYa);
+static_assert (members_of (^^N2::K, uctx)[44] == ^^N2::K::rYb);
+static_assert (members_of (^^N2::K, uctx)[45] == ^^N2::K::rYE);
+static_assert (members_of (^^N2::K, uctx)[46] == ^^N2::K::rYg);
+static_assert (check_special_members (members_of (^^N2::K, uctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::K, uctx).size () == 11);
+static_assert (static_data_members_of (^^N2::K, uctx)[0] == ^^N2::K::b);
+static_assert (static_data_members_of (^^N2::K, uctx)[1] == N2::K::rXb);
+static_assert (static_data_members_of (^^N2::K, uctx)[2] == N2::K::rYb);
+static_assert (static_data_members_of (^^N2::K, uctx)[3] == ^^N2::K::rXa);
+static_assert (static_data_members_of (^^N2::K, uctx)[4] == ^^N2::K::rXb);
+static_assert (static_data_members_of (^^N2::K, uctx)[5] == ^^N2::K::rXE);
+static_assert (static_data_members_of (^^N2::K, uctx)[6] == ^^N2::K::rXg);
+static_assert (static_data_members_of (^^N2::K, uctx)[7] == ^^N2::K::rYa);
+static_assert (static_data_members_of (^^N2::K, uctx)[8] == ^^N2::K::rYb);
+static_assert (static_data_members_of (^^N2::K, uctx)[9] == ^^N2::K::rYE);
+static_assert (static_data_members_of (^^N2::K, uctx)[10] == ^^N2::K::rYg);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx).size () == 6);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx)[0] == ^^N2::K::a);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx)[1] == ^^N2::K::g);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx)[2] == N2::K::rXa);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx)[3] == N2::K::rXg);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx)[4] == N2::K::rYa);
+static_assert (nonstatic_data_members_of (^^N2::K, uctx)[5] == N2::K::rYg);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::K, uctx));
+
+static_assert (members_of (^^N2, gctx).size () == 14);
+static_assert ((members_of (^^N2, gctx) | filter (is_type) | filter (is_class_type) | to <vector> ()).size () == 10);
+static_assert ((members_of (^^N2, gctx) | filter (is_namespace) | to <vector> ()).size () == 3);
+static_assert ((members_of (^^N2, gctx) | filter (is_namespace_alias) | to <vector> ()).size () == 1);
+static_assert ((members_of (^^N2, gctx) | filter (is_concept) | to <vector> ()).size () == 1);
+
+namespace N2 {
+  struct L : public K {
+    static constexpr auto ctx = access_context::current ();
+  };
+  static constexpr auto ctx = L::ctx.via (^^L);
+}
+
+static_assert (members_of (^^N2::K, N2::ctx).size () == 40);
+static_assert (members_of (^^N2::K, N2::ctx)[0] == ^^N2::K::a);
+static_assert (members_of (^^N2::K, N2::ctx)[1] == ^^N2::K::b);
+static_assert (members_of (^^N2::K, N2::ctx)[2] == ^^N2::K::E);
+static_assert (members_of (^^N2::K, N2::ctx)[3] == ^^N2::K::c);
+static_assert (members_of (^^N2::K, N2::ctx)[4] == ^^N2::K::d);
+static_assert (members_of (^^N2::K, N2::ctx)[5] == ^^N2::K::A);
+static_assert (members_of (^^N2::K, N2::ctx)[6] == ^^N2::K::foo);
+static_assert (members_of (^^N2::K, N2::ctx)[7] == ^^N2::K::e);
+static_assert (members_of (^^N2::K, N2::ctx)[8] == ^^N2::K::f);
+static_assert (members_of (^^N2::K, N2::ctx)[9] == ^^N2::K::bar);
+static_assert (members_of (^^N2::K, N2::ctx)[10] == ^^N2::K::g);
+static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[11]));
+static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[11]));
+static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[11]) == 2);
+static_assert (type_of (members_of (^^N2::K, N2::ctx)[11]) == ^^long);
+static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[12]));
+static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[12]));
+static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[12]) == 0);
+static_assert (type_of (members_of (^^N2::K, N2::ctx)[12]) == ^^int);
+static_assert (members_of (^^N2::K, N2::ctx)[13] == N2::K::rXa);
+static_assert (members_of (^^N2::K, N2::ctx)[14] == N2::K::rXb);
+static_assert (members_of (^^N2::K, N2::ctx)[15] == N2::K::rXE);
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[16]) == string_view ("Xc"));
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[17]) == string_view ("Xd"));
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[18]) == string_view ("XA"));
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[19]) == string_view ("Xfoo"));
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[20]) == string_view ("Xe"));
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[21]) == string_view ("Xf"));
+static_assert (identifier_of (members_of (^^N2::K, N2::ctx)[22]) == string_view ("Xbar"));
+static_assert (members_of (^^N2::K, N2::ctx)[23] == N2::K::rXg);
+static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[24]));
+static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[24]));
+static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[24]) == 4);
+static_assert (type_of (members_of (^^N2::K, N2::ctx)[24]) == ^^long);
+static_assert (is_bit_field (members_of (^^N2::K, N2::ctx)[25]));
+static_assert (!has_identifier (members_of (^^N2::K, N2::ctx)[25]));
+static_assert (bit_size_of (members_of (^^N2::K, N2::ctx)[25]) == 0);
+static_assert (type_of (members_of (^^N2::K, N2::ctx)[25]) == ^^int);
+static_assert (members_of (^^N2::K, N2::ctx)[26] == ^^N2::K::rXa);
+static_assert (members_of (^^N2::K, N2::ctx)[27] == ^^N2::K::rXb);
+static_assert (members_of (^^N2::K, N2::ctx)[28] == ^^N2::K::rXE);
+static_assert (members_of (^^N2::K, N2::ctx)[29] == ^^N2::K::rXg);
+static_assert (members_of (^^N2::K, N2::ctx)[30] == ^^N2::K::rYa);
+static_assert (members_of (^^N2::K, N2::ctx)[31] == ^^N2::K::rYb);
+static_assert (members_of (^^N2::K, N2::ctx)[32] == ^^N2::K::rYE);
+static_assert (members_of (^^N2::K, N2::ctx)[33] == ^^N2::K::rYg);
+static_assert (check_special_members (members_of (^^N2::K, N2::ctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::K, N2::ctx).size () == 10);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[0] == ^^N2::K::b);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[1] == N2::K::rXb);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[2] == ^^N2::K::rXa);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[3] == ^^N2::K::rXb);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[4] == ^^N2::K::rXE);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[5] == ^^N2::K::rXg);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[6] == ^^N2::K::rYa);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[7] == ^^N2::K::rYb);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[8] == ^^N2::K::rYE);
+static_assert (static_data_members_of (^^N2::K, N2::ctx)[9] == ^^N2::K::rYg);
+static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx).size () == 4);
+static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[0] == ^^N2::K::a);
+static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[1] == ^^N2::K::g);
+static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[2] == N2::K::rXa);
+static_assert (nonstatic_data_members_of (^^N2::K, N2::ctx)[3] == N2::K::rXg);
+static_assert (has_inaccessible_nonstatic_data_members (^^N2::K, N2::ctx));
+static_assert (members_of (^^N2::L, gctx).size () == 7);
+static_assert (members_of (^^N2::L, gctx)[0] == ^^N2::L::ctx);
+static_assert (check_special_members (members_of (^^N2::L, gctx), 6, true, true, true, true, true, true));
+static_assert (static_data_members_of (^^N2::L, gctx).size () == 1);
+static_assert (static_data_members_of (^^N2::L, gctx)[0] == ^^N2::L::ctx);
+static_assert (nonstatic_data_members_of (^^N2::L, gctx).size () == 0);
+static_assert (!has_inaccessible_nonstatic_data_members (^^N2::L, gctx));
+
+static_assert (members_of (^^N2, gctx).size () == 16);
+static_assert ((members_of (^^N2, gctx) | filter (is_type) | filter (is_class_type) | to <vector> ()).size () == 11);
+static_assert ((members_of (^^N2, gctx) | filter (is_namespace) | to <vector> ()).size () == 3);
+static_assert ((members_of (^^N2, gctx) | filter (is_namespace_alias) | to <vector> ()).size () == 1);
+static_assert ((members_of (^^N2, gctx) | filter (is_concept) | to <vector> ()).size () == 1);
+static_assert ((members_of (^^N2, gctx) | filter (is_variable) | to <vector> ()).size () == 1);
+
+namespace N3 {
+  struct A {
+    union { int a; };
+  };
+
+  struct B {
+    static int foo (int);
+    static long foo (long);
+    static short foo (short);
+    static int foo (int, int);
+    static double foo (double, float);
+  };
+
+  template <typename, typename>
+  constexpr bool c = false;
+
+  template <typename T>
+  constexpr bool c <T, T> = true;
+
+  template <typename T>
+  struct C {
+    void foo () requires (c <T, int>);
+    void bar () requires (c <T, long>);
+    void baz () requires (c <T, long>);
+  };
+}
+
+static_assert (members_of (^^N3::A, gctx).size () == 8);
+static_assert (is_union_type (members_of (^^N3::A, gctx)[0]));
+static_assert (!has_identifier (members_of (^^N3::A, gctx)[0]));
+static_assert (is_nonstatic_data_member (members_of (^^N3::A, gctx)[1]));
+static_assert (!has_identifier (members_of (^^N3::A, gctx)[1]));
+static_assert (check_special_members (members_of (^^N3::A, gctx), 6, true, true, true, true, true, true));
+
+static_assert (members_of (^^N3::B, gctx).size () == 11);
+static_assert (is_function (members_of (^^N3::B, gctx)[0]));
+static_assert (identifier_of (members_of (^^N3::B, gctx)[0]) == "foo");
+static_assert (type_of (members_of (^^N3::B, gctx)[0]) == ^^int (int));
+static_assert (is_function (members_of (^^N3::B, gctx)[1]));
+static_assert (identifier_of (members_of (^^N3::B, gctx)[1]) == "foo");
+static_assert (type_of (members_of (^^N3::B, gctx)[1]) == ^^long (long));
+static_assert (is_function (members_of (^^N3::B, gctx)[2]));
+static_assert (identifier_of (members_of (^^N3::B, gctx)[2]) == "foo");
+static_assert (type_of (members_of (^^N3::B, gctx)[2]) == ^^short (short));
+static_assert (is_function (members_of (^^N3::B, gctx)[3]));
+static_assert (identifier_of (members_of (^^N3::B, gctx)[3]) == "foo");
+static_assert (type_of (members_of (^^N3::B, gctx)[3]) == ^^int (int, int));
+static_assert (is_function (members_of (^^N3::B, gctx)[4]));
+static_assert (identifier_of (members_of (^^N3::B, gctx)[4]) == "foo");
+static_assert (type_of (members_of (^^N3::B, gctx)[4]) == ^^double (double, float));
+static_assert (check_special_members (members_of (^^N3::B, gctx), 6, true, true, true, true, true, true));
+
+static_assert (members_of (^^N3::C <int>, gctx).size () == 7);
+static_assert (is_function (members_of (^^N3::C <int>, gctx)[0]));
+static_assert (identifier_of (members_of (^^N3::C <int>, gctx)[0]) == "foo");
+static_assert (check_special_members (members_of (^^N3::C <int>, gctx), 6, true, true, true, true, true, true));
+static_assert (members_of (^^N3::C <long>, gctx).size () == 8);
+static_assert (is_function (members_of (^^N3::C <long>, gctx)[0]));
+static_assert (identifier_of (members_of (^^N3::C <long>, gctx)[0]) == "bar");
+static_assert (is_function (members_of (^^N3::C <long>, gctx)[1]));
+static_assert (identifier_of (members_of (^^N3::C <long>, gctx)[1]) == "baz");
+static_assert (check_special_members (members_of (^^N3::C <long>, gctx), 6, true, true, true, true, true, true));
+static_assert (members_of (^^N3::C <short>, gctx).size () == 6);
+static_assert (check_special_members (members_of (^^N3::C <short>, gctx), 6, true, true, true, true, true, true));
diff --git a/gcc/testsuite/g++.dg/reflect/members_of2.C b/gcc/testsuite/g++.dg/reflect/members_of2.C
new file mode 100644 (file)
index 0000000..cbf155c
--- /dev/null
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::members_of.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+namespace N1
+{
+  void foo (int);
+  void foo (long);
+  void foo (double);
+  void foo (long);
+  void foo (int);
+  void foo (float);
+}
+
+namespace N2
+{
+  struct A {};
+  int A;
+  int B;
+  struct B {};
+}
+
+namespace N3
+{
+  struct A {};
+  void A (int);
+  void A (long);
+  void B (int);
+  void B (long);
+  struct B {};
+}
+
+namespace N4
+{
+  static union { int a; };
+}
+
+static constexpr auto ctx = access_context::current ();
+static_assert (members_of (^^N1, ctx).size () == 4);
+static_assert ((members_of (^^N1, ctx) | std::views::filter (is_function) | std::ranges::to <std::vector> ()).size () == 4);
+static_assert ((members_of (^^N1, ctx) | std::views::filter (has_identifier) | std::ranges::to <std::vector> ()).size () == 4);
+static_assert (members_of (^^N2, ctx).size () == 4);
+static_assert ((members_of (^^N2, ctx) | std::views::filter (is_variable) | std::ranges::to <std::vector> ()).size () == 2);
+static_assert ((members_of (^^N2, ctx) | std::views::filter (is_type) | std::ranges::to <std::vector> ()).size () == 2);
+static_assert ((members_of (^^N2, ctx) | std::views::filter (has_identifier) | std::ranges::to <std::vector> ()).size () == 4);
+static_assert (members_of (^^N3, ctx).size () == 6);
+static_assert ((members_of (^^N3, ctx) | std::views::filter (is_function) | std::ranges::to <std::vector> ()).size () == 4);
+static_assert ((members_of (^^N3, ctx) | std::views::filter (is_type) | std::ranges::to <std::vector> ()).size () == 2);
+static_assert ((members_of (^^N3, ctx) | std::views::filter (has_identifier) | std::ranges::to <std::vector> ()).size () == 6);
+static_assert (members_of (^^N4, ctx).size () == 2);
+static_assert ((members_of (^^N4, ctx) | std::views::filter (is_variable) | std::ranges::to <std::vector> ()).size () == 1);
+static_assert ((members_of (^^N4, ctx) | std::views::filter (is_type) | std::views::filter (is_union_type) | std::ranges::to <std::vector> ()).size () == 1);
+static_assert ((members_of (^^N4, ctx) | std::views::filter (has_identifier) | std::ranges::to <std::vector> ()).size () == 0);
diff --git a/gcc/testsuite/g++.dg/reflect/members_of3.C b/gcc/testsuite/g++.dg/reflect/members_of3.C
new file mode 100644 (file)
index 0000000..2ee9f46
--- /dev/null
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::members_of.
+
+#include <meta>
+#include <ranges>
+#include <tuple>
+
+using namespace std::meta;
+
+struct A {
+  int i;
+  template <int I> int &get () { return i; }
+};
+
+template <>
+struct std::tuple_size <A>
+{
+  static const int value = 4;
+};
+
+template <size_t I>
+struct std::tuple_element <I, A>
+{
+  using type = int;
+};
+
+int arr[4];
+
+namespace N1
+{
+  auto [x, y, z, w] = arr;
+}
+
+namespace N2
+{
+  auto [x, y, z, w] = A {};
+}
+
+static constexpr auto ctx = access_context::current ();
+static_assert (members_of (^^N1, ctx).size () == 1);
+static_assert (is_variable (members_of (^^N1, ctx)[0]));
+static_assert (!has_identifier (members_of (^^N1, ctx)[0]));
+static_assert (type_of (members_of (^^N1, ctx)[0]) == ^^int [4]);
+static_assert (!is_structured_binding (members_of (^^N1, ctx)[0]));
+static_assert (members_of (^^N2, ctx).size () == 5);
+static_assert ((members_of (^^N2, ctx) | std::views::filter (is_variable) | std::ranges::to <std::vector> ()).size () == 5);
+static_assert ((members_of (^^N2, ctx) | std::views::filter (has_identifier) | std::ranges::to <std::vector> ()).size () == 4);
+static_assert ((members_of (^^N2, ctx) | std::views::filter (is_structured_binding) | std::ranges::to <std::vector> ()).size () == 0);
diff --git a/gcc/testsuite/g++.dg/reflect/members_of4.C b/gcc/testsuite/g++.dg/reflect/members_of4.C
new file mode 100644 (file)
index 0000000..7c843a8
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::members_of.
+
+#include <meta>
+#include <ranges>
+#include <tuple>
+
+using namespace std::meta;
+
+auto l1 = [] (int x) {};
+auto l2 = [] (auto x) {};
+auto l3 = [] (int x) static {};
+auto l4 = [] (auto x) static {};
+
+static constexpr auto ctx = access_context::current ();
+// FIXME these two should pass, call operator is guaranteed
+// static_assert (std::ranges::distance (members_of (type_of (^^l1), ctx) | std::views::filter (is_operator_function)) >= 1);
+static_assert (std::ranges::distance (members_of (type_of (^^l2), ctx) | std::views::filter (is_operator_function_template)) >= 1);
+// static_assert (std::ranges::distance (members_of (type_of (^^l3), ctx) | std::views::filter (is_operator_function)) >= 1);
+static_assert (std::ranges::distance (members_of (type_of (^^l4), ctx) | std::views::filter (is_operator_function_template)) >= 1);
diff --git a/gcc/testsuite/g++.dg/reflect/members_of5.C b/gcc/testsuite/g++.dg/reflect/members_of5.C
new file mode 100644 (file)
index 0000000..f1987c6
--- /dev/null
@@ -0,0 +1,101 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::members_of.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template<typename F>
+consteval bool
+has_mem(info clazz, F f)
+{
+  for (info x : members_of(clazz, access_context::unchecked()))
+    if (f(x))
+      return true;
+  return false;
+}
+
+consteval auto is_operator(operators op)
+{ return [op](info mem) { return is_operator_function(mem) && operator_of(mem) == op; }; }
+
+struct ExplicitDef
+{
+  ExplicitDef() = default;
+  ExplicitDef(const ExplicitDef&) = default;
+  ExplicitDef(ExplicitDef&&) = default;
+
+  ExplicitDef& operator=(const ExplicitDef&) = default;
+  ExplicitDef& operator=(ExplicitDef&&) = default;
+  
+  ~ExplicitDef() = default;
+};
+
+static_assert (has_mem (^^ExplicitDef, is_default_constructor));
+static_assert (has_mem (^^ExplicitDef, is_copy_constructor));
+static_assert (has_mem (^^ExplicitDef, is_move_constructor));
+static_assert (has_mem (^^ExplicitDef, is_copy_assignment));
+static_assert (has_mem (^^ExplicitDef, is_move_assignment));
+static_assert (has_mem (^^ExplicitDef, is_destructor));
+static_assert (!has_mem (^^ExplicitDef, is_operator(op_equals_equals)));
+static_assert (!has_mem (^^ExplicitDef, is_operator(op_spaceship)));
+
+struct NoMoveDecl
+{
+  NoMoveDecl() = default;
+  NoMoveDecl(const NoMoveDecl&) = default;
+
+  NoMoveDecl& operator=(const NoMoveDecl&) = default;
+  
+  ~NoMoveDecl() = default;
+};
+
+static_assert (has_mem (^^NoMoveDecl, is_default_constructor));
+static_assert (has_mem (^^NoMoveDecl, is_copy_constructor));
+static_assert (!has_mem (^^NoMoveDecl, is_move_constructor));
+static_assert (has_mem (^^NoMoveDecl, is_copy_assignment));
+static_assert (!has_mem (^^NoMoveDecl, is_move_assignment));
+static_assert (has_mem (^^NoMoveDecl, is_destructor));
+static_assert (!has_mem (^^NoMoveDecl, is_operator(op_equals_equals)));
+static_assert (!has_mem (^^NoMoveDecl, is_operator(op_spaceship)));
+
+struct ImplicitDef
+{
+};
+
+static_assert (has_mem (^^ImplicitDef, is_default_constructor));
+static_assert (has_mem (^^ImplicitDef, is_copy_constructor));
+static_assert (has_mem (^^ImplicitDef, is_move_constructor));
+static_assert (has_mem (^^ImplicitDef, is_copy_assignment));
+static_assert (has_mem (^^ImplicitDef, is_move_assignment));
+static_assert (has_mem (^^ImplicitDef, is_destructor));
+static_assert (!has_mem (^^ImplicitDef, is_operator(op_equals_equals)));
+static_assert (!has_mem (^^ImplicitDef, is_operator(op_spaceship)));
+
+struct ExplicitRelOps
+{
+  bool operator==(const ExplicitRelOps&) const = default;
+  auto operator<=>(const ExplicitRelOps&) const = default;
+};
+ExplicitRelOps a,b;
+static_assert (has_mem (^^ExplicitRelOps, is_operator(op_equals_equals)));
+// FIXME, below check fails without this use
+auto r = a <=> b;
+static_assert (has_mem (^^ExplicitRelOps, is_operator(op_spaceship)));
+
+struct NoEqualDecl
+{
+  auto operator<=>(const NoEqualDecl&) const
+  { return std::strong_ordering::equal; }
+};
+static_assert (!has_mem (^^NoEqualDecl, is_operator(op_equals_equals)));
+static_assert (has_mem (^^NoEqualDecl, is_operator(op_spaceship)));
+
+struct ImplicitRelOps
+{
+  // operator== is implicitly declared
+  auto operator<=>(const ImplicitRelOps&) const = default;
+};
+static_assert (has_mem (^^ImplicitRelOps, is_operator(op_equals_equals)));
+static_assert (has_mem (^^ImplicitRelOps, is_operator(op_spaceship)));
diff --git a/gcc/testsuite/g++.dg/reflect/members_of6.C b/gcc/testsuite/g++.dg/reflect/members_of6.C
new file mode 100644 (file)
index 0000000..fa72c9e
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::members_of.
+
+#include <compare>
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+struct S
+{
+  auto operator <=> (const S &) const = default;
+};
+
+struct T
+{
+  auto operator <=> (this T, T) = default;
+  auto operator <=> (this const T &, const T &) = default;
+};
+
+constexpr access_context uctx = access_context::unchecked ();
+
+static_assert (members_of (^^S, uctx).size () == 8);
+static_assert (operator_of (members_of (^^T, uctx)[0]) == op_spaceship);
+static_assert ((members_of (^^S, uctx) | std::views::drop (1) | std::views::filter (is_special_member_function) | std::views::filter (is_defaulted) | std::ranges::to <std::vector> ()).size () == 6);
+static_assert ((members_of (^^S, uctx) | std::views::drop (1) | std::views::filter (is_operator_function) | std::views::filter (is_defaulted) | std::ranges::to <std::vector> ()).size () == 3);
+// TODO: Shouldn't the above have 2 implicitly-declared equality
+// operators?
+static_assert (members_of (^^T, uctx).size () == 9);
+static_assert (operator_of (members_of (^^T, uctx)[0]) == op_spaceship);
+static_assert (operator_of (members_of (^^T, uctx)[1]) == op_spaceship);
+static_assert ((members_of (^^T, uctx) | std::views::drop (2) | std::views::filter (is_special_member_function) | std::views::filter (is_defaulted) | std::ranges::to <std::vector> ()).size () == 6);
+static_assert ((members_of (^^T, uctx) | std::views::drop (2) | std::views::filter (is_operator_function) | std::views::filter (is_defaulted) | std::ranges::to <std::vector> ()).size () == 3);
diff --git a/gcc/testsuite/g++.dg/reflect/members_of7.C b/gcc/testsuite/g++.dg/reflect/members_of7.C
new file mode 100644 (file)
index 0000000..5402405
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::members_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr access_context uctx = access_context::unchecked ();
+
+namespace N
+{
+}
+
+consteval std::size_t
+foo ()
+{
+  return members_of (^^N, uctx).size ();
+}
+
+namespace N
+{
+  static_assert (foo () == 0);
+  int a;
+  static_assert (foo () == 1);
+  void bar (int);
+  static_assert (foo () == 2);
+  void baz (long);
+  static_assert (foo () == 3);
+  void baz (short, float);
+  static_assert (foo () == 4);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/metafn-ptr1.C b/gcc/testsuite/g++.dg/reflect/metafn-ptr1.C
new file mode 100644 (file)
index 0000000..271063c
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Try to invoke a metafunction through a function pointer.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval size_t
+invoke (size_t (*fp)(info))
+{
+  return fp (^^int);
+}
+
+void
+g ()
+{
+  static_assert (invoke (size_of) == sizeof (int));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/ns1.C b/gcc/testsuite/g++.dg/reflect/ns1.C
new file mode 100644 (file)
index 0000000..280c288
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on namespaces.
+
+constexpr auto glob = ^^::;
+
+namespace Q { }
+constexpr auto q = ^^Q;
+namespace Q { }
+static_assert (q == ^^Q);
+
+namespace A { namespace B { using C = int; } }
+constexpr auto r = ^^A::B::C &;
+
+namespace N {
+  using T = int;
+  namespace M {
+    using TT = int;
+  }
+}
+
+void
+f1 ()
+{
+  constexpr auto n = ^^N;
+  [: n :]::T i = 42;
+  typename [: n :]::T it = 42;
+
+  constexpr auto t = ^^N::T;
+  typename [: t :] j = 42;
+
+  constexpr auto m = ^^N::M;
+  [: m :]::TT k = 42;
+  typename [: m :]::TT kt = 42;
+
+  constexpr auto m2 = ^^t;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/ns2.C b/gcc/testsuite/g++.dg/reflect/ns2.C
new file mode 100644 (file)
index 0000000..482b875
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on namespaces.  Invalid stuff.
+
+void foo (int);
+
+namespace N {
+}
+
+void
+f1 ()
+{
+  constexpr auto r = ^^::;
+  [: r :] foo (0); // { dg-error "expected" }
+
+  constexpr auto q = ^^int;
+  [: q :]::T x; // { dg-error "reflection not usable in a splice scope|expected" }
+  // { dg-message ".int. is not a class, namespace, or enumeration" "" { target *-*-* } .-1 }
+
+  constexpr auto x = ^^N::X;  // { dg-error ".N::X. has not been declared" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/ns3.C b/gcc/testsuite/g++.dg/reflect/ns3.C
new file mode 100644 (file)
index 0000000..4d810eb
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test dependent namespaces.
+
+using info = decltype(^^int);
+
+template <info R> int fn() {
+  return [:R:]::v;
+}
+
+namespace NS {
+  int v = 1;
+}
+
+int a = fn<^^NS>();
diff --git a/gcc/testsuite/g++.dg/reflect/ns4.C b/gcc/testsuite/g++.dg/reflect/ns4.C
new file mode 100644 (file)
index 0000000..7d03d82
--- /dev/null
@@ -0,0 +1,94 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test dependent namespaces in typenames.
+
+using info = decltype(^^void);
+
+namespace N {
+  struct A { int i; using Q = int; };
+  template<typename T>
+  struct B { T t; };
+  static int glob;
+  using U = int;
+  int foo (int i) { return i; }
+  template<typename T>
+  T baz (T t) { return t; }
+  template<typename T>
+  constexpr T pi = 3.14;
+
+  namespace M {
+    struct C { int i; };
+    template<typename T>
+    struct D { T t; };
+    int mglob;
+    using V = int;
+    void bar () { }
+    template<typename T>
+    T qux (T t) { return t; }
+    template<typename T>
+    constexpr T pi2 = 3.14;
+  }
+}
+
+template<info R>
+void
+f ()
+{
+  typename [:R:]::A a{1};
+  typename[:R:]::template B<int> b{1};
+  typename [:R:]::A::Q i1;
+  typename [:R:]::U u;
+  [:R:]::M::bar ();
+  [:R:]::M::mglob++;
+  typename [:R:]::M::V i2;
+  typename [:R:]::M::C c{1};
+  typename [:R:]::M::template D<int> d{1};
+
+  // Not a TYPENAME_TYPE, but let's test it.
+  [:R:]::template baz<int>(42);
+  double d1 = [:R:]::template pi<double>;
+  int i3 = [:R:]::foo (42);
+  [:R:]::glob++;
+  [:R:]::M::template qux<int>(42);
+  double d2 = [:R:]::M::template pi2<double>;
+}
+
+template<info R>
+void
+g ()
+{
+  typename [:R:]::C c{1};
+  typename [:R:]::template D<int> d{1};
+  [:R:]::mglob++;
+  typename [:R:]::V v;
+  [:R:]::bar ();
+  [:R:]::template qux<int>(42);
+  double d2 = [:R:]::template pi2<double>;
+}
+
+template<info R>
+void
+bad ()
+{
+  typename [:R:]::NOTHERE x; // { dg-error ".NOTHERE. is not a member of .N." }
+  typename [:R:]::M::NOTHERE y;  // { dg-error ".NOTHERE. is not a member of .N::M." }
+}
+
+template<info R>
+struct E {
+  typename [:R:]::A a;
+  typename[:R:]::template B<int> b;
+  typename [:R:]::U u;
+  typename [:R:]::M::V v;
+  typename [:R:]::M::C c{1};
+  typename [:R:]::M::template D<int> d{1};
+};
+
+void
+doit ()
+{
+  f<^^N>();
+  bad<^^N>();
+  E<^^N> e;
+  g<^^N::M>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/ns5.C b/gcc/testsuite/g++.dg/reflect/ns5.C
new file mode 100644 (file)
index 0000000..236b292
--- /dev/null
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+template<typename>
+void foo () { }
+void bar () { }
+namespace N { }
+namespace M = N;
+template<typename T>
+T vt{};
+template<typename T>
+concept C = true;
+static int i;
+enum E { X };
+struct S { static int si; };
+template<typename T>
+struct D { static T di; };
+template<typename T>
+using Z = D<T>;
+
+template<info R> void fn1 () { typename [:R:]::X x; }  // { dg-error "not usable in a splice scope" }
+template<info R> void fn2 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn3 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn4 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn5 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn6 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn7 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn8 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn9 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
+template<info R> void fn10 () { typename [:R:]::X x; }  // { dg-error "not usable in a splice scope" }
+template<info R> void fn11 () { typename [:R:]::X x; }  // { dg-error "not usable in a splice scope" }
+
+template void fn1<^^foo<int>>(); // { dg-message "required from here" }
+template void fn2<^^foo>();     // { dg-message "required from here" }
+template void fn3<^^bar>();     // { dg-message "required from here" }
+template void fn4<^^vt<int>>();  // { dg-message "required from here" }
+template void fn5<^^vt>();      // { dg-message "required from here" }
+template void fn6<^^C>();       // { dg-message "required from here" }
+template void fn7<^^i>();       // { dg-message "required from here" }
+template void fn8<^^X>();       // { dg-message "required from here" }
+template void fn9<^^S::si>();   // { dg-message "required from here" }
+template void fn10<^^D<int>::di>(); // { dg-message "required from here" }
+template void fn11<^^Z>();      // { dg-message "required from here" }
diff --git a/gcc/testsuite/g++.dg/reflect/ns6.C b/gcc/testsuite/g++.dg/reflect/ns6.C
new file mode 100644 (file)
index 0000000..6eb6e35
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace N { void foo (); }
+
+// P2996 doesn't allow this.
+namespace [:^^N:] { } // { dg-error "expected" }
+
+// But this is fine.
+namespace A = [:^^N:];
+using namespace [:^^A:];
+
+void
+g ()
+{
+  foo ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/null1.C b/gcc/testsuite/g++.dg/reflect/null1.C
new file mode 100644 (file)
index 0000000..58eaa09
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test null reflection.
+
+#include <meta>
+
+struct S {};
+
+static_assert(std::meta::info() == std::meta::info());
+static_assert(std::meta::info{} == std::meta::info{});
+static_assert(std::meta::info() != ^^S);
+static_assert(std::meta::info{} != ^^S);
+
+constexpr std::meta::info g;
+constexpr std::meta::info g2{};
+static_assert(g == std::meta::info());
+static_assert(g == g2);
+constexpr std::meta::info *g3{};
+constexpr std::meta::info *g4{};
+
+consteval void
+f ()
+{
+  std::meta::info m;
+  std::meta::info m2{};
+  static std::meta::info m3;
+  static std::meta::info m4{};
+  static constexpr std::meta::info m5;
+  static constexpr std::meta::info m6{};
+}
diff --git a/gcc/testsuite/g++.dg/reflect/null2.C b/gcc/testsuite/g++.dg/reflect/null2.C
new file mode 100644 (file)
index 0000000..73b4ce4
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Here, x is a null reflection so should be allowed to compare equal
+// to itself.  meta::info should be const-default-constructible.
+
+constexpr decltype(^^::) x;
+static_assert(x == x);
diff --git a/gcc/testsuite/g++.dg/reflect/null3.C b/gcc/testsuite/g++.dg/reflect/null3.C
new file mode 100644 (file)
index 0000000..2fbd7cc
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test null reflection.
+
+using info = decltype(^^int);
+consteval info foo () { return {}; }
+static_assert (foo () == info ());
+consteval auto bar () { return info{}; }
+static_assert (bar () == info ());
diff --git a/gcc/testsuite/g++.dg/reflect/null4.C b/gcc/testsuite/g++.dg/reflect/null4.C
new file mode 100644 (file)
index 0000000..28e6972
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test null reflection.
+
+using info = decltype(^^int);
+
+struct S {
+  info i = {};
+};
+
+static_assert (S{}.i == info ());
+
+struct Q {
+  info i;
+  consteval Q() : i{} {}
+};
+
+static_assert (Q{}.i == info ());
diff --git a/gcc/testsuite/g++.dg/reflect/null5.C b/gcc/testsuite/g++.dg/reflect/null5.C
new file mode 100644 (file)
index 0000000..f768a48
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test null reflection.
+
+using info = decltype(^^int);
+
+inline constexpr info Ag {};
+
+consteval info return_null() {
+    return info{};
+}
+
+template <typename>
+struct S {
+    static constexpr info Bt {^^::};
+    static constexpr info Ct {};
+    static constexpr info Dt = return_null();
+};
+
+template struct S<int>;
+
+int main() {
+    template for (auto _ : {0}) {
+        constexpr info A {};
+    }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/object_of1.C b/gcc/testsuite/g++.dg/reflect/object_of1.C
new file mode 100644 (file)
index 0000000..37b2a5f
--- /dev/null
@@ -0,0 +1,85 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::object_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+int x;
+int& y = x;
+
+static_assert (^^x != ^^y);
+static_assert (object_of (^^x) == object_of (^^y));
+static_assert (is_object (object_of (^^x)));
+static_assert (is_object (object_of (^^y)));
+
+constexpr int i = 1;
+static_assert (object_of (^^i) == reflect_object (i));
+static_assert (is_object (object_of (^^i)));
+
+constexpr const int *p = &i;
+constexpr auto ro = object_of (^^p);
+static_assert (^^p != ro);
+static_assert (!is_variable (ro));
+static_assert (is_object (ro));
+static_assert (!is_value (ro));
+static_assert (ro == reflect_object (p));
+static_assert (ro != reflect_constant (&i));
+
+void
+g ()
+{
+  constexpr int &r = x;
+  constexpr auto r1 = object_of (^^r);
+  static_assert (is_object (object_of (^^r)));
+  static int sl = 42;
+  constexpr auto r2 = object_of (^^sl);
+  static_assert (is_object (object_of (^^sl)));
+}
+
+const int &rc = 42;
+// Here, object_of yields _ZGR2rc_.
+static_assert (object_of (^^rc) != reflect_constant (42));
+static_assert (!is_variable (object_of (^^rc)));
+static_assert (is_object (object_of (^^rc)));
+static_assert (!is_value (object_of (^^rc)));
+
+struct A { const int ci = 0; int nci; };
+struct B : A { mutable int i; };
+
+B arr[2];
+static_assert (object_of (^^arr) != ^^arr);
+static_assert (is_object (object_of (^^arr)));
+static_assert (reflect_object (arr) == object_of (^^arr));
+static_assert (reflect_object (arr[0]) != object_of (^^arr));
+static_assert (type_of (object_of (^^arr)) == ^^B[2]);
+
+const A &r = arr[1];
+static_assert (object_of (^^r) != ^^r);
+static_assert (is_object (object_of (^^r)));
+static_assert (reflect_object (arr[1]) != object_of (^^r));
+// TODO Fails because the array index has types long int x int.
+//static_assert (reflect_object (static_cast<A&>(arr[1])) == object_of (^^r));
+static_assert (type_of (^^r) == ^^const A&);
+static_assert (type_of (object_of (^^r)) == ^^A);
+
+struct S { int i; } s;
+static_assert (object_of (^^s) != ^^s);
+static_assert (is_object (object_of (^^s)));
+static_assert (reflect_object (s) == object_of (^^s));
+static_assert (type_of (object_of (^^s)) == ^^S);
+
+template<int, int&, S>
+struct X { };
+constexpr auto T = ^^X<1, x, S{}>;
+constexpr auto o1 = object_of (template_arguments_of (T)[1]);
+constexpr auto o2 = object_of (template_arguments_of (T)[2]);
+static_assert (is_object (o1));
+static_assert (is_object (o2));
+static_assert (o1 == template_arguments_of (T)[1]);
+static_assert (o2 == template_arguments_of (T)[2]);
+static_assert (o1 == reflect_object (x));
+static_assert (type_of (o1) == ^^int);
+// ??? May not be true.
+static_assert (type_of (o2) == ^^const S);
diff --git a/gcc/testsuite/g++.dg/reflect/object_of2.C b/gcc/testsuite/g++.dg/reflect/object_of2.C
new file mode 100644 (file)
index 0000000..8737764
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::object_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+void fn ();
+constexpr auto r1 = object_of (reflect_constant (3)); // { dg-error "uncaught exception" }
+constexpr auto r2 = object_of (^^fn); // { dg-error "uncaught exception" }
+
+static int G;
+
+void
+f (int p)
+{
+  int i = 42;
+  constexpr auto r3 = object_of (^^p); // { dg-error "uncaught exception" }
+  constexpr auto r4 = object_of (^^i); // { dg-error "uncaught exception" }
+}
+
+template<int>
+struct X { };
+constexpr auto T = ^^X<1>;
+constexpr auto o = object_of (template_arguments_of (T)[0]); // { dg-error "uncaught exception" }
diff --git a/gcc/testsuite/g++.dg/reflect/odr1.C b/gcc/testsuite/g++.dg/reflect/odr1.C
new file mode 100644 (file)
index 0000000..7678d65
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+template<info val>
+void
+f ()
+{
+  [:val:];       // { dg-error "use of local variable with automatic storage from containing function" }
+  [:val:] = {};          // { dg-error "use of local variable with automatic storage from containing function" }
+  /* This is ill-formed because:
+     - the splice-expression designates b,
+     - the splice-expression names b ([basic.def.odr]/5),
+     - the splice-expression odr-uses b ([basic.def.odr]/5),
+     - however, the local entity b is not odr-usable from the scope inhabited
+       by the splice-expression ([basic.def.odr]/10.2).  Since the local
+       entity b is odr-used within a scope where b is not odr-usable,
+       the program is ill-formed (also [basic.def.odr]/10).  */
+  [:val:] z;  // { dg-error "use of local variable with automatic storage from containing function|expected" }
+  float a = [:val:]; // { dg-error "use of local variable with automatic storage from containing function" }
+}
+
+void
+g ()
+{
+  float b = 2.5f;
+  f<^^b>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/offset_of1.C b/gcc/testsuite/g++.dg/reflect/offset_of1.C
new file mode 100644 (file)
index 0000000..41f5c71
--- /dev/null
@@ -0,0 +1,132 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::offset_of.
+
+#include <meta>
+#include <cstddef>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_offset_of (info r)
+{
+  try { offset_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_offset_of (std::meta::reflect_constant (42)));
+static_assert (!has_offset_of (std::meta::reflect_object (arr[1])));
+static_assert (!has_offset_of (^^arr));
+static_assert (!has_offset_of (^^a3));
+static_assert (!has_offset_of (^^fn));
+static_assert (!has_offset_of (^^fn2));
+static_assert (!has_offset_of (^^Enum::A));
+static_assert (!has_offset_of (^^Alias));
+static_assert (!has_offset_of (^^S));
+static_assert (has_offset_of (^^S::mem));
+static_assert (has_offset_of (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!has_offset_of (^^TCls));
+static_assert (!has_offset_of (^^TFn));
+static_assert (!has_offset_of (^^TVar));
+static_assert (!has_offset_of (^^Concept));
+static_assert (!has_offset_of (^^NSAlias));
+static_assert (!has_offset_of (^^NS));
+static_assert (has_offset_of (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (!has_offset_of (std::meta::data_member_spec (^^int, { .name = "member" })));
+void bar (long, const T f, int g[2], T &);
+
+int
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (!has_offset_of (^^a));
+  static_assert (!has_offset_of (^^b));
+  static_assert (!has_offset_of (^^c));
+  static_assert (!has_offset_of (^^d));
+  static_assert (!has_offset_of (^^e));
+  static_assert (!has_offset_of (parameters_of (^^foo)[0]));
+  static_assert (!has_offset_of (parameters_of (^^bar)[0]));
+  return 0;
+}
+
+struct V
+{
+  char a;
+  short b;
+  char c;
+  int d;
+  char e;
+  long long f;
+  int : 2;
+  int g : 3;
+  union {
+    int h;
+    long i;
+  };
+};
+
+union W
+{
+  int a;
+  double b;
+};
+
+static_assert (offset_of (^^V::a).bytes == offsetof (V, a));
+static_assert (offset_of (^^V::a).bits == 0);
+static_assert (offset_of (^^V::b).bytes == offsetof (V, b));
+static_assert (offset_of (^^V::b).bits == 0);
+static_assert (offset_of (^^V::c).bytes == offsetof (V, c));
+static_assert (offset_of (^^V::c).bits == 0);
+static_assert (offset_of (^^V::d).bytes == offsetof (V, d));
+static_assert (offset_of (^^V::d).bits == 0);
+static_assert (offset_of (^^V::e).bytes == offsetof (V, e));
+static_assert (offset_of (^^V::e).bits == 0);
+static_assert (offset_of (^^V::f).bytes == offsetof (V, f));
+static_assert (offset_of (^^V::f).bits == 0);
+static_assert (offset_of (^^V::g).bytes == offsetof (V, f) + sizeof (long long));
+static_assert (offset_of (^^V::g).bits == 2);
+static_assert (offset_of (^^V::h).bytes == 0);
+static_assert (offset_of (^^V::h).bits == 0);
+static_assert (offset_of (^^V::i).bytes == 0);
+static_assert (offset_of (^^V::i).bits == 0);
+static_assert (offset_of (^^W::a).bytes == 0);
+static_assert (offset_of (^^W::a).bits == 0);
+static_assert (offset_of (^^W::b).bytes == 0);
+static_assert (offset_of (^^W::b).bits == 0);
+static_assert (offset_of (^^V::f) < offset_of (^^V::g));
+static_assert (offset_of (^^V::f) > offset_of (^^V::e));
+static_assert (offset_of (^^V::g) == offset_of (^^V::g));
+static_assert (offset_of (^^V::e).total_bits () == offsetof (V, e) * __CHAR_BIT__);
+static_assert (offset_of (^^V::g).total_bits () == (offsetof (V, f) + sizeof (long long)) * __CHAR_BIT__ + 2);
+using mo = decltype (offset_of (^^V::g));
+static_assert (dealias (^^mo) == ^^std::meta::member_offset);
+constexpr std::meta::member_offset mov = { .bytes = 1, .bits = 2 };
+static_assert (mov.total_bits () == __CHAR_BIT__ + 2);
diff --git a/gcc/testsuite/g++.dg/reflect/operator_of1.C b/gcc/testsuite/g++.dg/reflect/operator_of1.C
new file mode 100644 (file)
index 0000000..493c800
--- /dev/null
@@ -0,0 +1,354 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::operator_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+consteval bool
+is_operator (info r)
+{
+  try { operator_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!is_operator (null_reflection));
+static_assert (!is_operator (^^::));
+static_assert (!is_operator (^^ns));
+static_assert (!is_operator (^^ns_alias));
+static_assert (!is_operator (reflect_constant (3)));
+static_assert (!is_operator (^^cls));
+static_assert (!is_operator (^^cls::dm));
+static_assert (!is_operator (^^cls::ref_dm));
+static_assert (!is_operator (^^cls::static_dm));
+static_assert (!is_operator (^^cls::mem_fun));
+static_assert (!is_operator (^^cls::static_mem_fun));
+static_assert (!is_operator (^^cls::type));
+static_assert (!is_operator (^^cls_var));
+static_assert (!is_operator (^^onion));
+static_assert (!is_operator (^^anon));
+static_assert (!is_operator (^^fun));
+static_assert (!is_operator (^^alias));
+static_assert (!is_operator (^^var));
+static_assert (!is_operator (^^ref));
+static_assert (!is_operator (^^rref));
+static_assert (!is_operator (^^ptr));
+static_assert (!is_operator (^^cls_tmpl));
+static_assert (!is_operator (^^cls_tmpl<int>));
+static_assert (!is_operator (^^incomplete_cls<int>));
+static_assert (!is_operator (^^fun_tmpl));
+static_assert (!is_operator (^^fun_tmpl<int>));
+static_assert (!is_operator (^^conc));
+static_assert (!is_operator (substitute (^^conc, { ^^int })));
+static_assert (!is_operator (^^var_tmpl));
+static_assert (!is_operator (^^var_tmpl<int>));
+static_assert (!is_operator (^^cls_tmpl_alias));
+static_assert (!is_operator (^^cls_tmpl_alias<int>));
+static_assert (!is_operator (^^Enum));
+static_assert (!is_operator (^^Enum::A));
+static_assert (!is_operator (^^Enum_class));
+static_assert (!is_operator (^^Enum_class::A));
+static_assert (!is_operator (^^decomp));
+static_assert (!is_operator (^^decomp_ref));
+static_assert (!is_operator (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!is_operator (dms));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!is_operator (bases_of (^^Derived, access_context::current ())[0]));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!is_operator (^^T));
+  static_assert (!is_operator (R));
+  static_assert (!is_operator (R2));
+  static_assert (!is_operator (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (!is_operator (^^p));
+  static_assert (!is_operator (^^c));
+}
+
+struct S
+{
+  using size_t = decltype (sizeof 0);
+  void *operator new (size_t, void *);
+  void *operator new[] (size_t, void *);
+  void operator delete (void *);
+  void operator delete[] (void *);
+  S &operator () (const S &);
+  S &operator [] (const S &);
+  S &operator = (const S &);
+  S &operator << (int);
+  S &operator >> (int);
+  S &operator ++ ();
+  S &operator -- ();
+  S &operator ~ ();
+  S &operator ! ();
+  S &operator + (const S &);
+  S &operator - (const S &);
+  S &operator * (const S &);
+  S &operator / (const S &);
+  S &operator % (const S &);
+  S &operator ^ (const S &);
+  S &operator & (const S &);
+  S &operator | (const S &);
+  S &operator += (const S &);
+  S &operator -= (const S &);
+  S &operator *= (const S &);
+  S &operator /= (const S &);
+  S &operator %= (const S &);
+  S &operator ^= (const S &);
+  S &operator &= (const S &);
+  S &operator |= (const S &);
+  S &operator <<= (int);
+  S &operator >>= (int);
+  bool operator == (const S &);
+  bool operator != (const S &);
+  bool operator < (const S &);
+  bool operator > (const S &);
+  bool operator <= (const S &);
+  bool operator >= (const S &);
+  int operator <=> (const S &);
+  bool operator && (const S &);
+  bool operator || (const S &);
+  S &operator , (const S &);
+  S *operator -> ();
+  S &operator ->* (const S &);
+  S &operator co_await ();
+};
+
+struct T
+{
+  T &operator ++ (int);
+  T &operator -- (int);        
+  T &operator + ();
+  T &operator - ();
+};
+
+struct U
+{
+  U &operator compl ();
+  U &operator not ();
+  U &operator xor (const U &);
+  U &operator bitand (const U &);
+  U &operator bitor (const U &);
+  U &operator xor_eq (const U &);
+  U &operator and_eq (const U &);
+  U &operator or_eq (const U &);
+  bool operator and (const U &);
+  bool operator or (const U &);
+
+  template <typename... Args>
+  S &operator () (const Args&...);
+  template <typename... Args>
+  S &operator [] (const Args&...);
+};
+
+struct W
+{
+  using size_t = decltype (sizeof 0);
+  template <int> void *operator new (size_t, void *);
+  template <int> void *operator new[] (size_t, void *);
+  template <int> void operator delete (void *, W);
+  template <int> void operator delete[] (void *, W);
+  template <int> W &operator () (const W &);
+  template <int> W &operator [] (const W &);
+  template <int> W &operator = (const W &);
+  template <int> W &operator << (int);
+  template <int> W &operator >> (int);
+  template <int> W &operator ++ ();
+  template <int> W &operator -- ();
+  template <int> W &operator ~ ();
+  template <int> W &operator ! ();
+  template <int> W &operator + (const W &);
+  template <int> W &operator - (const W &);
+  template <int> W &operator * (const W &);
+  template <int> W &operator / (const W &);
+  template <int> W &operator % (const W &);
+  template <int> W &operator ^ (const W &);
+  template <int> W &operator & (const W &);
+  template <int> W &operator | (const W &);
+  template <int> W &operator += (const W &);
+  template <int> W &operator -= (const W &);
+  template <int> W &operator *= (const W &);
+  template <int> W &operator /= (const W &);
+  template <int> W &operator %= (const W &);
+  template <int> W &operator ^= (const W &);
+  template <int> W &operator &= (const W &);
+  template <int> W &operator |= (const W &);
+  template <int> W &operator <<= (int);
+  template <int> W &operator >>= (int);
+  template <int> bool operator == (const W &);
+  template <int> bool operator != (const W &);
+  template <int> bool operator < (const W &);
+  template <int> bool operator > (const W &);
+  template <int> bool operator <= (const W &);
+  template <int> bool operator >= (const W &);
+  template <int> int operator <=> (const W &);
+  template <int> bool operator && (const W &);
+  template <int> bool operator || (const W &);
+  template <int> W &operator , (const W &);
+  template <int> W *operator -> ();
+  template <int> W &operator ->* (const W &);
+  template <int> W &operator co_await ();
+};
+
+struct X
+{
+  template <int> X &operator ++ (int);
+  template <int> X &operator -- (int); 
+  template <int> X &operator + ();
+  template <int> X &operator - ();
+};
+
+static_assert (operator_of (^^S::operator new) == op_new);
+static_assert (operator_of (^^S::operator delete) == std::meta::op_delete);
+static_assert (operator_of (^^S::operator new[]) == std::meta::operators::op_array_new);
+static_assert (operator_of (^^S::operator delete[]) == op_array_delete);
+static_assert (operator_of (^^S::operator co_await) == op_co_await);
+static_assert (operator_of (^^S::operator ()) == op_parentheses);
+static_assert (operator_of (^^S::operator []) == op_square_brackets);
+static_assert (operator_of (^^S::operator ->) == op_arrow);
+static_assert (operator_of (^^S::operator ->*) == op_arrow_star);
+static_assert (operator_of (^^S::operator ~) == op_tilde);
+static_assert (operator_of (^^S::operator !) == op_exclamation);
+static_assert (operator_of (^^S::operator +) == op_plus);
+static_assert (operator_of (^^S::operator -) == op_minus);
+static_assert (operator_of (^^S::operator *) == op_star);
+static_assert (operator_of (^^S::operator /) == op_slash);
+static_assert (operator_of (^^S::operator %) == op_percent);
+static_assert (operator_of (^^S::operator ^) == op_caret);
+static_assert (operator_of (^^S::operator &) == op_ampersand);
+static_assert (operator_of (^^S::operator =) == op_equals);
+static_assert (operator_of (^^S::operator |) == op_pipe);
+static_assert (operator_of (^^S::operator +=) == op_plus_equals);
+static_assert (operator_of (^^S::operator -=) == op_minus_equals);
+static_assert (operator_of (^^S::operator *=) == op_star_equals);
+static_assert (operator_of (^^S::operator /=) == op_slash_equals);
+static_assert (operator_of (^^S::operator %=) == op_percent_equals);
+static_assert (operator_of (^^S::operator ^=) == op_caret_equals);
+static_assert (operator_of (^^S::operator &=) == op_ampersand_equals);
+static_assert (operator_of (^^S::operator |=) == op_pipe_equals);
+static_assert (operator_of (^^S::operator ==) == op_equals_equals);
+static_assert (operator_of (^^S::operator !=) == op_exclamation_equals);
+static_assert (operator_of (^^S::operator <) == op_less);
+static_assert (operator_of (^^S::operator >) == op_greater);
+static_assert (operator_of (^^S::operator <=) == op_less_equals);
+static_assert (operator_of (^^S::operator >=) == op_greater_equals);
+static_assert (operator_of (^^S::operator <=>) == op_spaceship);
+static_assert (operator_of (^^S::operator &&) == op_ampersand_ampersand);
+static_assert (operator_of (^^S::operator ||) == op_pipe_pipe);
+static_assert (operator_of (^^S::operator <<) == op_less_less);
+static_assert (operator_of (^^S::operator >>) == op_greater_greater);
+static_assert (operator_of (^^S::operator <<=) == op_less_less_equals);
+static_assert (operator_of (^^S::operator >>=) == op_greater_greater_equals);
+static_assert (operator_of (^^S::operator ++) == op_plus_plus);
+static_assert (operator_of (^^S::operator --) == op_minus_minus);
+static_assert (operator_of (^^S::operator ,) == op_comma);
+static_assert (operator_of (^^T::operator +) == op_plus);
+static_assert (operator_of (^^T::operator -) == op_minus);
+static_assert (operator_of (^^T::operator ++) == op_plus_plus);
+static_assert (operator_of (^^T::operator --) == op_minus_minus);
+static_assert (operator_of (^^U::operator compl) == op_tilde);
+static_assert (operator_of (^^U::operator not) == op_exclamation);
+static_assert (operator_of (^^U::operator bitand) == op_ampersand);
+static_assert (operator_of (^^U::operator bitor) == op_pipe);
+static_assert (operator_of (^^U::operator xor_eq) == op_caret_equals);
+static_assert (operator_of (^^U::operator and_eq) == op_ampersand_equals);
+static_assert (operator_of (^^U::operator or_eq) == op_pipe_equals);
+static_assert (operator_of (^^U::operator and) == op_ampersand_ampersand);
+static_assert (operator_of (^^U::operator or) == op_pipe_pipe);
+static_assert (operator_of (^^U::operator ()) == op_parentheses);
+static_assert (operator_of (^^U::operator []) == op_square_brackets);
+static_assert (operator_of (^^W::operator new) == op_new);
+static_assert (operator_of (^^W::operator delete) == std::meta::op_delete);
+static_assert (operator_of (^^W::operator new[]) == std::meta::operators::op_array_new);
+static_assert (operator_of (^^W::operator delete[]) == op_array_delete);
+static_assert (operator_of (^^W::operator co_await) == op_co_await);
+static_assert (operator_of (^^W::operator ()) == op_parentheses);
+static_assert (operator_of (^^W::operator []) == op_square_brackets);
+static_assert (operator_of (^^W::operator ->) == op_arrow);
+static_assert (operator_of (^^W::operator ->*) == op_arrow_star);
+static_assert (operator_of (^^W::operator ~) == op_tilde);
+static_assert (operator_of (^^W::operator !) == op_exclamation);
+static_assert (operator_of (^^W::operator +) == op_plus);
+static_assert (operator_of (^^W::operator -) == op_minus);
+static_assert (operator_of (^^W::operator *) == op_star);
+static_assert (operator_of (^^W::operator /) == op_slash);
+static_assert (operator_of (^^W::operator %) == op_percent);
+static_assert (operator_of (^^W::operator ^) == op_caret);
+static_assert (operator_of (^^W::operator &) == op_ampersand);
+static_assert (operator_of (template_of (^^W::operator = <0>)) == op_equals);
+static_assert (operator_of (^^W::operator |) == op_pipe);
+static_assert (operator_of (^^W::operator +=) == op_plus_equals);
+static_assert (operator_of (^^W::operator -=) == op_minus_equals);
+static_assert (operator_of (^^W::operator *=) == op_star_equals);
+static_assert (operator_of (^^W::operator /=) == op_slash_equals);
+static_assert (operator_of (^^W::operator %=) == op_percent_equals);
+static_assert (operator_of (^^W::operator ^=) == op_caret_equals);
+static_assert (operator_of (^^W::operator &=) == op_ampersand_equals);
+static_assert (operator_of (^^W::operator |=) == op_pipe_equals);
+static_assert (operator_of (^^W::operator ==) == op_equals_equals);
+static_assert (operator_of (^^W::operator !=) == op_exclamation_equals);
+static_assert (operator_of (^^W::operator <) == op_less);
+static_assert (operator_of (^^W::operator >) == op_greater);
+static_assert (operator_of (^^W::operator <=) == op_less_equals);
+static_assert (operator_of (^^W::operator >=) == op_greater_equals);
+static_assert (operator_of (^^W::operator <=>) == op_spaceship);
+static_assert (operator_of (^^W::operator &&) == op_ampersand_ampersand);
+static_assert (operator_of (^^W::operator ||) == op_pipe_pipe);
+static_assert (operator_of (^^W::operator <<) == op_less_less);
+static_assert (operator_of (^^W::operator >>) == op_greater_greater);
+static_assert (operator_of (^^W::operator <<=) == op_less_less_equals);
+static_assert (operator_of (^^W::operator >>=) == op_greater_greater_equals);
+static_assert (operator_of (^^W::operator ++) == op_plus_plus);
+static_assert (operator_of (^^W::operator --) == op_minus_minus);
+static_assert (operator_of (^^W::operator ,) == op_comma);
+static_assert (operator_of (^^X::operator +) == op_plus);
+static_assert (operator_of (^^X::operator -) == op_minus);
+static_assert (operator_of (^^X::operator ++) == op_plus_plus);
+static_assert (operator_of (^^X::operator --) == op_minus_minus);
diff --git a/gcc/testsuite/g++.dg/reflect/override1.C b/gcc/testsuite/g++.dg/reflect/override1.C
new file mode 100644 (file)
index 0000000..d3124f5
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// CWG 3117 - Overriding by a consteval virtual function
+
+using info = decltype(^^::);
+
+struct B {
+  virtual void foo();
+};
+
+struct D1 : B {
+  consteval virtual void foo() override { } // { dg-error "overriding" }
+};
+
+struct D2 : B {
+  info i;
+  consteval virtual void foo() override { }
+};
+
+struct D3 : B {
+  virtual void foo() override { }
+};
+
+struct B2 {
+  consteval virtual void foo() { }
+};
+
+struct D4 : B2 {
+  consteval virtual void foo() override { }
+};
+
+struct D5 : B2 {
+  virtual void foo() override { } // { dg-error "overriding" }
+};
+
+struct D6 : B2 {
+  info i;
+  virtual void foo() override { } // { dg-error "consteval-only type|overriding" }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-1.C b/gcc/testsuite/g++.dg/reflect/p2996-1.C
new file mode 100644 (file)
index 0000000..d89b9b0
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from the P2996 paper.
+
+#include <meta>
+
+static_assert(std::meta::is_type(^^int()));  // ^^ applies to the type-id "int()"
+
+template<bool> struct X {};
+consteval bool operator<(std::meta::info, X<false>) { return false; }
+consteval void g(std::meta::info r, X<false> xv) {
+  r == ^^int && true;    // { dg-error "expected" }
+  r == ^^int & true;     // { dg-error "expected" }
+  r == (^^int) && true;  // OK
+  r == ^^int &&&& true;  // { dg-error "expected|cannot declare" }
+  ^^X < xv;              // { dg-error "could not convert" }
+                        // error: reflect-expression whose terminal name is a
+                         // template-name is followed by <
+  (^^X) < xv;            // OK
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-10.C b/gcc/testsuite/g++.dg/reflect/p2996-10.C
new file mode 100644 (file)
index 0000000..d3369e2
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [dcl.type.splice].
+
+struct S { using type = int; };
+template <auto R> struct TCls {
+  typename [:R:]::type member;  // typename applies to the qualified name
+};
+
+void fn() {
+  [:^^S::type:] *var;           // { dg-error "expected a reflection of an expression|not declared" }
+  typename [:^^S::type:] *var;  // OK, declares variable with type int*
+}
+
+using alias = [:^^S::type:];    // OK, type-only context
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-11.C b/gcc/testsuite/g++.dg/reflect/p2996-11.C
new file mode 100644 (file)
index 0000000..5341f1f
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.prim.id.qual].
+
+template<int V>
+struct TCls {
+  static constexpr int s = V;
+  using type = int;
+};
+
+int v1 = [:^^TCls<1>:]::s;
+int v2 = template [:^^TCls:]<2>::s;        // OK, template binds to splice-scope-specifier
+typename [:^^TCls:]<3>::type v3 = 3;       // OK, typename binds to the qualified name
+template [:^^TCls:]<3>::type v4 = 4;       // OK, template binds to the splice-scope-specifier
+typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as v3
+[:^^TCls:]<3>::type v6 = 6;      // { dg-error "missing .template.|expected" }
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-12.C b/gcc/testsuite/g++.dg/reflect/p2996-12.C
new file mode 100644 (file)
index 0000000..58a1456
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [basic.splice].
+
+using info = decltype(^^int);
+
+constexpr int v = 1;
+template<int V> struct TCls {
+  static constexpr int s = V + 1;
+};
+
+// OK, a splice-specialization-specifier with a splice-expression as a template argument
+using alias = [:^^TCls:]<([:^^v:])>;
+
+static_assert(alias::s == 2);
+
+// error: < means less than
+auto o1 = [:^^TCls:]<([:^^v:])>();  // { dg-error "reflection .TCls<1>. not usable" }
+// OK, o2 is an object of type TCls<1>
+auto o2 = typename [:^^TCls:]<([:^^v:])>();
+
+consteval int bad_splice(info v) {
+  return [:v:];          // { dg-error ".v. is not a constant expression" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-13.C b/gcc/testsuite/g++.dg/reflect/p2996-13.C
new file mode 100644 (file)
index 0000000..5d95871
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.prim.req.type].
+
+template<typename T, typename T::type = 0> struct S;
+template<typename T> using Ref = T&;
+template<typename T> concept C = requires {
+  typename T::inner;
+  // required nested member name
+  typename S<T>;
+  // required valid (13.3) template-id; fails if T::type does not exist as a type
+  // to which 0 can be implicitly converted
+  typename Ref<T>;
+  // required alias template substitution, fails if T is void
+  typename [:T::r1:];
+  // fails if T::r1 is not a reflection of a type
+  typename [:T::r2:]<int>;
+  // fails if T::r2 is not a reflection of a template Z for which Z<int> is a type
+};
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-14.C b/gcc/testsuite/g++.dg/reflect/p2996-14.C
new file mode 100644 (file)
index 0000000..33c7d89
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.reflect]/5.
+
+using info = decltype(^^void);
+
+struct A { struct S {}; };
+struct B : A { using A::S; };
+constexpr info r1 = ^^B::S;    // { dg-error "cannot be applied to a using-declaration" }
+struct C : virtual B { struct S {}; };
+struct D : virtual B, C {};
+D::S s;
+constexpr info r2 = ^^D::S;// OK, names C::S per 6.5.2
+// OK, result C::S not found through using-declarator
+
+struct E : A { };
+constexpr info r3 = ^^E::S;
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-15.C b/gcc/testsuite/g++.dg/reflect/p2996-15.C
new file mode 100644 (file)
index 0000000..3ced176
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.const].
+
+using info = decltype(^^int);
+
+struct Base { };
+struct Derived : Base { info r; };
+
+consteval const Base& fn(const Derived& derived) { return derived; }
+
+constexpr Derived obj{.r=^^::}; // OK
+constexpr const Derived& d = obj; // OK
+constexpr const Base& b1 = fn(obj); // { dg-error "reference into an object of consteval-only" }
+constexpr const Base& b2 = obj;          // { dg-error "reference into an object of consteval-only" }
+constexpr Base b3 = obj;
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-16.C b/gcc/testsuite/g++.dg/reflect/p2996-16.C
new file mode 100644 (file)
index 0000000..91506d3
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// List of Types to List of Sizes
+
+#include <algorithm>
+#include <array>
+#include <meta>
+#include <ranges>
+
+constexpr std::array types = {^^int, ^^float, ^^double};
+constexpr std::array sizes = []{
+  std::array<std::size_t, types.size()> r;
+  std::ranges::transform(types, r.begin(), std::meta::size_of);
+  return r;
+}();
+static_assert (sizes[0] == sizeof (int));
+static_assert (sizes[1] == sizeof (float));
+static_assert (sizes[2] == sizeof (double));
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-17.C b/gcc/testsuite/g++.dg/reflect/p2996-17.C
new file mode 100644 (file)
index 0000000..e9dabb0
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r13.html#compile-time-ticket-counter
+
+#include <meta>
+
+template<int N> struct Helper;
+
+struct TU_Ticket {
+  static consteval int latest ()
+  {
+    int k = 0;
+    while (is_complete_type (substitute (^^Helper,
+                                        { std::meta::reflect_constant (k) })))
+      ++k;
+    return k;
+  }
+  static consteval void increment ()
+  {
+    define_aggregate (substitute (^^Helper,
+                                 { std::meta::reflect_constant (latest ()) }),
+                     {});
+  }
+};
+constexpr int x = TU_Ticket::latest ();  // x initialized to 0.
+consteval { TU_Ticket::increment (); }
+constexpr int y = TU_Ticket::latest ();  // y initialized to 1.
+consteval { TU_Ticket::increment (); }
+constexpr int z = TU_Ticket::latest ();  // z initialized to 2.
+static_assert (x == 0);
+static_assert (y == 1);
+static_assert (z == 2);
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-18.C b/gcc/testsuite/g++.dg/reflect/p2996-18.C
new file mode 100644 (file)
index 0000000..ec72e44
--- /dev/null
@@ -0,0 +1,46 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [meta.reflection.access.context].
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A {
+  int a = 0;
+  consteval A(int p) : a(p) {}
+};
+struct B : A {
+  using A::A;
+  consteval B(int p, int q) : A(p * q) {}
+  info s = access_context::current().scope();
+};
+struct C : B { using B::B; };
+
+struct Agg {
+  consteval bool eq(info rhs = access_context::current().scope()) {
+    return s == rhs;
+  }
+  info s = access_context::current().scope();
+};
+
+namespace NS {
+  static_assert(Agg{}.s == access_context::current().scope());              // OK
+  static_assert(Agg{}.eq());                                                // OK
+  static_assert(B(1).s == ^^B);                                             // OK
+  static_assert(is_constructor(B{1, 2}.s) && parent_of(B{1, 2}.s) == ^^B);  // OK
+  static_assert(is_constructor(C{1, 2}.s) && parent_of(C{1, 2}.s) == ^^B);  // OK
+
+  auto fn() -> [:is_namespace(access_context::current().scope()) ? ^^int : ^^bool:];
+  static_assert(return_type_of(type_of(^^fn)) == ^^int);
+  static_assert(type_of(^^fn) == ^^auto()->int);                            // OK
+
+  template<auto R>
+    struct TCls {
+      consteval bool fn()
+        requires (is_type(access_context::current().scope())) {
+          return true;                  // OK, scope is TCls<R>.
+        }
+    };
+  static_assert(TCls<0>{}.fn());        // OK
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-19.C b/gcc/testsuite/g++.dg/reflect/p2996-19.C
new file mode 100644 (file)
index 0000000..e859a08
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [meta.reflection.access.queries].
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval access_context fn() {
+  return access_context::current();
+}
+
+class Cls {
+  int mem;
+  friend consteval access_context fn();
+public:
+  static constexpr auto r = ^^mem;
+};
+
+static_assert(is_accessible(Cls::r, fn()));                             // OK
+static_assert(!is_accessible(Cls::r, access_context::current()));       // OK
+static_assert(is_accessible(Cls::r, access_context::unchecked()));      // OK
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-2.C b/gcc/testsuite/g++.dg/reflect/p2996-2.C
new file mode 100644 (file)
index 0000000..a4edaf4
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from the P2996 paper.
+
+#include <vector>
+
+template <typename T> void fn() requires (^^T != ^^int);
+template <typename T> void fn() requires (^^T == ^^int);
+template <typename T> void fn() requires (sizeof(T) == sizeof(int));
+
+constexpr auto a = ^^fn<char>;     // OK
+constexpr auto b = ^^fn<int>;      // { dg-error "insufficient contextual information to determine type" }
+
+constexpr auto c = ^^std::vector;  // OK
+
+template <typename T>
+struct S {
+  static constexpr auto r = ^^T;
+  using type = T;
+};
+static_assert(S<int>::r == ^^int);
+static_assert(^^S<int>::type != ^^int);
+
+typedef struct X {} Y;
+typedef struct Z {} Z;
+constexpr auto e = ^^Y;  // OK, represents the type alias Y
+constexpr auto f = ^^Z;  // OK, represents the type Z (not the type alias)
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-20.C b/gcc/testsuite/g++.dg/reflect/p2996-20.C
new file mode 100644 (file)
index 0000000..2c87776
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <functional>
+#include <meta>
+#include <utility>
+#include <vector>
+#include <initializer_list>
+#include <tuple>
+
+template<std::pair<std::size_t, std::size_t>... indices>
+struct Indexer {
+   template<typename Tuples>
+   // Can use tuple indexing instead of tuple of tuples
+   constexpr auto operator()(Tuples&& tuples) const {
+     using ResultType = std::tuple<
+       std::tuple_element_t<
+         indices.second,
+         std::remove_cvref_t<std::tuple_element_t<indices.first, std::remove_cvref_t<Tuples>>>
+       >...
+     >;
+     return ResultType(std::get<indices.second>(std::get<indices.first>(std::forward<Tuples>(tuples)))...);
+   }
+};
+
+template <class T>
+consteval auto subst_by_value(std::meta::info tmpl, std::vector<T> args)
+    -> std::meta::info
+{
+    std::vector<std::meta::info> a2;
+    for (T x : args) {
+        a2.push_back(std::meta::reflect_constant(x));
+    }
+
+    return substitute(tmpl, a2);
+}
+
+consteval auto make_indexer(std::vector<std::size_t> sizes)
+    -> std::meta::info
+{
+    std::vector<std::pair<int, int>> args;
+
+    for (std::size_t tidx = 0; tidx < sizes.size(); ++tidx) {
+        for (std::size_t eidx = 0; eidx < sizes[tidx]; ++eidx) {
+            args.push_back({tidx, eidx});
+        }
+    }
+
+    return subst_by_value(^^Indexer, args);
+}
+
+template<typename... Tuples>
+constexpr auto my_tuple_cat(Tuples&&... tuples) {
+    constexpr typename [: make_indexer({tuple_size(remove_cvref(^^Tuples))...}) :] indexer;
+    return indexer(std::forward_as_tuple(std::forward<Tuples>(tuples)...));
+}
+
+int r;
+constexpr auto x = my_tuple_cat(std::make_tuple(10, std::ref(r)), std::make_tuple(21.0, 22, 23, 24));
+static_assert(std::same_as<decltype(x), const std::tuple<int, int&, double, int, int, int>>);
+static_assert(std::get<5>(x) == 24);
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-21.C b/gcc/testsuite/g++.dg/reflect/p2996-21.C
new file mode 100644 (file)
index 0000000..8a9f789
--- /dev/null
@@ -0,0 +1,68 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.const]/31.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S0 {
+  consteval {                                          // { dg-message "'consteval' block defined here" }
+    std::meta::define_aggregate(^^S0, {});             // error: scope associated with S0 encloses the consteval block
+  }                                                    // { dg-error "'define_aggregate' evaluated from 'consteval' block enclosed by 'S0' being defined" "" { target *-*-* } .-1 }
+};
+
+struct S1;
+consteval { std::meta::define_aggregate(^^S1, {}); }   // OK
+
+template <std::meta::info R> consteval void tfn1() {
+  std::meta::define_aggregate(R, {});
+}
+
+struct S2;
+consteval { tfn1<^^S2>(); }                            // OK
+
+template <std::meta::info R> consteval void tfn2() {
+  consteval { std::meta::define_aggregate(R, {}); }    // { dg-error "'consteval void tfn2\\\(\\\) \\\[with std::meta::info R = \\\^\\\^S3\\\]' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'S3' scope" }
+}                                                      // { dg-message "'consteval' block defined here" "" { target *-*-* } .-1 }
+
+struct S3;
+consteval { tfn2<^^S3>(); }
+  // error: function parameter scope of tfn2<^^S3> intervenes between the declaration of S3
+  // and the consteval block that produces the injected declaration
+
+template <typename> struct TCls {
+  struct S4;
+  static void sfn() requires ([] {
+    consteval { std::meta::define_aggregate(^^S4, {}); } // { dg-error "TCls<void>::<lambda\\\(\\\)>' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'TCls<void>::S4' scope" }
+    return true;                                       // { dg-message "'consteval' block defined here" "" { target *-*-* } .-1 }
+  }()) { }
+};
+
+consteval { TCls<void>::sfn(); }       // error: TCls<void>::S4 is not enclosed by requires-clause lambda
+// { dg-error "call to non-'constexpr' function 'static void TCls< <template-parameter-1-1> >::sfn\\\(\\\) requires \\\(<lambda>\\\)\\\(\\\) \\\[with <template-parameter-1-1> = void\\\]'" "" { target *-*-* } .-1 }
+
+struct S5;
+struct Cls {
+  consteval { std::meta::define_aggregate(^^S5, {}); }  // error: S5 is not enclosed by class Cls
+};                                             // { dg-error "'Cls' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'S5' scope" "" { target *-*-* } .-1 }
+                                               // { dg-message "'consteval' block defined here" "" { target *-*-* } .-2 }
+
+struct S6;                                     // { dg-message "'consteval' block defined here" "" { target *-*-* } .+1 }
+consteval {                                    // #1
+  struct S7;                                   // local class
+
+  std::meta::define_aggregate(^^S7, {});       // error: consteval block #1 does not enclose itself,
+                                               // but encloses S7
+                                               // { dg-error "'define_aggregate' evaluated from 'consteval' block which encloses '<lambda\\\(\\\)> static::S7' being defined" "" { target *-*-* } .-2 }
+
+  struct S8;
+  consteval {                                  // #2
+    std::meta::define_aggregate(^^S6, {});     // error: consteval block #1 encloses
+                                               // consteval block #2 but not S6
+                                               // { dg-error "'<lambda\\\(\\\)> static' intervenes between 'consteval' block 'define_aggregate' is evaluated from and 'S6' scope" "" { target *-*-* } .-2 }
+                                               // { dg-message "'consteval' block defined here" "" { target *-*-* } .-4 }
+
+    std::meta::define_aggregate(^^S8, {});     // OK, consteval block #1 encloses both #2 and S8
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-3.C b/gcc/testsuite/g++.dg/reflect/p2996-3.C
new file mode 100644 (file)
index 0000000..c61bb02
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test that was in [expr.prim.id.qual].
+
+template <int V>
+struct TCls {
+  static constexpr int s = V;
+  using type = int;
+};
+
+constexpr int v1 = [:^^TCls<1>:]::s;
+static_assert (v1 == 1);
+constexpr int v2 = template [:^^TCls:]<2>::s;
+  // OK, template binds to splice-scope-specifier
+static_assert (v2 == 2);
+
+constexpr typename [:^^TCls:]<3>::type v3 = 3;
+  // OK, typename binds to the qualified name
+static_assert (v3 == 3);
+
+constexpr [:^^TCls:]<3>::type v4 = 4; // { dg-error "missing .template.|expected" }
+  // error: [:^^TCls:]< is parsed as a splice-expression followed
+  // by a comparison operator
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-4.C b/gcc/testsuite/g++.dg/reflect/p2996-4.C
new file mode 100644 (file)
index 0000000..4d0ee97
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.prim.splice].
+
+struct S { static constexpr int a = 1; };
+template <typename> struct TCls { static constexpr int b = 2; };
+
+constexpr int c = [:^^S:]::a;                   // [:^^S:] is not an expression
+static_assert(c == 1);
+
+constexpr int d = template [:^^TCls:]<int>::b;  // template [:^^TCls:]<int> is not
+                                                // an expression
+static_assert(d == 2);
+
+template <auto V> constexpr int e = [:V:];   // splice-expression
+constexpr int f1 = e<^^S::a>;  // splice-expression
+constexpr int f2 = template [:^^e:]<^^S::a>;  // splice-expression
+static_assert(f1 == 1);
+static_assert(f2 == 1);
+
+constexpr auto g = typename [:^^int:](42);
+  // [:^^int:] forms part of a type, not a splice-expression
+static_assert(g == 42);
+
+constexpr auto h = ^^g;
+constexpr auto i = e<[:^^h:]>;   // { dg-error "unparenthesized splice|invalid" }
+constexpr auto j = e<([:^^h:])>;
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-5.C b/gcc/testsuite/g++.dg/reflect/p2996-5.C
new file mode 100644 (file)
index 0000000..e9bbbc9
--- /dev/null
@@ -0,0 +1,50 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [basic.fundamental].
+
+#include <meta>
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+template <auto> struct TCls {};
+template <auto> void TFn();
+template <auto> int TVar;
+template <auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+constexpr auto r1 = std::meta::reflect_constant(42);  // represents int value of 42
+
+constexpr auto r2 = std::meta::reflect_object(arr[1]);  // represents int object
+
+constexpr auto r3 = ^^arr;      // represents a variable
+constexpr auto r4 = ^^a3;       // represents a structured binding
+constexpr auto r5 = ^^fn;       // represents a function
+constexpr auto r6 = ^^Enum::A;  // represents an enumerator
+constexpr auto r7 = ^^Alias;    // represents a type alias
+constexpr auto r8 = ^^S;        // represents a type
+constexpr auto r9 = ^^S::mem;   // represents a class member
+
+constexpr auto r10 = std::meta::members_of (^^S, std::meta::access_context::current ())[1];
+    // represents an unnamed bit-field
+
+constexpr auto r11 = ^^TCls;     // represents a class template
+constexpr auto r12 = ^^TFn;      // represents a function template
+constexpr auto r13 = ^^TVar;     // represents a variable template
+constexpr auto r14 = ^^Concept;  // represents a concept
+constexpr auto r15 = ^^NSAlias;  // represents a namespace alias
+constexpr auto r16 = ^^NS;       // represents a namespace
+
+constexpr auto r17 = std::meta::bases_of(^^S, std::meta::access_context::current ())[0];
+    // represents a direct base class relationship
+
+constexpr auto r18 = std::meta::data_member_spec(^^int, {.name="member"});
+    // represents a data member description
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-6.C b/gcc/testsuite/g++.dg/reflect/p2996-6.C
new file mode 100644 (file)
index 0000000..4f98e21
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [temp.dep.splice].
+
+template <auto T, auto NS>
+void fn() {
+  using a = [:T:]<1>;  // [:T:] and [:T:]<1> are dependent
+
+  static_assert([:NS:]::template TCls<1>::v == a::v);  // [:NS:] is dependent
+}
+
+namespace NS {
+template <auto V> struct TCls { static constexpr int v = V; };
+}
+
+int main() {
+  fn<^^NS::TCls, ^^NS>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-7.C b/gcc/testsuite/g++.dg/reflect/p2996-7.C
new file mode 100644 (file)
index 0000000..6d9a632
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [temp.dep.namespace].
+
+using info = decltype(^^int);
+
+template <info R> int fn() {
+  namespace Alias = [:R:];  // [:R:] is dependent
+  return Alias::v;  // Alias is dependent
+}
+
+namespace NS {
+  int v = 1;
+}
+
+int a = fn<^^NS>();
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-8.C b/gcc/testsuite/g++.dg/reflect/p2996-8.C
new file mode 100644 (file)
index 0000000..38a9db4
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [temp.dep.splice].
+
+template<template<class> class X>
+struct S {
+  typename [: ^^X :]<int, float> m; // { dg-error "wrong number of template arguments" }
+};
+
+template<class> struct V1 {};
+template<class, class = int> struct V2 {};
+
+S<V1> s1; // { dg-message "required from here" }
+S<V2> s2; // OK
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-9.C b/gcc/testsuite/g++.dg/reflect/p2996-9.C
new file mode 100644 (file)
index 0000000..6b659cc
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [over.match.viable].
+// FIXME We should give the errors below.
+
+namespace A {
+  extern "C" void f(int = 5);
+}
+namespace B {
+  extern "C" void f(int = 5);
+}
+
+void splice() {
+  [:^^A::f:](3);  // OK, default argument was not used for viability
+  [:^^A::f:]();   // error: found default argument twice
+}
+
+using A::f;
+using B::f;
+
+void use() {
+  f(3);           // OK, default argument was not used for viability
+  f();            // error: found default argument twice
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p3394-1.C b/gcc/testsuite/g++.dg/reflect/p3394-1.C
new file mode 100644 (file)
index 0000000..23e676f
--- /dev/null
@@ -0,0 +1,174 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Slightly tweaked test from P3394R4 3.2
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3394r4.html#test-parametrization
+// TODO: Doesn't link currently, once it does, it should be dg-do run test
+// with output checking or something like that.
+
+#include <meta>
+#include <array>
+#include <print>
+
+namespace impl {
+  template <auto... vals>
+  struct replicator_type {
+    template <typename F>
+    constexpr void operator >> (F body) const
+    {
+      (body.template operator () <vals> (), ...);
+    }
+  };
+
+  template <auto... vals>
+  replicator_type <vals...> replicator = {};
+}
+
+template <typename R>
+consteval auto
+expand (R range)
+{
+  std::vector<std::meta::info> args;
+  for (auto r : range)
+    args.push_back (std::meta::reflect_constant (r));
+  return substitute (^^impl::replicator, args);
+}
+
+template <size_t N, class F>
+constexpr decltype (auto)
+with_indices (F f)
+{
+  return [&] <size_t... Is> (std::index_sequence <Is...>) -> decltype (auto) {
+          return f(std::integral_constant<size_t, Is>{}...);
+        }  (std::make_index_sequence <N> {});
+}
+
+template <typename... Ts>
+struct Tuple {
+  struct storage;
+  consteval {
+    define_aggregate (^^storage, { data_member_spec (^^Ts, { .name = "_" })... });
+  }
+  static constexpr auto ctx = std::meta::access_context::current ();
+  static constexpr auto nsdms
+    = define_static_array (nonstatic_data_members_of (^^storage, ctx));
+
+  storage s;
+
+  template <class F>
+  decltype (auto) apply (F f)
+  {
+    return with_indices <sizeof... (Ts)> ([&] (auto... Is) -> decltype (auto) {
+                                           return f (s.[: nsdms[Is] :]...);
+                                         });
+  }
+};
+
+template <typename... Ts>
+Tuple (Ts...) -> Tuple <Ts...>;
+
+template <size_t N, typename... Ts>
+struct Parametrize {
+  Tuple <Ts...> arr[N];
+  auto begin () const { return arr; }
+  auto end () const { return arr + N; }
+};
+
+template <typename... Ts, size_t N>
+constexpr auto
+parametrize (Tuple<Ts...> (&&arr) [N])
+{
+  return with_indices <N> ([&] (auto... Is) {
+                            return Parametrize <N, Ts...> { { arr[Is]... } };
+                          });
+}
+
+consteval auto
+nonstatic_member_functions_of (std::meta::info type)
+{
+  auto ctx = std::meta::access_context::current ();
+  auto members = members_of (type, ctx);
+  std::erase_if (members, [] (std::meta::info m) {
+                           return not (is_function (m)
+                                       and not is_static_member (m)
+                                       and not is_special_member_function (m));
+                         });
+  return members;
+}
+
+consteval std::meta::info
+parametrization_of (std::meta::info M)
+{
+  for (auto a : annotations_of (M))
+    {
+      auto t = type_of (a);
+      if (has_template_arguments (t) and template_of (t) == ^^Parametrize)
+       return a;
+    }
+  return std::meta::info ();
+}
+
+template <std::meta::info M, class F>
+void
+invoke_single_test (F f)
+{
+  constexpr auto A = parametrization_of (M);
+
+  if constexpr (A != std::meta::info ())
+    {
+      constexpr auto Params = extract <typename [: type_of (A) :]> (A);
+      for (auto P : Params)
+       P.apply (f);
+    }
+  else
+    f ();
+}
+
+template <std::meta::info M>
+void
+invoke_single_test ()
+{
+  invoke_single_test <M> ([: M :]);
+}
+
+template <std::meta::info Namespace>
+void
+invoke_all ()
+{
+  [: expand (members_of (Namespace, std::meta::access_context::current ())) :]
+    >> [] <std::meta::info M> {
+        if constexpr (is_function(M) and identifier_of (M).starts_with ("test_"))
+          invoke_single_test <M> ();
+        else if constexpr (is_type (M))
+          [: expand (nonstatic_member_functions_of (M)) :]
+            >> [] <std::meta::info F> {
+                 if constexpr (identifier_of (F).starts_with ("test_"))
+                   invoke_single_test <F> ([&] (auto... args) {
+                                             typename [: M :] fixture;
+                                             fixture.[: F :] (args...);
+                                           });
+               };
+       };
+}
+
+namespace N
+{
+  [[=parametrize ({ Tuple {1, 1, 2}, Tuple {1, 2, 3} })]]
+  void test_sum (int x, int y, int z)
+  {
+    std::println ("Called test_sum (x={}, y={}, z={})", x, y, z);
+  }
+
+  struct Fixture {
+    Fixture () { std::println ("setup fixture"); }
+    ~Fixture() { std::println ("teardown fixture"); }
+    [[=parametrize ({ Tuple {1}, Tuple {2} })]]
+    void test_one (int x) { std::println ("test one({})", x); }
+    void test_two () { std::println("test two"); }
+  };
+}
+
+int
+main ()
+{
+  invoke_all <^^N> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/p3491-1.C b/gcc/testsuite/g++.dg/reflect/p3491-1.C
new file mode 100644 (file)
index 0000000..d8e5722
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from P3491R3 3.3
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3491r3.html#return-type-and-layering
+
+#include <meta>
+#include <ranges>
+#include <type_traits>
+
+template <std::size_t N>
+struct FixedString {
+  char data[N] = {};
+
+  constexpr FixedString (char const (&str) [N]) { std::ranges::copy (str, str + N, data); }
+};
+
+template <FixedString S>
+struct Test { };
+
+using A = Test <"foo">;
+using E = Test <([: std::meta::reflect_constant_string ("foo") :])>;
+using F = [: substitute (^^Test, { std::meta::reflect_constant_string ("foo") }) :];
+
+static_assert (std::is_same_v <A, E>);
+static_assert (std::is_same_v <A, F>);
diff --git a/gcc/testsuite/g++.dg/reflect/p3491-2.C b/gcc/testsuite/g++.dg/reflect/p3491-2.C
new file mode 100644 (file)
index 0000000..b0de7a9
--- /dev/null
@@ -0,0 +1,50 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from P3491R3 3.5.4
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3491r3.html#with-expansion-statements
+
+#include <meta>
+#include <ranges>
+#include <type_traits>
+
+constexpr auto foo() -> std::vector<int> { return {1, 2, 3}; }
+
+consteval void bar() {
+    template for (constexpr int I : foo()) {
+        // doesn't work
+    }          // { dg-error "modification of '<temporary>' from outside current evaluation is not a constant expression" }
+}
+
+consteval int baz() {
+    int r = 0;
+#if 0
+    // TODO: This doesn't work yet.
+    template for (constexpr int I : std::define_static_array(foo())) {
+       r += I;
+    }
+#else
+    // Ugly workaround for that.
+    template for (constexpr int I : (const std::span<const int>)std::define_static_array(foo())) {
+       r += I;
+    }
+#endif
+    return r;
+}
+
+consteval int qux() {
+    int r = 0;
+    template for (constexpr int I : [: std::meta::reflect_constant_array(foo()) :]) {
+        r += I;
+    }
+    return r;
+}
+
+template <typename>
+consteval int fred() {
+    constexpr auto [...m] = [: std::meta::reflect_constant_array(foo()) :];
+    return (... + m);
+}
+
+static_assert (baz() == 6);
+static_assert (qux() == 6);
+static_assert (fred<int>() == 6);
diff --git a/gcc/testsuite/g++.dg/reflect/p3491-3.C b/gcc/testsuite/g++.dg/reflect/p3491-3.C
new file mode 100644 (file)
index 0000000..77d16b8
--- /dev/null
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from P3491R3 3.5.5
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3491r3.html#implementing-source_location
+
+#include <meta>
+
+class source_location {
+    struct impl {
+       char const* filename;
+       int line;
+    };
+    impl const* p_;
+    constexpr source_location(impl const* x) noexcept : p_{x} {}
+
+public:
+    static consteval auto current(char const* file = __builtin_FILE(),
+                                 int line = __builtin_LINE()) noexcept
+       -> source_location
+    {
+       // first, we canonicalize the file
+       // Note, the paper uses just define_static_string(file), but that
+       // doesn't work, char const* argument isn't a valid input_range.
+       impl data = {.filename = std::define_static_string(std::string_view(file)), .line = line};
+
+       // then we canonicalize the data
+       impl const* p = std::define_static_object(data);
+
+       // and now we have an external linkage object mangled with this location
+       return source_location{p};
+    }
+    constexpr source_location() noexcept : p_{nullptr} { }
+    constexpr int line() const noexcept { return p_ ? p_->line : 0; }
+    constexpr const char* file_name() const noexcept { return p_ ? p_->filename : ""; }
+};
+
+static_assert (::source_location::current ().line() == std::source_location::current ().line ());
+static_assert (::source_location::current ().line() == std::source_location::current ().line ());
+static_assert (::source_location::current ().line()
+              == std::source_location::current ().line () - 1);
+static_assert (std::string_view (::source_location::current ().file_name ())
+              == std::string_view (std::source_location::current ().file_name ()));
+static_assert (::source_location().line() == 0);
+static_assert (std::string_view (::source_location ().file_name ())
+              == std::string_view (""));
diff --git a/gcc/testsuite/g++.dg/reflect/pack-index1.C b/gcc/testsuite/g++.dg/reflect/pack-index1.C
new file mode 100644 (file)
index 0000000..f68705b
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections and pack indexing.
+
+struct S {
+  int x;
+  static int sx;
+  using type = int;
+};
+
+template<typename... Ts>
+void
+f ()
+{
+  constexpr auto r1 = ^^Ts...[0]::sx;
+  constexpr auto r2 = ^^typename Ts...[0]::type;
+
+  // NTTPs and pack-index-expressions cannot appear as operands
+  // of the reflection operator.
+  constexpr auto e = ^^Ts...[0]; // { dg-error "cannot be applied" }
+}
+
+
+void
+g ()
+{
+  f<S>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of1.C b/gcc/testsuite/g++.dg/reflect/parameters_of1.C
new file mode 100644 (file)
index 0000000..eb5481e
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::parameters_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<class, class> struct same_type;
+template<class T> struct same_type<T, T> {};
+
+void fun (int, float, double, char);
+
+consteval void
+f ()
+{
+  auto parms = parameters_of (^^fun);
+
+  same_type<decltype(parms), std::vector<info>>();
+
+  constexpr auto p0 = parameters_of (^^fun)[0];
+  static_assert (is_function_parameter (p0));
+  constexpr auto p1 = parameters_of (^^fun)[1];
+  static_assert (is_function_parameter (p1));
+  constexpr auto p2 = parameters_of (^^fun)[2];
+  static_assert (is_function_parameter (p2));
+  constexpr auto p3 = parameters_of (^^fun)[3];
+  static_assert (is_function_parameter (p3));
+}
+
+void
+g ()
+{
+  f ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of2.C b/gcc/testsuite/g++.dg/reflect/parameters_of2.C
new file mode 100644 (file)
index 0000000..3cccfab
--- /dev/null
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::parameters_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+void fn0 ();
+void fn1 (int);
+void fn2 (int, int);
+void fn3 (int, int, int);
+void fn4 (int, int, int, int);
+template<typename... Ts>
+void tfn (Ts...);
+
+static_assert (parameters_of (^^void()).size() == 0);
+static_assert (parameters_of (^^void(void)).size() == 0);
+static_assert (parameters_of (^^void(...)).size() == 0);
+static_assert (parameters_of (^^void(int)).size() == 1);
+static_assert (parameters_of (^^void(int, ...)).size() == 1);
+static_assert (parameters_of (^^void(int, int)).size() == 2);
+static_assert (parameters_of (^^void(int, int, ...)).size() == 2);
+static_assert (parameters_of (^^void(int, int, int)).size() == 3);
+static_assert (parameters_of (^^void(int, int, int, ...)).size() == 3);
+static_assert (parameters_of (^^void(int, int, int, int)).size() == 4);
+static_assert (parameters_of (^^void(int, int, int, int, ...)).size() == 4);
+static_assert (parameters_of (^^void(int, int, int, int, int)).size() == 5);
+static_assert (parameters_of (^^void(int, int, int, int, int, ...)).size() == 5);
+static_assert (parameters_of (^^void(int, int, int, int, int, int)).size() == 6);
+static_assert (parameters_of (^^void(int, int, int, int, int, int, ...)).size() == 6);
+static_assert (parameters_of (^^void(int, int, int, int, int, int, int)).size() == 7);
+static_assert (parameters_of (^^void(int, int, int, int, int, int, int, ...)).size() == 7);
+
+static_assert (parameters_of (^^fn0).size() == 0);
+static_assert (parameters_of (^^fn1).size() == 1);
+static_assert (parameters_of (^^fn2).size() == 2);
+static_assert (parameters_of (^^fn3).size() == 3);
+static_assert (parameters_of (^^fn4).size() == 4);
+
+static_assert (parameters_of (^^tfn<>).size() == 0);
diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of3.C b/gcc/testsuite/g++.dg/reflect/parameters_of3.C
new file mode 100644 (file)
index 0000000..3bb2a2c
--- /dev/null
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::parameters_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+void lox (int = 0, int = 0, int = 0);
+static_assert (parameters_of (^^lox).size() == 3);
+
+struct C {
+  ~C();
+  void foo (int, bool = false);
+  bool bar (this C &self, int, ...);
+  static C &baz (int, ...);
+  using U = void(int, int, int);
+};
+
+static_assert (parameters_of (^^C::foo).size() == 2);
+static_assert (parameters_of (^^C::bar).size() == 2);
+static_assert (parameters_of (^^C::baz).size() == 1);
+static_assert (parameters_of (^^C::~C).size() == 0);
+
+template<typename... Ts>
+void pack (Ts...) { }
+static_assert (parameters_of (^^pack<>).size() == 0);
+static_assert (parameters_of (^^pack<int>).size() == 1);
+static_assert (parameters_of (^^pack<int, char>).size() == 2);
+static_assert (parameters_of (^^pack<int, char, float>).size() == 3);
+static_assert (parameters_of (^^pack<int, char, float, unsigned>).size() == 4);
+static_assert (parameters_of (^^pack<int, char, float, unsigned, short>).size() == 5);
+
+void fn (int a, bool b);
+void fn (int a, bool b = false);
+void fn (int a, bool b);
+static_assert (parameters_of (^^fn).size() == 2);
+
+using A = void(int, int);
+static_assert (parameters_of (dealias(^^A)).size() == 2);
+static_assert (parameters_of (dealias(^^C::U)).size() == 3);
diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of4.C b/gcc/testsuite/g++.dg/reflect/parameters_of4.C
new file mode 100644 (file)
index 0000000..a5b4230
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::parameters_of.
+
+#include <meta>
+
+template<auto R> void foo () {}  // { dg-message "sorry, unimplemented: mangling" }
+void
+g ()
+{
+  foo<std::meta::parameters_of(^^g)[0]>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of5.C b/gcc/testsuite/g++.dg/reflect/parameters_of5.C
new file mode 100644 (file)
index 0000000..0519189
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::parameters_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct C {
+  ~C();
+};
+
+consteval void
+f1 ()
+{
+  parameters_of (^^C);
+}
+
+consteval bool
+test1 ()
+{
+  try { f1 (); }
+  catch (std::meta::exception &) { return true; }
+  catch (...) { return false; }
+  return false;
+}
+
+consteval void
+f2 ()
+{
+  parameters_of (^^int);
+}
+
+consteval bool
+test2 ()
+{
+  try { f2 (); }
+  catch (std::meta::exception &) { return true; }
+  catch (...) { return false; }
+  return false;
+}
+
+static_assert (test1 () && test2 ());
diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of6.C b/gcc/testsuite/g++.dg/reflect/parameters_of6.C
new file mode 100644 (file)
index 0000000..0fbeee3
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+constexpr auto x = ^^std::meta::type_of;
+constexpr auto m = parameters_of(x)[0];
+static_assert (std::meta::type_of (m) == dealias (^^std::meta::info));
diff --git a/gcc/testsuite/g++.dg/reflect/parent_of1.C b/gcc/testsuite/g++.dg/reflect/parent_of1.C
new file mode 100644 (file)
index 0000000..38b6b2d
--- /dev/null
@@ -0,0 +1,238 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::parent_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+consteval bool
+has_parent_of (info r)
+{
+  try { parent_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_parent_of (null_reflection));
+static_assert (!has_parent_of (^^::));
+static_assert (parent_of (^^ns) == ^^::);
+static_assert (parent_of (^^std) == ^^::);
+static_assert (parent_of (^^ns_alias) == ^^::);
+static_assert (!has_parent_of (reflect_constant (3)));
+static_assert (parent_of (^^cls) == ^^::);
+static_assert (parent_of (^^cls::dm) == ^^cls);
+static_assert (parent_of (^^cls::ref_dm) == ^^cls);
+static_assert (parent_of (^^cls::static_dm) == ^^cls);
+static_assert (parent_of (^^cls::mem_fun) == ^^cls);
+static_assert (parent_of (^^cls::static_mem_fun) == ^^cls);
+static_assert (parent_of (^^cls::type) == ^^cls);
+static_assert (parent_of (^^cls_var) == ^^::);
+static_assert (parent_of (^^onion) == ^^::);
+static_assert (is_union_type (parent_of (^^anon)));
+static_assert (parent_of (parent_of (^^anon)) == ^^::);
+static_assert (parent_of (^^fun) == ^^::);
+static_assert (parent_of (^^alias) == ^^::);
+static_assert (parent_of (^^var) == ^^::);
+static_assert (parent_of (^^ref) == ^^::);
+static_assert (parent_of (^^rref) == ^^::);
+static_assert (parent_of (^^ptr) == ^^::);
+static_assert (parent_of (^^cls_tmpl) == ^^::);
+static_assert (parent_of (^^cls_tmpl<int>) == ^^::);
+static_assert (parent_of (^^incomplete_cls<int>) == ^^::);
+static_assert (parent_of (^^fun_tmpl) == ^^::);
+static_assert (parent_of (^^fun_tmpl<int>) == ^^::);
+static_assert (parent_of (^^conc) == ^^::);
+static_assert (!has_parent_of (substitute (^^conc, { ^^int })));
+static_assert (parent_of (^^var_tmpl) == ^^::);
+static_assert (parent_of (^^var_tmpl<int>) == ^^::);
+static_assert (parent_of (^^cls_tmpl_alias) == ^^::);
+static_assert (parent_of (^^cls_tmpl_alias<int>) == ^^::);
+static_assert (parent_of (^^Enum) == ^^::);
+static_assert (parent_of (^^Enum::A) == ^^Enum);
+static_assert (parent_of (^^A) == ^^Enum);
+static_assert (parent_of (^^Enum_class) == ^^::);
+static_assert (parent_of (^^Enum_class::A) == ^^Enum_class);
+static_assert (parent_of (^^decomp) == ^^::);
+static_assert (parent_of (^^decomp_ref) == ^^::);
+static_assert (parent_of (^^arr) == ^^::);
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_parent_of (dms));
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+struct Base {};
+struct Derived : Base {};
+static_assert (parent_of (bases_of (^^Derived, ctx)[0]) == ^^Derived);
+
+consteval {
+  int a = 42;
+  static_assert (parent_of (^^a) == ^^::);
+  consteval {
+    int b = 42;
+    static_assert (parent_of (^^b) == ^^::);
+  }
+}
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_parent_of (^^T));
+//  static_assert (parent_of (R));
+//  static_assert (parent_of (R2));
+//  static_assert (parent_of (R3));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+  static_assert (parent_of (^^p) == ^^g);
+  static_assert (parent_of (^^c) == ^^g);
+  static_assert (parent_of (parameters_of (^^g)[0]) == ^^g);
+  static_assert (parent_of (^^g) == ^^::);
+  consteval {
+    int a = 42;
+    static_assert (parent_of (^^a) == ^^g);
+    consteval {
+      int b = 42;
+      static_assert (parent_of (^^b) == ^^g);
+      consteval {
+       int c = 42;
+       static_assert (parent_of (^^c) == ^^g);
+      }
+    }
+  }
+}
+
+int
+main ()
+{
+}
+
+namespace N
+{
+  extern "C" void foo (int);
+  void baz (int);
+  namespace M
+  {
+    namespace O
+    {
+      struct S {};
+    }
+  }
+  consteval {
+    int a = 42;
+    static_assert (parent_of (^^a) == ^^N);
+    consteval {
+      int b = 42;
+      static_assert (parent_of (^^b) == ^^N);
+    }
+  }
+}
+extern "C" void bar ();
+
+static_assert (!has_parent_of (^^main));
+static_assert (!has_parent_of (^^N::foo));
+static_assert (!has_parent_of (^^bar));
+static_assert (parent_of (^^N::baz) == ^^N);
+static_assert (parent_of (^^N::M::O::S) == ^^N::M::O);
+static_assert (parent_of (^^N::M::O) == ^^N::M);
+static_assert (parent_of (^^N::M) == ^^N);
+static_assert (parent_of (^^N) == ^^::);
+
+enum F {
+  F1,
+  F2 = parent_of (^^F1) == ^^F,
+  F3 = (parent_of (^^F2) == ^^F) + 1,
+};
+static_assert (F2 == 1 && F3 == 2);
+
+void
+qux ()
+{
+  auto a = [] ()
+    {
+      int b;
+      static_assert (is_function (parent_of (^^b)));
+      static_assert (is_class_type (parent_of (parent_of (^^b))));
+      static_assert (parent_of (parent_of (parent_of (^^b))) == ^^qux);
+    };
+  static_assert (parent_of (^^a) == ^^qux);
+  static_assert (parent_of (type_of (^^a)) == ^^qux);
+}
+
+struct I { };
+
+struct J : I {
+  union {
+    int o;
+  };
+
+  enum N {
+    A
+  };
+
+  consteval {
+    int a = 42;
+    static_assert (parent_of (^^a) == ^^J);
+    consteval {
+      int b = 42;
+      static_assert (parent_of (^^b) == ^^J);
+      consteval {
+       int c = 42;
+       static_assert (parent_of (^^c) == ^^J);
+      }
+    }
+  }
+};
+
+static_assert (parent_of (^^J) == ^^::);
+static_assert (parent_of (bases_of (^^J, ctx)[0]) == ^^J);
+static_assert (is_union_type (parent_of (^^J::o)));
+static_assert (parent_of(^^J::N) == ^^J);
+static_assert (parent_of(^^J::A) == ^^J::N);
+
+static union { union { int anon2; union { int anon3; }; }; };
+static_assert (is_union_type (parent_of (^^anon2)));
+static_assert (is_union_type (parent_of (parent_of (^^anon2))));
+static_assert (parent_of (parent_of (parent_of (^^anon2))) == ^^::);
+static_assert (is_union_type (parent_of (^^anon3)));
+static_assert (is_union_type (parent_of (parent_of (^^anon3))));
+static_assert (is_union_type (parent_of (parent_of (parent_of (^^anon3)))));
+static_assert (parent_of (parent_of (parent_of (parent_of (^^anon3)))) == ^^::);
diff --git a/gcc/testsuite/g++.dg/reflect/parm1.C b/gcc/testsuite/g++.dg/reflect/parm1.C
new file mode 100644 (file)
index 0000000..8416be5
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections as function parameters.
+
+#include <meta>
+
+// FIXME PR62244
+//consteval int fn(decltype(^^::) x = ^^x) { return 0; }
+//constexpr int x = fn ();
+
+consteval auto
+ref (std::meta::info r)
+{
+  return r;
+}
+
+consteval std::meta::info
+def (std::meta::info r = std::meta::info(^^int))
+{
+  return r;
+}
+
+consteval std::meta::info
+def2 (std::meta::info r = ^^int)
+{
+  return r;
+}
+
+void
+g (int p)
+{
+  constexpr auto r = ref (^^int);
+  [: r :] i1 = 42;  // { dg-error "expected a reflection of an expression" }
+  typename [: r :] i2 = 42;
+  [: ref (r) :] i3 = 42;  // { dg-error "expected a reflection of an expression" }
+
+  constexpr auto r2 = def ();
+  [: r2 :] i4 = 42;  // { dg-error "expected a reflection of an expression" }
+  typename [: r2 :] i5 = 42;
+  [: def () :] i6 = 42;  // { dg-error "expected a reflection of an expression" }
+
+  constexpr auto r3 = def2 ();
+  [: r3 :] i7 = 42;  // { dg-error "expected a reflection of an expression" }
+  typename [: r3 :] i8 = 42;
+  [: def2 () :] i9 = 42;  // { dg-error "expected a reflection of an expression" }
+
+  constexpr auto r4 = std::meta::info(^^int);
+  [: r4 :] i10 = 42;  // { dg-error "expected a reflection of an expression" }
+  typename [: r4 :] i11 = 42;
+
+  constexpr auto r5 = std::meta::info(r4);
+  [: r5 :] i12 = 42;  // { dg-error "expected a reflection of an expression" }
+  typename [: r5 :] i13 = 42;
+
+  constexpr auto r6 = ^^p;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/parm2.C b/gcc/testsuite/g++.dg/reflect/parm2.C
new file mode 100644 (file)
index 0000000..60a11d0
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// From [dcl.fct.default].
+
+using info = decltype(^^int);
+
+int b;
+class X {
+  int a;
+  int mem1(int i = a);    // { dg-error "invalid use of non-static data member .X::a." }
+  int mem2(int i = b);    // OK; use X::b
+  consteval void mem3(info r = ^^a) {};    // OK
+  int mem4(int i = [:^^a:]); // { dg-error "cannot implicitly reference" }
+
+  static int b;
+};
diff --git a/gcc/testsuite/g++.dg/reflect/parm3.C b/gcc/testsuite/g++.dg/reflect/parm3.C
new file mode 100644 (file)
index 0000000..1ff9357
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test invoking functions with a reflection argument.
+
+using info = decltype(^^int);
+
+consteval void foo (info) { }
+constexpr void bar (info) { } // { dg-error "function of consteval-only type must be declared .consteval." }
+void baz (info) { }  // { dg-error "function of consteval-only type must be declared .consteval." }
+
+void
+f ()
+{
+  foo (^^void);
+  bar (^^void);  // { dg-error "consteval-only expressions" }
+  baz (^^void);  // { dg-error "consteval-only expressions" }
+}
+
+constexpr void
+g ()
+{
+  foo (^^void);
+  bar (^^void);  // { dg-error "consteval-only expressions" }
+  baz (^^void);  // { dg-error "consteval-only expressions" }
+}
+
+consteval void
+h ()
+{
+  foo (^^void);
+  bar (^^void);
+  baz (^^void);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/parm4.C b/gcc/testsuite/g++.dg/reflect/parm4.C
new file mode 100644 (file)
index 0000000..dd76062
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test invoking functions with a reflection argument.
+
+using info = decltype(^^int);
+
+struct S {
+  int mfn0 (info) { return 0; }  // { dg-error "function of consteval-only type must be declared .consteval." }
+  constexpr int mfn1 (info) { return 1; }  // { dg-error "function of consteval-only type must be declared .consteval." }
+  consteval int mfn2 (info) { return 2; }
+  int mfn3 (int, info) { return 0; }  // { dg-error "function of consteval-only type must be declared .consteval." }
+  info mfn4 () { return ^^int; }  // { dg-error "consteval-only expressions|function of consteval-only type must be declared .consteval." }
+};
+
+void
+g (S s)
+{
+  int i0 = s.mfn0 (^^int);  // { dg-error "consteval-only expressions" }
+  constexpr int i1 = s.mfn1 (^^int);
+  constexpr int i2 = s.mfn2 (^^int);
+  int i3 = s.mfn3 (42, ^^int);  // { dg-error "consteval-only expressions" }
+  info i4 = s.mfn4 ();  // { dg-error "consteval-only variable" }
+}
+
+template<typename T>
+int fn (T) { return 4; } // { dg-error "function of consteval-only type must be declared .consteval." }
+const int a = fn (^^int); // { dg-error "consteval-only expressions" }
+int b = fn (^^int); // { dg-error "consteval-only expressions" }
+
+template<typename T>
+T fn2 () { return ^^void; } // { dg-error "consteval-only" }
+const info i = fn2<info>(); // { dg-error "consteval-only variable" }
diff --git a/gcc/testsuite/g++.dg/reflect/pr122634-1.C b/gcc/testsuite/g++.dg/reflect/pr122634-1.C
new file mode 100644 (file)
index 0000000..6f36abf
--- /dev/null
@@ -0,0 +1,65 @@
+// PR c++/122634
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a; };
+namespace N { struct B { int b; }; }
+struct C : typename [: ^^A :] {};
+struct D : [: ^^A :] {};
+struct E : [: ^^N :] :: B {};
+struct F : [: ^^:: :] :: A {};
+struct G : public typename [: ^^A :] {};
+struct H : public [: ^^A :] {};
+struct I : public [: ^^N :] :: B {};
+struct J : public [: ^^:: :] :: A {};
+template <auto I>
+struct K : typename [: I :] {};
+template <auto I>
+struct L : [: I :] {};
+template <auto I>
+struct M : [: I :] :: B {};
+template <auto I>
+struct O : [: I :] :: A {};
+template <auto I>
+struct P : public typename [: I :] {};
+template <auto I>
+struct Q : public [: I :] {};
+template <auto I>
+struct R : public [: I :] :: B {};
+template <auto I>
+struct S : public [: I :] :: A {};
+
+constexpr access_context ctx = access_context::unprivileged ();
+static_assert (type_of (bases_of (^^C, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^D, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^E, ctx)[0]) == ^^N::B);
+static_assert (type_of (bases_of (^^F, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^G, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^H, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^I, ctx)[0]) == ^^N::B);
+static_assert (type_of (bases_of (^^J, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^K <^^A>, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^L <^^A>, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^M <^^N>, ctx)[0]) == ^^N::B);
+static_assert (type_of (bases_of (^^O <^^::>, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^P <^^A>, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^Q <^^A>, ctx)[0]) == ^^A);
+static_assert (type_of (bases_of (^^R <^^N>, ctx)[0]) == ^^N::B);
+static_assert (type_of (bases_of (^^S <^^::>, ctx)[0]) == ^^A);
+
+int
+foo (C &c, D &d, E &e, F &f, G &g, H &h, I &i, J &j)
+{
+  return c.a + d.a + e.b + f.a + g.a + h.a + i.b + j.a;
+}
+
+int
+bar (K <^^A> &k, L <^^A> &l, M <^^N> &m, O <^^::> &o,
+     P <^^A> &p, Q <^^A> &q, R <^^N> &r, S <^^::> &s)
+{
+  return k.a + l.a + m.b + o.a + p.a + q.a + r.b + s.a;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/pr122634-2.C b/gcc/testsuite/g++.dg/reflect/pr122634-2.C
new file mode 100644 (file)
index 0000000..7db5b19
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/122634
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace N { struct A {}; }
+struct B : typename [: ^^N :] :: A {}; // { dg-error "keyword 'typename' not allowed outside of templates" }
+template <auto I>
+struct C : typename [: ^^N :] :: A {};         // { dg-error "keyword 'typename' not allowed in this context" }
+template <auto I>
+struct D : typename [: I :] :: A {};   // { dg-error "keyword 'typename' not allowed in this context" }
diff --git a/gcc/testsuite/g++.dg/reflect/qrn1.C b/gcc/testsuite/g++.dg/reflect/qrn1.C
new file mode 100644 (file)
index 0000000..7864a15
--- /dev/null
@@ -0,0 +1,272 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on reflection-names.
+//   reflection-name:
+//    nested-name-specifier[opt] identifier
+//    nested-name-specifier template identifier
+
+int i;
+using T = int;
+typedef int TY;
+
+template<typename T>
+concept F = requires { typename T::type; };
+
+template<typename T>
+void foo (T) { }
+
+void bar () { }
+
+template<typename T>
+T V{};
+
+enum E { E1 };
+struct S {
+  static constexpr int i = 42;
+  using type = int;
+};
+template<typename T>
+struct C {
+  static constexpr T t{};
+  using type = T;
+};
+
+using US = S;
+using UC = C<int>;
+
+template<typename T>
+using AT = C<T>;
+
+namespace N {
+  int n;
+  using W = int;
+
+  template<typename T>
+  concept FF = requires { typename T::type; };
+
+  namespace M {
+    int m;
+    using WW = int;
+    enum EE { EE1 };
+    struct SS {
+      static constexpr int i = 42;
+      using type = int;
+    };
+    template<typename T>
+    struct CC {
+      static constexpr T t{};
+      using type = T;
+    };
+
+    using NMSS = SS;
+    using NMCC = CC<int>;
+  }
+};
+
+namespace NN = N;
+
+// nested-name-specifier[opt] identifier
+void
+f1 (S s)
+{
+  constexpr auto m0 = ^^::N::M;
+  constexpr auto m1 = ^^N::M;
+  constexpr auto m2 = ^^N;
+  constexpr auto m3 = ^^NN;
+  constexpr auto m4 = ^^::N;
+  constexpr auto m5 = ^^::NN;
+
+  [: m0 :]::m = 0;
+  [: m0 :]::WW v37 = 0;
+  [: m1 :]::m = 0;
+  [: m1 :]::WW v32 = 0;
+  [: m2 :]::n = 0;
+  [: m2 :]::W v33 = 0;
+  [: m3 :]::n = 0;
+  [: m3 :]::W v34 = 0;
+  [: m4 :]::n = 0;
+  [: m4 :]::W v35 = 0;
+  [: m5 :]::n = 0;
+  [: m5 :]::W v36 = 0;
+
+  constexpr auto r1 = ^^i;
+  constexpr auto r2 = ^^::i;
+  constexpr auto r3 = ^^T;
+  constexpr auto r4 = ^^::T;
+  constexpr auto r5 = ^^::TY;
+  constexpr auto r6 = ^^E::E1;
+  constexpr auto r7 = ^^S::i;
+  constexpr auto r8 = ^^S::type;
+  constexpr auto r9 = ^^C<int>::t;
+  constexpr auto r10 = ^^C<int>::type;
+  constexpr auto r11 = ^^US::i;
+  constexpr auto r12 = ^^US::type;
+  constexpr auto r13 = ^^UC::t;
+  constexpr auto r14 = ^^UC::type;
+  constexpr auto r15 = ^^N::n;
+  constexpr auto r16 = ^^N::W;
+  constexpr auto r17 = ^^NN::n;
+  constexpr auto r18 = ^^NN::W;
+  constexpr auto r19 = ^^decltype(s)::i;
+  constexpr auto r20 = ^^decltype(s)::type;
+  // For pack-indexing, see pack-index1.C.
+  constexpr auto rs = ^^S;
+  constexpr auto r21 = ^^[: rs :]::type;
+  constexpr auto r22 = ^^typename [: rs :]::type;
+  constexpr auto rc = ^^C;
+  constexpr auto r23 = ^^[: rc :]<int>::type;  // { dg-error "missing .template.|declared" }
+  constexpr auto r24 = ^^typename [: rc :]<int>::type;
+  constexpr auto r25 = ^^::N::n;
+  constexpr auto r26 = ^^::N::W;
+  constexpr auto r27 = ^^N::M::m;
+  constexpr auto r28 = ^^N::M::WW;
+  constexpr auto r29 = ^^N::M::EE;
+  constexpr auto r30 = ^^N::M::EE::EE1;
+  constexpr auto r31 = ^^[: m1 :]::EE::EE1;
+  constexpr N::M::SS ss{};
+  constexpr auto r32 = ^^decltype(ss)::type;
+  constexpr N::M::CC<int> cc{};
+  constexpr auto r33 = ^^decltype(cc)::type;
+  constexpr auto r34 = ^^N::M::SS::type;
+  constexpr auto r35 = ^^N::M::CC<int>::type;
+  constexpr auto r36 = ^^N::M::NMSS::type;
+  constexpr auto r37 = ^^N::M::NMCC::type;
+  constexpr auto r38 = ^^[: m1 :]::SS::type;
+  constexpr auto r39 = ^^typename [: m1 :]::SS::type;
+  constexpr auto r40 = ^^[: m1 :]::CC<int>::type;
+  constexpr auto r41 = ^^typename [: m1 :]::CC<int>::type;
+  constexpr auto r42 = ^^::C<int>::type;
+
+  [: r1 :] = 42;
+  ++[: r2 :];
+  typename [: r3 :] v1 = 3;
+  typename [: r4 :] v2 = 2;
+  typename [: r5 :] v3 = 1;
+  int n = [: r6 :];
+  n += [: r7 :];
+  typename [: r8 :] v5 = 1;
+  n += [: r9 :];
+  typename [: r10 :] v6 = 4;
+  n += [: r11 :];
+  typename [: r12 :] v7 = 4;
+  n += [: r13 :];
+  typename [: r14 :] v8 = 4;
+  [: r15 :]++;
+  typename [: r16 :] v9 = 4;
+  --[: r17 :];
+  typename [: r18 :] v10 = 4;
+  n *= [: r19 :];
+  typename [: r20 :] v11 = 4;
+  typename [: r21 :] v12 = 4;
+  typename [: r22 :] v13 = 4;
+  typename [: r24 :] v15 = 4;
+  [: r25 :]--;
+  typename [: r26 :] v16 = 7;
+  [: r27 :] = 1;
+  typename [: r28 :] v17 = 7;
+  typename [: r29 :] v18;
+  v18 = [: r30 :];
+  v18 = [: r31 :];
+  typename [: r32 :] v19 = 7;
+  typename [: r33 :] v20 = 7;
+  typename [: r34 :] v21 = 7;
+  typename [: r35 :] v22 = 7;
+  typename [: r36 :] v23 = 7;
+  typename [: r37 :] v24 = 7;
+  typename [: r38 :] v25 = 7;
+  typename [: r39 :] v26 = 7;
+  typename [: r40 :] v27 = 7;
+  typename [: r41 :] v28 = 7;
+  typename [: r42 :] v29 = 7;
+
+  constexpr auto r46 = ^^::F;
+  constexpr auto r47 = ^^::F;
+  constexpr auto r48 = ^^N::FF;
+  constexpr auto r49 = ^^::N::FF;
+  constexpr auto r50 = ^^NN::FF;
+  constexpr auto r51 = ^^::NN::FF;
+
+  constexpr auto r52 = ^^C;
+  constexpr auto r53 = ^^C<int>;
+  constexpr auto r54 = ^^::C;
+  constexpr auto r55 = ^^::template C;
+  constexpr auto r56 = ^^::C<int>;
+  constexpr auto r57 = ^^::template C<int>;
+
+  typename [: r53 :] c1;
+  typename [: r56 :] c2;
+  typename [: r57 :] c3;
+
+  constexpr auto r58 = ^^foo;
+  constexpr auto r59 = ^^::foo;
+
+  constexpr auto r60 = ^^V;
+  constexpr auto r61 = ^^::V;
+
+  constexpr auto r62 = ^^AT;
+  constexpr auto r63 = ^^::AT;
+
+  constexpr auto r64 = ^^bar;
+  constexpr auto r65 = ^^::bar;
+}
+
+// nested-name-specifier template identifier
+consteval void
+f2 ()
+{
+  constexpr auto r1 = ^^::template C<int>;
+  constexpr auto r2 = ^^::template C<int>::type;
+  constexpr auto r3 = ^^N::M::template CC<int>::type;
+  constexpr auto r4 = ^^N::M::template CC<int>::t;
+  constexpr auto r5 = ^^N::M::template CC;
+  constexpr auto r6 = ^^NN::M::template CC<int>::type;
+  constexpr auto r7 = ^^NN::M::template CC<int>::t;
+  constexpr auto r8 = ^^NN::M::template CC;
+
+  // clang rejects these.
+  constexpr auto r9 = ^^N::M::template NMCC::type;
+  constexpr auto r10 = ^^N::M::template NMCC::t;
+  constexpr auto r11 = ^^N::M::template NMCC;
+  constexpr auto r12 = ^^NN::M::template NMCC::type;
+  constexpr auto r13 = ^^NN::M::template NMCC::t;
+  constexpr auto r14 = ^^NN::M::template NMCC;
+  //constexpr auto r15 = ^^::template UC;
+  constexpr auto r16 = ^^::template UC::type;
+
+  typename [: r2 :] v1 = 7;
+  typename [: r3 :] v2 = 7;
+  int n = [: r4 :];
+  typename [: r6 :] v3 = 1;
+  n += [: r7 :];
+}
+
+template<typename T>
+void
+f3 (T t)
+{
+  /* Otherwise, if the identifier names a type alias that was introduced
+     by the declaration of a template parameter, R represents the underlying
+     entity of that type alias.
+     So the reflection here should reflect the targ (int), not T itself?  */
+  constexpr auto r = ^^T;
+  static_assert (r == ^^int);
+}
+
+struct B {
+  unsigned int a:32;
+  unsigned int:32;
+};
+
+void
+f4 ()
+{
+  constexpr auto r = ^^B::a;
+}
+
+void
+g ()
+{
+  f1 (S{});
+  f2 ();
+  f3 (42);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/qrn2.C b/gcc/testsuite/g++.dg/reflect/qrn2.C
new file mode 100644 (file)
index 0000000..51c3c9f
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on reflection-names.  Invalid code.
+
+class A { int x; };
+template<typename T>
+class B { T x; };
+struct C { int x; };
+template<typename T>
+struct D { T x; };
+
+template<typename T>
+void foo (T) { }
+
+template<typename T>
+void foo (T, T) { }
+
+void bar (int) { }
+void bar (int, int) { }
+
+void
+g ()
+{
+  constexpr auto r1 = ^^A::x;    // { dg-error "private within this context" }
+  constexpr auto r2 = ^^B<int>::x;  // { dg-error "private within this context" }
+
+  constexpr auto r3 = ^^C::x;
+  int i1 = [: r3 :];     // { dg-error "cannot implicitly reference a class member .C::x. through a splice" }
+  [: r3 :];              // { dg-error "cannot implicitly reference a class member .C::x. through a splice" }
+  [: r3 :] = 0;                  // { dg-error "cannot implicitly reference a class member .C::x. through a splice" }
+
+  constexpr auto r4 = ^^foo;  // { dg-error "reflection of an overload set" }
+  constexpr auto r5 = ^^bar;  // { dg-error "reflection of an overload set" }
+  constexpr auto r6 = ^^D::x; // { dg-error "expected" }
+  constexpr auto r7 = ^^D<int>::x;
+  [: r7 :];   // { dg-error "cannot implicitly reference a class member .D<int>::x. through a splice" }
+}
+
+void
+f ()
+{
+  g ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/range_args.C b/gcc/testsuite/g++.dg/reflect/range_args.C
new file mode 100644 (file)
index 0000000..fa06cf0
--- /dev/null
@@ -0,0 +1,96 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_constructible_type.
+
+#include <array>
+#include <forward_list>
+#include <list>
+#include <meta>
+#include <ranges>
+#include <span>
+#include <vector>
+
+using namespace std::meta;
+
+template <class... Args>
+struct SupportArgs { 
+  SupportArgs (Args...) noexcept;
+
+  int operator() (Args...) noexcept;
+};
+
+void error();
+
+template<typename Rg>
+consteval bool
+test_type_range(Rg&& rg)
+{
+  info _ = common_type(rg);
+  info _ = common_reference(rg);
+      
+  if (!can_substitute (^^SupportArgs, rg)) error();
+  auto target = substitute(^^SupportArgs, rg);
+  if (!is_constructible_type (target, rg)) error();
+  if (!is_nothrow_constructible_type (target, rg)) error();
+  if (!!is_trivially_constructible_type (target, rg)) error();
+
+  auto result = invoke_result(target, rg);
+  if (!is_invocable_type (target, rg)) error();
+  if (!is_invocable_r_type (result, target, rg)) error();
+  if (!is_nothrow_invocable_type (target, rg)) error();
+  if (!is_nothrow_invocable_r_type (result, target, rg)) error();
+  return true;
+}
+
+constexpr info vt[] = {^^int, ^^int, ^^float, ^^int, ^^float, ^^double};
+static_assert (test_type_range (vt | std::views::filter (is_integral_type))); // bidirectional
+static_assert (test_type_range (vt | std::views::take_while (is_integral_type))); // non-common
+static_assert (test_type_range (vt | std::views::to_input)); // input
+static_assert (test_type_range (vt | std::views::cache_latest)); // input, move-only
+
+template<typename Rg>
+consteval bool
+test_value_range(Rg&& rg)
+{
+  using V = std::ranges::range_value_t<Rg>;
+
+  info ra = reflect_constant_array(rg);
+  std::span<const V> va = define_static_array(rg);
+  if (extract<const V*>(ra) != va.data())
+    error();
+
+  info rs = reflect_constant_string(rg);
+  const V* vs = define_static_string(rg);
+  if (extract<const V*>(rs) != vs)
+    error();
+
+  return true;
+}
+
+constexpr std::span<const char> vv = "abcd01234";
+constexpr bool not_digit(char c) {
+  return c < '0' || c > '9';
+}
+
+static_assert (test_value_range (vv | std::views::filter (not_digit))); // bidirectional
+static_assert (test_value_range (vv | std::views::take_while (not_digit))); // non-common
+static_assert (test_value_range (vv | std::views::to_input)); // input
+static_assert (test_value_range (vv | std::views::cache_latest)); // input, move-only
+                                                                
+template<int> struct Aggr;
+constexpr info dmt[] = {
+  data_member_spec(^^int, {.name = "a"}),
+  data_member_spec(^^int, {.name = "b"}),
+  data_member_spec(^^float, {.name = "c"}),
+  data_member_spec(^^double, {.name = "d"}),
+};
+consteval bool of_int_type(info dm) {
+  return type_of(dm) == ^^int;
+}
+
+consteval {
+  define_aggregate (^^Aggr<0>, dmt | std::views::filter (of_int_type)); // bidirectional
+  define_aggregate (^^Aggr<1>, dmt | std::views::take_while (of_int_type)); // non-common
+  define_aggregate (^^Aggr<2>, dmt | std::views::to_input); // input
+  define_aggregate (^^Aggr<3>, dmt | std::views::cache_latest); // input, move-only
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant1.C b/gcc/testsuite/g++.dg/reflect/reflect_constant1.C
new file mode 100644 (file)
index 0000000..adae634
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+
+using namespace std::meta;
+template<auto D>
+  struct A { };
+
+struct N { int x; };
+struct K { char const* p; };
+
+
+constexpr info r1 = reflect_constant(42);
+static_assert(is_value(r1));
+static_assert(r1 == template_arguments_of(^^A<42>)[0]);
+
+constexpr info r2 = reflect_constant(N{42});
+static_assert(is_object(r2));
+static_assert(r2 == template_arguments_of(^^A<N{42}>)[0]);
+
+constexpr info r3 = reflect_constant(K{nullptr});   // OK
+static_assert(is_object(r3));
+constexpr info r4 = reflect_constant(K{"ebab"});    // { dg-error "uncaught exception" }
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant2.C b/gcc/testsuite/g++.dg/reflect/reflect_constant2.C
new file mode 100644 (file)
index 0000000..95b5852
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr auto one = reflect_constant(1);
+static_assert ([:one:] == 1);
+
+template<info> struct S {};
+template<info> void foo () {}
+
+template<int P>
+void
+fn_tmpl ()
+{
+  static_assert(is_value(reflect_constant(P)));
+  static_assert(!is_object(reflect_constant(P)));
+  static_assert(type_of(reflect_constant(P)) == ^^int);
+  static_assert([:reflect_constant(P):] == 1);
+}
+
+void
+g ()
+{
+  S<reflect_constant (nullptr)> s;
+  foo<reflect_constant (nullptr)>();
+  fn_tmpl<1>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant3.C b/gcc/testsuite/g++.dg/reflect/reflect_constant3.C
new file mode 100644 (file)
index 0000000..c362b03
--- /dev/null
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+
+using namespace std::meta;
+
+static_assert ([:reflect_constant (42):] == 42);
+static_assert (type_of (reflect_constant (42)) == ^^int);
+static_assert (is_value (reflect_constant (42)));
+static_assert (!is_object (reflect_constant (42)));
+
+enum E { A = 42 };
+static_assert ([:reflect_constant (A):] == A);
+static_assert (type_of (reflect_constant (E::A)) == ^^E);
+static_assert (is_value (reflect_constant (E::A)));
+static_assert (!is_object (reflect_constant (E::A)));
+
+enum class EC { A = 42 };
+static_assert ([:reflect_constant (EC::A):] == EC::A);
+static_assert (type_of (reflect_constant (EC::A)) == ^^EC);
+static_assert (is_value (reflect_constant (EC::A)));
+static_assert (!is_object (reflect_constant (EC::A)));
+
+const int i = 42;
+static_assert ([:reflect_constant (i):] == i);
+static_assert (type_of (reflect_constant (i)) == ^^int);
+static_assert (is_value (reflect_constant (i)));
+static_assert (!is_object (reflect_constant (i)));
+
+const int &r = 42;
+static_assert ([:reflect_constant (r):] == r);
+static_assert (type_of (reflect_constant (r)) == ^^int);
+static_assert (is_value (reflect_constant (r)));
+static_assert (!is_object (reflect_constant (r)));
+
+constexpr int ci = 42;
+static_assert ([:reflect_constant (ci):] == ci);
+static_assert (type_of (reflect_constant (ci)) == ^^int);
+static_assert (is_value (reflect_constant (ci)));
+static_assert (!is_object (reflect_constant (ci)));
+
+void fn() {}
+static_assert ([:reflect_constant (&fn):] == &fn);
+static_assert (type_of (reflect_constant (&fn)) == ^^void(*)());
+static_assert (is_value (reflect_constant (&fn)));
+static_assert (!is_object (reflect_constant (&fn)));
+
+constexpr int cfn () { return 42; }
+static_assert ([:reflect_constant (cfn ()):] == 42);
+static_assert (type_of (reflect_constant (cfn ())) == ^^int);
+static_assert (is_value (reflect_constant (cfn ())));
+static_assert (!is_object (reflect_constant (cfn ())));
+
+struct S {
+  int k;
+  void fn();
+};
+static_assert ([:reflect_constant (&S::k):] == &S::k);
+static_assert (type_of (reflect_constant (&S::k)) == ^^int (S::*));
+static_assert (is_value (reflect_constant (&S::k)));
+static_assert (!is_object (reflect_constant (&S::k)));
+static_assert ([:reflect_constant (&S::fn):] == &S::fn);
+static_assert (type_of (reflect_constant (&S::fn)) == ^^void (S::*)());
+static_assert (is_value (reflect_constant (&S::fn)));
+static_assert (!is_object (reflect_constant (&S::fn)));
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant4.C b/gcc/testsuite/g++.dg/reflect/reflect_constant4.C
new file mode 100644 (file)
index 0000000..1ffaa5b
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+
+using namespace std::meta;
+
+int i;
+int foo ();
+struct S {};
+
+constexpr auto r1 = reflect_constant (i); // { dg-error "not usable in a constant expression" }
+constexpr auto r2 = reflect_constant (foo ()); // { dg-error "call to non-.constexpr." }
+constexpr auto r3 = reflect_constant (S); // { dg-error "expected" }
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant5.C b/gcc/testsuite/g++.dg/reflect/reflect_constant5.C
new file mode 100644 (file)
index 0000000..35c0bfe
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {};
+constexpr auto r = reflect_constant (S{});
+S s = [:r:];
+static_assert (!is_value (r));
+static_assert (is_object (r));
+
+struct R { int i; };
+constexpr auto rr = reflect_constant (R{42});
+static_assert ([:rr:].i == 42);
+static_assert (!is_value (rr));
+static_assert (is_object (rr));
+
+static_assert (is_value (reflect_constant (nullptr_t{})));
+static_assert (!is_object (reflect_constant (nullptr_t{})));
+static_assert (is_value (reflect_constant (auto(42))));
+static_assert (!is_object (reflect_constant (auto(42))));
+constexpr int foo () { return 42; }
+static_assert (is_value (reflect_constant (foo ())));
+static_assert (!is_object (reflect_constant (foo ())));
+static constexpr int i = 0;
+static_assert (is_value (reflect_constant (&i)));
+static_assert (!is_object (reflect_constant (&i)));
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant6.C b/gcc/testsuite/g++.dg/reflect/reflect_constant6.C
new file mode 100644 (file)
index 0000000..6f12be7
--- /dev/null
@@ -0,0 +1,46 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.  The glvalue-to-prvalue conversion may have
+// side-effects as part of the constant expression evaluation that the call to
+// reflect_constant is part of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct B {
+  int *const p;
+  consteval B(int *p) : p(p) {}
+};
+
+consteval int g() {
+  int x = 42;
+  B b(&x);
+  reflect_constant (b);
+  return x;
+}
+static_assert(g() == 43); // { dg-error "uncaught exception|non-constant" }
+
+struct A {
+  int *const p;
+  consteval A(int *p) : p(p) {}
+  consteval A(const A &oth) : p(nullptr) {
+    if (oth.p) {
+      ++*oth.p;
+    }
+  }
+};
+
+consteval int f() {
+  int x = 42;
+  A a(&x);
+  reflect_constant (a);
+  return x;
+}
+
+// FIXME Clang++ accepts this, but we throw: we think that the temporary
+// argument to reflect_constant can't be a NTTP.
+// As reflect_constant accept by value, the parameter of reflect_constant(a)
+// is copy-initialized with a, which set p to nullptr, i.e. we no longer 
+// have pointer to stack variable.
+static_assert(f() == 43); // { dg-error "uncaught exception|non-constant" }
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant7.C b/gcc/testsuite/g++.dg/reflect/reflect_constant7.C
new file mode 100644 (file)
index 0000000..d830887
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+using namespace std::meta;
+
+struct A {
+  int *const p;
+  constexpr A(int *p) : p(p) { delete p; }
+  constexpr A(const A &) : p(0) {}
+};
+
+consteval info f() {
+  return reflect_constant<A>(new int);
+}
+
+const A &a = [:f():];
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant8.C b/gcc/testsuite/g++.dg/reflect/reflect_constant8.C
new file mode 100644 (file)
index 0000000..0cad276
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant.
+
+#include <meta>
+using namespace std::meta;
+
+// Not copy-constructible.
+struct S {
+  S();
+  S(const S&) = delete;
+};
+
+constexpr info r1 = reflect_constant (S{}); // { dg-error "no matching function for call" }
+
+// Not copy-constructible.
+struct S2 {
+  S2();
+  S2(S2&) = delete;
+};
+
+constexpr info r2 = reflect_constant (S2{}); // { dg-error "no matching function for call" }
+
+volatile constexpr int vi = 42;
+constexpr info r3 = reflect_constant (vi); // { dg-error "lvalue-to-rvalue conversion" }
+
+// Not a structural type.
+struct M {
+  mutable int i;
+};
+constexpr info r4 = reflect_constant (M{42}); // { dg-error ".M. must be a cv-unqualified structural type" }
+
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant9.C b/gcc/testsuite/g++.dg/reflect/reflect_constant9.C
new file mode 100644 (file)
index 0000000..1055c74
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Per N5014 [temp.arg.nontype] copying an template
+// parameter object of class type must produce structurally
+// equivalent values, but both clang and GCC does not seem
+// to implement that.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A {
+  int x;
+  constexpr A(int p) : x(p) {}
+  constexpr A(const A &oth) : x(oth.x ? oth.x-1 : oth.x) {
+  }
+};
+
+consteval bool
+can_reflect_constant (int x)
+{
+  try { reflect_constant (A(x)); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+// FIXME
+// This should pass, with A::x being zero, copies are equivalent.
+static_assert(!can_reflect_constant(0));
+// As neither GCC and clang see to implement the aforementioned
+// rule, I believe all should work.
+static_assert(!can_reflect_constant(1));
+static_assert(!can_reflect_constant(4));
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_array1.C b/gcc/testsuite/g++.dg/reflect/reflect_constant_array1.C
new file mode 100644 (file)
index 0000000..1d95891
--- /dev/null
@@ -0,0 +1,110 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_array.
+
+#include <array>
+#include <meta>
+#include <ranges>
+#include <span>
+
+using namespace std::meta;
+
+struct V { int a, b, c; };
+constexpr auto a = reflect_constant_array ("abcd");
+constexpr auto b = reflect_constant_array (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}");
+constexpr auto c = reflect_constant_array (std::vector <char> {});
+constexpr auto d = reflect_constant_array (std::array { 1, 2, 42, 3 });
+constexpr float ea[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
+constexpr auto e = reflect_constant_array (ea);
+constexpr int fb[] = { 1, 2, 3, 4, 5, 6 };
+constexpr std::span <const int> fa (fb);
+constexpr auto f = reflect_constant_array (fa);
+constexpr auto g = reflect_constant_array (fa.subspan (1, 4));
+constexpr auto h = reflect_constant_array (fa.subspan (1, 4) | std::views::reverse);
+constexpr auto i = reflect_constant_array (std::vector <V> { V { 1, 2, 3 }, V { 2, 3, 4 }, V { 3, 4, 5 } });
+static_assert (a == reflect_constant_string ("abcd"));
+static_assert (b == reflect_constant_string (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}"));
+static_assert (c == reflect_constant_array (std::vector <char> {}));
+static_assert (d == reflect_constant_array (std::vector <int> { 1, 2, 42, 3 }));
+static_assert (e == reflect_constant_array (std::array { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f }));
+static_assert (f == reflect_constant_array (std::vector <int> { 1, 2, 3, 4, 5, 6 }));
+static_assert (d != f);
+static_assert (g == reflect_constant_array (std::array { 2, 3, 4, 5 }));
+static_assert (h == reflect_constant_array (std::vector <int> { 5, 4, 3, 2 }));
+//static_assert (i == reflect_constant_array (std::vector <V> { V { 1, 2, 3 }, V { 2, 3, 4 }, V { 3, 4, 5 } }));
+static_assert (is_variable (a));
+static_assert (is_variable (b));
+static_assert (is_variable (c));
+static_assert (is_variable (d));
+static_assert (is_variable (e));
+static_assert (is_variable (f));
+static_assert (is_variable (g));
+static_assert (is_variable (h));
+static_assert (is_variable (i));
+static_assert (type_of (a) == ^^const char [5]);
+static_assert (type_of (b) == ^^const char32_t [9]);
+static_assert (type_of (c) == ^^const std::array <char, 0>);
+static_assert (type_of (d) == ^^const int [4]);
+static_assert (type_of (e) == ^^const float [6]);
+static_assert (type_of (f) == ^^const int [6]);
+static_assert (type_of (g) == ^^const int [4]);
+static_assert (type_of (h) == ^^const int [4]);
+static_assert (type_of (i) == ^^const V [3]);
+auto as = &[: a :];
+auto bs = &[: b :];
+auto cs = &[: c :];
+auto ds = &[: d :];
+auto es = &[: e :];
+auto fs = &[: f :];
+auto gs = &[: g :];
+auto hs = &[: h :];
+auto is = &[: i :];
+
+int
+main ()
+{
+  if (std::string_view (*as) != std::string_view ("abcd"))
+    __builtin_abort ();
+  if (std::u32string_view (*bs) != std::u32string_view (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}"))
+    __builtin_abort ();
+  for (const char &x : *cs)
+    __builtin_abort ();
+  int i = 0;
+  for (const int &x : *ds)
+    if (x != "\x{1}\x{2}\x{2a}\x{3}"[i++])
+      __builtin_abort ();
+  if (i != 4)
+    __builtin_abort ();
+  i = 0;
+  for (const float &x : *es)
+    if (x != ++i)
+      __builtin_abort ();
+  if (i != 6)
+    __builtin_abort ();
+  i = 0;
+  for (const int &x : *fs)
+    if (x != ++i)
+      __builtin_abort ();
+  if (i != 6)
+    __builtin_abort ();
+  i = 1;
+  for (const int &x : *gs)
+    if (x != ++i)
+      __builtin_abort ();
+  if (i != 5)
+    __builtin_abort ();
+  i = 6;
+  for (const int &x : *hs)
+    if (x != --i)
+      __builtin_abort ();
+  if (i != 2)
+    __builtin_abort ();
+  i = 0;
+  for (const V &x : *is)
+    if (x.a != i + 1 || x.b != i + 2 || x.c != i + 3)
+      __builtin_abort ();
+    else
+      ++i;
+  if (i != 3)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_array2.C b/gcc/testsuite/g++.dg/reflect/reflect_constant_array2.C
new file mode 100644 (file)
index 0000000..21ee65c
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_string.
+
+#include <meta>
+#include <ranges>
+#include <span>
+
+using namespace std::meta;
+
+struct A { int a, b; mutable int c; };
+constexpr auto a = reflect_constant_array (std::vector <A> { A { 1, 2, 3 } });
+// { dg-error "'reflect_constant_array' argument with 'std::ranges::range_value_t<std::vector<A> >' \\\{aka 'A'\\\} which is not a structural type" "" { target *-*-* } .-1 }
+struct B { constexpr B (int x, int y) : a (x), b (y) {} constexpr ~B () {} B (const B &) = delete; int a, b; };
+constexpr B b[2] = { { 1, 2 }, { 2, 3 } };
+constexpr auto c = reflect_constant_array (b);
+// { dg-error "'reflect_constant_array' argument with 'std::ranges::range_value_t<const B \\\[2\\\]>' \\\{aka 'B'\\\} which is not copy constructible" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_array3.C b/gcc/testsuite/g++.dg/reflect/reflect_constant_array3.C
new file mode 100644 (file)
index 0000000..3805671
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_array.
+
+#include <meta>
+#include <ranges>
+#include <span>
+
+using namespace std::meta;
+
+constexpr int arr[4]{1, 2, 3, 4};
+constexpr info rarr = reflect_constant_array(std::span<const int, 4>(arr));
+static_assert (constant_of(^^arr) == rarr);
+
+constexpr int marr[2][2]{1, 2, 3, 4};
+// LWG4483 multidimensional arrays
+// constexpr info mrarr = reflect_constant_array(std::span<const int[2], 2>(marr));
+// static_assert (constant_of(^^marr) == mrarr);
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_array4.C b/gcc/testsuite/g++.dg/reflect/reflect_constant_array4.C
new file mode 100644 (file)
index 0000000..faf2c4a
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_array.
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+constexpr int x[]{1,2,3,4,5};
+constexpr int y[]{11,12,13,14,15};
+constexpr auto as_pair = []<typename T1, typename T2>(const std::tuple<T1, T2>& t) static
+{ return std::pair<T1, T2>(t); };
+
+constexpr info r = reflect_constant_array(std::views::zip (x, y) | std::views::transform (as_pair));
+// FIXME this should be pass
+// static_assert (type_of (^^r) == ^^const std::pair<int, int>[5]);
+// static_assert ([: r :][2].first == 3);
+// static_assert ([: r :][2].second == 13);
+
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_string1.C b/gcc/testsuite/g++.dg/reflect/reflect_constant_string1.C
new file mode 100644 (file)
index 0000000..92656e9
--- /dev/null
@@ -0,0 +1,133 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_string.
+
+#include <meta>
+#include <ranges>
+#include <span>
+
+using namespace std::meta;
+
+constexpr auto a = reflect_constant_string ("abcd");
+constexpr auto b = reflect_constant_string (u8"abcd\N{LATIN SMALL LETTER AE}");
+constexpr auto c = reflect_constant_string (L"abcd");
+constexpr auto d = reflect_constant_string (u"abcd\0ef");
+constexpr auto e = reflect_constant_string (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}");
+constexpr auto f = reflect_constant_string (std::string_view ("abcd", 5));
+constexpr auto g = reflect_constant_string (std::string_view ("abcdefg", 4));
+constexpr auto h = reflect_constant_string (std::u8string_view (u8"ab\0\N{LATIN SMALL LETTER AE}", 5));
+constexpr auto i = reflect_constant_string (std::string_view ("abcdefgh", 9).substr (0, 5));
+constexpr auto j = reflect_constant_string (std::string_view ("abcdefgh", 9).substr (4, 3));
+constexpr auto k = reflect_constant_string (std::u32string_view (U"abcdefgh", 9).substr (3, 4));
+constexpr char8_t la[] = { u8'h', u8'e', u8'l', u8'l', u8'o', u8'\0' };
+constexpr auto l = reflect_constant_string (la);
+constexpr std::span <const char8_t> ma (la);
+constexpr auto m = reflect_constant_string (ma);
+constexpr auto n = reflect_constant_string (ma.subspan (1, 4));
+constexpr auto o = reflect_constant_string (ma.subspan (1, 4) | std::views::reverse);
+constexpr auto p = reflect_constant_string (std::vector <wchar_t> { L'W', L'o', L'r', L'l', L'd' });
+constexpr auto q = reflect_constant_string (std::vector <char16_t> { u'e', u'x', u't', u'r', u'e', u'm', u'e', u'l', u'y',
+                                                                    u' ', u'l', u'o', u'n', u'g',
+                                                                    u' ', u's', u't', u'r', u'i', u'n', u'g',
+                                                                    u' ', u'w', u'i', u't', u'h',
+                                                                    u' ', u'n', u'o', u'n', u'-', u'A', u'S', u'C', u'I', u'I',
+                                                                    u' ', u'c', u'h', u'a', u'r', u'a', u'c', u't', u'e', u'r', u's',
+                                                                    u' ', u'\N{LATIN SMALL LETTER A WITH ACUTE}' });
+static_assert (a == reflect_constant_string ("abcd"));
+static_assert (b == reflect_constant_string (u8"abcd\N{LATIN SMALL LETTER AE}"));
+static_assert (c == reflect_constant_string (L"abcd"));
+static_assert (d == reflect_constant_string (u"abcd\0ef"));
+static_assert (e == reflect_constant_string (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}"));
+static_assert (f == reflect_constant_string ("abcd\0"));
+static_assert (a != f);
+static_assert (g == a);
+static_assert (h == reflect_constant_string (u8"ab\0\N{LATIN SMALL LETTER AE}"));
+static_assert (i == reflect_constant_string ("abcde"));
+static_assert (a != i);
+static_assert (j == reflect_constant_string ("efg"));
+static_assert (a != j);
+static_assert (k == reflect_constant_string (U"defg"));
+static_assert (l == reflect_constant_string (u8"hello\0"));
+static_assert (m == l);
+static_assert (n == reflect_constant_string (u8"ello"));
+static_assert (o == reflect_constant_string (u8"olle"));
+static_assert (p == reflect_constant_string (L"World"));
+static_assert (q == reflect_constant_string (u"extremely long string with non-ASCII characters \N{LATIN SMALL LETTER A WITH ACUTE}"));
+static_assert (reflect_constant_string ("bar") != reflect_constant_string ("baz"));
+static_assert (is_variable (a));
+static_assert (is_variable (b));
+static_assert (is_variable (c));
+static_assert (is_variable (d));
+static_assert (is_variable (e));
+static_assert (is_variable (f));
+static_assert (is_variable (g));
+static_assert (is_variable (h));
+static_assert (type_of (a) == ^^const char [5]);
+static_assert (type_of (b) == ^^const char8_t [sizeof u8"abcd\N{LATIN SMALL LETTER AE}"]);
+static_assert (type_of (c) == ^^const wchar_t [5]);
+static_assert (type_of (d) == ^^const char16_t [8]);
+static_assert (type_of (e) == ^^const char32_t [9]);
+static_assert (type_of (f) == ^^const char [6]);
+static_assert (type_of (g) == ^^const char [5]);
+static_assert (type_of (h) == ^^const char8_t [6]);
+static_assert (type_of (q) == ^^const char16_t [50]);
+auto as = &[: a :];
+auto bs = &[: b :];
+auto cs = &[: c :];
+auto ds = &[: d :];
+auto es = &[: e :];
+auto fs = &[: f :];
+auto gs = &[: g :];
+auto hs = &[: h :];
+auto is = &[: i :];
+auto js = &[: j :];
+auto ks = &[: k :];
+auto ls = &[: l :];
+auto ms = &[: m :];
+auto ns = &[: n :];
+auto os = &[: o :];
+auto ps = &[: p :];
+auto qs = &[: q :];
+
+int
+main ()
+{
+  if (std::string_view (*as) != std::string_view ("abcd"))
+    __builtin_abort ();
+  if (std::u8string_view (*bs) != std::u8string_view (u8"abcd\N{LATIN SMALL LETTER AE}"))
+    __builtin_abort ();
+  if (std::wstring_view (*cs) != std::wstring_view (L"abcd"))
+    __builtin_abort ();
+  if (std::u16string_view (*ds) != std::u16string_view (u"abcd\0ef"))
+    __builtin_abort ();
+  if (std::u32string_view (*es) != std::u32string_view (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}"))
+    __builtin_abort ();
+  if (std::string_view (*fs) != std::string_view ("abcd\0"))
+    __builtin_abort ();
+  if (gs != as)
+    __builtin_abort ();
+  if (std::u8string_view (*hs) != std::u8string_view (u8"ab\0\N{LATIN SMALL LETTER AE}"))
+    __builtin_abort ();
+  if (std::string_view (*is) != std::string_view ("abcde"))
+    __builtin_abort ();
+  if ((const char *) as == (const char *) is)
+    __builtin_abort ();
+  if (std::string_view (*js) != std::string_view ("efg"))
+    __builtin_abort ();
+  if ((const char *) as == (const char *) js)
+    __builtin_abort ();
+  if (std::u32string_view (*ks) != std::u32string_view (U"defg"))
+    __builtin_abort ();
+  if (std::u8string_view (*ls) != std::u8string_view (u8"hello\0"))
+    __builtin_abort ();
+  if (ms != ls)
+    __builtin_abort ();
+  if (std::u8string_view (*ns) != std::u8string_view (u8"ello"))
+    __builtin_abort ();
+  if (std::u8string_view (*os) != std::u8string_view (u8"olle"))
+    __builtin_abort ();
+  if (std::wstring_view (*ps) != std::wstring_view (L"World"))
+    __builtin_abort ();
+  if (std::u16string_view (*qs) != std::u16string_view (u"extremely long string with non-ASCII characters \N{LATIN SMALL LETTER A WITH ACUTE}"))
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_string2.C b/gcc/testsuite/g++.dg/reflect/reflect_constant_string2.C
new file mode 100644 (file)
index 0000000..3b84356
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_constant_string.
+
+#include <meta>
+#include <ranges>
+#include <span>
+
+using namespace std::meta;
+
+struct V { int a, b, c; };
+constexpr auto a = reflect_constant_string (std::vector <int> { 42, 43, 44 }); // { dg-error "'reflect_constant_string' called with 'std::ranges::range_value_t<std::vector<int> >' \\\{aka 'int'\\\} rather than 'char', 'wchar_t', 'char8_t', 'char16_t' or 'char32_t'" }
+constexpr auto b = reflect_constant_string (std::vector <float> {});           // { dg-error "'reflect_constant_string' called with 'std::ranges::range_value_t<std::vector<float> >' \\\{aka 'float'\\\} rather than 'char', 'wchar_t', 'char8_t', 'char16_t' or 'char32_t'" }
+constexpr auto c = reflect_constant_string (std::vector <V> { V { 1, 2, 3 } });        // { dg-error "'reflect_constant_string' called with 'std::ranges::range_value_t<std::vector<V> >' \\\{aka 'V'\\\} rather than 'char', 'wchar_t', 'char8_t', 'char16_t' or 'char32_t'" }
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_function1.C b/gcc/testsuite/g++.dg/reflect/reflect_function1.C
new file mode 100644 (file)
index 0000000..cf24a17
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_function.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  void foo(this S) {}
+};
+
+int
+main ()
+{
+  [:reflect_function(*&S::foo):](S()); // { dg-error "cannot implicitly reference" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_function2.C b/gcc/testsuite/g++.dg/reflect/reflect_function2.C
new file mode 100644 (file)
index 0000000..f9885a8
--- /dev/null
@@ -0,0 +1,74 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_function.
+
+#include <meta>
+
+using namespace std::meta;
+using namespace std::literals;
+
+void foo ();
+static_assert (reflect_function (::foo) == ^^::foo);
+static_assert (is_function (reflect_function (::foo)));
+static_assert (!is_object (reflect_function (::foo)));
+static_assert (!is_value (reflect_function (::foo)));
+static_assert (type_of (reflect_function (::foo)) == ^^void ());
+static_assert (identifier_of (reflect_function (::foo)) == "foo"sv);
+
+const auto &ref = ::foo;
+static_assert (reflect_function (ref) == ^^::foo);
+static_assert (is_function (reflect_function (ref)));
+static_assert (!is_object (reflect_function (ref)));
+static_assert (!is_value (reflect_function (ref)));
+static_assert (type_of (reflect_function (ref)) == ^^void());
+static_assert (identifier_of (reflect_function (ref)) == "foo"sv);
+
+constexpr void (*fp)() = ::foo;
+static_assert (reflect_function (*fp) == ^^::foo);
+static_assert (is_function (reflect_function (*fp)));
+static_assert (!is_object (reflect_function (*fp)));
+static_assert (!is_value (reflect_function (*fp)));
+static_assert (type_of (reflect_function (*fp)) == ^^void());
+static_assert (identifier_of (reflect_function (*fp)) == "foo"sv);
+
+template <void(&P)()>
+void
+fn_fn_ref_param ()
+{
+  static constexpr auto R = reflect_function (P);
+  static_assert (is_function (R));
+  static_assert (type_of (R) == ^^void ());
+  static_assert (identifier_of (R) == "doit"sv);
+}
+
+constexpr int bar (int i) { return i + 42; }
+static_assert ([:reflect_function (bar):](0) == 42);
+
+template<int N>
+constexpr int
+baz (int i)
+{
+  return i + N;
+}
+static_assert ([:reflect_function (baz<1>):](1) == 2);
+
+void
+doit ()
+{
+  fn_fn_ref_param<doit>();
+  [:reflect_function (::foo):]();
+  [:reflect_function (::ref):]();
+  [:reflect_function (*::fp):]();
+}
+
+extern int (&fref)();
+
+consteval bool
+can_reflect_extern_reference ()
+{
+  try { reflect_function (fref); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert(!can_reflect_extern_reference());
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_object1.C b/gcc/testsuite/g++.dg/reflect/reflect_object1.C
new file mode 100644 (file)
index 0000000..d330984
--- /dev/null
@@ -0,0 +1,88 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_object.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S { int m; };
+
+template <int &> void fn();
+int p[2];
+static_assert(template_arguments_of(^^fn<p[1]>)[0] == reflect_object(p[1]));
+int pp[2][2];
+static_assert(template_arguments_of(^^fn<pp[1][1]>)[0] == reflect_object(pp[1][1]));
+
+template <const int &P>
+void
+fn_int_ref ()
+{
+  static constexpr auto R = reflect_object(P);
+
+  static_assert(is_object(R));
+  static_assert(!is_value(R));
+  static_assert(!is_variable(R));
+  if constexpr (is_const(R)) {
+    static_assert(type_of(R) == ^^const int);
+    static_assert([:R:] == 2);
+  } else {
+    static_assert(type_of(R) == ^^int);
+  }
+}
+
+template <const int &P>
+void
+fn_int_subobject_ref ()
+{
+  static constexpr auto R = reflect_object(P);
+
+  static_assert(is_object(R));
+  static_assert(!is_value(R));
+  static_assert(!is_variable(R));
+  static_assert(type_of(R) == ^^const int);
+  static_assert([:R:] == 3);
+}
+
+template <S P>
+void
+fn_cls_value ()
+{
+  static constexpr auto R = reflect_object(P);
+
+  static_assert(is_object(R));
+  static_assert(!is_value(R));
+  static_assert(!is_variable(R));
+  static_assert(type_of(R) == ^^const S);
+  static_assert([:R:].m == 5);
+}
+
+template <S &P>
+void
+fn_cls_ref ()
+{
+  static constexpr auto R = reflect_object(P);
+
+  static_assert(is_object(R));
+  static_assert(!is_value(R));
+  static_assert(!is_variable(R));
+  static_assert(type_of(R) == ^^S);
+}
+
+void
+doit ()
+{
+  static constexpr int k = 2;
+  fn_int_ref<k>();
+
+  static int k2;
+  fn_int_ref<k2>();
+
+  static constexpr std::pair<int, int> p {3, 4};
+  fn_int_subobject_ref<p.first>();
+
+  fn_cls_value<{5}>();
+
+  static S s;
+  fn_cls_ref<s>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_object2.C b/gcc/testsuite/g++.dg/reflect/reflect_object2.C
new file mode 100644 (file)
index 0000000..adf17a2
--- /dev/null
@@ -0,0 +1,115 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_object.
+
+#include <meta>
+
+using namespace std::meta;
+
+static int obj = 42;
+constexpr auto robj = reflect_object (obj);
+static const int cobj = 42;
+constexpr auto rcobj = reflect_object (cobj);
+static_assert ([:rcobj:] == 42);
+static constexpr int ceobj = 42;
+constexpr auto rceobj = reflect_object (ceobj);
+static_assert ([:rceobj:] == 42);
+
+static_assert (reflect_object (obj) != ^^obj);
+static_assert (type_of (reflect_object (obj)) == ^^int);
+static_assert (is_object (reflect_object (obj)));
+static_assert (!is_value (reflect_object (obj)));
+static_assert (!is_variable (reflect_object (obj)));
+static_assert (reflect_object (cobj) != ^^cobj);
+static_assert (type_of (reflect_object (cobj)) == ^^const int);
+static_assert (is_object (reflect_object (cobj)));
+static_assert (!is_value (reflect_object (cobj)));
+static_assert (!is_variable (reflect_object (cobj)));
+static_assert (reflect_object (ceobj) != ^^ceobj);
+static_assert (type_of (reflect_object (ceobj)) == ^^const int);
+static_assert (is_object (reflect_object (ceobj)));
+static_assert (!is_value (reflect_object (ceobj)));
+static_assert (!is_variable (reflect_object (ceobj)));
+
+static_assert (!is_const (reflect_object (obj)));
+static_assert (is_const (reflect_object (cobj)));
+static_assert (is_const (reflect_object (ceobj)));
+
+const int &ref = obj;
+static_assert (reflect_object (ref) != ^^obj);
+static_assert (type_of (reflect_object (ref)) == ^^int);
+static_assert (is_object (reflect_object (ref)));
+static_assert (!is_value (reflect_object (ref)));
+static_assert (!is_variable (reflect_object (ref)));
+static_assert (!is_const (reflect_object (ref)));
+
+constexpr const int *pobj = &ceobj;
+static_assert (reflect_object (pobj) != ^^pobj);
+static_assert (type_of (reflect_object (pobj)) == ^^const int *const);
+static_assert (is_object (reflect_object (pobj)));
+static_assert (!is_value (reflect_object (pobj)));
+static_assert (!is_variable (reflect_object (pobj)));
+static_assert (is_const (reflect_object (pobj)));
+
+static constexpr std::pair<int, short> p = {1, 2};
+static_assert (reflect_object (p) != ^^p);
+static_assert (reflect_object (p.first) != ^^p);
+static_assert (type_of (reflect_object (p)) == ^^const std::pair<int, short>);
+static_assert (&[:reflect_object (p.first):] == &p.first);
+static_assert ([:reflect_object (p.first):] == 1);
+static_assert (type_of (reflect_object (p.first)) == ^^const int);
+static_assert (&[:reflect_object (p.second):] == &p.second);
+static_assert ([:reflect_object (p.second):] == 2);
+static_assert (type_of(reflect_object (p.second)) == ^^const short);
+static_assert (is_object (reflect_object (p)));
+static_assert (!is_value (reflect_object (p)));
+static_assert (is_object (reflect_object (p.first)));
+static_assert (!is_value (reflect_object (p.first)));
+
+struct B {};
+struct D : B {};
+D d;
+static_assert (type_of (reflect_object (d)) == ^^D);
+// TODO
+//static_assert (type_of (reflect_object (static_cast<B &>(d))) == ^^B);
+
+template<typename T>
+constexpr T
+bar (T a)
+{
+  return a + 42;
+}
+
+constexpr int (*barp)(int) = &bar<int>;
+constexpr auto rbar = reflect_object (barp);
+static_assert ([:rbar:](0) == 42);
+
+unsigned long letter;
+static_assert (size_of (reflect_object (letter)) == sizeof (unsigned long));
+
+template<auto K> constexpr auto R = reflect_object (K);
+B b = [:R<B{}>:];
+
+struct S { int m; };
+constexpr S s{42};
+static_assert (reflect_object (s) != ^^s);
+static_assert (type_of (reflect_object (s)) == ^^const S);
+static_assert (is_object (reflect_object (s)));
+static_assert (!is_variable (reflect_object (s)));
+static_assert (is_const (reflect_object (s)));
+
+template<auto V>
+  requires (is_class_type (^^decltype(V)))
+consteval bool
+fn ()
+{
+  return reflect_constant (V) == reflect_object (V);
+}
+static_assert (fn<s>());
+
+void
+g ()
+{
+  int i = [:robj:];
+  [:rbar:](42);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_object3.C b/gcc/testsuite/g++.dg/reflect/reflect_object3.C
new file mode 100644 (file)
index 0000000..baa8adb
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_object.
+
+#include <meta>
+
+using namespace std::meta;
+
+const char *s = "foo";
+constexpr auto r1 = reflect_object (s);
+extern int x;
+constexpr auto r2 = reflect_object (x);
+int ai[10];
+constexpr auto r3 = reflect_object (ai);
+
+constexpr auto e1 = reflect_object (42); // { dg-error "cannot bind" }
+
+struct J1 {
+  J1 *self = this;
+};
+constexpr auto e2 = reflect_object (J1{}); // { dg-error "cannot bind" }
+
+struct J2 {
+  J2 *self = this;
+  constexpr J2() {}
+  constexpr J2(const J2&) {}
+};
+constexpr auto e3 = reflect_object (J2{}); // { dg-error "cannot bind" }
+
+struct X { int n; };
+struct Y { const int &r; };
+constexpr auto e4 = reflect_object (Y{X{1}.n}); // { dg-error "cannot bind" }
+
+void
+f1 ()
+{
+  constexpr int& ref = x;
+  constexpr auto rref = reflect_object (ref);
+}
+
+consteval bool
+can_reflect_object_on_str ()
+{
+  try { reflect_object ("foo"); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!can_reflect_object_on_str ());
+
+extern int& vref;
+
+consteval bool
+can_reflect_extern_reference ()
+{
+  try { reflect_object (vref); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert(!can_reflect_extern_reference());
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_object4.C b/gcc/testsuite/g++.dg/reflect/reflect_object4.C
new file mode 100644 (file)
index 0000000..a220ab4
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::reflect_object.
+
+#include <meta>
+
+using namespace std::meta;
+
+void fn();
+constexpr auto e = reflect_object (fn); // { dg-error "no matching function for call" }
diff --git a/gcc/testsuite/g++.dg/reflect/return_type_of1.C b/gcc/testsuite/g++.dg/reflect/return_type_of1.C
new file mode 100644 (file)
index 0000000..5855a64
--- /dev/null
@@ -0,0 +1,99 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::return_type_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+int &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+U fn3 (int);
+using fn4 = unsigned long (int, long);
+using fn5 = U (...);
+auto fn6 (int);
+auto &fn7 (long long);
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_return_type_of (info r)
+{
+  try { return_type_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_return_type_of (std::meta::reflect_constant (42)));
+static_assert (!has_return_type_of (std::meta::reflect_object (arr[1])));
+static_assert (!has_return_type_of (^^arr));
+static_assert (!has_return_type_of (^^a3));
+static_assert (has_return_type_of (^^fn));
+static_assert (has_return_type_of (^^fn2));
+static_assert (has_return_type_of (^^fn3));
+static_assert (has_return_type_of (^^fn4));
+static_assert (has_return_type_of (^^fn5));
+static_assert (!has_return_type_of (^^fn6));
+static_assert (!has_return_type_of (^^fn7));
+using intref = int &;
+static_assert (return_type_of (^^fn) == ^^void);
+static_assert (return_type_of (^^fn2) == dealias (^^intref));
+using ulong = unsigned long;
+static_assert (return_type_of (^^fn3) == ^^U);
+static_assert (return_type_of (^^fn4) == dealias (^^ulong));
+static_assert (return_type_of (^^fn5) == ^^U);
+static_assert (!has_return_type_of (^^Enum::A));
+static_assert (!has_return_type_of (^^Alias));
+static_assert (!has_return_type_of (^^S));
+static_assert (!has_return_type_of (^^S::mem));
+static_assert (!has_return_type_of (members_of (^^S, ctx)[1]));
+static_assert (!has_return_type_of (^^TCls));
+static_assert (!has_return_type_of (^^TFn));
+static_assert (!has_return_type_of (^^TVar));
+static_assert (!has_return_type_of (^^Concept));
+static_assert (!has_return_type_of (^^NSAlias));
+static_assert (!has_return_type_of (^^NS));
+static_assert (!has_return_type_of (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (!has_return_type_of (std::meta::data_member_spec (^^int, { .name = "member" })));
+
+struct V
+{
+  V ()
+  {
+    int i = 42;
+    static_assert (!has_return_type_of (parent_of (^^i)));
+  }
+  ~V ()
+  {
+    int i = 42;
+    static_assert (!has_return_type_of (parent_of (^^i)));
+  }
+  V (int, long)
+  {
+    int i = 42;
+    static_assert (!has_return_type_of (parent_of (^^i)));
+  }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/return_type_of2.C b/gcc/testsuite/g++.dg/reflect/return_type_of2.C
new file mode 100644 (file)
index 0000000..273197e
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::return_type_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  S () {
+    int a;
+    constexpr auto r = return_type_of (type_of (parent_of (^^a))); // { dg-error "does not have a type" }
+    constexpr auto t = return_type_of (parent_of (^^a)); // { dg-error "function or function type with a return type" }
+  }
+  ~S () {
+    int a;
+    constexpr auto r = return_type_of (type_of (parent_of (^^a))); // { dg-error "does not have a type" }
+    constexpr auto t = return_type_of (parent_of (^^a)); // { dg-error "function or function type with a return type" }
+  }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/serialize1.C b/gcc/testsuite/g++.dg/reflect/serialize1.C
new file mode 100644 (file)
index 0000000..a1d50b8
--- /dev/null
@@ -0,0 +1,151 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection -O0" }
+
+#include <meta>
+#include <cstdlib>
+
+namespace impl {
+  template <auto... vals>
+  struct replicator_type {
+    template <typename F>
+    constexpr void operator >> (F body) const
+    { (body.template operator()<vals>(), ...); }
+  };
+
+  template <auto... vals>
+  replicator_type <vals...> replicator = {};
+}
+
+template <typename R>
+consteval auto
+expand (R range)
+{
+  std::vector <std::meta::info> args;
+  for (auto r : range)
+    args.push_back (std::meta::reflect_constant (r));
+  return substitute (^^impl::replicator, args);
+}
+
+struct Person1 {
+  std::string name;
+  int age;
+};
+
+constexpr std::string
+serialize1 (Person1 s)
+{
+  std::string result = " ";
+  impl::replicator <^^Person1::name, ^^Person1::age> >> [&] <auto m> {
+    result += identifier_of (m);
+    result += "=";
+    if constexpr (type_of (m) == ^^int)
+      result += std::string (s.[: m :] / 10, 'X');
+    else
+      result += s.[: m :];
+    result += " ";
+  };
+  return result;
+}
+
+struct Person2 {
+  int age;
+  std::string name;
+};
+
+constexpr std::string
+serialize2 (Person2 s)
+{
+  std::string result = " ";
+  constexpr auto ctx = std::meta::access_context::current ();
+  [: expand (nonstatic_data_members_of (^^Person2, ctx)) :] >> [&] <auto m> {
+    result += identifier_of (m);
+    result += "=";
+    if constexpr (type_of (m) == ^^int)
+      result += std::string (s.[: m :] / 10, 'X');
+    else
+      result += s.[: m :];
+    result += " ";
+  };
+  return result;
+}
+
+struct Person3 {
+  std::string name, surname;
+  int age;
+};
+
+template <typename S>
+constexpr std::string
+serialize3 (S s)
+{
+  std::string result = " ";
+  constexpr auto ctx = std::meta::access_context::current ();
+  [: expand (nonstatic_data_members_of (^^S, ctx)) :] >> [&] <auto m> {
+    result += identifier_of (m);
+    result += "=";
+    if constexpr (type_of (m) == ^^int)
+      result += std::string (s.[: m :] / 10, 'X');
+    else
+      result += s.[: m :];
+    result += " ";
+  };
+  return result;
+}
+
+template <typename S>
+constexpr std::string
+serialize4 (S s)
+{
+  std::string result = " ";
+  constexpr auto ctx = std::meta::access_context::current ();
+  template for (constexpr auto m : [: reflect_constant_array (nonstatic_data_members_of (^^S, ctx)) :]) {
+    result += identifier_of (m);
+    result += "=";
+    if constexpr (type_of (m) == ^^int)
+      result += std::string (s.[: m :] / 10, 'X');
+    else
+      result += s.[: m :];
+    result += " ";
+  };
+  return result;
+}
+
+constexpr Person1 john { "John", 42 };
+constexpr Person2 joe { 37, "Joe" };
+constexpr Person3 john_smith { "John", "Smith", 71 };
+
+static_assert (serialize1 (john) == " name=John age=XXXX ");
+static_assert (serialize2 (joe) == " age=XXX name=Joe ");
+static_assert (serialize3 (john) == " name=John age=XXXX ");
+static_assert (serialize3 (joe) == " age=XXX name=Joe ");
+static_assert (serialize3 (john_smith) == " name=John surname=Smith age=XXXXXXX ");
+static_assert (serialize4 (john) == " name=John age=XXXX ");
+static_assert (serialize4 (joe) == " age=XXX name=Joe ");
+static_assert (serialize4 (john_smith) == " name=John surname=Smith age=XXXXXXX ");
+
+int
+main ()
+{
+  Person1 jack { "Jack", 53 };
+  std::string s1 = serialize1 (jack);
+  if (s1 != " name=Jack age=XXXXX ")
+    std::abort ();
+  Person2 harry { 28, "Harry" };
+  std::string s2 = serialize2 (harry);
+  if (s2 != " age=XX name=Harry ")
+    std::abort ();
+  if (serialize3 (jack) != s1)
+    std::abort ();
+  if (serialize3 (harry) != s2)
+    std::abort ();
+  Person3 jane_doe { "Jane", "Doe", 19 };
+  std::string s3 = serialize3 (jane_doe);
+  if (s3 != " name=Jane surname=Doe age=X ")
+    std::abort ();
+  if (serialize4 (jack) != s1)
+    std::abort ();
+  if (serialize4 (harry) != s2)
+    std::abort ();
+  if (serialize4 (jane_doe) != s3)
+    std::abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/serialize2.C b/gcc/testsuite/g++.dg/reflect/serialize2.C
new file mode 100644 (file)
index 0000000..9b3ae68
--- /dev/null
@@ -0,0 +1,67 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection -O0" }
+
+#include <meta>
+#include <cstdlib>
+
+namespace impl {
+  template <auto... vals>
+  struct replicator_type {
+    template <typename F>
+    constexpr void operator >> (F body) const
+    { (body.template operator()<vals>(), ...); }
+  };
+
+  template <auto... vals>
+  replicator_type <vals...> replicator = {};
+}
+
+template <typename R>
+consteval auto
+expand (R range)
+{
+  std::vector <std::meta::info> args;
+  for (auto r : range)
+    args.push_back (std::meta::reflect_constant (r));
+  return substitute (^^impl::replicator, args);
+}
+
+struct Person {
+  std::string name;
+  int age;
+};
+
+template <typename S>
+constexpr std::string
+serialize (S s)
+{
+  std::string result = " ";
+#if 0
+  // TODO, this ICEs in tsubst_expr.
+  impl::replicator <^^S::age, ^^S::name> >> [&] <auto m> {
+#else
+  impl::replicator <^^Person::age, ^^Person::name> >> [&] <auto m> {
+#endif
+    result += identifier_of (m);
+    result += "=";
+    if constexpr (type_of (m) == ^^int)
+      result += std::string (s.[: m :] / 10, 'X');
+    else
+      result += s.[: m :];
+    result += " ";
+  };
+  return result;
+}
+
+constexpr Person john { "John", 42 };
+
+static_assert (serialize (john) == " age=XXXX name=John ");
+
+int
+main ()
+{
+  Person jack { "Jack", 53 };
+  std::string s = serialize (jack);
+  if (s != " age=XXXXX name=Jack ")
+    std::abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/size_of1.C b/gcc/testsuite/g++.dg/reflect/size_of1.C
new file mode 100644 (file)
index 0000000..f150068
--- /dev/null
@@ -0,0 +1,122 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::size_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+extern int arr2[];
+extern int arr3[2];
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+int &ref = arr[0];
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_size_of (info r)
+{
+  try { size_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (has_size_of (std::meta::reflect_constant (42)));
+static_assert (has_size_of (std::meta::reflect_object (arr[1])));
+static_assert (has_size_of (^^arr));
+static_assert (!has_size_of (^^a3));
+static_assert (!has_size_of (^^fn));
+static_assert (!has_size_of (^^fn2));
+static_assert (!has_size_of (^^Enum::A));
+static_assert (has_size_of (^^Alias));
+static_assert (has_size_of (^^S));
+static_assert (has_size_of (^^S::mem));
+static_assert (!has_size_of (members_of (^^S, access_context::current ())[1]));
+static_assert (!has_size_of (^^TCls));
+static_assert (!has_size_of (^^TFn));
+static_assert (!has_size_of (^^TVar));
+static_assert (!has_size_of (^^Concept));
+static_assert (!has_size_of (^^NSAlias));
+static_assert (!has_size_of (^^NS));
+static_assert (has_size_of (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (has_size_of (std::meta::data_member_spec (^^int, { .name = "member" })));
+static_assert (!has_size_of (std::meta::data_member_spec (^^int, { .name = "member", .bit_width = 6 })));
+static_assert (!has_size_of (std::meta::data_member_spec (^^int, { .bit_width = 15 })));
+static_assert (!has_size_of (^^arr2));
+static_assert (has_size_of (^^arr3));
+static_assert (!has_size_of (^^ref));
+static_assert (size_of (^^arr) == sizeof (arr));
+static_assert (size_of (std::meta::reflect_constant (42)) == sizeof (int));
+static_assert (size_of (^^Alias) == sizeof (int));
+static_assert (size_of (^^S) == sizeof (S));
+static_assert (size_of (^^S::mem) == sizeof (S::mem));
+static_assert (size_of (std::meta::bases_of (^^S, ctx)[0]) == sizeof (B));
+static_assert (size_of (std::meta::data_member_spec (^^int, { .name = "member" })) == sizeof (int));
+static_assert (size_of (^^arr3) == sizeof (arr3));
+using fnt = int (int, int);
+static_assert (!has_size_of (^^fnt));
+void bar (long, const T f, int g[2], T &);
+
+int
+foo (int a, const long b, T c, int d[4], T &e, int f)
+{
+  static_assert (has_size_of (^^a));
+  static_assert (has_size_of (^^b));
+  static_assert (has_size_of (^^c));
+  static_assert (has_size_of (^^d));
+  static_assert (!has_size_of (^^e));
+  static_assert (!has_size_of (parameters_of (^^foo)[0]));
+  static_assert (!has_size_of (parameters_of (^^foo)[5]));
+  static_assert (!has_size_of (parameters_of (^^bar)[0]));
+  static_assert (size_of (^^a) == sizeof (int));
+  static_assert (size_of (^^b) == sizeof (long));
+  static_assert (size_of (^^c) == sizeof (T));
+  static_assert (size_of (^^d) == sizeof (int *));
+  return 0;
+}
+
+struct V
+{
+  char a;
+  long long f;
+  int : 2;
+  int g : 3;
+  int &h;
+};
+using CV = const V;
+
+static_assert (size_of (^^int) == sizeof (int));
+static_assert (size_of (^^char) == sizeof (char));
+static_assert (size_of (^^V) == sizeof (V));
+static_assert (size_of (^^CV) == sizeof (V));
+static_assert (size_of (^^char *) == sizeof (char *));
+static_assert (size_of (^^char &) == sizeof (char *));
+static_assert (sizeof (char) == sizeof (char *) || size_of (^^char &) != sizeof (char &));
+static_assert (size_of (^^V::a) == sizeof (char));
+static_assert (size_of (^^V::f) == sizeof (long long));
+static_assert (!has_size_of (^^V::g));
+static_assert (size_of (^^V::h) == sizeof (int *));
diff --git a/gcc/testsuite/g++.dg/reflect/source_location_of1.C b/gcc/testsuite/g++.dg/reflect/source_location_of1.C
new file mode 100644 (file)
index 0000000..8ba34db
--- /dev/null
@@ -0,0 +1,113 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::source_location_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+static_assert (source_location_of (^^::).line () == std::source_location ().line ());
+static_assert (source_location_of (^^int).line () == std::source_location ().line ());
+struct S {};
+static_assert (source_location_of (^^S).line () == std::source_location::current ().line () - 1);
+int x;
+static_assert (source_location_of (^^x).line () == std::source_location::current ().line () - 1);
+enum E {
+  E1,
+  E2
+};
+static_assert (source_location_of (^^E).line () == std::source_location::current ().line () - 4);
+static_assert (source_location_of (^^E1).line () == std::source_location::current ().line () - 4);
+static_assert (source_location_of (^^E2).line () == std::source_location::current ().line () - 4);
+union U {};
+static_assert (source_location_of (^^U).line () == std::source_location::current ().line () - 1);
+void foo (int, int) {}
+static_assert (source_location_of (^^foo).line () == std::source_location::current ().line () - 1);
+namespace N { namespace O {} }
+static_assert (source_location_of (^^N).line () == std::source_location::current ().line () - 1);
+static_assert (source_location_of (^^N::O).line () == std::source_location::current ().line () - 2);
+using I = int;
+static_assert (source_location_of (^^I).line () == std::source_location::current ().line () - 1);
+static_assert (source_location_of (dealias (^^I)).line () == std::source_location ().line ());
+typedef S J;
+static_assert (source_location_of (dealias (^^J)).line () == source_location_of (^^S).line ());
+static_assert (source_location_of (data_member_spec (^^int, { .name = "_" })).line () == std::source_location ().line ());
+constexpr auto ctx = access_context::current ();
+struct V {};
+struct Y { int a, b, c; };
+struct W : [[=1]] public S, [[=2, =Y { 42, 42, 42 }]] virtual V {};
+static_assert (source_location_of (bases_of (^^W, ctx)[0]).line () == std::source_location::current ().line () - 1);
+static_assert (source_location_of (bases_of (^^W, ctx)[1]).line () == std::source_location::current ().line () - 2);
+static_assert (source_location_of (annotations_of (bases_of (^^W, ctx)[0])[0]).line () == std::source_location::current ().line () - 3);
+static_assert (source_location_of (annotations_of (bases_of (^^W, ctx)[1])[1]).line () == std::source_location::current ().line () - 4);
+struct X : public S,
+          [[=3]] public V
+{
+};
+static_assert (source_location_of (bases_of (^^X, ctx)[0]).line () == std::source_location::current ().line () - 4);
+// TODO: we don't track location of base specifiers, so just location of the derived class definition is used.
+static_assert (source_location_of (bases_of (^^X, ctx)[1]).line () == std::source_location::current ().line () - 6);
+static_assert (source_location_of (annotations_of (bases_of (^^X, ctx)[1])[0]).line () == std::source_location::current ().line () - 6);
+[[=1]]
+[[=2]] extern int an;
+[[=Y { 1, 2, 3 }]] extern int an;
+[[=3.0f + 4.0f]] int an;
+static_assert (source_location_of (annotations_of (^^an)[0]).line () == std::source_location::current ().line () - 4);
+static_assert (source_location_of (annotations_of (^^an)[1]).line () == std::source_location::current ().line () - 4);
+static_assert (source_location_of (annotations_of (^^an)[2]).line () == std::source_location::current ().line () - 4);
+static_assert (source_location_of (annotations_of (^^an)[3]).line () == std::source_location::current ().line () - 4);
+
+#include <string_view>
+
+int baz (int x, int y);
+static_assert (source_location_of (parameters_of (^^baz)[0]).line () == std::source_location::current ().line () - 1);
+
+void
+bar (int a, int b)
+{
+  static_assert (source_location_of (^^a).line ()
+                == std::source_location::current ().line () - 3);
+  static_assert (source_location_of (^^b).line ()
+                == source_location_of (^^a).line ());
+  static_assert (std::string_view (source_location_of (^^bar).file_name ())
+                == std::string_view (std::source_location::current ().file_name ()));
+  static_assert (std::string_view (source_location_of (^^a).function_name ())
+                == std::string_view (std::source_location::current ().function_name ()));
+  static_assert (std::string_view (source_location_of (^^b).function_name ())
+                == std::string_view (std::source_location::current ().function_name ()));
+  int c;
+  static_assert (source_location_of (^^c).line ()
+                == std::source_location::current ().line () - 2);
+  static_assert (std::string_view (source_location_of (^^c).file_name ())
+                == std::string_view (std::source_location::current ().file_name ()));
+  static_assert (std::string_view (source_location_of (^^a).function_name ())
+                == std::string_view (std::source_location::current ().function_name ()));
+  constexpr auto d = parameters_of (^^bar)[0];
+  static_assert (source_location_of (d).line ()
+                == source_location_of (^^a).line ());
+  static_assert (std::string_view (source_location_of (d).file_name ())
+                == std::string_view (source_location_of (^^a).file_name ()));
+  static_assert (std::string_view (source_location_of (d).function_name ())
+                == std::string_view (source_location_of (^^a).function_name ()));
+}
+
+template <int N>
+void
+qux ()
+{
+  [[=1]]
+  [[=N + 42]]
+  [[=Y { N, N + 1, N + 2 }]]
+  [[=Y { 1, 2, 3 }]] int an;
+  static_assert (N && source_location_of (annotations_of (^^an)[0]).line () == std::source_location::current ().line () - 4);
+  static_assert (N && source_location_of (annotations_of (^^an)[1]).line () == std::source_location::current ().line () - 4);
+//  static_assert (N && source_location_of (annotations_of (^^an)[2]).line () == std::source_location::current ().line () - 4);
+//  static_assert (N && source_location_of (annotations_of (^^an)[3]).line () == std::source_location::current ().line () - 4);
+}
+
+void
+plugh ()
+{
+  qux <1> ();
+  qux <2> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/source_location_of2.C b/gcc/testsuite/g++.dg/reflect/source_location_of2.C
new file mode 100644 (file)
index 0000000..7ea4d9e
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::source_location_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+template <typename F>
+consteval info
+select_mem (info clazz, F f)
+{
+  for (info x : members_of (clazz, access_context::unchecked ()))
+    if (f (x))
+      return x;
+}
+
+consteval auto is_operator (operators op)
+{
+  return [op] (info mem) { return is_operator_function (mem) && operator_of (mem) == op; };
+}
+
+constexpr auto implicitDefLine = std::source_location::current ().line ()+2;
+struct
+ImplicitDef
+{};
+
+static_assert (source_location_of (select_mem (^^ImplicitDef, is_default_constructor)).line () == implicitDefLine);
+static_assert (source_location_of (select_mem (^^ImplicitDef, is_copy_constructor)).line () == implicitDefLine);
+static_assert (source_location_of (select_mem (^^ImplicitDef, is_move_constructor)).line () == implicitDefLine);
+static_assert (source_location_of (select_mem (^^ImplicitDef, is_copy_assignment)).line () == implicitDefLine);
+static_assert (source_location_of (select_mem (^^ImplicitDef, is_move_assignment)).line () == implicitDefLine);
+static_assert (source_location_of (select_mem (^^ImplicitDef, is_destructor)).line () == implicitDefLine);
+
+constexpr auto implicitEqLine = std::source_location::current ().line ()+3;
+struct ImplicitEq
+{
+  auto operator<=> (const ImplicitEq&) const = default;
+};
+
+// Would expect either class head, or operator<=> line
+static_assert (source_location_of (^^ImplicitEq::operator==).line () == 0);
+static_assert (source_location_of (select_mem (^^ImplicitEq, is_operator (op_equals_equals))).line () == implicitEqLine);
+static_assert (source_location_of (select_mem (^^ImplicitEq, is_operator (op_spaceship))).line () == implicitEqLine);
diff --git a/gcc/testsuite/g++.dg/reflect/splice1.C b/gcc/testsuite/g++.dg/reflect/splice1.C
new file mode 100644 (file)
index 0000000..fd9fab1
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+#include <ranges>
+
+using namespace std::meta;
+
+struct S {
+  int mem;
+  int : 5;
+};
+struct T : public S {
+};
+
+[[=1]] void
+foo ()
+{
+  S s = { 0 }, t = { 0 };
+  constexpr auto ctx = access_context::unchecked ();
+  s.[: members_of (^^S, ctx)[1] :] = 1;        // { dg-error "cannot use an unnamed bit-field .S::<anonymous>. in a splice expression" }
+  s.[: (members_of (^^S, ctx) | std::views::filter (is_default_constructor) | std::ranges::to <std::vector> ())[0] :] ();      // { dg-error "cannot use constructor or destructor .constexpr S::S\\(\\). in a splice expression" }
+  s.[: (members_of (^^S, ctx) | std::views::filter (is_copy_constructor) | std::ranges::to <std::vector> ())[0] :] (t);                // { dg-error "cannot use constructor or destructor .constexpr S::S\\(const S&\\). in a splice expression" }
+  s.[: (members_of (^^S, ctx) | std::views::filter (is_destructor) | std::ranges::to <std::vector> ())[0] :] ();               // { dg-error "cannot use constructor or destructor .constexpr S::~S\\(\\). in a splice expression" }
+  [: annotations_of (^^foo)[0] :]; // { dg-error "cannot use an annotation .1. in a splice expression" }
+  [: data_member_spec (^^S, { .name = "name" }) :]; // { dg-error "cannot use a data member specification in a splice expression" }
+  [: bases_of (^^T, ctx)[0] :];                                                                                                        // { dg-error "" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/splice2.C b/gcc/testsuite/g++.dg/reflect/splice2.C
new file mode 100644 (file)
index 0000000..73de0ab
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+constexpr int foo (int) { return 42; };
+constexpr auto bar = ^^foo;
+constexpr int foo (long) { return 43; }
+constexpr int foo (long long) { return 44; }
+static_assert (foo (0) == 42);
+static_assert (foo (0L) == 43);
+static_assert (foo (0LL) == 44);
+static_assert ([: bar :] (0) == 42);
+static_assert ([: bar :] (0L) == 42);
+static_assert ([: bar :] (0LL) == 42);
diff --git a/gcc/testsuite/g++.dg/reflect/splice3.C b/gcc/testsuite/g++.dg/reflect/splice3.C
new file mode 100644 (file)
index 0000000..8843444
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A { static int x; };
+int q = A ().[: ^^x :];  // { dg-error "'x' has not been declared" }
diff --git a/gcc/testsuite/g++.dg/reflect/splice4.C b/gcc/testsuite/g++.dg/reflect/splice4.C
new file mode 100644 (file)
index 0000000..29567d2
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+namespace M
+{
+  template <int N>
+  constexpr int foo () { return N; }
+}
+
+static_assert (template [: ^^M::foo :] <42> () == 42);
+static_assert (template [: members_of (^^M, std::meta::access_context::unchecked ())[0] :] <43> () == 43);
+int a = [: ^^M::foo :] <44> ();
+// { dg-error "reflection 'M::foo<44>' not usable in a splice expression with template arguments" "" { target *-*-* } .-1 }
+int b = [: members_of (^^M, std::meta::access_context::unchecked ())[0] :] <45> ();
+// { dg-error "reflection 'M::foo<45>' not usable in a splice expression with template arguments" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/reflect/splice5.C b/gcc/testsuite/g++.dg/reflect/splice5.C
new file mode 100644 (file)
index 0000000..f06e227
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+void foo (int);
+template <typename T>
+void bar (T);
+struct S {
+  void foo (int);
+  template <typename T>
+  void bar (T);
+};
+
+void
+baz (S &s)
+{
+  template [: ^^foo :] (0);                    // { dg-error "reflection 'foo' not usable in a template splice" }
+  template [: ^^bar :] (0);                    // { dg-message "only function templates are allowed here" "" { target *-*-* } .-1 }
+  s.template [: ^^S::foo :] (0);               // { dg-error "reflection 'S::foo' not usable in a template splice" }
+  s.template [: ^^S::bar :] (0);               // { dg-message "only function templates are allowed here" "" { target *-*-* } .-1 }
+}
+
+template <int N>
+void
+qux (S &s)
+{
+  // TODO: We don't reject this one.
+  template [: N == 0 ? ^^foo : ^^:: :] (0);    // { dg-error "reflection 'foo' not usable in a template splice" "" { xfail *-*-* } }
+  template [: N == 0 ? ^^bar : ^^:: :] (0);    // { dg-message "only function templates are allowed here" "" { xfail *-*-* } .-1 }
+  // TODO: The first one should be rejected, the second one accepted.
+  // We emit nonsensical unrelated errors.
+  // s.template [: N == 0 ? ^^S::foo : ^^:: :] (0);
+  // s.template [: N == 0 ? ^^S::bar : ^^:: :] (0);
+}
+
+void
+corge (S &s)
+{
+  qux <0> (s);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/splice6.C b/gcc/testsuite/g++.dg/reflect/splice6.C
new file mode 100644 (file)
index 0000000..798bd48
--- /dev/null
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template <typename U>
+constexpr int foo (int x, const U &) { return 41 + x; }
+constexpr auto foo1 = ^^foo;
+template <typename U>
+constexpr int foo (long x, const U &) { return 42 + x; }
+template <typename U>
+constexpr int foo (long long x, const U &) { return 43 + x; }
+
+static_assert (template [:foo1:] (1, 1.0f) == 42);
+static_assert (template [:foo1:] (1L, 1.0) == 42);
+static_assert (template [:foo1:] (1LL, 1.0L) == 42);
+static_assert (template [:foo1:] <float> (1, 1.0f) == 42);
+static_assert (template [:foo1:] <double> (1L, 1.0) == 42);
+static_assert (template [:foo1:] <long double> (1LL, 1.0L) == 42);
+
+template <int N>
+void
+bar ()
+{
+  static_assert (template [:foo1:] (1, 1.0f) == N);
+  static_assert (template [:foo1:] (1L, 1.0) == N);
+  static_assert (template [:foo1:] (1LL, 1.0L) == N);
+  static_assert (template [:foo1:] <float> (1, 1.0f) == N);
+  static_assert (template [:foo1:] <double> (1L, 1.0) == N);
+  static_assert (template [:foo1:] <long double> (1LL, 1.0L) == N);
+}
+
+template <auto f>
+void
+baz ()
+{
+  static_assert (template [:f:] (1, 1.0f) == 42);
+  static_assert (template [:f:] (1L, 1.0) == 42);
+  static_assert (template [:f:] (1LL, 1.0L) == 42);
+  static_assert (template [:f:] <float> (1, 1.0f) == 42);
+  static_assert (template [:f:] <double> (1L, 1.0) == 42);
+  static_assert (template [:f:] <long double> (1LL, 1.0L) == 42);
+}
+
+void
+qux ()
+{
+  bar <42> ();
+  baz <foo1> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/splice7.C b/gcc/testsuite/g++.dg/reflect/splice7.C
new file mode 100644 (file)
index 0000000..50426c9
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+constexpr int x = 42;
+struct S { static constexpr int x = 20; template <int N> static constexpr int a = N; };
+static_assert (S {}.template [:^^S::a:]<x> == 42);
diff --git a/gcc/testsuite/g++.dg/reflect/splicing-base1.C b/gcc/testsuite/g++.dg/reflect/splicing-base1.C
new file mode 100644 (file)
index 0000000..0838750
--- /dev/null
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test from [expr.ref].
+
+#include <meta>
+
+struct B {
+  int b;
+};
+struct C : B {
+  constexpr int get() const { return b; }
+};
+struct D : B, C { }; // { dg-warning "inaccessible" }
+
+constexpr int f() {
+  D d = {1, {}};
+
+  // b unambiguously refers to the direct base class of type B,
+  // not the indirect base class of type B
+  B& b = d.[: std::meta::bases_of(^^D, std::meta::access_context::current())[0] :];
+  b.b += 10;
+  return 10 * b.b + d.get();
+}
+static_assert(f() == 110);
diff --git a/gcc/testsuite/g++.dg/reflect/splicing-base2.C b/gcc/testsuite/g++.dg/reflect/splicing-base2.C
new file mode 100644 (file)
index 0000000..d7b96e6
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+using namespace std::meta;
+
+struct B {
+  int b;
+};
+struct D : B { };
+
+template<info R>
+constexpr int
+f ()
+{
+  D d = {42};
+  B& b = d.[:R:];
+  return b.b;
+}
+static_assert (f<bases_of(^^D, access_context::current ())[0]> () == 42);
+
+template<info R>
+constexpr int
+g ()
+{
+  D d = {42};
+  B *bp = &d.[:R:];
+  return bp->b;
+}
+static_assert (g<bases_of(^^D, access_context::current ())[0]> () == 42);
diff --git a/gcc/testsuite/g++.dg/reflect/splicing-base3.C b/gcc/testsuite/g++.dg/reflect/splicing-base3.C
new file mode 100644 (file)
index 0000000..92faa11
--- /dev/null
@@ -0,0 +1,112 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+struct D { int d; };
+struct E { int e; };
+struct F { int f; };
+struct G { int g; };
+struct H { int h; };
+struct I : public A, protected B, private C { int i; };
+struct J : protected D, private E, public F { int j; };
+struct K : public G, protected I, private H, public J { int k; };
+struct L : virtual A { int l; };
+struct M : virtual A { int m; };
+struct N : public L, protected M, public virtual A { int n; };
+
+constexpr access_context gctx = access_context::current ();
+constexpr access_context uctx = access_context::unchecked ();
+
+void
+g ()
+{
+  I i;
+  A &a1 = i.[: bases_of(^^I, gctx)[0] :];
+  a1.a++;
+  A &a2 = i.[: bases_of(^^I, uctx)[0] :];
+  a2.a++;
+  B &b = i.[: bases_of(^^I, uctx)[1] :];
+  b.b++;
+  C &c = i.[: bases_of(^^I, uctx)[2] :];
+  c.c++;
+  A *ap1 = &i.[: bases_of(^^I, gctx)[0] :];
+  ap1->a++;
+  A *ap2 = &i.[: bases_of(^^I, uctx)[0] :];
+  ap2->a++;
+  B *bp = &i.[: bases_of(^^I, uctx)[1] :];
+  bp->b++;
+  C *cp = &i.[: bases_of(^^I, uctx)[2] :];
+  cp->c++;
+
+  J j;
+  F &f1 = j.[: bases_of(^^J, gctx)[0] :];
+  f1.f++;
+  D &d = j.[: bases_of(^^J, uctx)[0] :];
+  d.d++;
+  E &e = j.[: bases_of(^^J, uctx)[1] :];
+  e.e++;
+  F &f2 = j.[: bases_of(^^J, uctx)[2] :];
+  f2.f++;
+  F *fp1 = &j.[: bases_of(^^J, gctx)[0] :];
+  fp1->f++;
+  D *dp = &j.[: bases_of(^^J, uctx)[0] :];
+  dp->d++;
+  E *ep = &j.[: bases_of(^^J, uctx)[1] :];
+  ep->e++;
+  F *fp2 = &j.[: bases_of(^^J, uctx)[2] :];
+  fp2->f++;
+
+  K k;
+  G &g1 = k.[: bases_of(^^K, gctx)[0] :];
+  g1.g++;
+  J &j1 = k.[: bases_of(^^K, gctx)[1] :];
+  j1.j++;
+  G *gp = &k.[: bases_of(^^K, gctx)[0] :];
+  gp->g++;
+  J *jp1 = &k.[: bases_of(^^K, gctx)[1] :];
+  jp1->j++;
+  G &g2 = k.[: bases_of(^^K, uctx)[0] :];
+  g2.g++;
+  I &i2 = k.[: bases_of(^^K, uctx)[1] :];
+  i2.i++;
+  H &h = k.[: bases_of(^^K, uctx)[2] :];
+  h.h++;
+  J &j3 = k.[: bases_of(^^K, uctx)[3] :];
+  j3.j++;
+  G *gp2 = &k.[: bases_of(^^K, uctx)[0] :];
+  gp2->g++;
+  I *ip2 = &k.[: bases_of(^^K, uctx)[1] :];
+  ip2->i++;
+  H *hp = &k.[: bases_of(^^K, uctx)[2] :];
+  hp->h++;
+  J *jp3 = &k.[: bases_of(^^K, uctx)[3] :];
+  jp3->j++;
+
+  N n;
+  L &l = n.[: bases_of(^^N, gctx)[0] :];
+  l.l++;
+  A &a3 = n.[: bases_of(^^N, gctx)[1] :];
+  a3.a++;
+  L *lp = &n.[: bases_of(^^N, gctx)[0] :];
+  lp->l++;
+  A *ap3 = &n.[: bases_of(^^N, gctx)[1] :];
+  ap3->a++;
+  L &l2 = n.[: bases_of(^^N, uctx)[0] :];
+  l2.l++;
+  M &m = n.[: bases_of(^^N, uctx)[1] :];
+  m.m++;
+  A &a4 = n.[: bases_of(^^N, uctx)[2] :];
+  a4.a++;
+  L *lp2 = &n.[: bases_of(^^N, uctx)[0] :];
+  lp2->l++;
+  M *mp = &n.[: bases_of(^^N, uctx)[1] :];
+  mp->m++;
+  A *ap4 = &n.[: bases_of(^^N, uctx)[2] :];
+  ap4->a++;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/splicing-base4.C b/gcc/testsuite/g++.dg/reflect/splicing-base4.C
new file mode 100644 (file)
index 0000000..1f9bd3d
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a; };
+struct B { int b; };
+struct C : A, B { };
+struct D : A, B { };
+
+constexpr access_context uctx = access_context::unchecked ();
+
+void
+g ()
+{
+  A a{1};
+  A &ar = a.[: bases_of(^^A, uctx)[0] :];
+  C c;
+  A &a2 = c.[: bases_of(^^C, uctx)[0] :];
+  B &b = c.[: bases_of(^^C, uctx)[0] :]; // { dg-error "invalid initialization of reference" }
+  A *ap = &c.[: bases_of(^^C, uctx)[1] :];  // { dg-error "cannot convert" }
+  A &a3 = c.[: bases_of(^^D, uctx)[0] :]; // { dg-error "not a base type for type" }
+  B &b2 = c.[: bases_of(^^D, uctx)[1] :]; // { dg-error "not a base type for type" }
+}
+
+// { dg-error "call to non-.constexpr." "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/reflect/storage_duration1.C b/gcc/testsuite/g++.dg/reflect/storage_duration1.C
new file mode 100644 (file)
index 0000000..ca64346
--- /dev/null
@@ -0,0 +1,141 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_{static,thread,automatic}_storage_duration.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  int nsdm;
+  static_assert (!has_static_storage_duration (^^nsdm));
+  static_assert (!has_thread_storage_duration (^^nsdm));
+  static_assert (!has_automatic_storage_duration (^^nsdm));
+
+  static inline int sdm;
+  static_assert (has_static_storage_duration (^^sdm));
+  static_assert (!has_thread_storage_duration (^^sdm));
+  static_assert (!has_automatic_storage_duration (^^sdm));
+
+  static thread_local int stdm;
+  static_assert (!has_static_storage_duration (^^stdm));
+  static_assert (has_thread_storage_duration (^^stdm));
+  static_assert (!has_automatic_storage_duration (^^stdm));
+
+  static void smemfn ();
+  static_assert (!has_static_storage_duration (^^smemfn));
+  static_assert (!has_thread_storage_duration (^^smemfn));
+  static_assert (!has_automatic_storage_duration (^^smemfn));
+
+  void memfn ();
+  static_assert (!has_static_storage_duration (^^memfn));
+  static_assert (!has_thread_storage_duration (^^memfn));
+  static_assert (!has_automatic_storage_duration (^^memfn));
+};
+
+extern int i0;
+static_assert (has_static_storage_duration (^^i0));
+static_assert (!has_thread_storage_duration (^^i0));
+static_assert (!has_automatic_storage_duration (^^i0));
+
+int i1;
+static_assert (has_static_storage_duration (^^i1));
+static_assert (!has_thread_storage_duration (^^i1));
+static_assert (!has_automatic_storage_duration (^^i1));
+
+static int i2;
+static_assert (has_static_storage_duration (^^i2));
+static_assert (!has_thread_storage_duration (^^i2));
+static_assert (!has_automatic_storage_duration (^^i2));
+
+thread_local int i3;
+static_assert (!has_static_storage_duration (^^i3));
+static_assert (has_thread_storage_duration (^^i3));
+static_assert (!has_automatic_storage_duration (^^i3));
+
+static thread_local int i4;
+static_assert (!has_static_storage_duration (^^i4));
+static_assert (has_thread_storage_duration (^^i4));
+static_assert (!has_automatic_storage_duration (^^i4));
+
+void
+foo (float parm)
+{
+  static_assert (!has_static_storage_duration (^^foo));
+  static_assert (!has_thread_storage_duration (^^foo));
+  static_assert (!has_automatic_storage_duration (^^foo));
+
+  static_assert (!has_static_storage_duration (^^parm));
+  static_assert (!has_thread_storage_duration (^^parm));
+  static_assert (has_automatic_storage_duration (^^parm));
+
+  int nonstatic_var;
+  static_assert (!has_static_storage_duration (^^nonstatic_var));
+  static_assert (!has_thread_storage_duration (^^nonstatic_var));
+  static_assert (has_automatic_storage_duration (^^nonstatic_var));
+
+  int& ref_to_nonstatic_var = nonstatic_var;
+  static_assert (!has_static_storage_duration (^^ref_to_nonstatic_var));
+  static_assert (!has_thread_storage_duration (^^ref_to_nonstatic_var));
+  static_assert (has_automatic_storage_duration (^^ref_to_nonstatic_var));
+
+  static int& static_ref_to_var = nonstatic_var;
+  static_assert (has_static_storage_duration (^^static_ref_to_var));
+  static_assert (!has_thread_storage_duration (^^static_ref_to_var));
+  static_assert (!has_automatic_storage_duration (^^static_ref_to_var));
+
+  static int static_var;
+  static_assert (has_static_storage_duration (^^static_var));
+  static_assert (!has_thread_storage_duration (^^static_var));
+  static_assert (!has_automatic_storage_duration (^^static_var));
+
+  int& ref_to_static_var = static_var;
+  static_assert (!has_static_storage_duration (^^ref_to_static_var));
+  static_assert (!has_thread_storage_duration (^^ref_to_static_var));
+  static_assert (has_automatic_storage_duration (^^ref_to_static_var));
+
+  thread_local int tl_var;
+  static_assert (!has_static_storage_duration (^^tl_var));
+  static_assert (has_thread_storage_duration (^^tl_var));
+  static_assert (!has_automatic_storage_duration (^^tl_var));
+
+  std::pair<int, int> p;
+  auto [aa, ab] = p;
+  static_assert (!has_static_storage_duration (^^aa));
+  static_assert (!has_thread_storage_duration (^^aa));
+  static_assert (!has_automatic_storage_duration (^^aa));
+
+  static auto [sa, sb] = p;
+  static_assert (!has_static_storage_duration (^^sa));
+  static_assert (!has_thread_storage_duration (^^sa));
+  static_assert (!has_automatic_storage_duration (^^sa));
+
+  thread_local auto [ta, tb] = p;
+  static_assert (!has_static_storage_duration (^^ta));
+  static_assert (!has_thread_storage_duration (^^ta));
+  static_assert (!has_automatic_storage_duration (^^ta));
+}
+
+template<auto V> struct TCls {};
+static_assert (!has_static_storage_duration (template_arguments_of (^^TCls<5>)[0]));
+static_assert (!has_thread_storage_duration (template_arguments_of (^^TCls<5>)[0]));
+static_assert (!has_automatic_storage_duration (template_arguments_of (^^TCls<5>)[0]));
+
+static_assert (has_static_storage_duration (template_arguments_of (^^TCls<S{}>)[0]));
+static_assert (!has_thread_storage_duration (template_arguments_of (^^TCls<S{}>)[0]));
+static_assert (!has_automatic_storage_duration (template_arguments_of (^^TCls<S{}>)[0]));
+
+template<auto K> constexpr auto R = reflect_object (K);
+static_assert (has_static_storage_duration (R<S{}>));
+static_assert (!has_thread_storage_duration (R<S{}>));
+static_assert (!has_automatic_storage_duration (R<S{}>));
+
+static std::pair<int, int> p;
+constexpr auto first = reflect_object (p.first);
+static_assert (has_static_storage_duration (first));
+static_assert (!has_thread_storage_duration (first));
+static_assert (!has_automatic_storage_duration (first));
+
+static_assert (!has_static_storage_duration (reflect_constant(4)));
+static_assert (!has_thread_storage_duration (reflect_constant(4)));
+static_assert (!has_automatic_storage_duration (reflect_constant(4)));
diff --git a/gcc/testsuite/g++.dg/reflect/storage_duration2.C b/gcc/testsuite/g++.dg/reflect/storage_duration2.C
new file mode 100644 (file)
index 0000000..86f9bf5
--- /dev/null
@@ -0,0 +1,218 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_{static,thread,automatic}_storage_duration.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+static_assert (!has_static_storage_duration (null_reflection));
+static_assert (!has_thread_storage_duration (null_reflection));
+static_assert (!has_automatic_storage_duration (null_reflection));
+
+static_assert (!has_static_storage_duration (^^::));
+static_assert (!has_thread_storage_duration (^^::));
+static_assert (!has_automatic_storage_duration (^^::));
+
+static_assert (!has_static_storage_duration (reflect_constant (3)));
+static_assert (!has_thread_storage_duration (reflect_constant (3)));
+static_assert (!has_automatic_storage_duration (reflect_constant (3)));
+
+static_assert (!has_static_storage_duration (^^cls));
+static_assert (!has_thread_storage_duration (^^cls));
+static_assert (!has_automatic_storage_duration (^^cls));
+
+static_assert (!has_static_storage_duration (^^cls::dm));
+static_assert (!has_thread_storage_duration (^^cls::dm));
+static_assert (!has_automatic_storage_duration (^^cls::dm));
+
+static_assert (!has_static_storage_duration (^^cls::ref_dm));
+static_assert (!has_thread_storage_duration (^^cls::ref_dm));
+static_assert (!has_automatic_storage_duration (^^cls::ref_dm));
+
+static_assert (has_static_storage_duration (^^cls::static_dm));
+static_assert (!has_thread_storage_duration (^^cls::static_dm));
+static_assert (!has_automatic_storage_duration (^^cls::static_dm));
+
+
+static_assert (!has_static_storage_duration (^^cls::mem_fun));
+static_assert (!has_thread_storage_duration (^^cls::mem_fun));
+static_assert (!has_automatic_storage_duration (^^cls::mem_fun));
+
+static_assert (!has_static_storage_duration (^^cls::static_mem_fun));
+static_assert (!has_thread_storage_duration (^^cls::static_mem_fun));
+static_assert (!has_automatic_storage_duration (^^cls::static_mem_fun));
+
+static_assert (!has_static_storage_duration (^^cls::type));
+static_assert (!has_thread_storage_duration (^^cls::type));
+static_assert (!has_automatic_storage_duration (^^cls::type));
+
+static_assert (has_static_storage_duration (^^cls_var));
+static_assert (!has_thread_storage_duration (^^cls_var));
+static_assert (!has_automatic_storage_duration (^^cls_var));
+
+static_assert (!has_static_storage_duration (^^onion));
+static_assert (!has_thread_storage_duration (^^onion));
+static_assert (!has_automatic_storage_duration (^^onion));
+
+static_assert (!has_static_storage_duration (^^anon));
+static_assert (!has_thread_storage_duration (^^anon));
+static_assert (!has_automatic_storage_duration (^^anon));
+
+static_assert (!has_static_storage_duration (^^fun));
+static_assert (!has_thread_storage_duration (^^fun));
+static_assert (!has_automatic_storage_duration (^^fun));
+
+static_assert (!has_static_storage_duration (^^alias));
+static_assert (!has_thread_storage_duration (^^alias));
+static_assert (!has_automatic_storage_duration (^^alias));
+
+static_assert (has_static_storage_duration (^^var));
+static_assert (!has_thread_storage_duration (^^var));
+static_assert (!has_automatic_storage_duration (^^var));
+
+static_assert (has_static_storage_duration (^^ref));
+static_assert (!has_thread_storage_duration (^^ref));
+static_assert (!has_automatic_storage_duration (^^ref));
+
+static_assert (has_static_storage_duration (^^rref));
+static_assert (!has_thread_storage_duration (^^rref));
+static_assert (!has_automatic_storage_duration (^^rref));
+
+static_assert (has_static_storage_duration (^^ptr));
+static_assert (!has_thread_storage_duration (^^ptr));
+static_assert (!has_automatic_storage_duration (^^ptr));
+
+static_assert (!has_static_storage_duration (^^cls_tmpl));
+static_assert (!has_thread_storage_duration (^^cls_tmpl));
+static_assert (!has_automatic_storage_duration (^^cls_tmpl));
+
+static_assert (!has_static_storage_duration (^^cls_tmpl<int>));
+static_assert (!has_thread_storage_duration (^^cls_tmpl<int>));
+static_assert (!has_automatic_storage_duration (^^cls_tmpl<int>));
+
+static_assert (!has_static_storage_duration (^^incomplete_cls<int>));
+static_assert (!has_thread_storage_duration (^^incomplete_cls<int>));
+static_assert (!has_automatic_storage_duration (^^incomplete_cls<int>));
+
+static_assert (!has_static_storage_duration (^^fun_tmpl));
+static_assert (!has_thread_storage_duration (^^fun_tmpl));
+static_assert (!has_automatic_storage_duration (^^fun_tmpl));
+
+static_assert (!has_static_storage_duration (^^fun_tmpl<int>));
+static_assert (!has_thread_storage_duration (^^fun_tmpl<int>));
+static_assert (!has_automatic_storage_duration (^^fun_tmpl<int>));
+
+static_assert (!has_static_storage_duration (^^conc));
+static_assert (!has_thread_storage_duration (^^conc));
+static_assert (!has_automatic_storage_duration (^^conc));
+
+static_assert (!has_static_storage_duration (substitute (^^conc, {^^int})));
+static_assert (!has_thread_storage_duration (substitute (^^conc, {^^int})));
+static_assert (!has_automatic_storage_duration (substitute (^^conc, {^^int})));
+
+static_assert (!has_static_storage_duration (^^var_tmpl));
+static_assert (!has_thread_storage_duration (^^var_tmpl));
+static_assert (!has_automatic_storage_duration (^^var_tmpl));
+
+static_assert (has_static_storage_duration (^^var_tmpl<int>));
+static_assert (!has_thread_storage_duration (^^var_tmpl<int>));
+static_assert (!has_automatic_storage_duration (^^var_tmpl<int>));
+
+static_assert (!has_static_storage_duration (^^cls_tmpl_alias));
+static_assert (!has_thread_storage_duration (^^cls_tmpl_alias));
+static_assert (!has_automatic_storage_duration (^^cls_tmpl_alias));
+
+static_assert (!has_static_storage_duration (^^cls_tmpl_alias<int>));
+static_assert (!has_thread_storage_duration (^^cls_tmpl_alias<int>));
+static_assert (!has_automatic_storage_duration (^^cls_tmpl_alias<int>));
+
+static_assert (!has_static_storage_duration (^^Enum));
+static_assert (!has_thread_storage_duration (^^Enum));
+static_assert (!has_automatic_storage_duration (^^Enum));
+
+static_assert (!has_static_storage_duration (^^Enum::A));
+static_assert (!has_thread_storage_duration (^^Enum::A));
+static_assert (!has_automatic_storage_duration (^^Enum::A));
+
+static_assert (!has_static_storage_duration (^^Enum_class));
+static_assert (!has_thread_storage_duration (^^Enum_class));
+static_assert (!has_automatic_storage_duration (^^Enum_class));
+
+static_assert (!has_static_storage_duration (^^Enum_class::A));
+static_assert (!has_thread_storage_duration (^^Enum_class::A));
+static_assert (!has_automatic_storage_duration (^^Enum_class::A));
+
+static_assert (!has_static_storage_duration (^^decomp));
+static_assert (!has_thread_storage_duration (^^decomp));
+static_assert (!has_automatic_storage_duration (^^decomp));
+
+static_assert (!has_static_storage_duration (^^decomp_ref));
+static_assert (!has_thread_storage_duration (^^decomp_ref));
+static_assert (!has_automatic_storage_duration (^^decomp_ref));
+
+static_assert (has_static_storage_duration (^^arr));
+static_assert (!has_thread_storage_duration (^^arr));
+static_assert (!has_automatic_storage_duration (^^arr));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!has_static_storage_duration (dms));
+static_assert (!has_thread_storage_duration (dms));
+static_assert (!has_automatic_storage_duration (dms));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!has_static_storage_duration (^^T));
+  static_assert (!has_thread_storage_duration (^^T));
+  static_assert (!has_automatic_storage_duration (^^T));
+  static_assert (has_static_storage_duration (R));
+  static_assert (!has_thread_storage_duration (R));
+  static_assert (!has_automatic_storage_duration (R));
+  static_assert (!has_static_storage_duration (R2));
+  static_assert (!has_thread_storage_duration (R2));
+  static_assert (!has_automatic_storage_duration (R2));
+  static_assert (!has_static_storage_duration (R3));
+  static_assert (!has_thread_storage_duration (R3));
+  static_assert (!has_automatic_storage_duration (R3));
+}
+
+void
+g ()
+{
+  f<int, ^^var, ^^ns, ^^cls>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/storage_duration3.C b/gcc/testsuite/g++.dg/reflect/storage_duration3.C
new file mode 100644 (file)
index 0000000..0fb71c8
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::has_{static,thread,automatic}_storage_duration.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { const int ci = 0; int nci; };
+struct B : A { mutable int i; };
+
+B arr[2];
+const A &r = arr[1];
+static_assert (has_static_storage_duration (^^arr));
+static_assert (!has_thread_storage_duration (^^arr));
+static_assert (!has_automatic_storage_duration (^^arr));
+static_assert (has_static_storage_duration (^^r));
+static_assert (!has_thread_storage_duration (^^r));
+static_assert (!has_automatic_storage_duration (^^r));
diff --git a/gcc/testsuite/g++.dg/reflect/subobjects_of1.C b/gcc/testsuite/g++.dg/reflect/subobjects_of1.C
new file mode 100644 (file)
index 0000000..bf8f4ef
--- /dev/null
@@ -0,0 +1,214 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::subobjects_of and has_inaccessible_subobjects.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a; };
+struct B { int b; };
+struct C { int c; };
+struct D { int d; };
+struct E { int e; };
+struct F { int f; };
+struct G { int g; };
+struct H { int h; };
+struct I : public A, protected B, private C { int i; };
+struct J : protected D, private E, public F { int j; };
+struct K : public G, protected I, private H, public J {
+public:
+  int Za;
+  static int Zb;
+  enum ZE { ZE0 };
+  using Zc = int;
+  typedef long Zd;
+  template <typename T>
+  struct ZA {};
+  template <typename T>
+  static consteval bool Zfoo (const T &) { return true; }
+  template <int N>
+  static constexpr int Ze = N;
+  template <typename T>
+  using Zf = const T &;
+  void Zbar () {}
+  auto Zbaz ();
+  int Zg : 5;
+  long : 4;
+  int : 0;
+  consteval {
+    ZA <int> z = {};
+    static_assert (Ze <42> == 42);
+    Zf <int> w = 42;
+  }
+protected:
+  int Xa;
+  static int Xb;
+  enum XE { XE0 };
+  using Xc = int;
+  typedef long Xd;
+  template <typename T>
+  struct XA {};
+  template <typename T>
+  static consteval bool Xfoo (const T &) { return true; }
+  template <int N>
+  static constexpr int Xe = N;
+  template <typename T>
+  using Xf = const T &;
+  void Xbar () {}
+  auto Xbaz ();
+  int Xg : 5;
+  long : 4;
+  int : 0;
+private:
+  int Ya;
+  static int Yb;
+  enum YE { YE0 };
+  using Yc = int;
+  typedef long Yd;
+  template <typename T>
+  struct YA {};
+  template <typename T>
+  static consteval bool Yfoo (const T &) { return true; }
+  template <int N>
+  static constexpr int Ye = N;
+  template <typename T>
+  using Yf = const T &;
+  void Ybar () {}
+  auto Ybaz ();
+  int Yg : 7;
+  long : 6;
+  int : 0;
+};
+struct L : virtual A { int l; };
+struct M : virtual A { int m; };
+struct N : public L, protected M, public virtual A { int n; };
+struct O : public L, public M, public virtual A { int o; };
+struct P : public L, public M, public virtual A { protected: int p; };
+
+constexpr access_context gctx = access_context::current ();
+constexpr access_context uctx = access_context::unchecked ();
+
+static_assert (subobjects_of (^^A, uctx).size () == 1);
+static_assert (subobjects_of (^^A, uctx)[0] == nonstatic_data_members_of (^^A, uctx)[0]);
+static_assert (subobjects_of (^^B, uctx).size () == 1);
+static_assert (subobjects_of (^^B, uctx)[0] == nonstatic_data_members_of (^^B, uctx)[0]);
+static_assert (subobjects_of (^^C, uctx).size () == 1);
+static_assert (subobjects_of (^^C, uctx)[0] == nonstatic_data_members_of (^^C, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^C, uctx));
+static_assert (subobjects_of (^^D, uctx).size () == 1);
+static_assert (subobjects_of (^^D, uctx)[0] == nonstatic_data_members_of (^^D, uctx)[0]);
+static_assert (subobjects_of (^^E, uctx).size () == 1);
+static_assert (subobjects_of (^^E, uctx)[0] == nonstatic_data_members_of (^^E, uctx)[0]);
+static_assert (subobjects_of (^^F, uctx).size () == 1);
+static_assert (subobjects_of (^^F, uctx)[0] == nonstatic_data_members_of (^^F, uctx)[0]);
+static_assert (subobjects_of (^^G, uctx).size () == 1);
+static_assert (subobjects_of (^^G, uctx)[0] == nonstatic_data_members_of (^^G, uctx)[0]);
+static_assert (subobjects_of (^^H, uctx).size () == 1);
+static_assert (subobjects_of (^^H, uctx)[0] == nonstatic_data_members_of (^^H, uctx)[0]);
+static_assert (subobjects_of (^^I, uctx).size () == 4);
+static_assert (subobjects_of (^^I, uctx)[0] == bases_of (^^I, uctx)[0]);
+static_assert (subobjects_of (^^I, uctx)[1] == bases_of (^^I, uctx)[1]);
+static_assert (subobjects_of (^^I, uctx)[2] == bases_of (^^I, uctx)[2]);
+static_assert (subobjects_of (^^I, uctx)[3] == nonstatic_data_members_of (^^I, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^I, uctx));
+static_assert (subobjects_of (^^J, uctx).size () == 4);
+static_assert (subobjects_of (^^J, uctx)[0] == bases_of (^^J, uctx)[0]);
+static_assert (subobjects_of (^^J, uctx)[1] == bases_of (^^J, uctx)[1]);
+static_assert (subobjects_of (^^J, uctx)[2] == bases_of (^^J, uctx)[2]);
+static_assert (subobjects_of (^^J, uctx)[3] == nonstatic_data_members_of (^^J, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^J, uctx));
+static_assert (subobjects_of (^^K, uctx).size () == 10);
+static_assert (subobjects_of (^^K, uctx)[0] == bases_of (^^K, uctx)[0]);
+static_assert (subobjects_of (^^K, uctx)[1] == bases_of (^^K, uctx)[1]);
+static_assert (subobjects_of (^^K, uctx)[2] == bases_of (^^K, uctx)[2]);
+static_assert (subobjects_of (^^K, uctx)[3] == bases_of (^^K, uctx)[3]);
+static_assert (subobjects_of (^^K, uctx)[4] == nonstatic_data_members_of (^^K, uctx)[0]);
+static_assert (subobjects_of (^^K, uctx)[5] == nonstatic_data_members_of (^^K, uctx)[1]);
+static_assert (subobjects_of (^^K, uctx)[6] == nonstatic_data_members_of (^^K, uctx)[2]);
+static_assert (subobjects_of (^^K, uctx)[7] == nonstatic_data_members_of (^^K, uctx)[3]);
+static_assert (subobjects_of (^^K, uctx)[8] == nonstatic_data_members_of (^^K, uctx)[4]);
+static_assert (subobjects_of (^^K, uctx)[9] == nonstatic_data_members_of (^^K, uctx)[5]);
+static_assert (!has_inaccessible_subobjects (^^K, uctx));
+static_assert (subobjects_of (^^L, uctx).size () == 2);
+static_assert (subobjects_of (^^L, uctx)[0] == bases_of (^^L, uctx)[0]);
+static_assert (subobjects_of (^^L, uctx)[1] == nonstatic_data_members_of (^^L, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^L, uctx));
+static_assert (subobjects_of (^^M, uctx).size () == 2);
+static_assert (subobjects_of (^^M, uctx)[0] == bases_of (^^M, uctx)[0]);
+static_assert (subobjects_of (^^M, uctx)[1] == nonstatic_data_members_of (^^M, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^M, uctx));
+static_assert (subobjects_of (^^N, uctx).size () == 4);
+static_assert (subobjects_of (^^N, uctx)[0] == bases_of (^^N, uctx)[0]);
+static_assert (subobjects_of (^^N, uctx)[1] == bases_of (^^N, uctx)[1]);
+static_assert (subobjects_of (^^N, uctx)[2] == bases_of (^^N, uctx)[2]);
+static_assert (subobjects_of (^^N, uctx)[3] == nonstatic_data_members_of (^^N, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^N, uctx));
+static_assert (subobjects_of (^^O, uctx).size () == 4);
+static_assert (subobjects_of (^^O, uctx)[0] == bases_of (^^O, uctx)[0]);
+static_assert (subobjects_of (^^O, uctx)[1] == bases_of (^^O, uctx)[1]);
+static_assert (subobjects_of (^^O, uctx)[2] == bases_of (^^O, uctx)[2]);
+static_assert (subobjects_of (^^O, uctx)[3] == nonstatic_data_members_of (^^O, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^O, uctx));
+static_assert (subobjects_of (^^P, uctx).size () == 4);
+static_assert (subobjects_of (^^P, uctx)[0] == bases_of (^^P, uctx)[0]);
+static_assert (subobjects_of (^^P, uctx)[1] == bases_of (^^P, uctx)[1]);
+static_assert (subobjects_of (^^P, uctx)[2] == bases_of (^^P, uctx)[2]);
+static_assert (subobjects_of (^^P, uctx)[3] == nonstatic_data_members_of (^^P, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^P, uctx));
+
+static_assert (subobjects_of (^^A, gctx).size () == 1);
+static_assert (subobjects_of (^^A, gctx)[0] == nonstatic_data_members_of (^^A, uctx)[0]);
+static_assert (subobjects_of (^^B, gctx).size () == 1);
+static_assert (subobjects_of (^^B, gctx)[0] == nonstatic_data_members_of (^^B, uctx)[0]);
+static_assert (subobjects_of (^^C, gctx).size () == 1);
+static_assert (subobjects_of (^^C, gctx)[0] == nonstatic_data_members_of (^^C, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^C, gctx));
+static_assert (subobjects_of (^^D, gctx).size () == 1);
+static_assert (subobjects_of (^^D, gctx)[0] == nonstatic_data_members_of (^^D, uctx)[0]);
+static_assert (subobjects_of (^^E, gctx).size () == 1);
+static_assert (subobjects_of (^^E, gctx)[0] == nonstatic_data_members_of (^^E, uctx)[0]);
+static_assert (subobjects_of (^^F, gctx).size () == 1);
+static_assert (subobjects_of (^^F, gctx)[0] == nonstatic_data_members_of (^^F, uctx)[0]);
+static_assert (subobjects_of (^^G, gctx).size () == 1);
+static_assert (subobjects_of (^^G, gctx)[0] == nonstatic_data_members_of (^^G, uctx)[0]);
+static_assert (subobjects_of (^^H, gctx).size () == 1);
+static_assert (subobjects_of (^^H, gctx)[0] == nonstatic_data_members_of (^^H, uctx)[0]);
+static_assert (subobjects_of (^^I, gctx).size () == 2);
+static_assert (subobjects_of (^^I, gctx)[0] == bases_of (^^I, uctx)[0]);
+static_assert (subobjects_of (^^I, gctx)[1] == nonstatic_data_members_of (^^I, uctx)[0]);
+static_assert (has_inaccessible_subobjects (^^I, gctx));
+static_assert (subobjects_of (^^J, gctx).size () == 2);
+static_assert (subobjects_of (^^J, gctx)[0] == bases_of (^^J, uctx)[2]);
+static_assert (subobjects_of (^^J, gctx)[1] == nonstatic_data_members_of (^^J, uctx)[0]);
+static_assert (has_inaccessible_subobjects (^^J, gctx));
+static_assert (subobjects_of (^^K, gctx).size () == 4);
+static_assert (subobjects_of (^^K, gctx)[0] == bases_of (^^K, uctx)[0]);
+static_assert (subobjects_of (^^K, gctx)[1] == bases_of (^^K, uctx)[3]);
+static_assert (subobjects_of (^^K, gctx)[2] == ^^K::Za);
+static_assert (subobjects_of (^^K, gctx)[3] == ^^K::Zg);
+static_assert (has_inaccessible_subobjects (^^K, gctx));
+static_assert (subobjects_of (^^L, gctx).size () == 2);
+static_assert (subobjects_of (^^L, gctx)[0] == bases_of (^^L, uctx)[0]);
+static_assert (subobjects_of (^^L, gctx)[1] == nonstatic_data_members_of (^^L, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^L, uctx));
+static_assert (subobjects_of (^^M, gctx).size () == 2);
+static_assert (subobjects_of (^^M, gctx)[0] == bases_of (^^M, uctx)[0]);
+static_assert (subobjects_of (^^M, gctx)[1] == nonstatic_data_members_of (^^M, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^M, gctx));
+static_assert (subobjects_of (^^N, gctx).size () == 3);
+static_assert (subobjects_of (^^N, gctx)[0] == bases_of (^^N, uctx)[0]);
+static_assert (subobjects_of (^^N, gctx)[1] == bases_of (^^N, uctx)[2]);
+static_assert (subobjects_of (^^N, gctx)[2] == nonstatic_data_members_of (^^N, uctx)[0]);
+static_assert (has_inaccessible_subobjects (^^N, gctx));
+static_assert (subobjects_of (^^O, gctx).size () == 4);
+static_assert (subobjects_of (^^O, gctx)[0] == bases_of (^^O, uctx)[0]);
+static_assert (subobjects_of (^^O, gctx)[1] == bases_of (^^O, uctx)[1]);
+static_assert (subobjects_of (^^O, gctx)[2] == bases_of (^^O, uctx)[2]);
+static_assert (subobjects_of (^^O, gctx)[3] == nonstatic_data_members_of (^^O, uctx)[0]);
+static_assert (!has_inaccessible_subobjects (^^O, gctx));
+static_assert (subobjects_of (^^P, gctx).size () == 3);
+static_assert (subobjects_of (^^P, gctx)[0] == bases_of (^^P, uctx)[0]);
+static_assert (subobjects_of (^^P, gctx)[1] == bases_of (^^P, uctx)[1]);
+static_assert (subobjects_of (^^P, gctx)[2] == bases_of (^^P, uctx)[2]);
+static_assert (has_inaccessible_subobjects (^^P, gctx));
diff --git a/gcc/testsuite/g++.dg/reflect/substitute1.C b/gcc/testsuite/g++.dg/reflect/substitute1.C
new file mode 100644 (file)
index 0000000..76958ee
--- /dev/null
@@ -0,0 +1,238 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::substitute.
+
+#include <meta>
+#include <ranges>
+#include <vector>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+struct cls {
+  int dm;
+  static int static_dm;
+  void mem_fun ();
+  static void static_mem_fun ();
+  int &ref_dm = dm;
+  using type = int;
+} cls_var;
+union onion { };
+static union { int anon; };
+using alias = cls;
+void fun ();
+int var;
+int &ref = var;
+int &&rref = 42;
+int *ptr = &var;
+namespace ns {}
+namespace ns_alias = ns;
+enum Enum { A };
+enum class Enum_class { A };
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {};
+template<typename> void fun_tmpl ();
+template<typename> concept conc = requires { true; };
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+
+int arr[] = { 42 };
+auto [ decomp ] = arr;
+auto &[ decomp_ref ] = arr;
+
+template <reflection_range R = std::initializer_list <info>>
+consteval bool
+could_substitute (info r, R &&args)
+{
+  try { substitute (r, args); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!could_substitute (null_reflection, {}));
+static_assert (!could_substitute (^^::, {}));
+static_assert (!could_substitute (^^ns, {}));
+static_assert (!could_substitute (^^ns_alias, {}));
+static_assert (!could_substitute (reflect_constant (3), {}));
+static_assert (!could_substitute (^^cls, {}));
+static_assert (!could_substitute (^^cls::dm, {}));
+static_assert (!could_substitute (^^cls::ref_dm, {}));
+static_assert (!could_substitute (^^cls::static_dm, {}));
+static_assert (!could_substitute (^^cls::mem_fun, {}));
+static_assert (!could_substitute (^^cls::static_mem_fun, {}));
+static_assert (!could_substitute (^^cls::type, {}));
+static_assert (!could_substitute (^^cls_var, {}));
+static_assert (!could_substitute (^^onion, {}));
+static_assert (!could_substitute (^^anon, {}));
+static_assert (!could_substitute (^^fun, {}));
+static_assert (!could_substitute (^^alias, {}));
+static_assert (!could_substitute (^^var, {}));
+static_assert (!could_substitute (^^ref, {}));
+static_assert (!could_substitute (^^rref, {}));
+static_assert (!could_substitute (^^ptr, {}));
+static_assert (!could_substitute (^^cls_tmpl, {}));
+static_assert (!could_substitute (^^cls_tmpl<int>, {}));
+static_assert (!could_substitute (^^incomplete_cls<int>, {}));
+static_assert (!could_substitute (^^fun_tmpl, {}));
+static_assert (!could_substitute (^^fun_tmpl<int>, {}));
+static_assert (!could_substitute (^^conc, {}));
+static_assert (!could_substitute (substitute (^^conc, { ^^int }), {}));
+static_assert (!could_substitute (^^var_tmpl, {}));
+static_assert (!could_substitute (^^var_tmpl<int>, {}));
+static_assert (!could_substitute (^^cls_tmpl_alias, {}));
+static_assert (!could_substitute (^^cls_tmpl_alias<int>, {}));
+static_assert (!could_substitute (^^Enum, {}));
+static_assert (!could_substitute (^^Enum::A, {}));
+static_assert (!could_substitute (^^Enum_class, {}));
+static_assert (!could_substitute (^^Enum_class::A, {}));
+static_assert (!could_substitute (^^decomp, {}));
+static_assert (!could_substitute (^^decomp_ref, {}));
+static_assert (!could_substitute (^^arr, {}));
+
+constexpr auto dms = data_member_spec (^^int, { .name = "dms" });
+static_assert (!could_substitute (dms, {}));
+
+struct Base {};
+struct Derived : Base {};
+static_assert (!could_substitute (bases_of (^^Derived, access_context::current ())[0], {}));
+
+template<typename T, info R, info R2, info R3>
+void
+f ()
+{
+  static_assert (!could_substitute (^^T, {}));
+  static_assert (!could_substitute (R, {}));
+  static_assert (!could_substitute (R2, {}));
+  static_assert (!could_substitute (R3, {}));
+}
+
+void
+g (int p, cls c)
+{
+  f<int, ^^var, ^^ns, ^^cls_tmpl_alias>();
+  static_assert (!could_substitute (^^p, {}));
+  static_assert (!could_substitute (^^c, {}));
+}
+
+template <typename T>
+struct S {};
+
+template <float F, int N>
+struct T {};
+
+template <typename ...T>
+struct U {};
+
+template <typename T>
+T foo (T x) { return x; }
+
+template <int N>
+constexpr int v = N;
+
+template <typename T>
+concept C = requires { T::s; };
+
+struct V { int s; };
+
+struct NS {
+  constexpr NS (int x) : ns (x) {}
+  constexpr NS (const NS &x) : ns (x.ns) {}
+  constexpr ~NS () {}
+private:
+  int ns;
+};
+[[=1]] void bar (int x);
+
+static_assert (!could_substitute (^^S, {}));
+static_assert (!could_substitute (^^S, { null_reflection }));
+static_assert (!could_substitute (^^S, { parameters_of (^^bar)[0] }));
+static_assert (!could_substitute (^^S, { annotations_of (^^bar)[0] }));
+static_assert (!could_substitute (^^S, { ^^:: }));
+static_assert (!could_substitute (^^S, { ^^ns }));
+static_assert (!could_substitute (^^S, { ^^ns_alias }));
+static_assert (!could_substitute (^^S, { ^^NS::~NS }));
+static_assert (!could_substitute (^^S, { reflect_constant (42) }));
+constexpr int n = 42;
+static_assert (!could_substitute (^^S, { ^^n }));
+constexpr NS nsv (42);
+static_assert (!could_substitute (^^S, { ^^nsv }));
+
+static_assert (!could_substitute (^^S, {}));
+static_assert (substitute (^^S, { ^^int }) == ^^S <int>);
+static_assert (substitute (^^S, { ^^V }) == ^^S <V>);
+static_assert (substitute (^^S, { ^^NS }) == ^^S <NS>);
+static_assert (!is_value (substitute (^^S, { ^^int })));
+static_assert (!is_object (substitute (^^S, { ^^int })));
+static_assert (!could_substitute (^^S, { ^^int, ^^long }));
+static_assert (!could_substitute (^^S, { reflect_constant (42) }));
+static_assert (!could_substitute (^^S, { ^^n }));
+static_assert (!could_substitute (^^T, {}));
+static_assert (!could_substitute (^^T, { ^^float, ^^int }));
+constexpr float fv = 42.0f;
+static_assert (substitute (^^T, { ^^fv, reflect_constant (42) }) == ^^T <42.0f, 42>);
+static_assert (!is_value (substitute (^^T, { ^^fv, reflect_constant (42) })));
+static_assert (!is_object (substitute (^^T, { ^^fv, reflect_constant (42) })));
+static_assert (substitute (^^T, { ^^fv, reflect_constant (0) }) == ^^T <42.0f, 0>);
+static_assert (!is_value (substitute (^^T, { ^^fv, reflect_constant (0) })));
+static_assert (!is_object (substitute (^^T, { ^^fv, reflect_constant (0) })));
+static_assert (substitute (^^T, { ^^fv, ^^n }) == ^^T <42.0f, 42>);
+static_assert (!is_value (substitute (^^T, { ^^fv, ^^n })));
+static_assert (!is_object (substitute (^^T, { ^^fv, ^^n })));
+static_assert (!could_substitute (^^T, { ^^n, ^^fv }));
+static_assert (!could_substitute (^^T, { ^^fv, ^^n, ^^fv }));
+
+static_assert (substitute (^^U, {}) == ^^U <>);
+static_assert (!is_value (substitute (^^U, {})));
+static_assert (!is_object (substitute (^^U, {})));
+static_assert (substitute (^^U, { ^^int }) == ^^U <int>);
+static_assert (substitute (^^U, { ^^int, ^^long, ^^const int &, ^^float, ^^double }) == ^^U <int, long, const int &, float, double>);
+static_assert (substitute (^^U, std::vector <info> { ^^int, ^^long, ^^const int &, ^^float, ^^double } | std::views::reverse) == ^^U <double, float, const int &, long, int>);
+static_assert (!could_substitute (^^U, { ^^int, ^^long, ^^const int &, ^^n, ^^float }));
+
+static_assert (!could_substitute (^^v, {}));
+static_assert (substitute (^^v, { reflect_constant (15) }) == ^^v <15>);
+static_assert (!is_value (substitute (^^v, { reflect_constant (15) })));
+static_assert (!is_object (substitute (^^v, { reflect_constant (15) })));
+static_assert (substitute (^^v, { ^^n }) == ^^v <42>);
+static_assert (!is_value (substitute (^^v, { ^^n })));
+static_assert (!is_object (substitute (^^v, { ^^n })));
+static_assert (!could_substitute (^^v, { ^^n, ^^n }));
+static_assert (!could_substitute (^^v, { ^^int }));
+
+static_assert (!could_substitute (^^C, {}));
+static_assert (substitute (^^C, { ^^int }) == reflect_constant (false));
+static_assert (is_value (substitute (^^C, { ^^int })));
+static_assert (!is_object (substitute (^^C, { ^^int })));
+static_assert (substitute (^^C, { ^^V }) == reflect_constant (true));
+static_assert (is_value (substitute (^^C, { ^^V })));
+static_assert (!is_object (substitute (^^C, { ^^V })));
+static_assert (!could_substitute (^^C, { ^^int, ^^int }));
+static_assert (!could_substitute (^^C, { reflect_constant (42) }));
+static_assert (!could_substitute (^^C, { ^^n }));
+
+static_assert (!could_substitute (^^foo, {}));
+static_assert (substitute (^^foo, { ^^int }) == ^^foo <int>);
+static_assert (!is_value (substitute (^^foo, { ^^int })));
+static_assert (!is_object (substitute (^^foo, { ^^int })));
+static_assert (substitute (^^foo, { ^^int }) == ^^foo <int>);
+static_assert (substitute (^^foo, { ^^V }) == ^^foo <V>);
+static_assert (substitute (^^foo, { ^^NS }) == ^^foo <NS>);
+static_assert (!could_substitute (^^foo, { ^^int, ^^long }));
+static_assert (!could_substitute (^^foo, { reflect_constant (42) }));
+static_assert (!could_substitute (^^foo, { ^^n }));
+
+template <class T, class U>
+struct TU1 {};
+template <class T, class U>
+struct TU2 {};
+
+template <template <class, class> class T, class U, class V>
+T <U, V> baz () { return T <U, V> {}; }
+
+static_assert (return_type_of (^^baz <TU1, int, long>) == ^^TU1 <int, long>);
+static_assert (return_type_of (^^baz <TU2, double, int>) == ^^TU2 <double, int>);
+static_assert (substitute (^^baz, { ^^TU1, ^^int, ^^long }) == ^^baz <TU1, int, long>);
+static_assert (!is_value (substitute (^^baz, { ^^TU1, ^^int, ^^long })));
+static_assert (!is_object (substitute (^^baz, { ^^TU1, ^^int, ^^long })));
+static_assert (substitute (^^baz, { ^^TU2, ^^double, ^^int }) == ^^baz <TU2, double, int>);
diff --git a/gcc/testsuite/g++.dg/reflect/substitute2.C b/gcc/testsuite/g++.dg/reflect/substitute2.C
new file mode 100644 (file)
index 0000000..064f08e
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+template <info R>
+struct A {
+  static constexpr auto value = R;
+};
+
+template <class... R>
+struct B { };
+
+template <size_t I, typename J>
+using C = [: template_arguments_of (^^J)[I] :];
+
+template <class T>
+using D = [: [] {
+  std::vector<info> args;
+  for (info b : bases_of (T::value, access_context::unchecked ()))
+    args.push_back (substitute (^^A, { reflect_constant (b) }));
+  return substitute (^^B, args); } () :];
+
+struct E { };
+struct F : E { };
+
+constexpr auto b = bases_of (^^F, access_context::unchecked ())[0];
+static_assert (std::same_as <C <0, D <A <^^F>>>, A <b>>);
diff --git a/gcc/testsuite/g++.dg/reflect/symbol_of1.C b/gcc/testsuite/g++.dg/reflect/symbol_of1.C
new file mode 100644 (file)
index 0000000..7a3357c
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::symbol_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+has_symbol_of (operators op)
+{
+  try { symbol_of (op); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_symbol_of (static_cast <operators> (4242)));
+static_assert (symbol_of (op_new) == std::string_view ("new"));
+static_assert (symbol_of (op_delete) == std::string_view ("delete"));
+static_assert (symbol_of (op_array_new) == std::string_view ("new[]"));
+static_assert (symbol_of (op_array_delete) == std::string_view ("delete[]"));
+static_assert (symbol_of (op_co_await) == std::string_view ("co_await"));
+static_assert (symbol_of (op_parentheses) == std::string_view ("()"));
+static_assert (symbol_of (op_square_brackets) == std::string_view ("[]"));
+static_assert (symbol_of (op_arrow) == std::string_view ("->"));
+static_assert (symbol_of (op_arrow_star) == std::string_view ("->*"));
+static_assert (symbol_of (op_tilde) == std::string_view ("~"));
+static_assert (symbol_of (op_exclamation) == std::string_view ("!"));
+static_assert (symbol_of (op_plus) == std::string_view ("+"));
+static_assert (symbol_of (op_minus) == std::string_view ("-"));
+static_assert (symbol_of (op_star) == std::string_view ("*"));
+static_assert (symbol_of (op_slash) == std::string_view ("/"));
+static_assert (symbol_of (op_percent) == std::string_view ("%"));
+static_assert (symbol_of (op_caret) == std::string_view ("^"));
+static_assert (symbol_of (op_ampersand) == std::string_view ("&"));
+static_assert (symbol_of (op_equals) == std::string_view ("="));
+static_assert (symbol_of (op_pipe) == std::string_view ("|"));
+static_assert (symbol_of (op_plus_equals) == std::string_view ("+="));
+static_assert (symbol_of (op_minus_equals) == std::string_view ("-="));
+static_assert (symbol_of (op_star_equals) == std::string_view ("*="));
+static_assert (symbol_of (op_slash_equals) == std::string_view ("/="));
+static_assert (symbol_of (op_percent_equals) == std::string_view ("%="));
+static_assert (symbol_of (op_caret_equals) == std::string_view ("^="));
+static_assert (symbol_of (op_ampersand_equals) == std::string_view ("&="));
+static_assert (symbol_of (op_pipe_equals) == std::string_view ("|="));
+static_assert (symbol_of (op_equals_equals) == std::string_view ("=="));
+static_assert (symbol_of (op_exclamation_equals) == std::string_view ("!="));
+static_assert (symbol_of (op_less) == std::string_view ("<"));
+static_assert (symbol_of (op_greater) == std::string_view (">"));
+static_assert (symbol_of (op_less_equals) == std::string_view ("<="));
+static_assert (symbol_of (op_greater_equals) == std::string_view (">="));
+static_assert (symbol_of (op_spaceship) == std::string_view ("<=>"));
+static_assert (symbol_of (op_ampersand_ampersand) == std::string_view ("&&"));
+static_assert (symbol_of (op_pipe_pipe) == std::string_view ("||"));
+static_assert (symbol_of (op_less_less) == std::string_view ("<<"));
+static_assert (symbol_of (op_greater_greater) == std::string_view (">>"));
+static_assert (symbol_of (op_less_less_equals) == std::string_view ("<<="));
+static_assert (symbol_of (op_greater_greater_equals) == std::string_view (">>="));
+static_assert (symbol_of (op_plus_plus) == std::string_view ("++"));
+static_assert (symbol_of (op_minus_minus) == std::string_view ("--"));
+static_assert (symbol_of (op_comma) == std::string_view (","));
diff --git a/gcc/testsuite/g++.dg/reflect/symbol_of2.C b/gcc/testsuite/g++.dg/reflect/symbol_of2.C
new file mode 100644 (file)
index 0000000..5e27aa6
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-iconv "IBM1047" }
+// { dg-additional-options "-freflection -fexec-charset=IBM1047" }
+// Test std::meta::symbol_of.
+
+#include "symbol_of1.C"
diff --git a/gcc/testsuite/g++.dg/reflect/template_arguments_of1.C b/gcc/testsuite/g++.dg/reflect/template_arguments_of1.C
new file mode 100644 (file)
index 0000000..02d0036
--- /dev/null
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::template_arguments_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+template<class T, class U = T> struct Pair { };
+template<class T> struct Pair<char, T> { };
+template<class T> using PairPtr = Pair<T*>;
+
+static_assert(template_of(^^Pair<int>) == ^^Pair);
+static_assert(template_of(^^Pair<char, char>) == ^^Pair);
+static_assert(template_arguments_of(^^Pair<int>).size() == 2);
+static_assert(template_arguments_of(^^Pair<int>)[0] == ^^int);
+static_assert(template_arguments_of(^^Pair<int>)[1] == ^^int);
+
+static_assert(template_of(^^PairPtr<int>) == ^^PairPtr);
+static_assert(template_arguments_of(^^PairPtr<int>).size() == 1);
+static_assert(template_arguments_of(^^PairPtr<int>)[0] == ^^int);
+
+struct S { };
+int i;
+template<int, int&, S, template<class> class>
+  struct X { };
+constexpr auto T = ^^X<1, i, S{}, PairPtr>;
+static_assert(is_value(template_arguments_of(T)[0]));
+static_assert(!is_object(template_arguments_of(T)[0]));
+static_assert(!is_value(template_arguments_of(T)[1]));
+static_assert(is_object(template_arguments_of(T)[1]));
+static_assert(is_object(template_arguments_of(T)[2]));
+static_assert(!is_value(template_arguments_of(T)[2]));
+static_assert(!is_value(template_arguments_of(T)[3]));
+static_assert(!is_object(template_arguments_of(T)[3]));
+static_assert(template_arguments_of(T)[3] == ^^PairPtr);
diff --git a/gcc/testsuite/g++.dg/reflect/template_arguments_of2.C b/gcc/testsuite/g++.dg/reflect/template_arguments_of2.C
new file mode 100644 (file)
index 0000000..da5a44e
--- /dev/null
@@ -0,0 +1,107 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::template_arguments_of.
+// Taken from test/std/experimental/reflection/template-arguments.pass.cpp
+
+#include <meta>
+
+using namespace std::meta;
+
+template <typename P1, auto P2, template <typename...> class P3>
+struct TCls {
+  template <typename> struct TInnerCls {};
+};
+
+template <typename P1, auto P2, template <typename...> class P3>
+void TFn();
+
+template <typename P1, auto P2, template <typename...> class P3>
+int TVar = 0;
+
+template <typename P1, auto P2, template <typename...> class P3>
+using TAlias = int;
+
+template <typename P1, auto P2, template <typename...> class P3>
+concept Concept = requires { true; };
+
+
+static_assert(template_arguments_of(^^TCls<int, 9, std::vector>).size() == 3);
+static_assert(template_arguments_of(^^TCls<int, 9, std::vector>)[0] == ^^int);
+static_assert([:template_arguments_of(^^TCls<int, 9, std::vector>)[1]:] == 9);
+static_assert(template_arguments_of(^^TCls<int, 9, std::vector>)[2] == ^^std::vector);
+
+static_assert(template_arguments_of(^^TFn<int, 9, std::vector>).size() == 3);
+static_assert(template_arguments_of(^^TFn<int, 9, std::vector>)[0] == ^^int);
+static_assert([:template_arguments_of(^^TFn<int, 9, std::vector>)[1]:] == 9);
+static_assert(template_arguments_of(^^TFn<int, 9, std::vector>)[2] == ^^std::vector);
+
+static_assert(template_arguments_of(^^TVar<int, 9, std::vector>).size() == 3);
+static_assert(template_arguments_of(^^TVar<int, 9, std::vector>)[0] == ^^int);
+static_assert([:template_arguments_of(^^TVar<int, 9, std::vector>)[1]:] == 9);
+static_assert(template_arguments_of(^^TVar<int, 9, std::vector>)[2] == ^^std::vector);
+
+static_assert(template_arguments_of(^^TAlias<int, 9, std::vector>).size() == 3);
+static_assert(template_arguments_of(^^TAlias<int, 9, std::vector>)[0] == ^^int);
+static_assert([:template_arguments_of(^^TAlias<int, 9, std::vector>)[1]:] == 9);
+static_assert(template_arguments_of(^^TAlias<int, 9, std::vector>)[2] == ^^std::vector);
+
+template <typename T>
+using DependentAlias = TCls<int, 9, std::vector>::template TInnerCls<T>;
+static_assert(template_arguments_of(^^DependentAlias<int>).size() == 1);
+static_assert(template_arguments_of(^^DependentAlias<int>)[0] == ^^int);
+
+template <typename T, T Val> struct WithDependentArgument {};
+static_assert(template_arguments_of(^^WithDependentArgument<int, 5>).size() == 2);
+static_assert(template_arguments_of(^^WithDependentArgument<int, 5>)[0] == ^^int);
+
+template <typename... Ts> struct WithTypeParamPack {};
+static_assert(template_arguments_of(^^WithTypeParamPack<int, bool>).size() == 2);
+static_assert(template_arguments_of(^^WithTypeParamPack<int, bool>)[0] == ^^int);
+static_assert(template_arguments_of(^^WithTypeParamPack<int, bool>)[1] == ^^bool);
+static_assert(template_arguments_of(^^WithTypeParamPack<>).size() == 0);
+
+struct S {
+  int mem;
+  bool operator==(const S&) const = default;
+};
+template <auto... Vs> struct WithAutoParamPack {};
+
+static_assert(template_arguments_of(^^WithAutoParamPack<4, S{3}>).size() == 2);
+static_assert([:template_arguments_of(^^WithAutoParamPack<4, S{3}>)[0]:] == 4);
+static_assert([:template_arguments_of(^^WithAutoParamPack<4, S{3}>)[1]:] == S{3});
+static_assert(template_arguments_of(^^WithAutoParamPack<>).size() == 0);
+
+template <float> struct WithFloat {};
+template <const float *> struct WithPtr {};
+template <const int &> struct WithRef {};
+template <info> struct WithReflection {};
+
+constexpr float F = 4.5f;
+static_assert(template_arguments_of(^^WithFloat<F>).size() == 1);
+static_assert([:template_arguments_of(^^WithFloat<F>)[0]:] == F);
+
+constexpr float Fs[] = {4.5, 5.5, 6.5};
+static_assert(template_arguments_of(^^WithPtr<Fs>).size() == 1);
+static_assert([:template_arguments_of(^^WithPtr<Fs>)[0]:] == +Fs);
+
+static_assert(template_arguments_of(^^WithPtr<nullptr>).size() == 1);
+static_assert([:template_arguments_of(^^WithPtr<nullptr>)[0]:] == nullptr);
+
+const int I = 5;
+using T = WithRef<I>;
+static_assert(template_arguments_of(dealias(^^T)).size() == 1);
+static_assert([:template_arguments_of(^^WithRef<I>)[0]:] == I);
+
+static_assert(template_arguments_of(^^WithReflection<^^int>).size() == 1);
+static_assert(template_arguments_of(^^WithReflection<^^int>)[0] == reflect_constant(^^int));
+
+template <int &> void fn();
+int p[2];
+static_assert(template_arguments_of(^^fn<p[1]>)[0] == reflect_object(p[1]));
+
+template<class T> struct X {};
+X<int> obj1;
+X<decltype(obj1)> obj2;
+
+static_assert(has_template_arguments(template_arguments_of(^^decltype(obj2))[0])
+             == has_template_arguments(^^X<int>));
diff --git a/gcc/testsuite/g++.dg/reflect/template_arguments_of3.C b/gcc/testsuite/g++.dg/reflect/template_arguments_of3.C
new file mode 100644 (file)
index 0000000..d6ad5cd
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::template_arguments_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+using U = int;
+typedef double V;
+
+template<typename T, typename U>
+struct S {};
+
+static_assert (template_arguments_of (^^S<int, double>)[0] == ^^int);
+static_assert (template_arguments_of (^^S<int, double>)[1] == ^^double);
+static_assert (template_arguments_of (^^S<U, V>)[0] == ^^int);
+static_assert (template_arguments_of (^^S<U, V>)[1] == ^^double);
diff --git a/gcc/testsuite/g++.dg/reflect/template_of1.C b/gcc/testsuite/g++.dg/reflect/template_of1.C
new file mode 100644 (file)
index 0000000..2075946
--- /dev/null
@@ -0,0 +1,119 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::template_of.
+
+#include <meta>
+#include <vector>
+
+using namespace std::meta;
+
+template<typename> struct incomplete_cls;
+template<typename> struct cls_tmpl {
+  template <typename T> struct inner {};
+};
+template<typename> void fun_tmpl ();
+template<typename> int var_tmpl;
+template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
+template<typename> using int_alias = int;
+template<typename U> using dep_alias = cls_tmpl<int>::template inner<U>;
+
+static_assert (template_of (^^cls_tmpl<int>) == ^^cls_tmpl);
+static_assert (template_of (^^incomplete_cls<int>) == ^^incomplete_cls);
+static_assert (template_of (^^int_alias<int>) == ^^int_alias);
+static_assert (template_of (^^dep_alias<bool>) == ^^dep_alias);
+static_assert (template_of (^^fun_tmpl<int>) == ^^fun_tmpl);
+static_assert (template_of (^^var_tmpl<int>) == ^^var_tmpl);
+static_assert (template_of (^^cls_tmpl_alias<int>) == ^^cls_tmpl_alias);
+
+struct W {
+  using U = cls_tmpl<int>;
+};
+static_assert (template_of (dealias (^^W::U)) == ^^cls_tmpl);
+
+template <typename P1, auto P2, template <typename...> class P3>
+struct class_tmpl {
+  template <typename> struct inner {};
+};
+static_assert (template_of (^^class_tmpl<int, 9, std::vector>) == ^^class_tmpl);
+
+template <typename P1, auto P2, template <typename...> class P3>
+void fn_tmpl ();
+static_assert (template_of (^^fn_tmpl<int, 9, std::vector>) == ^^fn_tmpl);
+
+template <typename P1, auto P2, template <typename...> class P3>
+int var_tmpl2 = 0;
+static_assert (template_of (^^var_tmpl2<int, 9, std::vector>) == ^^var_tmpl2);
+
+template <typename P1, auto P2, template <typename...> class P3>
+using alias = int;
+static_assert (template_of (^^alias<int, 9, std::vector>) == ^^alias);
+
+template <typename T>
+using dep_alias2 = class_tmpl<int, 9, std::vector>::template inner<T>;
+static_assert (template_of (^^dep_alias2<int>) == ^^dep_alias2);
+
+template <typename T, T> struct A {};
+static_assert (template_of (^^A<int, 5>) == ^^A);
+
+template <typename... Ts> struct B {};
+static_assert (template_of (^^B<int, bool>) == ^^B);
+
+struct S {
+  int mem;
+  bool operator==(const S&) const = default;
+};
+template <auto... Vs> struct auto_pack {};
+static_assert (template_of (^^auto_pack<4, S{3}>) == ^^auto_pack);
+
+template <float> struct float_targ {};
+constexpr float F = 4.5f;
+static_assert (template_of (^^float_targ<F>) == ^^float_targ);
+
+template <const float *> struct ptr_targ {};
+constexpr float Fs[] = {4.5, 5.5, 6.5};
+static_assert (template_of (^^ptr_targ<Fs>) == ^^ptr_targ);
+static_assert (template_of (^^ptr_targ<nullptr>) == ^^ptr_targ);
+
+template <const int &> struct ref_targ {};
+const int I = 5;
+using T = ref_targ<I>;
+static_assert (template_of (dealias(^^T)) == ^^ref_targ);
+
+template <std::meta::info> struct refl_targ {};
+static_assert (template_of (^^refl_targ<^^int>) == ^^refl_targ);
+
+struct M {
+  template<typename T>
+  struct N { };
+};
+
+template<typename T>
+struct TS {
+  template<typename U>
+  struct N { };
+};
+
+static_assert (template_of (^^M::N<int>) == ^^M::N);
+static_assert (template_of (^^TS<int>::N<int>) == ^^TS<int>::N);
+
+template<typename T>
+struct X { };
+
+template<typename T>
+struct X<T*> { };
+
+template<>
+struct X<int> { };
+
+static_assert (template_of (^^X<int>) == ^^X);
+static_assert (template_of (^^X<int *>) == ^^X);
+
+template<typename = int>
+struct Y { };
+static_assert (template_of (^^Y<>) == ^^Y);
+
+struct Z {
+  using Alias = X<int>;
+};
+
+static_assert (template_of (dealias (^^Z::Alias)) == ^^X);
diff --git a/gcc/testsuite/g++.dg/reflect/template_of2.C b/gcc/testsuite/g++.dg/reflect/template_of2.C
new file mode 100644 (file)
index 0000000..73aa0bc
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::template_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct S {
+  template<typename T>
+  void fn (T) { }
+
+  template<typename T>
+  using U = int;
+};
+
+template<typename T>
+struct TS {
+  template<typename U>
+  void fn (T) { }
+
+  template<typename TT>
+  using U = int;
+};
+
+static_assert (template_of (^^S::fn<int>) == ^^S::fn);
+static_assert (template_of (^^TS<int>::fn<int>) == ^^TS<int>::fn);
+static_assert (template_of (^^S::U<int>) == ^^S::U);
+// FIXME
+// template<class T> template<class U> using TS<T>::W = int
+//                   template<class U> using TS<int>::W = int
+//static_assert (template_of (^^TS<int>::U<int>) == ^^TS<int>::U);
diff --git a/gcc/testsuite/g++.dg/reflect/template_of3.C b/gcc/testsuite/g++.dg/reflect/template_of3.C
new file mode 100644 (file)
index 0000000..2f7239f
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::template_of.
+
+#include <meta>
+
+consteval void
+foo ()
+{
+  template_of (^^int);
+}
+
+consteval bool
+test ()
+{
+  try { foo (); }
+  catch (std::meta::exception &) { return true; }
+  catch (...) { return false; }
+  return false;
+}
+
+static_assert (test ());
diff --git a/gcc/testsuite/g++.dg/reflect/tuple1.C b/gcc/testsuite/g++.dg/reflect/tuple1.C
new file mode 100644 (file)
index 0000000..2357eeb
--- /dev/null
@@ -0,0 +1,86 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::tuple_{size,element}.
+
+#include <array>
+#include <complex>
+#include <meta>
+#include <ranges>
+#include <tuple>
+
+using namespace std::meta;
+
+struct E {};
+
+using Tup0 = std::tuple<>;
+static_assert (tuple_size (^^Tup0) == 0);
+
+using Tup1 = std::tuple<int>;
+static_assert (tuple_size (^^Tup1) == 1);
+static_assert (tuple_element (0, ^^Tup1) == ^^int);
+
+using Tup2 = std::tuple<int, bool>;
+static_assert (tuple_size (^^Tup2) == 2);
+static_assert (tuple_element (0, ^^Tup2) == ^^int);
+static_assert (tuple_element (1, ^^Tup2) == ^^bool);
+
+using Tup3 = std::tuple<int, bool, char>;
+static_assert (tuple_size (^^Tup3) == 3);
+static_assert (tuple_element (0, ^^Tup3) == ^^int);
+static_assert (tuple_element (1, ^^Tup3) == ^^bool);
+static_assert (tuple_element (2, ^^Tup3) == ^^char);
+
+using Tup10 = std::tuple<int, int, int, int, int, int, int, int, int, int>;
+static_assert (tuple_size (^^Tup10) == 10);
+static_assert (tuple_element (0, ^^Tup10) == ^^int);
+static_assert (tuple_element (9, ^^Tup10) == ^^int);
+
+using mytype1 = float;
+using mytype2 = mytype1 *;
+static_assert (tuple_size (^^std::tuple<mytype1, mytype2>) == 2);
+static_assert (tuple_element (0, ^^std::tuple<mytype1>) == ^^float);
+static_assert (tuple_element (1, ^^std::tuple<mytype1, mytype2>) == ^^float *);
+
+static_assert (tuple_size (^^std::tuple<>) == 0);
+static_assert (tuple_size (^^std::tuple<int>) == 1);
+static_assert (tuple_size (^^std::tuple<void>) == 1);
+static_assert (tuple_size (^^std::tuple<std::tuple<void>>) == 1);
+static_assert (tuple_size (^^const std::tuple<>) == 0);
+static_assert (tuple_size (^^const std::tuple<int>) == 1);
+static_assert (tuple_size (^^const std::tuple<void>) == 1);
+static_assert (tuple_size (^^const std::tuple<std::tuple<void>>) == 1);
+
+using Arr5 = std::array<int, 5>;
+static_assert (tuple_size (^^Arr5) == 5);
+static_assert (tuple_size (^^const Arr5) == 5);
+static_assert (tuple_element (0, ^^Arr5) == ^^int);
+static_assert (tuple_element (1, ^^Arr5) == ^^int);
+static_assert (tuple_element (2, ^^Arr5) == ^^int);
+static_assert (tuple_element (3, ^^Arr5) == ^^int);
+static_assert (tuple_element (4, ^^Arr5) == ^^int);
+using Arr0 = std::array<int, 0>;
+static_assert (tuple_size (^^Arr0) == 0);
+
+using Pair = std::pair<E, int>;
+// Always 2.
+static_assert (tuple_size (^^Pair) == 2);
+static_assert (tuple_element (0, ^^Pair) == ^^E);
+static_assert (tuple_element (1, ^^Pair) == ^^int);
+
+using C = std::complex<double>;
+static_assert (tuple_size (^^C) == 2);
+static_assert (tuple_element (0, ^^C) == ^^double);
+static_assert (tuple_element (1, ^^C) == ^^double);
+
+using S1 = std::ranges::subrange<int *>;
+using S2 = std::ranges::subrange<long *, void *>;
+static_assert (tuple_size (^^S1) == 2);
+static_assert (tuple_size (^^S2) == 2);
+static_assert (tuple_element (0, ^^S1) == ^^int *);
+static_assert (tuple_element (1, ^^S1) == ^^int *);
+static_assert (tuple_element (0, ^^const S1) == ^^int *);
+static_assert (tuple_element (1, ^^const S1) == ^^int *);
+static_assert (tuple_element (0, ^^S2) == ^^long *);
+static_assert (tuple_element (1, ^^S2) == ^^void *);
+static_assert (tuple_element (0, ^^const S2) == ^^long *);
+static_assert (tuple_element (1, ^^const S2) == ^^void *);
diff --git a/gcc/testsuite/g++.dg/reflect/tuple2.C b/gcc/testsuite/g++.dg/reflect/tuple2.C
new file mode 100644 (file)
index 0000000..a4af2f5
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::tuple_{size,element}.
+
+#include <array>
+#include <meta>
+
+using namespace std::meta;
+
+constexpr auto s1 = tuple_size (^^int); // { dg-error "couldn't instantiate 'std::tuple_size<int>'" }
+int x;
+constexpr auto s2 = tuple_size (^^x); // { dg-error "uncaught exception" }
+
+constexpr auto r1 = tuple_element (666, ^^std::tuple<int>); // { dg-error "uncaught exception" }
+
+using Arr0 = std::array<int, 0>;
+constexpr auto r2 = tuple_element (1, ^^Arr0);
+
+// { dg-error "tuple index must be in range" "" { target *-*-* } 0 }
+// { dg-error "array index is in range" "" { target *-*-* } 0 }
+// { dg-error "pack index .666." "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/reflect/type1.C b/gcc/testsuite/g++.dg/reflect/type1.C
new file mode 100644 (file)
index 0000000..74bc272
--- /dev/null
@@ -0,0 +1,190 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on types.
+
+template<class, class> struct same_type;
+template<class T> struct same_type<T, T> {};
+
+using size_t = decltype(sizeof(int));
+using info = decltype(^^void);
+using T = int;
+
+struct S { int i; };
+
+constexpr auto g1 = ^^unsigned;
+constexpr auto g2 = ^^S;
+constexpr static auto g3 = ^^unsigned;
+constexpr static auto g4 = ^^S;
+constexpr info g5 = ^^void;
+constexpr info g6 = ^^decltype(42);
+constexpr info g7 = ^^T;
+constexpr info g8 = ^^decltype(^^int);
+constexpr info g9 = ^^void() const & noexcept;
+
+[: g1 :] u1;  // { dg-error "expected unqualified-id" }
+typename [: g1 :] u2;
+
+namespace N {
+  [: g1 :] nu1;  // { dg-error "expected unqualified-id" }
+  typename [: g1 :] nu2;
+}
+
+void
+f1 ()
+{
+  constexpr auto r1 = ^^int;
+  [: r1 :] v1 = 42;  // { dg-error "expected a reflection of an expression" }
+  typename [: r1 :] v1t = 42;
+  same_type<decltype(v1t), int>();
+
+  const typename [: r1 :] v2 = 42;
+  same_type<decltype(v2), const int>();
+
+  const volatile typename [: r1 :] v3 = 42;
+  same_type<decltype(v3), const volatile int>();
+  const typename [: r1 :] *v4 = &v1t;
+  same_type<decltype(v4), const int *>();
+
+  constexpr auto r2 = ^^double;
+  [: r2 :] v5 = 42.2;  // { dg-error "expected a reflection of an expression" }
+  typename [: r2 :] v5t = 42.2;
+  same_type<decltype(v5t), double>();
+
+  [: r2 :] &v6 = v5t;  // { dg-error "expected a reflection of an expression|.v6. was not declared" }
+  typename [: r2 :] &v6t = v5t;
+  same_type<decltype(v6t), double &>();
+
+  constexpr auto r3 = ^^S;
+  [: r3 :] v7 = { 42 };  // { dg-error "expected a reflection of an expression" }
+  typename [: r3 :] v7t = { 42 };
+  same_type<decltype(v7t), S>();
+  const typename [: r3 :] v8 = { 42 };
+  same_type<decltype(v8), const S>();
+
+  constexpr auto r4 = ^^long long int;
+  [: r4 :] v9 = 0ll;  // { dg-error "expected a reflection of an expression" }
+  typename [: r4 :] v9t = 0ll;
+  same_type<decltype(v9t), long long int>();
+
+  constexpr auto r5 = ^^const int;
+  [: r5 :] v10 = 0;  // { dg-error "expected a reflection of an expression" }
+  typename [: r5 :] v10t = 0;
+  same_type<decltype(v10t), const int>();
+
+  constexpr auto r6 = ^^volatile short;
+  [: r6 :] v11 = 0;  // { dg-error "expected a reflection of an expression" }
+  typename [: r6 :] v11t = 0;
+  same_type<decltype(v11t), volatile short>();
+
+  constexpr auto r7 = ^^bool;
+  [: r7 :] v12 = 0;  // { dg-error "expected a reflection of an expression" }
+  typename [: r7 :] v12t = 0;
+  same_type<decltype(v12t), bool>();
+
+  constexpr auto r8 = ^^wchar_t;
+  [: r8 :] v13 = 0;  // { dg-error "expected a reflection of an expression" }
+  typename [: r8 :] v13t = 0;
+  same_type<decltype(v13t), wchar_t>();
+
+  constexpr auto r9 = ^^decltype(sizeof 0);
+  [: r9 :] v14 = 0;  // { dg-error "expected a reflection of an expression" }
+  typename [: r9 :] v14t = 0;
+  same_type<decltype(v14t), size_t>();
+
+  constexpr auto r10 = ^^signed;
+  [: r10 :] v15 = 0;  // { dg-error "expected a reflection of an expression" }
+  typename [: r10 :] v15t = 0;
+  same_type<decltype(v15t), int>();
+
+}
+
+void
+f2 ()
+{
+  typename [:^^char:] c1 = '*';
+  same_type<decltype(c1), char>();
+
+  const typename [:^^char:] c2 = '*';
+  same_type<decltype(c2), const char>();
+
+  typename [:^^int:]* c3 = nullptr;
+  same_type<decltype(c3), int *>();
+
+  typename [:^^int:] c4 = 42;
+  same_type<decltype(c4), int>();
+
+  typename [:^^int:] &c5 = c4;
+  same_type<decltype(c5), int &>();
+
+  typename [:^^int:] arr1[10];
+  same_type<decltype(arr1), int[10]>();
+}
+
+void
+f3 ()
+{
+  typename [: g1 :] v1 = 42;
+  same_type<decltype(v1), unsigned>();
+  typename [: g3 :] v2 = 42;
+  same_type<decltype(v2), unsigned>();
+  typename [: g2 :] v3 = { 42 };
+  same_type<decltype(v3), S>();
+  typename [: g4 :] v4 = { 42 };
+  same_type<decltype(v4), S>();
+}
+
+void
+f4 ()
+{
+  static constexpr auto r = ^^unsigned;
+  constexpr auto p = &r;
+  [: *p :] i1 = 0u;  // { dg-error "expected a reflection of an expression" }
+  typename [: *p :] i2 = 0u;
+}
+
+constexpr void
+f5 ()
+{
+  static constexpr auto r = ^^unsigned;
+  constexpr auto p = &r;
+  [: *p :] i1 = 0u;  // { dg-error "expected a reflection of an expression" }
+  typename [: *p :] i2 = 0u;
+}
+
+consteval void
+f6 ()
+{
+  static constexpr auto r = ^^unsigned;
+  constexpr auto p = &r;
+  [: *p :] i1 = 0u;  // { dg-error "expected a reflection of an expression" }
+  typename [: *p :] i2 = 0u;
+  auto t = r;
+  ^^int;
+}
+
+void
+f7 ()
+{
+  {
+    {
+      constexpr auto r = ^^int;
+      typename [: r :] v = 42;
+      same_type<decltype(v), int>();
+    }
+  }
+}
+
+enum E { X, Y };
+enum class SE { yay, nay };
+
+void
+f8 ()
+{
+  constexpr auto r = ^^E;
+  [: r :] e = Y;  // { dg-error "expected a reflection of an expression" }
+  typename [: r :] et;
+
+  constexpr auto r2 = ^^SE;
+  [: r2 :] e2 = SE::yay;  // { dg-error "expected a reflection of an expression" }
+  typename [: r2 :] et2;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type10.C b/gcc/testsuite/g++.dg/reflect/type10.C
new file mode 100644 (file)
index 0000000..21e2c42
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+void fn1 ([: ^^int :]);  // { dg-error "declared void|expected a reflection of an expression" }
+void fn2 ([: ^^int :][]);  // { dg-error "declared void|expected a reflection of an expression" }
+void fn3 (typename [: ^^int :]);
+void fn4 (typename [: ^^int :] *);
+
+constexpr auto r = ^^fn3;
+void fn3 ([: r :]); // { dg-error "declared void|expected a reflection of an expression" }
+
+template<info R, info T>
+void
+g ()
+{
+  void foo(typename [:R:]);
+  foo (nullptr);
+
+  int bar(typename [:T:]);
+  bar ({});
+}
+
+struct X { };
+
+void
+f ()
+{
+  g<^^int*, ^^X>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type2.C b/gcc/testsuite/g++.dg/reflect/type2.C
new file mode 100644 (file)
index 0000000..7d1f16b
--- /dev/null
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on types.  Invalid cases.
+
+struct A;
+
+void
+f1 ()
+{
+  const auto r = ^^double; // { dg-error "consteval-only variable" }
+  constexpr auto r2 = ^^int;
+  r2; // { dg-error "consteval-only expressions" }
+  ^^void; // { dg-error "consteval-only expressions" }
+  ^^int == ^^int; // { dg-error "consteval-only expressions" }
+  (void) ^^float; // { dg-error "consteval-only expressions" }
+  auto rr = r; // { dg-error "consteval-only variable" }
+
+  constexpr auto x = &(^^int); // { dg-error "lvalue required" }
+
+  // These are verboten.
+  constexpr auto a = ^^auto;  // { dg-error "cannot be applied to" }
+  constexpr auto d = ^^decltype(auto);  // { dg-error "cannot be applied to" }
+
+  constexpr auto r3 = ^^A;
+  [: r3 :] inc;        // { dg-error "expected a reflection of an expression" }
+}
+
+constexpr void
+f2 ()
+{
+  auto r = ^^int; // { dg-error "consteval-only variable" }
+}
+
+void
+f3 ()
+{
+  [: ^^:: :] i; // { dg-error "expected" }
+  typename [: ^^:: :] i2;  // { dg-error "expected" }
+}
+
+void
+f4 ()
+{
+  using T1 = ^^int;  // { dg-error "expected type-specifier" }
+}
+
+template<typename... T>
+void
+f5 ()
+{
+  constexpr auto r = ^^T; // { dg-error "parameter packs not expanded with" }
+}
+
+void
+g ()
+{
+  f2 ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type3.C b/gcc/testsuite/g++.dg/reflect/type3.C
new file mode 100644 (file)
index 0000000..edf4d4d
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflections on types.
+
+struct S { int i; };
+
+constexpr auto g1 = ^^int;
+constexpr auto g2 = ^^S;
+
+// Create int foo (int, S *);
+typename [: g1 :] foo (typename [: g1 :], typename [: g2 :] *);
+
+void
+bar (S *s)
+{
+  foo (42, s);
+}
+
+template<typename T>
+constexpr int bar (T t) { return t; }
+
+void
+g ()
+{
+  constexpr auto r = [: ^^bar<typename [: ^^int :]> :](42);
+  static_assert (r == 42);
+}
+
+struct A {
+  int a;
+  consteval A(int p) : a(p) {}
+};
+constexpr auto r = ^^A;
+struct B : A {
+  using [: r :]::A;
+  consteval B([: ^^int :] p, [: ^^int :] q) : A(p * q) {}
+};
diff --git a/gcc/testsuite/g++.dg/reflect/type4.C b/gcc/testsuite/g++.dg/reflect/type4.C
new file mode 100644 (file)
index 0000000..0f0c2c1
--- /dev/null
@@ -0,0 +1,136 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflect-expression -> ^^ type-id.
+// type-id:
+//   type-specifier-seq abstract-declarator(opt)
+
+enum E { E1 };
+struct S { };
+using T = int;
+template<typename T>
+class C {
+  using type = T;
+};
+union U { int i; };
+
+template<typename T>
+using AT = C<T>;
+
+void
+f1 ()
+{
+  // type-specifier -> simple-type-specifier
+  constexpr auto r1 = ^^void;
+  constexpr auto r2 = ^^void*;
+  constexpr auto r3 = ^^int&;
+  constexpr auto r4 = ^^int&&;
+  constexpr auto r5 = ^^decltype(sizeof(0));
+  constexpr auto r6 = ^^E*;
+  constexpr auto r7 = ^^S*;
+  constexpr auto r8 = ^^T*;
+  constexpr auto r9 = ^^const void*;
+  constexpr auto r10 = ^^const int&;
+  constexpr auto r11 = ^^E const*;
+  constexpr auto r12 = ^^S const*const;
+  constexpr auto r13 = ^^const T *;
+  constexpr auto r14 = ^^E;
+  constexpr auto r15 = ^^S;
+  constexpr auto r16 = ^^T;
+  constexpr auto r17 = ^^T&&;
+  constexpr auto r18 = ^^int*[3];
+  constexpr auto r19 = ^^int (*)[3];
+  constexpr auto r20 = ^^int *();
+  constexpr auto r21 = ^^int (*)(double);
+
+  int i = 42;
+  E e;
+  S s;
+  typename [: r1 :] fn1 ();
+  typename [: r16 :] fn2 (typename [: r1 :]);
+  typename [: r2 :] v1 = nullptr;
+  typename [: r3 :] v2 = i;
+  typename [: r4 :] v3 = 42;
+  typename [: r5 :] v4 = 0U;
+  typename [: r6 :] v5 = &e;
+  typename [: r7 :] v6 = &s;
+  typename [: r8 :] v7 = &i;
+  typename [: r9 :] v8 = nullptr;
+  typename [: r10 :] v9 = 42;
+  typename [: r11 :] v10 = &e;
+  typename [: r12 :] v11 = &s;
+  typename [: r13 :] v12 = &i;
+  typename [: r14 :] v13;
+  typename [: r15 :] v14;
+  typename [: r16 :] v15;
+  typename [: r17 :] v16 = 42;
+  typename [: r18 :] v17 = {nullptr};
+  typename [: r19 :] v18;
+  typename [: r20 :] v19;
+  typename [: r21 :] v20;
+
+  // type-specifier -> elaborated-type-specifier
+  constexpr auto r22 = ^^struct S;
+  constexpr auto r23 = ^^struct ::S;
+  constexpr auto r24 = ^^struct C<int>;
+  constexpr auto r25 = ^^struct ::C<int>;
+  constexpr auto r26 = ^^struct ::template C<int>;
+  constexpr auto r27 = ^^union U;
+  constexpr auto r28 = ^^union ::U;
+  constexpr auto r29 = ^^enum E;
+  constexpr auto r30 = ^^enum ::E;
+  constexpr auto r31 = ^^const struct S;
+  constexpr auto r32 = ^^const struct ::S;
+  constexpr auto r33 = ^^const struct C<int>;
+  constexpr auto r34 = ^^const struct ::C<int>;
+  constexpr auto r35 = ^^const struct ::template C<int>;
+  constexpr auto r36 = ^^const union U;
+  constexpr auto r37 = ^^const union ::U;
+  constexpr auto r38 = ^^const enum E;
+  constexpr auto r39 = ^^const enum ::E;
+
+  typename [: r22 :] s1;
+  typename [: r23 :] s2;
+  typename [: r31 :] s3;
+  typename [: r32 :] s4;
+  typename [: r24 :] c1;
+  typename [: r25 :] c2;
+  typename [: r26 :] c3;
+  typename [: r33 :] c4;
+  typename [: r34 :] c5;
+  typename [: r35 :] c6;
+  typename [: r27 :] u1;
+  typename [: r28 :] u2;
+  typename [: r36 :] u3{1};
+  typename [: r37 :] u4{1};
+  typename [: r29 :] e1;
+  typename [: r30 :] e2;
+  typename [: r38 :] e3 = E1;
+  typename [: r39 :] e4 = E1;
+
+  // type-specifier -> typename-specifier
+  constexpr auto r40 = ^^typename ::E;
+  constexpr auto r41 = ^^typename ::C<int>;
+  constexpr auto r42 = ^^typename ::template C<int>;
+  constexpr auto r43 = ^^typename ::S;
+  constexpr auto r44 = ^^typename ::T;
+  constexpr auto r45 = ^^typename ::U;
+
+  typename [: r40 :] e5;
+  typename [: r41 :] c7;
+  typename [: r42 :] c8;
+  typename [: r43 :] s5;
+  typename [: r44 :] i1;
+  typename [: r45 :] u5;
+
+  constexpr auto r46 = ^^AT<int>;
+  constexpr auto r47 = ^^::AT<int>;
+  constexpr auto r48 = ^^::template AT<int>;
+  constexpr auto r49 = ^^typename ::AT<int>;
+  constexpr auto r50 = ^^typename ::template AT<int>;
+
+  typename [: r46 :] c9;
+  typename [: r47 :] c10;
+  typename [: r48 :] c11;
+  typename [: r49 :] c12;
+  typename [: r50 :] c13;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type5.C b/gcc/testsuite/g++.dg/reflect/type5.C
new file mode 100644 (file)
index 0000000..8a7debb
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Distilled from [temp.res.general].
+
+enum class Enum { A, B, C };
+template<class T> struct S {
+  using Alias = [:^^int:];
+  auto h() -> [:^^S:]<T*>;
+  using enum [:^^Enum:];
+};
diff --git a/gcc/testsuite/g++.dg/reflect/type6.C b/gcc/testsuite/g++.dg/reflect/type6.C
new file mode 100644 (file)
index 0000000..f2db869
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^int);
+
+template<typename T> concept C = requires {
+  typename [:T::r1:];
+  typename [:T::r2:]<int>;
+};
+
+template<typename T>
+struct Z { };
+
+struct S {
+  static constexpr info r1 = ^^int;
+  static constexpr info r2 = ^^Z;
+};
+
+void
+g (S s)
+{
+  typename [: S::r1 :] i = 42;
+  typename [: S::r2 :]<int> z;
+  C auto a = s;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type7.C b/gcc/testsuite/g++.dg/reflect/type7.C
new file mode 100644 (file)
index 0000000..444df8e
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -fconcepts-diagnostics-depth=2" }
+
+using info = decltype(^^int);
+
+template<typename T> concept C = requires {
+  typename [:T::r1:]; // { dg-error ".r1. is not a member of .int." }
+  typename [:T::r2:]<int>;  // { dg-error ".r2. is not a member of .int." }
+};
+
+void
+g ()
+{
+  C auto a = 42;  // { dg-error "does not satisfy placeholder constraints" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type8.C b/gcc/testsuite/g++.dg/reflect/type8.C
new file mode 100644 (file)
index 0000000..82243d7
--- /dev/null
@@ -0,0 +1,76 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test splice-expressions in decltype.
+
+template<class, class> struct same_type;
+template<class T> struct same_type<T, T> {};
+
+struct S {
+  static const int &&mem();
+  static int i;
+  int j;
+} s;
+
+const int && foo();
+decltype(foo()) x1 = 17;       // type is const int&&
+same_type<decltype(x1), const int &&> s1;
+decltype([: ^^x1 :]) x5 = 18;    // type is const int&&
+same_type<decltype(x5), const int &&> s2;
+decltype(([: ^^x1 :])) x6 = 19;  // type is const int&
+same_type<decltype(x6), const int &> s3;
+same_type<decltype(foo), const int&&()> s4a;
+same_type<decltype([: ^^foo :]), const int&&()> s4b;
+same_type<decltype(S::i), int> s5a;
+same_type<decltype([: ^^S::i :]), int> s5b;
+same_type<decltype((S::i)), int&> s6a;
+same_type<decltype(([: ^^S::i :])), int&> s6b;
+same_type<decltype(S::mem), const int&&()> s7a;
+same_type<decltype([: ^^S::mem :]), const int&&()> s7b;
+same_type<decltype((S::mem)), const int&& (&)()> s8a;
+same_type<decltype(([: ^^S::mem :])), const int&& (&)()> s8b;
+same_type<decltype(s.j), int> s9a;
+same_type<decltype([: ^^s :].j), int> s9b;
+same_type<decltype((s.j)), int&> s10a;
+same_type<decltype(([: ^^s :].j)), int&> s10b;
+
+namespace N {
+  struct A { } a;
+}
+
+same_type<decltype(N::a), N::A> s11a;
+same_type<decltype([: ^^N :]::a), N::A> s11b;
+same_type<decltype([: ^^N::a :]), N::A> s11c;
+
+struct B {
+  int i : 31;
+} b;
+
+same_type<decltype(b.i), int> s12a;
+same_type<decltype([: ^^b :].i), int> s12b;
+same_type<decltype((b.i)), int&> s13a;
+same_type<decltype(([: ^^b :].i)), int&> s13b;
+
+template<typename T>
+struct C {
+  static constexpr T t{};
+};
+
+template<typename T>
+void
+g ()
+{
+  same_type<decltype(C<T>::t), const int>();
+  same_type<decltype((C<T>::t)), const int&>();
+  same_type<decltype([: ^^C<T>::t :]), const int>();
+  same_type<decltype(([: ^^C<T>::t :])), const int&>();
+  same_type<decltype([: ^^C<T> :]::t), const int>();
+  same_type<decltype(([: ^^C<T> :]::t)), const int&>();
+  same_type<decltype(template [: ^^C :]<T>::t), const int>();
+  same_type<decltype((template [: ^^C :]<T>::t)), const int&>();
+}
+
+void
+doit ()
+{
+  g<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type9.C b/gcc/testsuite/g++.dg/reflect/type9.C
new file mode 100644 (file)
index 0000000..56bed45
--- /dev/null
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^void);
+
+template<typename>
+void foo () { }
+void bar () { }
+namespace N { }
+namespace M = N;
+template<typename T>
+T vt{};
+template<typename T>
+concept C = true;
+static int i;
+enum E { X };
+struct S { static int si; };
+template<typename T>
+struct D { static T di; };
+template<typename T>
+using Z = D<T>;
+
+template<info R> void fn1 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn2 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn3 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn4 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn5 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn6 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn7 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn8 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn9 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn10 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn11 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn12 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn13 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+
+template void fn1<^^foo<int>>();  // { dg-message "required from here" }
+template void fn2<^^foo>();      // { dg-message "required from here" }
+template void fn3<^^N>();        // { dg-message "required from here" }
+template void fn4<^^M>();        // { dg-message "required from here" }
+template void fn5<^^bar>();      // { dg-message "required from here" }
+template void fn6<^^vt<int>>();          // { dg-message "required from here" }
+template void fn7<^^vt>();       // { dg-message "required from here" }
+template void fn8<^^C>();        // { dg-message "required from here" }
+template void fn9<^^i>();        // { dg-message "required from here" }
+template void fn10<^^X>();       // { dg-message "required from here" }
+template void fn11<^^S::si>();   // { dg-message "required from here" }
+template void fn12<^^D<int>::di>(); // { dg-message "required from here" }
+template void fn13<^^Z>();       // { dg-message "required from here" }
diff --git a/gcc/testsuite/g++.dg/reflect/type_of1.C b/gcc/testsuite/g++.dg/reflect/type_of1.C
new file mode 100644 (file)
index 0000000..4433b7c
--- /dev/null
@@ -0,0 +1,190 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::type_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+  int v : 5;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_type (info r)
+{
+  try { type_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (has_type (std::meta::reflect_constant (42)));
+static_assert (has_type (std::meta::reflect_object (arr[1])));
+static_assert (has_type (^^arr));
+static_assert (!has_type (^^a3));
+static_assert (has_type (^^fn));
+static_assert (!has_type (^^fn2));
+static_assert (has_type (^^Enum::A));
+static_assert (!has_type (^^Alias));
+static_assert (!has_type (^^S));
+static_assert (has_type (^^S::mem));
+static_assert (has_type (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!has_type (^^TCls));
+static_assert (!has_type (^^TFn));
+static_assert (!has_type (^^TVar));
+static_assert (!has_type (^^Concept));
+static_assert (!has_type (^^NSAlias));
+static_assert (!has_type (^^NS));
+static_assert (has_type (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (has_type (std::meta::data_member_spec (^^int, { .name = "member" })));
+static_assert (has_type (std::meta::data_member_spec (^^int, { .name = "member", .bit_width = 6 })));
+static_assert (has_type (std::meta::data_member_spec (^^int, { .bit_width = 0 })));
+static_assert (has_type (std::meta::data_member_spec (^^int, { .bit_width = 5 })));
+void bar (long, const T f, int g[2], T &);
+
+int
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (has_type (^^a));
+  static_assert (has_type (^^b));
+  static_assert (has_type (^^c));
+  static_assert (has_type (^^d));
+  static_assert (has_type (^^e));
+  static_assert (has_type (parameters_of (^^foo)[0]));
+  static_assert (has_type (parameters_of (^^foo)[1]));
+  static_assert (has_type (parameters_of (^^foo)[2]));
+  static_assert (has_type (parameters_of (^^foo)[3]));
+  static_assert (has_type (parameters_of (^^foo)[4]));
+  static_assert (has_type (parameters_of (^^bar)[0]));
+  static_assert (has_type (parameters_of (^^bar)[1]));
+  static_assert (has_type (parameters_of (^^bar)[2]));
+  static_assert (has_type (parameters_of (^^bar)[3]));
+  static_assert (type_of (^^a) == ^^int);
+  using clong = const long;
+  static_assert (type_of (^^b) == dealias(^^clong));
+  static_assert (type_of (^^c) == ^^T);
+  using ptr = int *;
+  static_assert (type_of (^^d) == dealias (^^ptr));
+  using ref = T &;
+  static_assert (type_of (^^e) == dealias (^^ref));
+  static_assert (type_of (parameters_of (^^foo)[0]) == ^^int);
+  static_assert (type_of (parameters_of (^^foo)[1]) == ^^long);
+  static_assert (type_of (parameters_of (^^foo)[2]) == ^^T);
+  static_assert (type_of (parameters_of (^^foo)[3]) == dealias (^^ptr));
+  static_assert (type_of (parameters_of (^^foo)[4]) == dealias (^^ref));
+  static_assert (type_of (parameters_of (^^bar)[0]) == ^^long);
+  static_assert (type_of (parameters_of (^^bar)[1]) == ^^T);
+  static_assert (type_of (parameters_of (^^bar)[2]) == dealias (^^ptr));
+  static_assert (type_of (parameters_of (^^bar)[3]) == dealias (^^ref));
+  return 0;
+}
+
+static_assert (type_of (std::meta::reflect_constant (42)) == ^^int);
+static_assert (type_of (std::meta::reflect_constant (42.0)) == ^^double);
+static_assert (type_of (std::meta::reflect_constant (U { 42 })) == ^^const U);
+static_assert (type_of (std::meta::reflect_object (arr[1])) == ^^int);
+using int3 = int[3];
+static_assert (type_of (^^arr) == dealias (^^int3));
+static_assert (type_of (^^fn) == ^^void ());
+static_assert (type_of (^^Enum::A) == ^^Enum);
+static_assert (type_of (^^A) == ^^Enum);
+static_assert (type_of (^^S::mem) == ^^int);
+static_assert (type_of (^^U::v) == ^^int);
+static_assert (type_of (std::meta::members_of (^^S, ctx)[1]) == ^^int);
+static_assert (type_of (std::meta::bases_of (^^S, ctx)[0]) == ^^B);
+static_assert (type_of (std::meta::data_member_spec (^^int, { .name = "member" })) == ^^int);
+static_assert (type_of (std::meta::data_member_spec (^^const long, { .name = "member", .bit_width = 8 })) == ^^const long);
+static_assert (type_of (std::meta::data_member_spec (^^int3, { .name = "member" })) == ^^int[3]);
+static_assert (type_of (std::meta::data_member_spec (^^int, { .bit_width = 7 })) == ^^int);
+static_assert (type_of (std::meta::data_member_spec (^^int, { .bit_width = 0 })) == ^^int);
+
+consteval int
+test (info x, info y)
+{
+  if (x == y)
+    return 0;
+  throw 1;
+}
+
+static_assert (type_of (^^test) == ^^int (info, info));
+
+using ull = unsigned long long;
+
+enum Enum2 {
+  E21,
+  E22,
+  E23 = 3L,
+  E24,
+  E25 = 5ULL,
+  E26,
+  E27 = 7 + test (type_of (^^E21), ^^int)
+         + test (type_of (^^E22), ^^int)
+         + test (type_of (^^E23), ^^long)
+         + test (type_of (^^E24), ^^long)
+         + test (type_of (^^E25), dealias (^^ull))
+         + test (type_of (^^E26), dealias (^^ull))
+};
+
+static_assert (type_of (^^E21) == ^^Enum2);
+static_assert (type_of (^^E22) == ^^Enum2);
+static_assert (type_of (^^E23) == ^^Enum2);
+static_assert (type_of (^^E24) == ^^Enum2);
+static_assert (type_of (^^E25) == ^^Enum2);
+static_assert (type_of (^^E26) == ^^Enum2);
+static_assert (type_of (^^E27) == ^^Enum2);
+
+enum Enum3 : long {
+  E31,
+  E32,
+  E33 = 3L,
+  E34,
+  E35 = 5ULL,
+  E36,
+  E37 = 7 + test (type_of (^^E31), ^^long)
+         + test (type_of (^^E32), ^^long)
+         + test (type_of (^^E33), ^^long)
+         + test (type_of (^^E34), ^^long)
+         + test (type_of (^^E35), ^^long)
+         + test (type_of (^^E36), ^^long)
+};
+
+static_assert (type_of (^^E31) == ^^Enum3);
+static_assert (type_of (^^E32) == ^^Enum3);
+static_assert (type_of (^^E33) == ^^Enum3);
+static_assert (type_of (^^E34) == ^^Enum3);
+static_assert (type_of (^^E35) == ^^Enum3);
+static_assert (type_of (^^E36) == ^^Enum3);
+static_assert (type_of (^^E37) == ^^Enum3);
+
+constexpr auto a = reflect_constant_string ("abcd");
+static_assert (type_of (a) == ^^const char [5]);
+auto as = &[: a :];
+static_assert (type_of (^^as) == ^^const char (*) [5]);
+struct V { int a, b, c; };
+auto bs = &[: reflect_constant (V { 2, 3, 4 }) :];
+static_assert (type_of (^^bs) == ^^const V *);
diff --git a/gcc/testsuite/g++.dg/reflect/type_of2.C b/gcc/testsuite/g++.dg/reflect/type_of2.C
new file mode 100644 (file)
index 0000000..2956791
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::type_of.
+
+#include <meta>
+using namespace std::meta;
+
+template<typename T>
+consteval auto
+foo ()
+{
+  auto Functions = std::vector<info>{};
+  for (auto Info : members_of (^^T, access_context::current ()))
+    if (!is_special_member_function (Info) && is_function (Info))
+      Functions.push_back(Info);
+  return Functions;
+}
+
+struct F {
+  auto f(int)->void;
+};
+
+void
+g ()
+{
+  constexpr auto fInfo = foo<F>()[0];
+  using fType = [:type_of(fInfo):];
+  // TODO Should work: non-const non-volatile member functions have ordinary
+  // function types.
+  //static_assert (std::same_as<fType, auto(int)->void>);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type_rels1.C b/gcc/testsuite/g++.dg/reflect/type_rels1.C
new file mode 100644 (file)
index 0000000..ee5ca22
--- /dev/null
@@ -0,0 +1,141 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_same_type.
+
+#include <meta>
+
+using namespace std::meta;
+
+using U = int;
+using UU = U;
+
+static_assert (is_same_type (^^int, ^^int));
+static_assert (is_same_type (^^int, ^^U));
+static_assert (is_same_type (^^int, ^^UU));
+static_assert (!is_same_type (^^int, ^^const int));
+static_assert (!is_same_type (^^int, ^^const UU));
+static_assert (!is_same_type (^^int *, ^^int[]));
+static_assert (!is_same_type (^^int&, ^^int&&));
+
+struct incomplete;
+struct B {};
+struct D : B {};
+struct E1 : D {};
+struct E2 : D {};
+static_assert (is_base_of_type (^^B, ^^D));
+static_assert (is_base_of_type (^^D, ^^E1));
+static_assert (is_base_of_type (^^B, ^^E1));
+static_assert (is_base_of_type (^^B, ^^B));
+static_assert (!is_base_of_type (^^D, ^^B));
+static_assert (!is_base_of_type (^^E1, ^^D));
+static_assert (!is_base_of_type (^^E1, ^^B));
+static_assert (!is_base_of_type (^^B, ^^int));
+static_assert (!is_base_of_type (^^incomplete, ^^D));
+
+struct V : virtual E1, virtual E2 {};
+static_assert (!is_virtual_base_of_type (^^B, ^^D));
+static_assert (!is_virtual_base_of_type (^^const B, ^^D));
+static_assert (!is_virtual_base_of_type (^^D, ^^B));
+static_assert (!is_virtual_base_of_type (^^D, ^^int));
+static_assert (!is_virtual_base_of_type (^^B, ^^B));
+static_assert (is_virtual_base_of_type (^^B, ^^V));
+static_assert (is_virtual_base_of_type (^^D, ^^V));
+static_assert (is_virtual_base_of_type (^^E1, ^^V));
+static_assert (is_virtual_base_of_type (^^E2, ^^V));
+
+struct D1 : private virtual B {};
+struct D2 : protected virtual B {};
+struct D3 : private D1 {};
+struct D4 : private D2 {};
+struct D5 : protected D2 {};
+struct D6 : protected D2 {};
+static_assert (is_virtual_base_of_type (^^B, ^^D1));
+static_assert (is_virtual_base_of_type (^^B, ^^D2));
+static_assert (is_virtual_base_of_type (^^B, ^^D3));
+static_assert (is_virtual_base_of_type (^^B, ^^D4));
+static_assert (is_virtual_base_of_type (^^B, ^^D5));
+static_assert (is_virtual_base_of_type (^^B, ^^D6));
+
+struct W : V {};
+struct Y : virtual V {};
+static_assert (is_virtual_base_of_type (^^E1, ^^W));
+static_assert (is_virtual_base_of_type (^^E2, ^^W));
+static_assert (is_virtual_base_of_type (^^E1, ^^Y));
+static_assert (is_virtual_base_of_type (^^E2, ^^Y));
+
+struct X {};
+struct Z { Z(int); };
+struct Z2 { Z2(int) noexcept; };
+static_assert (is_convertible_type (^^bool, ^^int));
+static_assert (is_convertible_type (^^int, ^^double));
+static_assert (!is_convertible_type (^^int, ^^X));
+static_assert (is_convertible_type (^^int, ^^Z));
+static_assert (!is_convertible_type (^^Z, ^^int));
+
+static_assert (is_nothrow_convertible_type (^^bool, ^^int));
+static_assert (is_nothrow_convertible_type (^^int, ^^double));
+static_assert (!is_nothrow_convertible_type (^^int, ^^X));
+static_assert (!is_nothrow_convertible_type (^^int, ^^Z));
+static_assert (!is_nothrow_convertible_type (^^Z, ^^int));
+static_assert (is_nothrow_convertible_type (^^int, ^^Z2));
+static_assert (!is_nothrow_convertible_type (^^Z2, ^^int));
+
+static_assert (is_layout_compatible_type (^^void, ^^void));
+static_assert (is_layout_compatible_type (^^int, ^^int));
+static_assert (!is_layout_compatible_type (^^int, ^^int[]));
+static_assert (!is_layout_compatible_type (^^int, ^^int[1]));
+static_assert (is_layout_compatible_type (^^int[], ^^int[]));
+static_assert (is_layout_compatible_type (^^int[1], ^^int[1]));
+static_assert (!is_layout_compatible_type (^^int[1], ^^int[]));
+static_assert (!is_layout_compatible_type (^^int[1], ^^int[2]));
+static_assert (is_layout_compatible_type (^^incomplete[], ^^incomplete[]));
+
+namespace LC {
+  enum E1 : int { };
+  enum E2 : int;
+  static_assert (is_layout_compatible_type (^^E1, ^^E2));
+  enum E3 : unsigned int;
+  static_assert (!is_layout_compatible_type (^^E1, ^^E3));
+  enum E4 : char { };
+  enum E5 : signed char { };
+  enum E6 : unsigned char { };
+  static_assert (!is_layout_compatible_type (^^E4, ^^E5));
+  static_assert (!is_layout_compatible_type (^^E4, ^^E6));
+  static_assert (!is_layout_compatible_type (^^E5, ^^E6));
+  struct A { int a; };
+  struct B { const int b; };
+  static_assert (is_layout_compatible_type (^^A, ^^B));
+  static_assert (is_layout_compatible_type (^^B, ^^A));
+  struct C : A { };
+  struct D : B { };
+  static_assert (is_layout_compatible_type (^^C, ^^D));
+  struct E : A { int i; };
+  static_assert (!is_layout_compatible_type (^^E, ^^A));
+}
+
+namespace PI {
+  struct B { };
+  static_assert (is_pointer_interconvertible_base_of_type (^^B, ^^B));
+  static_assert (is_pointer_interconvertible_base_of_type (^^B, ^^const B));
+  static_assert (is_pointer_interconvertible_base_of_type (^^const B, ^^B));
+  static_assert (is_pointer_interconvertible_base_of_type (^^const B, ^^const B));
+  struct D : B { int i; };
+  static_assert (is_pointer_interconvertible_base_of_type (^^D, ^^D));
+  static_assert (is_pointer_interconvertible_base_of_type (^^B, ^^D));
+  static_assert (is_pointer_interconvertible_base_of_type (^^const B, ^^D));
+  static_assert (is_pointer_interconvertible_base_of_type (^^B, ^^const D));
+  static_assert (is_pointer_interconvertible_base_of_type (^^const B, ^^const D));
+  static_assert (!is_pointer_interconvertible_base_of_type (^^D, ^^B));
+  struct E : D { };
+  static_assert (!is_pointer_interconvertible_base_of_type (^^E, ^^B));
+  struct D1 : B { };
+  struct D2 : B { };
+  struct D3 : D1, D2 { };
+  static_assert (!is_pointer_interconvertible_base_of_type (^^B, ^^D3));
+  union U;
+  static_assert (!is_pointer_interconvertible_base_of_type (^^U, ^^U));
+  static_assert (!is_pointer_interconvertible_base_of_type (^^U, ^^D));
+  struct I;
+  static_assert (is_pointer_interconvertible_base_of_type (^^I, ^^I));
+  static_assert (is_pointer_interconvertible_base_of_type (^^I, ^^const I));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait1.C b/gcc/testsuite/g++.dg/reflect/type_trait1.C
new file mode 100644 (file)
index 0000000..e70fa1f
--- /dev/null
@@ -0,0 +1,654 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits].
+
+#include <meta>
+using namespace std::meta;
+
+struct cls {
+  using type = int;
+  void mem_fun ();
+  static void static_mem_fun ();
+};
+struct empty { };
+using alias = cls;
+struct derived : cls { };
+union onion {
+  onion &operator=(const cls&);
+  onion &operator=(cls&&);
+};
+enum class Enum : short {};
+enum class Enum_class { A };
+class abstract_cls { virtual void fn() = 0; };
+class final_cls final {};
+struct ctor_cls {
+  ctor_cls (int, bool) noexcept {}
+};
+struct trivial_cls {
+  int i;
+  bool b;
+};
+class virtual_dtor_cls {
+  virtual ~virtual_dtor_cls () {}
+};
+int fun (bool, char) noexcept { return 0; }
+
+static_assert (!is_function_type (^^void));
+static_assert (!is_function_type (^^int));
+static_assert (!is_function_type (^^const int));
+static_assert (!is_function_type (^^volatile int));
+static_assert (!is_function_type (^^unsigned));
+static_assert (!is_function_type (^^float));
+static_assert (!is_function_type (^^int&));
+static_assert (!is_function_type (^^int&&));
+static_assert (!is_function_type (^^int *));
+static_assert (!is_function_type (^^int[1]));
+static_assert (!is_function_type (^^int[]));
+static_assert (!is_function_type (^^nullptr_t));
+static_assert (!is_function_type (^^std::meta::info));
+static_assert (!is_function_type (^^int (cls::*)));
+static_assert (!is_function_type (^^int (cls::*)()));
+static_assert (!is_function_type (^^cls));
+static_assert (is_function_type (type_of (^^cls::mem_fun)));
+static_assert (is_function_type (type_of (^^cls::static_mem_fun)));
+static_assert (!is_function_type (^^empty));
+static_assert (!is_function_type (^^abstract_cls));
+static_assert (!is_function_type (^^final_cls));
+static_assert (!is_function_type (^^ctor_cls));
+static_assert (!is_function_type (^^trivial_cls));
+static_assert (!is_function_type (^^virtual_dtor_cls));
+static_assert (!is_function_type (^^onion));
+static_assert (!is_function_type (^^Enum));
+static_assert (!is_function_type (^^Enum_class));
+static_assert (is_function_type (^^void ()));
+
+static_assert (is_void_type (^^void));
+static_assert (is_void_type (^^const void));
+static_assert (is_void_type (^^volatile void));
+static_assert (!is_void_type (^^void *));
+static_assert (!is_void_type (^^int));
+static_assert (!is_void_type (^^const int));
+static_assert (!is_void_type (^^volatile int));
+static_assert (!is_void_type (^^unsigned));
+static_assert (!is_void_type (^^float));
+static_assert (!is_void_type (^^int&));
+static_assert (!is_void_type (^^int&&));
+static_assert (!is_void_type (^^int *));
+static_assert (!is_void_type (^^int[1]));
+static_assert (!is_void_type (^^int[]));
+static_assert (!is_void_type (^^nullptr_t));
+static_assert (!is_void_type (^^std::meta::info));
+static_assert (!is_void_type (^^int (cls::*)));
+static_assert (!is_void_type (^^int (cls::*)()));
+static_assert (!is_void_type (^^cls));
+static_assert (!is_void_type (^^empty));
+static_assert (!is_void_type (^^abstract_cls));
+static_assert (!is_void_type (^^final_cls));
+static_assert (!is_void_type (^^ctor_cls));
+static_assert (!is_void_type (^^trivial_cls));
+static_assert (!is_void_type (^^virtual_dtor_cls));
+static_assert (!is_void_type (^^onion));
+static_assert (!is_void_type (^^Enum));
+static_assert (!is_void_type (^^Enum_class));
+static_assert (!is_void_type (^^void ()));
+
+static_assert (!is_null_pointer_type (^^void));
+static_assert (!is_null_pointer_type (^^int));
+static_assert (!is_null_pointer_type (^^const int));
+static_assert (!is_null_pointer_type (^^volatile int));
+static_assert (!is_null_pointer_type (^^unsigned));
+static_assert (!is_null_pointer_type (^^float));
+static_assert (!is_null_pointer_type (^^int&));
+static_assert (!is_null_pointer_type (^^int&&));
+static_assert (!is_null_pointer_type (^^int *));
+static_assert (!is_null_pointer_type (^^int[1]));
+static_assert (!is_null_pointer_type (^^int[]));
+static_assert (is_null_pointer_type (^^nullptr_t));
+static_assert (!is_null_pointer_type (^^std::meta::info));
+static_assert (!is_null_pointer_type (^^int (cls::*)));
+static_assert (!is_null_pointer_type (^^int (cls::*)()));
+static_assert (!is_null_pointer_type (^^cls));
+static_assert (!is_null_pointer_type (^^empty));
+static_assert (!is_null_pointer_type (^^abstract_cls));
+static_assert (!is_null_pointer_type (^^final_cls));
+static_assert (!is_null_pointer_type (^^ctor_cls));
+static_assert (!is_null_pointer_type (^^trivial_cls));
+static_assert (!is_null_pointer_type (^^virtual_dtor_cls));
+static_assert (!is_null_pointer_type (^^onion));
+static_assert (!is_null_pointer_type (^^Enum));
+static_assert (!is_null_pointer_type (^^Enum_class));
+static_assert (!is_null_pointer_type (^^void ()));
+
+static_assert (!is_integral_type (^^void));
+static_assert (is_integral_type (^^bool));
+static_assert (is_integral_type (^^wchar_t));
+static_assert (is_integral_type (^^char8_t));
+static_assert (is_integral_type (^^char16_t));
+static_assert (is_integral_type (^^char32_t));
+static_assert (is_integral_type (^^int));
+static_assert (is_integral_type (^^const int));
+static_assert (is_integral_type (^^volatile int));
+static_assert (is_integral_type (^^unsigned));
+static_assert (!is_integral_type (^^float));
+static_assert (!is_integral_type (^^int&));
+static_assert (!is_integral_type (^^int&&));
+static_assert (!is_integral_type (^^int *));
+static_assert (!is_integral_type (^^int[1]));
+static_assert (!is_integral_type (^^int[]));
+static_assert (!is_integral_type (^^nullptr_t));
+static_assert (!is_integral_type (^^std::meta::info));
+static_assert (!is_integral_type (^^int (cls::*)));
+static_assert (!is_integral_type (^^int (cls::*)()));
+static_assert (!is_integral_type (^^cls));
+static_assert (!is_integral_type (^^empty));
+static_assert (!is_integral_type (^^abstract_cls));
+static_assert (!is_integral_type (^^final_cls));
+static_assert (!is_integral_type (^^ctor_cls));
+static_assert (!is_integral_type (^^trivial_cls));
+static_assert (!is_integral_type (^^virtual_dtor_cls));
+static_assert (!is_integral_type (^^onion));
+static_assert (!is_integral_type (^^Enum));
+static_assert (!is_integral_type (^^Enum_class));
+static_assert (!is_integral_type (^^void ()));
+
+static_assert (!is_floating_point_type (^^void));
+static_assert (!is_floating_point_type (^^int));
+static_assert (!is_floating_point_type (^^const int));
+static_assert (!is_floating_point_type (^^volatile int));
+static_assert (!is_floating_point_type (^^unsigned));
+static_assert (is_floating_point_type (^^float));
+static_assert (is_floating_point_type (^^double));
+static_assert (is_floating_point_type (^^const double));
+static_assert (!is_floating_point_type (^^int&));
+static_assert (!is_floating_point_type (^^int&&));
+static_assert (!is_floating_point_type (^^int *));
+static_assert (!is_floating_point_type (^^int[1]));
+static_assert (!is_floating_point_type (^^int[]));
+static_assert (!is_floating_point_type (^^nullptr_t));
+static_assert (!is_floating_point_type (^^std::meta::info));
+static_assert (!is_floating_point_type (^^int (cls::*)));
+static_assert (!is_floating_point_type (^^int (cls::*)()));
+static_assert (!is_floating_point_type (^^cls));
+static_assert (!is_floating_point_type (^^empty));
+static_assert (!is_floating_point_type (^^abstract_cls));
+static_assert (!is_floating_point_type (^^final_cls));
+static_assert (!is_floating_point_type (^^ctor_cls));
+static_assert (!is_floating_point_type (^^trivial_cls));
+static_assert (!is_floating_point_type (^^virtual_dtor_cls));
+static_assert (!is_floating_point_type (^^onion));
+static_assert (!is_floating_point_type (^^Enum));
+static_assert (!is_floating_point_type (^^Enum_class));
+static_assert (!is_floating_point_type (^^void ()));
+
+static_assert (!is_array_type (^^void));
+static_assert (!is_array_type (^^int));
+static_assert (!is_array_type (^^const int));
+static_assert (!is_array_type (^^volatile int));
+static_assert (!is_array_type (^^unsigned));
+static_assert (!is_array_type (^^float));
+static_assert (!is_array_type (^^int&));
+static_assert (!is_array_type (^^int&&));
+static_assert (!is_array_type (^^int *));
+static_assert (is_array_type (^^int[1]));
+static_assert (is_array_type (^^int[]));
+static_assert (!is_array_type (^^nullptr_t));
+static_assert (!is_array_type (^^std::meta::info));
+static_assert (!is_array_type (^^int (cls::*)));
+static_assert (!is_array_type (^^int (cls::*)()));
+static_assert (!is_array_type (^^cls));
+static_assert (!is_array_type (^^empty));
+static_assert (!is_array_type (^^abstract_cls));
+static_assert (!is_array_type (^^final_cls));
+static_assert (!is_array_type (^^ctor_cls));
+static_assert (!is_array_type (^^trivial_cls));
+static_assert (!is_array_type (^^virtual_dtor_cls));
+static_assert (!is_array_type (^^onion));
+static_assert (!is_array_type (^^Enum));
+static_assert (!is_array_type (^^Enum_class));
+static_assert (!is_array_type (^^void ()));
+
+static_assert (!is_pointer_type (^^void));
+static_assert (!is_pointer_type (^^int));
+static_assert (!is_pointer_type (^^const int));
+static_assert (!is_pointer_type (^^volatile int));
+static_assert (!is_pointer_type (^^unsigned));
+static_assert (!is_pointer_type (^^float));
+static_assert (!is_pointer_type (^^int&));
+static_assert (!is_pointer_type (^^int&&));
+static_assert (is_pointer_type (^^int *));
+static_assert (is_pointer_type (^^int **));
+static_assert (is_pointer_type (^^int *const *const));
+static_assert (!is_pointer_type (^^int[1]));
+static_assert (!is_pointer_type (^^int[]));
+static_assert (!is_pointer_type (^^nullptr_t));
+static_assert (!is_pointer_type (^^std::meta::info));
+static_assert (!is_pointer_type (^^int (cls::*)));
+static_assert (!is_pointer_type (^^int (cls::*)()));
+static_assert (!is_pointer_type (^^cls));
+static_assert (!is_pointer_type (^^empty));
+static_assert (!is_pointer_type (^^abstract_cls));
+static_assert (!is_pointer_type (^^final_cls));
+static_assert (!is_pointer_type (^^ctor_cls));
+static_assert (!is_pointer_type (^^trivial_cls));
+static_assert (!is_pointer_type (^^virtual_dtor_cls));
+static_assert (!is_pointer_type (^^onion));
+static_assert (!is_pointer_type (^^Enum));
+static_assert (!is_pointer_type (^^Enum_class));
+static_assert (!is_pointer_type (^^void ()));
+
+static_assert (!is_lvalue_reference_type (^^void));
+static_assert (!is_lvalue_reference_type (^^int));
+static_assert (!is_lvalue_reference_type (^^const int));
+static_assert (!is_lvalue_reference_type (^^volatile int));
+static_assert (!is_lvalue_reference_type (^^unsigned));
+static_assert (!is_lvalue_reference_type (^^float));
+static_assert (is_lvalue_reference_type (^^int&));
+static_assert (!is_lvalue_reference_type (^^int&&));
+static_assert (!is_lvalue_reference_type (^^int *));
+static_assert (!is_lvalue_reference_type (^^int[1]));
+static_assert (!is_lvalue_reference_type (^^int[]));
+static_assert (!is_lvalue_reference_type (^^nullptr_t));
+static_assert (!is_lvalue_reference_type (^^std::meta::info));
+static_assert (!is_lvalue_reference_type (^^int (cls::*)));
+static_assert (!is_lvalue_reference_type (^^int (cls::*)()));
+static_assert (!is_lvalue_reference_type (^^cls));
+static_assert (!is_lvalue_reference_type (^^empty));
+static_assert (!is_lvalue_reference_type (^^abstract_cls));
+static_assert (!is_lvalue_reference_type (^^final_cls));
+static_assert (!is_lvalue_reference_type (^^ctor_cls));
+static_assert (!is_lvalue_reference_type (^^trivial_cls));
+static_assert (!is_lvalue_reference_type (^^virtual_dtor_cls));
+static_assert (!is_lvalue_reference_type (^^onion));
+static_assert (!is_lvalue_reference_type (^^Enum));
+static_assert (!is_lvalue_reference_type (^^Enum_class));
+static_assert (!is_lvalue_reference_type (^^void ()));
+
+static_assert (!is_rvalue_reference_type (^^void));
+static_assert (!is_rvalue_reference_type (^^int));
+static_assert (!is_rvalue_reference_type (^^const int));
+static_assert (!is_rvalue_reference_type (^^volatile int));
+static_assert (!is_rvalue_reference_type (^^unsigned));
+static_assert (!is_rvalue_reference_type (^^float));
+static_assert (!is_rvalue_reference_type (^^int&));
+static_assert (is_rvalue_reference_type (^^int&&));
+static_assert (!is_rvalue_reference_type (^^int *));
+static_assert (!is_rvalue_reference_type (^^int[1]));
+static_assert (!is_rvalue_reference_type (^^int[]));
+static_assert (!is_rvalue_reference_type (^^nullptr_t));
+static_assert (!is_rvalue_reference_type (^^std::meta::info));
+static_assert (!is_rvalue_reference_type (^^int (cls::*)));
+static_assert (!is_rvalue_reference_type (^^int (cls::*)()));
+static_assert (!is_rvalue_reference_type (^^cls));
+static_assert (!is_rvalue_reference_type (^^empty));
+static_assert (!is_rvalue_reference_type (^^abstract_cls));
+static_assert (!is_rvalue_reference_type (^^final_cls));
+static_assert (!is_rvalue_reference_type (^^ctor_cls));
+static_assert (!is_rvalue_reference_type (^^trivial_cls));
+static_assert (!is_rvalue_reference_type (^^virtual_dtor_cls));
+static_assert (!is_rvalue_reference_type (^^onion));
+static_assert (!is_rvalue_reference_type (^^Enum));
+static_assert (!is_rvalue_reference_type (^^Enum_class));
+static_assert (!is_rvalue_reference_type (^^void ()));
+
+static_assert (!is_member_object_pointer_type (^^void));
+static_assert (!is_member_object_pointer_type (^^int));
+static_assert (!is_member_object_pointer_type (^^const int));
+static_assert (!is_member_object_pointer_type (^^volatile int));
+static_assert (!is_member_object_pointer_type (^^unsigned));
+static_assert (!is_member_object_pointer_type (^^float));
+static_assert (!is_member_object_pointer_type (^^int&));
+static_assert (!is_member_object_pointer_type (^^int&&));
+static_assert (!is_member_object_pointer_type (^^int *));
+static_assert (!is_member_object_pointer_type (^^int[1]));
+static_assert (!is_member_object_pointer_type (^^int[]));
+static_assert (!is_member_object_pointer_type (^^nullptr_t));
+static_assert (!is_member_object_pointer_type (^^std::meta::info));
+static_assert (is_member_object_pointer_type (^^int (cls::*)));
+static_assert (!is_member_object_pointer_type (^^int (cls::*)()));
+static_assert (!is_member_object_pointer_type (^^cls));
+static_assert (!is_member_object_pointer_type (^^empty));
+static_assert (!is_member_object_pointer_type (^^abstract_cls));
+static_assert (!is_member_object_pointer_type (^^final_cls));
+static_assert (!is_member_object_pointer_type (^^ctor_cls));
+static_assert (!is_member_object_pointer_type (^^trivial_cls));
+static_assert (!is_member_object_pointer_type (^^virtual_dtor_cls));
+static_assert (!is_member_object_pointer_type (^^onion));
+static_assert (!is_member_object_pointer_type (^^Enum));
+static_assert (!is_member_object_pointer_type (^^Enum_class));
+static_assert (!is_member_object_pointer_type (^^void ()));
+
+static_assert (!is_member_function_pointer_type (^^void));
+static_assert (!is_member_function_pointer_type (^^int));
+static_assert (!is_member_function_pointer_type (^^const int));
+static_assert (!is_member_function_pointer_type (^^volatile int));
+static_assert (!is_member_function_pointer_type (^^unsigned));
+static_assert (!is_member_function_pointer_type (^^float));
+static_assert (!is_member_function_pointer_type (^^int&));
+static_assert (!is_member_function_pointer_type (^^int&&));
+static_assert (!is_member_function_pointer_type (^^int *));
+static_assert (!is_member_function_pointer_type (^^int[1]));
+static_assert (!is_member_function_pointer_type (^^int[]));
+static_assert (!is_member_function_pointer_type (^^nullptr_t));
+static_assert (!is_member_function_pointer_type (^^std::meta::info));
+static_assert (!is_member_function_pointer_type (^^int (cls::*)));
+static_assert (is_member_function_pointer_type (^^int (cls::*)()));
+static_assert (!is_member_function_pointer_type (^^cls));
+static_assert (!is_member_function_pointer_type (^^empty));
+static_assert (!is_member_function_pointer_type (^^abstract_cls));
+static_assert (!is_member_function_pointer_type (^^final_cls));
+static_assert (!is_member_function_pointer_type (^^ctor_cls));
+static_assert (!is_member_function_pointer_type (^^trivial_cls));
+static_assert (!is_member_function_pointer_type (^^virtual_dtor_cls));
+static_assert (!is_member_function_pointer_type (^^onion));
+static_assert (!is_member_function_pointer_type (^^Enum));
+static_assert (!is_member_function_pointer_type (^^Enum_class));
+static_assert (!is_member_function_pointer_type (^^void ()));
+
+static_assert (!is_enum_type (^^void));
+static_assert (!is_enum_type (^^int));
+static_assert (!is_enum_type (^^const int));
+static_assert (!is_enum_type (^^volatile int));
+static_assert (!is_enum_type (^^unsigned));
+static_assert (!is_enum_type (^^float));
+static_assert (!is_enum_type (^^int&));
+static_assert (!is_enum_type (^^int&&));
+static_assert (!is_enum_type (^^int *));
+static_assert (!is_enum_type (^^int[1]));
+static_assert (!is_enum_type (^^int[]));
+static_assert (!is_enum_type (^^nullptr_t));
+static_assert (!is_enum_type (^^std::meta::info));
+static_assert (!is_enum_type (^^int (cls::*)));
+static_assert (!is_enum_type (^^int (cls::*)()));
+static_assert (!is_enum_type (^^cls));
+static_assert (!is_enum_type (^^empty));
+static_assert (!is_enum_type (^^abstract_cls));
+static_assert (!is_enum_type (^^final_cls));
+static_assert (!is_enum_type (^^ctor_cls));
+static_assert (!is_enum_type (^^trivial_cls));
+static_assert (!is_enum_type (^^virtual_dtor_cls));
+static_assert (!is_enum_type (^^onion));
+static_assert (is_enum_type (^^Enum));
+static_assert (is_enum_type (^^Enum_class));
+static_assert (!is_enum_type (^^void ()));
+
+static_assert (!is_union_type (^^void));
+static_assert (!is_union_type (^^int));
+static_assert (!is_union_type (^^const int));
+static_assert (!is_union_type (^^volatile int));
+static_assert (!is_union_type (^^unsigned));
+static_assert (!is_union_type (^^float));
+static_assert (!is_union_type (^^int&));
+static_assert (!is_union_type (^^int&&));
+static_assert (!is_union_type (^^int *));
+static_assert (!is_union_type (^^int[1]));
+static_assert (!is_union_type (^^int[]));
+static_assert (!is_union_type (^^nullptr_t));
+static_assert (!is_union_type (^^std::meta::info));
+static_assert (!is_union_type (^^int (cls::*)));
+static_assert (!is_union_type (^^int (cls::*)()));
+static_assert (!is_union_type (^^cls));
+static_assert (!is_union_type (^^empty));
+static_assert (!is_union_type (^^abstract_cls));
+static_assert (!is_union_type (^^final_cls));
+static_assert (!is_union_type (^^ctor_cls));
+static_assert (!is_union_type (^^trivial_cls));
+static_assert (!is_union_type (^^virtual_dtor_cls));
+static_assert (is_union_type (^^onion));
+static_assert (!is_union_type (^^Enum));
+static_assert (!is_union_type (^^Enum_class));
+static_assert (!is_union_type (^^void ()));
+
+static_assert (!is_class_type (^^void));
+static_assert (!is_class_type (^^int));
+static_assert (!is_class_type (^^const int));
+static_assert (!is_class_type (^^volatile int));
+static_assert (!is_class_type (^^unsigned));
+static_assert (!is_class_type (^^float));
+static_assert (!is_class_type (^^int&));
+static_assert (!is_class_type (^^int&&));
+static_assert (!is_class_type (^^int *));
+static_assert (!is_class_type (^^int[1]));
+static_assert (!is_class_type (^^int[]));
+static_assert (!is_class_type (^^nullptr_t));
+static_assert (!is_class_type (^^std::meta::info));
+static_assert (!is_class_type (^^int (cls::*)));
+static_assert (!is_class_type (^^int (cls::*)()));
+static_assert (is_class_type (^^cls));
+static_assert (is_class_type (^^empty));
+static_assert (is_class_type (^^abstract_cls));
+static_assert (is_class_type (^^final_cls));
+static_assert (is_class_type (^^ctor_cls));
+static_assert (is_class_type (^^trivial_cls));
+static_assert (is_class_type (^^virtual_dtor_cls));
+static_assert (!is_class_type (^^onion));
+static_assert (!is_class_type (^^Enum));
+static_assert (!is_class_type (^^Enum_class));
+static_assert (!is_class_type (^^void ()));
+
+static_assert (!is_reflection_type (^^void));
+static_assert (!is_reflection_type (^^int));
+static_assert (!is_reflection_type (^^const int));
+static_assert (!is_reflection_type (^^volatile int));
+static_assert (!is_reflection_type (^^unsigned));
+static_assert (!is_reflection_type (^^float));
+static_assert (!is_reflection_type (^^int&));
+static_assert (!is_reflection_type (^^int&&));
+static_assert (!is_reflection_type (^^int *));
+static_assert (!is_reflection_type (^^int[1]));
+static_assert (!is_reflection_type (^^int[]));
+static_assert (!is_reflection_type (^^nullptr_t));
+static_assert (is_reflection_type (^^std::meta::info));
+static_assert (!is_reflection_type (^^int (cls::*)));
+static_assert (!is_reflection_type (^^int (cls::*)()));
+static_assert (!is_reflection_type (^^cls));
+static_assert (!is_reflection_type (^^empty));
+static_assert (!is_reflection_type (^^abstract_cls));
+static_assert (!is_reflection_type (^^final_cls));
+static_assert (!is_reflection_type (^^ctor_cls));
+static_assert (!is_reflection_type (^^trivial_cls));
+static_assert (!is_reflection_type (^^virtual_dtor_cls));
+static_assert (!is_reflection_type (^^onion));
+static_assert (!is_reflection_type (^^Enum));
+static_assert (!is_reflection_type (^^Enum_class));
+static_assert (!is_reflection_type (^^void ()));
+
+static_assert (!is_reference_type (^^void));
+static_assert (!is_reference_type (^^int));
+static_assert (!is_reference_type (^^const int));
+static_assert (!is_reference_type (^^volatile int));
+static_assert (!is_reference_type (^^unsigned));
+static_assert (!is_reference_type (^^float));
+static_assert (is_reference_type (^^int&));
+static_assert (is_reference_type (^^int&&));
+static_assert (!is_reference_type (^^int *));
+static_assert (!is_reference_type (^^int[1]));
+static_assert (!is_reference_type (^^int[]));
+static_assert (!is_reference_type (^^nullptr_t));
+static_assert (!is_reference_type (^^std::meta::info));
+static_assert (!is_reference_type (^^int (cls::*)));
+static_assert (!is_reference_type (^^int (cls::*)()));
+static_assert (!is_reference_type (^^cls));
+static_assert (!is_reference_type (^^empty));
+static_assert (!is_reference_type (^^abstract_cls));
+static_assert (!is_reference_type (^^final_cls));
+static_assert (!is_reference_type (^^ctor_cls));
+static_assert (!is_reference_type (^^trivial_cls));
+static_assert (!is_reference_type (^^virtual_dtor_cls));
+static_assert (!is_reference_type (^^onion));
+static_assert (!is_reference_type (^^Enum));
+static_assert (!is_reference_type (^^Enum_class));
+static_assert (!is_reference_type (^^void ()));
+
+static_assert (!is_arithmetic_type (^^void));
+static_assert (is_arithmetic_type (^^bool));
+static_assert (is_arithmetic_type (^^char));
+static_assert (is_arithmetic_type (^^int));
+static_assert (is_arithmetic_type (^^const int));
+static_assert (is_arithmetic_type (^^volatile int));
+static_assert (is_arithmetic_type (^^float));
+static_assert (!is_arithmetic_type (^^cls));
+static_assert (!is_arithmetic_type (^^int&));
+static_assert (!is_arithmetic_type (^^int&&));
+static_assert (!is_arithmetic_type (^^int *));
+static_assert (!is_arithmetic_type (^^int [1]));
+static_assert (!is_arithmetic_type (^^int []));
+static_assert (!is_arithmetic_type (^^nullptr_t));
+static_assert (!is_arithmetic_type (^^std::meta::info));
+static_assert (!is_arithmetic_type (^^int (cls::*)));
+static_assert (!is_arithmetic_type (^^int (cls::*)()));
+static_assert (!is_arithmetic_type (^^cls));
+static_assert (!is_arithmetic_type (^^empty));
+static_assert (!is_arithmetic_type (^^abstract_cls));
+static_assert (!is_arithmetic_type (^^final_cls));
+static_assert (!is_arithmetic_type (^^ctor_cls));
+static_assert (!is_arithmetic_type (^^trivial_cls));
+static_assert (!is_arithmetic_type (^^virtual_dtor_cls));
+static_assert (!is_arithmetic_type (^^onion));
+static_assert (!is_arithmetic_type (^^Enum));
+static_assert (!is_arithmetic_type (^^Enum_class));
+static_assert (!is_arithmetic_type (^^void ()));
+
+static_assert (!is_object_type (^^void));
+static_assert (is_object_type (^^bool));
+static_assert (is_object_type (^^char));
+static_assert (is_object_type (^^int));
+static_assert (is_object_type (^^const int));
+static_assert (is_object_type (^^volatile int));
+static_assert (is_object_type (^^float));
+static_assert (is_object_type (^^cls));
+static_assert (!is_object_type (^^int&));
+static_assert (!is_object_type (^^int&&));
+static_assert (is_object_type (^^int *));
+static_assert (is_object_type (^^int [1]));
+static_assert (is_object_type (^^int []));
+static_assert (is_object_type (^^nullptr_t));
+static_assert (is_object_type (^^std::meta::info));
+static_assert (is_object_type (^^int (cls::*)));
+static_assert (is_object_type (^^int (cls::*)()));
+static_assert (is_object_type (^^cls));
+static_assert (is_object_type (^^empty));
+static_assert (is_object_type (^^abstract_cls));
+static_assert (is_object_type (^^final_cls));
+static_assert (is_object_type (^^ctor_cls));
+static_assert (is_object_type (^^trivial_cls));
+static_assert (is_object_type (^^virtual_dtor_cls));
+static_assert (is_object_type (^^onion));
+static_assert (is_object_type (^^Enum));
+static_assert (is_object_type (^^Enum_class));
+static_assert (!is_object_type (^^void ()));
+
+static_assert (!is_member_pointer_type (^^void));
+static_assert (!is_member_pointer_type (^^bool));
+static_assert (!is_member_pointer_type (^^char));
+static_assert (!is_member_pointer_type (^^int));
+static_assert (!is_member_pointer_type (^^const int));
+static_assert (!is_member_pointer_type (^^volatile int));
+static_assert (!is_member_pointer_type (^^float));
+static_assert (!is_member_pointer_type (^^cls));
+static_assert (!is_member_pointer_type (^^int&));
+static_assert (!is_member_pointer_type (^^int&&));
+static_assert (!is_member_pointer_type (^^int *));
+static_assert (!is_member_pointer_type (^^int [1]));
+static_assert (!is_member_pointer_type (^^int []));
+static_assert (!is_member_pointer_type (^^nullptr_t));
+static_assert (!is_member_pointer_type (^^std::meta::info));
+static_assert (is_member_pointer_type (^^int (cls::*)));
+static_assert (is_member_pointer_type (^^int (cls::*)()));
+static_assert (!is_member_pointer_type (^^cls));
+static_assert (!is_member_pointer_type (^^empty));
+static_assert (!is_member_pointer_type (^^abstract_cls));
+static_assert (!is_member_pointer_type (^^final_cls));
+static_assert (!is_member_pointer_type (^^ctor_cls));
+static_assert (!is_member_pointer_type (^^trivial_cls));
+static_assert (!is_member_pointer_type (^^virtual_dtor_cls));
+static_assert (!is_member_pointer_type (^^onion));
+static_assert (!is_member_pointer_type (^^Enum));
+static_assert (!is_member_pointer_type (^^Enum_class));
+static_assert (!is_member_pointer_type (^^void ()));
+
+static_assert (!is_scalar_type (^^void));
+static_assert (is_scalar_type (^^bool));
+static_assert (is_scalar_type (^^char));
+static_assert (is_scalar_type (^^int));
+static_assert (is_scalar_type (^^const int));
+static_assert (is_scalar_type (^^volatile int));
+static_assert (is_scalar_type (^^float));
+static_assert (!is_scalar_type (^^cls));
+static_assert (!is_scalar_type (^^int&));
+static_assert (!is_scalar_type (^^int&&));
+static_assert (is_scalar_type (^^int *));
+static_assert (!is_scalar_type (^^int [1]));
+static_assert (!is_scalar_type (^^int []));
+static_assert (is_scalar_type (^^nullptr_t));
+static_assert (is_scalar_type (^^std::meta::info));
+static_assert (is_scalar_type (^^int (cls::*)));
+static_assert (is_scalar_type (^^int (cls::*)()));
+static_assert (!is_scalar_type (^^cls));
+static_assert (!is_scalar_type (^^empty));
+static_assert (!is_scalar_type (^^abstract_cls));
+static_assert (!is_scalar_type (^^final_cls));
+static_assert (!is_scalar_type (^^ctor_cls));
+static_assert (!is_scalar_type (^^trivial_cls));
+static_assert (!is_scalar_type (^^virtual_dtor_cls));
+static_assert (!is_scalar_type (^^onion));
+static_assert (is_scalar_type (^^Enum));
+static_assert (is_scalar_type (^^Enum_class));
+static_assert (!is_scalar_type (^^void ()));
+
+static_assert (is_fundamental_type (^^void));
+static_assert (is_fundamental_type (^^bool));
+static_assert (is_fundamental_type (^^char));
+static_assert (is_fundamental_type (^^int));
+static_assert (is_fundamental_type (^^const int));
+static_assert (is_fundamental_type (^^volatile int));
+static_assert (is_fundamental_type (^^float));
+static_assert (!is_fundamental_type (^^cls));
+static_assert (!is_fundamental_type (^^int&));
+static_assert (!is_fundamental_type (^^int&&));
+static_assert (!is_fundamental_type (^^int *));
+static_assert (!is_fundamental_type (^^int [1]));
+static_assert (!is_fundamental_type (^^int []));
+static_assert (is_fundamental_type (^^nullptr_t));
+static_assert (is_fundamental_type (^^std::meta::info));
+static_assert (!is_fundamental_type (^^int (cls::*)));
+static_assert (!is_fundamental_type (^^int (cls::*)()));
+static_assert (!is_fundamental_type (^^cls));
+static_assert (!is_fundamental_type (^^empty));
+static_assert (!is_fundamental_type (^^abstract_cls));
+static_assert (!is_fundamental_type (^^final_cls));
+static_assert (!is_fundamental_type (^^ctor_cls));
+static_assert (!is_fundamental_type (^^trivial_cls));
+static_assert (!is_fundamental_type (^^virtual_dtor_cls));
+static_assert (!is_fundamental_type (^^onion));
+static_assert (!is_fundamental_type (^^Enum));
+static_assert (!is_fundamental_type (^^Enum_class));
+static_assert (!is_fundamental_type (^^void ()));
+
+static_assert (!is_compound_type (^^void));
+static_assert (!is_compound_type (^^bool));
+static_assert (!is_compound_type (^^char));
+static_assert (!is_compound_type (^^int));
+static_assert (!is_compound_type (^^const int));
+static_assert (!is_compound_type (^^volatile int));
+static_assert (!is_compound_type (^^float));
+static_assert (is_compound_type (^^cls));
+static_assert (is_compound_type (^^int&));
+static_assert (is_compound_type (^^int&&));
+static_assert (is_compound_type (^^int *));
+static_assert (is_compound_type (^^int [1]));
+static_assert (is_compound_type (^^int []));
+static_assert (!is_compound_type (^^nullptr_t));
+static_assert (!is_compound_type (^^std::meta::info));
+static_assert (is_compound_type (^^int (cls::*)));
+static_assert (is_compound_type (^^int (cls::*)()));
+static_assert (is_compound_type (^^cls));
+static_assert (is_compound_type (^^empty));
+static_assert (is_compound_type (^^abstract_cls));
+static_assert (is_compound_type (^^final_cls));
+static_assert (is_compound_type (^^ctor_cls));
+static_assert (is_compound_type (^^trivial_cls));
+static_assert (is_compound_type (^^virtual_dtor_cls));
+static_assert (is_compound_type (^^onion));
+static_assert (is_compound_type (^^Enum));
+static_assert (is_compound_type (^^Enum_class));
+static_assert (is_compound_type (^^void ()));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait10.C b/gcc/testsuite/g++.dg/reflect/type_trait10.C
new file mode 100644 (file)
index 0000000..896f9b0
--- /dev/null
@@ -0,0 +1,116 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], other
+// transformations.
+
+#include <meta>
+using namespace std::meta;
+
+class ClassType { };
+using CT = ClassType;
+
+static_assert (remove_cvref (^^const volatile int) == ^^int);
+static_assert (remove_cvref (^^const volatile int *) == ^^const volatile int *);
+static_assert (remove_cvref (^^const volatile int &) == ^^int);
+static_assert (remove_cvref (^^const volatile int &&) == ^^int);
+static_assert (remove_cvref (^^const volatile ClassType) == ^^ClassType);
+static_assert (remove_cvref (^^const volatile ClassType *) == ^^const volatile ClassType *);
+static_assert (remove_cvref (^^const volatile ClassType &) == ^^ClassType);
+static_assert (remove_cvref (^^const volatile ClassType &&) == ^^ClassType);
+static_assert (remove_cvref (^^CT) == ^^ClassType);
+static_assert (remove_cvref (^^CT &) == ^^ClassType);
+static_assert (remove_cvref (^^const CT &) == ^^ClassType);
+static_assert (remove_cvref (^^const int (&) [3]) == ^^int [3]);
+static_assert (remove_cvref (^^const int (&) ()) == ^^const int ());
+
+static_assert (decay (^^bool) == ^^bool);
+static_assert (decay (^^int) == ^^int);
+static_assert (decay (^^ClassType) == ^^ClassType);
+static_assert (decay (^^CT) == ^^ClassType);
+static_assert (decay (^^const int) == ^^int);
+static_assert (decay (^^volatile const long) == ^^long);
+static_assert (decay (^^int &) == ^^int);
+static_assert (decay (^^int &&) == ^^int);
+static_assert (decay (^^CT &) == ^^ClassType);
+static_assert (decay (^^volatile const int &) == ^^int);
+static_assert (decay (^^const int &&) == ^^int);
+static_assert (decay (^^int [4]) == ^^int *);
+static_assert (decay (^^const int []) == ^^const int *);
+static_assert (decay (^^int [5][2][1]) == ^^int (*)[2][1]);
+static_assert (decay (^^const int [][5][1]) == ^^const int (*)[5][1]);
+static_assert (decay (^^int (int)) == ^^int (*) (int));
+
+enum E1 : unsigned { };
+enum E2 : char { };
+enum class E3 { };
+enum class E4 : unsigned char { c = 1 };
+enum class E5 : int { a = -1, b = 1 };
+enum class E6 : long { c = __LONG_MAX__ };
+enum E7 { E70 = 0 };
+enum E8 { E80 = ~0UL };
+
+static_assert (underlying_type (^^E1) == ^^unsigned);
+static_assert (underlying_type (^^E2) == ^^char);
+static_assert (underlying_type (^^E3) == ^^int);
+static_assert (underlying_type (^^E4) == ^^unsigned char);
+static_assert (underlying_type (^^E5) == ^^int);
+static_assert (underlying_type (^^E6) == ^^long);
+static_assert (is_integral_type (underlying_type (^^E7)));
+static_assert (is_integral_type (underlying_type (^^E8)));
+
+struct S;
+struct T;
+template <typename T>
+struct U
+{
+};
+typedef int int2;
+struct V {};
+namespace
+{
+  struct W {};
+}
+
+template <typename T, typename U>
+struct eq
+{
+  constexpr eq ()
+  {
+    static_assert (type_order (^^T, ^^U) == std::strong_ordering::equal);
+    static_assert (type_order (^^U, ^^T) == std::strong_ordering::equal);
+  }
+};
+template <typename T, typename U>
+struct ne
+{
+  constexpr ne ()
+  {
+    static_assert (type_order (^^T, ^^U) != std::strong_ordering::equal);
+    static_assert (type_order (^^U, ^^T) != std::strong_ordering::equal);
+    static_assert (type_order (^^T, ^^U) == std::strong_ordering::greater
+                   ? type_order (^^U, ^^T) == std::strong_ordering::less
+                   : type_order (^^U, ^^T) == std::strong_ordering::greater);
+  }
+};
+
+constexpr eq <void, void> a;
+constexpr eq <const void, const void> b;
+constexpr eq <int, int> c;
+constexpr eq <long int, long int> d;
+constexpr eq <const volatile unsigned, const volatile unsigned> e;
+constexpr eq <S, S> f;
+constexpr eq <U <int>, U <int>> g;
+constexpr eq <unsigned[2], unsigned[2]> h;
+constexpr eq <int, int2> i;
+constexpr eq <int (*) (int, long), int (*) (int, long)> j;
+constexpr ne <int, long> k;
+constexpr ne <const int, int> l;
+constexpr ne <S, T> m;
+constexpr ne <int &, int &&> n;
+constexpr ne <U <S>, U <T>> o;
+constexpr ne <U <short>, U <char>> p;
+constexpr ne <int (*) (int, long), int (*) (int, int)> q;
+constexpr eq <W, W> r;
+constexpr ne <V, W> s;
+constexpr eq <U <W>, U <W>> t;
+constexpr ne <U <V>, U <W>> u;
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait11.C b/gcc/testsuite/g++.dg/reflect/type_trait11.C
new file mode 100644 (file)
index 0000000..977afbc
--- /dev/null
@@ -0,0 +1,447 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <functional>
+#include <meta>
+
+using namespace std::meta;
+
+class ClassType { };
+class DerivedType : public ClassType { };
+enum EnumType { e0 };
+struct ThrowDefaultClass { ThrowDefaultClass () noexcept (false); };
+struct ThrowCopyConsClass { ThrowCopyConsClass (const ThrowCopyConsClass &) noexcept (false); };
+struct ThrowMoveConsClass { ThrowMoveConsClass (ThrowMoveConsClass &&) noexcept (false); };
+struct NoexceptDefaultClass { NoexceptDefaultClass () noexcept (true); };
+struct ExceptDefaultClass { ExceptDefaultClass () noexcept (false); };
+struct NoexceptCopyConsClass { NoexceptCopyConsClass (const NoexceptCopyConsClass &) noexcept (true); };
+struct ExceptCopyConsClass { ExceptCopyConsClass (const ExceptCopyConsClass &) noexcept (false); };
+struct NoexceptMoveConsClass { NoexceptMoveConsClass (NoexceptMoveConsClass &&) noexcept (true); NoexceptMoveConsClass &operator= (NoexceptMoveConsClass &&) = default; };
+struct ExceptMoveConsClass { ExceptMoveConsClass (ExceptMoveConsClass &&) noexcept (false); };
+struct NoexceptCopyAssignClass { NoexceptCopyAssignClass &operator= (const NoexceptCopyAssignClass &) noexcept (true); };
+struct ExceptCopyAssignClass { ExceptCopyAssignClass &operator= (const ExceptCopyAssignClass &) noexcept (false); };
+struct NoexceptMoveAssignClass { NoexceptMoveAssignClass (NoexceptMoveAssignClass &&) = default; NoexceptMoveAssignClass &operator= (NoexceptMoveAssignClass &&) noexcept (true); };
+struct ExceptMoveAssignClass { ExceptMoveAssignClass &operator= (ExceptMoveAssignClass &&) noexcept (false); };
+struct DeletedCopyAssignClass { DeletedCopyAssignClass & operator= (const DeletedCopyAssignClass &) = delete; };
+struct DeletedMoveAssignClass { DeletedMoveAssignClass &operator= (DeletedMoveAssignClass &&) = delete; };
+struct NType { int i; int j; virtual ~NType (); };
+struct TType { int i; private: int j; };
+struct SLType { int i; int j; ~SLType (); };
+struct PODType { int i; int j; };
+struct LType { int i; constexpr LType (int j) : i(j) {} };
+struct HasTemplateCCtor { HasTemplateCCtor (const HasTemplateCCtor &) = default; template <class T> HasTemplateCCtor (T &&); };
+struct MoveOnly { MoveOnly (MoveOnly &&) = default; };
+struct MoveOnly2 { MoveOnly2 (MoveOnly2 &&) = delete; };
+class PolymorphicClass { virtual void rotate (int); };
+struct CopyConsOnlyType {
+  CopyConsOnlyType (int) { }
+  CopyConsOnlyType (CopyConsOnlyType &&) = delete;
+  CopyConsOnlyType (const CopyConsOnlyType &) = default;
+  CopyConsOnlyType &operator= (const CopyConsOnlyType &) = delete;
+  CopyConsOnlyType &operator= (CopyConsOnlyType &&) = delete;
+};
+struct MoveConsOnlyType {
+  MoveConsOnlyType (int) { }
+  MoveConsOnlyType (const MoveConsOnlyType &) = delete;
+  MoveConsOnlyType (MoveConsOnlyType &&) = default;
+  MoveConsOnlyType &operator= (const MoveConsOnlyType &) = delete;
+  MoveConsOnlyType &operator= (MoveConsOnlyType &&) = delete;
+};
+struct NoexceptExplicitClass {
+  NoexceptExplicitClass (double &) noexcept (true);
+  explicit NoexceptExplicitClass (int &) noexcept (true);
+  NoexceptExplicitClass (double &, int &, double &) noexcept (true);
+};
+struct ExceptExplicitClass {
+  ExceptExplicitClass (double &) noexcept (false);
+  explicit ExceptExplicitClass (int &) noexcept (false);
+  ExceptExplicitClass (double &, int &, double &) noexcept (false);
+};
+struct NothrowExplicitClass {
+  NothrowExplicitClass (double &) throw ();
+  explicit NothrowExplicitClass (int &) throw ();
+  NothrowExplicitClass (double &, int &, double &) throw ();
+};
+
+namespace N1
+{
+  struct Empty {};
+  struct B { int i; B () {} };
+  struct D : B {};
+  enum E { ee1 };
+  enum E2 { ee2 };
+  enum class SE { e1 };
+  enum class SE2 { e2 };
+  enum OpE : int;
+  enum class OpSE : bool;
+  union U { int i; Empty b; };
+  struct Abstract { virtual ~Abstract () = 0; };
+  struct AbstractDelDtor { ~AbstractDelDtor () = delete; virtual void foo () = 0; };
+  struct Ukn;
+  template <class To>
+  struct ImplicitTo { operator To (); };
+  template <class To>
+  struct DelImplicitTo { operator To () = delete; };
+  template <class To>
+  struct ExplicitTo { explicit operator To (); };
+  struct Ellipsis { Ellipsis (...) {} };
+  struct DelEllipsis { DelEllipsis (...) = delete; };
+  struct Any { template <class T> Any (T &&) {} };
+  struct nAny { template <class... T> nAny (T &&...) {} };
+  struct DelnAny { template <class... T> DelnAny (T &&...) = delete; };
+  template <class... Args>
+  struct FromArgs { FromArgs (Args...); };
+  struct DelDef { DelDef () = delete; };
+  struct DelCopy { DelCopy (const DelCopy &) = delete; };
+  struct DelDtor {
+    DelDtor () = default;
+    DelDtor (const DelDtor &) = default;
+    DelDtor (DelDtor &&) = default;
+    DelDtor (int);
+    DelDtor (int, B, U);
+    ~DelDtor () = delete;
+  };
+  struct Nontrivial {
+    Nontrivial ();
+    Nontrivial (const Nontrivial &);
+    Nontrivial &operator= (const Nontrivial &);
+    ~Nontrivial ();
+  };
+  union NontrivialUnion { int i; Nontrivial n; };
+  struct UnusualCopy { UnusualCopy (UnusualCopy &); };
+}
+struct X { X () = default; X (int) noexcept {} X (double) {} };
+struct Y { int i; X x; };
+struct Z : Y { };
+
+static_assert (is_trivially_constructible_type (^^int, {}));
+static_assert (is_trivially_constructible_type (^^int, { ^^int }));
+static_assert (is_trivially_constructible_type (^^int, { ^^int & }));
+static_assert (is_trivially_constructible_type (^^int, { ^^int && }));
+static_assert (is_trivially_constructible_type (^^int, { ^^const int & }));
+static_assert (!is_trivially_constructible_type (^^int, { ^^void * }));
+static_assert (!is_trivially_constructible_type (^^int, { ^^int * }));
+static_assert (!is_trivially_constructible_type (^^int, { ^^const int * }));
+static_assert (!is_trivially_constructible_type (^^int *, { ^^void * }));
+static_assert (!is_trivially_constructible_type (^^int *, { ^^const int * }));
+static_assert (!is_trivially_constructible_type (^^int &, { ^^const int }));
+static_assert (is_trivially_constructible_type (^^const int &, { ^^int }));
+static_assert (is_trivially_constructible_type (^^const int &, { ^^int & }));
+static_assert (is_trivially_constructible_type (^^const int *, { ^^int * }));
+static_assert (!is_trivially_constructible_type (^^PolymorphicClass, {}));
+static_assert (!is_trivially_constructible_type (^^PolymorphicClass, { ^^PolymorphicClass }));
+static_assert (!is_trivially_constructible_type (^^PolymorphicClass, { ^^PolymorphicClass & }));
+static_assert (!is_trivially_constructible_type (^^PolymorphicClass, { ^^PolymorphicClass && }));
+static_assert (!is_trivially_constructible_type (^^PolymorphicClass, { ^^const PolymorphicClass & }));
+static_assert (is_trivially_constructible_type (^^TType, {}));
+static_assert (is_trivially_constructible_type (^^TType, { ^^TType }));
+static_assert (is_trivially_constructible_type (^^TType, { ^^TType & }));
+static_assert (is_trivially_constructible_type (^^TType, { ^^TType && }));
+static_assert (is_trivially_constructible_type (^^TType, { ^^const TType & }));
+static_assert (!is_trivially_constructible_type (^^TType, { ^^int, ^^int }));
+static_assert (is_trivially_constructible_type (^^PODType, {}));
+static_assert (is_trivially_constructible_type (^^PODType, { ^^PODType }));
+static_assert (is_trivially_constructible_type (^^PODType, { ^^PODType & }));
+static_assert (is_trivially_constructible_type (^^PODType, { ^^PODType && }));
+static_assert (is_trivially_constructible_type (^^PODType, { ^^const PODType & }));
+static_assert (is_trivially_constructible_type (^^PODType, { ^^int, ^^int }));
+static_assert (!is_trivially_constructible_type (^^NType, {}));
+static_assert (!is_trivially_constructible_type (^^SLType, {}));
+static_assert (!is_trivially_constructible_type (^^LType, {}));
+static_assert (!is_trivially_constructible_type (^^LType, { ^^int }));
+static_assert (!is_trivially_constructible_type (^^N1::DelDef, {}));
+static_assert (!is_trivially_constructible_type (^^N1::Abstract, {}));
+static_assert (!is_trivially_constructible_type (^^N1::Ellipsis, {}));
+static_assert (!is_trivially_constructible_type (^^N1::DelEllipsis, {}));
+static_assert (!is_trivially_constructible_type (^^N1::Any, {}));
+static_assert (!is_trivially_constructible_type (^^N1::DelCopy, {}));
+static_assert (!is_trivially_constructible_type (^^N1::DelCopy, { ^^const N1::DelCopy & }));
+static_assert (!is_trivially_constructible_type (^^N1::DelDtor, {}));
+static_assert (!is_trivially_constructible_type (^^N1::Nontrivial, {}));
+static_assert (!is_trivially_constructible_type (^^N1::UnusualCopy, {}));
+static_assert (!is_trivially_constructible_type (^^CopyConsOnlyType, {}));
+static_assert (!is_trivially_constructible_type (^^CopyConsOnlyType, { ^^CopyConsOnlyType }));
+static_assert (is_trivially_constructible_type (^^CopyConsOnlyType, { ^^CopyConsOnlyType & }));
+static_assert (!is_trivially_constructible_type (^^CopyConsOnlyType, { ^^CopyConsOnlyType && }));
+static_assert (is_trivially_constructible_type (^^CopyConsOnlyType, { ^^const CopyConsOnlyType & }));
+static_assert (!is_trivially_constructible_type (^^MoveConsOnlyType, {}));
+static_assert (is_trivially_constructible_type (^^MoveConsOnlyType, { ^^MoveConsOnlyType }));
+static_assert (!is_trivially_constructible_type (^^MoveConsOnlyType, { ^^MoveConsOnlyType & }));
+static_assert (is_trivially_constructible_type (^^MoveConsOnlyType, { ^^MoveConsOnlyType && }));
+static_assert (!is_trivially_constructible_type (^^MoveConsOnlyType, { ^^const MoveConsOnlyType & }));
+static_assert (is_trivially_constructible_type (^^ClassType, { ^^DerivedType }));
+static_assert (is_trivially_constructible_type (^^ClassType, { ^^DerivedType & }));
+static_assert (is_trivially_constructible_type (^^ClassType, { ^^DerivedType && }));
+static_assert (is_trivially_constructible_type (^^ClassType, { ^^const DerivedType & }));
+static_assert (!is_trivially_constructible_type (^^HasTemplateCCtor, {}));
+static_assert (!is_trivially_constructible_type (^^HasTemplateCCtor, { ^^HasTemplateCCtor }));
+static_assert (is_trivially_constructible_type (^^HasTemplateCCtor, { ^^const HasTemplateCCtor & }));
+static_assert (!is_trivially_constructible_type (^^MoveOnly, {}));
+static_assert (is_trivially_constructible_type (^^MoveOnly, { ^^MoveOnly }));
+static_assert (!is_trivially_constructible_type (^^MoveOnly, { ^^MoveOnly & }));
+static_assert (is_trivially_constructible_type (^^MoveOnly, { ^^MoveOnly && }));
+static_assert (!is_trivially_constructible_type (^^MoveOnly, { ^^const MoveOnly & }));
+static_assert (!is_trivially_constructible_type (^^MoveOnly2, {}));
+static_assert (!is_trivially_constructible_type (^^int [], {}));
+
+static_assert (is_nothrow_constructible_type (^^NoexceptExplicitClass, { ^^double & }));
+static_assert (is_nothrow_constructible_type (^^NoexceptExplicitClass, { ^^int & }));
+static_assert (is_nothrow_constructible_type (^^NoexceptExplicitClass, { ^^double &, ^^int &, ^^double & }));
+static_assert (is_nothrow_constructible_type (^^NothrowExplicitClass, { ^^double & }));
+static_assert (is_nothrow_constructible_type (^^NothrowExplicitClass, { ^^int & }));
+static_assert (is_nothrow_constructible_type (^^NothrowExplicitClass, { ^^double &, ^^int &, ^^double & }));
+static_assert (is_nothrow_constructible_type (^^int [1], {}));
+static_assert (!is_nothrow_constructible_type (^^NoexceptExplicitClass, { ^^void * }));
+static_assert (!is_nothrow_constructible_type (^^NoexceptExplicitClass, {}));
+static_assert (!is_nothrow_constructible_type (^^NoexceptExplicitClass, { ^^int, ^^double }));
+static_assert (!is_nothrow_constructible_type (^^NothrowExplicitClass, { ^^void * }));
+static_assert (!is_nothrow_constructible_type (^^NothrowExplicitClass, {}));
+static_assert (!is_nothrow_constructible_type (^^NothrowExplicitClass, { ^^int, ^^double }));
+static_assert (!is_nothrow_constructible_type (^^ExceptExplicitClass, { ^^double & }));
+static_assert (!is_nothrow_constructible_type (^^ExceptExplicitClass, { ^^int & }));
+static_assert (!is_nothrow_constructible_type (^^ExceptExplicitClass, { ^^double &, ^^int &, ^^double & }));
+static_assert (!is_nothrow_constructible_type (^^int [], {}));
+static_assert (is_nothrow_constructible_type (^^int [1], {}));
+static_assert (is_nothrow_constructible_type (^^int [1], { ^^int }));
+static_assert (is_nothrow_constructible_type (^^int [2], { ^^int }));
+static_assert (is_nothrow_constructible_type (^^int [2], { ^^int, ^^int }));
+static_assert (!is_nothrow_constructible_type (^^int [1], { ^^int, ^^int }));
+static_assert (!is_nothrow_constructible_type (^^int [], {}));
+static_assert (!is_nothrow_constructible_type (^^int [], { ^^int }));
+static_assert (!is_nothrow_constructible_type (^^int [], { ^^int, ^^int }));
+static_assert (is_nothrow_constructible_type (^^X [2], {}));
+static_assert (is_nothrow_constructible_type (^^X [1], { ^^X }));
+static_assert (is_nothrow_constructible_type (^^X [1], { ^^int }));
+static_assert (!is_nothrow_constructible_type (^^X [1], { ^^double }));
+static_assert (!is_nothrow_constructible_type (^^X [2], { ^^int, ^^double }));
+static_assert (is_nothrow_constructible_type (^^Y, {}));
+static_assert (is_nothrow_constructible_type (^^Y, { ^^Y }));
+static_assert (is_nothrow_constructible_type (^^Y, { ^^int }));
+static_assert (!is_nothrow_constructible_type (^^Y, { ^^X }));
+static_assert (is_nothrow_constructible_type (^^Y, { ^^int, ^^X }));
+static_assert (is_nothrow_constructible_type (^^Y, { ^^int, ^^int }));
+static_assert (!is_nothrow_constructible_type (^^Y, { ^^int, ^^double }));
+static_assert (is_nothrow_constructible_type (^^Z, {}));
+static_assert (is_nothrow_constructible_type (^^Z, { ^^Z }));
+static_assert (is_nothrow_constructible_type (^^Z, { ^^Y }));
+static_assert (!is_nothrow_constructible_type (^^Z, { ^^int }));
+static_assert (!is_nothrow_constructible_type (^^Z, { ^^int, ^^X }));
+static_assert (!is_nothrow_constructible_type (^^Z, { ^^int, ^^int }));
+static_assert (!is_nothrow_constructible_type (^^Z, { ^^Y, ^^double }));
+static_assert (!is_nothrow_constructible_type (^^Z, { ^^int, ^^double }));
+static_assert (!is_nothrow_constructible_type (^^Z, { ^^X }));
+
+using func_type_v0 = void (*) ();
+using func_type_i0 = int (*) ();
+using func_type_l0 = int &(*) ();
+using func_type_ii = int (*) (int);
+using func_type_il = int (*) (int &);
+using func_type_ir = int (*) (int &&);
+struct W { };
+
+using mem_type_i = int W::*;
+using memfun_type_i = int (W::*) ();
+using memfun_type_iic = int &(W::*) (int &) const;
+struct F {
+  int &operator () ();
+  long &operator () () const;
+  short &operator () (int) &&;
+  char &operator () (int) const &;
+private:
+  void operator () (int, int);
+};
+using CF = const F;
+struct T { T (int) { } };
+struct NT { NT (int) noexcept { } };
+struct Ex { explicit Ex (int) noexcept { } };
+using func_type = void (*) ();
+using func_type_nt = void (*) () noexcept;
+using mem_type = int W::*;
+using memfun_type = int (W::*) ();
+using memfun_type_nt = int (W::*) () noexcept;
+struct F2 {
+  int &operator () ();
+  long &operator () () const noexcept;
+  short &operator () (int) &&;
+  char &operator () (int) const & noexcept;
+private:
+  void operator () (int, int) noexcept;
+};
+using CF2 = const F2;
+struct FW { W operator () () const noexcept { return {}; } };
+struct V { explicit V (W) noexcept; V (...); };
+
+static_assert (is_invocable_type (^^func_type_v0, {}));
+static_assert (!is_invocable_type (^^func_type_v0, { ^^int }));
+static_assert (is_invocable_type (^^func_type_i0, {}));
+static_assert (!is_invocable_type (^^func_type_i0, { ^^int }));
+static_assert (is_invocable_type (^^func_type_l0, {}));
+static_assert (!is_invocable_type (^^func_type_l0 (int), {}));
+static_assert (!is_invocable_type (^^func_type_ii, {}));
+static_assert (is_invocable_type (^^func_type_ii, { ^^int }));
+static_assert (!is_invocable_type (^^func_type_il, {}));
+static_assert (!is_invocable_type (^^func_type_il, { ^^int }));
+static_assert (is_invocable_type (^^func_type_il, { ^^int & }));
+static_assert (!is_invocable_type (^^func_type_ir, {}));
+static_assert (is_invocable_type (^^func_type_ir, { ^^int }));
+static_assert (!is_invocable_type (^^func_type_ir, { ^^int & }));
+static_assert (!is_invocable_type (^^mem_type_i, {}));
+static_assert (!is_invocable_type (^^mem_type_i, { ^^int }));
+static_assert (!is_invocable_type (^^mem_type_i, { ^^int & }));
+static_assert (is_invocable_type (^^mem_type_i, { ^^W & }));
+static_assert (!is_invocable_type (^^memfun_type_i, {}));
+static_assert (!is_invocable_type (^^memfun_type_i, { ^^int }));
+static_assert (!is_invocable_type (^^memfun_type_i, { ^^int & }));
+static_assert (is_invocable_type (^^memfun_type_i, { ^^W & }));
+static_assert (is_invocable_type (^^memfun_type_i, { ^^W * }));
+static_assert (!is_invocable_type (^^memfun_type_i, { ^^const W & }));
+static_assert (!is_invocable_type (^^memfun_type_i, { ^^W &, ^^int }));
+static_assert (!is_invocable_type (^^memfun_type_iic, {}));
+static_assert (!is_invocable_type (^^memfun_type_iic, { ^^int }));
+static_assert (!is_invocable_type (^^memfun_type_iic, { ^^int & }));
+static_assert (!is_invocable_type (^^memfun_type_iic, { ^^W &, ^^int }));
+static_assert (!is_invocable_type (^^memfun_type_iic, { ^^const W &, ^^int }));
+static_assert (!is_invocable_type (^^memfun_type_iic, { ^^const W &, ^^int &, ^^int }));
+static_assert (is_invocable_type (^^memfun_type_iic, { ^^const W &, ^^int & }));
+static_assert (is_invocable_type (^^memfun_type_iic, { ^^const W *, ^^int & }));
+static_assert (!is_invocable_type (^^F, { ^^int, ^^int }));
+
+static_assert (!is_nothrow_invocable_type (^^func_type, {}));
+static_assert (is_nothrow_invocable_type (^^func_type_nt, {}));
+static_assert (!is_nothrow_invocable_type (^^mem_type, {}));
+static_assert (!is_nothrow_invocable_type (^^mem_type, { ^^int }));
+static_assert (!is_nothrow_invocable_type (^^mem_type, { ^^int & }));
+static_assert (is_nothrow_invocable_type (^^mem_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_type (^^memfun_type, {}));
+static_assert (!is_nothrow_invocable_type (^^memfun_type, { ^^int }));
+static_assert (!is_nothrow_invocable_type (^^memfun_type, { ^^int & }));
+static_assert (!is_nothrow_invocable_type (^^memfun_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_type (^^memfun_type, { ^^W * }));
+static_assert (!is_nothrow_invocable_type (^^memfun_type_nt, {}));
+static_assert (!is_nothrow_invocable_type (^^memfun_type_nt, { ^^int }));
+static_assert (!is_nothrow_invocable_type (^^memfun_type_nt, { ^^int & }));
+static_assert (is_nothrow_invocable_type (^^memfun_type_nt, { ^^W & }));
+static_assert (is_nothrow_invocable_type (^^memfun_type_nt, { ^^W * }));
+static_assert (!is_nothrow_invocable_type (^^F2, {}));
+static_assert (is_nothrow_invocable_type (^^CF2, {}));
+static_assert (!is_nothrow_invocable_type (^^F2, { ^^int }));
+static_assert (is_nothrow_invocable_type (^^F2 &, { ^^int }));
+static_assert (is_nothrow_invocable_type (^^CF2, { ^^int }));
+static_assert (is_nothrow_invocable_type (^^CF2 &, { ^^int }));
+static_assert (!is_nothrow_invocable_type (^^F2, { ^^int, ^^int }));
+static_assert (is_nothrow_invocable_type (^^FW, {}));
+
+static_assert (is_invocable_r_type (^^void, ^^func_type_v0, {}));
+static_assert (!is_invocable_r_type (^^void *, ^^func_type_v0, {}));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_v0, {}));
+static_assert (!is_invocable_r_type (^^void, ^^func_type_v0, { ^^int }));
+static_assert (!is_invocable_r_type (^^void *, ^^func_type_v0, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_v0, { ^^int }));
+static_assert (is_invocable_r_type (^^void, ^^func_type_i0, {}));
+static_assert (is_invocable_r_type (^^int, ^^func_type_i0, {}));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_i0, {}));
+static_assert (is_invocable_r_type (^^long, ^^func_type_i0, {}));
+static_assert (!is_invocable_r_type (^^void, ^^func_type_i0, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_i0, { ^^int }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_i0, { ^^int }));
+static_assert (!is_invocable_r_type (^^long, ^^func_type_i0, { ^^int }));
+static_assert (is_invocable_r_type (^^void, ^^func_type_l0, {}));
+static_assert (is_invocable_r_type (^^int, ^^func_type_l0, {}));
+static_assert (is_invocable_r_type (^^int &, ^^func_type_l0, {}));
+static_assert (!is_invocable_r_type (^^int &&, ^^func_type_l0, {}));
+static_assert (is_invocable_r_type (^^long, ^^func_type_l0, {}));
+static_assert (!is_invocable_r_type (^^long &, ^^func_type_l0, {}));
+static_assert (!is_invocable_r_type (^^void, ^^func_type_l0, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_l0, { ^^int }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_l0, { ^^int }));
+static_assert (!is_invocable_r_type (^^long, ^^func_type_l0, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_ii, {}));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_ii, {}));
+static_assert (!is_invocable_r_type (^^long, ^^func_type_ii, {}));
+static_assert (is_invocable_r_type (^^int, ^^func_type_ii, { ^^int }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_ii, { ^^int }));
+static_assert (is_invocable_r_type (^^long, ^^func_type_ii, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_il, { ^^int }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_il, { ^^int }));
+static_assert (!is_invocable_r_type (^^long, ^^func_type_il, { ^^int }));
+static_assert (is_invocable_r_type (^^int, ^^func_type_il, { ^^int & }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_il, { ^^int & }));
+static_assert (is_invocable_r_type (^^long, ^^func_type_il, { ^^int & }));
+static_assert (is_invocable_r_type (^^int, ^^func_type_ir, { ^^int }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_ir, { ^^int }));
+static_assert (is_invocable_r_type (^^long, ^^func_type_ir, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^func_type_ir, { ^^int & }));
+static_assert (!is_invocable_r_type (^^int &, ^^func_type_ir, { ^^int & }));
+static_assert (!is_invocable_r_type (^^long, ^^func_type_ir, { ^^int & }));
+static_assert (!is_invocable_r_type (^^int, ^^mem_type_i, { ^^int }));
+static_assert (!is_invocable_r_type (^^int &, ^^mem_type_i, { ^^int }));
+static_assert (!is_invocable_r_type (^^long, ^^mem_type_i, { ^^int }));
+static_assert (!is_invocable_r_type (^^int, ^^mem_type_i, { ^^int & }));
+static_assert (!is_invocable_r_type (^^int &, ^^mem_type_i, { ^^int & }));
+static_assert (!is_invocable_r_type (^^long, ^^mem_type_i, { ^^int & }));
+static_assert (is_invocable_r_type (^^int, ^^mem_type_i, { ^^W & }));
+static_assert (is_invocable_r_type (^^int &, ^^mem_type_i, { ^^W & }));
+static_assert (is_invocable_r_type (^^long, ^^mem_type_i, { ^^W & }));
+static_assert (is_invocable_r_type (^^int, ^^memfun_type_i, { ^^W & }));
+static_assert (!is_invocable_r_type (^^int &, ^^memfun_type_i, { ^^W & }));
+static_assert (is_invocable_r_type (^^long, ^^memfun_type_i, { ^^W & }));
+static_assert (!is_invocable_r_type (^^int, ^^memfun_type_i, { ^^const W & }));
+static_assert (is_invocable_r_type (^^int, ^^memfun_type_iic, { ^^const W &, ^^int & }));
+static_assert (is_invocable_r_type (^^int &, ^^memfun_type_iic, { ^^const W &, ^^int & }));
+static_assert (is_invocable_r_type (^^long, ^^memfun_type_iic, { ^^const W &, ^^int & }));
+static_assert (!is_invocable_r_type (^^long &, ^^memfun_type_iic, { ^^const W &, ^^int & }));
+static_assert (is_invocable_r_type (^^int &, ^^F, {}));
+static_assert (is_invocable_r_type (^^int &, ^^F &, {}));
+static_assert (is_invocable_r_type (^^long &, ^^CF, {}));
+static_assert (is_invocable_r_type (^^long &, ^^CF &, {}));
+static_assert (is_invocable_r_type (^^short &, ^^F, { ^^int }));
+static_assert (is_invocable_r_type (^^char &, ^^F &, { ^^int }));
+static_assert (is_invocable_r_type (^^char &, ^^CF, { ^^int }));
+static_assert (is_invocable_r_type (^^char &, ^^CF &, { ^^int }));
+
+static_assert (is_nothrow_invocable_r_type (^^int, ^^mem_type, { ^^W & }));
+static_assert (is_nothrow_invocable_r_type (^^int &, ^^mem_type, { ^^W & }));
+static_assert (is_nothrow_invocable_r_type (^^long, ^^mem_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^long &, ^^mem_type, { ^^W & }));
+static_assert (is_nothrow_invocable_r_type (^^int &, ^^mem_type, { ^^W * }));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^mem_type, { ^^W & }));
+static_assert (is_nothrow_invocable_r_type (^^NT, ^^mem_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^mem_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^memfun_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^NT, ^^memfun_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^memfun_type, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^memfun_type_nt, { ^^W & }));
+static_assert (is_nothrow_invocable_r_type (^^NT, ^^memfun_type_nt, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^memfun_type_nt, { ^^W & }));
+static_assert (!is_nothrow_invocable_r_type (^^int &, ^^F2, {}));
+static_assert (is_nothrow_invocable_r_type (^^long &, ^^CF2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^F2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^NT, ^^F2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^F2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^void, ^^F2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^CF2, {}));
+static_assert (is_nothrow_invocable_r_type (^^NT, ^^CF2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^CF2, {}));
+static_assert (is_nothrow_invocable_r_type (^^void, ^^CF2, {}));
+static_assert (!is_nothrow_invocable_r_type (^^short &, ^^F2, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^char &, ^^F2 &, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^F2 &, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^NT, ^^F2 &, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^F2 &, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^char &, ^^CF2, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^char &, ^^CF2 &, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^void, ^^CF2 &, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^T, ^^CF2 &, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^NT, ^^CF2 &, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^Ex, ^^CF2 &, { ^^int }));
+static_assert (is_nothrow_invocable_r_type (^^void, ^^CF2 &, { ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^void, ^^F2, { ^^int, ^^int }));
+static_assert (!is_nothrow_invocable_r_type (^^V, ^^FW, {}));
+
+static_assert (invoke_result (^^std::copyable_function <void ()>, {}) == ^^void);
+static_assert (invoke_result (^^std::copyable_function <int ()>, {}) == ^^int);
+static_assert (invoke_result (^^std::copyable_function <int & ()>, {}) == ^^int &);
+static_assert (invoke_result (^^std::copyable_function <void (long, int)>, { ^^long, ^^int }) == ^^void);
+static_assert (invoke_result (^^std::copyable_function <int (double, unsigned)>, { ^^double, ^^unsigned }) == ^^int);
+static_assert (invoke_result (^^std::copyable_function <int & (int &)>, { ^^int & }) == ^^int &);
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait12.C b/gcc/testsuite/g++.dg/reflect/type_trait12.C
new file mode 100644 (file)
index 0000000..372d740
--- /dev/null
@@ -0,0 +1,137 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// { dg-add-options float16 }
+// { dg-add-options float32 }
+// { dg-add-options float64 }
+// { dg-add-options float128 }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <functional>
+#include <meta>
+
+using namespace std::meta;
+
+struct A { int a, b, c; };
+class B { static int a; private: static int b; public: int c; };
+struct C { C () {} int a, b, c; };
+struct D { explicit D (int) {} int a, b, c; };
+struct E : public A { int d, e, f; };
+struct F : public C { using C::C; int d, e, f; };
+class G { int a, b; };
+struct H { private: int a, b; };
+struct I { protected: int a, b; };
+struct J { int a, b; void foo (); };
+struct K { int a, b; virtual void foo (); };
+struct L : virtual public A { int d, e; };
+struct M : protected A { int d, e; };
+struct N : private A { int d, e; };
+struct O { O () = delete; int a, b, c; };
+struct P { P () = default; int a, b, c; };
+struct Q { Q (); Q (const Q &); int a, b, c; };
+struct R { R (); R (const R &); R (R &&) = default; int a, b, c; };
+struct S { S (); ~S (); int a, b, c; };
+struct T { T (); ~T () = default; int a, b, c; };
+struct U { U (); U (const U &) = default; int a, b, c; };
+struct V { V () = default; V (const V &); int a, b, c; };
+enum W { W1 };
+enum class X : int { X1 };
+struct Y { int g; int foo (int); };
+struct Z;
+struct AA { Q a; Q b; };
+struct AB { Q a; Q b; ~AB () = default; };
+struct AC { Q a; Q b; ~AC () {} };
+struct AD : public Q {};
+struct AE : public Q { ~AE () = default; };
+struct AF : public Q { ~AF () {} };
+
+static_assert (!is_implicit_lifetime_type (^^void));
+static_assert (!is_implicit_lifetime_type (^^const void));
+static_assert (!is_implicit_lifetime_type (^^volatile void));
+static_assert (is_implicit_lifetime_type (^^char));
+static_assert (is_implicit_lifetime_type (^^signed char));
+static_assert (is_implicit_lifetime_type (^^const unsigned char));
+static_assert (is_implicit_lifetime_type (^^short));
+static_assert (is_implicit_lifetime_type (^^volatile unsigned short));
+static_assert (is_implicit_lifetime_type (^^int));
+static_assert (is_implicit_lifetime_type (^^unsigned int));
+static_assert (is_implicit_lifetime_type (^^const volatile long));
+static_assert (is_implicit_lifetime_type (^^unsigned long));
+static_assert (is_implicit_lifetime_type (^^long long));
+static_assert (is_implicit_lifetime_type (^^unsigned long long));
+#ifdef __SIZEOF_INT128__
+__extension__ static_assert (is_implicit_lifetime_type (^^__int128));
+__extension__ static_assert (is_implicit_lifetime_type (^^unsigned __int128));
+#endif
+static_assert (is_implicit_lifetime_type (^^float));
+static_assert (is_implicit_lifetime_type (^^double));
+static_assert (is_implicit_lifetime_type (^^long double volatile));
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (is_implicit_lifetime_type (^^_Float16));
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (is_implicit_lifetime_type (^^_Float32));
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (is_implicit_lifetime_type (^^const _Float64));
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (is_implicit_lifetime_type (^^_Float128));
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+static_assert (is_implicit_lifetime_type (^^decltype(0.bf16)));
+#endif
+static_assert (is_implicit_lifetime_type (^^W));
+static_assert (is_implicit_lifetime_type (^^const volatile X));
+static_assert (is_implicit_lifetime_type (^^int *));
+static_assert (is_implicit_lifetime_type (^^int (*) (int)));
+static_assert (is_implicit_lifetime_type (^^int (Y::*)));
+static_assert (is_implicit_lifetime_type (^^int (Y::*) (int)));
+static_assert (!is_implicit_lifetime_type (^^int &));
+static_assert (!is_implicit_lifetime_type (^^char &&));
+static_assert (is_implicit_lifetime_type (^^int []));
+__extension__ static_assert (!is_implicit_lifetime_type (^^int [0]));
+static_assert (is_implicit_lifetime_type (^^int [1]));
+static_assert (is_implicit_lifetime_type (^^const Y [42]));
+static_assert (!is_implicit_lifetime_type (^^int ()));
+static_assert (!is_implicit_lifetime_type (^^int () &));
+static_assert (!is_implicit_lifetime_type (^^int () const));
+static_assert (!is_implicit_lifetime_type (^^int (&) ()));
+static_assert (is_implicit_lifetime_type (^^Z []));
+static_assert (is_implicit_lifetime_type (^^Z [5]));
+static_assert (is_implicit_lifetime_type (^^A));
+static_assert (is_implicit_lifetime_type (^^B));
+static_assert (is_implicit_lifetime_type (^^C));
+static_assert (is_implicit_lifetime_type (^^D));
+static_assert (is_implicit_lifetime_type (^^E));
+static_assert (is_implicit_lifetime_type (^^F));
+static_assert (is_implicit_lifetime_type (^^G));
+static_assert (is_implicit_lifetime_type (^^H));
+static_assert (is_implicit_lifetime_type (^^I));
+static_assert (is_implicit_lifetime_type (^^J));
+static_assert (!is_implicit_lifetime_type (^^K));
+static_assert (!is_implicit_lifetime_type (^^L));
+static_assert (is_implicit_lifetime_type (^^M));
+static_assert (is_implicit_lifetime_type (^^N));
+static_assert (is_implicit_lifetime_type (^^O));
+static_assert (is_implicit_lifetime_type (^^P));
+static_assert (!is_implicit_lifetime_type (^^Q));
+static_assert (is_implicit_lifetime_type (^^R));
+static_assert (!is_implicit_lifetime_type (^^S));
+static_assert (is_implicit_lifetime_type (^^S [3]));
+static_assert (is_implicit_lifetime_type (^^T));
+static_assert (is_implicit_lifetime_type (^^U));
+static_assert (is_implicit_lifetime_type (^^V));
+static_assert (is_implicit_lifetime_type (^^_Complex double));
+static_assert (is_implicit_lifetime_type (^^int [[gnu::vector_size (4 * sizeof (int))]]));
+static_assert (is_implicit_lifetime_type (^^AA));
+static_assert (is_implicit_lifetime_type (^^AB));
+static_assert (!is_implicit_lifetime_type (^^AC));
+static_assert (is_implicit_lifetime_type (^^AD));
+static_assert (is_implicit_lifetime_type (^^AE));
+static_assert (!is_implicit_lifetime_type (^^AF));
+
+void
+foo (int n)
+{
+  __extension__ static_assert (is_implicit_lifetime_type (^^char [n]));
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait13.C b/gcc/testsuite/g++.dg/reflect/type_trait13.C
new file mode 100644 (file)
index 0000000..cd9f956
--- /dev/null
@@ -0,0 +1,425 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <meta>
+#include <utility>
+#include <array>
+#include <tuple>
+#include <queue>
+#include <stack>
+
+using namespace std::meta;
+
+class ClassType { };
+enum EnumType { e0 };
+struct ThrowCopyConsClass { ThrowCopyConsClass (const ThrowCopyConsClass &) noexcept (false); };
+struct DeletedCopyAssignClass { DeletedCopyAssignClass & operator= (const DeletedCopyAssignClass &) = delete; };
+struct DeletedMoveAssignClass { DeletedMoveAssignClass &operator= (DeletedMoveAssignClass &&) = delete; };
+struct PODType { int i; int j; };
+union UnionType { };
+
+namespace N1
+{
+  struct Empty {};
+  enum class SE { e1 };
+  struct Abstract { virtual ~Abstract () = 0; };
+  struct Any { template <class T> Any (T &&) {} };
+  struct nAny { template <class... T> nAny (T &&...) {} };
+  struct DelCopy { DelCopy (const DelCopy &) = delete; };
+  struct Nontrivial {
+    Nontrivial ();
+    Nontrivial (const Nontrivial &);
+    Nontrivial &operator= (const Nontrivial &);
+    ~Nontrivial ();
+  };
+  union NontrivialUnion { int i; Nontrivial n; };
+}
+
+namespace funny1 {
+  struct F {};
+  void swap (F &, F &) = delete;
+  void swap (F (&) [5], F (&) [5]);
+  struct F2 { friend void swap (F2 &, F2 &) = delete; };
+  struct F3 { friend void swap (F3 &, F3) {} };
+  struct DummyCmp { template <class T> bool operator () (const T &, const T &) const { return false; } };
+}
+
+namespace funny2 {
+  struct T0 {};
+  void swap (T0, T0);
+  struct T1 {};
+  struct T2 {};
+  void swap (T1, T2);
+  void swap (T2, T1);
+  struct BoolLike {};
+  void swap (BoolLike, bool &);
+  void swap (bool &, BoolLike);
+  struct F0 {};
+  void swap (F0, F0) = delete;
+  struct F1 {};
+  void swap (F0, F1) = delete;
+  void swap (F1, F0) = delete;
+  struct F2 {};
+  struct F3 {};
+  void swap (F2, F3);
+  void swap (F3, F2) = delete;
+  struct F4 { friend void swap (F4, F4) = delete; };
+}
+
+namespace funny3 {
+  struct F {};
+  void swap (F &, F &) = delete;
+  void swap (F (&) [5], F (&) [5]) noexcept;
+  void swap (F (&) [6], F (&) [6]);
+  struct A {};
+  void swap (A &, A &) noexcept (false);
+}
+namespace std {
+  template <>
+  void swap <funny3::A> (funny3::A &, funny3::A &) noexcept {}
+  template <>
+  void swap <funny3::A> (funny3::A (&) [3], funny3::A (&) [3]) noexcept (false) {}
+}
+namespace ns1 {
+  struct SwapThrow {};
+  void swap (SwapThrow &, SwapThrow &);
+  void swap (SwapThrow (&) [3], SwapThrow (&) [3]) noexcept;
+}
+namespace ns2 {
+  struct SwapThrow {
+    SwapThrow () noexcept = default;
+    SwapThrow (const SwapThrow &) noexcept (false);
+    SwapThrow &operator = (const SwapThrow &) noexcept (false);
+  };
+}
+namespace ns3 {
+  struct SwapNoThrow {
+    SwapNoThrow () noexcept = default;
+    SwapNoThrow (const SwapNoThrow &) noexcept (false);
+    SwapNoThrow &operator = (const SwapNoThrow &) noexcept (false);
+  };
+  void swap (SwapNoThrow &, SwapNoThrow &) noexcept;
+}
+namespace ns4 {
+  struct SwapNoThrow {};
+}
+namespace ns5 {
+  struct SwapThrow {
+    SwapThrow () noexcept = default;
+    SwapThrow (SwapThrow &&) noexcept;
+    SwapThrow & operator = (const SwapThrow &) noexcept (false);
+  };
+}
+namespace comps {
+  struct CompareNoThrowCopyable {
+    template <class T>
+    bool operator () (const T &, const T &) const { return false; }
+  };
+  struct CompareNonCopyable {
+    CompareNonCopyable () = default;
+    CompareNonCopyable (const CompareNonCopyable &) = delete;
+    CompareNonCopyable &operator= (const CompareNonCopyable &) noexcept;
+    template <class T>
+    bool operator () (const T &, const T &) const { return false; }
+  };
+  struct CompareThrowCopyable {
+    CompareThrowCopyable () = default;
+    CompareThrowCopyable (const CompareThrowCopyable &) noexcept (false);
+    CompareThrowCopyable &operator = (const CompareThrowCopyable &);
+    template <class T>
+    bool operator () (const T &, const T &) const { return false; }
+  };
+}
+
+namespace funny4 {
+  struct T0 {};
+  void swap (T0, T0) noexcept;
+  struct T1 { friend void swap (T1, T1) noexcept; };
+  struct T2 {};
+  struct T3 {};
+  void swap (T2, T3) noexcept;
+  void swap (T3, T2) noexcept;
+  struct T4 { operator T0 () const noexcept; };
+  struct F0 {};
+  void swap (F0, F0) = delete;
+  struct F1 {};
+  void swap (F1, F1);
+  struct F2 {};
+  void swap (F0, F2) noexcept;
+  void swap (F2, F0);
+  struct F3 { friend void swap (F3, F3) = delete; };
+  struct F4 { friend void swap (F4, F4); };
+  struct F5 { operator T0 () const; };
+  struct BoolLike {};
+  void swap (BoolLike, bool &) noexcept;
+  void swap (bool &, BoolLike) noexcept;
+  struct BoolLikeErr {};
+  void swap (BoolLikeErr, bool &);
+  void swap (bool &, BoolLikeErr) noexcept;
+}
+
+static_assert (is_swappable_type (^^int));
+static_assert (is_swappable_type (^^bool));
+static_assert (is_swappable_type (^^decltype (nullptr)));
+static_assert (is_swappable_type (^^int &));
+static_assert (is_swappable_type (^^int &&));
+static_assert (is_swappable_type (^^int [1]));
+static_assert (is_swappable_type (^^int [1][2]));
+static_assert (is_swappable_type (^^int [1][2][3]));
+static_assert (is_swappable_type (^^int (&) [1]));
+static_assert (is_swappable_type (^^funny1::F [5]));
+static_assert (is_swappable_type (^^funny1::F3));
+static_assert (is_swappable_type (^^funny1::F3 [1]));
+static_assert (is_swappable_type (^^funny1::F3 [1][2]));
+static_assert (is_swappable_type (^^funny1::F3 [1][2][3]));
+static_assert (is_swappable_type (^^ThrowCopyConsClass));
+static_assert (is_swappable_type (^^EnumType));
+static_assert (is_swappable_type (^^PODType));
+static_assert (is_swappable_type (^^UnionType));
+static_assert (is_swappable_type (^^N1::SE));
+static_assert (is_swappable_type (^^N1::Empty));
+static_assert (is_swappable_type (^^void *));
+static_assert (is_swappable_type (^^int const *));
+static_assert (is_swappable_type (^^ClassType *));
+static_assert (is_swappable_type (^^int ClassType::*));
+static_assert (is_swappable_type (^^void (ClassType::*) ()));
+static_assert (is_swappable_type (^^N1::Nontrivial));
+static_assert (is_swappable_type (^^N1::Any));
+static_assert (is_swappable_type (^^N1::nAny));
+static_assert (is_swappable_type (^^std::pair <int, int>));
+static_assert (is_swappable_type (^^std::pair <int, int> [1]));
+static_assert (is_swappable_type (^^std::pair <int, int> [1][2]));
+static_assert (is_swappable_type (^^std::pair <int, int> [1][2][3]));
+static_assert (is_swappable_type (^^std::pair <N1::Nontrivial, N1::Nontrivial>));
+static_assert (is_swappable_type (^^std::tuple <int>));
+static_assert (is_swappable_type (^^std::tuple <int> [1]));
+static_assert (is_swappable_type (^^std::tuple <int> [1][2]));
+static_assert (is_swappable_type (^^std::tuple <int> [1][2][3]));
+static_assert (is_swappable_type (^^std::tuple <>));
+static_assert (is_swappable_type (^^std::tuple <> [1]));
+static_assert (is_swappable_type (^^std::tuple <> [1][2]));
+static_assert (is_swappable_type (^^std::tuple <> [1][2][3]));
+static_assert (is_swappable_type (^^std::tuple <N1::Nontrivial>));
+static_assert (is_swappable_type (^^std::array <int, 1>));
+static_assert (is_swappable_type (^^std::array <int, 1> [1]));
+static_assert (is_swappable_type (^^std::array <int, 1> [1][2]));
+static_assert (is_swappable_type (^^std::array <int, 1> [1][2][3]));
+static_assert (is_swappable_type (^^std::array <N1::Nontrivial, 1>));
+static_assert (is_swappable_type (^^std::array <int, 0>));
+static_assert (is_swappable_type (^^std::array <N1::DelCopy, 0>));
+static_assert (is_swappable_type (^^std::queue <int>));
+static_assert (is_swappable_type (^^std::queue <int> [1]));
+static_assert (is_swappable_type (^^std::queue <int> [1][2]));
+static_assert (is_swappable_type (^^std::queue <int> [1][2][3]));
+static_assert (is_swappable_type (^^std::queue <N1::Nontrivial>));
+//static_assert (is_swappable_type (^^std::priority_queue <int>));
+//static_assert (is_swappable_type (^^std::priority_queue <int> [1]));
+//static_assert (is_swappable_type (^^std::priority_queue <int> [1][2]));
+//static_assert (is_swappable_type (^^std::priority_queue <int> [1][2][3]));
+//static_assert (is_swappable_type (^^std::priority_queue <N1::Nontrivial, std::vector <N1::Nontrivial>, funny1::DummyCmp>));
+static_assert (is_swappable_type (^^std::stack <int>));
+static_assert (is_swappable_type (^^std::stack <int> [1]));
+static_assert (is_swappable_type (^^std::stack <int> [1][2]));
+static_assert (is_swappable_type (^^std::stack <int> [1][2][3]));
+static_assert (is_swappable_type (^^std::stack <N1::Nontrivial>));
+static_assert (!is_swappable_type (^^void));
+static_assert (!is_swappable_type (^^const void));
+static_assert (!is_swappable_type (^^void ()));
+static_assert (!is_swappable_type (^^void () const));
+static_assert (!is_swappable_type (^^void () volatile));
+static_assert (!is_swappable_type (^^void () const volatile));
+static_assert (!is_swappable_type (^^const int));
+static_assert (!is_swappable_type (^^const bool));
+static_assert (!is_swappable_type (^^int []));
+static_assert (!is_swappable_type (^^const int []));
+static_assert (!is_swappable_type (^^int [][1]));
+static_assert (!is_swappable_type (^^const int [1]));
+static_assert (!is_swappable_type (^^const int [1][2]));
+static_assert (!is_swappable_type (^^const int [1][2][3]));
+static_assert (!is_swappable_type (^^N1::DelCopy));
+static_assert (!is_swappable_type (^^N1::Abstract));
+static_assert (!is_swappable_type (^^N1::NontrivialUnion));
+static_assert (!is_swappable_type (^^funny1::F));
+static_assert (!is_swappable_type (^^funny1::F [1]));
+static_assert (!is_swappable_type (^^funny1::F [1][2]));
+static_assert (!is_swappable_type (^^funny1::F [1][2][3]));
+static_assert (!is_swappable_type (^^funny1::F [4]));
+static_assert (!is_swappable_type (^^N1::DelCopy));
+static_assert (!is_swappable_type (^^DeletedCopyAssignClass));
+static_assert (!is_swappable_type (^^DeletedMoveAssignClass));
+static_assert (!is_swappable_type (^^funny1::F2));
+static_assert (!is_swappable_type (^^funny1::F2 [1]));
+static_assert (!is_swappable_type (^^funny1::F2 [1][2]));
+static_assert (!is_swappable_type (^^funny1::F2 [1][2][3]));
+static_assert (!is_swappable_type (^^funny1::F2 [4]));
+static_assert (!is_swappable_type (^^funny1::F2 [5]));
+
+static_assert (is_swappable_with_type (^^int &, ^^int &));
+static_assert (is_swappable_with_type (^^funny2::T0, ^^funny2::T0));
+static_assert (is_swappable_with_type (^^funny2::T0, ^^const funny2::T0));
+static_assert (is_swappable_with_type (^^funny2::T1, ^^funny2::T2));
+static_assert (is_swappable_with_type (^^funny2::T2, ^^funny2::T1));
+static_assert (is_swappable_with_type (^^funny2::BoolLike, ^^bool &));
+static_assert (is_swappable_with_type (^^const funny2::BoolLike, ^^bool &));
+static_assert (!is_swappable_with_type (^^int, ^^int));
+static_assert (!is_swappable_with_type (^^int &, ^^unsigned &));
+static_assert (!is_swappable_with_type (^^const int &, ^^const int &));
+static_assert (!is_swappable_with_type (^^funny2::F0, ^^funny2::F0));
+static_assert (!is_swappable_with_type (^^funny2::F0, ^^const funny2::F0));
+static_assert (!is_swappable_with_type (^^funny2::T0, ^^funny2::T1));
+static_assert (!is_swappable_with_type (^^funny2::F0, ^^funny2::F1));
+static_assert (!is_swappable_with_type (^^funny2::F0, ^^const funny2::F1));
+static_assert (!is_swappable_with_type (^^const funny2::F0, ^^funny2::F1));
+static_assert (!is_swappable_with_type (^^funny2::F2, ^^funny2::F3));
+static_assert (!is_swappable_with_type (^^funny2::F2, ^^const funny2::F3));
+static_assert (!is_swappable_with_type (^^const funny2::F2, ^^funny2::F3));
+static_assert (!is_swappable_with_type (^^funny2::F4, ^^funny2::F4));
+static_assert (!is_swappable_with_type (^^funny2::BoolLike, ^^funny2::BoolLike));
+
+static_assert (is_nothrow_swappable_type (^^int));
+static_assert (is_nothrow_swappable_type (^^bool));
+static_assert (is_nothrow_swappable_type (^^decltype (nullptr)));
+static_assert (is_nothrow_swappable_type (^^int &));
+static_assert (is_nothrow_swappable_type (^^int &&));
+static_assert (is_nothrow_swappable_type (^^int [1]));
+static_assert (is_nothrow_swappable_type (^^int [1][2]));
+static_assert (is_nothrow_swappable_type (^^int [1][2][3]));
+static_assert (is_nothrow_swappable_type (^^funny3::F [5]));
+static_assert (is_nothrow_swappable_type (^^EnumType));
+static_assert (is_nothrow_swappable_type (^^PODType));
+static_assert (is_nothrow_swappable_type (^^UnionType));
+static_assert (is_nothrow_swappable_type (^^N1::SE));
+static_assert (is_nothrow_swappable_type (^^N1::Empty));
+static_assert (is_nothrow_swappable_type (^^void *));
+static_assert (is_nothrow_swappable_type (^^void (*) ()));
+static_assert (is_nothrow_swappable_type (^^int const *));
+static_assert (is_nothrow_swappable_type (^^ClassType *));
+static_assert (is_nothrow_swappable_type (^^int ClassType::*));
+static_assert (is_nothrow_swappable_type (^^void (ClassType::*) ()));
+static_assert (is_nothrow_swappable_type (^^int (ClassType::*) () const volatile));
+static_assert (is_nothrow_swappable_type (^^ns1::SwapThrow [3]));
+static_assert (is_nothrow_swappable_type (^^ns3::SwapNoThrow));
+static_assert (is_nothrow_swappable_type (^^ns3::SwapNoThrow [1]));
+static_assert (is_nothrow_swappable_type (^^ns3::SwapNoThrow [3]));
+static_assert (is_nothrow_swappable_type (^^ns3::SwapNoThrow [2][3][4]));
+static_assert (is_nothrow_swappable_type (^^ns4::SwapNoThrow));
+static_assert (is_nothrow_swappable_type (^^ns4::SwapNoThrow [1]));
+static_assert (is_nothrow_swappable_type (^^ns4::SwapNoThrow [3]));
+static_assert (is_nothrow_swappable_type (^^ns4::SwapNoThrow [2][3][4]));
+static_assert (is_nothrow_swappable_type (^^std::pair <int, int>));
+static_assert (is_nothrow_swappable_type (^^std::pair <int, int> [1]));
+static_assert (is_nothrow_swappable_type (^^std::pair <int, int> [1][2]));
+static_assert (is_nothrow_swappable_type (^^std::tuple <int>));
+static_assert (is_nothrow_swappable_type (^^std::tuple <int> [1]));
+static_assert (is_nothrow_swappable_type (^^std::tuple <int> [1][2]));
+static_assert (is_nothrow_swappable_type (^^std::tuple <>));
+static_assert (is_nothrow_swappable_type (^^std::tuple <> [1]));
+static_assert (is_nothrow_swappable_type (^^std::tuple <> [1][2]));
+static_assert (is_nothrow_swappable_type (^^std::array <int, 1>));
+static_assert (is_nothrow_swappable_type (^^std::array <int, 0>));
+static_assert (is_nothrow_swappable_type (^^std::array <N1::DelCopy, 0>));
+static_assert (is_nothrow_swappable_type (^^std::array <ns1::SwapThrow, 0>));
+static_assert (is_nothrow_swappable_type (^^std::queue <int>));
+//static_assert (is_nothrow_swappable_type (^^std::priority_queue <int>));
+static_assert (is_nothrow_swappable_type (^^std::stack <int>));
+//static_assert (is_nothrow_swappable_type (^^std::priority_queue <int, std::vector <int>, comps::CompareNoThrowCopyable>));
+static_assert (!is_nothrow_swappable_type (^^void));
+static_assert (!is_nothrow_swappable_type (^^const void));
+static_assert (!is_nothrow_swappable_type (^^void ()));
+static_assert (!is_nothrow_swappable_type (^^void () const));
+static_assert (!is_nothrow_swappable_type (^^void () volatile));
+static_assert (!is_nothrow_swappable_type (^^void () const volatile));
+static_assert (!is_nothrow_swappable_type (^^const int));
+static_assert (!is_nothrow_swappable_type (^^const bool));
+static_assert (!is_nothrow_swappable_type (^^const int [1]));
+static_assert (!is_nothrow_swappable_type (^^const int [1][2]));
+static_assert (!is_nothrow_swappable_type (^^const int [1][2][3]));
+static_assert (!is_nothrow_swappable_type (^^int []));
+static_assert (!is_nothrow_swappable_type (^^const int []));
+static_assert (!is_nothrow_swappable_type (^^int [][1]));
+static_assert (!is_nothrow_swappable_type (^^const funny3::F [5]));
+static_assert (!is_nothrow_swappable_type (^^N1::Abstract));
+static_assert (!is_nothrow_swappable_type (^^N1::DelCopy));
+static_assert (!is_nothrow_swappable_type (^^funny3::F));
+static_assert (!is_nothrow_swappable_type (^^funny3::F [1]));
+static_assert (!is_nothrow_swappable_type (^^funny3::F [1][2]));
+static_assert (!is_nothrow_swappable_type (^^funny3::F [1][2][3]));
+static_assert (!is_nothrow_swappable_type (^^funny3::F [6]));
+static_assert (!is_nothrow_swappable_type (^^funny3::A));
+static_assert (!is_nothrow_swappable_type (^^funny3::A [3]));
+static_assert (!is_nothrow_swappable_type (^^ns1::SwapThrow));
+static_assert (!is_nothrow_swappable_type (^^ns1::SwapThrow [1]));
+static_assert (!is_nothrow_swappable_type (^^ns1::SwapThrow [3][2]));
+static_assert (!is_nothrow_swappable_type (^^ns1::SwapThrow [2][3][4]));
+static_assert (!is_nothrow_swappable_type (^^ns2::SwapThrow));
+static_assert (!is_nothrow_swappable_type (^^ns2::SwapThrow [1]));
+static_assert (!is_nothrow_swappable_type (^^ns2::SwapThrow [2][3][4]));
+static_assert (!is_nothrow_swappable_type (^^ns5::SwapThrow));
+static_assert (!is_nothrow_swappable_type (^^ns5::SwapThrow [1]));
+static_assert (!is_nothrow_swappable_type (^^ns5::SwapThrow [2][3][4]));
+static_assert (!is_nothrow_swappable_type (^^ThrowCopyConsClass));
+static_assert (!is_nothrow_swappable_type (^^std::pair <ThrowCopyConsClass, ThrowCopyConsClass>));
+static_assert (!is_nothrow_swappable_type (^^std::tuple <ThrowCopyConsClass>));
+static_assert (!is_nothrow_swappable_type (^^std::array <ThrowCopyConsClass, 1>));
+static_assert (is_nothrow_swappable_type (^^std::queue <ThrowCopyConsClass>));
+static_assert (is_nothrow_swappable_type (^^std::priority_queue <ThrowCopyConsClass, std::vector <ThrowCopyConsClass>, comps::CompareNoThrowCopyable>));
+static_assert (is_nothrow_swappable_type (^^std::stack <ThrowCopyConsClass>));
+static_assert (!is_nothrow_swappable_type (^^std::priority_queue <int, std::vector <int>, comps::CompareNonCopyable>));
+static_assert (!is_nothrow_swappable_type (^^std::priority_queue <int, std::vector <int>, comps::CompareThrowCopyable>));
+
+static_assert (is_nothrow_swappable_with_type (^^int &, ^^int &));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T0, ^^funny4::T0));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T0, ^^const funny4::T0));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T1, ^^funny4::T1));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T1, ^^const funny4::T1));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T2, ^^funny4::T3));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T3, ^^funny4::T2));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T0, ^^funny4::T4));
+static_assert (is_nothrow_swappable_with_type (^^funny4::T4, ^^funny4::T0));
+static_assert (is_nothrow_swappable_with_type (^^funny4::BoolLike, ^^bool &));
+static_assert (is_nothrow_swappable_with_type (^^const funny4::BoolLike, ^^bool &));
+static_assert (!is_nothrow_swappable_with_type (^^const int &, ^^const int &));
+static_assert (!is_nothrow_swappable_with_type (^^int &, ^^unsigned &));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F0, ^^funny4::F0));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F0, ^^const funny4::F0));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F1, ^^funny4::F1));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F1, ^^const funny4::F1));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F0, ^^funny4::F2));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F2, ^^funny4::F0));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F3, ^^funny4::F3));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F3, ^^const funny4::F3));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F4, ^^funny4::F4));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F4, ^^const funny4::F4));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::T0, ^^funny4::F5));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::F5, ^^funny4::T0));
+static_assert (!is_nothrow_swappable_with_type (^^funny4::BoolLikeErr, ^^bool &));
+static_assert (!is_nothrow_swappable_with_type (^^const funny4::BoolLikeErr, ^^bool &));
+
+static_assert (unwrap_reference (^^int) == ^^int);
+static_assert (unwrap_reference (^^const int) == ^^const int);
+static_assert (unwrap_reference (^^const int &) == ^^const int &);
+static_assert (unwrap_reference (^^const int *) == ^^const int *);
+static_assert (unwrap_reference (^^const int *&) == ^^const int *&);
+static_assert (unwrap_reference (^^std::reference_wrapper <int>) == ^^int &);
+static_assert (unwrap_reference (^^std::reference_wrapper <const int>) == ^^const int &);
+static_assert (unwrap_reference (^^std::reference_wrapper <long>) == ^^long &);
+static_assert (unwrap_reference (^^const std::reference_wrapper <int>) == ^^const std::reference_wrapper <int>);
+static_assert (unwrap_reference (^^volatile std::reference_wrapper <int>) == ^^volatile std::reference_wrapper <int>);
+static_assert (unwrap_reference (^^const volatile std::reference_wrapper <int>) == ^^const volatile std::reference_wrapper <int>);
+static_assert (unwrap_reference (^^std::reference_wrapper <int> &) == ^^std::reference_wrapper <int> &);
+static_assert (unwrap_reference (^^std::reference_wrapper <int> &&) == ^^std::reference_wrapper <int> &&);
+static_assert (unwrap_reference (^^const std::reference_wrapper <int> &) == ^^const std::reference_wrapper <int> &);
+
+static_assert (unwrap_ref_decay (^^int) == decay (^^int));
+static_assert (unwrap_ref_decay (^^const int) == decay (^^const int));
+static_assert (unwrap_ref_decay (^^const int &) == decay (^^const int &));
+static_assert (unwrap_ref_decay (^^const int *) == decay (^^const int *));
+static_assert (unwrap_ref_decay (^^const int *&) == decay (^^const int *&));
+static_assert (unwrap_ref_decay (^^std::reference_wrapper <int>) == ^^int &);
+static_assert (unwrap_ref_decay (^^std::reference_wrapper <int> &) == ^^int &);
+static_assert (unwrap_ref_decay (^^const std::reference_wrapper <int>) == ^^int &);
+static_assert (unwrap_ref_decay (^^const std::reference_wrapper <int> &) == ^^int &);
+static_assert (unwrap_ref_decay (^^std::reference_wrapper <const int>) == ^^const int &);
+static_assert (unwrap_ref_decay (^^std::reference_wrapper <const int> &) == ^^const int &);
+static_assert (unwrap_ref_decay (^^std::reference_wrapper <long>) == ^^long &);
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait2.C b/gcc/testsuite/g++.dg/reflect/type_trait2.C
new file mode 100644 (file)
index 0000000..3bf87ad
--- /dev/null
@@ -0,0 +1,92 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], const-volatile
+// modifications.
+
+#include <meta>
+using namespace std::meta;
+
+struct C { };
+
+static_assert (remove_const (^^const int) == ^^int);
+static_assert (remove_const (^^volatile int) == ^^volatile int);
+static_assert (remove_const (^^const volatile int) == ^^volatile int);
+static_assert (remove_const (^^const volatile int *) == ^^const volatile int *);
+static_assert (remove_const (^^const volatile int &) == ^^const volatile int &);
+static_assert (remove_const (^^const volatile int []) == ^^volatile int []);
+static_assert (remove_const (^^volatile int *const) == ^^volatile int *);
+static_assert (remove_const (^^const volatile C) == ^^volatile C);
+static_assert (remove_const (^^void (C::* const volatile)(int) const) == ^^void (C::* volatile)(int) const);
+static_assert (remove_const (^^int (int)) == ^^int (int));
+using T1 = int;
+static_assert (remove_const (^^T1) == dealias (^^T1));
+
+static_assert (remove_volatile (^^const int) == ^^const int);
+static_assert (remove_volatile (^^volatile int) == ^^int);
+static_assert (remove_volatile (^^const volatile int) == ^^const int);
+static_assert (remove_volatile (^^const volatile int *) == ^^const volatile int *);
+static_assert (remove_volatile (^^const volatile int &) == ^^const volatile int &);
+static_assert (remove_volatile (^^const volatile int []) == ^^const int []);
+static_assert (remove_volatile (^^volatile int *const) == ^^volatile int *const);
+static_assert (remove_volatile (^^volatile int *volatile) == ^^volatile int *);
+static_assert (remove_volatile (^^const volatile C) == ^^const C);
+static_assert (remove_volatile (^^void (C::* const volatile)(int) const) == ^^void (C::* const)(int) const);
+static_assert (remove_volatile (^^int (int)) == ^^int (int));
+static_assert (remove_volatile (^^T1) == dealias (^^T1));
+
+static_assert (remove_cv (^^const int) == ^^int);
+static_assert (remove_cv (^^volatile int) == ^^int);
+static_assert (remove_cv (^^const volatile int) == ^^int);
+static_assert (remove_cv (^^const volatile int *) == ^^const volatile int *);
+static_assert (remove_cv (^^const volatile int &) == ^^const volatile int &);
+static_assert (remove_cv (^^const volatile int []) == ^^int []);
+static_assert (remove_cv (^^volatile int *const) == ^^volatile int *);
+static_assert (remove_cv (^^const volatile C) == ^^C);
+static_assert (remove_cv (^^void (C::* const volatile)(int) const) == ^^void (C::*)(int) const);
+static_assert (remove_cv (^^int (int)) == ^^int (int));
+static_assert (remove_cv (^^T1) == dealias (^^T1));
+
+static_assert (add_const (^^int) == ^^const int);
+static_assert (add_const (^^const int) == ^^const int);
+static_assert (add_const (^^volatile int) == ^^const volatile int);
+static_assert (add_const (^^const volatile int) == ^^const volatile int);
+static_assert (add_const (^^const volatile int *) == ^^const volatile int *const);
+static_assert (add_const (^^int []) == ^^const int[]);
+static_assert (add_const (^^int *) == ^^int *const);
+static_assert (add_const (^^C) == ^^const C);
+static_assert (add_const (^^void (C::*)(int) const) == ^^void (C::* const)(int) const);
+static_assert (add_const (^^int (int)) == ^^int (int));
+static_assert (add_const (^^int &) == ^^int &);
+static_assert (add_const (^^const int &&) == ^^const int &&);
+using T2 = const int;
+static_assert (add_const (^^T2) == dealias (^^T2));
+
+static_assert (add_volatile (^^int) == ^^volatile int);
+static_assert (add_volatile (^^const int) == ^^const volatile int);
+static_assert (add_volatile (^^volatile int) == ^^volatile int);
+static_assert (add_volatile (^^const volatile int) == ^^const volatile int);
+static_assert (add_volatile (^^const volatile int *) == ^^const volatile int *volatile);
+static_assert (add_volatile (^^int []) == ^^volatile int[]);
+static_assert (add_volatile (^^int *) == ^^int *volatile);
+static_assert (add_volatile (^^C) == ^^volatile C);
+static_assert (add_volatile (^^void (C::*)(int) const) == ^^void (C::* volatile)(int) const);
+static_assert (add_volatile (^^int (int)) == ^^int (int));
+static_assert (add_volatile (^^int &) == ^^int &);
+static_assert (add_volatile (^^const int &&) == ^^const int &&);
+using T3 = volatile int;
+static_assert (add_volatile (^^T3) == dealias (^^T3));
+
+static_assert (add_cv (^^int) == ^^const volatile int);
+static_assert (add_cv (^^const int) == ^^const volatile int);
+static_assert (add_cv (^^volatile int) == ^^const volatile int);
+static_assert (add_cv (^^const volatile int) == ^^const volatile int);
+static_assert (add_cv (^^const volatile int *) == ^^const volatile int *const volatile);
+static_assert (add_cv (^^int []) == ^^const volatile int[]);
+static_assert (add_cv (^^int *) == ^^int *const volatile);
+static_assert (add_cv (^^C) == ^^const volatile C);
+static_assert (add_cv (^^void (C::*)(int) const) == ^^void (C::* const volatile)(int) const);
+static_assert (add_cv (^^int (int)) == ^^int (int));
+static_assert (add_cv (^^int &) == ^^int &);
+static_assert (add_cv (^^const int &&) == ^^const int &&);
+using T4 = const volatile int;
+static_assert (add_cv (^^T4) == dealias (^^T4));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait3.C b/gcc/testsuite/g++.dg/reflect/type_trait3.C
new file mode 100644 (file)
index 0000000..eca95ad
--- /dev/null
@@ -0,0 +1,218 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], reference, sign,
+// array and pointer modifications.
+
+#include <meta>
+using namespace std::meta;
+
+struct C { };
+enum E1 : int { E10, E11 };
+enum E2 : unsigned char { E20, E21 };
+enum E3 : short int { E30, E31 };
+enum E4 : long long { E40, E41 };
+
+static_assert (remove_reference (^^int) == ^^int);
+static_assert (remove_reference (^^const int *) == ^^const int *);
+static_assert (remove_reference (^^unsigned long &) == ^^unsigned long);
+static_assert (remove_reference (^^const short &) == ^^const short);
+static_assert (remove_reference (^^long long &&) == ^^long long);
+static_assert (remove_reference (^^volatile char &&) == ^^volatile char);
+static_assert (remove_reference (^^int *&) == ^^int *);
+static_assert (remove_reference (^^C &) == ^^C);
+static_assert (remove_reference (^^C &&) == ^^C);
+static_assert (remove_reference (^^C) == ^^C);
+static_assert (remove_reference (^^int (&) (int)) == ^^int (int));
+static_assert (remove_reference (^^int (&&) (int)) == ^^int (int));
+static_assert (remove_reference (^^int (int)) == ^^int (int));
+using T1 = int;
+static_assert (remove_reference (^^T1) == dealias (^^T1));
+
+static_assert (add_lvalue_reference (^^int) == ^^int &);
+static_assert (add_lvalue_reference (^^int &) == ^^int &);
+static_assert (add_lvalue_reference (^^const int) == ^^const int &);
+static_assert (add_lvalue_reference (^^int *) == ^^int *&);
+static_assert (add_lvalue_reference (^^C &) == ^^C &);
+static_assert (add_lvalue_reference (^^C) == ^^C &);
+static_assert (add_lvalue_reference (^^int (int)) == ^^int (&) (int));
+static_assert (add_lvalue_reference (^^int &&) == ^^int &);
+static_assert (add_lvalue_reference (^^C &&) == ^^C &);
+static_assert (add_lvalue_reference (^^void) == ^^void);
+static_assert (add_lvalue_reference (^^const void) == ^^const void);
+static_assert (add_lvalue_reference (^^bool (int) const) == ^^bool (int) const);
+static_assert (add_lvalue_reference (^^bool (int) &) == ^^bool (int) &);
+static_assert (add_lvalue_reference (^^bool (int) const &&) == ^^bool (int) const &&);
+static_assert (add_lvalue_reference (^^bool (int)) == ^^bool (&) (int));
+using T2 = int &;
+static_assert (add_lvalue_reference (^^T2) == dealias (^^T2));
+
+static_assert (add_rvalue_reference (^^int) == ^^int &&);
+static_assert (add_rvalue_reference (^^int &&) == ^^int &&);
+static_assert (add_rvalue_reference (^^int &) == ^^int &);
+static_assert (add_rvalue_reference (^^const int) == ^^const int &&);
+static_assert (add_rvalue_reference (^^int *) == ^^int *&&);
+static_assert (add_rvalue_reference (^^C &&) == ^^C &&);
+static_assert (add_rvalue_reference (^^C) == ^^C &&);
+static_assert (add_rvalue_reference (^^int (int)) == ^^int (&&) (int));
+static_assert (add_rvalue_reference (^^void) == ^^void);
+static_assert (add_rvalue_reference (^^const void) == ^^const void);
+static_assert (add_rvalue_reference (^^bool (int) const) == ^^bool (int) const);
+static_assert (add_rvalue_reference (^^bool (int) &) == ^^bool (int) &);
+static_assert (add_rvalue_reference (^^bool (int) const &&) == ^^bool (int) const &&);
+static_assert (add_rvalue_reference (^^bool (int)) == ^^bool (&&) (int));
+using T3 = int &&;
+static_assert (add_rvalue_reference (^^T3) == dealias (^^T3));
+
+static_assert (make_signed (^^const char) == ^^const signed char);
+static_assert (make_signed (^^volatile signed char) == ^^volatile signed char);
+static_assert (make_signed (^^unsigned char) == ^^signed char);
+static_assert (make_signed (^^const signed short) == ^^const short);
+static_assert (make_signed (^^volatile unsigned short) == ^^volatile signed short);
+static_assert (make_signed (^^int) == ^^signed int);
+static_assert (make_signed (^^const unsigned int) == ^^const int);
+static_assert (make_signed (^^volatile long) == ^^volatile signed long);
+static_assert (make_signed (^^unsigned long) == ^^long);
+static_assert (make_signed (^^const signed long long) == ^^const long long);
+static_assert (make_signed (^^volatile long long unsigned) == ^^volatile long long);
+#if __SIZEOF_SHORT__ > 1 && __SIZEOF_SHORT__ < __SIZEOF_INT__ \
+    && __SIZEOF_INT__ < __SIZEOF_LONG_LONG__
+static_assert (make_signed (^^const E1) == ^^const int);
+static_assert (make_signed (^^volatile E2) == ^^volatile signed char);
+static_assert (make_signed (^^E3) == ^^short);
+#if __SIZEOF_LONG__ < __SIZEOF_LONG_LONG__
+static_assert (make_signed (^^const volatile E4) == ^^const volatile long long);
+#else
+static_assert (make_signed (^^const volatile E4) == ^^const volatile long);
+#endif
+static_assert (make_signed (^^volatile char8_t) == ^^volatile signed char);
+static_assert (sizeof (char16_t) != sizeof (short) || make_signed (^^char16_t) == ^^signed short);
+static_assert (sizeof (char32_t) != sizeof (int) || make_signed (^^const volatile char32_t) == ^^const volatile int);
+static_assert (sizeof (wchar_t) != sizeof (short) || make_signed (^^wchar_t) == ^^short);
+static_assert (sizeof (wchar_t) != sizeof (int) || make_signed (^^wchar_t) == ^^signed int);
+#endif
+static_assert (make_signed (^^T1) == ^^int);
+
+static_assert (make_unsigned (^^const char) == ^^const unsigned char);
+static_assert (make_unsigned (^^volatile signed char) == ^^volatile unsigned char);
+static_assert (make_unsigned (^^unsigned char) == ^^unsigned char);
+static_assert (make_unsigned (^^const signed short) == ^^const unsigned short);
+static_assert (make_unsigned (^^volatile unsigned short) == ^^volatile unsigned short);
+static_assert (make_unsigned (^^int) == ^^unsigned int);
+static_assert (make_unsigned (^^const unsigned int) == ^^const unsigned);
+static_assert (make_unsigned (^^volatile long) == ^^volatile unsigned long);
+static_assert (make_unsigned (^^unsigned long) == ^^unsigned long);
+static_assert (make_unsigned (^^const signed long long) == ^^const unsigned long long);
+static_assert (make_unsigned (^^volatile long long unsigned) == ^^volatile unsigned long long);
+#if __SIZEOF_SHORT__ > 1 && __SIZEOF_SHORT__ < __SIZEOF_INT__ \
+    && __SIZEOF_INT__ < __SIZEOF_LONG_LONG__
+static_assert (make_unsigned (^^const E1) == ^^const unsigned int);
+static_assert (make_unsigned (^^volatile E2) == ^^volatile unsigned char);
+static_assert (make_unsigned (^^E3) == ^^unsigned short);
+#if __SIZEOF_LONG__ < __SIZEOF_LONG_LONG__
+static_assert (make_unsigned (^^const volatile E4) == ^^const volatile unsigned long long);
+#else
+static_assert (make_unsigned (^^const volatile E4) == ^^const volatile long unsigned);
+#endif
+static_assert (make_unsigned (^^volatile char8_t) == ^^volatile unsigned char);
+static_assert (sizeof (char16_t) != sizeof (short) || make_unsigned (^^char16_t) == ^^unsigned short);
+static_assert (sizeof (char32_t) != sizeof (int) || make_unsigned (^^const volatile char32_t) == ^^const volatile unsigned);
+static_assert (sizeof (wchar_t) != sizeof (short) || make_unsigned (^^wchar_t) == ^^unsigned short);
+static_assert (sizeof (wchar_t) != sizeof (int) || make_unsigned (^^wchar_t) == ^^unsigned int);
+#endif
+using T4 = unsigned;
+static_assert (make_unsigned (^^T4) == ^^unsigned);
+
+static_assert (remove_extent (^^int) == ^^int);
+static_assert (remove_extent (^^int[2]) == ^^int);
+static_assert (remove_extent (^^int[2][3]) == ^^int[3]);
+static_assert (remove_extent (^^int[][3]) == ^^int[3]);
+static_assert (remove_extent (^^const int[2]) == ^^const int);
+static_assert (remove_extent (^^C) == ^^C);
+static_assert (remove_extent (^^C[2]) == ^^C);
+static_assert (remove_extent (^^C[2][3]) == ^^C[3]);
+static_assert (remove_extent (^^C[][3]) == ^^C[3]);
+static_assert (remove_extent (^^const C[2]) == ^^const C);
+static_assert (remove_extent (^^T1) == ^^int);
+
+static_assert (remove_all_extents (^^int) == ^^int);
+static_assert (remove_all_extents (^^int[2]) == ^^int);
+static_assert (remove_all_extents (^^int[2][3]) == ^^int);
+static_assert (remove_all_extents (^^int[][3]) == ^^int);
+static_assert (remove_all_extents (^^const int[2][3]) == ^^const int);
+static_assert (remove_all_extents (^^C) == ^^C);
+static_assert (remove_all_extents (^^C[2]) == ^^C);
+static_assert (remove_all_extents (^^C[2][3]) == ^^C);
+static_assert (remove_all_extents (^^C[][3]) == ^^C);
+static_assert (remove_all_extents (^^const C[2][3]) == ^^const C);
+static_assert (remove_all_extents (^^T1) == ^^int);
+
+static_assert (remove_pointer (^^int *) == ^^int);
+static_assert (remove_pointer (^^int) == ^^int);
+static_assert (remove_pointer (^^const int *) == ^^const int);
+static_assert (remove_pointer (^^int **) == ^^int *);
+static_assert (remove_pointer (^^C *) == ^^C);
+static_assert (remove_pointer (^^C) == ^^C);
+static_assert (remove_pointer (^^T1) == ^^int);
+
+static_assert (add_pointer (^^int) == ^^int *);
+static_assert (add_pointer (^^int *) == ^^int **);
+static_assert (add_pointer (^^const int) == ^^const int *);
+static_assert (add_pointer (^^int &) == ^^int *);
+static_assert (add_pointer (^^C *) == ^^C **);
+static_assert (add_pointer (^^C) == ^^C *);
+static_assert (add_pointer (^^void) == ^^void *);
+static_assert (add_pointer (^^const void) == ^^const void *);
+static_assert (add_pointer (^^volatile void) == ^^volatile void *);
+static_assert (add_pointer (^^const volatile void) == ^^const volatile void *);
+
+consteval
+{
+  try
+    {
+      make_signed (^^bool);
+      throw 1;
+    }
+  catch (std::meta::exception &)
+    {
+    }
+  try
+    {
+      make_unsigned (^^bool);
+      throw 1;
+    }
+  catch (std::meta::exception &)
+    {
+    }
+  try
+    {
+      make_signed (^^float);
+      throw 1;
+    }
+  catch (std::meta::exception &)
+    {
+    }
+  try
+    {
+      make_unsigned (^^double);
+      throw 1;
+    }
+  catch (std::meta::exception &)
+    {
+    }
+  try
+    {
+      make_signed (^^C);
+      throw 1;
+    }
+  catch (std::meta::exception &)
+    {
+    }
+  try
+    {
+      make_unsigned (^^C);
+      throw 1;
+    }
+  catch (std::meta::exception &)
+    {
+    }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait4.C b/gcc/testsuite/g++.dg/reflect/type_trait4.C
new file mode 100644 (file)
index 0000000..7d44ab2
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target { c++26 && int128 } } }
+// { dg-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], sign modifications.
+
+#include <meta>
+using namespace std::meta;
+
+static_assert (make_signed (^^const signed __int128) == ^^const __int128);
+static_assert (make_signed (^^volatile __int128 unsigned) == ^^volatile __int128);
+
+static_assert (make_unsigned (^^const volatile signed __int128) == ^^const volatile unsigned __int128);
+static_assert (make_unsigned (^^__int128 unsigned) == ^^unsigned __int128);
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait5.C b/gcc/testsuite/g++.dg/reflect/type_trait5.C
new file mode 100644 (file)
index 0000000..ff02588
--- /dev/null
@@ -0,0 +1,453 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <meta>
+using namespace std::meta;
+
+struct C { };
+
+struct HasTemplateCCtor
+{
+  HasTemplateCCtor (const HasTemplateCCtor &) = default;
+  template <class T>
+  HasTemplateCCtor (T &&);
+};
+                
+struct MoveOnly
+{
+  MoveOnly (MoveOnly &&) = default;
+};
+  
+struct MoveOnly2
+{
+  MoveOnly2 (MoveOnly2 &&) = delete;
+};
+
+class EmptyClassOne
+{ typedef int type; };
+
+class EmptyClassTwo
+{ static int data; };
+
+class EmptyClassThree
+{ int f(); };
+
+class NonEmptyClassOne
+{ int data; };
+
+class NonEmptyClassTwo
+{
+  virtual int f();
+  virtual ~NonEmptyClassTwo();
+};
+
+class ClassType { };
+typedef const ClassType cClassType;
+typedef volatile ClassType vClassType;
+typedef const volatile ClassType cvClassType;
+
+class DerivedType : public ClassType { };
+
+class FinalType final : public DerivedType { };
+
+enum EnumType { e0 };
+
+struct ConvType
+{ operator int () const; };
+
+class AbstractClass
+{
+  virtual void rotate (int) = 0;
+};
+
+class PolymorphicClass
+{
+  virtual void rotate (int);
+};
+
+class DerivedPolymorphic : public PolymorphicClass { };
+
+class VirtualDestructorClass
+{
+  virtual ~VirtualDestructorClass();
+};
+
+union UnionType { };
+
+union IncompleteUnion;
+
+class IncompleteClass;
+
+struct ExplicitClass
+{
+  ExplicitClass (double &);
+  explicit ExplicitClass (int &);
+  ExplicitClass (double &, int &, double &);
+};
+
+struct NoexceptMoveAssignClass
+{
+  NoexceptMoveAssignClass (NoexceptMoveAssignClass &&) = default;
+  NoexceptMoveAssignClass &operator= (NoexceptMoveAssignClass &&) noexcept (true);
+};
+
+struct NType
+{
+  int i;
+  int j;
+  virtual ~NType ();
+};
+
+struct TType
+{
+  int i;
+private:
+  int j;
+};
+
+struct SLType
+{
+  int i;
+  int j;
+  ~SLType ();
+};
+
+struct PODType
+{
+  int i;
+  int j;
+};
+
+struct CopyConsOnlyType
+{
+  CopyConsOnlyType (int) { }
+  CopyConsOnlyType (CopyConsOnlyType &&) = delete;
+  CopyConsOnlyType (const CopyConsOnlyType &) = default;
+  CopyConsOnlyType &operator= (const CopyConsOnlyType &) = delete;
+  CopyConsOnlyType &operator= (CopyConsOnlyType &&) = delete;
+};
+
+struct MoveConsOnlyType
+{
+  MoveConsOnlyType (int) { }
+  MoveConsOnlyType (const MoveConsOnlyType &) = delete;
+  MoveConsOnlyType (MoveConsOnlyType &&) = default;
+  MoveConsOnlyType& operator= (const MoveConsOnlyType &) = delete;
+  MoveConsOnlyType& operator= (MoveConsOnlyType &&) = delete;
+};
+
+struct Incomplete_struct;
+
+namespace construct
+{
+  struct Empty {};
+
+  struct B { int i; B () {} };
+
+  union U { int i; Empty b; };
+
+  struct Abstract
+  {
+    virtual ~Abstract () = 0;
+  };
+
+  struct Any
+  {
+    template <class T>
+    Any (T &&) {}
+  };
+
+  struct DelDef
+  {
+    DelDef () = delete;
+  };
+
+  struct DelCopy
+  {
+    DelCopy (const DelCopy &) = delete;
+  };
+
+  struct DelDtor
+  {
+    DelDtor () = default;
+    DelDtor (const DelDtor &) = default;
+    DelDtor (DelDtor &&) = default;
+    DelDtor (int);
+    DelDtor (int, B, U);
+    ~DelDtor () = delete;
+  };
+
+  struct Ellipsis
+  {
+    Ellipsis (...) {}
+  };
+
+  struct DelEllipsis
+  {
+    DelEllipsis (...) = delete;
+  };
+
+  struct Nontrivial
+  {
+    Nontrivial ();
+    Nontrivial (const Nontrivial &);
+    Nontrivial &operator= (const Nontrivial &);
+    ~Nontrivial ();
+  };
+
+  struct UnusualCopy
+  {
+    UnusualCopy (UnusualCopy &);
+  };
+}
+
+namespace N
+{
+  void foo ();
+}
+
+int v = 1;
+struct S1 { decltype (^^long) a; };
+union U2 { int a; decltype (^^N::foo) b; };
+struct S3 { const decltype (^^N) *c; };
+struct S4 : public S3 {};
+struct S5 { int a; long *b; };
+
+static_assert (is_const_type (^^const int));
+static_assert (is_const_type (^^const volatile int));
+static_assert (is_const_type (^^cClassType));
+static_assert (is_const_type (^^cvClassType));
+static_assert (!is_const_type (^^int));
+static_assert (!is_const_type (^^volatile int));
+static_assert (!is_const_type (^^ClassType));
+static_assert (!is_const_type (^^vClassType));
+
+static_assert (is_volatile_type (^^volatile int));
+static_assert (is_volatile_type (^^const volatile int));
+static_assert (is_volatile_type (^^vClassType));
+static_assert (is_volatile_type (^^cvClassType));
+static_assert (!is_volatile_type (^^int));
+static_assert (!is_volatile_type (^^const int));
+static_assert (!is_volatile_type (^^ClassType));
+static_assert (!is_volatile_type (^^cClassType));
+
+static_assert (is_trivially_copyable_type (^^int));
+static_assert (is_trivially_copyable_type (^^volatile int));
+static_assert (is_trivially_copyable_type (^^TType));
+static_assert (is_trivially_copyable_type (^^PODType));
+static_assert (!is_trivially_copyable_type (^^NType));
+static_assert (!is_trivially_copyable_type (^^SLType));
+static_assert (is_trivially_copyable_type (^^construct::DelDef));
+static_assert (!is_trivially_copyable_type (^^construct::Abstract));
+static_assert (is_trivially_copyable_type (^^construct::Ellipsis));
+static_assert (is_trivially_copyable_type (^^construct::DelEllipsis));
+static_assert (is_trivially_copyable_type (^^construct::Any));
+static_assert (is_trivially_copyable_type (^^construct::DelCopy));
+static_assert (is_trivially_copyable_type (^^construct::DelDtor));
+static_assert (!is_trivially_copyable_type (^^construct::Nontrivial));
+static_assert (!is_trivially_copyable_type (^^construct::UnusualCopy));
+static_assert (is_trivially_copyable_type (^^CopyConsOnlyType));
+static_assert (is_trivially_copyable_type (^^MoveConsOnlyType));
+static_assert (is_trivially_copyable_type (^^HasTemplateCCtor));
+static_assert (is_trivially_copyable_type (^^MoveOnly));
+static_assert (is_trivially_copyable_type (^^MoveOnly2));
+static_assert (is_trivially_copyable_type (^^volatile int));
+static_assert (is_trivially_copyable_type (^^TType));
+static_assert (is_trivially_copyable_type (^^PODType));
+static_assert (!is_trivially_copyable_type (^^NType));
+static_assert (!is_trivially_copyable_type (^^SLType));
+static_assert (is_trivially_copyable_type (^^construct::DelDef));
+static_assert (!is_trivially_copyable_type (^^construct::Abstract));
+static_assert (is_trivially_copyable_type (^^construct::Ellipsis));
+static_assert (is_trivially_copyable_type (^^construct::DelEllipsis));
+static_assert (is_trivially_copyable_type (^^construct::Any));
+static_assert (is_trivially_copyable_type (^^construct::DelCopy));
+static_assert (is_trivially_copyable_type (^^construct::DelDtor));
+static_assert (!is_trivially_copyable_type (^^construct::Nontrivial));
+static_assert (!is_trivially_copyable_type (^^construct::UnusualCopy));
+static_assert (is_trivially_copyable_type (^^CopyConsOnlyType));
+static_assert (is_trivially_copyable_type (^^MoveConsOnlyType));
+static_assert (is_trivially_copyable_type (^^HasTemplateCCtor));
+static_assert (is_trivially_copyable_type (^^MoveOnly));
+static_assert (is_trivially_copyable_type (^^MoveOnly2));
+
+static_assert (is_standard_layout_type (^^SLType));
+static_assert (is_standard_layout_type (^^PODType));
+static_assert (!is_standard_layout_type (^^NType));
+static_assert (!is_standard_layout_type (^^TType));
+
+static_assert (is_empty_type (^^ClassType));
+static_assert (is_empty_type (^^EmptyClassOne));
+static_assert (is_empty_type (^^EmptyClassTwo));
+static_assert (is_empty_type (^^EmptyClassThree));
+static_assert (!is_empty_type (^^void));
+static_assert (!is_empty_type (^^float));
+static_assert (!is_empty_type (^^int[4]));
+static_assert (!is_empty_type (^^int *));
+static_assert (!is_empty_type (^^int &));
+static_assert (!is_empty_type (^^int (ClassType::*)));
+static_assert (!is_empty_type (^^EnumType));
+static_assert (!is_empty_type (^^int (int)));
+static_assert (!is_empty_type (^^AbstractClass));
+static_assert (!is_empty_type (^^NonEmptyClassOne));
+static_assert (!is_empty_type (^^NonEmptyClassTwo));
+
+static_assert (is_polymorphic_type (^^PolymorphicClass));
+static_assert (is_polymorphic_type (^^DerivedPolymorphic));
+static_assert (is_polymorphic_type (^^AbstractClass));
+static_assert (is_polymorphic_type (^^VirtualDestructorClass));
+static_assert (!is_polymorphic_type (^^void));
+static_assert (!is_polymorphic_type (^^int (int)));
+static_assert (!is_polymorphic_type (^^int &));
+static_assert (!is_polymorphic_type (^^EnumType));
+static_assert (!is_polymorphic_type (^^ClassType));
+static_assert (!is_polymorphic_type (^^DerivedType));
+
+static_assert (is_abstract_type (^^AbstractClass));
+static_assert (!is_abstract_type (^^void));
+static_assert (!is_abstract_type (^^int (int)));
+static_assert (!is_abstract_type (^^int &));
+static_assert (!is_abstract_type (^^ClassType));
+
+static_assert (is_final_type (^^FinalType));
+static_assert (!is_final_type (^^ClassType));
+static_assert (!is_final_type (^^DerivedType));
+
+static_assert (is_aggregate_type (^^ClassType));
+static_assert (is_aggregate_type (^^UnionType));
+static_assert (is_aggregate_type (^^SLType));
+static_assert (is_aggregate_type (^^unsigned[3]));
+static_assert (is_aggregate_type (^^unsigned[3][2]));
+static_assert (is_aggregate_type (^^unsigned[]));
+static_assert (is_aggregate_type (^^unsigned[][2]));
+static_assert (is_aggregate_type (^^EnumType[3]));
+static_assert (is_aggregate_type (^^EnumType[3][2]));
+static_assert (is_aggregate_type (^^EnumType[]));
+static_assert (is_aggregate_type (^^EnumType[][2]));
+static_assert (!is_aggregate_type (^^AbstractClass));
+static_assert (!is_aggregate_type (^^PolymorphicClass));
+static_assert (!is_aggregate_type (^^ExplicitClass));
+static_assert (!is_aggregate_type (^^char));
+static_assert (!is_aggregate_type (^^unsigned char));
+static_assert (!is_aggregate_type (^^signed char));
+static_assert (!is_aggregate_type (^^unsigned));
+static_assert (!is_aggregate_type (^^bool));
+static_assert (!is_aggregate_type (^^float));
+static_assert (!is_aggregate_type (^^double));
+static_assert (!is_aggregate_type (^^EnumType));
+static_assert (!is_aggregate_type (^^void));
+static_assert (!is_aggregate_type (^^NoexceptMoveAssignClass));
+
+static_assert (is_consteval_only_type (^^decltype (^^long)));
+static_assert (is_consteval_only_type (^^const decltype (^^N::foo)));
+static_assert (is_consteval_only_type (^^volatile decltype (^^N)));
+static_assert (is_consteval_only_type (^^const volatile decltype (^^v)));
+static_assert (is_consteval_only_type (^^const S1));
+static_assert (is_consteval_only_type (^^U2));
+static_assert (is_consteval_only_type (^^S3));
+static_assert (is_consteval_only_type (^^S4));
+static_assert (!is_consteval_only_type (^^int));
+static_assert (!is_consteval_only_type (^^S5));
+
+static_assert (!is_signed_type (^^void));
+static_assert (char (-1) < char (0) ? is_signed_type (^^char) : !is_signed_type (^^char));
+static_assert (is_signed_type (^^signed char));
+static_assert (!is_signed_type (^^unsigned char));
+static_assert (wchar_t (-1) < wchar_t (0) ? is_signed_type (^^wchar_t) : !is_signed_type (^^wchar_t));
+static_assert (is_signed_type (^^short));
+static_assert (!is_signed_type (^^unsigned short));
+static_assert (is_signed_type (^^int));
+static_assert (!is_signed_type (^^unsigned int));
+static_assert (is_signed_type (^^long));
+static_assert (!is_signed_type (^^unsigned long));
+static_assert (is_signed_type (^^long long));
+static_assert (!is_signed_type (^^unsigned long long));
+static_assert (is_signed_type (^^float));
+static_assert (is_signed_type (^^double));
+static_assert (is_signed_type (^^long double));
+static_assert (!is_signed_type (^^ClassType));
+
+static_assert (!is_unsigned_type (^^void));
+static_assert (char (-1) < char (0) ? !is_unsigned_type (^^char) : is_unsigned_type (^^char));
+static_assert (!is_unsigned_type (^^signed char));
+static_assert (is_unsigned_type (^^unsigned char));
+static_assert (wchar_t (-1) < wchar_t (0) ? !is_unsigned_type (^^wchar_t) : is_unsigned_type (^^wchar_t));
+static_assert (!is_unsigned_type (^^short));
+static_assert (is_unsigned_type (^^unsigned short));
+static_assert (!is_unsigned_type (^^int));
+static_assert (is_unsigned_type (^^unsigned int));
+static_assert (!is_unsigned_type (^^long));
+static_assert (is_unsigned_type (^^unsigned long));
+static_assert (!is_unsigned_type (^^long long));
+static_assert (is_unsigned_type (^^unsigned long long));
+static_assert (!is_unsigned_type (^^float));
+static_assert (!is_unsigned_type (^^double));
+static_assert (!is_unsigned_type (^^long double));
+static_assert (!is_unsigned_type (^^ClassType));
+
+static_assert (is_bounded_array_type (^^int[2]));
+static_assert (!is_bounded_array_type (^^int[]));
+static_assert (is_bounded_array_type (^^int[2][3]));
+static_assert (!is_bounded_array_type (^^int[][3]));
+static_assert (is_bounded_array_type (^^float *[2]));
+static_assert (!is_bounded_array_type (^^float *[]));
+static_assert (is_bounded_array_type (^^float *[2][3]));
+static_assert (!is_bounded_array_type (^^float *[][3]));
+static_assert (is_bounded_array_type (^^ClassType[2]));
+static_assert (!is_bounded_array_type (^^ClassType[]));
+static_assert (is_bounded_array_type (^^ClassType[2][3]));
+static_assert (!is_bounded_array_type (^^ClassType[][3]));
+static_assert (!is_bounded_array_type (^^int (*)[2]));
+static_assert (!is_bounded_array_type (^^int (*)[]));
+static_assert (!is_bounded_array_type (^^int (&)[2]));
+static_assert (!is_bounded_array_type (^^int (&)[]));
+static_assert (!is_bounded_array_type (^^ClassType));
+static_assert (!is_bounded_array_type (^^void ()));
+
+static_assert (!is_unbounded_array_type (^^int[2]));
+static_assert (is_unbounded_array_type (^^int[]));
+static_assert (!is_unbounded_array_type (^^int[2][3]));
+static_assert (is_unbounded_array_type (^^int[][3]));
+static_assert (!is_unbounded_array_type (^^float *[2]));
+static_assert (is_unbounded_array_type (^^float *[]));
+static_assert (!is_unbounded_array_type (^^float *[2][3]));
+static_assert (is_unbounded_array_type (^^float *[][3]));
+static_assert (!is_unbounded_array_type (^^ClassType[2]));
+static_assert (is_unbounded_array_type (^^ClassType[]));
+static_assert (!is_unbounded_array_type (^^ClassType[2][3]));
+static_assert (is_unbounded_array_type (^^ClassType[][3]));
+static_assert (!is_unbounded_array_type (^^IncompleteClass[2][3]));
+static_assert (is_unbounded_array_type (^^IncompleteClass[][3]));
+static_assert (!is_unbounded_array_type (^^int (*)[2]));
+static_assert (!is_unbounded_array_type (^^int (*)[]));
+static_assert (!is_unbounded_array_type (^^int (&)[2]));
+static_assert (!is_unbounded_array_type (^^int (&)[]));
+static_assert (!is_unbounded_array_type (^^ClassType));
+static_assert (!is_unbounded_array_type (^^IncompleteClass));
+static_assert (!is_unbounded_array_type (^^IncompleteUnion));
+
+enum class E { e1, e2 };
+static_assert (is_scoped_enum_type (^^E));
+enum class Ec : char { e1, e2 };
+static_assert (is_scoped_enum_type (^^Ec));
+enum U { u1, u2 };
+static_assert (!is_scoped_enum_type (^^U));
+enum F : int { f1, f2 };
+static_assert (!is_scoped_enum_type (^^F));
+static_assert (!is_scoped_enum_type (^^Incomplete_struct));
+struct S;
+static_assert (!is_scoped_enum_type (^^S));
+struct S { };
+static_assert (!is_scoped_enum_type (^^S));
+static_assert (!is_scoped_enum_type (^^int));
+static_assert (!is_scoped_enum_type (^^int[]));
+static_assert (!is_scoped_enum_type (^^int[2]));
+static_assert (!is_scoped_enum_type (^^int[][2]));
+static_assert (!is_scoped_enum_type (^^int[2][3]));
+static_assert (!is_scoped_enum_type (^^int *));
+static_assert (!is_scoped_enum_type (^^int &));
+static_assert (!is_scoped_enum_type (^^int *&));
+static_assert (!is_scoped_enum_type (^^int ()));
+static_assert (!is_scoped_enum_type (^^int (*) ()));
+static_assert (!is_scoped_enum_type (^^int (&) ()));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait6.C b/gcc/testsuite/g++.dg/reflect/type_trait6.C
new file mode 100644 (file)
index 0000000..e1b466f
--- /dev/null
@@ -0,0 +1,1381 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <meta>
+using namespace std::meta;
+
+class ClassType { };
+class DerivedType : public ClassType { };
+enum EnumType { e0 };
+struct ThrowDefaultClass { ThrowDefaultClass () noexcept (false); };
+struct ThrowCopyConsClass { ThrowCopyConsClass (const ThrowCopyConsClass &) noexcept (false); };
+struct ThrowMoveConsClass { ThrowMoveConsClass (ThrowMoveConsClass &&) noexcept (false); };
+struct NoexceptDefaultClass { NoexceptDefaultClass () noexcept (true); };
+struct ExceptDefaultClass { ExceptDefaultClass () noexcept (false); };
+struct NoexceptCopyConsClass { NoexceptCopyConsClass (const NoexceptCopyConsClass &) noexcept (true); };
+struct ExceptCopyConsClass { ExceptCopyConsClass (const ExceptCopyConsClass &) noexcept (false); };
+struct NoexceptMoveConsClass { NoexceptMoveConsClass (NoexceptMoveConsClass &&) noexcept (true); NoexceptMoveConsClass &operator= (NoexceptMoveConsClass &&) = default; };
+struct ExceptMoveConsClass { ExceptMoveConsClass (ExceptMoveConsClass &&) noexcept (false); };
+struct NoexceptCopyAssignClass { NoexceptCopyAssignClass &operator= (const NoexceptCopyAssignClass &) noexcept (true); };
+struct ExceptCopyAssignClass { ExceptCopyAssignClass &operator= (const ExceptCopyAssignClass &) noexcept (false); };
+struct NoexceptMoveAssignClass { NoexceptMoveAssignClass (NoexceptMoveAssignClass &&) = default; NoexceptMoveAssignClass &operator= (NoexceptMoveAssignClass &&) noexcept (true); };
+struct ExceptMoveAssignClass { ExceptMoveAssignClass &operator= (ExceptMoveAssignClass &&) noexcept (false); };
+struct DeletedCopyAssignClass { DeletedCopyAssignClass & operator= (const DeletedCopyAssignClass &) = delete; };
+struct DeletedMoveAssignClass { DeletedMoveAssignClass &operator= (DeletedMoveAssignClass &&) = delete; };
+struct NType { int i; int j; virtual ~NType (); };
+struct TType { int i; private: int j; };
+struct SLType { int i; int j; ~SLType (); };
+struct PODType { int i; int j; };
+
+namespace N1
+{
+  struct Empty {};
+  struct B { int i; B () {} };
+  struct D : B {};
+  enum E { ee1 };
+  enum E2 { ee2 };
+  enum class SE { e1 };
+  enum class SE2 { e2 };
+  enum OpE : int;
+  enum class OpSE : bool;
+  union U { int i; Empty b; };
+  struct Abstract { virtual ~Abstract () = 0; };
+  struct AbstractDelDtor { ~AbstractDelDtor () = delete; virtual void foo () = 0; };
+  struct Ukn;
+  template <class To>
+  struct ImplicitTo { operator To (); };
+  template <class To>
+  struct DelImplicitTo { operator To () = delete; };
+  template <class To>
+  struct ExplicitTo { explicit operator To (); };
+  struct Ellipsis { Ellipsis (...) {} };
+  struct DelEllipsis { DelEllipsis (...) = delete; };
+  struct Any { template <class T> Any (T &&) {} };
+  struct nAny { template <class... T> nAny (T &&...) {} };
+  struct DelnAny { template <class... T> DelnAny (T &&...) = delete; };
+  template <class... Args>
+  struct FromArgs { FromArgs (Args...); };
+  struct DelDef { DelDef () = delete; };
+  struct DelCopy { DelCopy (const DelCopy &) = delete; };
+  struct DelDtor {
+    DelDtor () = default;
+    DelDtor (const DelDtor &) = default;
+    DelDtor (DelDtor &&) = default;
+    DelDtor (int);
+    DelDtor (int, B, U);
+    ~DelDtor () = delete;
+  };
+  struct Nontrivial {
+    Nontrivial ();
+    Nontrivial (const Nontrivial &);
+    Nontrivial &operator= (const Nontrivial &);
+    ~Nontrivial ();
+  };
+  union NontrivialUnion { int i; Nontrivial n; };
+  struct UnusualCopy { UnusualCopy (UnusualCopy &); };
+}
+
+namespace N2
+{
+  struct E {};
+  struct NTD1 { ~NTD1 () = default; };
+  struct NTD2 { ~NTD2 (); };
+  struct NTD3 { ~NTD3 () noexcept (true); };
+  struct TD1 { ~TD1 () noexcept (false); };
+  struct TD2 { ~TD2 () noexcept (false); };
+  struct Aggr { int i; bool b; E e; };
+  struct Aggr2 { int i; bool b; TD1 r; };
+  struct Del { ~Del () = delete; };
+  struct Del2 { ~Del2 () noexcept = delete; };
+  struct Del3 { ~Del3 () noexcept (false) = delete; };
+  struct Der : Aggr {};
+  struct Der2 : Aggr2 {};
+  union U1 { int i; double d; void *p; TD1 *pt; };
+  union Ut { int i; double d; void *p; TD1 pt; };
+  enum class En { a, b, c, d };
+  enum En2 { En2a, En2b, En2c, En2d };
+  enum OpE : int;
+  enum class OpSE : bool;
+  struct Abstract1 { virtual ~Abstract1 () = 0; };
+  struct AbstractDelDtor { ~AbstractDelDtor () = delete; virtual void foo () = 0; };
+  struct Abstract2 { virtual ~Abstract2 () noexcept (false) = 0; };
+  struct Abstract3 { ~Abstract3 () noexcept (false); virtual void foo () noexcept = 0; };
+  struct Nontrivial {
+    Nontrivial ();
+    Nontrivial (const Nontrivial &);
+    Nontrivial &operator= (const Nontrivial &);
+    ~Nontrivial ();
+  };
+  union NontrivialUnion { int i; Nontrivial n; };
+  struct UnusualCopy { UnusualCopy (UnusualCopy &); };
+  struct Ellipsis { Ellipsis (...) {} };
+  struct DelEllipsis { DelEllipsis (...) = delete; };
+  struct DelDef { DelDef () = delete; };
+  struct DelCopy { DelCopy (const DelCopy &) = delete; };
+}
+
+namespace N3
+{
+  struct Empty {};
+  struct B { int i; B (){} };
+  struct D : B {};
+  enum E { ee1 };
+  enum E2 { ee2 };
+  enum class SE { e1 };
+  enum class SE2 { e2 };
+  enum OpE : int;
+  enum class OpSE : bool;
+  union U { int i; Empty b; };
+  union UAssignAll { bool b; char c; template <class T> void operator= (T &&); };
+  union UDelAssignAll { bool b; char c; template <class T> void operator= (T &&) = delete; };
+  struct Abstract { virtual ~Abstract () = 0; };
+  struct AbstractDelDtor { ~AbstractDelDtor () = delete; virtual void foo () = 0; };
+  struct Ukn;
+  template <class To>
+  struct ImplicitTo { operator To (); };
+  template <class To>
+  struct ExplicitTo { explicit operator To (); };
+  template <class To>
+  struct DelImplicitTo { operator To () = delete; };
+  template<class To> struct DelExplicitTo { explicit operator To () = delete; };
+  struct Ellipsis { Ellipsis (...) {} };
+  struct DelEllipsis { DelEllipsis (...) = delete; };
+  struct Any { template <class T> Any (T &&) {} };
+  struct nAny { template <class... T> nAny (T &&...) {} };
+  struct DelnAny { template <class... T> DelnAny (T &&...) = delete; };
+  template<class... Args>
+  struct FromArgs { FromArgs (Args...); };
+  template<class... Args>
+  struct DelFromArgs { DelFromArgs (Args...) = delete; };
+  struct DelDef { DelDef () = delete; };
+  struct DelCopy { DelCopy (const DelCopy &) = delete; };
+  struct DelDtor {
+    DelDtor () = default;
+    DelDtor (const DelDtor &) = default;
+    DelDtor (DelDtor &&) = default;
+    DelDtor (int);
+    DelDtor (int, B, U);
+    ~DelDtor () = delete;
+  };
+  struct Nontrivial {
+    Nontrivial ();
+    Nontrivial (const Nontrivial &);
+    Nontrivial &operator= (const Nontrivial &);
+    ~Nontrivial ();
+  };
+  union NontrivialUnion { int i; Nontrivial n; };
+  struct UnusualCopy { UnusualCopy (UnusualCopy &); };
+  struct AnyAssign { template <class T> void operator= (T &&); };
+  struct DelAnyAssign { template <class T> void operator= (T &&) = delete; };
+  struct DelCopyAssign {
+    DelCopyAssign &operator= (const DelCopyAssign &) = delete;
+    DelCopyAssign &operator= (DelCopyAssign &&) = default;
+  };
+  struct MO { MO (MO &&) = default; MO &operator= (MO &&) = default; };
+}
+
+struct CopyConsOnlyType {
+  CopyConsOnlyType (int) { }
+  CopyConsOnlyType (CopyConsOnlyType &&) = delete;
+  CopyConsOnlyType (const CopyConsOnlyType &) = default;
+  CopyConsOnlyType &operator= (const CopyConsOnlyType &) = delete;
+  CopyConsOnlyType &operator= (CopyConsOnlyType &&) = delete;
+};
+
+struct MoveConsOnlyType {
+  MoveConsOnlyType (int) { }
+  MoveConsOnlyType (const MoveConsOnlyType &) = delete;
+  MoveConsOnlyType (MoveConsOnlyType &&) = default;
+  MoveConsOnlyType &operator= (const MoveConsOnlyType &) = delete;
+  MoveConsOnlyType &operator= (MoveConsOnlyType &&) = delete;
+};
+
+struct HasTemplateCtor { HasTemplateCtor () = default; template <class T> HasTemplateCtor (); };
+struct HasTemplateCCtor {
+  HasTemplateCCtor (const HasTemplateCCtor &) = default;
+  template <class T>
+  HasTemplateCCtor (T &&);
+};
+struct MoveOnly { MoveOnly (MoveOnly &&) = default; };
+struct MoveOnly2 { MoveOnly2 (MoveOnly2 &&) = delete; };
+struct HasTemplateCAssign
+{
+  HasTemplateCAssign &operator= (const HasTemplateCAssign &) = default;
+  template <class T>
+  HasTemplateCAssign &operator= (T &&);
+};
+struct MoveOnly3 { MoveOnly3 &operator= (MoveOnly3 &&) = default; };
+struct MoveOnly4 { MoveOnly4 &operator= (MoveOnly4 &&) = delete; };
+
+static_assert (is_default_constructible_type (^^int));
+static_assert (is_default_constructible_type (^^int const));
+static_assert (is_default_constructible_type (^^int const volatile));
+static_assert (is_default_constructible_type (^^int *));
+static_assert (is_default_constructible_type (^^void *));
+static_assert (is_default_constructible_type (^^void *const));
+static_assert (is_default_constructible_type (^^int N1::B::*));
+static_assert (is_default_constructible_type (^^void (*) ()));
+static_assert (is_default_constructible_type (^^std::nullptr_t));
+static_assert (is_default_constructible_type (^^std::nullptr_t const));
+static_assert (is_default_constructible_type (^^N1::Empty));
+static_assert (is_default_constructible_type (^^N1::Empty const));
+static_assert (is_default_constructible_type (^^N1::FromArgs <>));
+static_assert (is_default_constructible_type (^^N1::FromArgs <> const));
+static_assert (is_default_constructible_type (^^N1::nAny));
+static_assert (is_default_constructible_type (^^N1::nAny const));
+static_assert (is_default_constructible_type (^^N1::Ellipsis));
+static_assert (is_default_constructible_type (^^N1::Ellipsis const));
+static_assert (is_default_constructible_type (^^N1::U));
+static_assert (is_default_constructible_type (^^N1::U const));
+static_assert (is_default_constructible_type (^^N1::E));
+static_assert (is_default_constructible_type (^^N1::E const));
+static_assert (is_default_constructible_type (^^N1::SE));
+static_assert (is_default_constructible_type (^^N1::SE const));
+static_assert (is_default_constructible_type (^^N1::OpE));
+static_assert (is_default_constructible_type (^^N1::OpE const));
+static_assert (is_default_constructible_type (^^N1::OpSE));
+static_assert (is_default_constructible_type (^^N1::OpSE const));
+static_assert (is_default_constructible_type (^^int [1]));
+static_assert (is_default_constructible_type (^^const int [1]));
+static_assert (is_default_constructible_type (^^int [1][2]));
+static_assert (is_default_constructible_type (^^const int [1][2]));
+static_assert (is_default_constructible_type (^^N1::FromArgs <> [1]));
+static_assert (is_default_constructible_type (^^const N1::FromArgs <> [1]));
+static_assert (is_default_constructible_type (^^N1::U [1]));
+static_assert (is_default_constructible_type (^^const N1::U [1]));
+static_assert (is_default_constructible_type (^^N1::Empty [1]));
+static_assert (is_default_constructible_type (^^const N1::Empty [1]));
+static_assert (is_default_constructible_type (^^N1::Ellipsis [1]));
+static_assert (is_default_constructible_type (^^const N1::Ellipsis [1]));
+static_assert (is_default_constructible_type (^^std::nullptr_t [1]));
+static_assert (is_default_constructible_type (^^const std::nullptr_t [1]));
+static_assert (is_default_constructible_type (^^N1::nAny [1]));
+static_assert (is_default_constructible_type (^^const N1::nAny [1]));
+static_assert (is_default_constructible_type (^^N1::E [1]));
+static_assert (is_default_constructible_type (^^const N1::E [1]));
+static_assert (is_default_constructible_type (^^N1::SE [1]));
+static_assert (is_default_constructible_type (^^const N1::SE [1]));
+static_assert (is_default_constructible_type (^^N1::OpE [1]));
+static_assert (is_default_constructible_type (^^const N1::OpE [1]));
+static_assert (is_default_constructible_type (^^N1::OpSE [1]));
+static_assert (is_default_constructible_type (^^const N1::OpSE [1]));
+static_assert (is_default_constructible_type (^^int * [1]));
+static_assert (is_default_constructible_type (^^int * const [1]));
+static_assert (is_default_constructible_type (^^int N1::B::* [1]));
+static_assert (is_default_constructible_type (^^int N1::B::* const [1]));
+static_assert (is_default_constructible_type (^^std::initializer_list <int>));
+static_assert (is_default_constructible_type (^^const std::initializer_list <int>));
+static_assert (is_default_constructible_type (^^std::initializer_list <int> [1]));
+static_assert (is_default_constructible_type (^^const std::initializer_list <int> [1]));
+static_assert (is_default_constructible_type (^^NoexceptDefaultClass));
+static_assert (is_default_constructible_type (^^ThrowDefaultClass));
+static_assert (is_default_constructible_type (^^ExceptDefaultClass));
+static_assert (!is_default_constructible_type (^^void));
+static_assert (!is_default_constructible_type (^^const void));
+static_assert (!is_default_constructible_type (^^N1::Abstract));
+static_assert (!is_default_constructible_type (^^const N1::Abstract));
+static_assert (!is_default_constructible_type (^^N1::Any));
+static_assert (!is_default_constructible_type (^^const N1::Any));
+static_assert (!is_default_constructible_type (^^N1::FromArgs <int>));
+static_assert (!is_default_constructible_type (^^const N1::FromArgs <int>));
+static_assert (!is_default_constructible_type (^^int &));
+static_assert (!is_default_constructible_type (^^int &&));
+static_assert (!is_default_constructible_type (^^void ()));
+static_assert (!is_default_constructible_type (^^void () const volatile));
+static_assert (!is_default_constructible_type (^^void (&) ()));
+static_assert (!is_default_constructible_type (^^int (&) [1]));
+static_assert (!is_default_constructible_type (^^int (&) []));
+static_assert (!is_default_constructible_type (^^int []));
+static_assert (!is_default_constructible_type (^^const int []));
+static_assert (!is_default_constructible_type (^^int [][1][2]));
+static_assert (!is_default_constructible_type (^^const int [][1][2]));
+static_assert (!is_default_constructible_type (^^N1::Any [1]));
+static_assert (!is_default_constructible_type (^^const N1::Any [1]));
+static_assert (!is_default_constructible_type (^^N1::FromArgs <int> [1]));
+static_assert (!is_default_constructible_type (^^const N1::FromArgs <int> [1]));
+static_assert (!is_default_constructible_type (^^N1::FromArgs <std::initializer_list <int>>));
+static_assert (!is_default_constructible_type (^^const N1::FromArgs <std::initializer_list <int>>));
+static_assert (!is_default_constructible_type (^^const N1::FromArgs <const std::initializer_list <int>>));
+static_assert (!is_default_constructible_type (^^N1::DelDef));
+static_assert (!is_default_constructible_type (^^const N1::DelDef));
+static_assert (!is_default_constructible_type (^^N1::DelCopy));
+static_assert (!is_default_constructible_type (^^const N1::DelCopy));
+static_assert (!is_default_constructible_type (^^N1::DelDtor));
+static_assert (!is_default_constructible_type (^^const N1::DelDtor));
+static_assert (!is_default_constructible_type (^^int []));
+static_assert (!is_default_constructible_type (^^N1::Empty []));
+static_assert (!is_default_constructible_type (^^N1::B []));
+static_assert (!is_default_constructible_type (^^N1::D []));
+static_assert (!is_default_constructible_type (^^N1::U []));
+static_assert (!is_default_constructible_type (^^N1::Ukn []));
+static_assert (!is_default_constructible_type (^^N1::Ellipsis []));
+static_assert (!is_default_constructible_type (^^N1::Any []));
+static_assert (!is_default_constructible_type (^^N1::nAny []));
+
+static_assert (is_copy_constructible_type (^^int));
+static_assert (is_copy_constructible_type (^^float));
+static_assert (is_copy_constructible_type (^^EnumType));
+static_assert (is_copy_constructible_type (^^int *));
+static_assert (is_copy_constructible_type (^^int (*) (int)));
+static_assert (is_copy_constructible_type (^^int (ClassType::*)));
+static_assert (is_copy_constructible_type (^^int (ClassType::*) (int)));
+static_assert (is_copy_constructible_type (^^NoexceptCopyConsClass));
+static_assert (is_copy_constructible_type (^^const NoexceptCopyConsClass));
+static_assert (is_copy_constructible_type (^^ThrowCopyConsClass));
+static_assert (is_copy_constructible_type (^^ExceptCopyConsClass));
+static_assert (!is_copy_constructible_type (^^void));
+static_assert (!is_copy_constructible_type (^^int [2]));
+static_assert (!is_copy_constructible_type (^^int []));
+static_assert (!is_copy_constructible_type (^^float [][3]));
+static_assert (!is_copy_constructible_type (^^EnumType [2][3][4]));
+static_assert (!is_copy_constructible_type (^^int * [3]));
+static_assert (!is_copy_constructible_type (^^int (* [][2]) (int)));
+static_assert (!is_copy_constructible_type (^^int (ClassType::* [2][3])));
+static_assert (!is_copy_constructible_type (^^int (ClassType::* [][2][3]) (int)));
+static_assert (!is_copy_constructible_type (^^ClassType (unsigned) const &));
+static_assert (!is_copy_constructible_type (^^bool (ClassType) const));
+static_assert (!is_copy_constructible_type (^^bool (...) &&));
+static_assert (!is_copy_constructible_type (^^EnumType (int, ...)));
+static_assert (!is_copy_constructible_type (^^volatile NoexceptCopyConsClass));
+
+static_assert (is_move_constructible_type (^^int));
+static_assert (is_move_constructible_type (^^float));
+static_assert (is_move_constructible_type (^^EnumType));
+static_assert (is_move_constructible_type (^^int *));
+static_assert (is_move_constructible_type (^^int (*) (int)));
+static_assert (is_move_constructible_type (^^int (ClassType::*)));
+static_assert (is_move_constructible_type (^^int (ClassType::*) (int)));
+static_assert (is_move_constructible_type (^^NoexceptMoveConsClass));
+static_assert (is_move_constructible_type (^^ThrowMoveConsClass));
+static_assert (is_move_constructible_type (^^ExceptMoveConsClass));
+static_assert (!is_move_constructible_type (^^void));
+static_assert (!is_move_constructible_type (^^int [2]));
+static_assert (!is_move_constructible_type (^^int []));
+static_assert (!is_move_constructible_type (^^float [][3]));
+static_assert (!is_move_constructible_type (^^EnumType [2][3][4]));
+static_assert (!is_move_constructible_type (^^int * [3]));
+static_assert (!is_move_constructible_type (^^int (* [][2]) (int)));
+static_assert (!is_move_constructible_type (^^int (ClassType::* [2][3])));
+static_assert (!is_move_constructible_type (^^int (ClassType::* [][2][3]) (int)));
+static_assert (!is_move_constructible_type (^^ClassType (unsigned) const &));
+static_assert (!is_move_constructible_type (^^bool (ClassType) const));
+static_assert (!is_move_constructible_type (^^bool (...) &&));
+static_assert (!is_move_constructible_type (^^EnumType (int, ...)));
+static_assert (!is_move_constructible_type (^^const NoexceptMoveConsClass));
+static_assert (!is_move_constructible_type (^^volatile NoexceptMoveConsClass));
+
+static_assert (is_assignable_type (^^int &, ^^int));
+static_assert (is_assignable_type (^^int &, ^^const int));
+static_assert (is_assignable_type (^^int &, ^^int &));
+static_assert (is_assignable_type (^^int &, ^^const int &));
+static_assert (!is_assignable_type (^^int, ^^int));
+static_assert (!is_assignable_type (^^int, ^^const int));
+static_assert (!is_assignable_type (^^int, ^^int &));
+static_assert (!is_assignable_type (^^int, ^^const int &));
+static_assert (!is_assignable_type (^^const int, ^^int));
+static_assert (!is_assignable_type (^^const int, ^^const int));
+static_assert (!is_assignable_type (^^const int, ^^int &));
+static_assert (!is_assignable_type (^^const int, ^^const int &));
+static_assert (!is_assignable_type (^^const int &, ^^int));
+static_assert (!is_assignable_type (^^const int &, ^^const int));
+static_assert (!is_assignable_type (^^const int &, ^^int &));
+static_assert (!is_assignable_type (^^const int &, ^^const int &));
+static_assert (is_assignable_type (^^N3::Empty &, ^^N3::Empty));
+static_assert (is_assignable_type (^^N3::Empty &, ^^const N3::Empty));
+static_assert (is_assignable_type (^^N3::Empty &, ^^N3::Empty &));
+static_assert (is_assignable_type (^^N3::Empty &, ^^const N3::Empty &));
+static_assert (is_assignable_type (^^N3::Empty, ^^N3::Empty));
+static_assert (is_assignable_type (^^N3::Empty, ^^const N3::Empty));
+static_assert (is_assignable_type (^^N3::Empty, ^^N3::Empty &));
+static_assert (is_assignable_type (^^N3::Empty, ^^const N3::Empty &));
+static_assert (is_assignable_type (^^N3::B &, ^^N3::B));
+static_assert (is_assignable_type (^^N3::B &, ^^const N3::B));
+static_assert (is_assignable_type (^^N3::B &, ^^N3::B &));
+static_assert (is_assignable_type (^^N3::B &, ^^const N3::B &));
+static_assert (is_assignable_type (^^N3::B, ^^N3::B));
+static_assert (is_assignable_type (^^N3::B, ^^const N3::B));
+static_assert (is_assignable_type (^^N3::B, ^^N3::B &));
+static_assert (is_assignable_type (^^N3::B, ^^const N3::B &));
+static_assert (is_assignable_type (^^bool &, ^^bool));
+static_assert (is_assignable_type (^^bool &, ^^const bool));
+static_assert (is_assignable_type (^^bool &, ^^bool &));
+static_assert (is_assignable_type (^^bool &, ^^const bool &));
+static_assert (!is_assignable_type (^^bool, ^^bool));
+static_assert (!is_assignable_type (^^bool, ^^const bool));
+static_assert (!is_assignable_type (^^bool, ^^bool &));
+static_assert (!is_assignable_type (^^bool, ^^const bool &));
+static_assert (is_assignable_type (^^std::nullptr_t &, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^std::nullptr_t &, ^^const std::nullptr_t));
+static_assert (is_assignable_type (^^std::nullptr_t &, ^^std::nullptr_t &));
+static_assert (is_assignable_type (^^std::nullptr_t &, ^^const std::nullptr_t &));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^const std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^std::nullptr_t &));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^const std::nullptr_t &));
+static_assert (is_assignable_type (^^N3::E &, ^^N3::E));
+static_assert (is_assignable_type (^^N3::E &, ^^const N3::E));
+static_assert (is_assignable_type (^^N3::E &, ^^N3::E &));
+static_assert (is_assignable_type (^^N3::E &, ^^const N3::E &));
+static_assert (is_assignable_type (^^int &, ^^N3::E));
+static_assert (is_assignable_type (^^int &, ^^const N3::E));
+static_assert (is_assignable_type (^^int &, ^^N3::E &));
+static_assert (is_assignable_type (^^int &, ^^const N3::E &));
+static_assert (!is_assignable_type (^^N3::E &, ^^int));
+static_assert (!is_assignable_type (^^N3::E &, ^^const int));
+static_assert (!is_assignable_type (^^N3::E &, ^^int &));
+static_assert (!is_assignable_type (^^N3::E &, ^^const int &));
+static_assert (!is_assignable_type (^^N3::E &, ^^N3::E2));
+static_assert (!is_assignable_type (^^N3::E &, ^^const N3::E2));
+static_assert (!is_assignable_type (^^N3::E &, ^^N3::E2 &));
+static_assert (!is_assignable_type (^^N3::E &, ^^const N3::E2 &));
+static_assert (!is_assignable_type (^^N3::E, ^^N3::E));
+static_assert (!is_assignable_type (^^N3::E, ^^const N3::E));
+static_assert (!is_assignable_type (^^N3::E, ^^N3::E &));
+static_assert (!is_assignable_type (^^N3::E, ^^const N3::E &));
+static_assert (is_assignable_type (^^N3::SE &, ^^N3::SE));
+static_assert (is_assignable_type (^^N3::SE &, ^^const N3::SE));
+static_assert (is_assignable_type (^^N3::SE &, ^^N3::SE &));
+static_assert (is_assignable_type (^^N3::SE &, ^^const N3::SE &));
+static_assert (!is_assignable_type (^^int &, ^^N3::SE));
+static_assert (!is_assignable_type (^^int &, ^^const N3::SE));
+static_assert (!is_assignable_type (^^int &, ^^N3::SE &));
+static_assert (!is_assignable_type (^^int &, ^^const N3::SE &));
+static_assert (!is_assignable_type (^^N3::SE &, ^^int));
+static_assert (!is_assignable_type (^^N3::SE &, ^^const int));
+static_assert (!is_assignable_type (^^N3::SE &, ^^int &));
+static_assert (!is_assignable_type (^^N3::SE &, ^^const int &));
+static_assert (!is_assignable_type (^^N3::SE, ^^N3::SE));
+static_assert (!is_assignable_type (^^N3::SE, ^^const N3::SE));
+static_assert (!is_assignable_type (^^N3::SE, ^^N3::SE &));
+static_assert (!is_assignable_type (^^N3::SE, ^^const N3::SE &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^int));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::E));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::SE));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::Empty));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::U));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^int &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^std::nullptr_t &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::E &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::SE &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::Empty &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::U &));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::AnyAssign));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^std::initializer_list <int>));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^int [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^std::nullptr_t [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::E [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::SE [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^int (&) [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^std::nullptr_t (&) [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::E (&) [1]));
+static_assert (is_assignable_type (^^N3::AnyAssign &, ^^N3::SE (&) [1]));
+static_assert (is_assignable_type (^^int &, ^^N3::E));
+static_assert (!is_assignable_type (^^int &, ^^N3::SE));
+static_assert (is_assignable_type (^^bool &, ^^N3::E));
+static_assert (!is_assignable_type (^^bool &, ^^N3::SE));
+static_assert (is_assignable_type (^^bool &, ^^void *));
+static_assert (is_assignable_type (^^bool &, ^^int N3::B::*));
+static_assert (is_assignable_type (^^bool &, ^^void *));
+static_assert (!is_assignable_type (^^bool &, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^std::nullptr_t &, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^void *&, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^int *&, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^int N3::B::*&, ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t &, ^^bool));
+static_assert (!is_assignable_type (^^void *&, ^^bool));
+static_assert (!is_assignable_type (^^N3::E &, ^^bool));
+static_assert (!is_assignable_type (^^N3::SE &, ^^bool));
+static_assert (is_assignable_type (^^std::initializer_list <int> &, ^^std::initializer_list <int>));
+static_assert (is_assignable_type (^^std::initializer_list <int> &, ^^std::initializer_list <int> &&));
+static_assert (is_assignable_type (^^std::initializer_list <int> &, ^^const std::initializer_list <int> &&));
+static_assert (is_assignable_type (^^std::initializer_list <int> &, ^^std::initializer_list <int> &));
+static_assert (is_assignable_type (^^std::initializer_list <int> &, ^^const std::initializer_list <int> &));
+static_assert (!is_assignable_type (^^const std::initializer_list <int> &, ^^std::initializer_list <int>));
+static_assert (!is_assignable_type (^^const N3::AnyAssign &, ^^int));
+static_assert (!is_assignable_type (^^N3::AnyAssign &, ^^void));
+static_assert (!is_assignable_type (^^void, ^^int));
+static_assert (!is_assignable_type (^^const void, ^^int));
+static_assert (!is_assignable_type (^^int, ^^void));
+static_assert (!is_assignable_type (^^int, ^^const void));
+static_assert (!is_assignable_type (^^const int, ^^void));
+static_assert (!is_assignable_type (^^const int, ^^const void));
+static_assert (!is_assignable_type (^^int &, ^^void));
+static_assert (!is_assignable_type (^^int &, ^^const void));
+static_assert (!is_assignable_type (^^const int &, ^^void));
+static_assert (!is_assignable_type (^^const int &, ^^const void));
+static_assert (!is_assignable_type (^^void, ^^void));
+static_assert (!is_assignable_type (^^const void, ^^void));
+static_assert (!is_assignable_type (^^const void, ^^const void));
+static_assert (!is_assignable_type (^^int [1], ^^int [1]));
+static_assert (!is_assignable_type (^^int (&) [1], ^^int [1]));
+static_assert (!is_assignable_type (^^int (&) [1], ^^int (&) [1]));
+static_assert (!is_assignable_type (^^int [2], ^^int [1]));
+static_assert (!is_assignable_type (^^int (&) [2], ^^int [1]));
+static_assert (!is_assignable_type (^^int (&) [2], ^^int (&) [1]));
+static_assert (!is_assignable_type (^^int [1], ^^void));
+static_assert (!is_assignable_type (^^int (&) [1], ^^void));
+static_assert (!is_assignable_type (^^void, ^^int [1]));
+static_assert (!is_assignable_type (^^void, ^^int (&) [1]));
+static_assert (!is_assignable_type (^^int [], ^^int []));
+static_assert (!is_assignable_type (^^int (&) [], ^^int []));
+static_assert (!is_assignable_type (^^int (&) [], ^^int (&) []));
+static_assert (!is_assignable_type (^^int [1], ^^int []));
+static_assert (!is_assignable_type (^^int (&) [1], ^^int []));
+static_assert (!is_assignable_type (^^int (&) [1], ^^int (&) []));
+static_assert (!is_assignable_type (^^int [], ^^int [1]));
+static_assert (!is_assignable_type (^^int (&) [], ^^int [1]));
+static_assert (!is_assignable_type (^^int (&) [], ^^int (&) [1]));
+static_assert (!is_assignable_type (^^int [], ^^void));
+static_assert (!is_assignable_type (^^int (&) [], ^^void));
+static_assert (!is_assignable_type (^^void, ^^int []));
+static_assert (!is_assignable_type (^^void, ^^int (&) []));
+static_assert (is_assignable_type (^^N3::DelCopyAssign &, ^^N3::DelCopyAssign));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^const N3::DelCopyAssign));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^N3::DelCopyAssign &));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^const N3::DelCopyAssign &));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^void));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^void ()));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^void (&) ()));
+static_assert (!is_assignable_type (^^N3::DelCopyAssign &, ^^int));
+static_assert (is_assignable_type (^^N3::DelAnyAssign &, ^^N3::DelAnyAssign &&));
+static_assert (is_assignable_type (^^N3::DelAnyAssign &, ^^const N3::DelAnyAssign &));
+static_assert (is_assignable_type (^^N3::DelAnyAssign, ^^N3::DelAnyAssign &&));
+static_assert (is_assignable_type (^^N3::DelAnyAssign, ^^const N3::DelAnyAssign &));
+static_assert (!is_assignable_type (^^const N3::DelAnyAssign &, ^^N3::DelAnyAssign &&));
+static_assert (!is_assignable_type (^^const N3::DelAnyAssign &, ^^const N3::DelAnyAssign &));
+static_assert (!is_assignable_type (^^const N3::DelAnyAssign, ^^N3::DelAnyAssign &&));
+static_assert (!is_assignable_type (^^const N3::DelAnyAssign, ^^const N3::DelAnyAssign &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^const int &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^void));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^void ()));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^void () const));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^void (&) ()));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^void (&&) ()));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^std::nullptr_t &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^std::initializer_list <int>));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^std::initializer_list <int> &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^bool));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^bool &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::E));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::E &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::SE));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::SE &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::Empty));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::Empty &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::B));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::B &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::U));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::U &));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^void *));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int *));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::B *));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^N3::D *));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int N3::B::*));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int N3::D::*));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int []));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int [1]));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int (&) []));
+static_assert (!is_assignable_type (^^N3::DelAnyAssign &, ^^int (&) [1]));
+static_assert (!is_assignable_type (^^void (), ^^void));
+static_assert (!is_assignable_type (^^void, ^^void ()));
+static_assert (!is_assignable_type (^^void (), ^^void ()));
+static_assert (!is_assignable_type (^^void (&) (), ^^void));
+static_assert (!is_assignable_type (^^void, ^^void (&) ()));
+static_assert (!is_assignable_type (^^void (&) (), ^^void (&) ()));
+static_assert (!is_assignable_type (^^void (&) (), ^^void ()));
+static_assert (!is_assignable_type (^^void (), ^^void (&) ()));
+static_assert (is_assignable_type (^^int &, ^^N3::ImplicitTo <int>));
+static_assert (!is_assignable_type (^^int &, ^^N3::ExplicitTo <int>));
+static_assert (!is_assignable_type (^^int, ^^N3::ImplicitTo <int>));
+static_assert (!is_assignable_type (^^int, ^^N3::ExplicitTo <int>));
+static_assert (!is_assignable_type (^^const int, ^^N3::ImplicitTo <int>));
+static_assert (!is_assignable_type (^^const int, ^^N3::ExplicitTo <int>));
+static_assert (!is_assignable_type (^^const int &, ^^N3::ImplicitTo <int>));
+static_assert (!is_assignable_type (^^const int &, ^^N3::ExplicitTo <int>));
+static_assert (is_assignable_type (^^N3::DelImplicitTo <int> &, ^^N3::DelImplicitTo <int>));
+static_assert (is_assignable_type (^^N3::DelImplicitTo <int>, ^^N3::DelImplicitTo <int>));
+static_assert (!is_assignable_type (^^int &, ^^N3::DelImplicitTo <int>));
+static_assert (!is_assignable_type (^^int, ^^N3::DelImplicitTo <int>));
+static_assert (!is_assignable_type (^^const int &, ^^N3::DelImplicitTo <int>));
+static_assert (!is_assignable_type (^^const int, ^^N3::DelImplicitTo <int>));
+static_assert (!is_assignable_type (^^int &, ^^N3::DelExplicitTo <int>));
+static_assert (!is_assignable_type (^^int, ^^N3::DelExplicitTo <int>));
+static_assert (!is_assignable_type (^^const int &, ^^N3::DelExplicitTo <int>));
+static_assert (!is_assignable_type (^^const int, ^^N3::DelExplicitTo <int>));
+static_assert (is_assignable_type (^^N3::B &, ^^N3::B));
+static_assert (is_assignable_type (^^N3::B &, ^^N3::D));
+static_assert (is_assignable_type (^^N3::B &, ^^N3::B &));
+static_assert (is_assignable_type (^^N3::B &, ^^N3::D &));
+static_assert (!is_assignable_type (^^const N3::B &, ^^N3::B &));
+static_assert (!is_assignable_type (^^const N3::B &, ^^N3::D &));
+static_assert (!is_assignable_type (^^N3::D &, ^^N3::B));
+static_assert (!is_assignable_type (^^N3::D &, ^^N3::B &));
+static_assert (is_assignable_type (^^N3::B *&, ^^N3::B *));
+static_assert (is_assignable_type (^^N3::B *&, ^^N3::D *));
+static_assert (is_assignable_type (^^const N3::B *&, ^^N3::D *));
+static_assert (is_assignable_type (^^const N3::B *&, ^^const N3::D *));
+static_assert (is_assignable_type (^^N3::B *&, ^^N3::B *&));
+static_assert (is_assignable_type (^^N3::B *&, ^^N3::D *&));
+static_assert (is_assignable_type (^^const N3::B *&, ^^N3::B *&));
+static_assert (is_assignable_type (^^const N3::B *&, ^^N3::D *&));
+static_assert (!is_assignable_type (^^N3::B * const &, ^^N3::B *&));
+static_assert (!is_assignable_type (^^N3::B * const &, ^^N3::D *&));
+static_assert (!is_assignable_type (^^N3::D *&, ^^N3::B *));
+static_assert (!is_assignable_type (^^N3::D *&, ^^N3::B *&));
+static_assert (is_assignable_type (^^N3::MO &, ^^N3::MO));
+static_assert (is_assignable_type (^^N3::MO &, ^^N3::MO &&));
+static_assert (is_assignable_type (^^N3::MO, ^^N3::MO));
+static_assert (is_assignable_type (^^N3::MO, ^^N3::MO &&));
+static_assert (!is_assignable_type (^^const N3::MO &, ^^N3::MO));
+static_assert (!is_assignable_type (^^const N3::MO &, ^^N3::MO &&));
+static_assert (!is_assignable_type (^^N3::MO &, ^^const N3::MO &&));
+static_assert (!is_assignable_type (^^N3::MO &, ^^N3::MO &));
+static_assert (!is_assignable_type (^^N3::MO &, ^^const N3::MO &));
+static_assert (!is_assignable_type (^^const N3::MO, ^^N3::MO));
+static_assert (!is_assignable_type (^^const N3::MO, ^^N3::MO &&));
+static_assert (!is_assignable_type (^^N3::MO, ^^const N3::MO &&));
+static_assert (!is_assignable_type (^^N3::MO, ^^N3::MO &));
+static_assert (!is_assignable_type (^^N3::MO, ^^const N3::MO &));
+static_assert (!is_assignable_type (^^N3::NontrivialUnion &, ^^N3::NontrivialUnion));
+static_assert (!is_assignable_type (^^N3::NontrivialUnion &, ^^N3::NontrivialUnion &&));
+static_assert (!is_assignable_type (^^N3::NontrivialUnion &, ^^N3::NontrivialUnion &));
+static_assert (!is_assignable_type (^^N3::NontrivialUnion &, ^^const N3::NontrivialUnion &));
+static_assert (!is_assignable_type (^^N3::NontrivialUnion &, ^^const N3::NontrivialUnion &&));
+static_assert (is_assignable_type (^^N3::Abstract &, ^^N3::Abstract));
+static_assert (is_assignable_type (^^N3::Abstract &, ^^N3::Abstract &&));
+static_assert (is_assignable_type (^^N3::Abstract &, ^^N3::Abstract &));
+static_assert (is_assignable_type (^^N3::Abstract &, ^^const N3::Abstract &));
+static_assert (is_assignable_type (^^N3::Abstract &, ^^const N3::Abstract &&));
+static_assert (is_assignable_type (^^N3::Abstract &&, ^^N3::Abstract));
+static_assert (is_assignable_type (^^N3::Abstract &&, ^^N3::Abstract &&));
+static_assert (is_assignable_type (^^N3::Abstract &&, ^^N3::Abstract &));
+static_assert (is_assignable_type (^^N3::Abstract &&, ^^const N3::Abstract &));
+static_assert (is_assignable_type (^^N3::Abstract &&, ^^const N3::Abstract &&));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &, ^^N3::AbstractDelDtor));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &, ^^N3::AbstractDelDtor &&));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &, ^^N3::AbstractDelDtor &));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &, ^^const N3::AbstractDelDtor &));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &, ^^const N3::AbstractDelDtor &&));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &&, ^^N3::AbstractDelDtor));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &&, ^^N3::AbstractDelDtor &&));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &&, ^^N3::AbstractDelDtor &));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &&, ^^const N3::AbstractDelDtor &));
+static_assert (is_assignable_type (^^N3::AbstractDelDtor &&, ^^const N3::AbstractDelDtor &&));
+static_assert (is_assignable_type (^^N3::DelDef &, ^^N3::DelDef));
+static_assert (is_assignable_type (^^N3::DelDef &, ^^N3::DelDef &&));
+static_assert (is_assignable_type (^^N3::DelDef &, ^^N3::DelDef &));
+static_assert (is_assignable_type (^^N3::DelDef &, ^^const N3::DelDef &));
+static_assert (is_assignable_type (^^N3::DelDef &, ^^const N3::DelDef &&));
+static_assert (is_assignable_type (^^N3::DelDef &&, ^^N3::DelDef));
+static_assert (is_assignable_type (^^N3::DelDef &&, ^^N3::DelDef &&));
+static_assert (is_assignable_type (^^N3::DelDef &&, ^^N3::DelDef &));
+static_assert (is_assignable_type (^^N3::DelDef &&, ^^const N3::DelDef &));
+static_assert (is_assignable_type (^^N3::DelDef &&, ^^const N3::DelDef &&));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::Ellipsis));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::Ellipsis));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::Ellipsis &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::Ellipsis &));
+static_assert (is_assignable_type (^^N3::Ellipsis, ^^N3::Ellipsis));
+static_assert (is_assignable_type (^^N3::Ellipsis, ^^const N3::Ellipsis));
+static_assert (is_assignable_type (^^N3::Ellipsis, ^^N3::Ellipsis &));
+static_assert (is_assignable_type (^^N3::Ellipsis, ^^const N3::Ellipsis &));
+static_assert (!is_assignable_type (^^N3::Ellipsis &, ^^void));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^int));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const int));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^int &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const int &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::Empty));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::Empty));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::Empty &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::Empty &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::E));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::E));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::E &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::E &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::SE));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::SE));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^N3::SE &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const N3::SE &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^bool));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const bool));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^bool &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const bool &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const std::nullptr_t));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^std::nullptr_t &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const std::nullptr_t &));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^void *));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const void *));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^void *&));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^const void *&));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^void ()));
+static_assert (is_assignable_type (^^N3::Ellipsis &, ^^void (&) ()));
+static_assert (is_assignable_type (^^N3::DelEllipsis &, ^^N3::DelEllipsis));
+static_assert (is_assignable_type (^^N3::DelEllipsis &, ^^const N3::DelEllipsis));
+static_assert (is_assignable_type (^^N3::DelEllipsis &, ^^N3::DelEllipsis &));
+static_assert (is_assignable_type (^^N3::DelEllipsis &, ^^const N3::DelEllipsis &));
+static_assert (is_assignable_type (^^N3::DelEllipsis, ^^N3::DelEllipsis));
+static_assert (is_assignable_type (^^N3::DelEllipsis, ^^const N3::DelEllipsis));
+static_assert (is_assignable_type (^^N3::DelEllipsis, ^^N3::DelEllipsis &));
+static_assert (is_assignable_type (^^N3::DelEllipsis, ^^const N3::DelEllipsis &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^void));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^int));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const int));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^int &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const int &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^N3::Empty));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const N3::Empty));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^N3::Empty &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const N3::Empty &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^N3::E));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const N3::E));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^N3::E &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const N3::E &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^N3::SE));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const N3::SE));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^N3::SE &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const N3::SE &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^bool));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const bool));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^bool &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const bool &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const std::nullptr_t));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^std::nullptr_t &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const std::nullptr_t &));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^void *));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const void *));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^void *&));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^const void *&));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^void ()));
+static_assert (!is_assignable_type (^^N3::DelEllipsis &, ^^void (&) ()));
+static_assert (is_assignable_type (^^N3::FromArgs <int> &, ^^int));
+static_assert (is_assignable_type (^^N3::FromArgs <int> &, ^^const int));
+static_assert (!is_assignable_type (^^N3::FromArgs <int> &, ^^N3::ImplicitTo <int>));
+static_assert (!is_assignable_type (^^N3::FromArgs <int> &, ^^N3::ImplicitTo <const int>));
+static_assert (!is_assignable_type (^^N3::FromArgs <int> &, ^^N3::ExplicitTo <int>));
+static_assert (!is_assignable_type (^^N3::FromArgs <int> &, ^^N3::ExplicitTo <const int>));
+static_assert (!is_assignable_type (^^N3::DelFromArgs <int> &, ^^int));
+static_assert (!is_assignable_type (^^N3::DelFromArgs <int> &, ^^const int));
+static_assert (is_assignable_type (^^void (*&) (), ^^N3::ImplicitTo <void (*) ()>));
+static_assert (!is_assignable_type (^^void (*&) (), ^^N3::ExplicitTo <void (*) ()>));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::UAssignAll));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^const N3::UAssignAll));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::UAssignAll &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^const N3::UAssignAll &));
+static_assert (is_assignable_type (^^N3::UAssignAll, ^^N3::UAssignAll));
+static_assert (is_assignable_type (^^N3::UAssignAll, ^^const N3::UAssignAll));
+static_assert (is_assignable_type (^^N3::UAssignAll, ^^N3::UAssignAll &));
+static_assert (is_assignable_type (^^N3::UAssignAll, ^^const N3::UAssignAll &));
+static_assert (!is_assignable_type (^^N3::UAssignAll &, ^^void));
+static_assert (!is_assignable_type (^^const N3::UAssignAll &, ^^void));
+static_assert (!is_assignable_type (^^const N3::UAssignAll &, ^^N3::UAssignAll));
+static_assert (!is_assignable_type (^^const N3::UAssignAll &, ^^const N3::UAssignAll));
+static_assert (!is_assignable_type (^^const N3::UAssignAll &, ^^N3::UAssignAll &));
+static_assert (!is_assignable_type (^^const N3::UAssignAll &, ^^const N3::UAssignAll &));
+static_assert (!is_assignable_type (^^N3::UAssignAll &, ^^void () const));
+static_assert (!is_assignable_type (^^N3::UAssignAll &, ^^void () &));
+static_assert (!is_assignable_type (^^N3::UAssignAll &, ^^void () const volatile &&));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::E));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::E &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::SE));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::SE &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^double));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^double &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::Empty));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::Empty &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::B));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::B &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::U));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^N3::U &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^std::nullptr_t));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^std::nullptr_t &));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^void ()));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^void (&) ()));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^void (*) ()));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^void (*&) ()));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int *));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int *&));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^void *));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^void *&));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^const int *));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^const int *&));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^const void *));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^const void *&));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int [1]));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int (&) [1]));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int []));
+static_assert (is_assignable_type (^^N3::UAssignAll &, ^^int (&) []));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::E));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::E &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::SE));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::SE &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^double));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^double &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::Empty));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::Empty &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::B));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::B &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::U));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^N3::U &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^std::nullptr_t &));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void ()));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void (&) ()));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void () const));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void (*) ()));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void (*&) ()));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int *));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int *&));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void *));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^void *&));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^const int *));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^const int *&));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^const void *));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^const void *&));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int [1]));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int (&) [1]));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int []));
+static_assert (!is_assignable_type (^^N3::UDelAssignAll &, ^^int (&) []));
+static_assert (!is_assignable_type (^^void (&) (), ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^void (&) ()));
+static_assert (!is_assignable_type (^^void (&) (), ^^int []));
+static_assert (!is_assignable_type (^^int [], ^^void (&) ()));
+static_assert (!is_assignable_type (^^int [], ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^int []));
+static_assert (!is_assignable_type (^^int [1], ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^int [1]));
+static_assert (!is_assignable_type (^^void, ^^std::nullptr_t));
+static_assert (!is_assignable_type (^^std::nullptr_t, ^^void));
+static_assert (!is_assignable_type (^^const N3::D &, ^^N3::B &));
+static_assert (!is_assignable_type (^^const N3::B &, ^^N3::B &));
+static_assert (is_assignable_type (^^N3::B &, ^^const N3::D &));
+static_assert (is_assignable_type (^^N3::B &, ^^const N3::B &));
+static_assert (is_assignable_type (^^int &, ^^const int &));
+static_assert (is_assignable_type (^^int &, ^^const double &));
+
+static_assert (is_copy_assignable_type (^^int));
+static_assert (is_copy_assignable_type (^^float));
+static_assert (is_copy_assignable_type (^^EnumType));
+static_assert (is_copy_assignable_type (^^int *));
+static_assert (is_copy_assignable_type (^^int (*) (int)));
+static_assert (is_copy_assignable_type (^^int (ClassType::*)));
+static_assert (is_copy_assignable_type (^^int (ClassType::*) (int)));
+static_assert (is_copy_assignable_type (^^NoexceptCopyAssignClass));
+static_assert (is_copy_assignable_type (^^ExceptCopyAssignClass));
+static_assert (!is_copy_assignable_type (^^void));
+static_assert (!is_copy_assignable_type (^^int [2]));
+static_assert (!is_copy_assignable_type (^^float [][3]));
+static_assert (!is_copy_assignable_type (^^EnumType [2][3][4]));
+static_assert (!is_copy_assignable_type (^^int * [3]));
+static_assert (!is_copy_assignable_type (^^int (* [][2]) (int)));
+static_assert (!is_copy_assignable_type (^^int (ClassType::* [2][3])));
+static_assert (!is_copy_assignable_type (^^int (ClassType::* [][2][3]) (int)));
+static_assert (!is_copy_assignable_type (^^ClassType (unsigned) const &));
+static_assert (!is_copy_assignable_type (^^bool (ClassType) const));
+static_assert (!is_copy_assignable_type (^^bool (...) &&));
+static_assert (!is_copy_assignable_type (^^EnumType (int, ...)));
+static_assert (!is_copy_assignable_type (^^NoexceptMoveAssignClass));
+static_assert (!is_copy_assignable_type (^^ExceptMoveAssignClass));
+static_assert (!is_copy_assignable_type (^^DeletedCopyAssignClass));
+static_assert (!is_copy_assignable_type (^^DeletedMoveAssignClass));
+
+static_assert (is_move_assignable_type (^^int));
+static_assert (is_move_assignable_type (^^float));
+static_assert (is_move_assignable_type (^^EnumType));
+static_assert (is_move_assignable_type (^^int *));
+static_assert (is_move_assignable_type (^^int (*) (int)));
+static_assert (is_move_assignable_type (^^int (ClassType::*)));
+static_assert (is_move_assignable_type (^^int (ClassType::*) (int)));
+static_assert (is_move_assignable_type (^^NoexceptMoveAssignClass));
+static_assert (is_move_assignable_type (^^ExceptMoveAssignClass));
+static_assert (is_move_assignable_type (^^NoexceptCopyAssignClass));
+static_assert (is_move_assignable_type (^^ExceptCopyAssignClass));
+static_assert (!is_move_assignable_type (^^void));
+static_assert (!is_move_assignable_type (^^int [2]));
+static_assert (!is_move_assignable_type (^^float [][3]));
+static_assert (!is_move_assignable_type (^^EnumType [2][3][4]));
+static_assert (!is_move_assignable_type (^^int * [3]));
+static_assert (!is_move_assignable_type (^^int (* [][2]) (int)));
+static_assert (!is_move_assignable_type (^^int (ClassType::* [2][3])));
+static_assert (!is_move_assignable_type (^^int (ClassType::* [][2][3]) (int)));
+static_assert (!is_move_assignable_type (^^ClassType (unsigned) const &));
+static_assert (!is_move_assignable_type (^^bool (ClassType) const));
+static_assert (!is_move_assignable_type (^^bool (...) &&));
+static_assert (!is_move_assignable_type (^^EnumType (int, ...)));
+static_assert (!is_move_assignable_type (^^DeletedCopyAssignClass));
+static_assert (!is_move_assignable_type (^^DeletedMoveAssignClass));
+
+static_assert (is_destructible_type (^^int));
+static_assert (is_destructible_type (^^const int));
+static_assert (is_destructible_type (^^bool));
+static_assert (is_destructible_type (^^const bool));
+static_assert (is_destructible_type (^^int *));
+static_assert (is_destructible_type (^^void *));
+static_assert (is_destructible_type (^^int N2::Der::*));
+static_assert (is_destructible_type (^^const int N2::Der::*));
+static_assert (is_destructible_type (^^void (N2::Der::*) () const));
+static_assert (is_destructible_type (^^void (*) ()));
+static_assert (is_destructible_type (^^N2::En));
+static_assert (is_destructible_type (^^const N2::En));
+static_assert (is_destructible_type (^^N2::En2));
+static_assert (is_destructible_type (^^const N2::En2));
+static_assert (is_destructible_type (^^N2::OpE));
+static_assert (is_destructible_type (^^const N2::OpE));
+static_assert (is_destructible_type (^^N2::OpSE));
+static_assert (is_destructible_type (^^const N2::OpSE));
+static_assert (is_destructible_type (^^std::nullptr_t));
+static_assert (is_destructible_type (^^const std::nullptr_t));
+static_assert (is_destructible_type (^^N2::Der));
+static_assert (is_destructible_type (^^const N2::Der));
+static_assert (is_destructible_type (^^N2::Aggr));
+static_assert (is_destructible_type (^^const N2::Aggr));
+static_assert (is_destructible_type (^^N2::E));
+static_assert (is_destructible_type (^^const N2::E));
+static_assert (is_destructible_type (^^N2::U1));
+static_assert (is_destructible_type (^^const N2::U1));
+static_assert (is_destructible_type (^^N2::Abstract1));
+static_assert (is_destructible_type (^^const N2::Abstract1));
+static_assert (is_destructible_type (^^int [1]));
+static_assert (is_destructible_type (^^const int [1]));
+static_assert (is_destructible_type (^^int [1][2]));
+static_assert (is_destructible_type (^^const int [1][2]));
+static_assert (is_destructible_type (^^int &));
+static_assert (is_destructible_type (^^int &&));
+static_assert (is_destructible_type (^^int (&) [1]));
+static_assert (is_destructible_type (^^const int (&) [1]));
+static_assert (is_destructible_type (^^void (&) ()));
+static_assert (is_destructible_type (^^N2::Ellipsis));
+static_assert (is_destructible_type (^^const N2::Ellipsis));
+static_assert (is_destructible_type (^^N2::Abstract2));
+static_assert (is_destructible_type (^^const N2::Abstract2));
+static_assert (is_destructible_type (^^N2::Aggr2));
+static_assert (is_destructible_type (^^const N2::Aggr2));
+static_assert (is_destructible_type (^^N2::DelDef));
+static_assert (is_destructible_type (^^const N2::DelDef));
+static_assert (is_destructible_type (^^N2::DelCopy));
+static_assert (is_destructible_type (^^const N2::DelCopy));
+static_assert (is_destructible_type (^^N2::DelEllipsis));
+static_assert (is_destructible_type (^^const N2::DelEllipsis));
+static_assert (is_destructible_type (^^std::initializer_list <int>));
+static_assert (is_destructible_type (^^const std::initializer_list <int>));
+static_assert (is_destructible_type (^^std::initializer_list <N2::Del>));
+static_assert (!is_destructible_type (^^void));
+static_assert (!is_destructible_type (^^const void));
+static_assert (!is_destructible_type (^^void ()));
+static_assert (!is_destructible_type (^^void () const));
+static_assert (!is_destructible_type (^^int []));
+static_assert (!is_destructible_type (^^const int []));
+static_assert (!is_destructible_type (^^N2::Del));
+static_assert (!is_destructible_type (^^const N2::Del));
+static_assert (!is_destructible_type (^^N2::AbstractDelDtor));
+static_assert (!is_destructible_type (^^const N2::AbstractDelDtor));
+static_assert (!is_destructible_type (^^int [][1]));
+static_assert (!is_destructible_type (^^const int [][1]));
+static_assert (!is_destructible_type (^^N2::Del [1]));
+static_assert (!is_destructible_type (^^const N2::Del [1]));
+static_assert (!is_destructible_type (^^N2::Del []));
+static_assert (!is_destructible_type (^^const N2::Del []));
+static_assert (!is_destructible_type (^^N2::NontrivialUnion));
+static_assert (is_destructible_type (^^N2::UnusualCopy));
+
+static_assert (is_trivially_default_constructible_type (^^int));
+static_assert (is_trivially_default_constructible_type (^^TType));
+static_assert (is_trivially_default_constructible_type (^^PODType));
+static_assert (!is_trivially_default_constructible_type (^^NType));
+static_assert (!is_trivially_default_constructible_type (^^SLType));
+static_assert (!is_trivially_default_constructible_type (^^N1::DelDef));
+static_assert (!is_trivially_default_constructible_type (^^N1::Abstract));
+static_assert (!is_trivially_default_constructible_type (^^N1::Ellipsis));
+static_assert (!is_trivially_default_constructible_type (^^N1::DelEllipsis));
+static_assert (!is_trivially_default_constructible_type (^^N1::Any));
+static_assert (!is_trivially_default_constructible_type (^^N1::DelCopy));
+static_assert (!is_trivially_default_constructible_type (^^N1::DelDtor));
+static_assert (!is_trivially_default_constructible_type (^^N1::Nontrivial));
+static_assert (is_trivially_default_constructible_type (^^HasTemplateCtor));
+
+static_assert (!is_trivially_default_constructible_type (^^int []));
+struct A { };
+static_assert (!is_trivially_default_constructible_type (^^A []));
+struct B { B () { } };
+static_assert (!is_trivially_default_constructible_type (^^B []));
+
+static_assert (is_trivially_copy_constructible_type (^^int));
+static_assert (is_trivially_copy_constructible_type (^^TType));
+static_assert (is_trivially_copy_constructible_type (^^PODType));
+static_assert (!is_trivially_copy_constructible_type (^^NType));
+static_assert (!is_trivially_copy_constructible_type (^^SLType));
+static_assert (is_trivially_copy_constructible_type (^^N1::DelDef));
+static_assert (!is_trivially_copy_constructible_type (^^N1::Abstract));
+static_assert (is_trivially_copy_constructible_type (^^N1::Ellipsis));
+static_assert (is_trivially_copy_constructible_type (^^N1::DelEllipsis));
+static_assert (is_trivially_copy_constructible_type (^^N1::Any));
+static_assert (!is_trivially_copy_constructible_type (^^N1::DelCopy));
+static_assert (!is_trivially_copy_constructible_type (^^N1::DelDtor));
+static_assert (!is_trivially_copy_constructible_type (^^N1::Nontrivial));
+static_assert (!is_trivially_copy_constructible_type (^^N1::UnusualCopy));
+static_assert (is_trivially_copy_constructible_type (^^CopyConsOnlyType));
+static_assert (!is_trivially_copy_constructible_type (^^MoveConsOnlyType));
+static_assert (is_trivially_copy_constructible_type (^^HasTemplateCCtor));
+static_assert (!is_trivially_copy_constructible_type (^^MoveOnly));
+static_assert (!is_trivially_copy_constructible_type (^^MoveOnly2));
+static_assert (!is_trivially_copy_constructible_type (^^void));
+
+static_assert (is_trivially_move_constructible_type (^^int));
+static_assert (is_trivially_move_constructible_type (^^TType));
+static_assert (is_trivially_move_constructible_type (^^PODType));
+static_assert (!is_trivially_move_constructible_type (^^NType));
+static_assert (!is_trivially_move_constructible_type (^^SLType));
+static_assert (is_trivially_move_constructible_type (^^N1::DelDef));
+static_assert (!is_trivially_move_constructible_type (^^N1::Abstract));
+static_assert (is_trivially_move_constructible_type (^^N1::Ellipsis));
+static_assert (is_trivially_move_constructible_type (^^N1::DelEllipsis));
+static_assert (is_trivially_move_constructible_type (^^N1::Any));
+static_assert (!is_trivially_move_constructible_type (^^N1::DelCopy));
+static_assert (!is_trivially_move_constructible_type (^^N1::DelDtor));
+static_assert (!is_trivially_move_constructible_type (^^N1::Nontrivial));
+static_assert (!is_trivially_move_constructible_type (^^N1::UnusualCopy));
+static_assert (!is_trivially_move_constructible_type (^^CopyConsOnlyType));
+static_assert (is_trivially_move_constructible_type (^^MoveConsOnlyType));
+static_assert (!is_trivially_move_constructible_type (^^HasTemplateCCtor));
+static_assert (is_trivially_move_constructible_type (^^MoveOnly));
+static_assert (!is_trivially_move_constructible_type (^^MoveOnly2));
+static_assert (!is_trivially_move_constructible_type (^^void));
+
+static_assert (!is_trivially_assignable_type (^^int, ^^int));
+static_assert (is_trivially_assignable_type (^^int &, ^^int));
+static_assert (is_trivially_assignable_type (^^int &, ^^int &));
+static_assert (is_trivially_assignable_type (^^int &, ^^int &&));
+static_assert (is_trivially_assignable_type (^^int &, ^^const int &));
+static_assert (!is_trivially_assignable_type (^^int &, ^^int *));
+static_assert (!is_trivially_assignable_type (^^int &, ^^void *));
+static_assert (!is_trivially_assignable_type (^^const int, ^^int));
+static_assert (!is_trivially_assignable_type (^^const int &, ^^int));
+static_assert (!is_trivially_assignable_type (^^const int &, ^^const int &));
+static_assert (is_trivially_assignable_type (^^const int *&, ^^int *));
+static_assert (!is_trivially_assignable_type (^^int *&, ^^const int *&));
+static_assert (!is_trivially_assignable_type (^^int *&, ^^const int &));
+static_assert (!is_trivially_assignable_type (^^const int *&, ^^void *));
+static_assert (is_trivially_assignable_type (^^const void *&, ^^void *));
+static_assert (is_trivially_assignable_type (^^const void *&, ^^int *));
+static_assert (is_trivially_assignable_type (^^TType, ^^TType));
+static_assert (is_trivially_assignable_type (^^TType &, ^^TType));
+static_assert (is_trivially_assignable_type (^^TType &, ^^TType &));
+static_assert (is_trivially_assignable_type (^^TType &, ^^TType &&));
+static_assert (is_trivially_assignable_type (^^TType &, ^^const TType &));
+static_assert (is_trivially_assignable_type (^^PODType, ^^PODType));
+static_assert (!is_trivially_assignable_type (^^NType &, ^^NType &));
+static_assert (is_trivially_assignable_type (^^SLType, ^^SLType));
+static_assert (is_trivially_assignable_type (^^N3::Empty, ^^N3::Empty));
+static_assert (!is_trivially_assignable_type (^^N3::Abstract, ^^N3::Abstract));
+static_assert (is_trivially_assignable_type (^^N3::Ellipsis, ^^N3::Ellipsis));
+static_assert (is_trivially_assignable_type (^^N3::DelEllipsis, ^^N3::DelEllipsis));
+static_assert (is_trivially_assignable_type (^^N3::Any, ^^N3::Any));
+static_assert (is_trivially_assignable_type (^^N3::DelDef, ^^N3::DelDef));
+static_assert (is_trivially_assignable_type (^^N3::DelCopy, ^^N3::DelCopy));
+static_assert (!is_trivially_assignable_type (^^N3::Nontrivial, ^^N3::Nontrivial));
+static_assert (is_trivially_assignable_type (^^N3::AnyAssign, ^^N3::AnyAssign));
+static_assert (is_trivially_assignable_type (^^N3::DelAnyAssign, ^^N3::DelAnyAssign));
+static_assert (is_trivially_assignable_type (^^N3::DelCopyAssign, ^^N3::DelCopyAssign));
+static_assert (is_trivially_assignable_type (^^N3::MO, ^^N3::MO));
+static_assert (is_trivially_assignable_type (^^N3::MO, ^^N3::MO &&));
+static_assert (!is_trivially_assignable_type (^^N3::MO, ^^N3::MO &));
+static_assert (!is_trivially_assignable_type (^^N3::MO, ^^const N3::MO &));
+static_assert (!is_trivially_assignable_type (^^CopyConsOnlyType, ^^CopyConsOnlyType));
+static_assert (!is_trivially_assignable_type (^^CopyConsOnlyType, ^^const CopyConsOnlyType &));
+static_assert (!is_trivially_assignable_type (^^MoveConsOnlyType, ^^MoveConsOnlyType));
+static_assert (!is_trivially_assignable_type (^^MoveConsOnlyType, ^^MoveConsOnlyType &&));
+static_assert (!is_trivially_assignable_type (^^HasTemplateCAssign, ^^HasTemplateCAssign));
+static_assert (is_trivially_assignable_type (^^HasTemplateCAssign, ^^const HasTemplateCAssign &));
+static_assert (is_trivially_assignable_type (^^ClassType, ^^DerivedType));
+static_assert (is_trivially_assignable_type (^^ClassType, ^^DerivedType &));
+static_assert (is_trivially_assignable_type (^^ClassType, ^^DerivedType &&));
+static_assert (is_trivially_assignable_type (^^ClassType, ^^const DerivedType &));
+static_assert (is_trivially_assignable_type (^^MoveOnly3, ^^MoveOnly3));
+static_assert (is_trivially_assignable_type (^^MoveOnly3, ^^MoveOnly3 &&));
+static_assert (!is_trivially_assignable_type (^^MoveOnly3, ^^MoveOnly3 &));
+static_assert (!is_trivially_assignable_type (^^MoveOnly3, ^^const MoveOnly3 &));
+static_assert (!is_trivially_assignable_type (^^MoveOnly4, ^^MoveOnly4));
+
+static_assert (is_trivially_copy_assignable_type (^^int));
+static_assert (is_trivially_copy_assignable_type (^^TType));
+static_assert (is_trivially_copy_assignable_type (^^PODType));
+static_assert (!is_trivially_copy_assignable_type (^^NType));
+static_assert (is_trivially_copy_assignable_type (^^SLType));
+static_assert (is_trivially_copy_assignable_type (^^N3::Empty));
+static_assert (!is_trivially_copy_assignable_type (^^N3::Abstract));
+static_assert (is_trivially_copy_assignable_type (^^N3::Ellipsis));
+static_assert (is_trivially_copy_assignable_type (^^N3::DelEllipsis));
+static_assert (is_trivially_copy_assignable_type (^^N3::Any));
+static_assert (is_trivially_copy_assignable_type (^^N3::DelDef));
+static_assert (is_trivially_copy_assignable_type (^^N3::DelCopy));
+static_assert (!is_trivially_copy_assignable_type (^^N3::Nontrivial));
+static_assert (is_trivially_copy_assignable_type (^^N3::AnyAssign));
+static_assert (is_trivially_copy_assignable_type (^^N3::DelAnyAssign));
+static_assert (!is_trivially_copy_assignable_type (^^N3::DelCopyAssign));
+static_assert (!is_trivially_copy_assignable_type (^^N3::MO));
+static_assert (!is_trivially_copy_assignable_type (^^CopyConsOnlyType));
+static_assert (!is_trivially_copy_assignable_type (^^MoveConsOnlyType));
+static_assert (is_trivially_copy_assignable_type (^^HasTemplateCAssign));
+static_assert (!is_trivially_copy_assignable_type (^^MoveOnly3));
+static_assert (!is_trivially_copy_assignable_type (^^MoveOnly4));
+static_assert (!is_trivially_copy_assignable_type (^^void));
+
+static_assert (is_trivially_move_assignable_type (^^int));
+static_assert (is_trivially_move_assignable_type (^^TType));
+static_assert (is_trivially_move_assignable_type (^^PODType));
+static_assert (!is_trivially_move_assignable_type (^^NType));
+static_assert (is_trivially_move_assignable_type (^^SLType));
+static_assert (is_trivially_move_assignable_type (^^N3::Empty));
+static_assert (!is_trivially_move_assignable_type (^^N3::Abstract));
+static_assert (is_trivially_move_assignable_type (^^N3::Ellipsis));
+static_assert (is_trivially_move_assignable_type (^^N3::DelEllipsis));
+static_assert (is_trivially_move_assignable_type (^^N3::Any));
+static_assert (is_trivially_move_assignable_type (^^N3::DelDef));
+static_assert (is_trivially_move_assignable_type (^^N3::DelCopy));
+static_assert (!is_trivially_move_assignable_type (^^N3::Nontrivial));
+static_assert (is_trivially_move_assignable_type (^^N3::AnyAssign));
+static_assert (is_trivially_move_assignable_type (^^N3::DelAnyAssign));
+static_assert (is_trivially_move_assignable_type (^^N3::DelCopyAssign));
+static_assert (is_trivially_move_assignable_type (^^N3::MO));
+static_assert (!is_trivially_move_assignable_type (^^CopyConsOnlyType));
+static_assert (!is_trivially_move_assignable_type (^^MoveConsOnlyType));
+static_assert (!is_trivially_move_assignable_type (^^HasTemplateCAssign));
+static_assert (is_trivially_move_assignable_type (^^MoveOnly3));
+static_assert (!is_trivially_move_assignable_type (^^MoveOnly4));
+static_assert (!is_trivially_move_assignable_type (^^void));
+
+static_assert (is_trivially_destructible_type (^^int));
+static_assert (is_trivially_destructible_type (^^TType));
+static_assert (is_trivially_destructible_type (^^PODType));
+static_assert (!is_trivially_destructible_type (^^NType));
+static_assert (!is_trivially_destructible_type (^^SLType));
+
+static_assert (is_nothrow_default_constructible_type (^^int));
+static_assert (is_nothrow_default_constructible_type (^^float));
+static_assert (is_nothrow_default_constructible_type (^^EnumType));
+static_assert (is_nothrow_default_constructible_type (^^int *));
+static_assert (is_nothrow_default_constructible_type (^^int (*) (int)));
+static_assert (is_nothrow_default_constructible_type (^^int (ClassType:: *)));
+static_assert (is_nothrow_default_constructible_type (^^int (ClassType:: *) (int)));
+static_assert (is_nothrow_default_constructible_type (^^int [2]));
+static_assert (is_nothrow_default_constructible_type (^^EnumType [2][3][4]));
+static_assert (is_nothrow_default_constructible_type (^^int * [3]));
+static_assert (is_nothrow_default_constructible_type (^^int (ClassType::* [2][3])));
+static_assert (is_nothrow_default_constructible_type (^^ClassType));
+static_assert (is_nothrow_default_constructible_type (^^NoexceptDefaultClass));
+static_assert (!is_nothrow_default_constructible_type (^^void));
+static_assert (!is_nothrow_default_constructible_type (^^int []));
+static_assert (!is_nothrow_default_constructible_type (^^float [][3]));
+static_assert (!is_nothrow_default_constructible_type (^^int (* [][2]) (int)));
+static_assert (!is_nothrow_default_constructible_type (^^int (ClassType:: * [][2][3]) (int)));
+static_assert (!is_nothrow_default_constructible_type (^^ThrowDefaultClass));
+static_assert (!is_nothrow_default_constructible_type (^^ExceptDefaultClass));
+
+static_assert (is_nothrow_copy_constructible_type (^^int));
+static_assert (is_nothrow_copy_constructible_type (^^float));
+static_assert (is_nothrow_copy_constructible_type (^^EnumType));
+static_assert (is_nothrow_copy_constructible_type (^^int *));
+static_assert (is_nothrow_copy_constructible_type (^^int (*) (int)));
+static_assert (is_nothrow_copy_constructible_type (^^int (ClassType:: *)));
+static_assert (is_nothrow_copy_constructible_type (^^int (ClassType:: *) (int)));
+static_assert (is_nothrow_copy_constructible_type (^^NoexceptCopyConsClass));
+static_assert (is_nothrow_copy_constructible_type (^^const NoexceptCopyConsClass));
+static_assert (!is_nothrow_copy_constructible_type (^^void));
+static_assert (!is_nothrow_copy_constructible_type (^^int [2]));
+static_assert (!is_nothrow_copy_constructible_type (^^int []));
+static_assert (!is_nothrow_copy_constructible_type (^^float [][3]));
+static_assert (!is_nothrow_copy_constructible_type (^^EnumType [2][3][4]));
+static_assert (!is_nothrow_copy_constructible_type (^^int * [3]));
+static_assert (!is_nothrow_copy_constructible_type (^^int (* [][2]) (int)));
+static_assert (!is_nothrow_copy_constructible_type (^^int (ClassType:: * [2][3])));
+static_assert (!is_nothrow_copy_constructible_type (^^int (ClassType:: * [][2][3]) (int)));
+static_assert (!is_nothrow_copy_constructible_type (^^ClassType (unsigned) const &));
+static_assert (!is_nothrow_copy_constructible_type (^^bool (ClassType) const));
+static_assert (!is_nothrow_copy_constructible_type (^^bool (...) &&));
+static_assert (!is_nothrow_copy_constructible_type (^^EnumType (int, ...)));
+static_assert (!is_nothrow_copy_constructible_type (^^volatile NoexceptCopyConsClass));
+static_assert (!is_nothrow_copy_constructible_type (^^ThrowCopyConsClass));
+static_assert (!is_nothrow_copy_constructible_type (^^ExceptCopyConsClass));
+
+static_assert (is_nothrow_move_constructible_type (^^int));
+static_assert (is_nothrow_move_constructible_type (^^float));
+static_assert (is_nothrow_move_constructible_type (^^EnumType));
+static_assert (is_nothrow_move_constructible_type (^^int *));
+static_assert (is_nothrow_move_constructible_type (^^int (*) (int)));
+static_assert (is_nothrow_move_constructible_type (^^int (ClassType:: *)));
+static_assert (is_nothrow_move_constructible_type (^^int (ClassType:: *) (int)));
+static_assert (is_nothrow_move_constructible_type (^^NoexceptMoveConsClass));
+static_assert (!is_nothrow_move_constructible_type (^^void));
+static_assert (!is_nothrow_move_constructible_type (^^int [2]));
+static_assert (!is_nothrow_move_constructible_type (^^int []));
+static_assert (!is_nothrow_move_constructible_type (^^float [][3]));
+static_assert (!is_nothrow_move_constructible_type (^^EnumType [2][3][4]));
+static_assert (!is_nothrow_move_constructible_type (^^int * [3]));
+static_assert (!is_nothrow_move_constructible_type (^^int (* [][2]) (int)));
+static_assert (!is_nothrow_move_constructible_type (^^int (ClassType:: * [2][3])));
+static_assert (!is_nothrow_move_constructible_type (^^int (ClassType:: * [][2][3]) (int)));
+static_assert (!is_nothrow_move_constructible_type (^^ClassType (unsigned) const &));
+static_assert (!is_nothrow_move_constructible_type (^^bool (ClassType) const));
+static_assert (!is_nothrow_move_constructible_type (^^bool (...) &&));
+static_assert (!is_nothrow_move_constructible_type (^^EnumType (int, ...)));
+static_assert (!is_nothrow_move_constructible_type (^^const NoexceptMoveConsClass));
+static_assert (!is_nothrow_move_constructible_type (^^volatile NoexceptMoveConsClass));
+static_assert (!is_nothrow_move_constructible_type (^^ThrowMoveConsClass));
+static_assert (!is_nothrow_move_constructible_type (^^ExceptMoveConsClass));
+
+static_assert (is_nothrow_assignable_type (^^int &, ^^int));
+static_assert (is_nothrow_assignable_type (^^int &, ^^const int));
+static_assert (is_nothrow_assignable_type (^^NoexceptCopyAssignClass &, ^^const NoexceptCopyAssignClass &));
+static_assert (is_nothrow_assignable_type (^^NoexceptMoveAssignClass &, ^^NoexceptMoveAssignClass &&));
+static_assert (is_nothrow_assignable_type (^^NoexceptCopyAssignClass &, ^^NoexceptCopyAssignClass &&));
+static_assert (!is_nothrow_assignable_type (^^int, ^^int));
+static_assert (!is_nothrow_assignable_type (^^int, ^^const int));
+static_assert (!is_nothrow_assignable_type (^^ExceptCopyAssignClass &, ^^const ExceptCopyAssignClass &));
+static_assert (!is_nothrow_assignable_type (^^ExceptMoveAssignClass &, ^^ExceptMoveAssignClass &&));
+static_assert (!is_nothrow_assignable_type (^^NoexceptMoveAssignClass &, ^^const NoexceptMoveAssignClass &));
+
+static_assert (is_nothrow_copy_assignable_type (^^int));
+static_assert (is_nothrow_copy_assignable_type (^^float));
+static_assert (is_nothrow_copy_assignable_type (^^EnumType));
+static_assert (is_nothrow_copy_assignable_type (^^int *));
+static_assert (is_nothrow_copy_assignable_type (^^int (*) (int)));
+static_assert (is_nothrow_copy_assignable_type (^^int (ClassType:: *)));
+static_assert (is_nothrow_copy_assignable_type (^^int (ClassType:: *) (int)));
+static_assert (is_nothrow_copy_assignable_type (^^NoexceptCopyAssignClass));
+static_assert (!is_nothrow_copy_assignable_type (^^void));
+static_assert (!is_nothrow_copy_assignable_type (^^int [2]));
+static_assert (!is_nothrow_copy_assignable_type (^^float [][3]));
+static_assert (!is_nothrow_copy_assignable_type (^^EnumType [2][3][4]));
+static_assert (!is_nothrow_copy_assignable_type (^^int * [3]));
+static_assert (!is_nothrow_copy_assignable_type (^^int (* [][2]) (int)));
+static_assert (!is_nothrow_copy_assignable_type (^^int (ClassType:: * [2][3])));
+static_assert (!is_nothrow_copy_assignable_type (^^int (ClassType:: * [][2][3]) (int)));
+static_assert (!is_nothrow_copy_assignable_type (^^ClassType (unsigned) const &));
+static_assert (!is_nothrow_copy_assignable_type (^^bool (ClassType) const));
+static_assert (!is_nothrow_copy_assignable_type (^^bool (...) &&));
+static_assert (!is_nothrow_copy_assignable_type (^^EnumType (int, ...)));
+static_assert (!is_nothrow_copy_assignable_type (^^ExceptCopyAssignClass));
+static_assert (!is_nothrow_copy_assignable_type (^^NoexceptMoveAssignClass));
+static_assert (!is_nothrow_copy_assignable_type (^^ExceptMoveAssignClass));
+static_assert (!is_nothrow_copy_assignable_type (^^DeletedCopyAssignClass));
+static_assert (!is_nothrow_copy_assignable_type (^^DeletedMoveAssignClass));
+
+static_assert (is_nothrow_move_assignable_type (^^int));
+static_assert (is_nothrow_move_assignable_type (^^float));
+static_assert (is_nothrow_move_assignable_type (^^EnumType));
+static_assert (is_nothrow_move_assignable_type (^^int *));
+static_assert (is_nothrow_move_assignable_type (^^int (*) (int)));
+static_assert (is_nothrow_move_assignable_type (^^int (ClassType:: *)));
+static_assert (is_nothrow_move_assignable_type (^^int (ClassType:: *) (int)));
+static_assert (is_nothrow_move_assignable_type (^^NoexceptMoveAssignClass));
+static_assert (is_nothrow_move_assignable_type (^^NoexceptCopyAssignClass));
+static_assert (!is_nothrow_move_assignable_type (^^void));
+static_assert (!is_nothrow_move_assignable_type (^^int [2]));
+static_assert (!is_nothrow_move_assignable_type (^^float [][3]));
+static_assert (!is_nothrow_move_assignable_type (^^EnumType [2][3][4]));
+static_assert (!is_nothrow_move_assignable_type (^^int * [3]));
+static_assert (!is_nothrow_move_assignable_type (^^int (* [][2]) (int)));
+static_assert (!is_nothrow_move_assignable_type (^^int (ClassType:: * [2][3])));
+static_assert (!is_nothrow_move_assignable_type (^^int (ClassType:: * [][2][3]) (int)));
+static_assert (!is_nothrow_move_assignable_type (^^ClassType (unsigned) const &));
+static_assert (!is_nothrow_move_assignable_type (^^bool (ClassType) const));
+static_assert (!is_nothrow_move_assignable_type (^^bool (...) &&));
+static_assert (!is_nothrow_move_assignable_type (^^EnumType (int, ...)));
+static_assert (!is_nothrow_move_assignable_type (^^ExceptMoveAssignClass));
+static_assert (!is_nothrow_move_assignable_type (^^ExceptCopyAssignClass));
+static_assert (!is_nothrow_move_assignable_type (^^DeletedMoveAssignClass));
+static_assert (!is_nothrow_move_assignable_type (^^DeletedCopyAssignClass));
+
+static_assert (is_nothrow_destructible_type (^^int));
+static_assert (is_nothrow_destructible_type (^^const int));
+static_assert (is_nothrow_destructible_type (^^const volatile int));
+static_assert (is_nothrow_destructible_type (^^int [12]));
+static_assert (is_nothrow_destructible_type (^^const int [12]));
+static_assert (is_nothrow_destructible_type (^^const volatile int [12]));
+static_assert (is_nothrow_destructible_type (^^decltype (nullptr)));
+static_assert (is_nothrow_destructible_type (^^std::initializer_list<int>));
+static_assert (is_nothrow_destructible_type (^^std::initializer_list<decltype (nullptr)>));
+static_assert (is_nothrow_destructible_type (^^std::initializer_list<N2::TD1>));
+static_assert (is_nothrow_destructible_type (^^std::initializer_list<N2::TD2>));
+static_assert (is_nothrow_destructible_type (^^N2::E));
+static_assert (is_nothrow_destructible_type (^^const N2::E));
+static_assert (is_nothrow_destructible_type (^^const volatile N2::E));
+static_assert (is_nothrow_destructible_type (^^N2::NTD1));
+static_assert (is_nothrow_destructible_type (^^N2::NTD2));
+static_assert (is_nothrow_destructible_type (^^N2::NTD3));
+static_assert (is_nothrow_destructible_type (^^N2::Aggr));
+static_assert (is_nothrow_destructible_type (^^N2::U1));
+static_assert (is_nothrow_destructible_type (^^void (*) ()));
+static_assert (is_nothrow_destructible_type (^^void *));
+static_assert (is_nothrow_destructible_type (^^int &));
+static_assert (is_nothrow_destructible_type (^^N2::TD1 &));
+static_assert (is_nothrow_destructible_type (^^N2::TD2 &));
+static_assert (is_nothrow_destructible_type (^^N2::TD1 *));
+static_assert (is_nothrow_destructible_type (^^N2::TD2 *));
+static_assert (is_nothrow_destructible_type (^^void (&) ()));
+static_assert (is_nothrow_destructible_type (^^void (&&) ()));
+static_assert (is_nothrow_destructible_type (^^N2::En));
+static_assert (is_nothrow_destructible_type (^^N2::En *));
+static_assert (is_nothrow_destructible_type (^^N2::En &));
+static_assert (is_nothrow_destructible_type (^^N2::En2));
+static_assert (is_nothrow_destructible_type (^^N2::En2 *));
+static_assert (is_nothrow_destructible_type (^^N2::En2 &));
+static_assert (is_nothrow_destructible_type (^^N2::TD1 (&) (N2::Aggr2, N2::TD2)));
+static_assert (is_nothrow_destructible_type (^^N2::TD1 (*) (N2::Aggr2, N2::TD2)));
+static_assert (is_nothrow_destructible_type (^^N2::Abstract1));
+static_assert (is_nothrow_destructible_type (^^N2::Der));
+static_assert (is_nothrow_destructible_type (^^N2::Del &));
+static_assert (is_nothrow_destructible_type (^^N2::Del2 &));
+static_assert (is_nothrow_destructible_type (^^N2::Del3 &));
+static_assert (is_nothrow_destructible_type (^^N2::Del (&) [1]));
+static_assert (is_nothrow_destructible_type (^^N2::Del2 (&) [2]));
+static_assert (is_nothrow_destructible_type (^^N2::Del3 (&) [3]));
+static_assert (is_nothrow_destructible_type (^^N2::Del &&));
+static_assert (is_nothrow_destructible_type (^^N2::Del2 &&));
+static_assert (is_nothrow_destructible_type (^^N2::Del3 &));
+static_assert (is_nothrow_destructible_type (^^N2::Del (&&) [1]));
+static_assert (is_nothrow_destructible_type (^^N2::Del2 (&&) [2]));
+static_assert (is_nothrow_destructible_type (^^N2::Del3 (&&) [3]));
+static_assert (is_nothrow_destructible_type (^^N2::Ut &));
+static_assert (is_nothrow_destructible_type (^^N2::Ut &&));
+static_assert (is_nothrow_destructible_type (^^N2::Ut *));
+static_assert (is_nothrow_destructible_type (^^N2::Abstract2 &));
+static_assert (is_nothrow_destructible_type (^^N2::Abstract3 &));
+static_assert (is_nothrow_destructible_type (^^N2::Abstract2 *));
+static_assert (is_nothrow_destructible_type (^^N2::Abstract3 *));
+static_assert (!is_nothrow_destructible_type (^^void));
+static_assert (!is_nothrow_destructible_type (^^const void));
+static_assert (!is_nothrow_destructible_type (^^void ()));
+static_assert (!is_nothrow_destructible_type (^^void () const));
+static_assert (!is_nothrow_destructible_type (^^N2::TD1 (N2::Aggr2, N2::TD2)));
+static_assert (!is_nothrow_destructible_type (^^int []));
+static_assert (!is_nothrow_destructible_type (^^const int []));
+static_assert (!is_nothrow_destructible_type (^^const volatile int []));
+static_assert (!is_nothrow_destructible_type (^^int [][123]));
+static_assert (!is_nothrow_destructible_type (^^N2::TD1));
+static_assert (!is_nothrow_destructible_type (^^N2::TD2));
+static_assert (!is_nothrow_destructible_type (^^N2::Aggr2));
+static_assert (!is_nothrow_destructible_type (^^N2::Aggr2 [1]));
+static_assert (!is_nothrow_destructible_type (^^N2::TD1 [1][2]));
+static_assert (!is_nothrow_destructible_type (^^N2::Ut));
+static_assert (!is_nothrow_destructible_type (^^N2::Ut [3]));
+static_assert (!is_nothrow_destructible_type (^^N2::AbstractDelDtor));
+static_assert (!is_nothrow_destructible_type (^^N2::Abstract2));
+static_assert (!is_nothrow_destructible_type (^^N2::Abstract3));
+static_assert (!is_nothrow_destructible_type (^^N2::Der2));
+static_assert (!is_nothrow_destructible_type (^^N2::Del));
+static_assert (!is_nothrow_destructible_type (^^N2::Del2));
+static_assert (!is_nothrow_destructible_type (^^N2::Del3));
+static_assert (!is_nothrow_destructible_type (^^N2::Del [1]));
+static_assert (!is_nothrow_destructible_type (^^N2::Del2 [2]));
+static_assert (!is_nothrow_destructible_type (^^N2::Del3 [3]));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait8.C b/gcc/testsuite/g++.dg/reflect/type_trait8.C
new file mode 100644 (file)
index 0000000..33f0409
--- /dev/null
@@ -0,0 +1,129 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type properties.
+
+#include <meta>
+using namespace std::meta;
+
+class ClassType { };
+class DerivedType : public ClassType { };
+enum EnumType { e0 };
+class AbstractClass { virtual void rotate (int) = 0; };
+class PolymorphicClass { virtual void rotate (int); };
+class DerivedPolymorphic : public PolymorphicClass { };
+class VirtualDestructorClass { virtual ~VirtualDestructorClass (); };
+
+static_assert (has_virtual_destructor (^^VirtualDestructorClass));
+static_assert (!has_virtual_destructor (^^PolymorphicClass));
+static_assert (!has_virtual_destructor (^^DerivedPolymorphic));
+static_assert (!has_virtual_destructor (^^AbstractClass));
+static_assert (!has_virtual_destructor (^^void));
+static_assert (!has_virtual_destructor (^^int (int)));
+static_assert (!has_virtual_destructor (^^int &));
+static_assert (!has_virtual_destructor (^^EnumType));
+static_assert (!has_virtual_destructor (^^ClassType));
+static_assert (!has_virtual_destructor (^^DerivedType));
+
+static_assert (has_unique_object_representations (^^char));
+static_assert (has_unique_object_representations (^^unsigned char));
+static_assert (has_unique_object_representations (^^signed char));
+static_assert (has_unique_object_representations (^^unsigned));
+static_assert (has_unique_object_representations (^^bool));
+enum E3 : unsigned { };
+static_assert (has_unique_object_representations (^^E3));
+static_assert (has_unique_object_representations (^^unsigned [3]));
+static_assert (has_unique_object_representations (^^unsigned [3][2]));
+static_assert (has_unique_object_representations (^^unsigned []));
+static_assert (has_unique_object_representations (^^unsigned [][2]));
+static_assert (has_unique_object_representations (^^E3 [3]));
+static_assert (has_unique_object_representations (^^E3 [3][2]));
+static_assert (has_unique_object_representations (^^E3 []));
+static_assert (has_unique_object_representations (^^E3 [][2]));
+struct Padded { char c1; alignas(4) char c2; };
+struct Bitfield { int i : 3; };
+struct Aligned { alignas(4) char c; };
+static_assert (!has_unique_object_representations (^^void));
+static_assert (!has_unique_object_representations (^^float));
+static_assert (!has_unique_object_representations (^^Padded));
+static_assert (!has_unique_object_representations (^^Padded [2]));
+static_assert (!has_unique_object_representations (^^Padded [2][1]));
+static_assert (!has_unique_object_representations (^^Padded []));
+static_assert (!has_unique_object_representations (^^Padded [][1]));
+static_assert (!has_unique_object_representations (^^Bitfield));
+static_assert (!has_unique_object_representations (^^Bitfield [2]));
+static_assert (!has_unique_object_representations (^^Bitfield [2][1]));
+static_assert (!has_unique_object_representations (^^Bitfield []));
+static_assert (!has_unique_object_representations (^^Bitfield [][1]));
+static_assert (!has_unique_object_representations (^^Aligned));
+static_assert (!has_unique_object_representations (^^Aligned [2]));
+static_assert (!has_unique_object_representations (^^Aligned [2][1]));
+static_assert (!has_unique_object_representations (^^Aligned []));
+static_assert (!has_unique_object_representations (^^Aligned [][1]));
+
+struct A { A(); };
+struct B { operator int (); explicit operator int && (); };
+struct C { operator int (); explicit operator int & (); };
+
+static_assert (!reference_constructs_from_temporary (^^int, ^^int));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^void));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^const volatile void));
+static_assert (!reference_constructs_from_temporary (^^void, ^^void));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^int));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^int &));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^int &&));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^long));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^long &));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^long &&));
+static_assert (reference_constructs_from_temporary (^^const int &, ^^int));
+static_assert (!reference_constructs_from_temporary (^^const int &, ^^int &));
+static_assert (!reference_constructs_from_temporary (^^const int &, ^^int &&));
+static_assert (reference_constructs_from_temporary (^^const int &, ^^long));
+static_assert (reference_constructs_from_temporary (^^const int &, ^^long &));
+static_assert (reference_constructs_from_temporary (^^const int &, ^^long &&));
+static_assert (reference_constructs_from_temporary (^^int &&, ^^int));
+static_assert (!reference_constructs_from_temporary (^^int &&, ^^int &));
+static_assert (!reference_constructs_from_temporary (^^int &&, ^^int &&));
+static_assert (reference_constructs_from_temporary (^^int &&, ^^long));
+static_assert (reference_constructs_from_temporary (^^int &&, ^^long &));
+static_assert (reference_constructs_from_temporary (^^int &&, ^^long &&));
+static_assert (reference_constructs_from_temporary (^^const A &, ^^A));
+static_assert (!reference_constructs_from_temporary (^^const A &, ^^A &&));
+static_assert (reference_constructs_from_temporary (^^A &&, ^^A));
+static_assert (!reference_constructs_from_temporary (^^int &, ^^int []));
+static_assert (!reference_constructs_from_temporary (^^const int &, ^^int []));
+static_assert (!reference_constructs_from_temporary (^^int &&, ^^int []));
+static_assert (!reference_constructs_from_temporary (^^int &&, ^^B));
+static_assert (!reference_constructs_from_temporary (^^const int &, ^^C));
+static_assert (reference_constructs_from_temporary (^^const std::string &, ^^const char *));
+
+static_assert (!reference_converts_from_temporary (^^int, ^^int));
+static_assert (!reference_converts_from_temporary (^^int &, ^^void));
+static_assert (!reference_converts_from_temporary (^^int &, ^^const volatile void));
+static_assert (!reference_converts_from_temporary (^^void, ^^void));
+static_assert (!reference_converts_from_temporary (^^int &, ^^int));
+static_assert (!reference_converts_from_temporary (^^int &, ^^int &));
+static_assert (!reference_converts_from_temporary (^^int &, ^^int &&));
+static_assert (!reference_converts_from_temporary (^^int &, ^^long));
+static_assert (!reference_converts_from_temporary (^^int &, ^^long &));
+static_assert (!reference_converts_from_temporary (^^int &, ^^long &&));
+static_assert (reference_converts_from_temporary (^^const int &, ^^int));
+static_assert (!reference_converts_from_temporary (^^const int &, ^^int &));
+static_assert (!reference_converts_from_temporary (^^const int &, ^^int &&));
+static_assert (reference_converts_from_temporary (^^const int &, ^^long));
+static_assert (reference_converts_from_temporary (^^const int &, ^^long &));
+static_assert (reference_converts_from_temporary (^^const int &, ^^long &&));
+static_assert (reference_converts_from_temporary (^^int &&, ^^int));
+static_assert (!reference_converts_from_temporary (^^int &&, ^^int &));
+static_assert (!reference_converts_from_temporary (^^int &&, ^^int &&));
+static_assert (reference_converts_from_temporary (^^int &&, ^^long));
+static_assert (reference_converts_from_temporary (^^int &&, ^^long &));
+static_assert (reference_converts_from_temporary (^^int &&, ^^long &&));
+static_assert (reference_converts_from_temporary (^^const A &, ^^A));
+static_assert (!reference_converts_from_temporary (^^const A &, ^^A &&));
+static_assert (reference_converts_from_temporary (^^A &&, ^^A));
+static_assert (!reference_converts_from_temporary (^^int &, ^^int []));
+static_assert (!reference_converts_from_temporary (^^const int &, ^^int []));
+static_assert (!reference_converts_from_temporary (^^int &&, ^^int []));
+static_assert (reference_converts_from_temporary (^^int &&, ^^B));
+static_assert (reference_converts_from_temporary (^^const int &, ^^C));
+static_assert (reference_converts_from_temporary (^^const std::string &, ^^const char *));
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait9.C b/gcc/testsuite/g++.dg/reflect/type_trait9.C
new file mode 100644 (file)
index 0000000..4790f16
--- /dev/null
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test reflection type traits [meta.reflection.traits], type property
+// queries.
+
+#include <meta>
+using namespace std::meta;
+
+class ClassType { };
+
+static_assert (rank (^^int) == 0);
+static_assert (rank (^^const void) == 0);
+static_assert (rank (^^char &) == 0);
+static_assert (rank (^^long &&) == 0);
+static_assert (rank (^^int [2]) == 1);
+static_assert (rank (^^int [][4]) == 2);
+static_assert (rank (^^int [2][2][4][4][6][6]) == 6);
+static_assert (rank (^^int []) == 1);
+static_assert (rank (^^ClassType) == 0);
+static_assert (rank (^^ClassType [2]) == 1);
+static_assert (rank (^^ClassType [][4]) == 2);
+static_assert (rank (^^ClassType [2][2][4][4][6][6]) == 6);
+static_assert (rank (^^ClassType []) == 1);
+using D = ClassType [2][2][4][4][6][6][6];
+static_assert (rank (^^D) == 7);
+
+static_assert (extent (^^int) == 0);
+static_assert (extent (^^const void, 0) == 0);
+static_assert (extent (^^char &, 42) == 0);
+static_assert (extent (^^long &&, 18) == 0);
+static_assert (extent (^^int [2]) == 2);
+static_assert (extent (^^int [2][4]) == 2);
+static_assert (extent (^^int [][4]) == 0);
+static_assert (extent (^^int []) == 0);
+static_assert (extent (^^int, 0) == 0);
+static_assert (extent (^^int [2], 0) == 2);
+static_assert (extent (^^int [2][4], 0) == 2);
+static_assert (extent (^^int [][4], 0) == 0);
+static_assert (extent (^^int [], 0) == 0);
+static_assert (extent (^^int, 1) == 0);
+static_assert (extent (^^int [2], 1) == 0);
+static_assert (extent (^^int [2][4], 1) == 4);
+static_assert (extent (^^int [][4], 1) == 4);
+static_assert (extent (^^int [10][4][6][8][12][2], 4) == 12);
+static_assert (extent (^^int [], 1) == 0);
+static_assert (extent (^^ClassType) == 0);
+static_assert (extent (^^ClassType [2]) == 2);
+static_assert (extent (^^ClassType [2][4]) == 2);
+static_assert (extent (^^ClassType [][4]) == 0);
+static_assert (extent (^^ClassType, 0) == 0);
+static_assert (extent (^^ClassType [2], 0) == 2);
+static_assert (extent (^^ClassType [2][4], 0) == 2);
+static_assert (extent (^^ClassType [][4], 0) == 0);
+static_assert (extent (^^ClassType, 1) == 0);
+static_assert (extent (^^ClassType [2], 1) == 0);
+static_assert (extent (^^ClassType [2][4], 1) == 4);
+static_assert (extent (^^ClassType [][4], 1) == 4);
+static_assert (extent (^^ClassType [10][4][6][8][12][2], 4) == 12);
+
+__extension__ void
+ext ()
+{
+  static_assert (rank (^^int [0]) == 1);
+  static_assert (extent (^^int [0]) == 0);
+  static_assert (extent (^^int [0], 0) == 0);
+  static_assert (extent (^^int [0], 1) == 0);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/u8display_string_of1.C b/gcc/testsuite/g++.dg/reflect/u8display_string_of1.C
new file mode 100644 (file)
index 0000000..693162e
--- /dev/null
@@ -0,0 +1,230 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::u8display_string_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr info null_reflection;
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T () {}
+  T (const T &) {}
+  ~T () {}
+};
+struct U {
+  int u;
+  int v : 5;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+namespace {
+  namespace NS2 {}
+};
+namespace NS3 {
+  namespace {
+    namespace {
+      namespace NS4 {}
+    }
+  }
+};
+enum { Z };
+
+constexpr auto ctx = access_context::current ();
+
+struct AN { int a; long b; char c; };
+
+[[=1, =AN { 1, 42, ' ' }]] void bar (long, const T f, int g[2], T &);
+
+struct V1 {
+  constexpr V1 (int) {}
+};
+struct V2 {
+  V2 &operator = (const V2 &);
+};
+struct V3 {
+  V3 &operator = (V3 &&);
+};
+struct V4 {
+  V4 &operator += (const V4 &);
+};
+struct V5 {
+  operator int ();
+};
+int operator ""_a (const char *);
+
+void
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (u8display_string_of (^^a) == u8"a");
+  static_assert (u8display_string_of (^^b) == u8"b");
+  static_assert (u8display_string_of (^^c) == u8"c");
+  static_assert (u8display_string_of (^^d) == u8"d");
+  static_assert (u8display_string_of (^^e) == u8"e");
+  static_assert (u8display_string_of (parameters_of (^^foo)[0]) == u8"<parameter a of void foo(int, long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^foo)[1]) == u8"<parameter b of void foo(int, long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^foo)[2]) == u8"<parameter c of void foo(int, long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^foo)[3]) == u8"<parameter d of void foo(int, long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^foo)[4]) == u8"<parameter e of void foo(int, long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^bar)[0]) == u8"<unnamed parameter 1 of void bar(long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^bar)[1]) == u8"<parameter f of void bar(long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^bar)[2]) == u8"<parameter g of void bar(long int, T, int*, T&)>");
+  static_assert (u8display_string_of (parameters_of (^^bar)[3]) == u8"<unnamed parameter 4 of void bar(long int, T, int*, T&)>");
+  static_assert (u8display_string_of (null_reflection) == u8"<null reflection>");
+  static_assert (u8display_string_of (^^::) == u8"::");
+  static_assert (u8display_string_of (^^NS2) == u8"{anonymous}::NS2");
+  static_assert (u8display_string_of (parent_of (^^NS2)) == u8"{anonymous}");
+  static_assert (u8display_string_of (^^NS3::NS4) == u8"NS3::{anonymous}::{anonymous}::NS4");
+  static_assert (u8display_string_of (parent_of (^^NS3::NS4)) == u8"NS3::{anonymous}::{anonymous}");
+  static_assert (u8display_string_of (parent_of (parent_of (^^NS3::NS4))) == u8"NS3::{anonymous}");
+  static_assert (u8display_string_of (parent_of (parent_of (parent_of   (^^NS3::NS4)))) == u8"NS3");
+  static_assert (u8display_string_of (^^Z) == u8"Z");
+  static_assert (u8display_string_of (parent_of (^^Z)) == u8"<unnamed enum>");
+  static_assert (u8display_string_of (reflect_constant (42)) == u8"42");
+  static_assert (u8display_string_of (reflect_object (arr[1])) == u8"arr[1]");
+  static_assert (u8display_string_of (^^arr) == u8"arr");
+  static_assert (u8display_string_of (^^a3) == u8"a3");
+  static_assert (u8display_string_of (^^fn) == u8"void fn()");
+  static_assert (u8display_string_of (^^fn2) == u8"auto& fn2()");
+  static_assert (u8display_string_of (^^Enum::A) == u8"A");
+  static_assert (u8display_string_of (^^Alias) == u8"Alias {aka int}");
+  static_assert (u8display_string_of (^^S) == u8"S");
+  static_assert (u8display_string_of (^^S::mem) == u8"S::mem");
+  static_assert (u8display_string_of (members_of (^^S, ctx)[1]) == u8"S::<unnamed bit-field>");
+  static_assert (u8display_string_of (^^TCls) == u8"template<auto <anonymous> > struct TCls");
+  static_assert (u8display_string_of (^^TFn) == u8"template<auto <anonymous> > void TFn()");
+  static_assert (u8display_string_of (^^TVar) == u8"template<auto <anonymous> > int TVar<<anonymous> >");
+  static_assert (u8display_string_of (^^Concept) == u8"template<auto <anonymous> > concept Concept");
+  static_assert (u8display_string_of (^^NSAlias) == u8"NSAlias");
+  static_assert (u8display_string_of (^^NS) == u8"NS");
+  static_assert (u8display_string_of (bases_of (^^S, ctx)[0]) == u8"S: B");
+  static_assert (u8display_string_of (data_member_spec (^^int, { .name = "member", .alignment = 128, .no_unique_address = true })) == u8"(int, member, 128, , true)");
+  static_assert (u8display_string_of (data_member_spec (^^const int, { .name = "member", .bit_width = 6 })) == u8"(const int, member, , 6, false)");
+  static_assert (u8display_string_of (data_member_spec (^^int, { .bit_width = 0 })) == u8"(int, , , 0, false)");
+  static_assert (u8display_string_of (data_member_spec (^^long, { .bit_width = 5 })) == u8"(long int, , , 5, false)");
+  static_assert (u8display_string_of (annotations_of (^^bar)[0]) == u8"[[=1]]");
+  static_assert (u8display_string_of (annotations_of (^^bar)[1]) == u8"[[=AN{1, 42, ' '}]]");
+  static_assert (u8display_string_of (^^int) == u8"int");
+  static_assert (u8display_string_of (^^unsigned) == u8"unsigned int");
+  static_assert (u8display_string_of (^^unsigned long) == u8"long unsigned int");
+  static_assert (u8display_string_of (^^const long long &) == u8"const long long int&");
+  static_assert (u8display_string_of (^^const double **) == u8"const double**");
+  static_assert (u8display_string_of (^^int (int)) == u8"int(int)");
+  static_assert (u8display_string_of (^^int (&) (int, long, S &)) == u8"int (&)(int, long int, S&)");
+  static_assert (u8display_string_of (^^int (*) (int, long, S &)) == u8"int (*)(int, long int, S&)");
+  static_assert (u8display_string_of (members_of (^^V2, ctx)[0]) == u8"V2& V2::operator=(const V2&)");
+  static_assert (u8display_string_of (members_of (^^V3, ctx)[0]) == u8"V3& V3::operator=(V3&&)");
+  static_assert (u8display_string_of (members_of (^^V4, ctx)[0]) == u8"V4& V4::operator+=(const V4&)");
+  static_assert (u8display_string_of (members_of (^^V5, ctx)[0]) == u8"V5::operator int()");
+  static_assert (u8display_string_of (^^operator""_a) == u8"int operator\"\"_a(const char*)");
+}
+
+namespace NS5 {
+  int arr[] = {1, 2, 3};
+  auto [a1, a2, a3] = arr;
+  void fn();
+  auto &fn2();
+  enum Enum { A };
+  using Alias = int;
+  struct B {};
+  struct S : B {
+    int mem;
+    int : 0;
+  };
+  struct T {
+    T () {}
+    T (const T &) {}
+    ~T () {}
+  };
+  struct U {
+    int u;
+    int v : 5;
+  };
+  template<auto> struct TCls {};
+  template<auto> void TFn();
+  template<auto> int TVar;
+  template<auto> concept Concept = requires { true; };
+  enum { Z };
+
+  struct AN { int a; long b; char c; };
+
+  [[=1, =AN { 1, 42, ' ' }]] void bar (long, const T f, int g[2], T &);
+
+  struct V1 {
+    constexpr V1 (int) {}
+  };
+  struct V2 {
+    V2 &operator = (const V2 &);
+  };
+  struct V3 {
+    V3 &operator = (V3 &&);
+  };
+  struct V4 {
+    V4 &operator += (const V4 &);
+  };
+  struct V5 {
+    operator int ();
+  };
+  int operator ""_a (const char *);
+
+  void
+  foo (int a, const long b, T c, int d[4], T &e)
+  {
+    static_assert (u8display_string_of (^^a) == u8"a");
+    static_assert (u8display_string_of (^^b) == u8"b");
+    static_assert (u8display_string_of (^^c) == u8"c");
+    static_assert (u8display_string_of (^^d) == u8"d");
+    static_assert (u8display_string_of (^^e) == u8"e");
+    static_assert (u8display_string_of (parameters_of (^^foo)[0]) == u8"<parameter a of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^foo)[1]) == u8"<parameter b of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^foo)[2]) == u8"<parameter c of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^foo)[3]) == u8"<parameter d of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^foo)[4]) == u8"<parameter e of void NS5::foo(int, long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^bar)[0]) == u8"<unnamed parameter 1 of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^bar)[1]) == u8"<parameter f of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^bar)[2]) == u8"<parameter g of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (u8display_string_of (parameters_of (^^bar)[3]) == u8"<unnamed parameter 4 of void NS5::bar(long int, T, int*, T&)>");
+    static_assert (u8display_string_of (^^Z) == u8"NS5::Z");
+    static_assert (u8display_string_of (parent_of (^^Z)) == u8"NS5::<unnamed enum>");
+    static_assert (u8display_string_of (reflect_constant (42)) == u8"42");
+    static_assert (u8display_string_of (reflect_object (arr[1])) == u8"NS5::arr[1]");
+    static_assert (u8display_string_of (^^arr) == u8"NS5::arr");
+    static_assert (u8display_string_of (^^a3) == u8"NS5::a3");
+    static_assert (u8display_string_of (^^fn) == u8"void NS5::fn()");
+    static_assert (u8display_string_of (^^fn2) == u8"auto& NS5::fn2()");
+    static_assert (u8display_string_of (^^Enum::A) == u8"NS5::A");
+    static_assert (u8display_string_of (^^Alias) == u8"NS5::Alias {aka int}");
+    static_assert (u8display_string_of (^^S) == u8"NS5::S");
+    static_assert (u8display_string_of (^^S::mem) == u8"NS5::S::mem");
+    static_assert (u8display_string_of (members_of (^^S, ctx)[1]) == u8"NS5::S::<unnamed bit-field>");
+    static_assert (u8display_string_of (^^TCls) == u8"template<auto <anonymous> > struct NS5::TCls");
+    static_assert (u8display_string_of (^^TFn) == u8"template<auto <anonymous> > void NS5::TFn()");
+    static_assert (u8display_string_of (^^TVar) == u8"template<auto <anonymous> > int NS5::TVar<<anonymous> >");
+    static_assert (u8display_string_of (^^Concept) == u8"template<auto <anonymous> > concept NS5::Concept");
+    static_assert (u8display_string_of (bases_of (^^S, ctx)[0]) == u8"NS5::S: NS5::B");
+    static_assert (u8display_string_of (annotations_of (^^bar)[0]) == u8"[[=1]]");
+    static_assert (u8display_string_of (annotations_of (^^bar)[1]) == u8"[[=NS5::AN{1, 42, ' '}]]");
+    static_assert (u8display_string_of (^^int (&) (int, long, S &)) == u8"int (&)(int, long int, NS5::S&)");
+    static_assert (u8display_string_of (^^int (*) (int, long, S &)) == u8"int (*)(int, long int, NS5::S&)");
+    static_assert (u8display_string_of (members_of (^^V2, ctx)[0]) == u8"NS5::V2& NS5::V2::operator=(const NS5::V2&)");
+    static_assert (u8display_string_of (members_of (^^V3, ctx)[0]) == u8"NS5::V3& NS5::V3::operator=(NS5::V3&&)");
+    static_assert (u8display_string_of (members_of (^^V4, ctx)[0]) == u8"NS5::V4& NS5::V4::operator+=(const NS5::V4&)");
+    static_assert (u8display_string_of (members_of (^^V5, ctx)[0]) == u8"NS5::V5::operator int()");
+    static_assert (u8display_string_of (^^operator""_a) == u8"int NS5::operator\"\"_a(const char*)");
+  }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C b/gcc/testsuite/g++.dg/reflect/u8identifier_of1.C
new file mode 100644 (file)
index 0000000..0d30197
--- /dev/null
@@ -0,0 +1,168 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::u8identifier_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+struct C { };
+
+constexpr std::u8string_view sv = std::meta::u8identifier_of (^^C);
+static_assert (sv == u8"C");
+static_assert (sv.data ()[0] == u8'C');
+static_assert (sv.data ()[1] == u8'\0');
+
+struct S { };
+using T = int;
+using U = S;
+enum E { E1, E2 };
+enum { E3, E4 };
+typedef enum { E5, E6 } E7;
+
+static_assert (u8identifier_of (^^T) == std::u8string_view (u8"T"));
+static_assert (u8identifier_of (^^S) == std::u8string_view (u8"S"));
+static_assert (u8identifier_of (^^U) == std::u8string_view (u8"U"));
+static_assert (u8identifier_of (^^std) == std::u8string_view (u8"std"));
+static_assert (u8identifier_of (^^std::meta) == std::u8string_view (u8"meta"));
+static_assert (u8identifier_of (^^E1) == std::u8string_view (u8"E1"));
+static_assert (u8identifier_of (^^E) == std::u8string_view (u8"E"));
+static_assert (u8identifier_of (parent_of (^^E5)) == std::u8string_view (u8"E7"));
+static_assert (u8identifier_of (^^E7) == std::u8string_view (u8"E7"));
+static_assert (u8identifier_of (data_member_spec (^^long, { .name = u8"foo", .bit_width = 6 })) == std::u8string_view (u8"foo"));
+static_assert (u8identifier_of (data_member_spec (^^long, { .name = u8"extremely_long_string_used_as_identifier" })) == std::u8string_view (u8"extremely_long_string_used_as_identifier"));
+
+namespace N {}
+namespace NA = N;
+static_assert (u8identifier_of (^^N) == std::u8string_view (u8"N"));
+static_assert (u8identifier_of (^^NA) == std::u8string_view (u8"NA"));
+
+namespace {
+  int a;
+  namespace M {}
+  static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
+  static_assert (u8identifier_of (^^M) == std::u8string_view (u8"M"));
+}
+
+typedef struct {
+  int a;
+  static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
+} SV;
+static_assert (u8identifier_of (^^SV) == std::u8string_view (u8"SV"));
+static_assert (u8identifier_of (parent_of (^^SV::a)) == std::u8string_view (u8"SV"));
+static_assert (u8identifier_of (dealias (^^SV)) == std::u8string_view (u8"SV"));
+
+template <int N>
+struct ST
+{
+  static_assert (u8identifier_of (^^ST) == std::u8string_view (u8"ST"));
+};
+
+struct V
+{
+  void foo () { int a; static_assert (u8identifier_of (parent_of (^^a)) == std::u8string_view (u8"foo")); }
+  template <int N>
+  void bar () { int a; static_assert (u8identifier_of (parent_of (^^a)) == std::u8string_view (u8"bar")); }
+};
+
+int
+operator ""_a (const char *)
+{
+  int a;
+  static_assert (u8identifier_of (parent_of (^^a)) == std::u8string_view (u8"_a"));
+  return 0;
+}
+
+int v;
+static_assert (u8identifier_of (^^V::foo) == std::u8string_view (u8"foo"));
+static_assert (u8identifier_of (^^V::bar) == std::u8string_view (u8"bar"));
+
+void foo (int);
+static_assert (u8identifier_of (^^foo) == std::u8string_view (u8"foo"));
+
+int arr[3];
+
+void
+foo (int a)
+{
+  auto [b, c, d] = arr;
+  static_assert (u8identifier_of (^^foo) == std::u8string_view (u8"foo"));
+  static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
+  static_assert (u8identifier_of (^^b) == std::u8string_view (u8"b"));
+  static_assert (u8identifier_of (^^c) == std::u8string_view (u8"c"));
+  static_assert (u8identifier_of (^^d) == std::u8string_view (u8"d"));
+}
+
+template <int N>
+void
+bar (int a)
+{
+  auto [...b, c] = arr;
+  static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
+  static_assert (u8identifier_of (^^c) == std::u8string_view (u8"c"));
+}
+
+void
+baz ()
+{
+  auto a = [] {
+    int a;
+    static_assert (u8identifier_of (^^a) == std::u8string_view (u8"a"));
+    static_assert (u8identifier_of (parent_of (parent_of (parent_of (^^a)))) == std::u8string_view (u8"baz"));
+  };
+  using t = decltype (a);
+  static_assert (u8identifier_of (^^t) == std::u8string_view (u8"t"));
+}
+
+void qux (int, int b, int c, int d, int);
+constexpr auto p0 = parameters_of (^^qux)[0];
+constexpr auto p1 = parameters_of (^^qux)[1];
+constexpr auto p2 = parameters_of (^^qux)[2];
+constexpr auto p3 = parameters_of (^^qux)[3];
+constexpr auto p4 = parameters_of (^^qux)[4];
+static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
+static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
+static_assert (u8identifier_of (p3) == std::u8string_view (u8"d"));
+void qux (int a, int, int c, int e, int);
+static_assert (u8identifier_of (p0) == std::u8string_view (u8"a"));
+static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
+static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
+
+void
+qux (int a, int, int, int e, int)
+{
+  static_assert (u8identifier_of (p0) == std::u8string_view (u8"a"));
+  static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
+  static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
+  static_assert (u8identifier_of (variable_of (p0)) == std::u8string_view (u8"a"));
+  static_assert (u8identifier_of (variable_of (p3)) == std::u8string_view (u8"e"));
+}
+
+void qux (int f, int, int, int, int g);
+static_assert (u8identifier_of (p1) == std::u8string_view (u8"b"));
+static_assert (u8identifier_of (p2) == std::u8string_view (u8"c"));
+static_assert (u8identifier_of (p4) == std::u8string_view (u8"g"));
+
+template <typename... T>
+void
+freddy (int a, T... b)
+{
+}
+
+static_assert (u8identifier_of (parameters_of (^^freddy <int, long, char>)[0]) == std::u8string_view (u8"a"));
+
+struct {
+  int a;
+} s;
+
+static_assert (u8identifier_of (^^s) == std::u8string_view (u8"s"));
+
+int qu\u00E6 = 1;
+
+static_assert (u8identifier_of (^^qu\u00E6) == std::u8string_view (u8"qu\N{LATIN SMALL LETTER AE}"));
+
+typedef enum {
+  E8,
+  E9
+} E10;
+static_assert (u8identifier_of (parent_of (^^E8)) == std::u8string_view (u8"E10"));
diff --git a/gcc/testsuite/g++.dg/reflect/u8symbol_of1.C b/gcc/testsuite/g++.dg/reflect/u8symbol_of1.C
new file mode 100644 (file)
index 0000000..1c8bc41
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::u8symbol_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval bool
+has_u8symbol_of (operators op)
+{
+  try { u8symbol_of (op); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_u8symbol_of (static_cast <operators> (4242)));
+static_assert (u8symbol_of (op_new) == std::u8string_view (u8"new"));
+static_assert (u8symbol_of (op_delete) == std::u8string_view (u8"delete"));
+static_assert (u8symbol_of (op_array_new) == std::u8string_view (u8"new[]"));
+static_assert (u8symbol_of (op_array_delete) == std::u8string_view (u8"delete[]"));
+static_assert (u8symbol_of (op_co_await) == std::u8string_view (u8"co_await"));
+static_assert (u8symbol_of (op_parentheses) == std::u8string_view (u8"()"));
+static_assert (u8symbol_of (op_square_brackets) == std::u8string_view (u8"[]"));
+static_assert (u8symbol_of (op_arrow) == std::u8string_view (u8"->"));
+static_assert (u8symbol_of (op_arrow_star) == std::u8string_view (u8"->*"));
+static_assert (u8symbol_of (op_tilde) == std::u8string_view (u8"~"));
+static_assert (u8symbol_of (op_exclamation) == std::u8string_view (u8"!"));
+static_assert (u8symbol_of (op_plus) == std::u8string_view (u8"+"));
+static_assert (u8symbol_of (op_minus) == std::u8string_view (u8"-"));
+static_assert (u8symbol_of (op_star) == std::u8string_view (u8"*"));
+static_assert (u8symbol_of (op_slash) == std::u8string_view (u8"/"));
+static_assert (u8symbol_of (op_percent) == std::u8string_view (u8"%"));
+static_assert (u8symbol_of (op_caret) == std::u8string_view (u8"^"));
+static_assert (u8symbol_of (op_ampersand) == std::u8string_view (u8"&"));
+static_assert (u8symbol_of (op_equals) == std::u8string_view (u8"="));
+static_assert (u8symbol_of (op_pipe) == std::u8string_view (u8"|"));
+static_assert (u8symbol_of (op_plus_equals) == std::u8string_view (u8"+="));
+static_assert (u8symbol_of (op_minus_equals) == std::u8string_view (u8"-="));
+static_assert (u8symbol_of (op_star_equals) == std::u8string_view (u8"*="));
+static_assert (u8symbol_of (op_slash_equals) == std::u8string_view (u8"/="));
+static_assert (u8symbol_of (op_percent_equals) == std::u8string_view (u8"%="));
+static_assert (u8symbol_of (op_caret_equals) == std::u8string_view (u8"^="));
+static_assert (u8symbol_of (op_ampersand_equals) == std::u8string_view (u8"&="));
+static_assert (u8symbol_of (op_pipe_equals) == std::u8string_view (u8"|="));
+static_assert (u8symbol_of (op_equals_equals) == std::u8string_view (u8"=="));
+static_assert (u8symbol_of (op_exclamation_equals) == std::u8string_view (u8"!="));
+static_assert (u8symbol_of (op_less) == std::u8string_view (u8"<"));
+static_assert (u8symbol_of (op_greater) == std::u8string_view (u8">"));
+static_assert (u8symbol_of (op_less_equals) == std::u8string_view (u8"<="));
+static_assert (u8symbol_of (op_greater_equals) == std::u8string_view (u8">="));
+static_assert (u8symbol_of (op_spaceship) == std::u8string_view (u8"<=>"));
+static_assert (u8symbol_of (op_ampersand_ampersand) == std::u8string_view (u8"&&"));
+static_assert (u8symbol_of (op_pipe_pipe) == std::u8string_view (u8"||"));
+static_assert (u8symbol_of (op_less_less) == std::u8string_view (u8"<<"));
+static_assert (u8symbol_of (op_greater_greater) == std::u8string_view (u8">>"));
+static_assert (u8symbol_of (op_less_less_equals) == std::u8string_view (u8"<<="));
+static_assert (u8symbol_of (op_greater_greater_equals) == std::u8string_view (u8">>="));
+static_assert (u8symbol_of (op_plus_plus) == std::u8string_view (u8"++"));
+static_assert (u8symbol_of (op_minus_minus) == std::u8string_view (u8"--"));
+static_assert (u8symbol_of (op_comma) == std::u8string_view (u8","));
diff --git a/gcc/testsuite/g++.dg/reflect/underlying_type1.C b/gcc/testsuite/g++.dg/reflect/underlying_type1.C
new file mode 100644 (file)
index 0000000..8d5dbb2
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::underlying_type.
+
+#include <meta>
+
+constexpr auto a = std::meta::underlying_type (^^int); // { dg-error "uncaught exception of type" }
+
+enum E {
+  E0 = 1,
+  E1 = std::meta::underlying_type (^^E) == ^^int,      // { dg-error "uncaught exception of type" }
+  E2 = 2                                               // { dg-error "enumerator value for 'E1' is not an integer constant" "" { target *-*-* } .-1 }
+};
diff --git a/gcc/testsuite/g++.dg/reflect/using1.C b/gcc/testsuite/g++.dg/reflect/using1.C
new file mode 100644 (file)
index 0000000..915f81f
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A {
+  int a;
+  consteval A(int p) : a(p) {}
+};
+
+constexpr auto r = ^^A;
+
+struct B : A {
+  using typename [: r :]::A;
+};
diff --git a/gcc/testsuite/g++.dg/reflect/value_or_object1.C b/gcc/testsuite/g++.dg/reflect/value_or_object1.C
new file mode 100644 (file)
index 0000000..9135bab
--- /dev/null
@@ -0,0 +1,50 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::is_value and is_object.
+
+#include <meta>
+
+using namespace std::meta;
+
+constexpr int i = 42;
+
+template<int N>
+constexpr int v = N;
+
+static_assert (!is_object (^^i));
+static_assert (!is_value (^^i));
+static_assert (is_variable (^^i));
+static_assert (!is_object (reflect_constant (^^i)));
+static_assert (is_value (reflect_constant (^^i)));
+static_assert (!is_variable (reflect_constant (^^i)));
+static_assert (!is_object (substitute (^^v, { reflect_constant (15) })));
+static_assert (!is_object (^^v<15>));
+static_assert (!is_value (^^v<15>));
+static_assert (is_variable (^^v<15>));
+static_assert (is_value (reflect_constant (^^v<15>)));
+static_assert (!is_object (reflect_constant (^^v<15>)));
+static_assert (!is_variable (reflect_constant (^^v<15>)));
+
+constexpr std::pair<std::pair<int, bool>, int> p = {{1, true}, 2};
+constexpr info rfirst = reflect_object (p.first);
+static_assert (is_object (rfirst) && !is_value (rfirst));
+static_assert (type_of (rfirst) == ^^const std::pair<int, bool>);
+static_assert (rfirst != reflect_constant (std::make_pair (1, true)));
+
+constexpr int k = 3;
+constexpr const int *pk = &k;
+constexpr const int &ref = k;
+constexpr auto rp = ^^pk;
+constexpr auto rref = ^^ref;
+static_assert (is_variable (rp));
+static_assert (!is_object (rp));
+static_assert (!is_value (rp));
+static_assert (!is_variable (reflect_constant (rp)));
+static_assert (!is_object (reflect_constant (rp)));
+static_assert (is_value (reflect_constant (rp)));
+static_assert (is_variable (rref));
+static_assert (!is_object (rref));
+static_assert (!is_value (rref));
+static_assert (!is_variable (reflect_constant (rref)));
+static_assert (!is_object (reflect_constant (rref)));
+static_assert (is_value (reflect_constant (rref)));
diff --git a/gcc/testsuite/g++.dg/reflect/variable_of1.C b/gcc/testsuite/g++.dg/reflect/variable_of1.C
new file mode 100644 (file)
index 0000000..ae27875
--- /dev/null
@@ -0,0 +1,136 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::variable_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+int arr[] = {1, 2, 3};
+auto [a1, a2, a3] = arr;
+void fn();
+auto &fn2();
+enum Enum { A };
+using Alias = int;
+struct B {};
+struct S : B {
+  int mem;
+  int : 0;
+};
+struct T {
+  T ();
+  T (const T &);
+  ~T ();
+};
+struct U {
+  int u;
+};
+template<auto> struct TCls {};
+template<auto> void TFn();
+template<auto> int TVar;
+template<auto> concept Concept = requires { true; };
+namespace NS {};
+namespace NSAlias = NS;
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+consteval bool
+has_variable_of (info r)
+{
+  try { variable_of (r); }
+  catch (std::meta::exception &) { return false; }
+  return true;
+}
+
+static_assert (!has_variable_of (std::meta::reflect_constant (42)));
+static_assert (!has_variable_of (std::meta::reflect_object (arr[1])));
+static_assert (!has_variable_of (^^arr));
+static_assert (!has_variable_of (^^a3));
+static_assert (!has_variable_of (^^fn));
+static_assert (!has_variable_of (^^fn2));
+static_assert (!has_variable_of (^^Enum::A));
+static_assert (!has_variable_of (^^Alias));
+static_assert (!has_variable_of (^^S));
+static_assert (!has_variable_of (^^S::mem));
+static_assert (!has_variable_of (std::meta::members_of (^^S, ctx)[1]));
+static_assert (!has_variable_of (^^TCls));
+static_assert (!has_variable_of (^^TFn));
+static_assert (!has_variable_of (^^TVar));
+static_assert (!has_variable_of (^^Concept));
+static_assert (!has_variable_of (^^NSAlias));
+static_assert (!has_variable_of (^^NS));
+static_assert (!has_variable_of (std::meta::bases_of (^^S, ctx)[0]));
+static_assert (!has_variable_of (std::meta::data_member_spec (^^int, { .name = "member" })));
+
+void
+bar (long, const T f, int g[2], T &)
+{
+}
+
+void
+foo (int a, const long b, T c, int d[4], T &e)
+{
+  static_assert (!has_variable_of (^^a));
+  static_assert (!has_variable_of (^^b));
+  static_assert (!has_variable_of (^^c));
+  static_assert (!has_variable_of (^^d));
+  static_assert (!has_variable_of (^^e));
+  static_assert (has_variable_of (parameters_of (^^foo)[0]));
+  static_assert (has_variable_of (parameters_of (^^foo)[1]));
+  static_assert (has_variable_of (parameters_of (^^foo)[2]));
+  static_assert (has_variable_of (parameters_of (^^foo)[3]));
+  static_assert (has_variable_of (parameters_of (^^foo)[4]));
+  static_assert (!has_variable_of (parameters_of (^^bar)[0]));
+  static_assert (!has_variable_of (parameters_of (^^bar)[1]));
+  static_assert (!has_variable_of (parameters_of (^^bar)[2]));
+  static_assert (!has_variable_of (parameters_of (^^bar)[3]));
+  static_assert (variable_of (parameters_of (^^foo)[0]) == ^^a);
+  static_assert (variable_of (parameters_of (^^foo)[1]) == ^^b);
+  static_assert (variable_of (parameters_of (^^foo)[2]) == ^^c);
+  static_assert (variable_of (parameters_of (^^foo)[3]) == ^^d);
+  static_assert (variable_of (parameters_of (^^foo)[4]) == ^^e);
+  static_assert (variable_of (parameters_of (^^foo)[0]) != parameters_of (^^foo)[0]);
+  static_assert (variable_of (parameters_of (^^foo)[1]) != parameters_of (^^foo)[1]);
+  static_assert (variable_of (parameters_of (^^foo)[2]) != parameters_of (^^foo)[2]);
+  static_assert (variable_of (parameters_of (^^foo)[3]) != parameters_of (^^foo)[3]);
+  static_assert (variable_of (parameters_of (^^foo)[4]) != parameters_of (^^foo)[4]);
+  static_assert (parameters_of (^^foo)[0] != ^^a);
+  static_assert (parameters_of (^^foo)[1] != ^^b);
+  static_assert (parameters_of (^^foo)[2] != ^^c);
+  static_assert (parameters_of (^^foo)[3] != ^^d);
+  static_assert (parameters_of (^^foo)[4] != ^^e);
+}
+
+consteval bool
+baz (int a, info b, info c, info d)
+{
+  if (a != 43)
+    return false;
+  if (b != d)
+    return false;
+  if (b == c)
+    return false;
+  if (b == parameters_of (^^baz)[1])
+    return false;
+
+  // variable can be accessed only in innermost scope
+  try { variable_of (c); return false; }
+  catch (exception) {}
+  try { variable_of (parameters_of (^^baz)[1]); return false; } 
+  catch (exception) {}
+  return true;
+}
+
+consteval bool
+qux (int a)
+{
+  return baz (a + 1, ^^a, parameters_of (^^qux)[0],
+  // TODO: This doesn't work yet, I think we want to check
+  // whether DECL_CONTEXT of the PARM_DECL is current_function_decl
+  // or any of the ctx->call->fundef->decl on the constexpr evaluation
+  // stack.  But currently we only have access to the innermost.
+             // variable_of (parameters_of (^^qux)[0]));
+             ^^a);
+}
+
+static_assert (qux (42));
diff --git a/gcc/testsuite/g++.dg/reflect/variable_of2.C b/gcc/testsuite/g++.dg/reflect/variable_of2.C
new file mode 100644 (file)
index 0000000..0a55f69
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::variable_of.
+
+#include <meta>
+
+using namespace std::meta;
+
+consteval int fn(int p) {
+  constexpr auto rp = parameters_of(^^fn)[0];
+  constexpr auto rv = variable_of(rp);
+  static_assert(is_function_parameter(rp));
+  static_assert(!is_function_parameter(rv));
+  static_assert(!is_variable(rp));
+  static_assert(is_variable(rv));
+  static_assert(^^p == rv);
+
+  return [:variable_of(parameters_of(^^fn)[0]):];
+}
+
+static_assert(fn(42) == 42);
diff --git a/gcc/testsuite/g++.dg/reflect/variable_of3.C b/gcc/testsuite/g++.dg/reflect/variable_of3.C
new file mode 100644 (file)
index 0000000..9b16346
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::variable_of.
+
+#include <meta>
+#include <utility>
+
+using namespace std::meta;
+
+constexpr int fn(int, int) {
+  return [: variable_of (parameters_of (^^fn)[0]) :]
+       + [: variable_of (parameters_of (^^fn)[1]) :];
+}
+
+static_assert(fn(10, 32) == 42);
+
+template<typename... Args>
+constexpr int bar(Args...)
+{
+  constexpr int vt[] {__integer_pack (sizeof...(Args))...};
+  constexpr auto [...ids] = vt;
+  return (0 + ... + [: variable_of (parameters_of (^^bar<Args...>)[ids]) :]);
+}
+
+static_assert(bar(42) == 42);
+static_assert(bar(10, 32) == 42);
+static_assert(bar(10, 15, 17) == 42);
+static_assert(bar(10, 15, 11, 6) == 42);
diff --git a/gcc/testsuite/g++.dg/reflect/variant1.C b/gcc/testsuite/g++.dg/reflect/variant1.C
new file mode 100644 (file)
index 0000000..a3cc066
--- /dev/null
@@ -0,0 +1,37 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::variant_{size,alternative}.
+
+#include <meta>
+#include <variant>
+
+using namespace std::meta;
+
+using V0 = std::variant<>;
+static_assert (variant_size (^^V0) == 0);
+static_assert (variant_size (^^const V0) == 0);
+
+using V1 = std::variant<void *>;
+static_assert (variant_size (^^V1) == 1);
+static_assert (variant_size (^^const V1) == 1);
+static_assert (variant_alternative (0, ^^V1) == ^^void *);
+
+using V4 = std::variant<long, long, void *, double>;
+static_assert (variant_size (^^V4) == 4);
+static_assert (variant_size (^^const V4) == 4);
+static_assert (variant_alternative (0, ^^V4) == ^^long);
+static_assert (variant_alternative (1, ^^V4) == ^^long);
+static_assert (variant_alternative (2, ^^V4) == ^^void *);
+static_assert (variant_alternative (3, ^^V4) == ^^double);
+// cv-qualification on the variant type propagates to the extracted alternative type.
+static_assert (variant_alternative (0, ^^const V4) == ^^const long);
+static_assert (variant_alternative (1, ^^const V4) == ^^const long);
+static_assert (variant_alternative (2, ^^const V4) == ^^void *const);
+static_assert (variant_alternative (3, ^^const V4) == ^^const double);
+
+using mytype1 = float;
+using mytype2 = mytype1 *;
+using V2 = std::variant<mytype1, mytype2>;
+static_assert (variant_size (^^V2) == 2);
+static_assert (variant_alternative (0, ^^V2) == ^^float);
+static_assert (variant_alternative (1, ^^V2) == ^^float *);
diff --git a/gcc/testsuite/g++.dg/reflect/variant2.C b/gcc/testsuite/g++.dg/reflect/variant2.C
new file mode 100644 (file)
index 0000000..4570aa7
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::variant_{size,alternative}.
+
+#include <meta>
+#include <variant>
+
+using namespace std::meta;
+
+constexpr auto s1 = variant_size (^^int); // { dg-error "couldn't instantiate 'std::variant_size<int>'" }
+int x;
+constexpr auto s2 = variant_size (^^x); // { dg-error "uncaught exception" }
+
+constexpr auto r1 = variant_alternative (0, ^^std::variant<>); // { dg-error "uncaught exception" }
+constexpr auto r2 = variant_alternative (0, ^^int); // { dg-error "uncaught exception" }
+constexpr auto r3 = variant_alternative (0, ^^x); // { dg-error "uncaught exception" }
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "pack index .0." "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/reflect/vector1.C b/gcc/testsuite/g++.dg/reflect/vector1.C
new file mode 100644 (file)
index 0000000..179a056
--- /dev/null
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::vector<std::meta::info>.
+
+#include <vector>
+#include <meta>
+
+using namespace std::meta;
+
+void die ();
+
+consteval void
+f ()
+{
+  constexpr auto e = std::vector<info>{^^int}[0];
+  typename [:e:] i = 42;
+  auto f = std::vector<info>{^^int}[0];
+  std::vector<info> v1 = { ^^int };
+  auto v2 = std::vector<info>{^^int};
+  if (v1.size () != v2.size ())
+    die ();
+}
+
+void
+g ()
+{
+  f ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/visibility1.C b/gcc/testsuite/g++.dg/reflect/visibility1.C
new file mode 100644 (file)
index 0000000..c47817b
--- /dev/null
@@ -0,0 +1,121 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -O0" }
+
+#include <meta>
+
+template <int N, std::meta::info I>
+void
+foo ()
+{
+}
+
+struct A {};
+
+namespace
+{
+  void baz (int) {}
+  struct B {};
+  struct C : public A {};
+  template <typename T>
+  struct G {};
+}
+
+struct D : public B {};
+
+template <typename T>
+struct F {};
+
+struct H : public A {};
+
+static union { int au; };
+int b;
+static int c;
+
+constexpr auto ctx = std::meta::access_context::current ();
+
+static void
+bar (int x)
+{
+  int v = 42;
+  foo <100, ^^x> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi100EL" } } - var in TU-local fn
+  foo <101, ^^v> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi101EL" } } - var in TU-local fn
+  foo <102, parameters_of (^^baz)[0]> ();      // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi102EL" } } - param of TU-local fn
+  foo <103, bases_of (^^C, ctx)[0]> ();                // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi103EL" } } - direct base relationship with TU-local derived
+  foo <104, bases_of (^^D, ctx)[0]> ();                // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi104EL" } } - direct base relationship with TU-local base
+  foo <105, data_member_spec (^^B, { .name = "foo" })> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi105EL" } } - data member spec with TU-local type
+}
+
+inline void
+qux (int x)
+{
+  int v = 42;
+  foo <106, ^^x> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi106EL" } } - var in inline fn - TODO, shall this be exported?
+  foo <107, ^^v> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi107EL" } } - var in inline fn - TODO, shall this be exported?
+}
+
+template <int N>
+void
+plugh (int x)
+{
+  int v = 42;
+  foo <132, ^^x> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi132EL" } } - var in public fn template instantiation - TODO, shall this be exported?
+  foo <133, ^^v> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi133EL" } } - var in public fn template instantiation - TODO, shall this be exported?
+  foo <134, parameters_of (parent_of (^^v))[0]> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi134EL" { target *-*-linux* } } } - fn parm of public fn template instantiation
+}
+
+namespace {
+template <int N>
+void
+garply (int x)
+{
+  int v = 42;
+  foo <135, ^^x> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi135EL" } } - var in TU-local fn template instantiation
+  foo <136, ^^v> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi136EL" } } - var in Tu-local fn template instantiation
+  foo <137, parameters_of (parent_of (^^v))[0]> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi137EL" } } - fn parm of TU-local fn template instantiation
+}
+}
+
+template <typename T>
+void
+fred (int x)
+{
+  int v = 42;
+  foo <138, ^^x> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi138EL" } } - var in TU-local fn template instantiation
+  foo <139, ^^v> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi139EL" } } - var in Tu-local fn template instantiation
+  foo <140, parameters_of (parent_of (^^v))[0]> (); // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi140EL" { xfail *-*-* } } } - fn parm of TU-local fn template instantiation - TODO, I think this shouldn't be exported and the mangling of these 3 doesn't include the template parameter
+}
+
+[[=1]] void
+xyzzy (int x)
+{
+  int v;
+  struct E {};
+  qux (x);
+  foo <108, annotations_of (^^xyzzy)[0]> ();   // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi108EL" } } - annotations always TU-local
+  foo <109, parameters_of (^^bar)[0]> ();      // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi109EL" } } - fn parm of TU-local fn
+  foo <110, parameters_of (^^qux)[0]> ();      // { dg-final { scan-assembler "\t.weak\t_Z3fooILi110EL" { target *-*-linux* } } } - fn parm of inline fn
+  foo <111, parameters_of (^^xyzzy)[0]> ();    // { dg-final { scan-assembler "\t.weak\t_Z3fooILi111EL" { target *-*-linux* } } } - fn parm of public fn
+  foo <112, ^^B> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi112EL" } } - TU-local class
+  foo <113, ^^C> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi113EL" } } - TU-local class
+  foo <114, ^^D> ();                           // { dg-final { scan-assembler "\t.weak\t_Z3fooILi114EL" { target *-*-linux* } } } - public class
+  foo <115, ^^E> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi115EL" } } - TU-local class
+  foo <116, ^^au> ();                          // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi116EL" } } - anon union var at namespace scope
+  foo <117, ^^F> ();                           // { dg-final { scan-assembler "\t.weak\t_Z3fooILi117EL" { target *-*-linux* } } } - public template
+  foo <118, ^^F <int>> ();                     // { dg-final { scan-assembler "\t.weak\t_Z3fooILi118EL" { target *-*-linux* } } } - specialization of public template
+  foo <119, ^^F <A>> ();                       // { dg-final { scan-assembler "\t.weak\t_Z3fooILi119EL" { target *-*-linux* } } } - specialization of public template
+  foo <120, ^^F <B>> ();                       // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi120EL" } } - specialization with TU-local parameter
+  foo <121, ^^G> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi121EL" } } - TU-local template
+  foo <122, ^^G <int>> ();                     // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi122EL" } } - specialization of TU-local template
+  foo <123, ^^G <A>> ();                       // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi123EL" } } - specialization of TU-local template
+  foo <124, ^^G <B>> ();                       // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi124EL" } } - specialization of TU-local template
+  foo <125, ^^x> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi125EL" } } - var in public fn but non-comdat - TODO, shall this be exported?
+  foo <126, ^^v> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi126EL" } } - var in public fn but non-comdat - TODO, shall this be exported?
+  foo <127, std::meta::info {}> ();            // { dg-final { scan-assembler "\t.weak\t_Z3fooILi127EL" { target *-*-linux* } } } - null reflection
+  foo <128, ^^b> ();                           // { dg-final { scan-assembler "\t.weak\t_Z3fooILi128EL" { target *-*-linux* } } } - public variable
+  foo <129, ^^c> ();                           // { dg-final { scan-assembler-not "\t.weak\t_Z3fooILi129EL" } } - TU-local variable
+  foo <130, data_member_spec (^^D, { .name = "foo" })> (); // { dg-final { scan-assembler "\t.weak\t_Z3fooILi130EL" { target *-*-linux* } } } - data member spec with public type
+  foo <131, bases_of (^^H, ctx)[0]> ();                // { dg-final { scan-assembler "\t.weak\t_Z3fooILi131EL" { target *-*-linux* } } } - direct base relationship with both types public
+  plugh <42> (x);
+  garply <42> (x);
+  fred <B> (x);
+}
index 1cea88b04e8d3fecf1eee3b08b6e332fb86921fd..4e158336c6ca013b5861afac3d5b80cf64920ab8 100644 (file)
@@ -1183,7 +1183,8 @@ struct GTY(()) tree_base {
         present in tree_base instead of tree_type is to save space.  The size
         of the field must be large enough to hold addr_space_t values.
         For CONSTRUCTOR nodes this holds the clobber_kind enum.
-        The C++ front-end uses this in IDENTIFIER_NODE and NAMESPACE_DECL.  */
+        The C++ front-end uses this in IDENTIFIER_NODE, REFLECT_EXPR, and
+        NAMESPACE_DECL.  */
       unsigned address_space : 8;
     } bits;
 
index 1adc66336d31ca93722481501595450c2533463f..b4734172f6b108b9bca2f855aa07c7214493d9fc 100644 (file)
@@ -1234,6 +1234,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define TREE_PURPOSE(NODE) (TREE_LIST_CHECK (NODE)->list.purpose)
 #define TREE_VALUE(NODE) (TREE_LIST_CHECK (NODE)->list.value)
 
+/* In TREE_VALUE of an attribute this means the attribute is never equal to
+   different attribute with the same name and value and that the attribute
+   is order sensitive, the order of attributes with this flag on their
+   TREE_VALUE should be preserved.  */
+#define ATTR_UNIQUE_VALUE_P(NODE) (TREE_LIST_CHECK (NODE)->base.protected_flag)
+
 /* In a TREE_VEC node.  */
 #define TREE_VEC_LENGTH(NODE) (TREE_VEC_CHECK (NODE)->base.u.length)
 #define TREE_VEC_BEGIN(NODE) (&TREE_VEC_CHECK (NODE)->vec.a[0])
@@ -2761,9 +2767,14 @@ extern tree vector_element_bits_tree (const_tree);
    vtable where the offset to the virtual base can be found.  */
 #define BINFO_VPTR_FIELD(NODE) (TREE_BINFO_CHECK (NODE)->binfo.vptr_field)
 
-/* Indicates the accesses this binfo has to its bases. The values are
+/* Indicates the accesses this binfo has to its bases.  The values are
    access_public_node, access_protected_node or access_private_node.
-   If this array is not present, public access is implied.  */
+   If this vector is not present, public access is implied.  If present,
+   the vector should have BINFO_N_BASE_BINFOS or larger length.  Elements
+   beyond BINFO_N_BASE_BINFOS are base attributes instead of the
+   access_p*_node values for base with index IDX at IDX + BINFO_N_BASE_BINFOS
+   index.  If that is beyond the length of the vector, no attributes for
+   that base is implied.  */
 #define BINFO_BASE_ACCESSES(NODE) \
   (TREE_BINFO_CHECK (NODE)->binfo.base_accesses)
 
index 02bba2daf10dd9ac72999cff3ffdd793943f5e01..e62c6ef9b9bd47875b913d4280022530c6557451 100644 (file)
@@ -1568,7 +1568,8 @@ start_class_def (tree type,
 
          tree base = finish_base_specifier
            (convert_in (base_classes->elements[i]), access,
-            (base_classes->flags[i] & GCC_CP_FLAG_BASECLASS_VIRTUAL) != 0);
+            (base_classes->flags[i] & GCC_CP_FLAG_BASECLASS_VIRTUAL) != 0,
+            NULL_TREE);
          TREE_CHAIN (base) = bases;
          bases = base;
        }
index b5689f8765bd6dc17cced80760df80666e8acf7d..f07052087a8da4233c0aff79b8a6dfe011006a4a 100644 (file)
@@ -840,6 +840,10 @@ _cpp_destroy_iconv (cpp_reader *pfile)
        iconv_close (pfile->char32_cset_desc.cd);
       if (pfile->wide_cset_desc.func == convert_using_iconv)
        iconv_close (pfile->wide_cset_desc.cd);
+      if (pfile->reverse_narrow_cset_desc.func == convert_using_iconv)
+       iconv_close (pfile->narrow_cset_desc.cd);
+      if (pfile->reverse_utf8_cset_desc.func == convert_using_iconv)
+       iconv_close (pfile->utf8_cset_desc.cd);
     }
 }
 
@@ -2726,6 +2730,110 @@ cpp_interpret_string_notranslate (cpp_reader *pfile, const cpp_string *from,
   return retval;
 }
 
+/* Convert a string FROM to TO, without handling of any UCNs etc., just
+   pure character set conversion.  If !REVERSE, convert from SOURCE_CHARSET
+   to execution charset corresponding to TYPE, if REVERSE, convert from the
+   execution charset corresponding to TYPE to SOURCE_CHARSET.  Return false
+   on error.  */
+
+bool
+cpp_translate_string (cpp_reader *pfile, const cpp_string *from,
+                     cpp_string *to, enum cpp_ttype type, bool reverse)
+{
+  struct cset_converter cvt = converter_for_type (pfile, type);
+  struct _cpp_strbuf tbuf;
+  if (reverse)
+    {
+      struct cset_converter *pcvt;
+      switch (type)
+       {
+       default:
+         pcvt = &pfile->reverse_narrow_cset_desc;
+         break;
+       case CPP_UTF8CHAR:
+       case CPP_UTF8STRING:
+         pcvt = &pfile->reverse_utf8_cset_desc;
+         break;
+       case CPP_CHAR16:
+       case CPP_STRING16:
+       case CPP_CHAR32:
+       case CPP_STRING32:
+       case CPP_WCHAR:
+       case CPP_WSTRING:
+         return false;
+       }
+      if (pcvt->func == NULL)
+       {
+         *pcvt = init_iconv_desc (pfile, cvt.from, cvt.to);
+         pcvt->width = cvt.width;
+       }
+      cvt = *pcvt;
+    }
+  tbuf.asize = MAX (OUTBUF_BLOCK_SIZE, from->len);
+  tbuf.text = XNEWVEC (uchar, tbuf.asize);
+  tbuf.len = 0;
+  if (!APPLY_CONVERSION (cvt, from->text, from->len, &tbuf))
+    {
+      XDELETEVEC (tbuf.text);
+      return false;
+    }
+  tbuf.text = XRESIZEVEC (uchar, tbuf.text, tbuf.len);
+  to->text = tbuf.text;
+  to->len = tbuf.len;
+  return true;
+}
+
+/* Return true if ID is a valid identifier, false otherwise.  Without any
+   diagnostics.  */
+
+bool
+cpp_valid_identifier (cpp_reader *pfile, const unsigned char *id)
+{
+  normalize_state nst = INITIAL_NORMALIZE_STATE;
+  const unsigned char *p = id;
+  if (*p == '\0')
+    return false;
+  const unsigned char *limit
+    = (const unsigned char *) strchr ((const char *) p, '\0');
+  static const cppchar_t utf8_signifier = 0xC0;
+  if (ISIDST (*p))
+    {
+      NORMALIZE_STATE_UPDATE_IDNUM (&nst, *p);
+      ++p;
+    }
+  while (*p)
+    {
+      if (p != id && ISIDNUM (*p))
+       {
+         while (ISIDNUM (*p))
+           ++p;
+         NORMALIZE_STATE_UPDATE_IDNUM (&nst, *(p - 1));
+         continue;
+       }
+      if (CPP_OPTION (pfile, extended_identifiers) && *p >= utf8_signifier)
+       {
+         const unsigned char *base = p;
+         size_t inbytesleft = limit - p;
+         cppchar_t c;
+         if (one_utf8_to_cppchar (&p, &inbytesleft, &c))
+           return false;
+         switch (ucn_valid_in_identifier (pfile, c, &nst))
+           {
+           default:
+             return false;
+           case 1:
+             continue;
+           case 2:
+             if (base == id)
+               return false;
+             continue;
+           }
+       }
+      return false;
+    }
+  return true;
+}
+
 \f
 /* Return number of source characters in STR.  */
 static unsigned
index 623f5bc6927cf32300f48b614a4806e1c1770b6a..bc0d7714e96f8482ef530a15eadc78d6f44f0a97 100644 (file)
@@ -101,6 +101,8 @@ class rich_location;
   OP(CLOSE_SQUARE,     "]")                                            \
   OP(OPEN_BRACE,       "{")                                            \
   OP(CLOSE_BRACE,      "}")                                            \
+  OP(OPEN_SPLICE,      "[:")                                           \
+  OP(CLOSE_SPLICE,     ":]")                                           \
   /* The remainder of the punctuation. Order is not significant.  */   \
   OP(SEMICOLON,                ";")    /* structure */                         \
   OP(ELLIPSIS,         "...")                                          \
@@ -111,6 +113,7 @@ class rich_location;
   OP(SCOPE,            "::")                                           \
   OP(DEREF_STAR,       "->*")                                          \
   OP(DOT_STAR,         ".*")                                           \
+  OP(REFLECT_OP,       "^^")                                           \
   OP(ATSIGN,           "@")  /* used in Objective-C */                 \
                                                                        \
   TK(NAME,             IDENT)   /* word */                             \
@@ -1306,6 +1309,9 @@ extern const char *cpp_interpret_string_ranges (cpp_reader *pfile,
 extern bool cpp_interpret_string_notranslate (cpp_reader *,
                                              const cpp_string *, size_t,
                                              cpp_string *, enum cpp_ttype);
+extern bool cpp_translate_string (cpp_reader *, const cpp_string *,
+                                 cpp_string *, enum cpp_ttype, bool);
+extern bool cpp_valid_identifier (cpp_reader *, const unsigned char *);
 
 /* Convert a host character constant to the execution character set.  */
 extern cppchar_t cpp_host_to_exec_charset (cpp_reader *, cppchar_t);
index df607de4bd8c456bfab755ed182fe8e0e021ed76..017e980a964129155ab8134fe17d7ff7c80887b2 100644 (file)
@@ -543,6 +543,14 @@ struct cpp_reader
      wide execution character set.  */
   struct cset_converter wide_cset_desc;
 
+  /* Descriptor for converting from the execution character set to the
+     source character set.  */
+  struct cset_converter reverse_narrow_cset_desc;
+
+  /* Descriptor for converting from the UTF-8 execution character set to the
+     source character set.  */
+  struct cset_converter reverse_utf8_cset_desc;
+
   /* Date and time text.  Calculated together if either is requested.  */
   const unsigned char *date;
   const unsigned char *time;
index 9d4c527d4cb8eae50545586fa0520ced2a8c84ad..df278534eeeef43184e9c10e9187c70c27721764 100644 (file)
@@ -4312,6 +4312,10 @@ _cpp_lex_direct (cpp_reader *pfile)
          else
            result->flags |= COLON_SCOPE;
        }
+      else if (*buffer->cur == ']'
+              && CPP_OPTION (pfile, cplusplus)
+              && CPP_OPTION (pfile, lang) >= CLK_GNUCXX26)
+       buffer->cur++, result->type = CPP_CLOSE_SPLICE;
       else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs))
        {
          buffer->cur++;
@@ -4323,7 +4327,15 @@ _cpp_lex_direct (cpp_reader *pfile)
     case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break;
     case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break;
     case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break;
-    case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break;
+    case '^':
+      result->type = CPP_XOR;
+      if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_XOR_EQ;
+      else if (*buffer->cur == '^'
+              && CPP_OPTION (pfile, cplusplus)
+              && CPP_OPTION (pfile, lang) >= CLK_GNUCXX26)
+       buffer->cur++, result->type = CPP_REFLECT_OP;
+      break;
     case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); result->val.token_no = 0; break;
 
     case '?': result->type = CPP_QUERY; break;
@@ -4331,7 +4343,24 @@ _cpp_lex_direct (cpp_reader *pfile)
     case ',': result->type = CPP_COMMA; break;
     case '(': result->type = CPP_OPEN_PAREN; break;
     case ')': result->type = CPP_CLOSE_PAREN; break;
-    case '[': result->type = CPP_OPEN_SQUARE; break;
+    case '[':
+      result->type = CPP_OPEN_SQUARE;
+      /* C++ [lex.pptoken]/4.3: "Otherwise, if the next three characters are
+        [:: and the subsequent character is not :, or if the next three
+        characters are [:>, the [ is treated as a preprocessing token by
+        itself and not as the first character of the preprocessing token [:."
+        Also, the tokens [: and :] cannot be composed from digraphs.  */
+      if (*buffer->cur == ':'
+         && CPP_OPTION (pfile, cplusplus)
+         && CPP_OPTION (pfile, lang) >= CLK_GNUCXX26)
+       {
+         if ((buffer->cur[1] == ':' && buffer->cur[2] != ':')
+             || buffer->cur[1] == '>')
+           break;
+         else
+           buffer->cur++, result->type = CPP_OPEN_SPLICE;
+       }
+      break;
     case ']': result->type = CPP_CLOSE_SQUARE; break;
     case '{': result->type = CPP_OPEN_BRACE; break;
     case '}': result->type = CPP_CLOSE_BRACE; break;
index ede10ec938f246373d54a8438e323433d3350ab2..dd1cc1ceb2f478238bc1b11778ce1b262897111b 100644 (file)
@@ -89,6 +89,7 @@ std_headers = \
        ${std_srcdir}/locale \
        ${std_srcdir}/map \
        ${std_srcdir}/memory_resource \
+       ${std_srcdir}/meta \
        ${std_srcdir}/mutex \
        ${std_srcdir}/ostream \
        ${std_srcdir}/print \
index d108eb0155b0778612ba541885a5dc571345700c..1dfb40385f5de7acf439003078bfccbbef72e5b2 100644 (file)
@@ -448,6 +448,7 @@ std_freestanding = \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/locale \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/map \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/memory_resource \
+@GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/meta \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/mutex \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/ostream \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/print \
index 8f97314a3741d9e42305bad87a84509b584c6a15..9c62ea78f7da9469b439addb97d770f8a340dcf2 100644 (file)
@@ -1005,7 +1005,7 @@ namespace ranges
     // for use by __range_iter_t below.
     template<typename _Tp>
       requires is_array_v<_Tp> || __member_begin<_Tp&> || __adl_begin<_Tp&>
-      auto
+      constexpr auto
       __begin(_Tp& __t)
       {
        if constexpr (is_array_v<_Tp>)
index e0b99b82a338c2006f6b5096cba5459c90f76e8b..175e695a96db1040c2e1a39e3bdec4984ec37fff 100644 (file)
@@ -2253,6 +2253,15 @@ ftms = {
   };
 };
 
+ftms = {
+  name = reflection;
+  values = {
+    v = 202506;
+    cxxmin = 26;
+    extra_cond = "__cpp_impl_reflection >= 202506L";
+  };
+};
+
 ftms = {
   name = is_implicit_lifetime;
   values = {
index 602deb5fc3bd0ae6a6310853fe1c7426171aece3..020c256ca0cad0a3a695c835e00e8781e45ae4a5 100644 (file)
 #endif /* !defined(__cpp_lib_is_implicit_lifetime) */
 #undef __glibcxx_want_is_implicit_lifetime
 
+#if !defined(__cpp_lib_reflection)
+# if (__cplusplus >  202302L) && (__cpp_impl_reflection >= 202506L)
+#  define __glibcxx_reflection 202506L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_reflection)
+#   define __cpp_lib_reflection 202506L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_reflection) */
+#undef __glibcxx_want_reflection
+
 #undef __glibcxx_want_all
index 96a75bd574fcf83407d9be9f457c95a5deaf1b89..433082facacdbb12b12bc753ccfd6dce7e58dbed 100644 (file)
 #if __cplusplus > 202302L
 #include <debugging>
 #include <inplace_vector>
+#include <meta>
 #include <text_encoding>
 #include <stdbit.h>
 #include <stdckdint.h>
diff --git a/libstdc++-v3/include/std/meta b/libstdc++-v3/include/std/meta
new file mode 100644 (file)
index 0000000..033746a
--- /dev/null
@@ -0,0 +1,653 @@
+// <meta> -*- C++ -*-
+
+// Copyright (C) 2025-2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/meta
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_META
+#define _GLIBCXX_META 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#define __glibcxx_want_reflection
+#include <bits/version.h>
+
+#if __glibcxx_reflection >= 202506L // C++ >= 26 && __cpp_impl_reflection
+
+#include <array>
+#include <initializer_list>
+#include <optional>
+#include <source_location>
+#include <span>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#if __has_builtin(__builtin_is_string_literal)
+  // [meta.string.literal], checking string literals
+  consteval bool is_string_literal(const char* __p)
+  {
+    return __builtin_is_string_literal(__p);
+  }
+
+  consteval bool is_string_literal(const wchar_t* __p)
+  {
+    return __builtin_is_string_literal(__p);
+  }
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+  consteval bool is_string_literal(const char8_t* __p)
+  {
+    return __builtin_is_string_literal(__p);
+  }
+#endif
+
+  consteval bool is_string_literal(const char16_t* __p)
+  {
+    return __builtin_is_string_literal(__p);
+  }
+
+  consteval bool is_string_literal(const char32_t* __p)
+  {
+    return __builtin_is_string_literal(__p);
+  }
+#endif
+
+  namespace meta
+  {
+    using info = decltype(^^int);
+
+    // [meta.reflection.exception], class exception
+    class exception : public std::exception {
+    private:
+      string _M_what;
+      u8string _M_u8what;
+      info _M_from;
+      source_location _M_where;
+
+    public:
+      consteval
+      exception(u8string_view __what, info __from,
+               source_location __where = source_location::current()) noexcept
+       : _M_what{_S_exception_cvt_from_utf8(__what)}, _M_u8what{__what},
+         _M_from{__from}, _M_where{__where} {}
+
+      consteval
+      exception(string_view __what, info __from,
+               source_location __where = source_location::current()) noexcept
+       : _M_what{__what}, _M_u8what{_S_exception_cvt_to_utf8(__what)},
+         _M_from{__from}, _M_where{__where} {}
+
+      consteval exception(const exception&) = default;
+      consteval exception(exception&&) = default;
+
+      consteval exception& operator=(const exception&) = default;
+      consteval exception& operator=(exception&&) = default;
+
+      consteval const char*
+      what() const noexcept override
+      {
+       // If u8string is not empty and string is empty, conversion
+       // from UTF-8 to ordinary literal encoding failed.
+       // In that case what() should be non-constant.
+       if (_M_what.size() == 0 && _M_u8what.size() != 0)
+         asm("");
+       return _M_what.c_str();
+      }
+      consteval u8string_view u8what() const noexcept { return _M_u8what; }
+      consteval info from() const noexcept { return _M_from; }
+      consteval source_location where() const noexcept { return _M_where; }
+    private:
+      // Helper special template metafunctions to convert from UTF-8 to
+      // ordinary literal encoding and vice versa.  On conversion failure
+      // they just return an empty {,u8}string_view.
+      template<ranges::input_range _Rg>
+       static consteval u8string_view _S_exception_cvt_to_utf8(_Rg&&);
+      template<ranges::input_range _Rg>
+       static consteval string_view _S_exception_cvt_from_utf8(_Rg&&);
+    };
+
+    // [meta.reflection.operators], operator representations
+    enum class operators {
+      op_new = 1,
+      op_delete,
+      op_array_new,
+      op_array_delete,
+      op_co_await,
+      op_parentheses,
+      op_square_brackets,
+      op_arrow,
+      op_arrow_star,
+      op_tilde,
+      op_exclamation,
+      op_plus,
+      op_minus,
+      op_star,
+      op_slash,
+      op_percent,
+      op_caret,
+      op_ampersand,
+      op_equals,
+      op_pipe,
+      op_plus_equals,
+      op_minus_equals,
+      op_star_equals,
+      op_slash_equals,
+      op_percent_equals,
+      op_caret_equals,
+      op_ampersand_equals,
+      op_pipe_equals,
+      op_equals_equals,
+      op_exclamation_equals,
+      op_less,
+      op_greater,
+      op_less_equals,
+      op_greater_equals,
+      op_spaceship,
+      op_ampersand_ampersand,
+      op_pipe_pipe,
+      op_less_less,
+      op_greater_greater,
+      op_less_less_equals,
+      op_greater_greater_equals,
+      op_plus_plus,
+      op_minus_minus,
+      op_comma
+    };
+    using enum operators;
+    consteval operators operator_of(info);
+    consteval string_view symbol_of(operators);
+    consteval u8string_view u8symbol_of(operators);
+
+    // [meta.reflection.names], reflection names and locations
+    consteval bool has_identifier(info);
+
+    consteval string_view identifier_of(info);
+    consteval u8string_view u8identifier_of(info);
+
+    consteval string_view display_string_of(info);
+    consteval u8string_view u8display_string_of(info);
+
+    consteval source_location source_location_of(info);
+
+    // [meta.reflection.queries], reflection queries
+    consteval info type_of(info);
+    consteval info object_of(info);
+    consteval info constant_of(info);
+
+    consteval bool is_public(info);
+    consteval bool is_protected(info);
+    consteval bool is_private(info);
+
+    consteval bool is_virtual(info);
+    consteval bool is_pure_virtual(info);
+    consteval bool is_override(info);
+    consteval bool is_final(info);
+
+    consteval bool is_deleted(info);
+    consteval bool is_defaulted(info);
+    consteval bool is_user_provided(info);
+    consteval bool is_user_declared(info);
+    consteval bool is_explicit(info);
+    consteval bool is_noexcept(info);
+
+    consteval bool is_bit_field(info);
+    consteval bool is_enumerator(info);
+    consteval bool is_annotation(info);
+
+    consteval bool is_const(info);
+    consteval bool is_volatile(info);
+    consteval bool is_mutable_member(info);
+    consteval bool is_lvalue_reference_qualified(info);
+    consteval bool is_rvalue_reference_qualified(info);
+
+    consteval bool has_static_storage_duration(info);
+    consteval bool has_thread_storage_duration(info);
+    consteval bool has_automatic_storage_duration(info);
+
+    consteval bool has_internal_linkage(info);
+    consteval bool has_module_linkage(info);
+    consteval bool has_external_linkage(info);
+    consteval bool has_c_language_linkage(info);
+    consteval bool has_linkage(info);
+
+    consteval bool is_complete_type(info);
+    consteval bool is_enumerable_type(info);
+
+    consteval bool is_variable(info);
+    consteval bool is_type(info);
+    consteval bool is_namespace(info);
+    consteval bool is_type_alias(info);
+    consteval bool is_namespace_alias(info);
+
+    consteval bool is_function(info);
+    consteval bool is_conversion_function(info);
+    consteval bool is_operator_function(info);
+    consteval bool is_literal_operator(info);
+    consteval bool is_special_member_function(info);
+    consteval bool is_constructor(info);
+    consteval bool is_default_constructor(info);
+    consteval bool is_copy_constructor(info);
+    consteval bool is_move_constructor(info);
+    consteval bool is_assignment(info);
+    consteval bool is_copy_assignment(info);
+    consteval bool is_move_assignment(info);
+    consteval bool is_destructor(info);
+
+    consteval bool is_function_parameter(info);
+    consteval bool is_explicit_object_parameter(info);
+    consteval bool has_default_argument(info);
+    consteval bool has_ellipsis_parameter(info);
+
+    consteval bool is_template(info);
+    consteval bool is_function_template(info);
+    consteval bool is_variable_template(info);
+    consteval bool is_class_template(info);
+    consteval bool is_alias_template(info);
+    consteval bool is_conversion_function_template(info);
+    consteval bool is_operator_function_template(info);
+    consteval bool is_literal_operator_template(info);
+    consteval bool is_constructor_template(info);
+    consteval bool is_concept(info);
+
+    consteval bool is_value(info);
+    consteval bool is_object(info);
+
+    consteval bool is_structured_binding(info);
+
+    consteval bool is_class_member(info);
+    consteval bool is_namespace_member(info);
+    consteval bool is_nonstatic_data_member(info);
+    consteval bool is_static_member(info);
+    consteval bool is_base(info);
+
+    consteval bool has_default_member_initializer(info);
+
+    consteval bool has_parent(info);
+    consteval info parent_of(info);
+
+    consteval info dealias(info);
+
+    consteval bool has_template_arguments(info);
+    consteval info template_of(info);
+    consteval vector<info> template_arguments_of(info);
+    consteval vector<info> parameters_of(info);
+    consteval info variable_of(info);
+    consteval info return_type_of(info);
+
+    // [meta.reflection.access.context], access control context
+    struct access_context {
+    private:
+      consteval access_context(info __scope, info __designating_class) noexcept
+       : _M_scope{__scope}, _M_designating_class{__designating_class} { }
+    public:
+      access_context() = delete;
+      consteval access_context(const access_context &) = default;
+      consteval access_context(access_context &&) = default;
+
+      consteval info scope() const { return _M_scope; }
+      consteval info designating_class() const { return _M_designating_class; }
+
+      static consteval access_context current() noexcept;
+      static consteval access_context unprivileged() noexcept
+      { return access_context { ^^::, info {} }; }
+      static consteval access_context unchecked() noexcept
+      { return access_context { info {}, info {} }; }
+      consteval access_context via(info) const;
+
+      info _M_scope;
+      info _M_designating_class;
+    };
+
+    // [meta.reflection.access.queries], member accessibility queries
+    consteval bool is_accessible(info, access_context);
+    consteval bool has_inaccessible_nonstatic_data_members(info,
+                                                          access_context);
+    consteval bool has_inaccessible_bases(info, access_context);
+    consteval bool has_inaccessible_subobjects(info, access_context);
+
+    // [meta.reflection.member.queries], reflection member queries
+    consteval vector<info> members_of(info, access_context);
+    consteval vector<info> bases_of(info, access_context);
+    consteval vector<info> static_data_members_of(info, access_context);
+    consteval vector<info> nonstatic_data_members_of(info, access_context);
+    consteval vector<info> subobjects_of(info, access_context);
+    consteval vector<info> enumerators_of(info);
+
+    // [meta.reflection.layout], reflection layout queries
+    struct member_offset {
+      ptrdiff_t bytes;
+      ptrdiff_t bits;
+
+      constexpr ptrdiff_t
+      total_bits() const
+      { return bytes * __CHAR_BIT__ + bits; }
+
+      auto operator<=>(const member_offset&) const = default;
+    };
+
+    consteval member_offset offset_of(info);
+    consteval size_t size_of(info);
+    consteval size_t alignment_of(info);
+    consteval size_t bit_size_of(info);
+
+    // [meta.reflection.extract], value extraction
+    template<class _Tp>
+      consteval _Tp extract(info);
+
+    // [meta.reflection.substitute], reflection substitution
+    template<class _Rg>
+      concept reflection_range = ranges::input_range<_Rg>
+       && same_as<ranges::range_value_t<_Rg>, info>
+       && same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, info>;
+
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool can_substitute(info, _Rg&&);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval info substitute(info, _Rg&&);
+
+    // [meta.reflection.result], expression result reflection
+    template<typename _Tp>
+      requires (is_copy_constructible_v<_Tp>)
+      consteval info reflect_constant(_Tp);
+    template<typename _Tp>
+      requires (!is_function_v<remove_reference_t<_Tp>>)
+      consteval info reflect_object(_Tp&);
+    template<typename _Tp>
+      requires (is_function_v<remove_reference_t<_Tp>>)
+      consteval info reflect_function(_Tp&);
+
+    // [meta.reflection.array], promoting to static storage arrays
+    template<ranges::input_range _Rg>
+      consteval info reflect_constant_string(_Rg&&);
+
+    template<ranges::input_range _Rg>
+      consteval info reflect_constant_array(_Rg&&);
+
+    // [meta.reflection.define.aggregate], class definition generation
+    struct data_member_options {
+      struct _Name {
+       template<class _Tp>
+         requires constructible_from<u8string, _Tp>
+         consteval _Name(_Tp&& __n) : _M_is_u8(true), _M_u8s((_Tp&&) __n) {}
+
+       template<class _Tp>
+         requires constructible_from<string, _Tp>
+         consteval _Name(_Tp&& __n) : _M_is_u8(false), _M_s((_Tp&&) __n) {}
+
+      private:
+       bool _M_is_u8;
+       u8string _M_u8s;
+       string _M_s;
+       info _M_unused = {};
+      };
+
+      optional<_Name> name;
+      optional<int> alignment;
+      optional<int> bit_width;
+      bool no_unique_address = false;
+    };
+    consteval info data_member_spec(info, data_member_options);
+    consteval bool is_data_member_spec(info);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval info define_aggregate(info, _Rg&&);
+
+    // associated with [meta.unary.cat], primary type categories
+    consteval bool is_void_type(info);
+    consteval bool is_null_pointer_type(info);
+    consteval bool is_integral_type(info);
+    consteval bool is_floating_point_type(info);
+    consteval bool is_array_type(info);
+    consteval bool is_pointer_type(info);
+    consteval bool is_lvalue_reference_type(info);
+    consteval bool is_rvalue_reference_type(info);
+    consteval bool is_member_object_pointer_type(info);
+    consteval bool is_member_function_pointer_type(info);
+    consteval bool is_enum_type(info);
+    consteval bool is_union_type(info);
+    consteval bool is_class_type(info);
+    consteval bool is_function_type(info);
+    consteval bool is_reflection_type(info);
+
+    // associated with [meta.unary.comp], composite type categories
+    consteval bool is_reference_type(info);
+    consteval bool is_arithmetic_type(info);
+    consteval bool is_fundamental_type(info);
+    consteval bool is_object_type(info);
+    consteval bool is_scalar_type(info);
+    consteval bool is_compound_type(info);
+    consteval bool is_member_pointer_type(info);
+
+    // associated with [meta.unary.prop], type properties
+    consteval bool is_const_type(info);
+    consteval bool is_volatile_type(info);
+    consteval bool is_trivially_copyable_type(info);
+    consteval bool is_standard_layout_type(info);
+    consteval bool is_empty_type(info);
+    consteval bool is_polymorphic_type(info);
+    consteval bool is_abstract_type(info);
+    consteval bool is_final_type(info);
+    consteval bool is_aggregate_type(info);
+    consteval bool is_consteval_only_type(info);
+    consteval bool is_signed_type(info);
+    consteval bool is_unsigned_type(info);
+    consteval bool is_bounded_array_type(info);
+    consteval bool is_unbounded_array_type(info);
+    consteval bool is_scoped_enum_type(info);
+
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_constructible_type(info, _Rg&&);
+    consteval bool is_default_constructible_type(info);
+    consteval bool is_copy_constructible_type(info);
+    consteval bool is_move_constructible_type(info);
+
+    consteval bool is_assignable_type(info, info);
+    consteval bool is_copy_assignable_type(info);
+    consteval bool is_move_assignable_type(info);
+
+    consteval bool is_swappable_with_type(info, info);
+    consteval bool is_swappable_type(info);
+
+    consteval bool is_destructible_type(info);
+
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_trivially_constructible_type(info, _Rg&&);
+    consteval bool is_trivially_default_constructible_type(info);
+    consteval bool is_trivially_copy_constructible_type(info);
+    consteval bool is_trivially_move_constructible_type(info);
+
+    consteval bool is_trivially_assignable_type(info, info);
+    consteval bool is_trivially_copy_assignable_type(info);
+    consteval bool is_trivially_move_assignable_type(info);
+    consteval bool is_trivially_destructible_type(info);
+
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_nothrow_constructible_type(info, _Rg&&);
+    consteval bool is_nothrow_default_constructible_type(info);
+    consteval bool is_nothrow_copy_constructible_type(info);
+    consteval bool is_nothrow_move_constructible_type(info);
+
+    consteval bool is_nothrow_assignable_type(info, info);
+    consteval bool is_nothrow_copy_assignable_type(info);
+    consteval bool is_nothrow_move_assignable_type(info);
+
+    consteval bool is_nothrow_swappable_with_type(info, info);
+    consteval bool is_nothrow_swappable_type(info);
+
+    consteval bool is_nothrow_destructible_type(info);
+
+    consteval bool is_implicit_lifetime_type(info);
+
+    consteval bool has_virtual_destructor(info);
+
+    consteval bool has_unique_object_representations(info);
+
+    consteval bool reference_constructs_from_temporary(info, info);
+    consteval bool reference_converts_from_temporary(info, info);
+
+    // associated with [meta.unary.prop.query], type property queries
+    consteval size_t rank(info);
+    consteval size_t extent(info, unsigned = 0);
+
+    // associated with [meta.rel], type relations
+    consteval bool is_same_type(info, info);
+    consteval bool is_base_of_type(info, info);
+    consteval bool is_virtual_base_of_type(info, info);
+    consteval bool is_convertible_type(info, info);
+    consteval bool is_nothrow_convertible_type(info, info);
+    consteval bool is_layout_compatible_type(info, info);
+    consteval bool is_pointer_interconvertible_base_of_type(info, info);
+
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_invocable_type(info, _Rg&&);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_invocable_r_type(info, info, _Rg&&);
+
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_nothrow_invocable_type(info, _Rg&&);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval bool is_nothrow_invocable_r_type(info, info, _Rg&&);
+
+    // associated with [meta.trans.cv], const-volatile modifications
+    consteval info remove_const(info);
+    consteval info remove_volatile(info);
+    consteval info remove_cv(info);
+    consteval info add_const(info);
+    consteval info add_volatile(info);
+    consteval info add_cv(info);
+
+    // associated with [meta.trans.ref], reference modifications
+    consteval info remove_reference(info);
+    consteval info add_lvalue_reference(info);
+    consteval info add_rvalue_reference(info);
+
+    // associated with [meta.trans.sign], sign modifications
+    consteval info make_signed(info);
+    consteval info make_unsigned(info);
+
+    // associated with [meta.trans.arr], array modifications
+    consteval info remove_extent(info);
+    consteval info remove_all_extents(info);
+
+    // associated with [meta.trans.ptr], pointer modifications
+    consteval info remove_pointer(info);
+    consteval info add_pointer(info);
+
+    // associated with [meta.trans.other], other transformations
+    consteval info remove_cvref(info);
+    consteval info decay(info);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval info common_type(_Rg&&);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval info common_reference(_Rg&&);
+    consteval info underlying_type(info);
+    template<reflection_range _Rg = initializer_list<info>>
+      consteval info invoke_result(info, _Rg&&);
+    consteval info unwrap_reference(info);
+    consteval info unwrap_ref_decay(info);
+
+    consteval size_t tuple_size(info);
+    consteval info tuple_element(size_t, info);
+
+    consteval size_t variant_size(info);
+    consteval info variant_alternative(size_t, info);
+
+    consteval strong_ordering type_order(info, info);
+
+    // [meta.reflection.annotation], annotation reflection
+    consteval vector<info> annotations_of(info);
+    consteval vector<info> annotations_of_with_type(info, info);
+
+    consteval access_context
+    access_context::via(info __cls) const
+    {
+      if (__cls != info {}
+         && (!std::meta::is_class_type(__cls)
+             || !std::meta::is_complete_type(__cls)))
+       {
+#if __cpp_exceptions
+         throw std::meta::exception(u8"via argument other than null "
+                                      "or complete class type reflection",
+                                    ^^access_context::via);
+#else
+         asm("");
+         return *this;
+#endif
+       }
+      return access_context { _M_scope, __cls };
+    }
+
+  } // namespace meta
+
+  // [meta.define.static], promoting to static storage strings
+  template<ranges::input_range _Rg>
+    consteval const ranges::range_value_t<_Rg>*
+    define_static_string(_Rg&& __r)
+    {
+      auto __str = meta::reflect_constant_string(__r);
+      return meta::extract<const ranges::range_value_t<_Rg>*>(__str);
+    }
+
+  template<ranges::input_range _Rg>
+    consteval span<const ranges::range_value_t<_Rg>>
+    define_static_array(_Rg&& __r)
+    {
+      using _Tp = ranges::range_value_t<_Rg>;
+      auto __array = meta::reflect_constant_array(__r);
+      auto __type = meta::type_of(__array);
+      if (meta::is_array_type(__type))
+       return span<const _Tp>(meta::extract<const _Tp*>(__array),
+                              meta::extent(__type, 0U));
+      else
+       return span<const _Tp>();
+    }
+
+  template<class _Tp>
+    consteval const remove_cvref_t<_Tp>*
+    define_static_object(_Tp&& __t)
+    {
+      using _Up = remove_cvref_t<_Tp>;
+      if constexpr (meta::is_class_type(^^_Up))
+       {
+         auto __cst = meta::reflect_constant(std::forward<_Tp>(__t));
+         return std::addressof(meta::extract<const _Up&>(__cst));
+       }
+      else
+       return std::define_static_array(span<const _Up>(std::addressof(__t),
+                                                       1)).data();
+    }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++26
+
+#endif // _GLIBCXX_META
index f9fbc32514ca0afbee5fb68049c81a8d27f8e7e7..82ee22c63e53db0d99e2afae0287f8130cda6bdf 100644 (file)
@@ -749,6 +749,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public false_type { };
 #endif
 
+#if __cpp_impl_reflection >= 202500L // C++ >= 26
+  /// is_reflection
+  template<typename _Tp>
+    struct is_reflection
+    : public false_type { };
+
+  template<>
+    struct is_reflection<decltype(^^int)>
+    : public true_type { };
+
+  template<>
+    struct is_reflection<const decltype(^^int)>
+    : public true_type { };
+
+  template<>
+    struct is_reflection<volatile decltype(^^int)>
+    : public true_type { };
+
+  template<>
+    struct is_reflection<const volatile decltype(^^int)>
+    : public true_type { };
+#endif
+
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
   template<typename _Tp>
@@ -814,7 +837,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_fundamental
     : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-                  is_null_pointer<_Tp>>::type
+                  is_null_pointer<_Tp>
+#if __cpp_impl_reflection >= 202500L
+                  , is_reflection<_Tp>
+#endif
+                  >::type
     { };
 
   /// is_object
@@ -3528,6 +3555,19 @@ template <typename _Tp>
     is_member_function_pointer<_Tp>::value;
 #endif
 
+#if __cpp_impl_reflection >= 202500L // C++ >= 26
+template <typename _Tp>
+  inline constexpr bool is_reflection_v = false;
+template <>
+  inline constexpr bool is_reflection_v<decltype(^^int)> = true;
+template <>
+  inline constexpr bool is_reflection_v<const decltype(^^int)> = true;
+template <>
+  inline constexpr bool is_reflection_v<volatile decltype(^^int)> = true;
+template <>
+  inline constexpr bool is_reflection_v<const volatile decltype(^^int)> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
@@ -3860,6 +3900,24 @@ template<typename _Ret, typename _Fn, typename... _Args>
 # endif
 #endif
 
+#if __cpp_impl_reflection >= 202500L \
+    && _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_is_consteval_only) // C++ >= 26
+  /// is_consteval_only - true if the type is consteval-only.
+  /// @since C++26
+  template<typename _Tp>
+    struct is_consteval_only
+    : bool_constant<__builtin_is_consteval_only(_Tp)>
+    { };
+
+  /** is_consteval_only_v - true if the type is consteval-only.
+   *  @ingroup variable_templates
+   *  @since C++26
+   */
+  template<typename _Tp>
+    inline constexpr bool is_consteval_only_v
+      = __builtin_is_consteval_only(_Tp);
+#endif
+
   /** * Remove references and cv-qualifiers.
    * @since C++20
    * @{
index ef0da5d685a88aae55859de68760d87d2a15709d..e134e395bb675c86d6a41ca202792129dcae1516 100644 (file)
@@ -2057,6 +2057,261 @@ export namespace std::pmr
   using std::pmr::unsynchronized_pool_resource;
 }
 
+// <meta>
+#if __glibcxx_reflection >= 202506L
+export namespace std
+{
+#if __has_builtin(__builtin_is_string_literal)
+  using std::is_string_literal;
+#endif
+  using std::define_static_string;
+  using std::define_static_array;
+  using std::define_static_object;
+  namespace meta
+  {
+    using std::meta::info;
+    using std::meta::exception;
+    using std::meta::operators;
+    using enum std::meta::operators;
+    using std::meta::operator_of;
+    using std::meta::symbol_of;
+    using std::meta::u8symbol_of;
+    using std::meta::has_identifier;
+    using std::meta::identifier_of;
+    using std::meta::u8identifier_of;
+    using std::meta::display_string_of;
+    using std::meta::u8display_string_of;
+    using std::meta::source_location_of;
+    using std::meta::type_of;
+    using std::meta::object_of;
+    using std::meta::constant_of;
+    using std::meta::is_public;
+    using std::meta::is_protected;
+    using std::meta::is_private;
+    using std::meta::is_virtual;
+    using std::meta::is_pure_virtual;
+    using std::meta::is_override;
+    using std::meta::is_final;
+    using std::meta::is_deleted;
+    using std::meta::is_defaulted;
+    using std::meta::is_user_provided;
+    using std::meta::is_user_declared;
+    using std::meta::is_explicit;
+    using std::meta::is_noexcept;
+    using std::meta::is_bit_field;
+    using std::meta::is_enumerator;
+    using std::meta::is_annotation;
+    using std::meta::is_const;
+    using std::meta::is_volatile;
+    using std::meta::is_mutable_member;
+    using std::meta::is_lvalue_reference_qualified;
+    using std::meta::is_rvalue_reference_qualified;
+    using std::meta::has_static_storage_duration;
+    using std::meta::has_thread_storage_duration;
+    using std::meta::has_automatic_storage_duration;
+    using std::meta::has_internal_linkage;
+    using std::meta::has_module_linkage;
+    using std::meta::has_external_linkage;
+    using std::meta::has_c_language_linkage;
+    using std::meta::has_linkage;
+    using std::meta::is_complete_type;
+    using std::meta::is_enumerable_type;
+    using std::meta::is_variable;
+    using std::meta::is_type;
+    using std::meta::is_namespace;
+    using std::meta::is_type_alias;
+    using std::meta::is_namespace_alias;
+    using std::meta::is_function;
+    using std::meta::is_conversion_function;
+    using std::meta::is_operator_function;
+    using std::meta::is_literal_operator;
+    using std::meta::is_special_member_function;
+    using std::meta::is_constructor;
+    using std::meta::is_default_constructor;
+    using std::meta::is_copy_constructor;
+    using std::meta::is_move_constructor;
+    using std::meta::is_assignment;
+    using std::meta::is_copy_assignment;
+    using std::meta::is_move_assignment;
+    using std::meta::is_destructor;
+    using std::meta::is_function_parameter;
+    using std::meta::is_explicit_object_parameter;
+    using std::meta::has_default_argument;
+    using std::meta::has_ellipsis_parameter;
+    using std::meta::is_template;
+    using std::meta::is_function_template;
+    using std::meta::is_variable_template;
+    using std::meta::is_class_template;
+    using std::meta::is_alias_template;
+    using std::meta::is_conversion_function_template;
+    using std::meta::is_operator_function_template;
+    using std::meta::is_literal_operator_template;
+    using std::meta::is_constructor_template;
+    using std::meta::is_concept;
+    using std::meta::is_value;
+    using std::meta::is_object;
+    using std::meta::is_structured_binding;
+    using std::meta::is_class_member;
+    using std::meta::is_namespace_member;
+    using std::meta::is_nonstatic_data_member;
+    using std::meta::is_static_member;
+    using std::meta::is_base;
+    using std::meta::has_default_member_initializer;
+    using std::meta::has_parent;
+    using std::meta::parent_of;
+    using std::meta::dealias;
+    using std::meta::has_template_arguments;
+    using std::meta::template_of;
+    using std::meta::template_arguments_of;
+    using std::meta::parameters_of;
+    using std::meta::variable_of;
+    using std::meta::return_type_of;
+    using std::meta::access_context;
+    using std::meta::is_accessible;
+    using std::meta::has_inaccessible_nonstatic_data_members;
+    using std::meta::has_inaccessible_bases;
+    using std::meta::has_inaccessible_subobjects;
+    using std::meta::members_of;
+    using std::meta::bases_of;
+    using std::meta::static_data_members_of;
+    using std::meta::nonstatic_data_members_of;
+    using std::meta::subobjects_of;
+    using std::meta::enumerators_of;
+    using std::meta::member_offset;
+    using std::meta::offset_of;
+    using std::meta::size_of;
+    using std::meta::alignment_of;
+    using std::meta::bit_size_of;
+    using std::meta::extract;
+    using std::meta::reflection_range;
+    using std::meta::can_substitute;
+    using std::meta::substitute;
+    using std::meta::reflect_constant;
+    using std::meta::reflect_object;
+    using std::meta::reflect_function;
+    using std::meta::reflect_constant_string;
+    using std::meta::reflect_constant_array;
+    using std::meta::data_member_options;
+    using std::meta::data_member_spec;
+    using std::meta::is_data_member_spec;
+    using std::meta::define_aggregate;
+    using std::meta::is_void_type;
+    using std::meta::is_null_pointer_type;
+    using std::meta::is_integral_type;
+    using std::meta::is_floating_point_type;
+    using std::meta::is_array_type;
+    using std::meta::is_pointer_type;
+    using std::meta::is_lvalue_reference_type;
+    using std::meta::is_rvalue_reference_type;
+    using std::meta::is_member_object_pointer_type;
+    using std::meta::is_member_function_pointer_type;
+    using std::meta::is_enum_type;
+    using std::meta::is_union_type;
+    using std::meta::is_class_type;
+    using std::meta::is_function_type;
+    using std::meta::is_reflection_type;
+    using std::meta::is_reference_type;
+    using std::meta::is_arithmetic_type;
+    using std::meta::is_fundamental_type;
+    using std::meta::is_object_type;
+    using std::meta::is_scalar_type;
+    using std::meta::is_compound_type;
+    using std::meta::is_member_pointer_type;
+    using std::meta::is_const_type;
+    using std::meta::is_volatile_type;
+    using std::meta::is_trivially_copyable_type;
+    using std::meta::is_standard_layout_type;
+    using std::meta::is_empty_type;
+    using std::meta::is_polymorphic_type;
+    using std::meta::is_abstract_type;
+    using std::meta::is_final_type;
+    using std::meta::is_aggregate_type;
+    using std::meta::is_consteval_only_type;
+    using std::meta::is_signed_type;
+    using std::meta::is_unsigned_type;
+    using std::meta::is_bounded_array_type;
+    using std::meta::is_unbounded_array_type;
+    using std::meta::is_scoped_enum_type;
+    using std::meta::is_constructible_type;
+    using std::meta::is_default_constructible_type;
+    using std::meta::is_copy_constructible_type;
+    using std::meta::is_move_constructible_type;
+    using std::meta::is_assignable_type;
+    using std::meta::is_copy_assignable_type;
+    using std::meta::is_move_assignable_type;
+    using std::meta::is_swappable_with_type;
+    using std::meta::is_swappable_type;
+    using std::meta::is_destructible_type;
+    using std::meta::is_trivially_constructible_type;
+    using std::meta::is_trivially_default_constructible_type;
+    using std::meta::is_trivially_copy_constructible_type;
+    using std::meta::is_trivially_move_constructible_type;
+    using std::meta::is_trivially_assignable_type;
+    using std::meta::is_trivially_copy_assignable_type;
+    using std::meta::is_trivially_move_assignable_type;
+    using std::meta::is_trivially_destructible_type;
+    using std::meta::is_nothrow_constructible_type;
+    using std::meta::is_nothrow_default_constructible_type;
+    using std::meta::is_nothrow_copy_constructible_type;
+    using std::meta::is_nothrow_move_constructible_type;
+    using std::meta::is_nothrow_assignable_type;
+    using std::meta::is_nothrow_copy_assignable_type;
+    using std::meta::is_nothrow_move_assignable_type;
+    using std::meta::is_nothrow_swappable_with_type;
+    using std::meta::is_nothrow_swappable_type;
+    using std::meta::is_nothrow_destructible_type;
+    using std::meta::is_implicit_lifetime_type;
+    using std::meta::has_virtual_destructor;
+    using std::meta::has_unique_object_representations;
+    using std::meta::reference_constructs_from_temporary;
+    using std::meta::reference_converts_from_temporary;
+    using std::meta::rank;
+    using std::meta::extent;
+    using std::meta::is_same_type;
+    using std::meta::is_base_of_type;
+    using std::meta::is_virtual_base_of_type;
+    using std::meta::is_convertible_type;
+    using std::meta::is_nothrow_convertible_type;
+    using std::meta::is_layout_compatible_type;
+    using std::meta::is_pointer_interconvertible_base_of_type;
+    using std::meta::is_invocable_type;
+    using std::meta::is_invocable_r_type;
+    using std::meta::is_nothrow_invocable_type;
+    using std::meta::is_nothrow_invocable_r_type;
+    using std::meta::remove_const;
+    using std::meta::remove_volatile;
+    using std::meta::remove_cv;
+    using std::meta::add_const;
+    using std::meta::add_volatile;
+    using std::meta::add_cv;
+    using std::meta::remove_reference;
+    using std::meta::add_lvalue_reference;
+    using std::meta::add_rvalue_reference;
+    using std::meta::make_signed;
+    using std::meta::make_unsigned;
+    using std::meta::remove_extent;
+    using std::meta::remove_all_extents;
+    using std::meta::remove_pointer;
+    using std::meta::add_pointer;
+    using std::meta::remove_cvref;
+    using std::meta::decay;
+    using std::meta::common_type;
+    using std::meta::common_reference;
+    using std::meta::underlying_type;
+    using std::meta::invoke_result;
+    using std::meta::unwrap_reference;
+    using std::meta::unwrap_ref_decay;
+    using std::meta::tuple_size;
+    using std::meta::tuple_element;
+    using std::meta::variant_size;
+    using std::meta::variant_alternative;
+    using std::meta::type_order;
+    using std::meta::annotations_of;
+    using std::meta::annotations_of_with_type;
+  }
+}
+#endif
+
 // <mutex>
 export namespace std
 {
diff --git a/libstdc++-v3/testsuite/20_util/is_consteval_only/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_consteval_only/requirements/explicit_instantiation.cc
new file mode 100644 (file)
index 0000000..d890f14
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+namespace std
+{
+  typedef short test_type;
+  template struct is_consteval_only<test_type>;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_consteval_only/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_consteval_only/requirements/typedefs.cc
new file mode 100644 (file)
index 0000000..29fb44c
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+void test01()
+{
+  // Check for required typedefs
+  typedef std::is_consteval_only<decltype (^^int)> test_type;
+  typedef test_type::value_type               value_type;
+  typedef test_type::type                     type;
+  typedef test_type::type::value_type         type_value_type;
+  typedef test_type::type::type               type_type;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_consteval_only/value.cc b/libstdc++-v3/testsuite/20_util/is_consteval_only/value.cc
new file mode 100644 (file)
index 0000000..7852a61
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <type_traits>
+#include <testsuite_tr1.h>
+
+void test01()
+{
+  using std::is_consteval_only;
+  using namespace __gnu_test;
+  int v = 1;
+  struct S1 { decltype(^^long) a; };
+  union U2 { int a; decltype(^^test01) b; };
+  struct S3 { const decltype(^^__gnu_test) *c; };
+  struct S4 : public S3 {};
+  struct S5 { int a; long *b; };
+
+  static_assert(test_category<is_consteval_only, decltype(^^long)>(true), "");
+  static_assert(test_category<is_consteval_only, const decltype(^^test01)>(true), "");
+  static_assert(test_category<is_consteval_only, volatile decltype(^^__gnu_test)>(true), "");
+  static_assert(test_category<is_consteval_only, const volatile decltype(^^v)>(true), "");
+  static_assert(test_category<is_consteval_only, const S1>(true), "");
+  static_assert(test_category<is_consteval_only, U2>(true), "");
+  static_assert(test_category<is_consteval_only, S3>(true), "");
+  static_assert(test_category<is_consteval_only, S4>(true), "");
+
+  // Sanity check.
+  static_assert(test_category<is_consteval_only, int>(false), "");
+  static_assert(test_category<is_consteval_only, S5>(false), "");
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_reflection/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_reflection/requirements/explicit_instantiation.cc
new file mode 100644 (file)
index 0000000..6d53380
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+namespace std
+{
+  typedef short test_type;
+  template struct is_reflection<test_type>;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_reflection/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_reflection/requirements/typedefs.cc
new file mode 100644 (file)
index 0000000..ab5c366
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+// NB: This file is for testing type_traits with NO OTHER INCLUDES.
+
+#include <type_traits>
+
+void test01()
+{
+  // Check for required typedefs
+  typedef std::is_reflection<decltype (^^int)> test_type;
+  typedef test_type::value_type               value_type;
+  typedef test_type::type                     type;
+  typedef test_type::type::value_type         type_value_type;
+  typedef test_type::type::type               type_type;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_reflection/value.cc b/libstdc++-v3/testsuite/20_util/is_reflection/value.cc
new file mode 100644 (file)
index 0000000..57f47d6
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <type_traits>
+#include <testsuite_tr1.h>
+
+void test01()
+{
+  using std::is_reflection;
+  using namespace __gnu_test;
+  int v = 1;
+
+  static_assert(test_category<is_reflection, decltype(^^long)>(true), "");
+  static_assert(test_category<is_reflection, const decltype(^^test01)>(true), "");
+  static_assert(test_category<is_reflection, volatile decltype(^^__gnu_test)>(true), "");
+  static_assert(test_category<is_reflection, const volatile decltype(^^v)>(true), "");
+
+  // Sanity check.
+  static_assert(test_category<is_reflection, int>(false), "");
+}
index e12c9c5e65718e1d99508973f812c76523359953..a0520b3d1b63c7ab55469fe0333c7f69add59388 100644 (file)
@@ -1,5 +1,6 @@
 // { dg-additional-options "-Wno-deprecated-declarations" { target c++2a } }
 // { dg-do compile { target c++17 } }
+// { dg-additional-options "-freflection" { target c++26 } }
 
 // Copyright (C) 2014-2026 Free Software Foundation, Inc.
 //
@@ -330,6 +331,15 @@ static_assert(is_convertible_v<int&, const int&>
 static_assert(!is_convertible_v<const int&, int&>
              && !is_convertible<const int&, int&>::value, "");
 
+#if __cpp_impl_reflection >= 202500L
+static_assert(is_reflection_v<decltype(^^int)>
+             && is_reflection<decltype(^^int)>::value, "");
+static_assert(!is_reflection_v<int> && !is_reflection<int>::value, "");
+static_assert(is_consteval_only_v<decltype(^^int)>
+             && is_consteval_only<decltype(^^int)>::value, "");
+static_assert(!is_consteval_only_v<int> && !is_consteval_only<int>::value, "");
+#endif
+
 static_assert(negation_v<false_type>, "");
 static_assert(!negation_v<true_type>, "");
 static_assert(conjunction_v<>, "");