[gcc r16-6808] c++: C++26 Reflection [PR120775]
Marek Polacek
mpolacek@gcc.gnu.org
Thu Jan 15 15:25:17 GMT 2026
https://gcc.gnu.org/g:4b0e94b394fa38cdc3431f3cfb333b85373bd948
commit r16-6808-g4b0e94b394fa38cdc3431f3cfb333b85373bd948
Author: Marek Polacek <polacek@redhat.com>
Date: Wed Jan 14 11:37:39 2026 -0500
c++: C++26 Reflection [PR120775]
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>
Diff:
---
gcc/attribs.cc | 42 +-
gcc/c-family/c-attribs.cc | 14 +-
gcc/c-family/c-cppbuiltin.cc | 4 +
gcc/c-family/c.opt | 4 +
gcc/cp/Make-lang.in | 20 +-
gcc/cp/config-lang.in | 2 +-
gcc/cp/constexpr.cc | 226 +-
gcc/cp/constraint.cc | 3 +
gcc/cp/cp-gimplify.cc | 96 +-
gcc/cp/cp-objcp-common.cc | 4 +
gcc/cp/cp-trait.def | 1 +
gcc/cp/cp-tree.def | 18 +
gcc/cp/cp-tree.h | 200 +-
gcc/cp/cvt.cc | 6 +
gcc/cp/cxx-pretty-print.cc | 20 +
gcc/cp/decl.cc | 167 +-
gcc/cp/decl2.cc | 92 +-
gcc/cp/error.cc | 45 +-
gcc/cp/init.cc | 7 +
gcc/cp/lex.cc | 10 +-
gcc/cp/mangle.cc | 150 +-
gcc/cp/metafns.gperf | 688 ++
gcc/cp/metafns.h | 1181 +++
gcc/cp/method.cc | 2 +-
gcc/cp/module.cc | 9 +
gcc/cp/name-lookup.cc | 34 +-
gcc/cp/operators.def | 151 +-
gcc/cp/parser.cc | 1170 ++-
gcc/cp/pt.cc | 338 +-
gcc/cp/reflect.cc | 8608 ++++++++++++++++++++
gcc/cp/search.cc | 14 +-
gcc/cp/semantics.cc | 73 +-
gcc/cp/tree.cc | 92 +-
gcc/cp/typeck.cc | 102 +-
gcc/doc/invoke.texi | 6 +-
gcc/dwarf2out.cc | 11 +-
gcc/testsuite/g++.dg/DRs/dr2581-1.C | 4 +-
gcc/testsuite/g++.dg/DRs/dr2581-2.C | 4 +-
gcc/testsuite/g++.dg/reflect/access_context1.C | 175 +
gcc/testsuite/g++.dg/reflect/access_context2.C | 15 +
gcc/testsuite/g++.dg/reflect/access_context3.C | 50 +
gcc/testsuite/g++.dg/reflect/adl1.C | 16 +
gcc/testsuite/g++.dg/reflect/alignment_of1.C | 165 +
gcc/testsuite/g++.dg/reflect/alignment_of2.C | 27 +
gcc/testsuite/g++.dg/reflect/annotations1.C | 139 +
gcc/testsuite/g++.dg/reflect/annotations2.C | 44 +
gcc/testsuite/g++.dg/reflect/annotations3.C | 174 +
gcc/testsuite/g++.dg/reflect/annotations4.C | 79 +
gcc/testsuite/g++.dg/reflect/annotations5.C | 30 +
gcc/testsuite/g++.dg/reflect/annotations6.C | 25 +
gcc/testsuite/g++.dg/reflect/annotations7.C | 12 +
gcc/testsuite/g++.dg/reflect/annotations8.C | 16 +
gcc/testsuite/g++.dg/reflect/anon1.C | 50 +
gcc/testsuite/g++.dg/reflect/anon2.C | 43 +
gcc/testsuite/g++.dg/reflect/anon3.C | 49 +
gcc/testsuite/g++.dg/reflect/bases_of1.C | 188 +
gcc/testsuite/g++.dg/reflect/bases_of2.C | 73 +
gcc/testsuite/g++.dg/reflect/bases_of3.C | 88 +
gcc/testsuite/g++.dg/reflect/bit_size_of1.C | 125 +
gcc/testsuite/g++.dg/reflect/bitfield1.C | 12 +
gcc/testsuite/g++.dg/reflect/can_substitute1.C | 200 +
gcc/testsuite/g++.dg/reflect/class1.C | 15 +
gcc/testsuite/g++.dg/reflect/class2.C | 27 +
gcc/testsuite/g++.dg/reflect/common_reference1.C | 61 +
gcc/testsuite/g++.dg/reflect/common_type1.C | 151 +
gcc/testsuite/g++.dg/reflect/compare1.C | 38 +
gcc/testsuite/g++.dg/reflect/compare10.C | 15 +
gcc/testsuite/g++.dg/reflect/compare2.C | 16 +
gcc/testsuite/g++.dg/reflect/compare3.C | 24 +
gcc/testsuite/g++.dg/reflect/compare4.C | 27 +
gcc/testsuite/g++.dg/reflect/compare5.C | 8 +
gcc/testsuite/g++.dg/reflect/compare6.C | 12 +
gcc/testsuite/g++.dg/reflect/compare7.C | 20 +
gcc/testsuite/g++.dg/reflect/compare8.C | 67 +
gcc/testsuite/g++.dg/reflect/compare9.C | 25 +
gcc/testsuite/g++.dg/reflect/compat1.C | 13 +
gcc/testsuite/g++.dg/reflect/complete1.C | 54 +
gcc/testsuite/g++.dg/reflect/constant_of1.C | 40 +
gcc/testsuite/g++.dg/reflect/constant_of2.C | 87 +
gcc/testsuite/g++.dg/reflect/constant_of3.C | 60 +
gcc/testsuite/g++.dg/reflect/constant_of4.C | 50 +
gcc/testsuite/g++.dg/reflect/constant_of5.C | 86 +
gcc/testsuite/g++.dg/reflect/constant_of6.C | 20 +
gcc/testsuite/g++.dg/reflect/constant_of7.C | 54 +
gcc/testsuite/g++.dg/reflect/constant_of8.C | 16 +
gcc/testsuite/g++.dg/reflect/constant_of9.C | 9 +
gcc/testsuite/g++.dg/reflect/crash1.C | 15 +
gcc/testsuite/g++.dg/reflect/crash10.C | 11 +
gcc/testsuite/g++.dg/reflect/crash11.C | 23 +
gcc/testsuite/g++.dg/reflect/crash12.C | 8 +
gcc/testsuite/g++.dg/reflect/crash13.C | 15 +
gcc/testsuite/g++.dg/reflect/crash14.C | 7 +
gcc/testsuite/g++.dg/reflect/crash15.C | 8 +
gcc/testsuite/g++.dg/reflect/crash16.C | 43 +
gcc/testsuite/g++.dg/reflect/crash17.C | 29 +
gcc/testsuite/g++.dg/reflect/crash18.C | 6 +
gcc/testsuite/g++.dg/reflect/crash2.C | 25 +
gcc/testsuite/g++.dg/reflect/crash3.C | 8 +
gcc/testsuite/g++.dg/reflect/crash4.C | 15 +
gcc/testsuite/g++.dg/reflect/crash5.C | 14 +
gcc/testsuite/g++.dg/reflect/crash6.C | 21 +
gcc/testsuite/g++.dg/reflect/crash7.C | 22 +
gcc/testsuite/g++.dg/reflect/crash8.C | 11 +
gcc/testsuite/g++.dg/reflect/crash9.C | 10 +
gcc/testsuite/g++.dg/reflect/data_member_spec1.C | 119 +
gcc/testsuite/g++.dg/reflect/data_member_spec2.C | 113 +
gcc/testsuite/g++.dg/reflect/data_member_spec3.C | 29 +
gcc/testsuite/g++.dg/reflect/data_member_spec4.C | 29 +
gcc/testsuite/g++.dg/reflect/dealias1.C | 36 +
gcc/testsuite/g++.dg/reflect/dealias2.C | 14 +
gcc/testsuite/g++.dg/reflect/dealias3.C | 32 +
gcc/testsuite/g++.dg/reflect/define_aggregate1.C | 108 +
gcc/testsuite/g++.dg/reflect/define_aggregate2.C | 44 +
gcc/testsuite/g++.dg/reflect/define_aggregate3.C | 217 +
gcc/testsuite/g++.dg/reflect/define_aggregate4.C | 225 +
gcc/testsuite/g++.dg/reflect/define_aggregate5.C | 25 +
.../g++.dg/reflect/define_static_array1.C | 91 +
.../g++.dg/reflect/define_static_array2.C | 30 +
.../g++.dg/reflect/define_static_array3.C | 16 +
.../g++.dg/reflect/define_static_array4.C | 17 +
.../g++.dg/reflect/define_static_object1.C | 18 +
.../g++.dg/reflect/define_static_object2.C | 18 +
.../g++.dg/reflect/define_static_string1.C | 133 +
gcc/testsuite/g++.dg/reflect/dep1.C | 14 +
gcc/testsuite/g++.dg/reflect/dep10.C | 15 +
gcc/testsuite/g++.dg/reflect/dep11.C | 18 +
gcc/testsuite/g++.dg/reflect/dep2.C | 36 +
gcc/testsuite/g++.dg/reflect/dep3.C | 33 +
gcc/testsuite/g++.dg/reflect/dep4.C | 24 +
gcc/testsuite/g++.dg/reflect/dep5.C | 29 +
gcc/testsuite/g++.dg/reflect/dep6.C | 20 +
gcc/testsuite/g++.dg/reflect/dep7.C | 23 +
gcc/testsuite/g++.dg/reflect/dep8.C | 70 +
gcc/testsuite/g++.dg/reflect/dep9.C | 40 +
gcc/testsuite/g++.dg/reflect/diag1.C | 25 +
gcc/testsuite/g++.dg/reflect/diag2.C | 25 +
gcc/testsuite/g++.dg/reflect/diag3.C | 28 +
gcc/testsuite/g++.dg/reflect/diag4.C | 17 +
gcc/testsuite/g++.dg/reflect/display_string_of1.C | 230 +
gcc/testsuite/g++.dg/reflect/eh1.C | 355 +
gcc/testsuite/g++.dg/reflect/eh2.C | 91 +
gcc/testsuite/g++.dg/reflect/eh3.C | 22 +
gcc/testsuite/g++.dg/reflect/eh4.C | 221 +
gcc/testsuite/g++.dg/reflect/eh5.C | 103 +
gcc/testsuite/g++.dg/reflect/eh6.C | 6 +
gcc/testsuite/g++.dg/reflect/eh7.C | 22 +
gcc/testsuite/g++.dg/reflect/eh8.C | 31 +
gcc/testsuite/g++.dg/reflect/eh9.C | 11 +
gcc/testsuite/g++.dg/reflect/enumerators_of1.C | 189 +
gcc/testsuite/g++.dg/reflect/error1.C | 18 +
gcc/testsuite/g++.dg/reflect/error10.C | 39 +
gcc/testsuite/g++.dg/reflect/error2.C | 19 +
gcc/testsuite/g++.dg/reflect/error3.C | 5 +
gcc/testsuite/g++.dg/reflect/error4.C | 11 +
gcc/testsuite/g++.dg/reflect/error5.C | 19 +
gcc/testsuite/g++.dg/reflect/error6.C | 24 +
gcc/testsuite/g++.dg/reflect/error8.C | 37 +
gcc/testsuite/g++.dg/reflect/error9.C | 6 +
gcc/testsuite/g++.dg/reflect/expr1.C | 68 +
gcc/testsuite/g++.dg/reflect/expr10.C | 39 +
gcc/testsuite/g++.dg/reflect/expr11.C | 32 +
gcc/testsuite/g++.dg/reflect/expr12.C | 30 +
gcc/testsuite/g++.dg/reflect/expr13.C | 20 +
gcc/testsuite/g++.dg/reflect/expr14.C | 16 +
gcc/testsuite/g++.dg/reflect/expr2.C | 60 +
gcc/testsuite/g++.dg/reflect/expr3.C | 47 +
gcc/testsuite/g++.dg/reflect/expr4.C | 61 +
gcc/testsuite/g++.dg/reflect/expr5.C | 22 +
gcc/testsuite/g++.dg/reflect/expr6.C | 49 +
gcc/testsuite/g++.dg/reflect/expr7.C | 11 +
gcc/testsuite/g++.dg/reflect/expr8.C | 30 +
gcc/testsuite/g++.dg/reflect/expr9.C | 73 +
gcc/testsuite/g++.dg/reflect/extract1.C | 183 +
gcc/testsuite/g++.dg/reflect/extract2.C | 140 +
gcc/testsuite/g++.dg/reflect/extract3.C | 90 +
gcc/testsuite/g++.dg/reflect/extract4.C | 30 +
gcc/testsuite/g++.dg/reflect/extract5.C | 31 +
gcc/testsuite/g++.dg/reflect/extract6.C | 20 +
gcc/testsuite/g++.dg/reflect/extract7.C | 27 +
gcc/testsuite/g++.dg/reflect/extract8.C | 18 +
gcc/testsuite/g++.dg/reflect/extract9.C | 25 +
gcc/testsuite/g++.dg/reflect/feat1.C | 17 +
gcc/testsuite/g++.dg/reflect/feat2.C | 11 +
.../g++.dg/reflect/has_c_language_linkage1.C | 160 +
.../g++.dg/reflect/has_default_argument1.C | 132 +
.../g++.dg/reflect/has_default_argument2.C | 32 +
.../reflect/has_default_member_initializer1.C | 133 +
.../g++.dg/reflect/has_ellipsis_parameter1.C | 148 +
.../g++.dg/reflect/has_external_linkage1.C | 149 +
.../g++.dg/reflect/has_external_linkage2.C | 13 +
gcc/testsuite/g++.dg/reflect/has_identifier1.C | 241 +
gcc/testsuite/g++.dg/reflect/has_identifier2.C | 57 +
.../g++.dg/reflect/has_internal_linkage1.C | 149 +
.../g++.dg/reflect/has_internal_linkage2.C | 13 +
gcc/testsuite/g++.dg/reflect/has_linkage1.C | 149 +
gcc/testsuite/g++.dg/reflect/has_module_linkage1.C | 149 +
gcc/testsuite/g++.dg/reflect/has_module_linkage2.C | 13 +
gcc/testsuite/g++.dg/reflect/has_parent1.C | 138 +
.../g++.dg/reflect/has_template_arguments1.C | 111 +
.../g++.dg/reflect/has_template_arguments2.C | 75 +
.../g++.dg/reflect/has_template_arguments3.C | 48 +
.../g++.dg/reflect/has_template_arguments4.C | 23 +
gcc/testsuite/g++.dg/reflect/identifier_of1.C | 181 +
gcc/testsuite/g++.dg/reflect/identifier_of2.C | 6 +
gcc/testsuite/g++.dg/reflect/init1.C | 59 +
gcc/testsuite/g++.dg/reflect/init10.C | 24 +
gcc/testsuite/g++.dg/reflect/init11.C | 25 +
gcc/testsuite/g++.dg/reflect/init12.C | 29 +
gcc/testsuite/g++.dg/reflect/init13.C | 55 +
gcc/testsuite/g++.dg/reflect/init14.C | 16 +
gcc/testsuite/g++.dg/reflect/init15.C | 29 +
gcc/testsuite/g++.dg/reflect/init16.C | 47 +
gcc/testsuite/g++.dg/reflect/init17.C | 30 +
gcc/testsuite/g++.dg/reflect/init2.C | 18 +
gcc/testsuite/g++.dg/reflect/init3.C | 8 +
gcc/testsuite/g++.dg/reflect/init4.C | 63 +
gcc/testsuite/g++.dg/reflect/init5.C | 21 +
gcc/testsuite/g++.dg/reflect/init6.C | 37 +
gcc/testsuite/g++.dg/reflect/init7.C | 41 +
gcc/testsuite/g++.dg/reflect/init8.C | 16 +
gcc/testsuite/g++.dg/reflect/init9.C | 53 +
gcc/testsuite/g++.dg/reflect/is_accessible1.C | 131 +
gcc/testsuite/g++.dg/reflect/is_accessible2.C | 470 ++
gcc/testsuite/g++.dg/reflect/is_alias_template1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_assignment1.C | 44 +
gcc/testsuite/g++.dg/reflect/is_bit_field1.C | 144 +
gcc/testsuite/g++.dg/reflect/is_class_member1.C | 128 +
gcc/testsuite/g++.dg/reflect/is_class_template1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_complete_type1.C | 109 +
gcc/testsuite/g++.dg/reflect/is_complete_type2.C | 25 +
gcc/testsuite/g++.dg/reflect/is_concept1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_const1.C | 116 +
gcc/testsuite/g++.dg/reflect/is_consteval_only1.C | 83 +
.../g++.dg/reflect/is_constructible_type1.C | 674 ++
.../g++.dg/reflect/is_constructible_type2.C | 137 +
.../g++.dg/reflect/is_constructor_template1.C | 56 +
gcc/testsuite/g++.dg/reflect/is_constuctor1.C | 101 +
.../g++.dg/reflect/is_conversion_function1.C | 56 +
.../reflect/is_conversion_function_template1.C | 54 +
gcc/testsuite/g++.dg/reflect/is_copy_assignment1.C | 101 +
.../g++.dg/reflect/is_copy_constructor1.C | 101 +
.../g++.dg/reflect/is_data_member_spec1.C | 105 +
.../g++.dg/reflect/is_default_constructor1.C | 101 +
gcc/testsuite/g++.dg/reflect/is_defaulted1.C | 169 +
gcc/testsuite/g++.dg/reflect/is_defaulted2.C | 64 +
gcc/testsuite/g++.dg/reflect/is_deleted1.C | 154 +
gcc/testsuite/g++.dg/reflect/is_deleted2.C | 89 +
gcc/testsuite/g++.dg/reflect/is_destructor1.C | 124 +
gcc/testsuite/g++.dg/reflect/is_enumerable_type1.C | 106 +
gcc/testsuite/g++.dg/reflect/is_enumerator1.C | 107 +
gcc/testsuite/g++.dg/reflect/is_explicit1.C | 72 +
gcc/testsuite/g++.dg/reflect/is_explicit2.C | 47 +
.../g++.dg/reflect/is_explicit_object_parameter1.C | 165 +
gcc/testsuite/g++.dg/reflect/is_final1.C | 56 +
gcc/testsuite/g++.dg/reflect/is_function1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_function2.C | 44 +
gcc/testsuite/g++.dg/reflect/is_function3.C | 15 +
.../g++.dg/reflect/is_function_parameter1.C | 105 +
.../g++.dg/reflect/is_function_parameter2.C | 13 +
.../g++.dg/reflect/is_function_template1.C | 105 +
.../g++.dg/reflect/is_function_template2.C | 44 +
gcc/testsuite/g++.dg/reflect/is_function_type1.C | 26 +
.../g++.dg/reflect/is_literal_operator1.C | 56 +
.../g++.dg/reflect/is_literal_operator_template1.C | 56 +
.../reflect/is_lrvalue_reference_qualified1.C | 93 +
gcc/testsuite/g++.dg/reflect/is_move_assignment1.C | 101 +
.../g++.dg/reflect/is_move_constructor1.C | 101 +
gcc/testsuite/g++.dg/reflect/is_mutable_member1.C | 133 +
gcc/testsuite/g++.dg/reflect/is_namespace1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_namespace_alias1.C | 105 +
.../g++.dg/reflect/is_namespace_member1.C | 147 +
gcc/testsuite/g++.dg/reflect/is_noexcept1.C | 180 +
gcc/testsuite/g++.dg/reflect/is_noexcept2.C | 65 +
gcc/testsuite/g++.dg/reflect/is_noexcept3.C | 175 +
gcc/testsuite/g++.dg/reflect/is_noexcept4.C | 120 +
.../g++.dg/reflect/is_nonstatic_data_member1.C | 127 +
gcc/testsuite/g++.dg/reflect/is_object1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_object2.C | 15 +
.../g++.dg/reflect/is_operator_function1.C | 56 +
.../reflect/is_operator_function_template1.C | 57 +
gcc/testsuite/g++.dg/reflect/is_override1.C | 154 +
gcc/testsuite/g++.dg/reflect/is_pure_virtual1.C | 48 +
.../g++.dg/reflect/is_special_member_function1.C | 101 +
gcc/testsuite/g++.dg/reflect/is_static_member1.C | 127 +
gcc/testsuite/g++.dg/reflect/is_string_literal1.C | 40 +
.../g++.dg/reflect/is_structured_binding1.C | 99 +
.../g++.dg/reflect/is_structured_binding2.C | 35 +
gcc/testsuite/g++.dg/reflect/is_template1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_template2.C | 9 +
gcc/testsuite/g++.dg/reflect/is_type1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_type_alias1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_type_alias2.C | 29 +
gcc/testsuite/g++.dg/reflect/is_type_alias3.C | 77 +
gcc/testsuite/g++.dg/reflect/is_user_declared1.C | 210 +
gcc/testsuite/g++.dg/reflect/is_user_declared2.C | 91 +
gcc/testsuite/g++.dg/reflect/is_user_provided1.C | 210 +
gcc/testsuite/g++.dg/reflect/is_user_provided2.C | 91 +
gcc/testsuite/g++.dg/reflect/is_variable1.C | 104 +
.../g++.dg/reflect/is_variable_template1.C | 105 +
gcc/testsuite/g++.dg/reflect/is_virtual1.C | 60 +
gcc/testsuite/g++.dg/reflect/is_volatile1.C | 116 +
gcc/testsuite/g++.dg/reflect/lex1.C | 13 +
gcc/testsuite/g++.dg/reflect/lex2.C | 21 +
gcc/testsuite/g++.dg/reflect/mangle1.C | 253 +
gcc/testsuite/g++.dg/reflect/member-visibility1.C | 412 +
gcc/testsuite/g++.dg/reflect/member-visibility2.C | 61 +
gcc/testsuite/g++.dg/reflect/member1.C | 99 +
gcc/testsuite/g++.dg/reflect/member10.C | 42 +
gcc/testsuite/g++.dg/reflect/member11.C | 19 +
gcc/testsuite/g++.dg/reflect/member12.C | 37 +
gcc/testsuite/g++.dg/reflect/member13.C | 46 +
gcc/testsuite/g++.dg/reflect/member14.C | 27 +
gcc/testsuite/g++.dg/reflect/member15.C | 177 +
gcc/testsuite/g++.dg/reflect/member16.C | 86 +
gcc/testsuite/g++.dg/reflect/member17.C | 402 +
gcc/testsuite/g++.dg/reflect/member18.C | 744 ++
gcc/testsuite/g++.dg/reflect/member19.C | 159 +
gcc/testsuite/g++.dg/reflect/member2.C | 14 +
gcc/testsuite/g++.dg/reflect/member20.C | 26 +
gcc/testsuite/g++.dg/reflect/member3.C | 35 +
gcc/testsuite/g++.dg/reflect/member4.C | 14 +
gcc/testsuite/g++.dg/reflect/member5.C | 19 +
gcc/testsuite/g++.dg/reflect/member6.C | 13 +
gcc/testsuite/g++.dg/reflect/member7.C | 78 +
gcc/testsuite/g++.dg/reflect/member8.C | 15 +
gcc/testsuite/g++.dg/reflect/member9.C | 18 +
gcc/testsuite/g++.dg/reflect/members_of1.C | 524 ++
gcc/testsuite/g++.dg/reflect/members_of2.C | 58 +
gcc/testsuite/g++.dg/reflect/members_of3.C | 49 +
gcc/testsuite/g++.dg/reflect/members_of4.C | 21 +
gcc/testsuite/g++.dg/reflect/members_of5.C | 101 +
gcc/testsuite/g++.dg/reflect/members_of6.C | 34 +
gcc/testsuite/g++.dg/reflect/members_of7.C | 32 +
gcc/testsuite/g++.dg/reflect/metafn-ptr1.C | 19 +
gcc/testsuite/g++.dg/reflect/ns1.C | 37 +
gcc/testsuite/g++.dg/reflect/ns2.C | 21 +
gcc/testsuite/g++.dg/reflect/ns3.C | 15 +
gcc/testsuite/g++.dg/reflect/ns4.C | 94 +
gcc/testsuite/g++.dg/reflect/ns5.C | 45 +
gcc/testsuite/g++.dg/reflect/ns6.C | 17 +
gcc/testsuite/g++.dg/reflect/null1.C | 30 +
gcc/testsuite/g++.dg/reflect/null2.C | 7 +
gcc/testsuite/g++.dg/reflect/null3.C | 9 +
gcc/testsuite/g++.dg/reflect/null4.C | 18 +
gcc/testsuite/g++.dg/reflect/null5.C | 26 +
gcc/testsuite/g++.dg/reflect/object_of1.C | 85 +
gcc/testsuite/g++.dg/reflect/object_of2.C | 26 +
gcc/testsuite/g++.dg/reflect/odr1.C | 29 +
gcc/testsuite/g++.dg/reflect/offset_of1.C | 132 +
gcc/testsuite/g++.dg/reflect/operator_of1.C | 354 +
gcc/testsuite/g++.dg/reflect/override1.C | 39 +
gcc/testsuite/g++.dg/reflect/p2996-1.C | 20 +
gcc/testsuite/g++.dg/reflect/p2996-10.C | 15 +
gcc/testsuite/g++.dg/reflect/p2996-11.C | 16 +
gcc/testsuite/g++.dg/reflect/p2996-12.C | 24 +
gcc/testsuite/g++.dg/reflect/p2996-13.C | 19 +
gcc/testsuite/g++.dg/reflect/p2996-14.C | 17 +
gcc/testsuite/g++.dg/reflect/p2996-15.C | 16 +
gcc/testsuite/g++.dg/reflect/p2996-16.C | 18 +
gcc/testsuite/g++.dg/reflect/p2996-17.C | 32 +
gcc/testsuite/g++.dg/reflect/p2996-18.C | 46 +
gcc/testsuite/g++.dg/reflect/p2996-19.C | 22 +
gcc/testsuite/g++.dg/reflect/p2996-2.C | 27 +
gcc/testsuite/g++.dg/reflect/p2996-20.C | 61 +
gcc/testsuite/g++.dg/reflect/p2996-21.C | 68 +
gcc/testsuite/g++.dg/reflect/p2996-3.C | 23 +
gcc/testsuite/g++.dg/reflect/p2996-4.C | 27 +
gcc/testsuite/g++.dg/reflect/p2996-5.C | 50 +
gcc/testsuite/g++.dg/reflect/p2996-6.C | 18 +
gcc/testsuite/g++.dg/reflect/p2996-7.C | 16 +
gcc/testsuite/g++.dg/reflect/p2996-8.C | 14 +
gcc/testsuite/g++.dg/reflect/p2996-9.C | 24 +
gcc/testsuite/g++.dg/reflect/p3394-1.C | 174 +
gcc/testsuite/g++.dg/reflect/p3491-1.C | 25 +
gcc/testsuite/g++.dg/reflect/p3491-2.C | 50 +
gcc/testsuite/g++.dg/reflect/p3491-3.C | 45 +
gcc/testsuite/g++.dg/reflect/pack-index1.C | 28 +
gcc/testsuite/g++.dg/reflect/parameters_of1.C | 35 +
gcc/testsuite/g++.dg/reflect/parameters_of2.C | 41 +
gcc/testsuite/g++.dg/reflect/parameters_of3.C | 41 +
gcc/testsuite/g++.dg/reflect/parameters_of4.C | 12 +
gcc/testsuite/g++.dg/reflect/parameters_of5.C | 43 +
gcc/testsuite/g++.dg/reflect/parameters_of6.C | 8 +
gcc/testsuite/g++.dg/reflect/parent_of1.C | 238 +
gcc/testsuite/g++.dg/reflect/parm1.C | 56 +
gcc/testsuite/g++.dg/reflect/parm2.C | 16 +
gcc/testsuite/g++.dg/reflect/parm3.C | 33 +
gcc/testsuite/g++.dg/reflect/parm4.C | 32 +
gcc/testsuite/g++.dg/reflect/pr122634-1.C | 65 +
gcc/testsuite/g++.dg/reflect/pr122634-2.C | 10 +
gcc/testsuite/g++.dg/reflect/qrn1.C | 272 +
gcc/testsuite/g++.dg/reflect/qrn2.C | 43 +
gcc/testsuite/g++.dg/reflect/range_args.C | 96 +
gcc/testsuite/g++.dg/reflect/reflect_constant1.C | 25 +
gcc/testsuite/g++.dg/reflect/reflect_constant2.C | 31 +
gcc/testsuite/g++.dg/reflect/reflect_constant3.C | 67 +
gcc/testsuite/g++.dg/reflect/reflect_constant4.C | 15 +
gcc/testsuite/g++.dg/reflect/reflect_constant5.C | 30 +
gcc/testsuite/g++.dg/reflect/reflect_constant6.C | 46 +
gcc/testsuite/g++.dg/reflect/reflect_constant7.C | 18 +
gcc/testsuite/g++.dg/reflect/reflect_constant8.C | 33 +
gcc/testsuite/g++.dg/reflect/reflect_constant9.C | 33 +
.../g++.dg/reflect/reflect_constant_array1.C | 110 +
.../g++.dg/reflect/reflect_constant_array2.C | 17 +
.../g++.dg/reflect/reflect_constant_array3.C | 18 +
.../g++.dg/reflect/reflect_constant_array4.C | 20 +
.../g++.dg/reflect/reflect_constant_string1.C | 133 +
.../g++.dg/reflect/reflect_constant_string2.C | 14 +
gcc/testsuite/g++.dg/reflect/reflect_function1.C | 17 +
gcc/testsuite/g++.dg/reflect/reflect_function2.C | 74 +
gcc/testsuite/g++.dg/reflect/reflect_object1.C | 88 +
gcc/testsuite/g++.dg/reflect/reflect_object2.C | 115 +
gcc/testsuite/g++.dg/reflect/reflect_object3.C | 61 +
gcc/testsuite/g++.dg/reflect/reflect_object4.C | 10 +
gcc/testsuite/g++.dg/reflect/return_type_of1.C | 99 +
gcc/testsuite/g++.dg/reflect/return_type_of2.C | 20 +
gcc/testsuite/g++.dg/reflect/serialize1.C | 151 +
gcc/testsuite/g++.dg/reflect/serialize2.C | 67 +
gcc/testsuite/g++.dg/reflect/size_of1.C | 122 +
gcc/testsuite/g++.dg/reflect/source_location_of1.C | 113 +
gcc/testsuite/g++.dg/reflect/source_location_of2.C | 44 +
gcc/testsuite/g++.dg/reflect/splice1.C | 28 +
gcc/testsuite/g++.dg/reflect/splice2.C | 13 +
gcc/testsuite/g++.dg/reflect/splice3.C | 5 +
gcc/testsuite/g++.dg/reflect/splice4.C | 17 +
gcc/testsuite/g++.dg/reflect/splice5.C | 39 +
gcc/testsuite/g++.dg/reflect/splice6.C | 48 +
gcc/testsuite/g++.dg/reflect/splice7.C | 6 +
gcc/testsuite/g++.dg/reflect/splicing-base1.C | 24 +
gcc/testsuite/g++.dg/reflect/splicing-base2.C | 30 +
gcc/testsuite/g++.dg/reflect/splicing-base3.C | 112 +
gcc/testsuite/g++.dg/reflect/splicing-base4.C | 28 +
gcc/testsuite/g++.dg/reflect/storage_duration1.C | 141 +
gcc/testsuite/g++.dg/reflect/storage_duration2.C | 218 +
gcc/testsuite/g++.dg/reflect/storage_duration3.C | 19 +
gcc/testsuite/g++.dg/reflect/subobjects_of1.C | 214 +
gcc/testsuite/g++.dg/reflect/substitute1.C | 238 +
gcc/testsuite/g++.dg/reflect/substitute2.C | 30 +
gcc/testsuite/g++.dg/reflect/symbol_of1.C | 61 +
gcc/testsuite/g++.dg/reflect/symbol_of2.C | 6 +
.../g++.dg/reflect/template_arguments_of1.C | 36 +
.../g++.dg/reflect/template_arguments_of2.C | 107 +
.../g++.dg/reflect/template_arguments_of3.C | 18 +
gcc/testsuite/g++.dg/reflect/template_of1.C | 119 +
gcc/testsuite/g++.dg/reflect/template_of2.C | 32 +
gcc/testsuite/g++.dg/reflect/template_of3.C | 22 +
gcc/testsuite/g++.dg/reflect/tuple1.C | 86 +
gcc/testsuite/g++.dg/reflect/tuple2.C | 21 +
gcc/testsuite/g++.dg/reflect/type1.C | 190 +
gcc/testsuite/g++.dg/reflect/type10.C | 31 +
gcc/testsuite/g++.dg/reflect/type2.C | 58 +
gcc/testsuite/g++.dg/reflect/type3.C | 37 +
gcc/testsuite/g++.dg/reflect/type4.C | 136 +
gcc/testsuite/g++.dg/reflect/type5.C | 10 +
gcc/testsuite/g++.dg/reflect/type6.C | 25 +
gcc/testsuite/g++.dg/reflect/type7.C | 15 +
gcc/testsuite/g++.dg/reflect/type8.C | 76 +
gcc/testsuite/g++.dg/reflect/type9.C | 49 +
gcc/testsuite/g++.dg/reflect/type_of1.C | 190 +
gcc/testsuite/g++.dg/reflect/type_of2.C | 31 +
gcc/testsuite/g++.dg/reflect/type_rels1.C | 141 +
gcc/testsuite/g++.dg/reflect/type_trait1.C | 654 ++
gcc/testsuite/g++.dg/reflect/type_trait10.C | 116 +
gcc/testsuite/g++.dg/reflect/type_trait11.C | 447 +
gcc/testsuite/g++.dg/reflect/type_trait12.C | 137 +
gcc/testsuite/g++.dg/reflect/type_trait13.C | 425 +
gcc/testsuite/g++.dg/reflect/type_trait2.C | 92 +
gcc/testsuite/g++.dg/reflect/type_trait3.C | 218 +
gcc/testsuite/g++.dg/reflect/type_trait4.C | 12 +
gcc/testsuite/g++.dg/reflect/type_trait5.C | 453 +
gcc/testsuite/g++.dg/reflect/type_trait6.C | 1381 ++++
gcc/testsuite/g++.dg/reflect/type_trait8.C | 129 +
gcc/testsuite/g++.dg/reflect/type_trait9.C | 67 +
.../g++.dg/reflect/u8display_string_of1.C | 230 +
gcc/testsuite/g++.dg/reflect/u8identifier_of1.C | 168 +
gcc/testsuite/g++.dg/reflect/u8symbol_of1.C | 61 +
gcc/testsuite/g++.dg/reflect/underlying_type1.C | 13 +
gcc/testsuite/g++.dg/reflect/using1.C | 13 +
gcc/testsuite/g++.dg/reflect/value_or_object1.C | 50 +
gcc/testsuite/g++.dg/reflect/variable_of1.C | 136 +
gcc/testsuite/g++.dg/reflect/variable_of2.C | 21 +
gcc/testsuite/g++.dg/reflect/variable_of3.C | 28 +
gcc/testsuite/g++.dg/reflect/variant1.C | 37 +
gcc/testsuite/g++.dg/reflect/variant2.C | 19 +
gcc/testsuite/g++.dg/reflect/vector1.C | 28 +
gcc/testsuite/g++.dg/reflect/visibility1.C | 121 +
gcc/tree-core.h | 3 +-
gcc/tree.h | 15 +-
libcc1/libcp1plugin.cc | 3 +-
libcpp/charset.cc | 108 +
libcpp/include/cpplib.h | 6 +
libcpp/internal.h | 8 +
libcpp/lex.cc | 33 +-
libstdc++-v3/include/Makefile.am | 1 +
libstdc++-v3/include/Makefile.in | 1 +
libstdc++-v3/include/bits/iterator_concepts.h | 2 +-
libstdc++-v3/include/bits/version.def | 9 +
libstdc++-v3/include/bits/version.h | 10 +
libstdc++-v3/include/precompiled/stdc++.h | 1 +
libstdc++-v3/include/std/meta | 653 ++
libstdc++-v3/include/std/type_traits | 60 +-
libstdc++-v3/src/c++23/std.cc.in | 255 +
.../requirements/explicit_instantiation.cc | 12 +
.../is_consteval_only/requirements/typedefs.cc | 16 +
.../testsuite/20_util/is_consteval_only/value.cc | 30 +
.../requirements/explicit_instantiation.cc | 12 +
.../20_util/is_reflection/requirements/typedefs.cc | 16 +
.../testsuite/20_util/is_reflection/value.cc | 20 +
.../20_util/variable_templates_for_traits.cc | 10 +
509 files changed, 49155 insertions(+), 280 deletions(-)
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index d57c17501075..db9a5c125ac8 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -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;
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 3b105df67d08..10d9a51418ef 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -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);
diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 68fdf3d9c2da..da7bb98c9da7 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -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");
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 797eb46b1273..e286c3b0535b 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -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.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index b0ed541f9446..7f476531d84d 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -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"
diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index 8ff475a09d96..845430f35a4a 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -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 \
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 54a50c4b6b04..0873226bc061 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -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);
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b70ecf99a30a..0b91e8785631 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -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;
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index df86c3903324..3c0f415fa87c 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -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);
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 1bbe43715e65..0f0d4a01eebb 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -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);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c7fc40d05445..395cadc5767d 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -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)
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 3e11b4deb7ba..770a681e124d 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7dc498ccae37..d7acfc8b7a33 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index 771f72106cd2..a984611ea8e2 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -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;
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index 3bb1097445ba..db13a83ff902 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -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);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 46a17a596edc..f1ba57cd177e 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -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;
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index c6449844965c..4de6345135f8 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -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
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index c51725555a9d..c184846066e0 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -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. */
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 01e3d007a491..7b17220ee9b0 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -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)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index c490fe8fca96..27c5192ab894 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -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"
}
};
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 7e39664ce8ef..06bd396c03ef 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -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
index 000000000000..b4e93623eac6
--- /dev/null
+++ b/gcc/cp/metafns.gperf
@@ -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
index 000000000000..779c8dc27990
--- /dev/null
+++ b/gcc/cp/metafns.h
@@ -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);
+}
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index e5ad3ac4494f..94fdc32d0bd6 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -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);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e6b2b2f78581..37b288767ab2 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -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
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 8847acc693c1..1b3713dc40e1 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -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);
}
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index dc01b7482c79..9f2c581ece11 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -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
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 2dc4863ec528..393c8b2ec44e 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -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 ();
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1c7a2ac2b112..3c9ba31b212d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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
index 000000000000..237f630d71ba
--- /dev/null
+++ b/gcc/cp/reflect.cc
@@ -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)
+ [...]
[diff truncated at 524288 bytes]
More information about the Libstdc++-cvs
mailing list