From: Marek Polacek Date: Wed, 14 Jan 2026 16:37:39 +0000 (-0500) Subject: c++: C++26 Reflection [PR120775] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b0e94b394fa38cdc3431f3cfb333b85373bd948;p=thirdparty%2Fgcc.git 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) : 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) : Detect any surviving consteval-only expressions. : 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. : 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 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 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 Signed-off-by: Valentyn Yukhymenko Signed-off-by: Alex Yesmanchyk Signed-off-by: Michael Levine Reviewed-by: Jason Merrill --- diff --git a/gcc/attribs.cc b/gcc/attribs.cc index d57c1750107..db9a5c125ac 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 3b105df67d0..10d9a51418e 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 68fdf3d9c2d..da7bb98c9da 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 797eb46b127..e286c3b0535 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 b0ed541f944..7f476531d84 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 8ff475a09d9..845430f35a4 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 54a50c4b6b0..0873226bc06 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 *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 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::{,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 b70ecf99a30..0b91e878563 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 df86c390332..3c0f415fa87 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 1bbe43715e6..0f0d4a01eeb 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 c7fc40d0544..395cadc5767 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 3e11b4deb7b..770a681e124 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 7dc498ccae3..d7acfc8b7a3 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_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:]. */ +#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 771f72106cd..a984611ea8e 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 3bb1097445b..db13a83ff90 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 46a17a596ed..f1ba57cd177 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 **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 c6449844965..4de6345135f 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 c51725555a9..c184846066e 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_("