diff options
Diffstat (limited to 'gcc')
377 files changed, 9994 insertions, 3872 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1b8058d..eab3231 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,358 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/97111 + * doc/invoke.texi: Add -Wanalyzer-throw-of-unexpected-type. + * gimple.h (gimple_call_nothrow_p): Make arg const. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * diagnostic-format-json.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * diagnostic-format-sarif.cc: Likewise. + * diagnostic-format-text.cc: Likewise. + * diagnostic.cc: Likewise. + * dumpfile.cc: Likewise. + * gcc-attribute-urlifier.cc: Likewise. + * gcc-urlifier.cc: Likewise. + * json-parsing.cc: Likewise. + * json.cc: Likewise. + * lazy-diagnostic-path.cc: Likewise. + * libgdiagnostics.cc: Likewise. + * libsarifreplay.cc: Likewise. + * lto-wrapper.cc: Likewise. + * make-unique.h: Delete. + * opts-diagnostic.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * pretty-print.cc: Likewise. + * text-art/style.cc: Likewise. + * text-art/styled-string.cc: Likewise. + * text-art/table.cc: Likewise. + * text-art/tree-widget.cc: Likewise. + * text-art/widget.cc: Likewise. + * timevar.cc: Likewise. + * toplev.cc: Likewise. + * tree-diagnostic-client-data-hooks.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * pass_manager.h (class pass_manager): Add "m_" prefix to all pass + fields. + * passes.cc (pass_manager::execute_early_local_passes): Update + for added "m_" prefix. + (pass_manager::execute_pass_mode_switching): Likewise. + (pass_manager::finish_optimization_passes): Likewise. + (pass_manager::pass_manager): Likewise. + (pass_manager::dump_profile_report): Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * diagnostic.h (diagnostic_context::m_opt_permissive): Convert + from int to diagnostic_option_id. Update comment. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * diagnostic.h (diagnostic_context::set_abort_on_error): New. + (diagnostic_context::m_abort_on_error): Make private. + (diagnostic_abort_on_error): Delete. + * opts.cc (setup_core_dumping): Update for above changes. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * diagnostic-format-sarif.cc (sarif_builder::get_opts): New + accessor. + (sarif_builder::get_version): Update for... + (sarif_builder::m_version): Replace this field... + (sarif_builder::m_m_sarif_gen_opts): ...with this. + (sarif_builder::sarif_builder): Replace version with + sarif_gen_opts throughout. + (sarif_builder::make_top_level_object): Use get_version. + (sarif_output_format::sarif_output_format): Replace version with + sarif_gen_opts throughout. + (sarif_stream_output_format::sarif_stream_output_format): + Likewise. + (sarif_file_output_format::sarif_file_output_format): Likewise. + (diagnostic_output_format_init_sarif_stderr): Drop version param + and use default for sarif_generation_options instead. + (diagnostic_output_format_init_sarif_file): Likewise. + (diagnostic_output_format_init_sarif_stream): Likewise. + (make_sarif_sink): Replace version with sarif_gen_opts throughout. + (sarif_generation_options::sarif_generation_options): New. + (selftest::test_sarif_diagnostic_context::test_sarif_diagnostic_context): + Replace version with sarif_gen_opts throughout. + (selftest::test_make_location_object): Likewise. + (selftest::test_simple_log): Likewise. + (selftest::test_simple_log_2): Likewise. + (selftest::test_message_with_embedded_link): Likewise. + (selftest::test_message_with_braces): Likewise. + (selftest::test_buffering): Likewise. + (selftest::run_tests_per_version): Replace with... + (selftest::for_each_sarif_gen_option): ...this... + (selftest::run_line_table_case_tests_per_version): ...and this. + (selftest::diagnostic_format_sarif_cc_tests): Update to use + for_each_sarif_gen_option and + run_line_table_case_tests_per_version. + * diagnostic-format-sarif.h (enum class sarif_version): Move lower + down. + (diagnostic_output_format_init_sarif_stderr): Drop "version" + param. + (diagnostic_output_format_init_sarif_file): Likewise. + (diagnostic_output_format_init_sarif_stream): Likewise. + (struct sarif_generation_options): New. + (make_sarif_sink): Add "formatted" param. Replace version param + with sarif_gen_opts. + * diagnostic.cc (diagnostic_output_format_init): Drop hardcoded + sarif_version::v2_1_0 arguments from calls, which instead use + the default ctor for sarif_generation_options internally. + * libgdiagnostics.cc (sarif_sink::sarif_sink): Replace version + param with sarif_gen_opts, and update for changes to + make_sarif_sink. + (diagnostic_manager_add_sarif_sink): Use sarif_gen_opts rather + than version. + * opts-diagnostic.cc (sarif_scheme_handler::make_sink): Likewise. + Pass "true" for "formatted" param. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + * value-relation.cc (value_relation::swap): New. + (value_relation::negate): Remove. + (dom_oracle::next_relation): New. + (block_relation_iterator::block_relation_iterator): New. + (block_relation_iterator::get_next_relation): New. + (dom_oracle::dump): Use iterator. + * value-relation.h (relation_oracle::next_relation): New. + (dom_oracle::next_relation): New prototype. + (class block_relation_iterator): New. + (FOR_EACH_RELATION_BB): New. + (FOR_EACH_RELATION_NAME): New. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + * range-op-ptr.cc (range_operator::lhs_op1_relation): Add + prange/prange/irange (PPI) default. + (pointer_plus_operator::lhs_op1_relation): New. + * range-op.cc (range_op_handler::lhs_op1_relation): Add RO_PPI case. + * range-op.h (range_op_handler::lhs_op1_relation): Add prototype. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-fold.cc (fold_using_range::range_of_range_op): Use a + new local variable for intermediate relation results. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-cache.cc (ranger_cache::apply_inferred_ranges): Pass + 'this' as the range-query to the inferred range constructor. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/95801 + * range-op.cc (operator_div::op2_range): New. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/119712 + * value-range.cc (range_bitmask::adjust_range): Delete. + (irange::set_range_from_bitmask): Integrate adjust_range. + (irange::update_bitmask): Do nothing if bitmask doesnt change. + (irange:intersect_bitmask): Do not call adjust_range. Exit if there + is no second bitmask. + * value-range.h (adjust_range): Remove prototype. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/67797 + * tree-tailcall.cc (find_tail_calls): Add support for ERF_RETURNS_ARG. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + * tree-cfg.cc (verify_gimple_cond): Error out if the comparison + throws. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR c/119432 + * tree-pretty-print.cc (op_symbol_code): For LROTATE_EXPR, + output __ROTATE_LEFT for gimple. + For RROTATE_EXPR output __ROTATE_RIGHT for gimple. + +2025-04-28 Richard Sandiford <richard.sandiford@arm.com> + + * rtl.h (native_decode_int): Declare. + * simplify-rtx.cc (native_decode_int): New function, split out from... + (native_decode_rtx): ...here. + +2025-04-28 H.J. Lu <hjl.tools@gmail.com> + Uros Bizjak <ubizjak@gmail.com> + + PR target/109780 + PR target/109093 + * config/i386/i386.cc (stack_access_data): New. + (ix86_update_stack_alignment): Likewise. + (ix86_find_all_reg_use_1): Likewise. + (ix86_find_all_reg_use): Likewise. + (ix86_find_max_used_stack_alignment): Also check memory accesses + from registers defined by stack or frame registers. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR ipa/119973 + * tree-ssa-structalias.cc (create_variable_info_for): + Build constraints from DECL_INITIAL directly rather than + the IPA reference list which is incomplete. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR lto/113207 + * ipa-free-lang-data.cc (fld_type_variant): Add extra checking. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119044 + * tree-predcom.cc (ref_at_iteration): Copy alias info + from the original ref. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119103 + * tree-ssa-loop-im.cc (in_loop_pipeline): Globalize. + (compute_invariantness): Override costing when we run + right before PRE and PRE is enabled. + (pass_lim::execute): Adjust. + * tree-vect-patterns.cc (vect_determine_precisions_from_users): + For variable shift amounts use range information. + +2025-04-28 Richard Biener <rguenther@suse.de> + + * genmatch.cc (::gen_transform): Add in_place parameter. + Assert it isn't set in unexpected places. + (possible_noop_convert): New. + (expr::gen_transform): Support in_place and emit code to + compute a child in-place when the operation is a conversion. + (dt_simplify::gen_1): Arrange for an outermost conversion + to be elided by generating the transform of the operand + in-place. + * match.pd (__real cepxi (x) -> cos (x)): Use single_use. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR middle-end/60779 + * common.opt (fcx-method=): New, map to flag_complex_method. + (Enum complex_method): New. + (fcx-limited-range): Alias to -fcx-method=limited-range. + (fcx-fortran-rules): Alias to -fcx-medhot=fortran. + * ipa-inline-transform.cc (inline_call): Check flag_complex_method. + * ipa-inline.cc (can_inline_edge_by_limits_p): Likewise. + * opts.cc (finish_options): Adjust. + (set_fast_math_flags): Likewise. + * doc/invoke.texi (fcx-method=): Document. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR middle-end/116083 + * stor-layout.cc (layout_type): Compute TYPE_SIZE and + TYPE_SIZE_UNIT for vector types from the component mode + sizes. + +2025-04-28 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vect_analyze_loop_operations): Prune + all actual analysis and only fail when we discover a not + SLP covered stmt. + (vect_analyze_loop_2): Remove path trying without SLP. + +2025-04-28 Richard Biener <rguenther@suse.de> + + * tree-vect-loop.cc (vect_loop_kill_debug_uses): Remove. + (maybe_set_vectorized_backedge_value): Likewise. + (vect_transform_loop_stmt): Likewise. Move dump printing + to vect_transform_stmt. + (vect_transform_loop): Remove loop over loop stmts transforming + them, but retain some DCE code still necessary. + * tree-vect-stmts.cc (vect_transform_stmt): Dump that + we're vectorizing a stmt. + +2025-04-28 Richard Biener <rguenther@suse.de> + + * params.opt (--param=vect-force-slp): Remove. + * doc/invoke.texi (--param=vect-force-slp): Likewise. + * tree-vect-loop.cc (vect_analyze_loop_2): Assume + param_vect_force_slp is 1. + * tree-vect-stmts.cc (vect_analyze_stmt): Likewise. + +2025-04-28 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/119493 + * tree-tailcall.cc (find_tail_calls): Handle non-gimple_reg_type + arguments which aren't just passed through for tail recursions + even for non-musttail calls. + +2025-04-28 LIU Hao <lh_mouse@126.com> + + PR target/111107 + * config/i386/cygming.h (STACK_REALIGN_DEFAULT): Copy from sol2.h. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR c/48274 + PR middle-end/112877 + PR middle-end/118288 + * gimple.cc (gimple_builtin_call_types_compatible_p): Remove the + targetm.calls.promote_prototypes call. + * tree.cc (tree_builtin_call_types_compatible_p): Likewise. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * calls.cc (initialize_argument_information): Promote small integer + arguments if TARGET_PROMOTE_PROTOTYPES returns true. + +2025-04-27 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv-v.cc (expand_const_vector): Extract + const vector stepped into separated func. + (expand_const_vector_single_step_npatterns): Add new func + to take care of single step. + (expand_const_vector_interleaved_stepped_npatterns): Add new + func to take care of interleaved step. + (expand_const_vector_stepped): Add new func to take care of + const vector stepped. + +2025-04-27 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv-v.cc (expand_const_vector_duplicate_repeating): + Add new func to take care of vector duplicate with repeating. + (expand_const_vector_duplicate_default): Add new func to take + care of default const vector duplicate. + (expand_const_vector_duplicate): Add new func to take care + of all const vector duplicate. + (expand_const_vector): Extract const vector duplicate into + separated function. + +2025-04-27 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv-v.cc (expand_const_vec_series): Add new + func to take care of the const vec_series. + (expand_const_vector): Extract const vec_series into separated + function. + +2025-04-27 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv-v.cc (expand_const_vector): Extract + const vec_duplicate into separated function. + (expand_const_vec_duplicate): Add new func to take care + of the const vec_duplicate. + +2025-04-27 liuhongt <hongtao.liu@intel.com> + + PR target/119549 + * common/config/i386/i386-common.cc (ix86_handle_option): + Refactor msse4 and mno-sse4. + * config/i386/i386.opt (msse4): Remove RejectNegative. + (mno-sse4): Remove the entry. + * config/i386/i386-options.cc + (ix86_valid_target_attribute_inner_p): Remove special code + which handles mno-sse4. + 2025-04-26 Jan Hubicka <hubicka@ucw.cz> PR target/105275 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index bcfb36f..e697180 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250427 +20250429 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 650de8b..5ec1e24 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * gcc-interface/utils.cc (create_param_decl): Remove the + targetm.calls.promote_prototypes call. + 2025-04-17 Jakub Jelinek <jakub@redhat.com> * gnatvsn.ads: Bump Library_Version to 16. diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 443dc6d..ce2f385 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,422 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/111536 + * engine.cc (maybe_update_for_edge): Update for new call_stmt + param to region_model::push_frame. + * program-state.cc (program_state::push_frame): Likewise. + * region-model.cc (region_model::update_for_gcall): Likewise. + (region_model::push_frame): Add "call_stmt" param. + Handle DECL_RESULT with DECL_BY_REFERENCE set on it by stashing + the region of the lhs of the call_stmt in the caller frame, + and writing a reference to it within the "result" in the callee + frame. + (region_model::pop_frame): Don't write back to the LHS for + DECL_BY_REFERENCE results. + (selftest::test_stack_frames): Update for new call_stmt param to + region_model::push_frame. + (selftest::test_get_representative_path_var): Likewise. + (selftest::test_state_merging): Likewise. + (selftest::test_alloca): Likewise. + * region-model.h (region_model::push_frame): Add "call_stmt" + param. + * region.cc: Include "tree-ssa.h". + (region::can_have_initial_svalue_p): Use ssa_defined_default_def_p + for ssa names, rather than special-casing it for just parameters. + This should now also cover DECL_RESULT with DECL_BY_REFERENCE and + hard registers. + * sm-signal.cc (update_model_for_signal_handler): Update for new + call_stmt param to region_model::push_frame. + * state-purge.cc (state_purge_per_decl::process_worklists): + Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/109366 + * region-model-manager.cc + (region_model_manager::maybe_fold_sub_svalue): Sub-values of zero + constants are zero. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/97111 + * analyzer.cc (is_cxa_throw_p): New. + (is_cxa_rethrow_p): New. + * analyzer.opt (Wanalyzer-throw-of-unexpected-type): New. + * analyzer.opt.urls: Regenerate. + * call-info.cc (custom_edge_info::create_enode): New. + * call-info.h (call_info::print): Drop "final". + (call_info::add_events_to_path): Likewise. + * checker-event.cc (event_kind_to_string): Add cases for + event_kind::catch_, event_kind::throw_, and event_kind::unwind. + (explicit_throw_event::print_desc): New. + (throw_from_call_to_external_fn_event::print_desc): New. + (unwind_event::print_desc): New. + * checker-event.h (enum class event_kind): Add catch_, throw_, + and unwind. + (class catch_cfg_edge_event): New. + (class throw_event): New. + (class explicit_throw_event): New. + (class throw_from_call_to_external_fn_event): New. + (class unwind_event): New. + * common.h (class eh_dispatch_cfg_superedge): New forward decl. + (class eh_dispatch_try_cfg_superedge): New forward decl. + (class eh_dispatch_allowed_cfg_superedge): New forward decl. + (custom_edge_info::create_enode): New vfunc decl. + (is_cxa_throw_p): New decl. + (is_cxa_rethrow_p): New decl. + * diagnostic-manager.cc + (diagnostic_manager::add_events_for_superedge): Special-case edges + for eh_dispach_try. + (diagnostic_manager::prune_path): Call consolidate_unwind_events. + (diagnostic_manager::prune_for_sm_diagnostic): Don't filter the new + event_kinds. + (diagnostic_manager::consolidate_unwind_events): New. + * diagnostic-manager.h + (diagnostic_manager::consolidate_unwind_events): New decl. + * engine.cc (exploded_node::on_stmt_pre): Handle "__cxa_throw", + "__cxa_rethrow", and resx statements. + (class throw_custom_edge): New. + (class unwind_custom_edge): New. + (get_eh_outedge): New. + (exploded_graph::unwind_from_exception): New. + (exploded_node::on_throw): New. + (exploded_node::on_resx): New. + (exploded_graph::get_or_create_node): Add "add_to_worklist" param + and use it. + (exploded_graph::process_node): Use edge_info's create_enode vfunc + to create enodes, rather than calling get_or_create_node directly. + Ignore CFG edges in the sgraph flagged with EH whilst we're + exploring the egraph. + (exploded_graph_annotator::print_enode): Handle case + exploded_node::status::special. + * exploded-graph.h (exploded_node::status): Add value "special". + (exploded_node::on_throw): New decl. + (exploded_node::on_resx): New decl. + (exploded_graph::get_or_create_node): Add optional + "add_to_worklist" param. + (exploded_graph::unwind_from_exception): New decl. + * kf-lang-cp.cc (class kf_cxa_allocate_exception): New. + (class kf_cxa_begin_catch): New. + (class kf_cxa_end_catch): New. + (class throw_of_unexpected_type): New. + (class kf_cxa_call_unexpected): New. + (register_known_functions_lang_cp): Register known functions + "__cxa_allocate_exception", "__cxa_begin_catch", + "__cxa_end_catch", and "__cxa_call_unexpected". + * kf.cc (class kf_eh_pointer): New. + (register_known_functions): Register it for BUILT_IN_EH_POINTER. + * region-model.cc: Include "analyzer/function-set.h". + (exception_node::operator==): New. + (exception_node::dump_to_pp): New. + (exception_node::dump): New. + (exception_node::to_json): New. + (exception_node::make_dump_widget): New. + (exception_node::maybe_get_type): New. + (exception_node::add_to_reachable_regions): New. + (region_model::region_model): Initialize + m_thrown_exceptions_stack and m_caught_exceptions_stack. + (region_model::operator=): Likewise. + (region_model::operator==): Compare them. + (region_model::dump_to_pp): Dump exception stacks. + (region_model::to_json): Add exception stacks. + (region_model::make_dump_widget): Likewise. + (class exception_thrown_from_unrecognized_call): New. + (get_fns_assumed_not_to_throw): New. + (can_throw_p): New. + (region_model::check_for_throw_inside_call): New. + (region_model::on_call_pre): Call check_for_throw_inside_call + on unknown fns or those we don't have a body for. + (region_model::maybe_update_for_edge): Handle eh_dispatch_stmt + statements. Drop old code that called + apply_constraints_for_exception on EDGE_EH edges. + (class rejected_eh_dispatch): New. + (exception_matches_type_p): New. + (matches_any_exception_type_p): New. + (region_model::apply_constraints_for_eh_dispatch): New. + (region_model::apply_constraints_for_eh_dispatch_try): New. + (region_model::apply_constraints_for_eh_dispatch_allowed): New. + (region_model::apply_constraints_for_exception): Delete. + (region_model::can_merge_with_p): Don't merge models with + non-equal exception stacks. + (region_model::get_referenced_base_regions): Add regions from + exception stacks. + * region-model.h (struct exception_node): New. + (region_model::push_thrown_exception): New. + (region_model::get_current_thrown_exception): New. + (region_model::pop_thrown_exception): New. + (region_model::push_caught_exception): New. + (region_model::get_current_caught_exception): New. + (region_model::pop_caught_exception): New. + (region_model::apply_constraints_for_eh_dispatch_try): New decl. + (region_model::apply_constraints_for_eh_dispatch_allowed) New decl. + (region_model::apply_constraints_for_exception): Delete. + (region_model::apply_constraints_for_eh_dispatch): New decl. + (region_model::check_for_throw_inside_call): New decl. + (region_model::m_thrown_exceptions_stack): New field. + (region_model::m_caught_exceptions_stack): New field. + * supergraph.cc: Include "except.h" and "analyzer/region-model.h". + (supergraph::add_cfg_edge): Special-case eh_dispatch edges. + (superedge::get_description): Use default_tree_printer. + (get_catch): New. + (eh_dispatch_cfg_superedge::make): New. + (eh_dispatch_cfg_superedge::eh_dispatch_cfg_superedge): New. + (eh_dispatch_cfg_superedge::get_eh_status): New. + (eh_dispatch_try_cfg_superedge::dump_label_to_pp): New. + (eh_dispatch_try_cfg_superedge::apply_constraints): New. + (eh_dispatch_allowed_cfg_superedge::eh_dispatch_allowed_cfg_superedge): + New. + (eh_dispatch_allowed_cfg_superedge::dump_label_to_pp): New. + (eh_dispatch_allowed_cfg_superedge::apply_constraints): New. + * supergraph.h: Include "except.h". + (superedge::dyn_cast_eh_dispatch_cfg_superedge): New vfunc. + (superedge::dyn_cast_eh_dispatch_try_cfg_superedge): New vfunc. + (superedge::dyn_cast_eh_dispatch_allowed_cfg_superedge): New + vfunc. + (class eh_dispatch_cfg_superedge): New. + (is_a_helper <const eh_dispatch_cfg_superedge *>::test): New. + (class eh_dispatch_try_cfg_superedge): New. + (is_a_helper <const eh_dispatch_try_cfg_superedge *>::test): New. + (class eh_dispatch_allowed_cfg_superedge): New. + (is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test): + New. + * svalue.cc (svalue::maybe_get_type_from_typeinfo): New. + * svalue.h (svalue::maybe_get_type_from_typeinfo): New decl. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * access-diagram.cc: Replace uses of ::make_unique with + std::make_unique. + * analyzer.cc: Likewise. + * bounds-checking.cc: Likewise. + * call-details.cc: Likewise. + * call-info.cc: Likewise. + * call-string.cc: Likewise. + * checker-path.cc: Likewise. + * common.h: Drop include of "make-unique.h". + * constraint-manager.cc: Replace uses of ::make_unique with + std::make_unique. + * diagnostic-manager.cc: Likewise. + * engine.cc: Likewise. + * infinite-loop.cc: Likewise. + * infinite-recursion.cc: Likewise. + * kf-analyzer.cc: Likewise. + * kf-lang-cp.cc: Likewise. + * kf.cc: Likewise. + * pending-diagnostic.cc: Likewise. + * program-point.cc: Likewise; drop #include. + * program-state.cc: Likewise. + * ranges.cc: Likewise. + * region-model.cc: Likewise. + * region.cc: Likewise; drop #include. + * sm-fd.cc: Likewise. + * sm-file.cc: Likewise. + * sm-malloc.cc: Likewise. + * sm-pattern-test.cc: Likewise. + * sm-sensitive.cc: Likewise. + * sm-signal.cc: Likewise. + * sm-taint.cc: Likewise. + * sm.cc: Likewise. + * store.cc: Likewise. + * supergraph.cc: Likewise. + * svalue.cc: Likewise; drop #include. + * varargs.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * engine.cc (class plugin_analyzer_init_impl): Convert + "m_checkers" to use std::vector of std::unique_ptr. Convert + "m_known_fn_mgr" to a reference. + (impl_run_checkers): Convert "checkers" to use std::vector of + std::unique_ptr and move it into the extrinsic_state. + * program-state.cc (extrinsic_state::dump_to_pp): Update for + changes to m_checkers. + (extrinsic_state::to_json): Likewise. + (extrinsic_state::get_sm_idx_by_name): Likewise. + (selftest::test_sm_state_map): Update to use std::unique_ptr + for state machines. + (selftest::test_program_state_1): Likewise. + (selftest::test_program_state_2): Likewise. + (selftest::test_program_state_merging): Likewise. + (selftest::test_program_state_merging_2): Likewise. + * program-state.h (class extrinsic_state): Convert "m_checkers" to + use std::vector of std::unique_ptr and to be owned by this object, + rather than a reference. Add ctor for use in selftests. + * sm-fd.cc (make_fd_state_machine): Update to use std::unique_ptr. + * sm-file.cc (make_fileptr_state_machine): Likewise. + * sm-malloc.cc (make_malloc_state_machine): Likewise. + * sm-pattern-test.cc (make_pattern_test_state_machine): Likewise. + * sm-sensitive.cc (make_sensitive_state_machine): Likewise. + * sm-signal.cc (make_signal_state_machine): Likewise. + * sm-taint.cc (make_taint_state_machine): Likewise. + * sm.cc: Define INCLUDE_LIST. + (make_checkers): Return the vector directly, rather than pass it + in by reference. Update to use std::unique_ptr throughout. Use + an intermediate list, and use that to filter with + flag_analyzer_checker, fixing memory leak for this case. + * sm.h: (make_checkers): Return the vector directly, rather than + pass it in by reference, and use std::vector of std::unique_ptr. + (make_malloc_state_machine): Convert return type to use std::unique_ptr. + (make_fileptr_state_machine): Likewise. + (make_taint_state_machine): Likewise. + (make_sensitive_state_machine): Likewise. + (make_signal_state_machine): Likewise. + (make_pattern_test_state_machine): Likewise. + (make_va_list_state_machine): Likewise. + (make_fd_state_machine): Likewise. + * varargs.cc (make_va_list_state_machine): Update to use + std::unique_ptr. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * call-summary.cc (call_summary_replay::call_summary_replay): + Convert "summary" from call_summary * to call_summary &. + (call_summary_replay::dump_to_pp): Likewise for m_summary. + * call-summary.h (call_summary_replay::call_summary_replay): + Likewise for "summary". + (call_summary_replay::m_summary): Likewise. + * engine.cc (call_summary_edge_info::call_summary_edge_info): + Likewise. + (call_summary_edge_info::update_state): Likewise. + (call_summary_edge_info::update_model): Likewise. + (call_summary_edge_info::print_desc): Likewise for m_summary. + (call_summary_edge_info::m_summary): Likewise. + (exploded_node::replay_call_summaries): Update for change to + replay_call_summary. + (exploded_node::replay_call_summary): Convert "summary" from + call_summary * to call_summary &. + * exploded-graph.h (exploded_node::replay_call_summary): Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * analyzer.cc: Convert gcall * to gcall & where we know the + pointer must be non-null. + * call-details.cc: Likewise. + * call-details.h: Likewise. + * call-info.cc: Likewise. + * call-info.h: Likewise. + * call-summary.h: Likewise. + * checker-event.cc: Likewise. + * checker-event.h: Likewise. + * common.h: Likewise. + * diagnostic-manager.cc: Likewise. + * engine.cc: Likewise. + * exploded-graph.h: Likewise. + * kf-analyzer.cc: Likewise. + * kf-lang-cp.cc: Likewise. + * kf.cc: Likewise. + * known-function-manager.cc: Likewise. + * program-state.cc: Likewise. + * program-state.h: Likewise. + * region-model.cc: Likewise. + * region-model.h: Likewise. + * sm-fd.cc: Likewise. + * sm-file.cc: Likewise. + * sm-malloc.cc: Likewise. + * sm-sensitive.cc: Likewise. + * sm-signal.cc: Likewise. + * sm-taint.cc: Likewise. + * sm.h: Likewise. + * store.cc: Likewise. + * store.h: Likewise. + * supergraph.cc: Likewise. + * supergraph.h: Likewise. + * svalue.h: Likewise. + * varargs.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * access-diagram.cc: Convert enum access_direction to + "enum class". + * bounds-checking.cc: Likewise. + * checker-event.cc: Convert enum event_kind to "enum class". + * checker-event.h: Likewise. + * checker-path.cc: Likewise. + * common.h: Convert enum access_direction to "enum class". + * constraint-manager.cc: Convert enum bound_kind to "enum class". + * constraint-manager.h: Likewise. + * diagnostic-manager.cc: Convert enum event_kind to "enum class". + * engine.cc: Convert enum status to "enum class". + * exploded-graph.h: Likewise. + * infinite-loop.cc: Likewise. + * kf-lang-cp.cc: Convert enum poison_kind to "enum class". + * kf.cc: Likewise. + * region-model-manager.cc: Likewise. + * region-model.cc: Likewise; also for enum access_direction. + * svalue.cc: Likewise. + * svalue.h: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * analyzer.h: Rename to... + * common.h: ...this. Add define of INCLUDE_VECTOR, includes of + "config.h", "system.h", "coretypes.h", "make-unique.h", "tree.h", + "function.h", "basic-block.h", "gimple.h", "options.h", + "bitmap.h", "diagnostic-core.h", and "diagnostic-path.h". + * access-diagram.h: Don't include "analyzer/analyzer.h". + * access-diagram.cc: Reorganize includes to #include + "analyzer/common.h" first, then group by subsystem, dropping + redundant headers. + * analysis-plan.cc: Likewise. + * analyzer-language.cc: Likewise. + * analyzer-pass.cc: Likewise. + * analyzer-selftests.cc: Likewise. + * analyzer.cc: Likewise. + * bounds-checking.cc: Likewise. + * call-details.cc: Likewise. + * call-info.cc: Likewise. + * call-string.cc: Likewise. + * call-summary.cc: Likewise. + * checker-event.cc: Likewise. + * checker-path.cc: Likewise. + * complexity.cc: Likewise. + * constraint-manager.cc: Likewise. + * diagnostic-manager.cc: Likewise. + * engine.cc: Likewise. + * feasible-graph.cc: Likewise. + * infinite-loop.cc: Likewise. + * infinite-recursion.cc: Likewise. + * kf-analyzer.cc: Likewise. + * kf-lang-cp.cc: Likewise. + * kf.cc: Likewise. + * known-function-manager.cc: Likewise. + * pending-diagnostic.cc: Likewise. + * program-point.cc: Likewise. + * program-state.cc: Likewise. + * ranges.cc: Likewise. + * record-layout.cc: Likewise. + * region-model-asm.cc: Likewise. + * region-model-manager.cc: Likewise. + * region-model-reachability.cc: Likewise. + * region-model.cc: Likewise. + * region.cc: Likewise. + * sm-fd.cc: Likewise. + * sm-file.cc: Likewise. + * sm-malloc.cc: Likewise. + * sm-pattern-test.cc: Likewise. + * sm-sensitive.cc: Likewise. + * sm-signal.cc: Likewise. + * sm-taint.cc: Likewise. + * sm.cc: Likewise. + * state-purge.cc: Likewise. + * store.cc: Likewise. + * supergraph.cc: Likewise. + * svalue.cc: Likewise. + * symbol.cc: Likewise. + * trimmed-graph.cc: Likewise. + * varargs.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * region-model.cc (region_model::on_stmt_pre): Use internal_error + if we see an unexpected gimple stmt code. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * call-details.cc (call_details::dump): New overload. + (call_details::make_dump_widget): New. + * call-details.h (call_details::dump): Declare new overload. + (call_details::make_dump_widget): New decl. + 2025-03-14 Jakub Jelinek <jakub@redhat.com> PR analyzer/119278 diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc index e1596bb..4283360 100644 --- a/gcc/analyzer/access-diagram.cc +++ b/gcc/analyzer/access-diagram.cc @@ -17,28 +17,18 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" #define INCLUDE_ALGORITHM #define INCLUDE_MAP #define INCLUDE_SET -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "diagnostic.h" +#include "analyzer/common.h" + +#include "fold-const.h" #include "intl.h" -#include "make-unique.h" -#include "tree-diagnostic.h" /* for default_tree_printer. */ -#include "analyzer/analyzer.h" + +#include "text-art/ruler.h" + #include "analyzer/region-model.h" #include "analyzer/access-diagram.h" -#include "text-art/ruler.h" -#include "fold-const.h" #include "analyzer/analyzer-selftests.h" #if ENABLE_ANALYZER @@ -245,7 +235,7 @@ get_access_size_str (style_manager &sm, pp_format_decoder (&pp) = default_tree_printer; if (num_bits.maybe_print_for_user (&pp, op.m_model)) { - if (op.m_dir == DIR_READ) + if (op.m_dir == access_direction::read) return fmt_styled_string (sm, _("read of %qT (%s)"), type, @@ -257,7 +247,7 @@ get_access_size_str (style_manager &sm, pp_formatted_text (&pp)); } } - if (op.m_dir == DIR_READ) + if (op.m_dir == access_direction::read) { if (auto p = num_bits.maybe_get_formatted_str (sm, op.m_model, @@ -284,13 +274,13 @@ get_access_size_str (style_manager &sm, if (type) { - if (op.m_dir == DIR_READ) + if (op.m_dir == access_direction::read) return fmt_styled_string (sm, _("read of %qT"), type); else return fmt_styled_string (sm, _("write of %qT"), type); } - if (op.m_dir == DIR_READ) + if (op.m_dir == access_direction::read) return styled_string (sm, _("read")); else return styled_string (sm, _("write")); @@ -375,11 +365,11 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm, if (!wi::fits_uhwi_p (concrete_num_bytes)) return nullptr; if (concrete_num_bytes == 1) - return ::make_unique <text_art::styled_string> + return std::make_unique <text_art::styled_string> (fmt_styled_string (sm, concrete_single_byte_fmt, concrete_num_bytes.to_uhwi ())); else - return ::make_unique <text_art::styled_string> + return std::make_unique <text_art::styled_string> (fmt_styled_string (sm, concrete_plural_bytes_fmt, concrete_num_bytes.to_uhwi ())); } @@ -389,7 +379,7 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm, pp_format_decoder (&pp) = default_tree_printer; if (!num_bytes->maybe_print_for_user (&pp, model)) return nullptr; - return ::make_unique <text_art::styled_string> + return std::make_unique <text_art::styled_string> (fmt_styled_string (sm, symbolic_bytes_fmt, pp_formatted_text (&pp))); } @@ -400,11 +390,11 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm, if (!wi::fits_uhwi_p (concrete_num_bits)) return nullptr; if (concrete_num_bits == 1) - return ::make_unique <text_art::styled_string> + return std::make_unique <text_art::styled_string> (fmt_styled_string (sm, concrete_single_bit_fmt, concrete_num_bits.to_uhwi ())); else - return ::make_unique <text_art::styled_string> + return std::make_unique <text_art::styled_string> (fmt_styled_string (sm, concrete_plural_bits_fmt, concrete_num_bits.to_uhwi ())); } @@ -414,7 +404,7 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm, pp_format_decoder (&pp) = default_tree_printer; if (!m_num_bits.maybe_print_for_user (&pp, model)) return nullptr; - return ::make_unique <text_art::styled_string> + return std::make_unique <text_art::styled_string> (fmt_styled_string (sm, symbolic_bits_fmt, pp_formatted_text (&pp))); } @@ -1975,11 +1965,11 @@ make_written_svalue_spatial_item (const access_operation &op, if (const initial_svalue *initial_sval = sval.dyn_cast_initial_svalue ()) if (const string_region *string_reg = initial_sval->get_region ()->dyn_cast_string_region ()) - return make_unique <string_literal_spatial_item> + return std::make_unique <string_literal_spatial_item> (sval, actual_bits, *string_reg, theme, svalue_spatial_item::kind::WRITTEN); - return make_unique <written_svalue_spatial_item> (op, sval, actual_bits); + return std::make_unique <written_svalue_spatial_item> (op, sval, actual_bits); } static std::unique_ptr<spatial_item> @@ -2000,7 +1990,7 @@ make_existing_svalue_spatial_item (const svalue *sval, const initial_svalue *initial_sval = (const initial_svalue *)sval; if (const string_region *string_reg = initial_sval->get_region ()->dyn_cast_string_region ()) - return make_unique <string_literal_spatial_item> + return std::make_unique <string_literal_spatial_item> (*sval, bits, *string_reg, theme, svalue_spatial_item::kind::EXISTING); @@ -2008,7 +1998,7 @@ make_existing_svalue_spatial_item (const svalue *sval, } case SK_COMPOUND: - return make_unique<compound_svalue_spatial_item> + return std::make_unique<compound_svalue_spatial_item> (*((const compound_svalue *)sval), bits, svalue_spatial_item::kind::EXISTING, @@ -2116,7 +2106,7 @@ public: } m_col_widths - = make_unique <table_dimension_sizes> (m_btm.get_num_columns ()); + = std::make_unique <table_dimension_sizes> (m_btm.get_num_columns ()); /* Now create child widgets. */ @@ -2211,8 +2201,8 @@ private: std::unique_ptr<boundaries> find_boundaries () const { - std::unique_ptr<boundaries> result - = make_unique<boundaries> (*m_op.m_base_region, m_logger); + auto result + = std::make_unique<boundaries> (*m_op.m_base_region, m_logger); m_valid_region_spatial_item.add_boundaries (*result, m_logger); m_accessed_region_spatial_item.add_boundaries (*result, m_logger); @@ -2271,7 +2261,7 @@ private: void add_direction_widget () { - add_child (::make_unique<direction_widget> (*this, m_btm)); + add_child (std::make_unique<direction_widget> (*this, m_btm)); } void add_invalid_accesses_to_region_table (table &t_region) @@ -2382,7 +2372,7 @@ private: bit_size_expr num_before_bits (invalid_before_bits.get_size (m_op.get_manager ())); std::unique_ptr<styled_string> label; - if (m_op.m_dir == DIR_READ) + if (m_op.m_dir == access_direction::read) label = num_before_bits.maybe_get_formatted_str (m_sm, m_op.m_model, _("under-read of %wi bit"), @@ -2423,7 +2413,7 @@ private: maybe_add_gap (w, invalid_before_bits, valid_bits); std::unique_ptr<styled_string> label; - if (m_op.m_dir == DIR_READ) + if (m_op.m_dir == access_direction::read) label = num_valid_bits.maybe_get_formatted_str (m_sm, m_op.m_model, _("size: %wi bit"), @@ -2459,7 +2449,7 @@ private: bit_size_expr num_after_bits (invalid_after_bits.get_size (m_op.get_manager ())); std::unique_ptr<styled_string> label; - if (m_op.m_dir == DIR_READ) + if (m_op.m_dir == access_direction::read) label = num_after_bits.maybe_get_formatted_str (m_sm, m_op.m_model, _("over-read of %wi bit"), @@ -2658,7 +2648,7 @@ direction_widget::paint_to_canvas (canvas &canvas) (canvas, canvas_x, canvas::range_t (get_y_range ()), - (m_dia_impl.get_op ().m_dir == DIR_READ + (m_dia_impl.get_op ().m_dir == access_direction::read ? theme::y_arrow_dir::UP : theme::y_arrow_dir::DOWN), style_id); @@ -2676,11 +2666,12 @@ access_diagram::access_diagram (const access_operation &op, style_manager &sm, const theme &theme, logger *logger) -: wrapper_widget (make_unique <access_diagram_impl> (op, - region_creation_event_id, - sm, - theme, - logger)) +: wrapper_widget + (std::make_unique <access_diagram_impl> (op, + region_creation_event_id, + sm, + theme, + logger)) { } diff --git a/gcc/analyzer/access-diagram.h b/gcc/analyzer/access-diagram.h index ba4649a..e31dd28 100644 --- a/gcc/analyzer/access-diagram.h +++ b/gcc/analyzer/access-diagram.h @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "text-art/canvas.h" #include "text-art/theme.h" #include "text-art/widget.h" -#include "analyzer/analyzer.h" + #include "analyzer/store.h" namespace ana { diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc index 7ae01c0..c563554 100644 --- a/gcc/analyzer/analysis-plan.cc +++ b/gcc/analyzer/analysis-plan.cc @@ -18,27 +18,19 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "options.h" -#include "cgraph.h" +#include "analyzer/common.h" + #include "timevar.h" -#include "ipa-utils.h" -#include "function.h" -#include "analyzer/analyzer.h" -#include "diagnostic-core.h" -#include "analyzer/analyzer-logging.h" -#include "analyzer/analysis-plan.h" #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" #include "cfg.h" -#include "basic-block.h" -#include "gimple.h" #include "gimple-iterator.h" #include "digraph.h" +#include "ipa-utils.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/analysis-plan.h" #include "analyzer/supergraph.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/analyzer-language.cc b/gcc/analyzer/analyzer-language.cc index a0fa9f5..9a25baf 100644 --- a/gcc/analyzer/analyzer-language.cc +++ b/gcc/analyzer/analyzer-language.cc @@ -18,15 +18,13 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" +#include "analyzer/common.h" + +#include "diagnostic.h" #include "stringpool.h" -#include "analyzer/analyzer.h" + #include "analyzer/analyzer-language.h" #include "analyzer/analyzer-logging.h" -#include "diagnostic.h" /* Map from identifier to INTEGER_CST. */ static GTY (()) hash_map <tree, tree> *analyzer_stashed_constants; diff --git a/gcc/analyzer/analyzer-pass.cc b/gcc/analyzer/analyzer-pass.cc index ab41de4..b3a0dfd 100644 --- a/gcc/analyzer/analyzer-pass.cc +++ b/gcc/analyzer/analyzer-pass.cc @@ -18,15 +18,10 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "context.h" +#include "analyzer/common.h" + #include "tree-pass.h" -#include "diagnostic.h" -#include "options.h" -#include "tree.h" -#include "analyzer/analyzer.h" + #include "analyzer/engine.h" namespace { diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc index 0f131f0..334c355 100644 --- a/gcc/analyzer/analyzer-selftests.cc +++ b/gcc/analyzer/analyzer-selftests.cc @@ -18,12 +18,10 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" +#include "analyzer/common.h" + #include "stringpool.h" -#include "analyzer/analyzer.h" + #include "analyzer/analyzer-selftests.h" #if CHECKING_P diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc index da7491b..56cb370 100644 --- a/gcc/analyzer/analyzer.cc +++ b/gcc/analyzer/analyzer.cc @@ -18,20 +18,12 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic.h" -#include "intl.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "tree-pretty-print.h" #include "diagnostic-event-id.h" #include "tree-dfa.h" -#include "make-unique.h" +#include "intl.h" #if ENABLE_ANALYZER @@ -227,11 +219,11 @@ std::unique_ptr<json::value> tree_to_json (tree node) { if (!node) - return ::make_unique<json::literal> (json::JSON_NULL); + return std::make_unique<json::literal> (json::JSON_NULL); pretty_printer pp; dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false); - return ::make_unique<json::string> (pp_formatted_text (&pp)); + return std::make_unique<json::string> (pp_formatted_text (&pp)); } /* Generate a JSON value for EVENT_ID. @@ -246,10 +238,10 @@ diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id) { pretty_printer pp; pp_printf (&pp, "%@", &event_id); - return ::make_unique<json::string> (pp_formatted_text (&pp)); + return std::make_unique<json::string> (pp_formatted_text (&pp)); } else - return ::make_unique<json::literal> (json::JSON_NULL); + return std::make_unique<json::literal> (json::JSON_NULL); } /* Generate a JSON value for OFFSET. @@ -261,7 +253,7 @@ bit_offset_to_json (const bit_offset_t &offset) { pretty_printer pp; pp_wide_int_large (&pp, offset, SIGNED); - return ::make_unique<json::string> (pp_formatted_text (&pp)); + return std::make_unique<json::string> (pp_formatted_text (&pp)); } /* Generate a JSON value for OFFSET. @@ -273,7 +265,7 @@ byte_offset_to_json (const byte_offset_t &offset) { pretty_printer pp; pp_wide_int_large (&pp, offset, SIGNED); - return ::make_unique<json::string> (pp_formatted_text (&pp)); + return std::make_unique<json::string> (pp_formatted_text (&pp)); } /* Workaround for lack of const-correctness of ssa_default_def. */ @@ -298,12 +290,12 @@ get_ssa_default_def (const function &fun, tree var) If LOOK_IN_STD is true, then also look for within std:: for the name. */ bool -is_special_named_call_p (const gcall *call, const char *funcname, +is_special_named_call_p (const gcall &call, const char *funcname, unsigned int num_args, bool look_in_std) { gcc_assert (funcname); - tree fndecl = gimple_call_fndecl (call); + tree fndecl = gimple_call_fndecl (&call); if (!fndecl) return false; @@ -396,7 +388,7 @@ is_std_named_call_p (const_tree fndecl, const char *funcname) bool is_named_call_p (const_tree fndecl, const char *funcname, - const gcall *call, unsigned int num_args) + const gcall &call, unsigned int num_args) { gcc_assert (fndecl); gcc_assert (funcname); @@ -404,7 +396,7 @@ is_named_call_p (const_tree fndecl, const char *funcname, if (!is_named_call_p (fndecl, funcname)) return false; - if (gimple_call_num_args (call) != num_args) + if (gimple_call_num_args (&call) != num_args) return false; return true; @@ -414,7 +406,7 @@ is_named_call_p (const_tree fndecl, const char *funcname, bool is_std_named_call_p (const_tree fndecl, const char *funcname, - const gcall *call, unsigned int num_args) + const gcall &call, unsigned int num_args) { gcc_assert (fndecl); gcc_assert (funcname); @@ -422,7 +414,7 @@ is_std_named_call_p (const_tree fndecl, const char *funcname, if (!is_std_named_call_p (fndecl, funcname)) return false; - if (gimple_call_num_args (call) != num_args) + if (gimple_call_num_args (&call) != num_args) return false; return true; @@ -431,12 +423,12 @@ is_std_named_call_p (const_tree fndecl, const char *funcname, /* Return true if stmt is a setjmp or sigsetjmp call. */ bool -is_setjmp_call_p (const gcall *call) +is_setjmp_call_p (const gcall &call) { if (is_special_named_call_p (call, "setjmp", 1) || is_special_named_call_p (call, "sigsetjmp", 2)) /* region_model::on_setjmp requires a pointer. */ - if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0)))) + if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (&call, 0)))) return true; return false; @@ -445,26 +437,46 @@ is_setjmp_call_p (const gcall *call) /* Return true if stmt is a longjmp or siglongjmp call. */ bool -is_longjmp_call_p (const gcall *call) +is_longjmp_call_p (const gcall &call) { if (is_special_named_call_p (call, "longjmp", 2) || is_special_named_call_p (call, "siglongjmp", 2)) /* exploded_node::on_longjmp requires a pointer for the initial argument. */ - if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0)))) + if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (&call, 0)))) return true; return false; } +bool +is_cxa_throw_p (const gcall &call) +{ + tree fndecl = gimple_call_fndecl (&call); + if (!fndecl) + return false; + + return is_named_call_p (fndecl, "__cxa_throw"); +} + +bool +is_cxa_rethrow_p (const gcall &call) +{ + tree fndecl = gimple_call_fndecl (&call); + if (!fndecl) + return false; + + return is_named_call_p (fndecl, "__cxa_rethrow"); +} + /* For a CALL that matched is_special_named_call_p or is_named_call_p for some name, return a name for the called function suitable for use in diagnostics (stripping the leading underscores). */ const char * -get_user_facing_name (const gcall *call) +get_user_facing_name (const gcall &call) { - tree fndecl = gimple_call_fndecl (call); + tree fndecl = gimple_call_fndecl (&call); gcc_assert (fndecl); tree identifier = DECL_NAME (fndecl); diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index d5f82c6..2ca9058 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -222,6 +222,10 @@ Wanalyzer-tainted-size Common Var(warn_analyzer_tainted_size) Init(1) Warning Warn about code paths in which an unsanitized value is used as a size. +Wanalyzer-throw-of-unexpected-type +Common Var(warn_analyzer_throw_of_unexpected_type) Init(1) Warning +Warn about code paths in which an exception of unexpected type is thrown. + Wanalyzer-undefined-behavior-ptrdiff Common Var(warn_analyzer_undefined_behavior_ptrdiff) Init(1) Warning Warn about code paths in which pointer subtraction involves undefined behavior. diff --git a/gcc/analyzer/analyzer.opt.urls b/gcc/analyzer/analyzer.opt.urls index 18a0d69..e76e6e5 100644 --- a/gcc/analyzer/analyzer.opt.urls +++ b/gcc/analyzer/analyzer.opt.urls @@ -114,6 +114,9 @@ UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-tainted-offset) Wanalyzer-tainted-size UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-tainted-size) +Wanalyzer-throw-of-unexpected-type +UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-throw-of-unexpected-type) + Wanalyzer-undefined-behavior-ptrdiff UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-undefined-behavior-ptrdiff) diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc index c83b419..a3b1345 100644 --- a/gcc/analyzer/bounds-checking.cc +++ b/gcc/analyzer/bounds-checking.cc @@ -17,21 +17,12 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" +#include "analyzer/common.h" + #include "intl.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" #include "diagnostic-diagram.h" #include "diagnostic-format-sarif.h" -#include "analyzer/analyzer.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/region-model.h" #include "analyzer/checker-event.h" @@ -105,9 +96,9 @@ public: so we don't need an event for that. */ if (byte_capacity) emission_path.add_event - (make_unique<oob_region_creation_event_capacity> (byte_capacity, - loc_info, - *this)); + (std::make_unique<oob_region_creation_event_capacity> (byte_capacity, + loc_info, + *this)); } void maybe_add_sarif_properties (sarif_object &result_obj) @@ -116,7 +107,7 @@ public: sarif_property_bag &props = result_obj.get_or_create_properties (); #define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/" props.set_string (PROPERTY_PREFIX "dir", - get_dir () == DIR_READ ? "read" : "write"); + get_dir () == access_direction::read ? "read" : "write"); props.set (PROPERTY_PREFIX "model", m_model.to_json ()); props.set (PROPERTY_PREFIX "region", m_reg->to_json ()); props.set (PROPERTY_PREFIX "diag_arg", tree_to_json (m_diag_arg)); @@ -298,9 +289,9 @@ public: { if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST) emission_path.add_event - (make_unique<oob_region_creation_event_capacity> (m_byte_bound, - loc_info, - *this)); + (std::make_unique<oob_region_creation_event_capacity> (m_byte_bound, + loc_info, + *this)); } void maybe_add_sarif_properties (sarif_object &result_obj) @@ -505,7 +496,7 @@ public: } } - enum access_direction get_dir () const final override { return DIR_WRITE; } + enum access_direction get_dir () const final override { return access_direction::write; } }; /* Concrete subclass to complain about buffer over-reads. */ @@ -689,7 +680,7 @@ public: } } - enum access_direction get_dir () const final override { return DIR_READ; } + enum access_direction get_dir () const final override { return access_direction::read; } }; /* Concrete subclass to complain about buffer underwrites. */ @@ -817,7 +808,7 @@ public: } } - enum access_direction get_dir () const final override { return DIR_WRITE; } + enum access_direction get_dir () const final override { return access_direction::write; } }; /* Concrete subclass to complain about buffer under-reads. */ @@ -945,7 +936,7 @@ public: } } - enum access_direction get_dir () const final override { return DIR_READ; } + enum access_direction get_dir () const final override { return access_direction::read; } }; /* Abstract class to complain about out-of-bounds read/writes where @@ -1116,7 +1107,7 @@ public: return true; } - enum access_direction get_dir () const final override { return DIR_WRITE; } + enum access_direction get_dir () const final override { return access_direction::write; } }; /* Concrete subclass to complain about over-reads with symbolic values. */ @@ -1243,7 +1234,7 @@ public: return true; } - enum access_direction get_dir () const final override { return DIR_READ; } + enum access_direction get_dir () const final override { return access_direction::read; } }; const svalue * @@ -1427,24 +1418,26 @@ region_model::check_symbolic_bounds (const region *base_reg, default: gcc_unreachable (); break; - case DIR_READ: + case access_direction::read: gcc_assert (sval_hint == nullptr); - ctxt->warn (make_unique<symbolic_buffer_over_read> (*this, - sized_offset_reg, - diag_arg, - offset_tree, - num_bytes_tree, - capacity_tree)); + ctxt->warn + (std::make_unique<symbolic_buffer_over_read> (*this, + sized_offset_reg, + diag_arg, + offset_tree, + num_bytes_tree, + capacity_tree)); return false; break; - case DIR_WRITE: - ctxt->warn (make_unique<symbolic_buffer_overflow> (*this, - sized_offset_reg, - diag_arg, - offset_tree, - num_bytes_tree, - capacity_tree, - sval_hint)); + case access_direction::write: + ctxt->warn + (std::make_unique<symbolic_buffer_overflow> (*this, + sized_offset_reg, + diag_arg, + offset_tree, + num_bytes_tree, + capacity_tree, + sval_hint)); return false; break; } @@ -1535,18 +1528,20 @@ region_model::check_region_bounds (const region *reg, default: gcc_unreachable (); break; - case DIR_READ: + case access_direction::read: gcc_assert (sval_hint == nullptr); - ctxt->warn (make_unique<concrete_buffer_under_read> (*this, reg, - diag_arg, - bits_outside)); + ctxt->warn + (std::make_unique<concrete_buffer_under_read> (*this, reg, + diag_arg, + bits_outside)); oob_safe = false; break; - case DIR_WRITE: - ctxt->warn (make_unique<concrete_buffer_underwrite> (*this, - reg, diag_arg, - bits_outside, - sval_hint)); + case access_direction::write: + ctxt->warn + (std::make_unique<concrete_buffer_underwrite> (*this, + reg, diag_arg, + bits_outside, + sval_hint)); oob_safe = false; break; } @@ -1571,20 +1566,22 @@ region_model::check_region_bounds (const region *reg, default: gcc_unreachable (); break; - case DIR_READ: + case access_direction::read: gcc_assert (sval_hint == nullptr); - ctxt->warn (make_unique<concrete_buffer_over_read> (*this, - reg, diag_arg, - bits_outside, - bit_bound)); + ctxt->warn + (std::make_unique<concrete_buffer_over_read> (*this, + reg, diag_arg, + bits_outside, + bit_bound)); oob_safe = false; break; - case DIR_WRITE: - ctxt->warn (make_unique<concrete_buffer_overflow> (*this, - reg, diag_arg, - bits_outside, - bit_bound, - sval_hint)); + case access_direction::write: + ctxt->warn + (std::make_unique<concrete_buffer_overflow> (*this, + reg, diag_arg, + bits_outside, + bit_bound, + sval_hint)); oob_safe = false; break; } diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc index 4122f84..bca8658 100644 --- a/gcc/analyzer/call-details.cc +++ b/gcc/analyzer/call-details.cc @@ -18,28 +18,20 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "diagnostic.h" #include "tree-diagnostic.h" /* for default_tree_printer. */ #include "gimple-pretty-print.h" -#include "analyzer/region-model.h" -#include "analyzer/call-details.h" -#include "analyzer/ranges.h" #include "stringpool.h" #include "attribs.h" -#include "make-unique.h" #include "diagnostic-format-sarif.h" +#include "analyzer/analyzer-logging.h" +#include "analyzer/region-model.h" +#include "analyzer/call-details.h" +#include "analyzer/ranges.h" + #if ENABLE_ANALYZER namespace ana { @@ -48,13 +40,13 @@ namespace ana { /* call_details's ctor. */ -call_details::call_details (const gcall *call, region_model *model, +call_details::call_details (const gcall &call, region_model *model, region_model_context *ctxt) : m_call (call), m_model (model), m_ctxt (ctxt), m_lhs_type (NULL_TREE), m_lhs_region (NULL) { m_lhs_type = NULL_TREE; - if (tree lhs = gimple_call_lhs (call)) + if (tree lhs = gimple_call_lhs (&call)) { m_lhs_region = model->get_lvalue (lhs, ctxt); m_lhs_type = TREE_TYPE (lhs); @@ -66,9 +58,11 @@ call_details::call_details (const gcall *call, region_model *model, call_details::call_details (const call_details &cd, region_model_context *ctxt) +: m_call (cd.m_call), m_model (cd.m_model), + m_ctxt (ctxt), + m_lhs_type (cd.m_lhs_type), + m_lhs_region (cd.m_lhs_region) { - *this = cd; - m_ctxt = ctxt; } /* Get the manager from m_model. */ @@ -252,7 +246,7 @@ call_details::set_any_lhs_with_defaults () const unsigned call_details::num_args () const { - return gimple_call_num_args (m_call); + return gimple_call_num_args (&m_call); } /* Return true if argument IDX is a size_t (or compatible with it). */ @@ -268,7 +262,7 @@ call_details::arg_is_size_p (unsigned idx) const location_t call_details::get_location () const { - return m_call->location; + return m_call.location; } /* Get argument IDX at the callsite as a tree. */ @@ -276,7 +270,7 @@ call_details::get_location () const tree call_details::get_arg_tree (unsigned idx) const { - return gimple_call_arg (m_call, idx); + return gimple_call_arg (&m_call, idx); } /* Get the type of argument IDX. */ @@ -284,7 +278,7 @@ call_details::get_arg_tree (unsigned idx) const tree call_details::get_arg_type (unsigned idx) const { - return TREE_TYPE (gimple_call_arg (m_call, idx)); + return TREE_TYPE (gimple_call_arg (&m_call, idx)); } /* Get argument IDX at the callsite as an svalue. */ @@ -340,7 +334,7 @@ void call_details::dump_to_pp (pretty_printer *pp, bool simple) const { pp_string (pp, "gcall: "); - pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */); + pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */); pp_newline (pp); pp_string (pp, "return region: "); if (m_lhs_region) @@ -348,7 +342,7 @@ call_details::dump_to_pp (pretty_printer *pp, bool simple) const else pp_string (pp, "NULL"); pp_newline (pp); - for (unsigned i = 0; i < gimple_call_num_args (m_call); i++) + for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++) { const svalue *arg_sval = get_arg_svalue (i); pp_printf (pp, "arg %i: ", i); @@ -366,6 +360,65 @@ call_details::dump (bool simple) const dump_to_pp (&pp, simple); } +/* Dump a tree-like representation of this call to stderr. */ + +DEBUG_FUNCTION void +call_details::dump () const +{ + text_art::dump (*this); +} + +std::unique_ptr<text_art::tree_widget> +call_details::make_dump_widget (const text_art::dump_widget_info &dwi) const +{ + using text_art::tree_widget; + std::unique_ptr<tree_widget> cd_widget + (tree_widget::from_fmt (dwi, nullptr, "Call Details")); + + { + pretty_printer the_pp; + pretty_printer * const pp = &the_pp; + pp_format_decoder (pp) = default_tree_printer; + pp_string (pp, "gcall: "); + pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */); + cd_widget->add_child (tree_widget::make (dwi, pp)); + } + { + pretty_printer the_pp; + pretty_printer * const pp = &the_pp; + pp_format_decoder (pp) = default_tree_printer; + pp_string (pp, "return region: "); + if (m_lhs_region) + m_lhs_region->dump_to_pp (pp, true); + else + pp_string (pp, "NULL"); + auto w = tree_widget::make (dwi, pp); + if (m_lhs_region) + w->add_child (m_lhs_region->make_dump_widget (dwi)); + cd_widget->add_child (std::move (w)); + } + if (gimple_call_num_args (&m_call) > 0) + { + std::unique_ptr<tree_widget> args_widget + (tree_widget::from_fmt (dwi, nullptr, "Arguments")); + for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++) + { + pretty_printer the_pp; + pretty_printer * const pp = &the_pp; + pp_format_decoder (pp) = default_tree_printer; + const svalue *arg_sval = get_arg_svalue (i); + pp_printf (pp, "%i: ", i); + arg_sval->dump_to_pp (pp, true); + auto w = tree_widget::make (dwi, pp); + w->add_child (arg_sval->make_dump_widget (dwi)); + args_widget->add_child (std::move (w)); + } + cd_widget->add_child (std::move (args_widget)); + } + + return cd_widget; +} + /* Get a conjured_svalue for this call for REG, and purge any state already relating to that conjured_svalue. */ @@ -373,7 +426,7 @@ const svalue * call_details::get_or_create_conjured_svalue (const region *reg) const { region_model_manager *mgr = m_model->get_manager (); - return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg, + return mgr->get_or_create_conjured_svalue (reg->get_type (), &m_call, reg, conjured_purge (m_model, m_ctxt)); } @@ -388,7 +441,7 @@ call_details::lookup_function_attribute (const char *attr_name) const if (tree fndecl = get_fndecl_for_call ()) allocfntype = TREE_TYPE (fndecl); else - allocfntype = gimple_call_fntype (m_call); + allocfntype = gimple_call_fntype (&m_call); if (!allocfntype) return NULL_TREE; @@ -540,10 +593,10 @@ call_details::complain_about_overlap (unsigned arg_idx_a, if (!byte_range_a.intersection (byte_range_b, *model).is_true ()) return; - ctxt->warn (make_unique<overlapping_buffers> (get_fndecl_for_call (), - byte_range_a, - byte_range_b, - num_bytes_read_sval)); + ctxt->warn (std::make_unique<overlapping_buffers> (get_fndecl_for_call (), + byte_range_a, + byte_range_b, + num_bytes_read_sval)); } } // namespace ana diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h index fee7ad4..c0a9118 100644 --- a/gcc/analyzer/call-details.h +++ b/gcc/analyzer/call-details.h @@ -28,7 +28,7 @@ namespace ana { class call_details { public: - call_details (const gcall *call, region_model *model, + call_details (const gcall &call, region_model *model, region_model_context *ctxt); call_details (const call_details &cd, region_model_context *ctxt); @@ -55,7 +55,7 @@ public: return INTEGRAL_TYPE_P (get_arg_type (idx)); } - const gcall *get_call_stmt () const { return m_call; } + const gcall &get_call_stmt () const { return m_call; } location_t get_location () const; tree get_arg_tree (unsigned idx) const; @@ -68,6 +68,10 @@ public: void dump_to_pp (pretty_printer *pp, bool simple) const; void dump (bool simple) const; + void dump () const; + + std::unique_ptr<text_art::tree_widget> + make_dump_widget (const text_art::dump_widget_info &dwi) const; const svalue *get_or_create_conjured_svalue (const region *) const; @@ -86,7 +90,7 @@ public: const svalue *num_bytes_read_sval) const; private: - const gcall *m_call; + const gcall &m_call; region_model *m_model; region_model_context *m_ctxt; tree m_lhs_type; @@ -110,13 +114,13 @@ public: bool operator== (const call_arg_details &other) const { - return (m_call == other.m_call + return (&m_call == &other.m_call && m_called_fndecl == other.m_called_fndecl && m_arg_idx == other.m_arg_idx && pending_diagnostic::same_tree_p (m_arg_expr, other.m_arg_expr)); } - const gcall *m_call; + const gcall &m_call; tree m_called_fndecl; unsigned m_arg_idx; // 0-based tree m_arg_expr; diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc index 1adbf64..9a698ef 100644 --- a/gcc/analyzer/call-info.cc +++ b/gcc/analyzer/call-info.cc @@ -18,45 +18,31 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "options.h" -#include "cgraph.h" -#include "tree-pretty-print.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "ordered-hash-map.h" #include "cfg.h" #include "digraph.h" -#include "analyzer/supergraph.h" #include "sbitmap.h" +#include "diagnostic-event-id.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/supergraph.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/constraint-manager.h" -#include "diagnostic-event-id.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/region-model-reachability.h" #include "analyzer/analyzer-selftests.h" #include "analyzer/program-state.h" -#include "diagnostic-path.h" #include "analyzer/checker-path.h" #include "analyzer/diagnostic-manager.h" #include "analyzer/exploded-graph.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -72,6 +58,18 @@ custom_edge_info::update_state (program_state *state, return update_model (state->m_region_model, eedge, ctxt); } +/* Base implementation of custom_edge_info::create_enode vfunc. */ + +exploded_node * +custom_edge_info::create_enode (exploded_graph &eg, + const program_point &point, + program_state &&state, + exploded_node *enode_for_diag, + region_model_context *) const +{ + return eg.get_or_create_node (point, state, enode_for_diag); +} + /* class call_info : public custom_edge_info. */ /* Implementation of custom_edge_info::print vfunc for call_info. */ @@ -115,7 +113,7 @@ call_info::add_events_to_path (checker_path *emission_path, const int stack_depth = src_point.get_stack_depth (); emission_path->add_event - (make_unique<call_event> (event_loc_info (get_call_stmt ()->location, + (std::make_unique<call_event> (event_loc_info (get_call_stmt ().location, caller_fndecl, stack_depth), this)); diff --git a/gcc/analyzer/call-info.h b/gcc/analyzer/call-info.h index ec304d8..6548d86 100644 --- a/gcc/analyzer/call-info.h +++ b/gcc/analyzer/call-info.h @@ -30,11 +30,11 @@ namespace ana { class call_info : public custom_edge_info { public: - void print (pretty_printer *pp) const final override; + void print (pretty_printer *pp) const override; void add_events_to_path (checker_path *emission_path, - const exploded_edge &eedge) const final override; + const exploded_edge &eedge) const override; - const gcall *get_call_stmt () const { return m_call_stmt; } + const gcall &get_call_stmt () const { return m_call_stmt; } tree get_fndecl () const { return m_fndecl; } virtual void print_desc (pretty_printer &pp) const = 0; @@ -47,7 +47,7 @@ protected: call_info (const call_details &cd, const function &called_fn); private: - const gcall *m_call_stmt; + const gcall &m_call_stmt; tree m_fndecl; }; diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc index 5099986..afa8004 100644 --- a/gcc/analyzer/call-string.cc +++ b/gcc/analyzer/call-string.cc @@ -18,26 +18,11 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "pretty-print.h" -#include "tree.h" -#include "options.h" -#include "ordered-hash-map.h" -#include "options.h" -#include "cgraph.h" -#include "function.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "digraph.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/supergraph.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -106,11 +91,11 @@ call_string::print (pretty_printer *pp) const std::unique_ptr<json::value> call_string::to_json () const { - auto arr = ::make_unique<json::array> (); + auto arr = std::make_unique<json::array> (); for (const call_string::element_t &e : m_elements) { - auto e_obj = ::make_unique<json::object> (); + auto e_obj = std::make_unique<json::object> (); e_obj->set_integer ("src_snode_idx", e.m_callee->m_index); e_obj->set_integer ("dst_snode_idx", e.m_caller->m_index); e_obj->set_string ("funcname", function_name (e.m_caller->m_fun)); diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc index 27fb575..33de3d6 100644 --- a/gcc/analyzer/call-summary.cc +++ b/gcc/analyzer/call-summary.cc @@ -17,16 +17,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "tree-dfa.h" -#include "diagnostic-core.h" -#include "diagnostic.h" -#include "tree-diagnostic.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "analyzer/region-model.h" #include "analyzer/call-summary.h" #include "analyzer/exploded-graph.h" @@ -165,7 +157,7 @@ call_summary::dump (const extrinsic_state &ext_state, bool simple) const call_summary_replay::call_summary_replay (const call_details &cd, const function &called_fn, - call_summary *summary, + call_summary &summary, const extrinsic_state &ext_state) : m_cd (cd), m_summary (summary), @@ -816,7 +808,7 @@ call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const pp_newline (pp); pp_string (pp, "CALLEE SUMMARY:"); pp_newline (pp); - m_summary->dump_to_pp (m_ext_state, pp, simple); + m_summary.dump_to_pp (m_ext_state, pp, simple); /* Current state of caller (could be in mid-update). */ pp_newline (pp); diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h index 220dd083..7280cca 100644 --- a/gcc/analyzer/call-summary.h +++ b/gcc/analyzer/call-summary.h @@ -69,11 +69,11 @@ class call_summary_replay public: call_summary_replay (const call_details &cd, const function &called_fn, - call_summary *m_summary, + call_summary &summary, const extrinsic_state &ext_state); const call_details &get_call_details () const { return m_cd; } - const gcall *get_call_stmt () const { return m_cd.get_call_stmt (); } + const gcall &get_call_stmt () const { return m_cd.get_call_stmt (); } region_model_manager *get_manager () const { return m_cd.get_manager (); } store_manager *get_store_manager () const { @@ -102,7 +102,7 @@ private: const region *convert_region_from_summary_1 (const region *); const call_details &m_cd; - call_summary *m_summary; + call_summary &m_summary; const extrinsic_state &m_ext_state; // Mapping from svalues in summary to svalues for callsite: diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc index 5d7647c..958cdbf 100644 --- a/gcc/analyzer/checker-event.cc +++ b/gcc/analyzer/checker-event.cc @@ -18,45 +18,31 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" +#include "analyzer/common.h" + #include "gimple-pretty-print.h" +#include "sbitmap.h" +#include "ordered-hash-map.h" #include "fold-const.h" -#include "diagnostic-path.h" -#include "options.h" -#include "cgraph.h" -#include "cfg.h" -#include "digraph.h" -#include "diagnostic-event-id.h" -#include "analyzer/analyzer.h" +#include "gimple-iterator.h" +#include "inlining-iterator.h" +#include "tree-logical-location.h" +#include "diagnostic-format-sarif.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" -#include "sbitmap.h" -#include "bitmap.h" -#include "ordered-hash-map.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/checker-path.h" -#include "gimple-iterator.h" -#include "inlining-iterator.h" #include "analyzer/supergraph.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" #include "analyzer/constraint-manager.h" #include "analyzer/checker-event.h" #include "analyzer/exploded-graph.h" -#include "diagnostic-format-sarif.h" -#include "tree-logical-location.h" #if ENABLE_ANALYZER @@ -71,40 +57,46 @@ event_kind_to_string (enum event_kind ek) { default: gcc_unreachable (); - case EK_DEBUG: - return "EK_DEBUG"; - case EK_CUSTOM: - return "EK_CUSTOM"; - case EK_STMT: - return "EK_STMT"; - case EK_REGION_CREATION: - return "EK_REGION_CREATION"; - case EK_FUNCTION_ENTRY: - return "EK_FUNCTION_ENTRY"; - case EK_STATE_CHANGE: - return "EK_STATE_CHANGE"; - case EK_START_CFG_EDGE: - return "EK_START_CFG_EDGE"; - case EK_END_CFG_EDGE: - return "EK_END_CFG_EDGE"; - case EK_CALL_EDGE: - return "EK_CALL_EDGE"; - case EK_RETURN_EDGE: - return "EK_RETURN_EDGE"; - case EK_START_CONSOLIDATED_CFG_EDGES: - return "EK_START_CONSOLIDATED_CFG_EDGES"; - case EK_END_CONSOLIDATED_CFG_EDGES: - return "EK_END_CONSOLIDATED_CFG_EDGES"; - case EK_INLINED_CALL: - return "EK_INLINED_CALL"; - case EK_SETJMP: - return "EK_SETJMP"; - case EK_REWIND_FROM_LONGJMP: - return "EK_REWIND_FROM_LONGJMP"; - case EK_REWIND_TO_SETJMP: - return "EK_REWIND_TO_SETJMP"; - case EK_WARNING: - return "EK_WARNING"; + case event_kind::debug: + return "debug"; + case event_kind::custom: + return "custom"; + case event_kind::stmt: + return "stmt"; + case event_kind::region_creation: + return "region_creation"; + case event_kind::function_entry: + return "function_entry"; + case event_kind::state_change: + return "state_change"; + case event_kind::start_cfg_edge: + return "start_cfg_edge"; + case event_kind::end_cfg_edge: + return "end_cfg_edge"; + case event_kind::catch_: + return "catch"; + case event_kind::call_edge: + return "call_edge"; + case event_kind::return_edge: + return "return_edge"; + case event_kind::start_consolidated_cfg_edges: + return "start_consolidated_cfg_edges"; + case event_kind::end_consolidated_cfg_edges: + return "end_consolidated_cfg_edges"; + case event_kind::inlined_call: + return "inlined_call"; + case event_kind::setjmp_: + return "setjmp"; + case event_kind::rewind_from_longjmp: + return "rewind_from_longjmp"; + case event_kind::rewind_to_setjmp: + return "rewind_to_setjmp"; + case event_kind::throw_: + return "throw"; + case event_kind::unwind: + return "unwind"; + case event_kind::warning: + return "warning"; } } @@ -258,7 +250,7 @@ precanned_custom_event::print_desc (pretty_printer &pp) const statement_event::statement_event (const gimple *stmt, tree fndecl, int depth, const program_state &dst_state) -: checker_event (EK_STMT, +: checker_event (event_kind::stmt, event_loc_info (gimple_location (stmt), fndecl, depth)), m_stmt (stmt), m_dst_state (dst_state) @@ -279,7 +271,7 @@ statement_event::print_desc (pretty_printer &pp) const /* class region_creation_event : public checker_event. */ region_creation_event::region_creation_event (const event_loc_info &loc_info) -: checker_event (EK_REGION_CREATION, loc_info) +: checker_event (event_kind::region_creation, loc_info) { } @@ -351,7 +343,7 @@ region_creation_event_debug::print_desc (pretty_printer &pp) const /* class function_entry_event : public checker_event. */ function_entry_event::function_entry_event (const program_point &dst_point) -: checker_event (EK_FUNCTION_ENTRY, +: checker_event (event_kind::function_entry, event_loc_info (dst_point.get_supernode ()->get_start_location (), dst_point.get_fndecl (), @@ -393,7 +385,7 @@ state_change_event::state_change_event (const supernode *node, const svalue *origin, const program_state &dst_state, const exploded_node *enode) -: checker_event (EK_STATE_CHANGE, +: checker_event (event_kind::state_change, event_loc_info (stmt->location, node->m_fun->decl, stack_depth)), @@ -741,7 +733,7 @@ start_cfg_edge_event::maybe_describe_condition (bool can_colorize, && zerop (rhs)) { if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs))) - if (is_special_named_call_p (call, "strcmp", 2)) + if (is_special_named_call_p (*call, "strcmp", 2)) { if (op == EQ_EXPR) return label_text::borrow ("when the strings are equal"); @@ -804,7 +796,7 @@ start_cfg_edge_event::should_print_expr_p (tree expr) call_event::call_event (const exploded_edge &eedge, const event_loc_info &loc_info) -: superedge_event (EK_CALL_EDGE, eedge, loc_info) +: superedge_event (event_kind::call_edge, eedge, loc_info) { if (eedge.m_sedge) gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL); @@ -880,7 +872,7 @@ call_event::get_callee_fndecl () const return_event::return_event (const exploded_edge &eedge, const event_loc_info &loc_info) -: superedge_event (EK_RETURN_EDGE, eedge, loc_info) +: superedge_event (event_kind::return_edge, eedge, loc_info) { if (eedge.m_sedge) gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN); @@ -1118,6 +1110,50 @@ rewind_to_setjmp_event::prepare_for_emission (checker_path *path, &m_original_setjmp_event_id); } +/* class throw_event : public checker_event. */ + +/* class explicit_throw_event : public throw_event. */ +void +explicit_throw_event::print_desc (pretty_printer &pp) const +{ + if (m_is_rethrow) + { + if (m_type) + pp_printf (&pp, "rethrowing exception of type %qT here...", m_type); + else + pp_printf (&pp, "rethrowing exception here..."); + } + else + { + if (m_type) + pp_printf (&pp, "throwing exception of type %qT here...", m_type); + else + pp_printf (&pp, "throwing exception here..."); + } +} + +/* class throw_from_call_to_external_fn_event : public throw_event. */ + +void +throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const +{ + if (m_fndecl) + pp_printf (&pp, "if %qD throws an exception...", m_fndecl); + else + pp_printf (&pp, "if the called function throws an exception..."); +} + +// class unwind_event : public checker_event + +void +unwind_event::print_desc (pretty_printer &pp) const +{ + if (m_num_frames > 1) + pp_printf (&pp, "unwinding %i stack frames", m_num_frames); + else + pp_printf (&pp, "unwinding stack frame"); +} + /* class warning_event : public checker_event. */ /* Implementation of diagnostic_event::print_desc vfunc for diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h index f92f514..f3ab899 100644 --- a/gcc/analyzer/checker-event.h +++ b/gcc/analyzer/checker-event.h @@ -30,25 +30,28 @@ namespace ana { /* An enum for discriminating between the concrete subclasses of checker_event. */ -enum event_kind -{ - EK_DEBUG, - EK_CUSTOM, - EK_STMT, - EK_REGION_CREATION, - EK_FUNCTION_ENTRY, - EK_STATE_CHANGE, - EK_START_CFG_EDGE, - EK_END_CFG_EDGE, - EK_CALL_EDGE, - EK_RETURN_EDGE, - EK_START_CONSOLIDATED_CFG_EDGES, - EK_END_CONSOLIDATED_CFG_EDGES, - EK_INLINED_CALL, - EK_SETJMP, - EK_REWIND_FROM_LONGJMP, - EK_REWIND_TO_SETJMP, - EK_WARNING +enum class event_kind +{ + debug, + custom, + stmt, + region_creation, + function_entry, + state_change, + start_cfg_edge, + end_cfg_edge, + catch_, + call_edge, + return_edge, + start_consolidated_cfg_edges, + end_consolidated_cfg_edges, + inlined_call, + setjmp_, + rewind_from_longjmp, + rewind_to_setjmp, + throw_, + unwind, + warning }; extern const char *event_kind_to_string (enum event_kind ek); @@ -60,27 +63,32 @@ extern const char *event_kind_to_string (enum event_kind ek); diagnostic_event checker_event - debug_event (EK_DEBUG) - custom_event (EK_CUSTOM) + debug_event (event_kind::debug) + custom_event (event_kind::custom) precanned_custom_event - statement_event (EK_STMT) - region_creation_event (EK_REGION_CREATION) - function_entry_event (EK_FUNCTION_ENTRY) - state_change_event (EK_STATE_CHANGE) + statement_event (event_kind::stmt) + region_creation_event (event_kind::region_creation) + function_entry_event (event_kind::function_entry) + state_change_event (event_kind::state_change) superedge_event cfg_edge_event - start_cfg_edge_event (EK_START_CFG_EDGE) - end_cfg_edge_event (EK_END_CFG_EDGE) - call_event (EK_CALL_EDGE) - return_edge (EK_RETURN_EDGE) - start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES) - end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES) - inlined_call_event (EK_INLINED_CALL) - setjmp_event (EK_SETJMP) + start_cfg_edge_event (event_kind::start_cfg_edge) + end_cfg_edge_event (event_kind::end_cfg_edge) + catch_cfg_edge_event (event_kind::catch_cfg_edge) + call_event (event_kind::call_edge) + return_edge (event_kind::return_edge) + start_consolidated_cfg_edges_event (event_kind::start_consolidated_cfg_edges) + end_consolidated_cfg_edges_event (event_kind::end_consolidated_cfg_edges) + inlined_call_event (event_kind::inlined_call) + setjmp_event (event_kind::setjmp_) rewind_event - rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP) - rewind_to_setjmp_event (EK_REWIND_TO_SETJMP) - warning_event (EK_WARNING). */ + rewind_from_longjmp_event (event_kind::rewind_from_longjmp) + rewind_to_setjmp_event (event_kind::rewind_to_setjmp) + throw_event (event_kind:throw_) + explicit_throw_event + throw_from_call_to_external_fn_event + unwind_event (event_kind::unwind) + warning_event (event_kind::warning). */ /* Abstract subclass of diagnostic_event; the base class for use in checker_path (the analyzer's diagnostic_path subclass). */ @@ -158,7 +166,7 @@ public: debug_event (const event_loc_info &loc_info, const char *desc) - : checker_event (EK_DEBUG, loc_info), + : checker_event (event_kind::debug, loc_info), m_desc (xstrdup (desc)) { } @@ -180,7 +188,7 @@ class custom_event : public checker_event { protected: custom_event (const event_loc_info &loc_info) - : checker_event (EK_CUSTOM, loc_info) + : checker_event (event_kind::custom, loc_info) { } }; @@ -329,7 +337,7 @@ class function_entry_event : public checker_event { public: function_entry_event (const event_loc_info &loc_info) - : checker_event (EK_FUNCTION_ENTRY, loc_info) + : checker_event (event_kind::function_entry, loc_info) { } @@ -435,7 +443,7 @@ class start_cfg_edge_event : public cfg_edge_event public: start_cfg_edge_event (const exploded_edge &eedge, const event_loc_info &loc_info) - : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info) + : cfg_edge_event (event_kind::start_cfg_edge, eedge, loc_info) { } @@ -461,7 +469,7 @@ class end_cfg_edge_event : public cfg_edge_event public: end_cfg_edge_event (const exploded_edge &eedge, const event_loc_info &loc_info) - : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info) + : cfg_edge_event (event_kind::end_cfg_edge, eedge, loc_info) { } @@ -471,6 +479,32 @@ public: } }; +/* A concrete event subclass for catching an exception + e.g. "...catching 'struct io_error' here". */ + +class catch_cfg_edge_event : public cfg_edge_event +{ +public: + catch_cfg_edge_event (const exploded_edge &eedge, + const event_loc_info &loc_info, + tree type) + : cfg_edge_event (event_kind::catch_, eedge, loc_info), + m_type (type) + { + } + + void print_desc (pretty_printer &pp) const final override + { + if (m_type) + pp_printf (&pp, "...catching exception of type %qT here", m_type); + else + pp_string (&pp, "...catching exception here"); + } + +private: + tree m_type; +}; + /* A concrete event subclass for an interprocedural call. */ class call_event : public superedge_event @@ -517,7 +551,7 @@ class start_consolidated_cfg_edges_event : public checker_event public: start_consolidated_cfg_edges_event (const event_loc_info &loc_info, bool edge_sense) - : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info), + : checker_event (event_kind::start_consolidated_cfg_edges, loc_info), m_edge_sense (edge_sense) { } @@ -537,7 +571,7 @@ class end_consolidated_cfg_edges_event : public checker_event { public: end_consolidated_cfg_edges_event (const event_loc_info &loc_info) - : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info) + : checker_event (event_kind::end_consolidated_cfg_edges, loc_info) { } @@ -558,7 +592,7 @@ public: tree apparent_caller_fndecl, int actual_depth, int stack_depth_adjustment) - : checker_event (EK_INLINED_CALL, + : checker_event (event_kind::inlined_call, event_loc_info (loc, apparent_caller_fndecl, actual_depth + stack_depth_adjustment)), @@ -583,8 +617,8 @@ class setjmp_event : public checker_event public: setjmp_event (const event_loc_info &loc_info, const exploded_node *enode, - const gcall *setjmp_call) - : checker_event (EK_SETJMP, loc_info), + const gcall &setjmp_call) + : checker_event (event_kind::setjmp_, loc_info), m_enode (enode), m_setjmp_call (setjmp_call) { } @@ -597,7 +631,7 @@ public: private: const exploded_node *m_enode; - const gcall *m_setjmp_call; + const gcall &m_setjmp_call; }; /* An abstract event subclass for rewinding from a longjmp to a setjmp @@ -633,7 +667,7 @@ public: rewind_from_longjmp_event (const exploded_edge *eedge, const event_loc_info &loc_info, const rewind_info_t *rewind_info) - : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info, + : rewind_event (eedge, event_kind::rewind_from_longjmp, loc_info, rewind_info) { } @@ -650,7 +684,7 @@ public: rewind_to_setjmp_event (const exploded_edge *eedge, const event_loc_info &loc_info, const rewind_info_t *rewind_info) - : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info, + : rewind_event (eedge, event_kind::rewind_to_setjmp, loc_info, rewind_info) { } @@ -665,6 +699,88 @@ private: diagnostic_event_id_t m_original_setjmp_event_id; }; +/* An abstract subclass for throwing/rethrowing an exception. */ + +class throw_event : public checker_event +{ +public: + throw_event (const event_loc_info &loc_info, + const exploded_node *enode, + const gcall &throw_call) + : checker_event (event_kind::throw_, loc_info), + m_enode (enode), + m_throw_call (throw_call) + { + } + +protected: + const exploded_node *m_enode; + const gcall &m_throw_call; +}; + +/* A concrete event subclass for an explicit "throw EXC;" + or "throw;" (actually, a call to __cxa_throw or __cxa_rethrow). */ + +class explicit_throw_event : public throw_event +{ +public: + explicit_throw_event (const event_loc_info &loc_info, + const exploded_node *enode, + const gcall &throw_call, + tree type, + bool is_rethrow) + : throw_event (loc_info, enode, throw_call), + m_type (type), + m_is_rethrow (is_rethrow) + { + } + + void print_desc (pretty_printer &pp) const final override; + +private: + tree m_type; + bool m_is_rethrow; +}; + +/* A concrete event subclass for an exception being thrown + from within a call to a function we don't have the body of, + or where we don't know what function was called. */ + +class throw_from_call_to_external_fn_event : public throw_event +{ +public: + throw_from_call_to_external_fn_event (const event_loc_info &loc_info, + const exploded_node *enode, + const gcall &throw_call, + tree fndecl) + : throw_event (loc_info, enode, throw_call), + m_fndecl (fndecl) + { + } + + void print_desc (pretty_printer &pp) const final override; + +private: + tree m_fndecl; +}; + +/* A concrete event subclass for unwinding a stack frame when + processing an exception. */ + +class unwind_event : public checker_event +{ +public: + unwind_event (const event_loc_info &loc_info) + : checker_event (event_kind::unwind, loc_info), + m_num_frames (1) + { + } + + void print_desc (pretty_printer &pp) const final override; + + int m_num_frames; +}; + /* Concrete subclass of checker_event for use at the end of a path: a repeat of the warning message at the end of the path (perhaps with references to pertinent events that occurred on the way), at the point @@ -677,7 +793,7 @@ public: const exploded_node *enode, const state_machine *sm, tree var, state_machine::state_t state) - : checker_event (EK_WARNING, loc_info), + : checker_event (event_kind::warning, loc_info), m_enode (enode), m_sm (sm), m_var (var), m_state (state) { diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index d97378e..9bde6f2 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -18,37 +18,22 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "gimple-pretty-print.h" -#include "fold-const.h" -#include "diagnostic-path.h" -#include "options.h" -#include "cgraph.h" -#include "cfg.h" -#include "digraph.h" -#include "diagnostic-event-id.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" -#include "analyzer/sm.h" +#include "analyzer/common.h" + +#include "tree-pretty-print.h" #include "sbitmap.h" -#include "bitmap.h" #include "ordered-hash-map.h" +#include "gimple-iterator.h" +#include "inlining-iterator.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/sm.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/checker-path.h" -#include "gimple-iterator.h" -#include "inlining-iterator.h" #include "analyzer/supergraph.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" @@ -56,7 +41,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/diagnostic-manager.h" #include "analyzer/checker-path.h" #include "analyzer/exploded-graph.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -164,8 +148,8 @@ checker_path::add_region_creation_events (pending_diagnostic *pd, pd->add_region_creation_events (reg, capacity, loc_info, *this); if (debug) - add_event (make_unique<region_creation_event_debug> (reg, capacity, - loc_info)); + add_event (std::make_unique<region_creation_event_debug> (reg, capacity, + loc_info)); } void @@ -183,8 +167,8 @@ checker_path::cfg_edge_pair_at_p (unsigned idx) const { if (m_events.length () < idx + 1) return false; - return (m_events[idx]->m_kind == EK_START_CFG_EDGE - && m_events[idx + 1]->m_kind == EK_END_CFG_EDGE); + return (m_events[idx]->m_kind == event_kind::start_cfg_edge + && m_events[idx + 1]->m_kind == event_kind::end_cfg_edge); } /* Consider a call from "outer" to "middle" which calls "inner", @@ -202,38 +186,38 @@ checker_path::cfg_edge_pair_at_p (unsigned idx) const (for gcc.dg/analyzer/inlining-4.c): before[0]: - EK_FUNCTION_ENTRY "entry to ‘outer’" + event_kind::function_entry "entry to ‘outer’" (depth 1, fndecl ‘outer’, m_loc=511c4) before[1]: - EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..." + event_kind::start_cfg_edge "following ‘true’ branch (when ‘flag != 0’)..." (depth 3 corrected from 1, fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f) before[2]: - EK_END_CFG_EDGE "...to here" + event_kind::end_cfg_edge "...to here" (depth 1, fndecl ‘outer’, m_loc=0) before[3]: - EK_WARNING "here (‘<unknown>’ is in state ‘null’)" + event_kind::warning "here (‘<unknown>’ is in state ‘null’)" (depth 1, fndecl ‘outer’, m_loc=80000004) We want to add inlined_call_events showing the calls, so that the above becomes: after[0]: - EK_FUNCTION_ENTRY "entry to ‘outer’" + event_kind::function_entry "entry to ‘outer’" (depth 1, fndecl ‘outer’, m_loc=511c4) after[1]: - EK_INLINED_CALL "inlined call to ‘middle’ from ‘outer’" + event_kind::inlined_call "inlined call to ‘middle’ from ‘outer’" (depth 1, fndecl ‘outer’, m_loc=53300) after[2]: - EK_INLINED_CALL "inlined call to ‘inner’ from ‘middle’" + event_kind::inlined_call "inlined call to ‘inner’ from ‘middle’" (depth 2, fndecl ‘middle’, m_loc=4d2e0) after[3]: - EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..." + event_kind::start_cfg_edge "following ‘true’ branch (when ‘flag != 0’)..." (depth 3 corrected from 1, fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f) - after[4]: EK_END_CFG_EDGE "...to here" + after[4]: event_kind::end_cfg_edge "...to here" (depth 1, fndecl ‘outer’, m_loc=0) - after[5]: EK_WARNING "here (‘<unknown>’ is in state ‘null’)" + after[5]: event_kind::warning "here (‘<unknown>’ is in state ‘null’)" (depth 1, fndecl ‘outer’, m_loc=80000004) where we've added events between before[0] and before[1] to show diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/common.h index 4843d99..cb03004 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/common.h @@ -1,4 +1,4 @@ -/* Utility functions for the analyzer. +/* Base header for the analyzer, plus utility functions. Copyright (C) 2019-2025 Free Software Foundation, Inc. Contributed by David Malcolm <dmalcolm@redhat.com>. @@ -18,9 +18,21 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#ifndef GCC_ANALYZER_ANALYZER_H -#define GCC_ANALYZER_ANALYZER_H +#ifndef GCC_ANALYZER_COMMON_H +#define GCC_ANALYZER_COMMON_H +#include "config.h" +#define INCLUDE_VECTOR +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "function.h" +#include "basic-block.h" +#include "gimple.h" +#include "options.h" +#include "bitmap.h" +#include "diagnostic-core.h" +#include "diagnostic-path.h" #include "rich-location.h" #include "function.h" #include "json.h" @@ -37,6 +49,9 @@ class supernode; class superedge; class cfg_superedge; class switch_cfg_superedge; + class eh_dispatch_cfg_superedge; + class eh_dispatch_try_cfg_superedge; + class eh_dispatch_allowed_cfg_superedge; class callgraph_superedge; class call_superedge; class return_superedge; @@ -350,10 +365,10 @@ public: /* An enum for describing the direction of an access to memory. */ -enum access_direction +enum class access_direction { - DIR_READ, - DIR_WRITE + read, + write }; /* Abstract base class for associating custom data with an @@ -384,6 +399,12 @@ public: virtual void add_events_to_path (checker_path *emission_path, const exploded_edge &eedge) const = 0; + + virtual exploded_node *create_enode (exploded_graph &eg, + const program_point &point, + program_state &&state, + exploded_node *enode_for_diag, + region_model_context *ctxt) const; }; /* Abstract base class for splitting state. @@ -447,21 +468,23 @@ extern tree remove_ssa_names (tree expr); } // namespace ana -extern bool is_special_named_call_p (const gcall *call, const char *funcname, +extern bool is_special_named_call_p (const gcall &call, const char *funcname, unsigned int num_args, bool look_in_std = false); extern bool is_named_call_p (const_tree fndecl, const char *funcname); extern bool is_named_call_p (const_tree fndecl, const char *funcname, - const gcall *call, unsigned int num_args); + const gcall &call, unsigned int num_args); extern bool is_std_function_p (const_tree fndecl); extern bool is_std_named_call_p (const_tree fndecl, const char *funcname); extern bool is_std_named_call_p (const_tree fndecl, const char *funcname, - const gcall *call, unsigned int num_args); -extern bool is_setjmp_call_p (const gcall *call); -extern bool is_longjmp_call_p (const gcall *call); -extern bool is_placement_new_p (const gcall *call); + const gcall &call, unsigned int num_args); +extern bool is_setjmp_call_p (const gcall &call); +extern bool is_longjmp_call_p (const gcall &call); +extern bool is_placement_new_p (const gcall &call); +extern bool is_cxa_throw_p (const gcall &call); +extern bool is_cxa_rethrow_p (const gcall &call); -extern const char *get_user_facing_name (const gcall *call); +extern const char *get_user_facing_name (const gcall &call); extern void register_analyzer_pass (); @@ -577,4 +600,4 @@ private: extern void sorry_no_analyzer (); #endif /* #if !ENABLE_ANALYZER */ -#endif /* GCC_ANALYZER_ANALYZER_H */ +#endif /* GCC_ANALYZER_COMMON_H */ diff --git a/gcc/analyzer/complexity.cc b/gcc/analyzer/complexity.cc index cb88f60..4a0a156 100644 --- a/gcc/analyzer/complexity.cc +++ b/gcc/analyzer/complexity.cc @@ -18,34 +18,14 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" -#include "fold-const.h" -#include "tree-pretty-print.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "options.h" #include "cgraph.h" #include "cfg.h" #include "digraph.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 55d8996..a3e682c 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -18,28 +18,17 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" +#include "analyzer/common.h" + #include "fold-const.h" -#include "selftest.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "analyzer/analyzer.h" #include "ordered-hash-map.h" -#include "options.h" #include "cgraph.h" #include "cfg.h" #include "digraph.h" -#include "analyzer/supergraph.h" #include "sbitmap.h" -#include "bitmap.h" +#include "tree-pretty-print.h" + +#include "analyzer/supergraph.h" #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" @@ -48,8 +37,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/constraint-manager.h" #include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" -#include "tree-pretty-print.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -126,7 +113,7 @@ bound::ensure_closed (enum bound_kind bound_kind) and convert x < 5 into x <= 4. */ gcc_assert (CONSTANT_CLASS_P (m_constant)); gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (m_constant))); - m_constant = fold_build2 (bound_kind == BK_UPPER ? MINUS_EXPR : PLUS_EXPR, + m_constant = fold_build2 (bound_kind == bound_kind::upper ? MINUS_EXPR : PLUS_EXPR, TREE_TYPE (m_constant), m_constant, integer_one_node); gcc_assert (CONSTANT_CLASS_P (m_constant)); @@ -203,8 +190,8 @@ range::constrained_to_single_element () return NULL_TREE; /* Convert any open bounds to closed bounds. */ - m_lower_bound.ensure_closed (BK_LOWER); - m_upper_bound.ensure_closed (BK_UPPER); + m_lower_bound.ensure_closed (bound_kind::lower); + m_upper_bound.ensure_closed (bound_kind::upper); // Are they equal? tree comparison = fold_binary (EQ_EXPR, boolean_type_node, @@ -315,18 +302,18 @@ range::add_bound (bound b, enum bound_kind bound_kind) { default: gcc_unreachable (); - case BK_LOWER: + case bound_kind::lower: /* Discard redundant bounds. */ if (m_lower_bound.m_constant) { - m_lower_bound.ensure_closed (BK_LOWER); + m_lower_bound.ensure_closed (bound_kind::lower); if (tree_int_cst_le (b.m_constant, m_lower_bound.m_constant)) return true; } if (m_upper_bound.m_constant) { - m_upper_bound.ensure_closed (BK_UPPER); + m_upper_bound.ensure_closed (bound_kind::upper); /* Reject B <= V <= UPPER when B > UPPER. */ if (!tree_int_cst_le (b.m_constant, m_upper_bound.m_constant)) @@ -335,18 +322,18 @@ range::add_bound (bound b, enum bound_kind bound_kind) m_lower_bound = b; break; - case BK_UPPER: + case bound_kind::upper: /* Discard redundant bounds. */ if (m_upper_bound.m_constant) { - m_upper_bound.ensure_closed (BK_UPPER); + m_upper_bound.ensure_closed (bound_kind::upper); if (!tree_int_cst_lt (b.m_constant, m_upper_bound.m_constant)) return true; } if (m_lower_bound.m_constant) { - m_lower_bound.ensure_closed (BK_LOWER); + m_lower_bound.ensure_closed (bound_kind::lower); /* Reject LOWER <= V <= B when LOWER > B. */ if (!tree_int_cst_le (m_lower_bound.m_constant, b.m_constant)) @@ -371,16 +358,16 @@ range::add_bound (enum tree_code op, tree rhs_const) return true; case LT_EXPR: /* "V < RHS_CONST" */ - return add_bound (bound (rhs_const, false), BK_UPPER); + return add_bound (bound (rhs_const, false), bound_kind::upper); case LE_EXPR: /* "V <= RHS_CONST" */ - return add_bound (bound (rhs_const, true), BK_UPPER); + return add_bound (bound (rhs_const, true), bound_kind::upper); case GE_EXPR: /* "V >= RHS_CONST" */ - return add_bound (bound (rhs_const, true), BK_LOWER); + return add_bound (bound (rhs_const, true), bound_kind::lower); case GT_EXPR: /* "V > RHS_CONST" */ - return add_bound (bound (rhs_const, false), BK_LOWER); + return add_bound (bound (rhs_const, false), bound_kind::lower); } } @@ -449,7 +436,7 @@ bounded_range::dump (bool show_types) const std::unique_ptr<json::object> bounded_range::to_json () const { - auto range_obj = ::make_unique<json::object> (); + auto range_obj = std::make_unique<json::object> (); set_json_attr (*range_obj, "lower", m_lower); set_json_attr (*range_obj, "upper", m_upper); return range_obj; @@ -718,7 +705,7 @@ bounded_ranges::dump (bool show_types) const std::unique_ptr<json::value> bounded_ranges::to_json () const { - auto arr_obj = ::make_unique<json::array> (); + auto arr_obj = std::make_unique<json::array> (); for (unsigned i = 0; i < m_ranges.length (); ++i) arr_obj->append (m_ranges[i].to_json ()); @@ -1116,9 +1103,9 @@ equiv_class::print (pretty_printer *pp) const std::unique_ptr<json::object> equiv_class::to_json () const { - auto ec_obj = ::make_unique<json::object> (); + auto ec_obj = std::make_unique<json::object> (); - auto sval_arr = ::make_unique<json::array> (); + auto sval_arr = std::make_unique<json::array> (); for (const svalue *sval : m_vars) sval_arr->append (sval->to_json ()); ec_obj->set ("svals", std::move (sval_arr)); @@ -1383,7 +1370,7 @@ constraint::print (pretty_printer *pp, const constraint_manager &cm) const std::unique_ptr<json::object> constraint::to_json () const { - auto con_obj = ::make_unique<json::object> (); + auto con_obj = std::make_unique<json::object> (); con_obj->set_integer ("lhs", m_lhs.as_int ()); con_obj->set_string ("op", constraint_op_code (m_op)); @@ -1471,7 +1458,7 @@ bounded_ranges_constraint::print (pretty_printer *pp, std::unique_ptr<json::object> bounded_ranges_constraint::to_json () const { - auto con_obj = ::make_unique<json::object> (); + auto con_obj = std::make_unique<json::object> (); con_obj->set_integer ("ec", m_ec_id.as_int ()); con_obj->set ("ranges", m_ranges->to_json ()); @@ -1784,11 +1771,11 @@ debug (const constraint_manager &cm) std::unique_ptr<json::object> constraint_manager::to_json () const { - auto cm_obj = ::make_unique<json::object> (); + auto cm_obj = std::make_unique<json::object> (); /* Equivalence classes. */ { - auto ec_arr = ::make_unique<json::array> (); + auto ec_arr = std::make_unique<json::array> (); for (const equiv_class *ec : m_equiv_classes) ec_arr->append (ec->to_json ()); cm_obj->set ("ecs", std::move (ec_arr)); @@ -1796,7 +1783,7 @@ constraint_manager::to_json () const /* Constraints. */ { - auto con_arr = ::make_unique<json::array> (); + auto con_arr = std::make_unique<json::array> (); for (const constraint &c : m_constraints) con_arr->append (c.to_json ()); cm_obj->set ("constraints", std::move (con_arr)); @@ -1804,7 +1791,7 @@ constraint_manager::to_json () const /* m_bounded_ranges_constraints. */ { - auto con_arr = ::make_unique<json::array> (); + auto con_arr = std::make_unique<json::array> (); for (const auto &c : m_bounded_ranges_constraints) con_arr->append (c.to_json ()); cm_obj->set ("bounded_ranges_constraints", std::move (con_arr)); @@ -2578,12 +2565,12 @@ constraint_manager::get_ec_bounds (equiv_class_id ec_id) const case CONSTRAINT_LT: /* We have "EC_ID < OTHER_CST". */ - result.add_bound (bound (other_cst, false), BK_UPPER); + result.add_bound (bound (other_cst, false), bound_kind::upper); break; case CONSTRAINT_LE: /* We have "EC_ID <= OTHER_CST". */ - result.add_bound (bound (other_cst, true), BK_UPPER); + result.add_bound (bound (other_cst, true), bound_kind::upper); break; } } @@ -2600,13 +2587,13 @@ constraint_manager::get_ec_bounds (equiv_class_id ec_id) const case CONSTRAINT_LT: /* We have "OTHER_CST < EC_ID" i.e. "EC_ID > OTHER_CST". */ - result.add_bound (bound (other_cst, false), BK_LOWER); + result.add_bound (bound (other_cst, false), bound_kind::lower); break; case CONSTRAINT_LE: /* We have "OTHER_CST <= EC_ID" i.e. "EC_ID >= OTHER_CST". */ - result.add_bound (bound (other_cst, true), BK_LOWER); + result.add_bound (bound (other_cst, true), bound_kind::lower); break; } } diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h index c22b99e..a26b48d 100644 --- a/gcc/analyzer/constraint-manager.h +++ b/gcc/analyzer/constraint-manager.h @@ -25,10 +25,10 @@ namespace ana { class constraint_manager; -enum bound_kind +enum class bound_kind { - BK_LOWER, - BK_UPPER + lower, + upper }; /* One of the end-points of a range. */ diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 4bf1dce..7575b16 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -18,22 +18,19 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "input.h" -#include "diagnostic-core.h" -#include "pretty-print.h" -#include "gcc-rich-location.h" +#include "analyzer/common.h" + +#include "cfg.h" +#include "basic-block.h" +#include "gimple.h" #include "gimple-pretty-print.h" -#include "function.h" -#include "diagnostic-event-id.h" -#include "diagnostic-path.h" -#include "bitmap.h" -#include "ordered-hash-map.h" -#include "analyzer/analyzer.h" +#include "gimple-iterator.h" +#include "inlining-iterator.h" +#include "cgraph.h" +#include "digraph.h" +#include "gcc-rich-location.h" +#include "diagnostic-format-sarif.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -43,13 +40,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/constraint-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "inlining-iterator.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" @@ -57,8 +47,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/feasible-graph.h" #include "analyzer/checker-path.h" #include "analyzer/reachability.h" -#include "make-unique.h" -#include "diagnostic-format-sarif.h" #if ENABLE_ANALYZER @@ -203,7 +191,7 @@ epath_finder::get_best_epath (const exploded_node *enode, logger->log ("trying to find shortest path ignoring feasibility"); gcc_assert (m_sep); std::unique_ptr<exploded_path> epath - = make_unique<exploded_path> (m_sep->get_shortest_path (enode)); + = std::make_unique<exploded_path> (m_sep->get_shortest_path (enode)); if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg)) { if (logger) @@ -742,7 +730,7 @@ saved_diagnostic::add_event (std::unique_ptr<checker_event> event) std::unique_ptr<json::object> saved_diagnostic::to_json () const { - auto sd_obj = ::make_unique<json::object> (); + auto sd_obj = std::make_unique<json::object> (); if (m_sm) sd_obj->set_string ("sm", m_sm->get_name ()); @@ -1048,10 +1036,10 @@ saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const props.set_integer (PROPERTY_PREFIX "idx", m_idx); if (m_duplicates.length () > 0) { - auto duplicates_arr = ::make_unique<json::array> (); + auto duplicates_arr = std::make_unique<json::array> (); for (auto iter : m_duplicates) { - auto sd_obj = ::make_unique<sarif_object> (); + auto sd_obj = std::make_unique<sarif_object> (); iter->maybe_add_sarif_properties (*sd_obj); duplicates_arr->append (std::move (sd_obj)); } @@ -1242,10 +1230,10 @@ diagnostic_manager::add_event (std::unique_ptr<checker_event> event) std::unique_ptr<json::object> diagnostic_manager::to_json () const { - auto dm_obj = ::make_unique<json::object> (); + auto dm_obj = std::make_unique<json::object> (); { - auto sd_arr = ::make_unique<json::array> (); + auto sd_arr = std::make_unique<json::array> (); int i; saved_diagnostic *sd; FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd) @@ -1816,16 +1804,16 @@ public: int stack_depth = src_stack_depth; m_emission_path->add_event - (make_unique<state_change_event> (supernode, - stmt, - stack_depth, - sm, - nullptr, - src_sm_val, - dst_sm_val, - nullptr, - dst_state, - src_node)); + (std::make_unique<state_change_event> (supernode, + stmt, + stack_depth, + sm, + nullptr, + src_sm_val, + dst_sm_val, + nullptr, + dst_state, + src_node)); return false; } @@ -1861,16 +1849,16 @@ public: return false; m_emission_path->add_event - (make_unique<state_change_event> (supernode, - stmt, - stack_depth, - sm, - sval, - src_sm_val, - dst_sm_val, - dst_origin_sval, - dst_state, - src_node)); + (std::make_unique<state_change_event> (supernode, + stmt, + stack_depth, + sm, + sval, + src_sm_val, + dst_sm_val, + dst_origin_sval, + dst_state, + src_node)); return false; } @@ -1963,7 +1951,7 @@ struct null_assignment_sm_context : public sm_context { } - tree get_fndecl_for_call (const gcall */*call*/) final override + tree get_fndecl_for_call (const gcall &/*call*/) final override { return NULL_TREE; } @@ -2007,15 +1995,15 @@ struct null_assignment_sm_context : public sm_context int stack_depth = m_point->get_stack_depth (); m_emission_path->add_event - (make_unique<state_change_event> (supernode, - m_stmt, - stack_depth, - m_sm, - var_new_sval, - from, to, - nullptr, - *m_new_state, - nullptr)); + (std::make_unique<state_change_event> (supernode, + m_stmt, + stack_depth, + m_sm, + var_new_sval, + from, to, + nullptr, + *m_new_state, + nullptr)); } void set_next_state (const gimple *stmt, @@ -2033,15 +2021,15 @@ struct null_assignment_sm_context : public sm_context int stack_depth = m_point->get_stack_depth (); m_emission_path->add_event - (make_unique<state_change_event> (supernode, - m_stmt, - stack_depth, - m_sm, - sval, - from, to, - nullptr, - *m_new_state, - nullptr)); + (std::make_unique<state_change_event> (supernode, + m_stmt, + stack_depth, + m_sm, + sval, + from, to, + nullptr, + *m_new_state, + nullptr)); } void warn (const supernode *, const gimple *, @@ -2220,18 +2208,19 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb, { const gimple *stmt = dst_point.get_stmt (); const gcall *call = dyn_cast <const gcall *> (stmt); - if (call && is_setjmp_call_p (call)) + if (call && is_setjmp_call_p (*call)) emission_path->add_event - (make_unique<setjmp_event> (event_loc_info (stmt->location, - dst_point.get_fndecl (), - dst_stack_depth), - dst_node, - call)); + (std::make_unique<setjmp_event> + (event_loc_info (stmt->location, + dst_point.get_fndecl (), + dst_stack_depth), + dst_node, + *call)); else emission_path->add_event - (make_unique<statement_event> (stmt, - dst_point.get_fndecl (), - dst_stack_depth, dst_state)); + (std::make_unique<statement_event> (stmt, + dst_point.get_fndecl (), + dst_stack_depth, dst_state)); /* Create state change events for assignment to NULL. Iterate through the stmts in dst_enode, adding state change @@ -2324,11 +2313,11 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb, " at this edge: "); pb.get_feasibility_problem ()->dump_to_pp (&pp); emission_path->add_event - (make_unique<precanned_custom_event> - (event_loc_info (dst_point.get_location (), - dst_point.get_fndecl (), - dst_stack_depth), - pp_formatted_text (&pp))); + (std::make_unique<precanned_custom_event> + (event_loc_info (dst_point.get_location (), + dst_point.get_fndecl (), + dst_stack_depth), + pp_formatted_text (&pp))); } } @@ -2438,18 +2427,48 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb, { case SUPEREDGE_CFG_EDGE: { + if (auto eh_dispatch_try_sedge + = eedge.m_sedge->dyn_cast_eh_dispatch_try_cfg_superedge ()) + { + if (eh_dispatch_try_sedge->get_eh_catch ()) + { + const region_model *model = src_node->get_state ().m_region_model; + auto curr_thrown_exception_node + = model->get_current_thrown_exception (); + gcc_assert (curr_thrown_exception_node); + tree type = curr_thrown_exception_node->maybe_get_type (); + emission_path->add_event + (std::make_unique<catch_cfg_edge_event> + (eedge, + event_loc_info (dst_point.get_supernode ()->get_start_location (), + dst_point.get_fndecl (), + dst_stack_depth), + type)); + return; + } + else + { + /* We have the "uncaught exception" sedge, from eh_dispatch + to a block containing resx. + Don't add any events for this, so that we can consolidate + adjacent stack unwinding events. */ + return; + } + } + emission_path->add_event - (make_unique<start_cfg_edge_event> - (eedge, - event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION, - src_point.get_fndecl (), - src_stack_depth))); + (std::make_unique<start_cfg_edge_event> + (eedge, + event_loc_info + (last_stmt ? last_stmt->location : UNKNOWN_LOCATION, + src_point.get_fndecl (), + src_stack_depth))); emission_path->add_event - (make_unique<end_cfg_edge_event> - (eedge, - event_loc_info (dst_point.get_supernode ()->get_start_location (), - dst_point.get_fndecl (), - dst_stack_depth))); + (std::make_unique<end_cfg_edge_event> + (eedge, + event_loc_info (dst_point.get_supernode ()->get_start_location (), + dst_point.get_fndecl (), + dst_stack_depth))); } break; @@ -2462,12 +2481,13 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb, /* TODO: add a subclass for this, or generate events for the summary. */ emission_path->add_event - (make_unique<debug_event> (event_loc_info (last_stmt - ? last_stmt->location - : UNKNOWN_LOCATION, - src_point.get_fndecl (), - src_stack_depth), - "call summary")); + (std::make_unique<debug_event> + (event_loc_info (last_stmt + ? last_stmt->location + : UNKNOWN_LOCATION, + src_point.get_fndecl (), + src_stack_depth), + "call summary")); } break; @@ -2476,14 +2496,13 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb, const return_superedge *return_edge = as_a <const return_superedge *> (eedge.m_sedge); - const gcall *call_stmt = return_edge->get_call_stmt (); + const gcall &call_stmt = return_edge->get_call_stmt (); emission_path->add_event - (make_unique<return_event> (eedge, - event_loc_info (call_stmt - ? call_stmt->location - : UNKNOWN_LOCATION, - dst_point.get_fndecl (), - dst_stack_depth))); + (std::make_unique<return_event> + (eedge, + event_loc_info (call_stmt.location, + dst_point.get_fndecl (), + dst_stack_depth))); } break; } @@ -2512,6 +2531,7 @@ diagnostic_manager::prune_path (checker_path *path, if (! flag_analyzer_show_events_in_system_headers) prune_system_headers (path); consolidate_conditions (path); + consolidate_unwind_events (path); finish_pruning (path); path->maybe_log (get_logger (), "pruned"); } @@ -2586,7 +2606,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, default: gcc_unreachable (); - case EK_DEBUG: + case event_kind::debug: if (m_verbosity < 4) { log ("filtering event %i: debug event", idx); @@ -2594,11 +2614,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, } break; - case EK_CUSTOM: + case event_kind::custom: /* Don't filter custom events. */ break; - case EK_STMT: + case event_kind::stmt: { if (m_verbosity < 4) { @@ -2608,11 +2628,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, } break; - case EK_REGION_CREATION: + case event_kind::region_creation: /* Don't filter these. */ break; - case EK_FUNCTION_ENTRY: + case event_kind::function_entry: if (m_verbosity < 1) { log ("filtering event %i: function entry", idx); @@ -2620,7 +2640,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, } break; - case EK_STATE_CHANGE: + case event_kind::state_change: { state_change_event *state_change = (state_change_event *)base_event; gcc_assert (state_change->m_dst_state.m_region_model); @@ -2674,7 +2694,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, } break; - case EK_START_CFG_EDGE: + case event_kind::start_cfg_edge: { cfg_edge_event *event = (cfg_edge_event *)base_event; @@ -2687,20 +2707,26 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, { log ("filtering events %i and %i: CFG edge", idx, idx + 1); path->delete_event (idx); - /* Also delete the corresponding EK_END_CFG_EDGE. */ + /* Also delete the corresponding event_kind::end_cfg_edge. */ gcc_assert (path->get_checker_event (idx)->m_kind - == EK_END_CFG_EDGE); + == event_kind::end_cfg_edge); path->delete_event (idx); } } break; - case EK_END_CFG_EDGE: - /* These come in pairs with EK_START_CFG_EDGE events and are + case event_kind::end_cfg_edge: + /* These come in pairs with event_kind::start_cfg_edge events and are filtered when their start event is filtered. */ break; - case EK_CALL_EDGE: + case event_kind::catch_: + case event_kind::throw_: + case event_kind::unwind: + /* Don't filter these. */ + break; + + case event_kind::call_edge: { call_event *event = (call_event *)base_event; const region_model *callee_model @@ -2741,7 +2767,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, } break; - case EK_RETURN_EDGE: + case event_kind::return_edge: { if (sval) { @@ -2785,19 +2811,19 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, } break; - case EK_INLINED_CALL: + case event_kind::inlined_call: /* We don't expect to see these yet, as they're added later. We'd want to keep them around. */ break; - case EK_SETJMP: + case event_kind::setjmp_: /* TODO: only show setjmp_events that matter i.e. those for which there is a later rewind event using them. */ - case EK_REWIND_FROM_LONGJMP: - case EK_REWIND_TO_SETJMP: + case event_kind::rewind_from_longjmp: + case event_kind::rewind_to_setjmp: break; - case EK_WARNING: + case event_kind::warning: /* Always show the final "warning" event in the path. */ break; } @@ -3073,7 +3099,7 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const continue; /* Are we looking for a run of all TRUE edges, or all FALSE edges? */ - gcc_assert (old_start_ev->m_kind == EK_START_CFG_EDGE); + gcc_assert (old_start_ev->m_kind == event_kind::start_cfg_edge); const start_cfg_edge_event *old_start_cfg_ev = (const start_cfg_edge_event *)old_start_ev; const cfg_superedge& first_cfg_sedge @@ -3096,7 +3122,7 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const { const checker_event *iter_ev = path->get_checker_event (next_idx); - gcc_assert (iter_ev->m_kind == EK_START_CFG_EDGE); + gcc_assert (iter_ev->m_kind == event_kind::start_cfg_edge); const start_cfg_edge_event *iter_cfg_ev = (const start_cfg_edge_event *)iter_ev; const cfg_superedge& iter_cfg_sedge @@ -3140,6 +3166,48 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const } } +/* Consolidate runs of consecutive unwind_event. */ + +void +diagnostic_manager::consolidate_unwind_events (checker_path *path) const +{ + /* Don't simplify edges if we're debugging them. */ + if (flag_analyzer_verbose_edges) + return; + + for (int start_idx = 0; + start_idx < (signed)path->num_events () - 1; + start_idx++) + { + /* Find a run of consecutive unwind_event instances. */ + if (path->get_checker_event (start_idx)->m_kind != event_kind::unwind) + continue; + int iter_idx = start_idx + 1; + while (iter_idx < (int)path->num_events ()) + if (path->get_checker_event (iter_idx)->m_kind == event_kind::unwind) + ++iter_idx; + else + break; + + /* iter_idx should now be one after the last unwind_event in the run. */ + const int last_idx = iter_idx - 1; + if (last_idx == start_idx) + continue; + + gcc_assert (last_idx > start_idx); + + log ("consolidating unwind events %i-%i into %i", + start_idx, last_idx, start_idx); + + unwind_event *first_event + = (unwind_event *)path->get_checker_event (start_idx); + const unwind_event *last_event + = (const unwind_event *)path->get_checker_event (last_idx); + first_event->m_num_frames += last_event->m_num_frames; + path->delete_events (start_idx + 1, last_idx - start_idx); + } +} + /* Final pass of diagnostic_manager::prune_path. If all we're left with is in one function, then filter function entry @@ -3154,7 +3222,7 @@ diagnostic_manager::finish_pruning (checker_path *path) const while (idx >= 0 && idx < (signed)path->num_events ()) { checker_event *base_event = path->get_checker_event (idx); - if (base_event->m_kind == EK_FUNCTION_ENTRY) + if (base_event->m_kind == event_kind::function_entry) { log ("filtering event %i:" " function entry for purely intraprocedural path", idx); diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h index 06a8233..b62fc7a 100644 --- a/gcc/analyzer/diagnostic-manager.h +++ b/gcc/analyzer/diagnostic-manager.h @@ -229,6 +229,7 @@ private: void prune_interproc_events (checker_path *path) const; void prune_system_headers (checker_path *path) const; void consolidate_conditions (checker_path *path) const; + void consolidate_unwind_events (checker_path *path) const; void finish_pruning (checker_path *path) const; engine *m_eng; diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 71d7ed7..c3e4800 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -18,23 +18,27 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "fold-const.h" +#include "analyzer/common.h" + +#include <zlib.h> + +#include "cfg.h" +#include "basic-block.h" #include "gcc-rich-location.h" -#include "diagnostic-core.h" -#include "diagnostic-event-id.h" -#include "diagnostic-path.h" -#include "function.h" -#include "pretty-print.h" -#include "sbitmap.h" -#include "bitmap.h" -#include "ordered-hash-map.h" -#include "analyzer/analyzer.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimple-pretty-print.h" +#include "cgraph.h" +#include "fold-const.h" +#include "digraph.h" +#include "plugin.h" +#include "target.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-dfa.h" + +#include "text-art/dump.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" @@ -44,13 +48,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "gimple-pretty-print.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" @@ -59,16 +56,8 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/state-purge.h" #include "analyzer/bar-chart.h" #include "analyzer/call-info.h" -#include <zlib.h> -#include "plugin.h" -#include "target.h" -#include <memory> -#include "stringpool.h" -#include "attribs.h" -#include "tree-dfa.h" #include "analyzer/known-function-manager.h" #include "analyzer/call-summary.h" -#include "text-art/dump.h" /* For an overview, see gcc/doc/analyzer.texi. */ @@ -322,11 +311,11 @@ public: logger *get_logger () const { return m_logger.get_logger (); } - tree get_fndecl_for_call (const gcall *call) final override + tree get_fndecl_for_call (const gcall &call) final override { impl_region_model_context old_ctxt (m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/, - NULL, call); + NULL, &call); region_model *model = m_new_state->m_region_model; return model->get_fndecl_for_call (call, &old_ctxt); } @@ -583,17 +572,17 @@ get_state_map_by_name (const char *name, { const sm_state_map *old_smap = m_old_state->m_checker_states[sm_idx]; *out_sm_context - = make_unique<impl_sm_context> (*m_eg, - sm_idx, - *sm, - m_enode_for_diag, - m_old_state, - m_new_state, - old_smap, - new_smap, - m_path_ctxt, - m_stmt_finder, - false); + = std::make_unique<impl_sm_context> (*m_eg, + sm_idx, + *sm, + m_enode_for_diag, + m_old_state, + m_new_state, + old_smap, + new_smap, + m_path_ctxt, + m_stmt_finder, + false); } return true; } @@ -609,7 +598,7 @@ public: std::unique_ptr<stmt_finder> clone () const final override { - return make_unique<leak_stmt_finder> (m_eg, m_var); + return std::make_unique<leak_stmt_finder> (m_eg, m_var); } const gimple *find_stmt (const exploded_path &epath) @@ -1207,10 +1196,10 @@ exploded_node::status_to_str (enum status s) switch (s) { default: gcc_unreachable (); - case STATUS_WORKLIST: return "WORKLIST"; - case STATUS_PROCESSED: return "PROCESSED"; - case STATUS_MERGER: return "MERGER"; - case STATUS_BULK_MERGED: return "BULK_MERGED"; + case status::worklist: return "worklist"; + case status::processed: return "processed"; + case status::merger: return "merger"; + case status::bulk_merged: return "bulk_merged"; } } @@ -1218,7 +1207,7 @@ exploded_node::status_to_str (enum status s) exploded_node::exploded_node (const point_and_state &ps, int index) -: m_ps (ps), m_status (STATUS_WORKLIST), m_index (index), +: m_ps (ps), m_status (status::worklist), m_index (index), m_num_processed_stmts (0) { gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ()); @@ -1296,9 +1285,9 @@ exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const pp_write_text_to_stream (pp); pp_printf (pp, "EN: %i", m_index); - if (m_status == STATUS_MERGER) + if (m_status == status::merger) pp_string (pp, " (merger)"); - else if (m_status == STATUS_BULK_MERGED) + else if (m_status == status::bulk_merged) pp_string (pp, " (bulk merged)"); pp_newline (pp); @@ -1440,7 +1429,7 @@ exploded_node::dump (const extrinsic_state &ext_state) const std::unique_ptr<json::object> exploded_node::to_json (const extrinsic_state &ext_state) const { - auto enode_obj = ::make_unique<json::object> (); + auto enode_obj = std::make_unique<json::object> (); enode_obj->set ("point", get_point ().to_json ()); enode_obj->set ("state", get_state ().to_json (ext_state)); @@ -1522,7 +1511,7 @@ exploded_node::on_stmt (exploded_graph &eg, gcc_assert (called_fn); return replay_call_summaries (eg, snode, - as_a <const gcall *> (stmt), + *as_a <const gcall *> (stmt), state, path_ctxt, *called_fn, @@ -1579,8 +1568,9 @@ exploded_node::on_stmt_pre (exploded_graph &eg, region_model_context *ctxt) { /* Handle special-case calls that require the full program_state. */ - if (const gcall *call = dyn_cast <const gcall *> (stmt)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) { + const gcall &call = *call_stmt; if (is_special_named_call_p (call, "__analyzer_dump", 0)) { /* Handle the builtin "__analyzer_dump" by dumping state @@ -1609,6 +1599,24 @@ exploded_node::on_stmt_pre (exploded_graph &eg, ctxt->maybe_did_work (); return; } + else if (is_cxa_throw_p (call)) + { + on_throw (eg, call, state, false, ctxt); + *out_terminate_path = true; + return; + } + else if (is_cxa_rethrow_p (call)) + { + on_throw (eg, call, state, true, ctxt); + *out_terminate_path = true; + return; + } + } + else if (const gresx *resx = dyn_cast <const gresx *> (stmt)) + { + on_resx (eg, *resx, state, ctxt); + *out_terminate_path = true; + return; } /* Otherwise, defer to m_region_model. */ @@ -1626,7 +1634,7 @@ exploded_node::on_stmt_post (const gimple *stmt, region_model_context *ctxt) { if (const gcall *call = dyn_cast <const gcall *> (stmt)) - state->m_region_model->on_call_post (call, unknown_side_effects, ctxt); + state->m_region_model->on_call_post (*call, unknown_side_effects, ctxt); } /* A concrete call_info subclass representing a replay of a call summary. */ @@ -1636,7 +1644,7 @@ class call_summary_edge_info : public call_info public: call_summary_edge_info (const call_details &cd, const function &called_fn, - call_summary *summary, + call_summary &summary, const extrinsic_state &ext_state) : call_info (cd, called_fn), m_called_fn (called_fn), @@ -1651,7 +1659,7 @@ public: /* Update STATE based on summary_end_state. */ call_details cd (get_call_details (state->m_region_model, ctxt)); call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state); - const program_state &summary_end_state = m_summary->get_state (); + const program_state &summary_end_state = m_summary.get_state (); return state->replay_call_summary (r, summary_end_state); } @@ -1662,19 +1670,19 @@ public: /* Update STATE based on summary_end_state. */ call_details cd (get_call_details (model, ctxt)); call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state); - const program_state &summary_end_state = m_summary->get_state (); + const program_state &summary_end_state = m_summary.get_state (); model->replay_call_summary (r, *summary_end_state.m_region_model); return true; } void print_desc (pretty_printer &pp) const final override { - pp_string (&pp, m_summary->get_desc ().get ()); + pp_string (&pp, m_summary.get_desc ().get ()); } private: const function &m_called_fn; - call_summary *m_summary; + call_summary &m_summary; const extrinsic_state &m_ext_state; }; @@ -1684,7 +1692,7 @@ private: exploded_node::on_stmt_flags exploded_node::replay_call_summaries (exploded_graph &eg, const supernode *snode, - const gcall *call_stmt, + const gcall &call_stmt, program_state *state, path_context *path_ctxt, const function &called_fn, @@ -1696,8 +1704,11 @@ exploded_node::replay_call_summaries (exploded_graph &eg, /* Each summary will call bifurcate on the PATH_CTXT. */ for (auto summary : called_fn_data.m_summaries) - replay_call_summary (eg, snode, call_stmt, state, - path_ctxt, called_fn, summary, ctxt); + { + gcc_assert (summary); + replay_call_summary (eg, snode, call_stmt, state, + path_ctxt, called_fn, *summary, ctxt); + } path_ctxt->terminate_path (); return on_stmt_flags (); @@ -1710,27 +1721,25 @@ exploded_node::replay_call_summaries (exploded_graph &eg, void exploded_node::replay_call_summary (exploded_graph &eg, const supernode *snode, - const gcall *call_stmt, + const gcall &call_stmt, program_state *old_state, path_context *path_ctxt, const function &called_fn, - call_summary *summary, + call_summary &summary, region_model_context *ctxt) { logger *logger = eg.get_logger (); LOG_SCOPE (logger); gcc_assert (snode); - gcc_assert (call_stmt); gcc_assert (old_state); - gcc_assert (summary); if (logger) logger->log ("using %s as summary for call to %qE from %qE", - summary->get_desc ().get (), + summary.get_desc ().get (), called_fn.decl, snode->get_function ()->decl); const extrinsic_state &ext_state = eg.get_ext_state (); - const program_state &summary_end_state = summary->get_state (); + const program_state &summary_end_state = summary.get_state (); if (logger) { pretty_printer *pp = logger->get_printer (); @@ -1752,10 +1761,11 @@ exploded_node::replay_call_summary (exploded_graph &eg, call_summary_replay r (cd, called_fn, summary, ext_state); if (path_ctxt) - path_ctxt->bifurcate (make_unique<call_summary_edge_info> (cd, - called_fn, - summary, - ext_state)); + path_ctxt->bifurcate + (std::make_unique<call_summary_edge_info> (cd, + called_fn, + summary, + ext_state)); } @@ -1826,7 +1836,7 @@ valid_longjmp_stack_p (const program_point &longjmp_point, class stale_jmp_buf : public pending_diagnostic_subclass<stale_jmp_buf> { public: - stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call, + stale_jmp_buf (const gcall &setjmp_call, const gcall &longjmp_call, const program_point &setjmp_point) : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call), m_setjmp_point (setjmp_point), m_stack_pop_event (NULL) @@ -1849,8 +1859,8 @@ public: bool operator== (const stale_jmp_buf &other) const { - return (m_setjmp_call == other.m_setjmp_call - && m_longjmp_call == other.m_longjmp_call); + return (&m_setjmp_call == &other.m_setjmp_call + && &m_longjmp_call == &other.m_longjmp_call); } bool @@ -1903,8 +1913,8 @@ public: private: - const gcall *m_setjmp_call; - const gcall *m_longjmp_call; + const gcall &m_setjmp_call; + const gcall &m_longjmp_call; program_point m_setjmp_point; custom_event *m_stack_pop_event; }; @@ -1917,11 +1927,11 @@ private: void exploded_node::on_longjmp (exploded_graph &eg, - const gcall *longjmp_call, + const gcall &longjmp_call, program_state *new_state, region_model_context *ctxt) { - tree buf_ptr = gimple_call_arg (longjmp_call, 0); + tree buf_ptr = gimple_call_arg (&longjmp_call, 0); gcc_assert (POINTER_TYPE_P (TREE_TYPE (buf_ptr))); region_model *new_region_model = new_state->m_region_model; @@ -1942,7 +1952,7 @@ exploded_node::on_longjmp (exploded_graph &eg, call back to the setjmp/sigsetjmp. */ rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call); - const gcall *setjmp_call = rewind_info.get_setjmp_call (); + const gcall &setjmp_call = rewind_info.get_setjmp_call (); const program_point &setjmp_point = rewind_info.get_setjmp_point (); const program_point &longjmp_point = get_point (); @@ -1950,9 +1960,9 @@ exploded_node::on_longjmp (exploded_graph &eg, /* Verify that the setjmp's call_stack hasn't been popped. */ if (!valid_longjmp_stack_p (longjmp_point, setjmp_point)) { - ctxt->warn (make_unique<stale_jmp_buf> (setjmp_call, - longjmp_call, - setjmp_point)); + ctxt->warn (std::make_unique<stale_jmp_buf> (setjmp_call, + longjmp_call, + setjmp_point)); return; } @@ -1986,8 +1996,8 @@ exploded_node::on_longjmp (exploded_graph &eg, { exploded_edge *eedge = eg.add_edge (const_cast<exploded_node *> (this), next, NULL, true, - make_unique<rewind_info_t> (tmp_setjmp_record, - longjmp_call)); + std::make_unique<rewind_info_t> (tmp_setjmp_record, + longjmp_call)); /* For any diagnostics that were queued here (such as leaks) we want the checker_path to show the rewinding events after the "final event" @@ -2025,6 +2035,332 @@ exploded_node::on_longjmp (exploded_graph &eg, } } +/* Subclass of call_info for exploded edges that express + a throw or rethrow of an exception (actually a call + to __cxa_throw or __cxa_rethrow). */ + +class throw_custom_edge : public call_info +{ +public: + throw_custom_edge (const call_details &cd, + tree type, + bool is_rethrow) + : call_info (cd), + m_type (type), + m_is_rethrow (is_rethrow) + { + } + + void print (pretty_printer *pp) const final override + { + if (m_is_rethrow) + { + if (m_type) + pp_printf (pp, "rethrowing %qT", m_type); + else + pp_printf (pp, "rethrowing"); + } + else + { + if (m_type) + pp_printf (pp, "throwing %qT", m_type); + else + pp_printf (pp, "throwing"); + } + } + + void print_desc (pretty_printer &pp) const final override + { + print (&pp); + } + + bool update_model (region_model *model, + const exploded_edge *, + region_model_context *ctxt) const final override + { + if (m_is_rethrow) + { + auto eh_node = model->get_current_caught_exception (); + gcc_assert (eh_node); + model->push_thrown_exception (*eh_node); + } + else + { + call_details cd (get_call_details (model, ctxt)); + + const svalue *exception_sval = cd.get_arg_svalue (0); + const svalue *tinfo_sval = cd.get_arg_svalue (1); + const svalue *destructor_sval = cd.get_arg_svalue (2); + + /* Push a new exception_node on the model's m_exception_stack. */ + exception_node eh_node (exception_sval, tinfo_sval, destructor_sval); + model->push_thrown_exception (eh_node); + } + + return true; + } + + void add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) const final override + { + const exploded_node *dst_node = eedge.m_dest; + const program_point &dst_point = dst_node->get_point (); + const int dst_stack_depth = dst_point.get_stack_depth (); + + const gcall &call = get_call_stmt (); + + emission_path->add_event + (std::make_unique<explicit_throw_event> + (event_loc_info (call.location, + dst_point.get_fndecl (), + dst_stack_depth), + dst_node, + call, + m_type, + m_is_rethrow)); + } + +private: + tree m_type; + bool m_is_rethrow; +}; + +/* Subclass of custom_edge_info for an exploded edge that expresses + unwinding one stack frame during exception handling. */ + +class unwind_custom_edge : public custom_edge_info +{ +public: + unwind_custom_edge (location_t loc) + : m_loc (loc) + { + } + + void print (pretty_printer *pp) const final override + { + pp_printf (pp, "unwinding frame"); + } + + bool update_model (region_model *model, + const exploded_edge *, + region_model_context *ctxt) const final override + { + model->pop_frame (NULL_TREE, nullptr, ctxt, nullptr, false); + return true; + } + + void add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) const final override + { + const exploded_node *src_node = eedge.m_src; + const program_point &src_point = src_node->get_point (); + const int src_stack_depth = src_point.get_stack_depth (); + emission_path->add_event + (std::make_unique<unwind_event> (event_loc_info (m_loc, + src_point.get_fndecl (), + src_stack_depth))); + } + +private: + location_t m_loc; +}; + +/* Locate an SNODE that's a CFG edge with the EH flag, + or return nullptr. */ + +static const superedge * +get_eh_outedge (const supernode &snode) +{ + for (auto out_sedge : snode.m_succs) + if (::edge cfg_edge = out_sedge->get_any_cfg_edge ()) + if (cfg_edge->flags & EDGE_EH) + return out_sedge; + + // Not found + return nullptr; +} + +/* Given THROWN_ENODE, which expreses a throw or rethrow occurring at + THROW_STMT, unwind intraprocedurally and interprocedurally to find + the next eh_dispatch statement to handle exceptions, if any. + + Add eedges and enodes to this graph expressing the actions taken + to reach an enode containing the eh_dispatch stmt, if any. + Only the final enode is added to this graph's worklist. + + Use CTXT to warn about problems e.g. memory leaks due to stack frames + being unwound. */ + +void +exploded_graph::unwind_from_exception (exploded_node &thrown_enode, + const gimple *throw_stmt, + region_model_context *ctxt) +{ + logger * const logger = get_logger (); + LOG_FUNC_1 (logger, "thrown EN: %i", thrown_enode.m_index); + + /* Iteratively unwind the stack looking for an out-cfg-edge + flagged EH. */ + exploded_node *iter_enode = &thrown_enode; + while (iter_enode) + { + /* If we have an out-cfg-edge flagged EH, follow that, + presumably to a bb with a label and an eh_dispatch stmt. + Otherwise assume no out-cfgs-edges, and we are unwinding to the + caller. */ + if (auto sedge = get_eh_outedge (*iter_enode->get_supernode ())) + { + /* Intraprocedural case. + Assume we have an out-edge flagged with EH leading to + code for dispatch to catch handlers. */ + const program_point next_point + = program_point::before_supernode (sedge->m_dest, + sedge, + iter_enode->get_point ().get_call_string ()); + exploded_node *next_enode + = get_or_create_node (next_point, + iter_enode->get_state (), + iter_enode, + /* Add this enode to the worklist. */ + true); + if (!next_enode) + return; + + add_edge (iter_enode, next_enode, NULL, false, nullptr); + return; + } + else + { + /* Interprocedural case. + No out-cfg-edge. Unwind one stack frame. */ + program_state unwound_state (iter_enode->get_state ()); + location_t loc = throw_stmt ? throw_stmt->location : UNKNOWN_LOCATION; + auto unwind_edge_info + = std::make_unique<unwind_custom_edge> (loc); + unwind_edge_info->update_model (unwound_state.m_region_model, nullptr, + ctxt); + + /* Detect leaks in the new state relative to the old state. + Use an alternate ctxt that uses the original enode and the stmt + (if any) for the location of any diagnostics. */ + { + uncertainty_t uncertainty; + impl_region_model_context ctxt (*this, + &thrown_enode, + &iter_enode->get_state (), + &unwound_state, + &uncertainty, + nullptr, + throw_stmt); + program_state::detect_leaks (iter_enode->get_state (), + unwound_state, + NULL, + get_ext_state (), &ctxt); + } + const call_string &cs = iter_enode->get_point ().get_call_string (); + if (cs.empty_p ()) + { + /* Top-level stack frame in analysis: unwinding + to the outside world that called us. */ + return; + } + else + { + /* Nested function in analysis: unwinding to + the callsite in the analysis (or beyond). */ + program_point unwound_point + = program_point::after_supernode (cs.get_caller_node (), cs); + unwound_point.pop_from_call_stack (); + + exploded_node *after_unwind_enode + = get_or_create_node (unwound_point, + std::move (unwound_state), + iter_enode, + /* Don't add this enode to the + worklist; we will process it + on the next iteration. */ + false); + + if (!after_unwind_enode) + return; + + add_edge (iter_enode, after_unwind_enode, NULL, true, + std::move (unwind_edge_info)); + iter_enode = after_unwind_enode; + } + } + } +} + +/* Handle THROW_CALL, a call to __cxa_throw or __cxa_rethrow. + + Create an eedge and destination enode for the throw/rethrow, adding + them to this egraph. The new enode isn't added to the worklist, but + instead exploded_graph::unwind_from_exception is immediately called + on it, potentially creating more eedges and enodes leading to an + eh_handler stmt. */ + +void +exploded_node::on_throw (exploded_graph &eg, + const gcall &throw_call, + program_state *new_state, + bool is_rethrow, + region_model_context *ctxt) +{ + region_model *model = new_state->m_region_model; + call_details cd (throw_call, model, ctxt); + + /* Create an enode and eedge for the "throw". */ + tree type = NULL_TREE; + if (is_rethrow) + { + const exception_node *eh_node = model->get_current_caught_exception (); + gcc_assert (eh_node); + type = eh_node->maybe_get_type (); + } + else + { + const svalue *tinfo_sval = cd.get_arg_svalue (1); + type = tinfo_sval->maybe_get_type_from_typeinfo (); + } + auto throw_edge_info + = std::make_unique<throw_custom_edge> (cd, type, is_rethrow); + throw_edge_info->update_model (model, nullptr, ctxt); + + program_point after_throw_point = get_point ().get_next (); + + exploded_node *after_throw_enode + = eg.get_or_create_node (after_throw_point, *new_state, this, + /* Don't add to worklist; we process + this immediately below. */ + false); + + if (!after_throw_enode) + return; + + /* Create custom exploded_edge for a throw. */ + eg.add_edge (this, after_throw_enode, NULL, true, + std::move (throw_edge_info)); + + eg.unwind_from_exception (*after_throw_enode, &throw_call, ctxt); +} + +/* Handle a gimple "resx" statement by adding eedges and enode. + that unwind to the next eh_dispatch statement, if any. Only + the final enode is added to the worklist. */ + +void +exploded_node::on_resx (exploded_graph &eg, + const gresx &/*resx*/, + program_state */*new_state*/, + region_model_context *ctxt) +{ + eg.unwind_from_exception (*this, + nullptr, + ctxt); +} + + /* Subroutine of exploded_graph::process_node for finding the successors of the supernode for a function exit basic block. @@ -2131,20 +2467,16 @@ dynamic_call_info_t::add_events_to_path (checker_path *emission_path, if (m_is_returning_call) emission_path->add_event - (make_unique<return_event> (eedge, - event_loc_info (m_dynamic_call - ? m_dynamic_call->location - : UNKNOWN_LOCATION, - dest_point.get_fndecl (), - dest_stack_depth))); + (std::make_unique<return_event> (eedge, + event_loc_info (m_dynamic_call.location, + dest_point.get_fndecl (), + dest_stack_depth))); else emission_path->add_event - (make_unique<call_event> (eedge, - event_loc_info (m_dynamic_call - ? m_dynamic_call->location - : UNKNOWN_LOCATION, - src_point.get_fndecl (), - src_stack_depth))); + (std::make_unique<call_event> (eedge, + event_loc_info (m_dynamic_call.location, + src_point.get_fndecl (), + src_stack_depth))); } /* class rewind_info_t : public custom_edge_info. */ @@ -2189,19 +2521,19 @@ rewind_info_t::add_events_to_path (checker_path *emission_path, const int dst_stack_depth = dst_point.get_stack_depth (); emission_path->add_event - (make_unique<rewind_from_longjmp_event> - (&eedge, - event_loc_info (get_longjmp_call ()->location, - src_point.get_fndecl (), - src_stack_depth), - this)); + (std::make_unique<rewind_from_longjmp_event> + (&eedge, + event_loc_info (get_longjmp_call ().location, + src_point.get_fndecl (), + src_stack_depth), + this)); emission_path->add_event - (make_unique<rewind_to_setjmp_event> - (&eedge, - event_loc_info (get_setjmp_call ()->location, - dst_point.get_fndecl (), - dst_stack_depth), - this)); + (std::make_unique<rewind_to_setjmp_event> + (&eedge, + event_loc_info (get_setjmp_call ().location, + dst_point.get_fndecl (), + dst_stack_depth), + this)); } /* class exploded_edge : public dedge<eg_traits>. */ @@ -2294,7 +2626,7 @@ exploded_edge::dump_dot_label (pretty_printer *pp) const std::unique_ptr<json::object> exploded_edge::to_json () const { - auto eedge_obj = ::make_unique<json::object> (); + auto eedge_obj = std::make_unique<json::object> (); eedge_obj->set_integer ("src_idx", m_src->m_index); eedge_obj->set_integer ("dst_idx", m_dest->m_index); if (m_sedge) @@ -2420,9 +2752,9 @@ strongly_connected_components::dump () const std::unique_ptr<json::array> strongly_connected_components::to_json () const { - auto scc_arr = ::make_unique<json::array> (); + auto scc_arr = std::make_unique<json::array> (); for (int i = 0; i < m_sg.num_nodes (); i++) - scc_arr->append (::make_unique<json::integer_number> (get_scc_id (i))); + scc_arr->append (std::make_unique<json::integer_number> (get_scc_id (i))); return scc_arr; } @@ -2518,7 +2850,7 @@ worklist::peek_next () void worklist::add_node (exploded_node *enode) { - gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST); + gcc_assert (enode->get_status () == exploded_node::status::worklist); m_queue.insert (key_t (*this, enode), enode); } @@ -2641,7 +2973,7 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb) std::unique_ptr<json::object> worklist::to_json () const { - auto worklist_obj = ::make_unique<json::object> (); + auto worklist_obj = std::make_unique<json::object> (); worklist_obj->set ("scc", m_scc.to_json ()); @@ -2791,8 +3123,8 @@ public: const exploded_edge &) const final override { emission_path->add_event - (make_unique<tainted_args_function_custom_event> - (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0))); + (std::make_unique<tainted_args_function_custom_event> + (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0))); } private: @@ -2833,7 +3165,7 @@ exploded_graph::add_function_entry (const function &fun) if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl))) { if (mark_params_as_tainted (&state, fun.decl, m_ext_state)) - edge_info = make_unique<tainted_args_function_info> (fun.decl); + edge_info = std::make_unique<tainted_args_function_info> (fun.decl); } if (!state.m_valid) @@ -2851,7 +3183,8 @@ exploded_graph::add_function_entry (const function &fun) } /* Get or create an exploded_node for (POINT, STATE). - If a new node is created, it is added to the worklist. + If a new node is created and ADD_TO_WORKLIST is true, + it is added to the worklist. Use ENODE_FOR_DIAG, a pre-existing enode, for any diagnostics that need to be emitted (e.g. when purging state *before* we have @@ -2860,7 +3193,8 @@ exploded_graph::add_function_entry (const function &fun) exploded_node * exploded_graph::get_or_create_node (const program_point &point, const program_state &state, - exploded_node *enode_for_diag) + exploded_node *enode_for_diag, + bool add_to_worklist) { logger * const logger = get_logger (); LOG_FUNC (logger); @@ -3035,7 +3369,10 @@ exploded_graph::get_or_create_node (const program_point &point, } /* Add the new node to the worlist. */ - m_worklist.add_node (node); + if (add_to_worklist) + m_worklist.add_node (node); + else + node->set_status (exploded_node::status::special); return node; } @@ -3238,16 +3575,16 @@ public: /* Show the field in the struct declaration, e.g. "(1) field 'store' is marked with '__attribute__((tainted_args))'" */ emission_path->add_event - (make_unique<tainted_args_field_custom_event> (m_field)); + (std::make_unique<tainted_args_field_custom_event> (m_field)); /* Show the callback in the initializer e.g. "(2) function 'gadget_dev_desc_UDC_store' used as initializer for field 'store' marked with '__attribute__((tainted_args))'". */ emission_path->add_event - (make_unique<tainted_args_callback_custom_event> - (event_loc_info (m_loc, m_fndecl, 0), - m_field)); + (std::make_unique<tainted_args_callback_custom_event> + (event_loc_info (m_loc, m_fndecl, 0), + m_field)); } private: @@ -3304,7 +3641,7 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl, } eg->add_edge (eg->get_origin (), enode, NULL, false, - make_unique<tainted_args_call_info> (field, fndecl, loc)); + std::make_unique<tainted_args_call_info> (field, fndecl, loc)); } /* Callback for walk_tree for finding callbacks within initializers; @@ -3397,7 +3734,7 @@ exploded_graph::process_worklist () while (m_worklist.length () > 0) { exploded_node *node = m_worklist.take_next (); - gcc_assert (node->get_status () == exploded_node::STATUS_WORKLIST); + gcc_assert (node->get_status () == exploded_node::status::worklist); gcc_assert (node->m_succs.length () == 0 || node == m_origin); @@ -3417,7 +3754,7 @@ exploded_graph::process_worklist () if (exploded_node *node_2 = m_worklist.peek_next ()) { gcc_assert (node_2->get_status () - == exploded_node::STATUS_WORKLIST); + == exploded_node::status::worklist); gcc_assert (node->m_succs.length () == 0); gcc_assert (node_2->m_succs.length () == 0); @@ -3462,7 +3799,7 @@ exploded_graph::process_worklist () /* Remove node_2 from the worklist. */ m_worklist.take_next (); - node_2->set_status (exploded_node::STATUS_MERGER); + node_2->set_status (exploded_node::status::merger); /* Continue processing "node" below. */ } @@ -3472,7 +3809,7 @@ exploded_graph::process_worklist () in the worklist, to be processed on the next iteration. */ add_edge (node, node_2, NULL, false); - node->set_status (exploded_node::STATUS_MERGER); + node->set_status (exploded_node::status::merger); continue; } else @@ -3517,7 +3854,7 @@ exploded_graph::process_worklist () else { add_edge (node, merged_enode, NULL, false); - node->set_status (exploded_node::STATUS_MERGER); + node->set_status (exploded_node::status::merger); } if (merged_enode == node_2) @@ -3525,7 +3862,7 @@ exploded_graph::process_worklist () else { add_edge (node_2, merged_enode, NULL, false); - node_2->set_status (exploded_node::STATUS_MERGER); + node_2->set_status (exploded_node::status::merger); } continue; @@ -3575,7 +3912,7 @@ exploded_graph::process_worklist () If ENODE's point is of the form (before-supernode, SNODE) and the next nodes in the worklist are a consecutive run of enodes of the same form, for the same supernode as ENODE (but potentially from different in-edges), - process them all together, setting their status to STATUS_BULK_MERGED, + process them all together, setting their status to status::bulk_merged, and return true. Otherwise, return false, in which case ENODE must be processed in the normal way. @@ -3614,7 +3951,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) int m_merger_idx; }; - gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST); + gcc_assert (enode->get_status () == exploded_node::status::worklist); gcc_assert (enode->m_succs.length () == 0); const program_point &point = enode->get_point (); @@ -3634,7 +3971,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) while (exploded_node *enode_2 = m_worklist.peek_next ()) { gcc_assert (enode_2->get_status () - == exploded_node::STATUS_WORKLIST); + == exploded_node::status::worklist); gcc_assert (enode_2->m_succs.length () == 0); const program_point &point_2 = enode_2->get_point (); @@ -3761,7 +4098,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) if (next) add_edge (it->m_input_enode, next, NULL, false); /* no "work" is done during merger. */ - it->m_input_enode->set_status (exploded_node::STATUS_BULK_MERGED); + it->m_input_enode->set_status (exploded_node::status::bulk_merged); } if (logger) @@ -3779,8 +4116,9 @@ static bool stmt_requires_new_enode_p (const gimple *stmt, const gimple *prev_stmt) { - if (const gcall *call = dyn_cast <const gcall *> (stmt)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) { + const gcall &call = *call_stmt; /* Stop consolidating at calls to "__analyzer_dump_exploded_nodes", so they always appear at the start of an exploded_node. */ @@ -3849,7 +4187,7 @@ state_change_requires_new_enode_p (const program_state &old_state, functions or calls that happen via function pointer. */ bool -exploded_graph::maybe_create_dynamic_call (const gcall *call, +exploded_graph::maybe_create_dynamic_call (const gcall &call, tree fn_decl, exploded_node *node, program_state next_state, @@ -3904,7 +4242,7 @@ exploded_graph::maybe_create_dynamic_call (const gcall *call, if (enode) add_edge (node,enode, NULL, false, /* No work is done by the call itself. */ - make_unique<dynamic_call_info_t> (call)); + std::make_unique<dynamic_call_info_t> (call)); return true; } } @@ -3992,7 +4330,7 @@ private: class jump_through_null : public pending_diagnostic_subclass<jump_through_null> { public: - jump_through_null (const gcall *call) + jump_through_null (const gcall &call) : m_call (call) {} @@ -4003,7 +4341,7 @@ public: bool operator== (const jump_through_null &other) const { - return m_call == other.m_call; + return &m_call == &other.m_call; } int get_controlling_option () const final override @@ -4024,7 +4362,7 @@ public: } private: - const gcall *m_call; + const gcall &m_call; }; /* The core of exploded_graph::process_worklist (the main analysis loop), @@ -4041,7 +4379,7 @@ exploded_graph::process_node (exploded_node *node) logger * const logger = get_logger (); LOG_FUNC_1 (logger, "EN: %i", node->m_index); - node->set_status (exploded_node::STATUS_PROCESSED); + node->set_status (exploded_node::status::processed); const program_point &point = node->get_point (); @@ -4269,12 +4607,18 @@ exploded_graph::process_node (exploded_node *node) NULL, /* no exploded_edge yet. */ &bifurcation_ctxt)) { - exploded_node *next2 - = get_or_create_node (next_point, bifurcated_new_state, node); - if (next2) - add_edge (node, next2, NULL, - true /* assume that work could be done */, - std::move (edge_info)); + if (exploded_node *next2 + = edge_info->create_enode + (*this, + next_point, + std::move (bifurcated_new_state), + node, + &bifurcation_ctxt)) + { + add_edge (node, next2, NULL, + true /* assume that work could be done */, + std::move (edge_info)); + } } else { @@ -4344,8 +4688,8 @@ exploded_graph::process_node (exploded_node *node) if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL && !(succ->get_any_callgraph_edge ())) { - const gcall *call - = point.get_supernode ()->get_final_call (); + const gcall &call + = *point.get_supernode ()->get_final_call (); impl_region_model_context ctxt (*this, node, @@ -4369,12 +4713,13 @@ exploded_graph::process_node (exploded_node *node) if (!call_discovered) { /* Check for jump through NULL. */ - if (tree fn_ptr = gimple_call_fn (call)) + if (tree fn_ptr = gimple_call_fn (&call)) { const svalue *fn_ptr_sval = model->get_rvalue (fn_ptr, &ctxt); if (fn_ptr_sval->all_zeroes_p ()) - ctxt.warn (make_unique<jump_through_null> (call)); + ctxt.warn + (std::make_unique<jump_through_null> (call)); } /* An unknown function or a special function was called @@ -4394,6 +4739,18 @@ exploded_graph::process_node (exploded_node *node) } } + /* Ignore CFG edges in the sgraph flagged with EH whilst + we're exploring the egraph. + We only use these sedges in special-case logic for + dealing with exception-handling. */ + if (auto cfg_sedge = succ->dyn_cast_cfg_superedge ()) + if (cfg_sedge->get_flags () & EDGE_EH) + { + if (logger) + logger->log ("rejecting EH edge"); + continue; + } + if (!node->on_edge (*this, succ, &next_point, &next_state, &uncertainty)) { @@ -4431,7 +4788,7 @@ exploded_graph::process_node (exploded_node *node) = next_point.get_supernode ()->get_returning_call (); if (call) - next_state.returning_call (*this, node, call, &uncertainty); + next_state.returning_call (*this, node, *call, &uncertainty); if (next_state.m_valid) { @@ -4441,7 +4798,7 @@ exploded_graph::process_node (exploded_node *node) node); if (enode) add_edge (node, enode, NULL, false, - make_unique<dynamic_call_info_t> (call, true)); + std::make_unique<dynamic_call_info_t> (*call, true)); } } } @@ -4660,11 +5017,11 @@ exploded_graph::dump_states_for_supernode (FILE *out, std::unique_ptr<json::object> exploded_graph::to_json () const { - auto egraph_obj = ::make_unique<json::object> (); + auto egraph_obj = std::make_unique<json::object> (); /* Nodes. */ { - auto nodes_arr = ::make_unique<json::array> (); + auto nodes_arr = std::make_unique<json::array> (); unsigned i; exploded_node *n; FOR_EACH_VEC_ELT (m_nodes, i, n) @@ -4674,7 +5031,7 @@ exploded_graph::to_json () const /* Edges. */ { - auto edges_arr = ::make_unique<json::array> (); + auto edges_arr = std::make_unique<json::array> (); unsigned i; exploded_edge *n; FOR_EACH_VEC_ELT (m_edges, i, n) @@ -4780,9 +5137,9 @@ exploded_path::feasible_p (logger *logger, const program_point &src_point = src_enode.get_point (); const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt (); - *out = ::make_unique<feasibility_problem> (edge_idx, *eedge, - last_stmt, - std::move (rc)); + *out = std::make_unique<feasibility_problem> (edge_idx, *eedge, + last_stmt, + std::move (rc)); } return false; } @@ -4986,7 +5343,7 @@ maybe_update_for_edge (logger *logger, == PK_BEFORE_SUPERNODE); function *fun = eedge->m_dest->get_function (); gcc_assert (fun); - m_model.push_frame (*fun, NULL, ctxt); + m_model.push_frame (*fun, nullptr, nullptr, ctxt); if (logger) logger->log (" pushing frame for %qD", fun->decl); } @@ -5037,8 +5394,8 @@ feasibility_state::update_for_stmt (const gimple *stmt) m_model.on_asm_stmt (asm_stmt, NULL); else if (const gcall *call = dyn_cast <const gcall *> (stmt)) { - bool unknown_side_effects = m_model.on_call_pre (call, NULL); - m_model.on_call_post (call, unknown_side_effects, NULL); + bool unknown_side_effects = m_model.on_call_pre (*call, NULL); + m_model.on_call_post (*call, unknown_side_effects, NULL); } else if (const greturn *return_ = dyn_cast <const greturn *> (stmt)) m_model.on_return (return_, NULL); @@ -5499,7 +5856,7 @@ exploded_graph::dump_exploded_nodes () const if (const gimple *stmt = enode->get_stmt ()) if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes", + if (is_special_named_call_p (*call, "__analyzer_dump_exploded_nodes", 1)) { if (seen.contains (stmt)) @@ -5520,13 +5877,13 @@ exploded_graph::dump_exploded_nodes () const { default: gcc_unreachable (); - case exploded_node::STATUS_WORKLIST: + case exploded_node::status::worklist: worklist_enodes.safe_push (other_enode); break; - case exploded_node::STATUS_PROCESSED: + case exploded_node::status::processed: processed_enodes.safe_push (other_enode); break; - case exploded_node::STATUS_MERGER: + case exploded_node::status::merger: merger_enodes.safe_push (other_enode); break; } @@ -6007,15 +6364,18 @@ private: { default: gcc_unreachable (); - case exploded_node::STATUS_WORKLIST: + case exploded_node::status::worklist: pp_string (pp, "(W)"); break; - case exploded_node::STATUS_PROCESSED: + case exploded_node::status::processed: + break; + case exploded_node::status::special: + pp_string (pp, "(S)"); break; - case exploded_node::STATUS_MERGER: + case exploded_node::status::merger: pp_string (pp, "(M)"); break; - case exploded_node::STATUS_BULK_MERGED: + case exploded_node::status::bulk_merged: pp_string (pp, "(BM)"); break; } @@ -6094,7 +6454,7 @@ dump_analyzer_json (const supergraph &sg, return; } - auto toplev_obj = ::make_unique<json::object> (); + auto toplev_obj = std::make_unique<json::object> (); toplev_obj->set ("sgraph", sg.to_json ()); toplev_obj->set ("egraph", eg.to_json ()); @@ -6115,8 +6475,8 @@ dump_analyzer_json (const supergraph &sg, class plugin_analyzer_init_impl : public plugin_analyzer_init_iface { public: - plugin_analyzer_init_impl (auto_delete_vec <state_machine> *checkers, - known_function_manager *known_fn_mgr, + plugin_analyzer_init_impl (std::vector<std::unique_ptr<state_machine>> &checkers, + known_function_manager &known_fn_mgr, logger *logger) : m_checkers (checkers), m_known_fn_mgr (known_fn_mgr), @@ -6126,14 +6486,14 @@ public: void register_state_machine (std::unique_ptr<state_machine> sm) final override { LOG_SCOPE (m_logger); - m_checkers->safe_push (sm.release ()); + m_checkers.push_back (std::move (sm)); } void register_known_function (const char *name, std::unique_ptr<known_function> kf) final override { LOG_SCOPE (m_logger); - m_known_fn_mgr->add (name, std::move (kf)); + m_known_fn_mgr.add (name, std::move (kf)); } logger *get_logger () const final override @@ -6142,8 +6502,8 @@ public: } private: - auto_delete_vec <state_machine> *m_checkers; - known_function_manager *m_known_fn_mgr; + std::vector<std::unique_ptr<state_machine>> &m_checkers; + known_function_manager &m_known_fn_mgr; logger *m_logger; }; @@ -6197,27 +6557,25 @@ impl_run_checkers (logger *logger) free (filename); } - auto_delete_vec <state_machine> checkers; - make_checkers (checkers, logger); + auto checkers = make_checkers (logger); register_known_functions (*eng.get_known_function_manager (), *eng.get_model_manager ()); - plugin_analyzer_init_impl data (&checkers, - eng.get_known_function_manager (), + plugin_analyzer_init_impl data (checkers, + *eng.get_known_function_manager (), logger); invoke_plugin_callbacks (PLUGIN_ANALYZER_INIT, &data); if (logger) { - int i; - state_machine *sm; - FOR_EACH_VEC_ELT (checkers, i, sm) - logger->log ("checkers[%i]: %s", i, sm->get_name ()); + int i = 0; + for (auto &sm : checkers) + logger->log ("checkers[%i]: %s", ++i, sm->get_name ()); } /* Extrinsic state shared by nodes in the graph. */ - const extrinsic_state ext_state (checkers, &eng, logger); + const extrinsic_state ext_state (std::move (checkers), &eng, logger); const analysis_plan plan (sg, logger); diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 6148ed7..32c72dc 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -206,20 +206,24 @@ class exploded_node : public dnode<eg_traits> This allows us to distinguish enodes that were merged during worklist-handling, and thus never had process_node called on them (in favor of processing the merged node). */ - enum status + enum class status { /* Node is in the worklist. */ - STATUS_WORKLIST, + worklist, /* Node has had exploded_graph::process_node called on it. */ - STATUS_PROCESSED, + processed, + + /* Node was excluded from worklist on creation. + e.g. for handling exception-unwinding. */ + special, /* Node was left unprocessed due to merger; it won't have had exploded_graph::process_node called on it. */ - STATUS_MERGER, + merger, /* Node was processed by maybe_process_run_of_before_supernode_enodes. */ - STATUS_BULK_MERGED + bulk_merged }; static const char * status_to_str (enum status s); @@ -282,7 +286,7 @@ class exploded_node : public dnode<eg_traits> on_stmt_flags replay_call_summaries (exploded_graph &eg, const supernode *snode, - const gcall *call_stmt, + const gcall &call_stmt, program_state *state, path_context *path_ctxt, const function &called_fn, @@ -290,11 +294,11 @@ class exploded_node : public dnode<eg_traits> region_model_context *ctxt); void replay_call_summary (exploded_graph &eg, const supernode *snode, - const gcall *call_stmt, + const gcall &call_stmt, program_state *state, path_context *path_ctxt, const function &called_fn, - call_summary *summary, + call_summary &summary, region_model_context *ctxt); bool on_edge (exploded_graph &eg, @@ -303,9 +307,18 @@ class exploded_node : public dnode<eg_traits> program_state *next_state, uncertainty_t *uncertainty); void on_longjmp (exploded_graph &eg, - const gcall *call, + const gcall &call, program_state *new_state, region_model_context *ctxt); + void on_throw (exploded_graph &eg, + const gcall &call, + program_state *new_state, + bool is_rethrow, + region_model_context *ctxt); + void on_resx (exploded_graph &eg, + const gresx &resx, + program_state *new_state, + region_model_context *ctxt); void detect_leaks (exploded_graph &eg); @@ -335,7 +348,7 @@ class exploded_node : public dnode<eg_traits> enum status get_status () const { return m_status; } void set_status (enum status status) { - gcc_assert (m_status == STATUS_WORKLIST); + gcc_assert (m_status == status::worklist); m_status = status; } @@ -424,7 +437,7 @@ private: class dynamic_call_info_t : public custom_edge_info { public: - dynamic_call_info_t (const gcall *dynamic_call, + dynamic_call_info_t (const gcall &dynamic_call, const bool is_returning_call = false) : m_dynamic_call (dynamic_call), m_is_returning_call (is_returning_call) @@ -445,7 +458,7 @@ public: void add_events_to_path (checker_path *emission_path, const exploded_edge &eedge) const final override; private: - const gcall *m_dynamic_call; + const gcall &m_dynamic_call; const bool m_is_returning_call; }; @@ -457,7 +470,7 @@ class rewind_info_t : public custom_edge_info { public: rewind_info_t (const setjmp_record &setjmp_record, - const gcall *longjmp_call) + const gcall &longjmp_call) : m_setjmp_record (setjmp_record), m_longjmp_call (longjmp_call) {} @@ -486,12 +499,12 @@ public: return origin_point; } - const gcall *get_setjmp_call () const + const gcall &get_setjmp_call () const { - return m_setjmp_record.m_setjmp_call; + return *m_setjmp_record.m_setjmp_call; } - const gcall *get_longjmp_call () const + const gcall &get_longjmp_call () const { return m_longjmp_call; } @@ -503,7 +516,7 @@ public: private: setjmp_record m_setjmp_record; - const gcall *m_longjmp_call; + const gcall &m_longjmp_call; }; /* Statistics about aspects of an exploded_graph. */ @@ -817,7 +830,7 @@ public: bool maybe_process_run_of_before_supernode_enodes (exploded_node *node); void process_node (exploded_node *node); - bool maybe_create_dynamic_call (const gcall *call, + bool maybe_create_dynamic_call (const gcall &call, tree fn_decl, exploded_node *node, program_state next_state, @@ -827,7 +840,8 @@ public: exploded_node *get_or_create_node (const program_point &point, const program_state &state, - exploded_node *enode_for_diag); + exploded_node *enode_for_diag, + bool add_to_worklist = true); exploded_edge *add_edge (exploded_node *src, exploded_node *dest, const superedge *sedge, bool could_do_work, std::unique_ptr<custom_edge_info> custom = NULL); @@ -881,6 +895,10 @@ public: void on_escaped_function (tree fndecl); + void unwind_from_exception (exploded_node &enode, + const gimple *stmt, + region_model_context *ctxt); + /* In infinite-loop.cc */ void detect_infinite_loops (); diff --git a/gcc/analyzer/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc index f8d28ac..25a97e7 100644 --- a/gcc/analyzer/feasible-graph.cc +++ b/gcc/analyzer/feasible-graph.cc @@ -18,21 +18,13 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "pretty-print.h" -#include "gcc-rich-location.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "diagnostic-core.h" -#include "diagnostic-event-id.h" -#include "diagnostic-path.h" -#include "bitmap.h" -#include "ordered-hash-map.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + +#include "cfg.h" +#include "gimple-iterator.h" +#include "cgraph.h" +#include "digraph.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -42,12 +34,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/constraint-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" diff --git a/gcc/analyzer/infinite-loop.cc b/gcc/analyzer/infinite-loop.cc index d6f05d8..ec0b079 100644 --- a/gcc/analyzer/infinite-loop.cc +++ b/gcc/analyzer/infinite-loop.cc @@ -18,28 +18,15 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "fold-const.h" -#include "gcc-rich-location.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "diagnostic-core.h" -#include "diagnostic-event-id.h" -#include "diagnostic-path.h" -#include "function.h" -#include "pretty-print.h" -#include "sbitmap.h" -#include "bitmap.h" -#include "tristate.h" -#include "ordered-hash-map.h" -#include "selftest.h" -#include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + +#include "cfg.h" +#include "gimple-iterator.h" +#include "gimple-pretty-print.h" +#include "cgraph.h" +#include "digraph.h" +#include "diagnostic-format-sarif.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" @@ -49,20 +36,11 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "gimple-pretty-print.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" #include "analyzer/checker-path.h" #include "analyzer/feasible-graph.h" -#include "make-unique.h" -#include "diagnostic-format-sarif.h" /* A bundle of data characterizing a particular infinite loop identified within the exploded graph. */ @@ -108,9 +86,9 @@ struct infinite_loop std::unique_ptr<json::object> to_json () const { - auto loop_obj = ::make_unique<json::object> (); + auto loop_obj = std::make_unique<json::object> (); loop_obj->set_integer ("enode", m_enode.m_index); - auto edge_arr = ::make_unique<json::array> (); + auto edge_arr = std::make_unique<json::array> (); for (auto eedge : m_eedge_vec) edge_arr->append (eedge->to_json ()); loop_obj->set ("eedges", std::move (edge_arr)); @@ -237,7 +215,7 @@ public: checker_path *emission_path) final override { emission_path->add_event - (make_unique<warning_event> + (std::make_unique<warning_event> (event_loc_info (m_inf_loop->m_loc, enode->get_function ()->decl, enode->get_stack_depth ()), @@ -285,43 +263,46 @@ public: if (switch_cfg_sedge->implicitly_created_default_p ()) { emission_path->add_event - (make_unique<perpetual_start_cfg_edge_event> (*eedge, - loc_info_from)); + (std::make_unique<perpetual_start_cfg_edge_event> + (*eedge, + loc_info_from)); emission_path->add_event - (make_unique<end_cfg_edge_event> - (*eedge, - loc_info_to)); + (std::make_unique<end_cfg_edge_event> + (*eedge, + loc_info_to)); } } if (cfg_sedge->true_value_p ()) { emission_path->add_event - (make_unique<perpetual_start_cfg_edge_event> (*eedge, - loc_info_from)); + (std::make_unique<perpetual_start_cfg_edge_event> + (*eedge, + loc_info_from)); emission_path->add_event - (make_unique<end_cfg_edge_event> - (*eedge, - loc_info_to)); + (std::make_unique<end_cfg_edge_event> + (*eedge, + loc_info_to)); } else if (cfg_sedge->false_value_p ()) { emission_path->add_event - (make_unique<perpetual_start_cfg_edge_event> (*eedge, - loc_info_from)); + (std::make_unique<perpetual_start_cfg_edge_event> + (*eedge, + loc_info_from)); emission_path->add_event - (make_unique<end_cfg_edge_event> - (*eedge, - loc_info_to)); + (std::make_unique<end_cfg_edge_event> + (*eedge, + loc_info_to)); } else if (cfg_sedge->back_edge_p ()) { emission_path->add_event - (make_unique<looping_back_event> (*eedge, loc_info_from)); + (std::make_unique<looping_back_event> (*eedge, loc_info_from)); emission_path->add_event - (make_unique<end_cfg_edge_event> - (*eedge, - loc_info_to)); + (std::make_unique<end_cfg_edge_event> + (*eedge, + loc_info_to)); } } } @@ -415,7 +396,7 @@ starts_infinite_loop_p (const exploded_node &enode, feasible_node *curr_fnode = nullptr; if (flag_dump_analyzer_infinite_loop) - fg = ::make_unique<feasible_graph> (); + fg = std::make_unique<feasible_graph> (); location_t first_loc = UNKNOWN_LOCATION; const exploded_node *iter = &enode; @@ -432,7 +413,7 @@ starts_infinite_loop_p (const exploded_node &enode, if (logger) logger->log ("iter: EN: %i", iter->m_index); /* Analysis bailed out before processing this node. */ - if (iter->get_status () == exploded_node::STATUS_WORKLIST) + if (iter->get_status () == exploded_node::status::worklist) { if (logger) logger->log ("rejecting: EN: %i is still in worklist", @@ -460,10 +441,10 @@ starts_infinite_loop_p (const exploded_node &enode, fg->dump_dot (filename, nullptr, dump_args); free (filename); } - return ::make_unique<infinite_loop> (enode, - first_loc, - std::move (eedges), - logger); + return std::make_unique<infinite_loop> (enode, + first_loc, + std::move (eedges), + logger); } else { @@ -593,7 +574,7 @@ exploded_graph::detect_infinite_loops () pending_location ploc (enode, snode, inf_loop->m_loc); auto d - = ::make_unique<infinite_loop_diagnostic> (std::move (inf_loop)); + = std::make_unique<infinite_loop_diagnostic> (std::move (inf_loop)); get_diagnostic_manager ().add_diagnostic (ploc, std::move (d)); } } diff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc index 42f87ed..0641117 100644 --- a/gcc/analyzer/infinite-recursion.cc +++ b/gcc/analyzer/infinite-recursion.cc @@ -18,28 +18,14 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "fold-const.h" -#include "gcc-rich-location.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "diagnostic-core.h" -#include "diagnostic-event-id.h" -#include "diagnostic-path.h" -#include "function.h" -#include "pretty-print.h" -#include "sbitmap.h" -#include "bitmap.h" -#include "tristate.h" -#include "ordered-hash-map.h" -#include "selftest.h" -#include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + +#include "cfg.h" +#include "gimple-iterator.h" +#include "gimple-pretty-print.h" +#include "cgraph.h" +#include "digraph.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" @@ -49,17 +35,9 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "gimple-pretty-print.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" -#include "make-unique.h" #include "analyzer/checker-path.h" #include "analyzer/feasible-graph.h" #include "diagnostic-format-sarif.h" @@ -170,14 +148,15 @@ public: { gcc_assert (m_prev_entry_event == NULL); std::unique_ptr<checker_event> prev_entry_event - = make_unique <recursive_function_entry_event> (dst_point, - *this, false); + = std::make_unique <recursive_function_entry_event> (dst_point, + *this, false); m_prev_entry_event = prev_entry_event.get (); emission_path->add_event (std::move (prev_entry_event)); } else if (eedge.m_dest == m_new_entry_enode) emission_path->add_event - (make_unique<recursive_function_entry_event> (dst_point, *this, true)); + (std::make_unique<recursive_function_entry_event> + (dst_point, *this, true)); else pending_diagnostic::add_function_entry_event (eedge, emission_path); } @@ -193,7 +172,7 @@ public: { gcc_assert (m_new_entry_enode); emission_path->add_event - (make_unique<warning_event> + (std::make_unique<warning_event> (event_loc_info (m_new_entry_enode->get_supernode ()->get_start_location (), m_callee_fndecl, @@ -645,7 +624,7 @@ exploded_graph::detect_infinite_recursion (exploded_node *enode) nullptr); get_diagnostic_manager ().add_diagnostic (ploc, - make_unique<infinite_recursion_diagnostic> (prev_entry_enode, - enode, - fndecl)); + std::make_unique<infinite_recursion_diagnostic> (prev_entry_enode, + enode, + fndecl)); } diff --git a/gcc/analyzer/kf-analyzer.cc b/gcc/analyzer/kf-analyzer.cc index 54f85a4..3e671e5 100644 --- a/gcc/analyzer/kf-analyzer.cc +++ b/gcc/analyzer/kf-analyzer.cc @@ -18,24 +18,16 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "diagnostic.h" #include "tree-diagnostic.h" /* for default_tree_printer. */ +#include "pretty-print-markup.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/region-model.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/call-details.h" -#include "make-unique.h" -#include "pretty-print-markup.h" #if ENABLE_ANALYZER @@ -110,7 +102,7 @@ public: const region *base_reg = reg->get_base_region (); const svalue *capacity = model->get_capacity (base_reg); label_text desc = capacity->get_desc (true); - warning_at (cd.get_call_stmt ()->location, 0, + warning_at (cd.get_call_stmt ().location, 0, "capacity: %qs", desc.get ()); } }; @@ -305,7 +297,7 @@ public: region_model_context *ctxt = cd.get_ctxt (); if (!ctxt) return; - ctxt->warn (make_unique<dump_path_diagnostic> ()); + ctxt->warn (std::make_unique<dump_path_diagnostic> ()); } }; @@ -382,22 +374,28 @@ public: void register_known_analyzer_functions (known_function_manager &kfm) { - kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ()); - kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ()); + kfm.add ("__analyzer_break", + std::make_unique<kf_analyzer_break> ()); + kfm.add ("__analyzer_describe", + std::make_unique<kf_analyzer_describe> ()); kfm.add ("__analyzer_dump_capacity", - make_unique<kf_analyzer_dump_capacity> ()); - kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ()); + std::make_unique<kf_analyzer_dump_capacity> ()); + kfm.add ("__analyzer_dump_escaped", + std::make_unique<kf_analyzer_dump_escaped> ()); kfm.add ("__analyzer_dump_exploded_nodes", - make_unique<kf_analyzer_dump_exploded_nodes> ()); + std::make_unique<kf_analyzer_dump_exploded_nodes> ()); kfm.add ("__analyzer_dump_named_constant", - make_unique<kf_analyzer_dump_named_constant> ()); - kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ()); + std::make_unique<kf_analyzer_dump_named_constant> ()); + kfm.add ("__analyzer_dump_path", + std::make_unique<kf_analyzer_dump_path> ()); kfm.add ("__analyzer_dump_region_model", - make_unique<kf_analyzer_dump_region_model> ()); - kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ()); + std::make_unique<kf_analyzer_dump_region_model> ()); + kfm.add ("__analyzer_eval", + std::make_unique<kf_analyzer_eval> ()); kfm.add ("__analyzer_get_unknown_ptr", - make_unique<kf_analyzer_get_unknown_ptr> ()); - kfm.add ("__analyzer_get_strlen", make_kf_strlen ()); + std::make_unique<kf_analyzer_get_unknown_ptr> ()); + kfm.add ("__analyzer_get_strlen", + make_kf_strlen ()); } } // namespace ana diff --git a/gcc/analyzer/kf-lang-cp.cc b/gcc/analyzer/kf-lang-cp.cc index b2b0c9b..01a98b0 100644 --- a/gcc/analyzer/kf-lang-cp.cc +++ b/gcc/analyzer/kf-lang-cp.cc @@ -18,20 +18,13 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "diagnostic.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -43,10 +36,9 @@ along with GCC; see the file COPYING3. If not see See https://en.cppreference.com/w/cpp/memory/new/operator_new. */ -bool is_placement_new_p (const gcall *call) +bool is_placement_new_p (const gcall &call) { - gcc_assert (call); - tree fndecl = gimple_call_fndecl (call); + tree fndecl = gimple_call_fndecl (&call); if (!fndecl || TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE) /* Give up on overloaded operator new. */ @@ -91,7 +83,7 @@ public: region_model_manager *mgr = cd.get_manager (); const svalue *size_sval = cd.get_arg_svalue (0); region_model_context *ctxt = cd.get_ctxt (); - const gcall *call = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); /* If the call was actually a placement new, check that accessing the buffer lhs is placed into does not result in out-of-bounds. */ @@ -169,10 +161,165 @@ public: /* If the ptr points to an underlying heap region, delete it, poisoning pointers. */ model->unbind_region_and_descendents (freed_reg, - POISON_KIND_DELETED); + poison_kind::deleted); + } + } + +}; + +class kf_cxa_allocate_exception : public known_function +{ +public: + bool matches_call_types_p (const call_details &cd) const final override + { + return cd.num_args () == 1 && cd.arg_is_size_p (0); + } + + void impl_call_pre (const call_details &cd) const final override + { + region_model *model = cd.get_model (); + region_model_manager *mgr = cd.get_manager (); + const svalue *size_sval = cd.get_arg_svalue (0); + region_model_context *ctxt = cd.get_ctxt (); + + /* Create a heap allocated region. */ + const region *new_reg + = model->get_or_create_region_for_heap_alloc (size_sval, ctxt); + if (cd.get_lhs_type ()) + { + const svalue *ptr_sval + = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg); + cd.maybe_set_lhs (ptr_sval); + } + } +}; + +class kf_cxa_begin_catch : public known_function +{ +public: + bool matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == 1 + && POINTER_TYPE_P (cd.get_arg_type (0))); + } + + void impl_call_pre (const call_details &cd) const final override + { + region_model *model = cd.get_model (); + + auto node = model->pop_thrown_exception (); + model->push_caught_exception (node); + cd.maybe_set_lhs (node.m_exception_sval); + } +}; + +class kf_cxa_end_catch : public known_function +{ +public: + bool matches_call_types_p (const call_details &cd) const final override + { + return cd.num_args () == 0; + } + + void impl_call_pre (const call_details &cd) const final override + { + region_model *model = cd.get_model (); + model->pop_caught_exception (); + } +}; + +/* A subclass of pending_diagnostic for complaining about an exception + of an unexpected type being thrown (due to a call to + __cxa_call_unexpected). + See https://en.cppreference.com/w/cpp/language/except_spec */ + +class throw_of_unexpected_type +: public pending_diagnostic_subclass<throw_of_unexpected_type> +{ +public: + throw_of_unexpected_type (tree exception_type, + tree thrown_from_fndecl) + : m_exception_type (exception_type), + m_thrown_from_fndecl (thrown_from_fndecl) + { + gcc_assert (m_exception_type); + gcc_assert (m_thrown_from_fndecl); + } + + const char *get_kind () const final override + { + return "throw_of_unexpected_type"; + } + + bool operator== (const throw_of_unexpected_type &other) const + { + return (m_exception_type == other.m_exception_type + && m_thrown_from_fndecl == other.m_thrown_from_fndecl); + } + + int get_controlling_option () const final override + { + return OPT_Wanalyzer_throw_of_unexpected_type; + } + + bool emit (diagnostic_emission_context &ctxt) final override + { + auto_diagnostic_group d; + + bool warned + = ctxt.warn ("throwing exception of unexpected type %qT from %qE", + m_exception_type, m_thrown_from_fndecl); + if (warned) + { + inform (DECL_SOURCE_LOCATION (m_thrown_from_fndecl), + "%qE declared here", m_thrown_from_fndecl); + // TODO: show specified types? } + return warned; + } + + bool + describe_final_event (pretty_printer &pp, + const evdesc::final_event &) final override + { + pp_printf (&pp, + "exception of unexpected type %qT thrown from %qE", + m_exception_type, m_thrown_from_fndecl); + return true; + } + +private: + tree m_exception_type; + tree m_thrown_from_fndecl; +}; + +/* See https://en.cppreference.com/w/cpp/language/except_spec */ + +class kf_cxa_call_unexpected : public known_function +{ +public: + bool matches_call_types_p (const call_details &cd) const final override + { + return (cd.num_args () == 1 + && POINTER_TYPE_P (cd.get_arg_type (0))); } + void impl_call_pre (const call_details &cd) const final override + { + if (region_model_context *ctxt = cd.get_ctxt ()) + { + region_model *model = cd.get_model (); + tree thrown_from_fndecl = model->get_current_function ()->decl; + /* We must have a thrown exception. */ + auto eh_node = model->get_current_thrown_exception (); + gcc_assert (eh_node); + tree exception_type = eh_node->maybe_get_type (); + ctxt->warn + (std::make_unique<throw_of_unexpected_type> (exception_type, + thrown_from_fndecl)); + ctxt->terminate_path (); + } + } }; /* Populate KFM with instances of known functions relating to C++. */ @@ -180,10 +327,21 @@ public: void register_known_functions_lang_cp (known_function_manager &kfm) { - kfm.add ("operator new", make_unique<kf_operator_new> ()); - kfm.add ("operator new []", make_unique<kf_operator_new> ()); - kfm.add ("operator delete", make_unique<kf_operator_delete> ()); - kfm.add ("operator delete []", make_unique<kf_operator_delete> ()); + kfm.add ("operator new", std::make_unique<kf_operator_new> ()); + kfm.add ("operator new []", std::make_unique<kf_operator_new> ()); + kfm.add ("operator delete", std::make_unique<kf_operator_delete> ()); + kfm.add ("operator delete []", std::make_unique<kf_operator_delete> ()); + + /* Functions mentioned in "Itanium C++ ABI: Exception Handling"'s + "Level II: C++ ABI" + https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-abi */ + kfm.add ("__cxa_allocate_exception", + std::make_unique<kf_cxa_allocate_exception> ()); + // We treat __cxa_throw and __cxa_rethrow as special cases + kfm.add ("__cxa_begin_catch", std::make_unique<kf_cxa_begin_catch> ()); + kfm.add ("__cxa_end_catch", std::make_unique<kf_cxa_end_catch> ()); + kfm.add ("__cxa_call_unexpected", + std::make_unique<kf_cxa_call_unexpected> ()); } } // namespace ana diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index dceedd4..75b6279 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -18,23 +18,14 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "diagnostic-metadata.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "diagnostic.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -50,7 +41,6 @@ public: : m_call_stmt (cd.get_call_stmt ()), m_callee_fndecl (cd.get_fndecl_for_call ()) { - gcc_assert (m_call_stmt); gcc_assert (m_callee_fndecl); } @@ -61,7 +51,7 @@ public: bool operator== (const undefined_function_behavior &other) const { - return (m_call_stmt == other.m_call_stmt + return (&m_call_stmt == &other.m_call_stmt && m_callee_fndecl == other.m_callee_fndecl); } @@ -70,7 +60,7 @@ public: tree get_callee_fndecl () const { return m_callee_fndecl; } private: - const gimple *m_call_stmt; + const gimple &m_call_stmt; tree m_callee_fndecl; }; @@ -596,7 +586,7 @@ kf_free::impl_call_post (const call_details &cd) const /* If the ptr points to an underlying heap region, delete it, poisoning pointers. */ region_model *model = cd.get_model (); - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, poison_kind::freed); model->unset_dynamic_extents (freed_reg); } } @@ -881,7 +871,7 @@ public: break; case MEMSPACE_STACK: if (ctxt) - ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg)); + ctxt->warn (std::make_unique<putenv_of_auto_var> (fndecl, reg)); break; } cd.set_any_lhs_with_defaults (); @@ -1084,7 +1074,7 @@ kf_realloc::impl_call_post (const call_details &cd) const /* If the ptr points to an underlying heap region, delete it, poisoning pointers. */ - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, poison_kind::freed); model->unset_dynamic_extents (freed_reg); } @@ -1129,9 +1119,9 @@ kf_realloc::impl_call_post (const call_details &cd) const if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<failure> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<failure> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<success_no_move> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<success_with_move> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1200,7 +1190,7 @@ kf_strchr::impl_call_post (const call_details &cd) const using the str_reg as the id of the conjured_svalue. */ const svalue *offset = mgr->get_or_create_conjured_svalue (size_type_node, - cd.get_call_stmt (), + &cd.get_call_stmt (), str_reg, conjured_purge (model, ctxt)); @@ -1220,8 +1210,8 @@ kf_strchr::impl_call_post (const call_details &cd) const /* Body of kf_strchr::impl_call_post. */ if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true)); + cd.get_ctxt ()->bifurcate (std::make_unique<strchr_call_info> (cd, false)); + cd.get_ctxt ()->bifurcate (std::make_unique<strchr_call_info> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -1286,6 +1276,27 @@ public: /* Currently a no-op. */ }; +/* Handler for "__builtin_eh_pointer". */ + +class kf_eh_pointer : public builtin_known_function +{ +public: + bool matches_call_types_p (const call_details &) const final override + { + return true; + } + + enum built_in_function builtin_code () const final override + { + return BUILT_IN_EH_POINTER; + } + + void impl_call_pre (const call_details &cd) const final override + { + cd.set_any_lhs_with_defaults (); + } +}; + /* Handler for "strcat" and "__builtin_strcat_chk". */ class kf_strcat : public builtin_known_function @@ -1476,7 +1487,7 @@ public: std::unique_ptr<known_function> make_kf_strlen () { - return make_unique<kf_strlen> (); + return std::make_unique<kf_strlen> (); } /* Handler for "strncpy" and "__builtin_strncpy". @@ -1650,11 +1661,13 @@ kf_strncpy::impl_call_post (const call_details &cd) const nullptr, nullptr); cd.get_ctxt ()->bifurcate - (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval, - false)); + (std::make_unique<strncpy_call_info> + (cd, num_bytes_with_terminator_sval, + false)); cd.get_ctxt ()->bifurcate - (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval, - true)); + (std::make_unique<strncpy_call_info> + (cd, num_bytes_with_terminator_sval, + true)); cd.get_ctxt ()->terminate_path (); } }; @@ -1757,7 +1770,7 @@ kf_strstr::impl_call_post (const call_details &cd) const using the str_reg as the id of the conjured_svalue. */ const svalue *offset = mgr->get_or_create_conjured_svalue (size_type_node, - cd.get_call_stmt (), + &cd.get_call_stmt (), str_reg, conjured_purge (model, ctxt)); @@ -1777,8 +1790,8 @@ kf_strstr::impl_call_post (const call_details &cd) const /* Body of kf_strstr::impl_call_post. */ if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, true)); + cd.get_ctxt ()->bifurcate (std::make_unique<strstr_call_info> (cd, false)); + cd.get_ctxt ()->bifurcate (std::make_unique<strstr_call_info> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -1924,7 +1937,7 @@ public: if (cd.get_arg_svalue (0)->all_zeroes_p ()) { if (ctxt) - ctxt->warn (::make_unique<undefined_behavior> (cd)); + ctxt->warn (::std::make_unique<undefined_behavior> (cd)); } /* Assume that "str" was actually non-null; terminate @@ -1958,14 +1971,14 @@ public: using the str_reg as the id of the conjured_svalue. */ const svalue *start_offset = mgr->get_or_create_conjured_svalue (size_type_node, - cd.get_call_stmt (), + &cd.get_call_stmt (), str_reg, conjured_purge (model, ctxt), 0); const svalue *nul_offset = mgr->get_or_create_conjured_svalue (size_type_node, - cd.get_call_stmt (), + &cd.get_call_stmt (), str_reg, conjured_purge (model, ctxt), @@ -2042,13 +2055,13 @@ public: Typically the str is either null or non-null at a particular site, so hopefully this will generally just lead to two out-edges. */ cd.get_ctxt ()->bifurcate - (make_unique<strtok_call_info> (cd, m_private_reg, false, false)); + (std::make_unique<strtok_call_info> (cd, m_private_reg, false, false)); cd.get_ctxt ()->bifurcate - (make_unique<strtok_call_info> (cd, m_private_reg, false, true)); + (std::make_unique<strtok_call_info> (cd, m_private_reg, false, true)); cd.get_ctxt ()->bifurcate - (make_unique<strtok_call_info> (cd, m_private_reg, true, false)); + (std::make_unique<strtok_call_info> (cd, m_private_reg, true, false)); cd.get_ctxt ()->bifurcate - (make_unique<strtok_call_info> (cd, m_private_reg, true, true)); + (std::make_unique<strtok_call_info> (cd, m_private_reg, true, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2074,127 +2087,127 @@ region_model::impl_deallocation_call (const call_details &cd) static void register_atomic_builtins (known_function_manager &kfm) { - kfm.add (BUILT_IN_ATOMIC_EXCHANGE, make_unique<kf_atomic_exchange> ()); - kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique<kf_atomic_exchange_n> ()); - kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique<kf_atomic_exchange_n> ()); - kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique<kf_atomic_exchange_n> ()); - kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique<kf_atomic_exchange_n> ()); - kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique<kf_atomic_exchange_n> ()); - kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique<kf_atomic_exchange_n> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique<kf_atomic_load> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique<kf_atomic_load_n> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique<kf_atomic_load_n> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique<kf_atomic_load_n> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ()); - kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ()); - kfm.add (BUILT_IN_ATOMIC_STORE, make_unique<kf_atomic_store> ()); - kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ()); - kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ()); - kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ()); - kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique<kf_atomic_store_n> ()); - kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique<kf_atomic_store_n> ()); - kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique<kf_atomic_store_n> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE, std::make_unique<kf_atomic_exchange> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, std::make_unique<kf_atomic_exchange_n> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, std::make_unique<kf_atomic_exchange_n> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, std::make_unique<kf_atomic_exchange_n> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, std::make_unique<kf_atomic_exchange_n> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, std::make_unique<kf_atomic_exchange_n> ()); + kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, std::make_unique<kf_atomic_exchange_n> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD, std::make_unique<kf_atomic_load> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_N, std::make_unique<kf_atomic_load_n> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_1, std::make_unique<kf_atomic_load_n> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_2, std::make_unique<kf_atomic_load_n> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_4, std::make_unique<kf_atomic_load_n> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_8, std::make_unique<kf_atomic_load_n> ()); + kfm.add (BUILT_IN_ATOMIC_LOAD_16, std::make_unique<kf_atomic_load_n> ()); + kfm.add (BUILT_IN_ATOMIC_STORE, std::make_unique<kf_atomic_store> ()); + kfm.add (BUILT_IN_ATOMIC_STORE_N, std::make_unique<kf_atomic_store_n> ()); + kfm.add (BUILT_IN_ATOMIC_STORE_1, std::make_unique<kf_atomic_store_n> ()); + kfm.add (BUILT_IN_ATOMIC_STORE_2, std::make_unique<kf_atomic_store_n> ()); + kfm.add (BUILT_IN_ATOMIC_STORE_4, std::make_unique<kf_atomic_store_n> ()); + kfm.add (BUILT_IN_ATOMIC_STORE_8, std::make_unique<kf_atomic_store_n> ()); + kfm.add (BUILT_IN_ATOMIC_STORE_16, std::make_unique<kf_atomic_store_n> ()); kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1, - make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2, - make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4, - make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8, - make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16, - make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1, - make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2, - make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4, - make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8, - make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16, - make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); + std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1, - make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2, - make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4, - make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8, - make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16, - make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1, - make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2, - make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4, - make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8, - make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16, - make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1, - make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2, - make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4, - make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8, - make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16, - make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1, - make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2, - make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4, - make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8, - make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16, - make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1, - make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2, - make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4, - make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8, - make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16, - make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); + std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1, - make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2, - make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4, - make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8, - make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16, - make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1, - make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2, - make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4, - make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8, - make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16, - make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1, - make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2, - make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4, - make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8, - make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16, - make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); + std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR)); } /* Handle calls to the various IFN_UBSAN_* with no return value. @@ -2224,14 +2237,14 @@ register_sanitizer_builtins (known_function_manager &kfm) /* Handle calls to the various IFN_UBSAN_* with no return value. For now, treat these as no-ops. */ kfm.add (IFN_UBSAN_NULL, - make_unique<kf_ubsan_noop> ()); + std::make_unique<kf_ubsan_noop> ()); kfm.add (IFN_UBSAN_BOUNDS, - make_unique<kf_ubsan_noop> ()); + std::make_unique<kf_ubsan_noop> ()); kfm.add (IFN_UBSAN_PTR, - make_unique<kf_ubsan_noop> ()); + std::make_unique<kf_ubsan_noop> ()); kfm.add (BUILT_IN_UBSAN_HANDLE_NONNULL_ARG, - make_unique<kf_ubsan_handler> ()); + std::make_unique<kf_ubsan_handler> ()); } /* Populate KFM with instances of known functions supported by the core of the @@ -2246,17 +2259,19 @@ register_known_functions (known_function_manager &kfm, /* Internal fns the analyzer has known_functions for. */ { - kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ()); + kfm.add (IFN_BUILTIN_EXPECT, std::make_unique<kf_expect> ()); } /* GCC built-ins that do not correspond to a function in the standard library. */ { - kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ()); - kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ()); - kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ()); - kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ()); - kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ()); + kfm.add (BUILT_IN_EXPECT, std::make_unique<kf_expect> ()); + kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, std::make_unique<kf_expect> ()); + kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, std::make_unique<kf_alloca> ()); + kfm.add (BUILT_IN_STACK_RESTORE, std::make_unique<kf_stack_restore> ()); + kfm.add (BUILT_IN_STACK_SAVE, std::make_unique<kf_stack_save> ()); + + kfm.add (BUILT_IN_EH_POINTER, std::make_unique<kf_eh_pointer> ()); register_atomic_builtins (kfm); register_sanitizer_builtins (kfm); @@ -2266,58 +2281,58 @@ register_known_functions (known_function_manager &kfm, /* Known builtins and C standard library functions the analyzer has known functions for. */ { - kfm.add ("alloca", make_unique<kf_alloca> ()); - kfm.add ("__builtin_alloca", make_unique<kf_alloca> ()); - kfm.add ("calloc", make_unique<kf_calloc> ()); - kfm.add ("__builtin_calloc", make_unique<kf_calloc> ()); - kfm.add ("free", make_unique<kf_free> ()); - kfm.add ("__builtin_free", make_unique<kf_free> ()); - kfm.add ("malloc", make_unique<kf_malloc> ()); - kfm.add ("__builtin_malloc", make_unique<kf_malloc> ()); + kfm.add ("alloca", std::make_unique<kf_alloca> ()); + kfm.add ("__builtin_alloca", std::make_unique<kf_alloca> ()); + kfm.add ("calloc", std::make_unique<kf_calloc> ()); + kfm.add ("__builtin_calloc", std::make_unique<kf_calloc> ()); + kfm.add ("free", std::make_unique<kf_free> ()); + kfm.add ("__builtin_free", std::make_unique<kf_free> ()); + kfm.add ("malloc", std::make_unique<kf_malloc> ()); + kfm.add ("__builtin_malloc", std::make_unique<kf_malloc> ()); kfm.add ("memcpy", - make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY)); + std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY)); kfm.add ("__builtin_memcpy", - make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY)); - kfm.add ("__memcpy_chk", make_unique<kf_memcpy_memmove> + std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY)); + kfm.add ("__memcpy_chk", std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY_CHK)); - kfm.add ("__builtin___memcpy_chk", make_unique<kf_memcpy_memmove> + kfm.add ("__builtin___memcpy_chk", std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY_CHK)); kfm.add ("memmove", - make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE)); + std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE)); kfm.add ("__builtin_memmove", - make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE)); - kfm.add ("__memmove_chk", make_unique<kf_memcpy_memmove> + std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE)); + kfm.add ("__memmove_chk", std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE_CHK)); - kfm.add ("__builtin___memmove_chk", make_unique<kf_memcpy_memmove> + kfm.add ("__builtin___memmove_chk", std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE_CHK)); - kfm.add ("memset", make_unique<kf_memset> (false)); - kfm.add ("__builtin_memset", make_unique<kf_memset> (false)); - kfm.add ("__memset_chk", make_unique<kf_memset> (true)); - kfm.add ("__builtin___memset_chk", make_unique<kf_memset> (true)); - kfm.add ("realloc", make_unique<kf_realloc> ()); - kfm.add ("__builtin_realloc", make_unique<kf_realloc> ()); - kfm.add ("sprintf", make_unique<kf_sprintf> ()); - kfm.add ("__builtin_sprintf", make_unique<kf_sprintf> ()); - kfm.add ("strchr", make_unique<kf_strchr> ()); - kfm.add ("__builtin_strchr", make_unique<kf_strchr> ()); - kfm.add ("strcpy", make_unique<kf_strcpy> (2, false)); - kfm.add ("__builtin_strcpy", make_unique<kf_strcpy> (2, false)); - kfm.add ("__strcpy_chk", make_unique<kf_strcpy> (3, true)); - kfm.add ("__builtin___strcpy_chk", make_unique<kf_strcpy> (3, true)); - kfm.add ("strcat", make_unique<kf_strcat> (2, false)); - kfm.add ("__builtin_strcat", make_unique<kf_strcat> (2, false)); - kfm.add ("__strcat_chk", make_unique<kf_strcat> (3, true)); - kfm.add ("__builtin___strcat_chk", make_unique<kf_strcat> (3, true)); - kfm.add ("strdup", make_unique<kf_strdup> ()); - kfm.add ("__builtin_strdup", make_unique<kf_strdup> ()); - kfm.add ("strncpy", make_unique<kf_strncpy> ()); - kfm.add ("__builtin_strncpy", make_unique<kf_strncpy> ()); - kfm.add ("strndup", make_unique<kf_strndup> ()); - kfm.add ("__builtin_strndup", make_unique<kf_strndup> ()); - kfm.add ("strlen", make_unique<kf_strlen> ()); - kfm.add ("__builtin_strlen", make_unique<kf_strlen> ()); - kfm.add ("strstr", make_unique<kf_strstr> ()); - kfm.add ("__builtin_strstr", make_unique<kf_strstr> ()); + kfm.add ("memset", std::make_unique<kf_memset> (false)); + kfm.add ("__builtin_memset", std::make_unique<kf_memset> (false)); + kfm.add ("__memset_chk", std::make_unique<kf_memset> (true)); + kfm.add ("__builtin___memset_chk", std::make_unique<kf_memset> (true)); + kfm.add ("realloc", std::make_unique<kf_realloc> ()); + kfm.add ("__builtin_realloc", std::make_unique<kf_realloc> ()); + kfm.add ("sprintf", std::make_unique<kf_sprintf> ()); + kfm.add ("__builtin_sprintf", std::make_unique<kf_sprintf> ()); + kfm.add ("strchr", std::make_unique<kf_strchr> ()); + kfm.add ("__builtin_strchr", std::make_unique<kf_strchr> ()); + kfm.add ("strcpy", std::make_unique<kf_strcpy> (2, false)); + kfm.add ("__builtin_strcpy", std::make_unique<kf_strcpy> (2, false)); + kfm.add ("__strcpy_chk", std::make_unique<kf_strcpy> (3, true)); + kfm.add ("__builtin___strcpy_chk", std::make_unique<kf_strcpy> (3, true)); + kfm.add ("strcat", std::make_unique<kf_strcat> (2, false)); + kfm.add ("__builtin_strcat", std::make_unique<kf_strcat> (2, false)); + kfm.add ("__strcat_chk", std::make_unique<kf_strcat> (3, true)); + kfm.add ("__builtin___strcat_chk", std::make_unique<kf_strcat> (3, true)); + kfm.add ("strdup", std::make_unique<kf_strdup> ()); + kfm.add ("__builtin_strdup", std::make_unique<kf_strdup> ()); + kfm.add ("strncpy", std::make_unique<kf_strncpy> ()); + kfm.add ("__builtin_strncpy", std::make_unique<kf_strncpy> ()); + kfm.add ("strndup", std::make_unique<kf_strndup> ()); + kfm.add ("__builtin_strndup", std::make_unique<kf_strndup> ()); + kfm.add ("strlen", std::make_unique<kf_strlen> ()); + kfm.add ("__builtin_strlen", std::make_unique<kf_strlen> ()); + kfm.add ("strstr", std::make_unique<kf_strstr> ()); + kfm.add ("__builtin_strstr", std::make_unique<kf_strstr> ()); register_atomic_builtins (kfm); register_varargs_builtins (kfm); @@ -2325,9 +2340,9 @@ register_known_functions (known_function_manager &kfm, /* Known POSIX functions, and some non-standard extensions. */ { - kfm.add ("fopen", make_unique<kf_fopen> ()); - kfm.add ("putenv", make_unique<kf_putenv> ()); - kfm.add ("strtok", make_unique<kf_strtok> (rmm)); + kfm.add ("fopen", std::make_unique<kf_fopen> ()); + kfm.add ("putenv", std::make_unique<kf_putenv> ()); + kfm.add ("strtok", std::make_unique<kf_strtok> (rmm)); register_known_fd_functions (kfm); register_known_file_functions (kfm); @@ -2335,13 +2350,13 @@ register_known_functions (known_function_manager &kfm, /* glibc functions. */ { - kfm.add ("__errno_location", make_unique<kf_errno_location> ()); - kfm.add ("error", make_unique<kf_error> (3)); - kfm.add ("error_at_line", make_unique<kf_error> (5)); + kfm.add ("__errno_location", std::make_unique<kf_errno_location> ()); + kfm.add ("error", std::make_unique<kf_error> (3)); + kfm.add ("error_at_line", std::make_unique<kf_error> (5)); /* Variants of "error" and "error_at_line" seen by the analyzer at -O0 (PR analyzer/115724). */ - kfm.add ("__error_alias", make_unique<kf_error> (3)); - kfm.add ("__error_at_line_alias", make_unique<kf_error> (5)); + kfm.add ("__error_alias", std::make_unique<kf_error> (3)); + kfm.add ("__error_at_line_alias", std::make_unique<kf_error> (5)); } /* Other implementations of C standard library. */ @@ -2355,9 +2370,9 @@ register_known_functions (known_function_manager &kfm, #define errno (*__error()) and similarly __errno for newlib. Add these as synonyms for "__errno_location". */ - kfm.add ("___errno", make_unique<kf_errno_location> ()); - kfm.add ("__error", make_unique<kf_errno_location> ()); - kfm.add ("__errno", make_unique<kf_errno_location> ()); + kfm.add ("___errno", std::make_unique<kf_errno_location> ()); + kfm.add ("__error", std::make_unique<kf_errno_location> ()); + kfm.add ("__errno", std::make_unique<kf_errno_location> ()); } /* Language-specific support functions. */ @@ -2367,22 +2382,22 @@ register_known_functions (known_function_manager &kfm, from <cstdlib> etc for the C spellings of these headers (e.g. <stdlib.h>), so we must match against these too. */ { - kfm.add_std_ns ("malloc", make_unique<kf_malloc> ()); - kfm.add_std_ns ("free", make_unique<kf_free> ()); - kfm.add_std_ns ("realloc", make_unique<kf_realloc> ()); - kfm.add_std_ns ("calloc", make_unique<kf_calloc> ()); + kfm.add_std_ns ("malloc", std::make_unique<kf_malloc> ()); + kfm.add_std_ns ("free", std::make_unique<kf_free> ()); + kfm.add_std_ns ("realloc", std::make_unique<kf_realloc> ()); + kfm.add_std_ns ("calloc", std::make_unique<kf_calloc> ()); kfm.add_std_ns ("memcpy", - make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY)); + std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY)); kfm.add_std_ns ("memmove", - make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE)); - kfm.add_std_ns ("memset", make_unique<kf_memset> (false)); - kfm.add_std_ns ("strcat", make_unique<kf_strcat> (2, false)); - kfm.add_std_ns ("strcpy", make_unique<kf_strcpy> (2, false)); - kfm.add_std_ns ("strlen", make_unique<kf_strlen> ()); - kfm.add_std_ns ("strncpy", make_unique<kf_strncpy> ()); - kfm.add_std_ns ("strtok", make_unique<kf_strtok> (rmm)); + std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE)); + kfm.add_std_ns ("memset", std::make_unique<kf_memset> (false)); + kfm.add_std_ns ("strcat", std::make_unique<kf_strcat> (2, false)); + kfm.add_std_ns ("strcpy", std::make_unique<kf_strcpy> (2, false)); + kfm.add_std_ns ("strlen", std::make_unique<kf_strlen> ()); + kfm.add_std_ns ("strncpy", std::make_unique<kf_strncpy> ()); + kfm.add_std_ns ("strtok", std::make_unique<kf_strtok> (rmm)); } } diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc index db670b8..1a2930e 100644 --- a/gcc/analyzer/known-function-manager.cc +++ b/gcc/analyzer/known-function-manager.cc @@ -18,17 +18,12 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-core.h" -#include "analyzer/analyzer-logging.h" #include "stringpool.h" -#include "basic-block.h" -#include "gimple.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/known-function-manager.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" @@ -108,7 +103,7 @@ known_function_manager::get_match (tree fndecl, const call_details &cd) const { if (const known_function *candidate = get_normal_builtin (DECL_FUNCTION_CODE (fndecl))) - if (gimple_builtin_call_types_compatible_p (cd.get_call_stmt (), + if (gimple_builtin_call_types_compatible_p (&cd.get_call_stmt (), fndecl)) return candidate; } diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc index 0f69d02..70dc815 100644 --- a/gcc/analyzer/pending-diagnostic.cc +++ b/gcc/analyzer/pending-diagnostic.cc @@ -18,18 +18,18 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "intl.h" -#include "diagnostic.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-event-id.h" +#include "cpplib.h" +#include "digraph.h" +#include "ordered-hash-map.h" +#include "cfg.h" +#include "gimple-iterator.h" +#include "cgraph.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" -#include "diagnostic-event-id.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" @@ -37,20 +37,10 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" -#include "cpplib.h" -#include "digraph.h" -#include "ordered-hash-map.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "cgraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" -#include "diagnostic-path.h" #include "analyzer/checker-path.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -195,7 +185,7 @@ pending_diagnostic::add_function_entry_event (const exploded_edge &eedge, { const exploded_node *dst_node = eedge.m_dest; const program_point &dst_point = dst_node->get_point (); - emission_path->add_event (make_unique<function_entry_event> (dst_point)); + emission_path->add_event (std::make_unique<function_entry_event> (dst_point)); } /* Base implementation of pending_diagnostic::add_call_event. @@ -210,12 +200,12 @@ pending_diagnostic::add_call_event (const exploded_edge &eedge, const int src_stack_depth = src_point.get_stack_depth (); const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt (); emission_path->add_event - (make_unique<call_event> (eedge, - event_loc_info (last_stmt - ? last_stmt->location - : UNKNOWN_LOCATION, - src_point.get_fndecl (), - src_stack_depth))); + (std::make_unique<call_event> (eedge, + event_loc_info (last_stmt + ? last_stmt->location + : UNKNOWN_LOCATION, + src_point.get_fndecl (), + src_stack_depth))); } /* Base implementation of pending_diagnostic::add_region_creation_events. @@ -228,12 +218,13 @@ pending_diagnostic::add_region_creation_events (const region *reg, checker_path &emission_path) { emission_path.add_event - (make_unique<region_creation_event_memory_space> (reg->get_memory_space (), - loc_info)); + (std::make_unique<region_creation_event_memory_space> + (reg->get_memory_space (), + loc_info)); if (capacity) emission_path.add_event - (make_unique<region_creation_event_capacity> (capacity, loc_info)); + (std::make_unique<region_creation_event_capacity> (capacity, loc_info)); } /* Base implementation of pending_diagnostic::add_final_event. @@ -247,7 +238,7 @@ pending_diagnostic::add_final_event (const state_machine *sm, checker_path *emission_path) { emission_path->add_event - (make_unique<warning_event> + (std::make_unique<warning_event> (loc_info, enode, sm, var, state)); diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index 473c102..c95f863 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -18,42 +18,28 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "gimple-pretty-print.h" +#include "analyzer/common.h" + +#include "diagnostic-event-id.h" #include "gcc-rich-location.h" -#include "ordered-hash-map.h" -#include "options.h" -#include "cgraph.h" -#include "function.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "digraph.h" -#include "analyzer/analyzer.h" +#include "gimple-pretty-print.h" +#include "sbitmap.h" +#include "selftest.h" +#include "shortest-paths.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/supergraph.h" #include "analyzer/program-point.h" -#include "sbitmap.h" -#include "bitmap.h" -#include "selftest.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/sm.h" #include "analyzer/program-state.h" -#include "diagnostic-event-id.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "shortest-paths.h" #include "analyzer/exploded-graph.h" #include "analyzer/analysis-plan.h" #include "analyzer/inlining-iterator.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -316,7 +302,7 @@ program_point::dump () const std::unique_ptr<json::object> program_point::to_json () const { - auto point_obj = ::make_unique<json::object> (); + auto point_obj = std::make_unique<json::object> (); point_obj->set_string ("kind", point_kind_to_string (get_kind ())); diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index ec96900..21f78e5 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -18,44 +18,36 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" -#include "diagnostic.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" -#include "analyzer/sm.h" +#include "analyzer/common.h" + #include "sbitmap.h" -#include "bitmap.h" #include "ordered-hash-map.h" #include "selftest.h" +#include "cfg.h" +#include "gimple-iterator.h" +#include "cgraph.h" +#include "digraph.h" +#include "diagnostic-event-id.h" + +#include "text-art/tree-widget.h" +#include "text-art/dump.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/sm.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/constraint-manager.h" -#include "diagnostic-event-id.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" #include "analyzer/state-purge.h" #include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" -#include "text-art/tree-widget.h" -#include "text-art/dump.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -69,11 +61,10 @@ void extrinsic_state::dump_to_pp (pretty_printer *pp) const { pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ()); - unsigned i; - state_machine *checker; - FOR_EACH_VEC_ELT (m_checkers, i, checker) + unsigned i = 0; + for (auto &checker : m_checkers) { - pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ()); + pp_printf (pp, "m_checkers[%i]: %qs\n", ++i, checker->get_name ()); checker->dump_to_pp (pp); } } @@ -101,13 +92,11 @@ extrinsic_state::dump () const std::unique_ptr<json::object> extrinsic_state::to_json () const { - auto ext_state_obj = ::make_unique<json::object> (); + auto ext_state_obj = std::make_unique<json::object> (); { - auto checkers_arr = ::make_unique<json::array> (); - unsigned i; - state_machine *sm; - FOR_EACH_VEC_ELT (m_checkers, i, sm) + auto checkers_arr = std::make_unique<json::array> (); + for (auto &sm : m_checkers) checkers_arr->append (sm->to_json ()); ext_state_obj->set ("checkers", std::move (checkers_arr)); } @@ -133,10 +122,8 @@ extrinsic_state::get_model_manager () const bool extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const { - unsigned i; - state_machine *sm; - FOR_EACH_VEC_ELT (m_checkers, i, sm) - if (0 == strcmp (name, sm->get_name ())) + for (size_t i = 0; i < m_checkers.size (); ++i) + if (0 == strcmp (name, m_checkers[i]->get_name ())) { /* Found NAME. */ *out = i; @@ -279,7 +266,7 @@ sm_state_map::dump (bool simple) const std::unique_ptr<json::object> sm_state_map::to_json () const { - auto map_obj = ::make_unique<json::object> (); + auto map_obj = std::make_unique<json::object> (); if (m_global_state != m_sm.get_start_state ()) map_obj->set ("global", m_global_state->to_json ()); @@ -1188,7 +1175,7 @@ program_state::dump () const std::unique_ptr<json::object> program_state::to_json (const extrinsic_state &ext_state) const { - auto state_obj = ::make_unique<json::object> (); + auto state_obj = std::make_unique<json::object> (); state_obj->set ("store", m_region_model->get_store ()->to_json ()); state_obj->set ("constraints", @@ -1199,7 +1186,7 @@ program_state::to_json (const extrinsic_state &ext_state) const /* Provide m_checker_states as an object, using names as keys. */ { - auto checkers_obj = ::make_unique<json::object> (); + auto checkers_obj = std::make_unique<json::object> (); int i; sm_state_map *smap; @@ -1244,7 +1231,7 @@ void program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED, const function &fun) { - m_region_model->push_frame (fun, NULL, NULL); + m_region_model->push_frame (fun, nullptr, nullptr, nullptr); } /* Get the current function of this state. */ @@ -1348,7 +1335,7 @@ program_state::on_edge (exploded_graph &eg, void program_state::push_call (exploded_graph &eg, exploded_node *enode, - const gcall *call_stmt, + const gcall &call_stmt, uncertainty_t *uncertainty) { /* Update state. */ @@ -1371,7 +1358,7 @@ program_state::push_call (exploded_graph &eg, void program_state::returning_call (exploded_graph &eg, exploded_node *enode, - const gcall *call_stmt, + const gcall &call_stmt, uncertainty_t *uncertainty) { /* Update state. */ @@ -1749,7 +1736,7 @@ program_state::replay_call_summary (call_summary_replay &r, /* Handle calls to "__analyzer_dump_state". */ void -program_state::impl_call_analyzer_dump_state (const gcall *call, +program_state::impl_call_analyzer_dump_state (const gcall &call, const extrinsic_state &ext_state, region_model_context *ctxt) { @@ -1757,13 +1744,13 @@ program_state::impl_call_analyzer_dump_state (const gcall *call, const char *sm_name = cd.get_arg_string_literal (0); if (!sm_name) { - error_at (call->location, "cannot determine state machine"); + error_at (call.location, "cannot determine state machine"); return; } unsigned sm_idx; if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx)) { - error_at (call->location, "unrecognized state machine %qs", sm_name); + error_at (call.location, "unrecognized state machine %qs", sm_name); return; } const sm_state_map *smap = m_checker_states[sm_idx]; @@ -1775,7 +1762,7 @@ program_state::impl_call_analyzer_dump_state (const gcall *call, sval = cast; state_machine::state_t state = smap->get_state (sval, ext_state); - warning_at (call->location, 0, "state: %qs", state->get_name ()); + warning_at (call.location, 0, "state: %qs", state->get_name ()); } #if CHECKING_P @@ -1791,12 +1778,13 @@ test_sm_state_map () tree y = build_global_decl ("y", integer_type_node); tree z = build_global_decl ("z", integer_type_node); - state_machine *sm = make_malloc_state_machine (NULL); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (sm); - engine eng; - extrinsic_state ext_state (checkers, &eng); + std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL); state_machine::state_t start = sm->get_start_state (); + std::vector<std::unique_ptr<state_machine>> checkers; + const state_machine &borrowed_sm = *sm.get (); + checkers.push_back (std::move (sm)); + engine eng; + extrinsic_state ext_state (std::move (checkers), &eng); /* Test setting states on svalue_id instances directly. */ { @@ -1808,7 +1796,7 @@ test_sm_state_map () const svalue *y_sval = model.get_rvalue (y, NULL); const svalue *z_sval = model.get_rvalue (z, NULL); - sm_state_map map (*sm); + sm_state_map map (borrowed_sm); ASSERT_TRUE (map.is_empty_p ()); ASSERT_EQ (map.get_state (x_sval, ext_state), start); @@ -1837,7 +1825,7 @@ test_sm_state_map () const svalue *y_sval = model.get_rvalue (y, NULL); const svalue *z_sval = model.get_rvalue (z, NULL); - sm_state_map map (*sm); + sm_state_map map (borrowed_sm); ASSERT_TRUE (map.is_empty_p ()); ASSERT_EQ (map.get_state (x_sval, ext_state), start); ASSERT_EQ (map.get_state (y_sval, ext_state), start); @@ -1860,9 +1848,9 @@ test_sm_state_map () const svalue *y_sval = model.get_rvalue (y, NULL); const svalue *z_sval = model.get_rvalue (z, NULL); - sm_state_map map0 (*sm); - sm_state_map map1 (*sm); - sm_state_map map2 (*sm); + sm_state_map map0 (borrowed_sm); + sm_state_map map1 (borrowed_sm); + sm_state_map map2 (borrowed_sm); ASSERT_EQ (map0.hash (), map1.hash ()); ASSERT_EQ (map0, map1); @@ -1883,9 +1871,9 @@ test_sm_state_map () const state_machine::state_t TEST_STATE_2 = &test_state_2; const state_machine::state test_state_3 ("test state 3", 3); const state_machine::state_t TEST_STATE_3 = &test_state_3; - sm_state_map map0 (*sm); - sm_state_map map1 (*sm); - sm_state_map map2 (*sm); + sm_state_map map0 (borrowed_sm); + sm_state_map map1 (borrowed_sm); + sm_state_map map2 (borrowed_sm); ASSERT_EQ (map0.hash (), map1.hash ()); ASSERT_EQ (map0, map1); @@ -1920,14 +1908,12 @@ test_program_state_1 () malloc sm-state, pointing to a region on the heap. */ tree p = build_global_decl ("p", ptr_type_node); - state_machine *sm = make_malloc_state_machine (NULL); + std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL); const state_machine::state_t UNCHECKED_STATE = sm->get_state_by_name ("unchecked"); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (sm); engine eng; - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (std::move (sm), &eng); region_model_manager *mgr = eng.get_model_manager (); program_state s (ext_state); region_model *model = s.m_region_model; @@ -1955,9 +1941,9 @@ test_program_state_2 () tree string_cst_ptr = build_string_literal (4, "foo"); - auto_delete_vec <state_machine> checkers; + std::vector<std::unique_ptr<state_machine>> checkers; engine eng; - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (std::move (checkers), &eng); program_state s (ext_state); region_model *model = s.m_region_model; @@ -1979,9 +1965,8 @@ test_program_state_merging () engine eng; region_model_manager *mgr = eng.get_model_manager (); program_point point (program_point::origin (*mgr)); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (make_malloc_state_machine (NULL)); - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (make_malloc_state_machine (NULL), + &eng); program_state s0 (ext_state); uncertainty_t uncertainty; @@ -2047,9 +2032,7 @@ test_program_state_merging_2 () engine eng; region_model_manager *mgr = eng.get_model_manager (); program_point point (program_point::origin (*mgr)); - auto_delete_vec <state_machine> checkers; - checkers.safe_push (make_signal_state_machine (NULL)); - extrinsic_state ext_state (checkers, &eng); + extrinsic_state ext_state (make_signal_state_machine (NULL), &eng); const state_machine::state test_state_0 ("test state 0", 0); const state_machine::state test_state_1 ("test state 1", 1); diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index e0f4ee8..269ffde 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -30,13 +30,25 @@ namespace ana { class extrinsic_state { public: - extrinsic_state (auto_delete_vec <state_machine> &checkers, + extrinsic_state (std::vector<std::unique_ptr<state_machine>> &&checkers, engine *eng, logger *logger = NULL) - : m_checkers (checkers), m_logger (logger), m_engine (eng) + : m_checkers (std::move (checkers)), + m_logger (logger), + m_engine (eng) { } + // For use in selftests that use just one state machine + extrinsic_state (std::unique_ptr<state_machine> sm, + engine *eng, + logger *logger = NULL) + : m_logger (logger), + m_engine (eng) + { + m_checkers.push_back (std::move (sm)); + } + const state_machine &get_sm (int idx) const { return *m_checkers[idx]; @@ -47,7 +59,7 @@ public: return m_checkers[idx]->get_name (); } - unsigned get_num_checkers () const { return m_checkers.length (); } + unsigned get_num_checkers () const { return m_checkers.size (); } logger *get_logger () const { return m_logger; } @@ -64,7 +76,7 @@ public: private: /* The state machines. */ - auto_delete_vec <state_machine> &m_checkers; + std::vector<std::unique_ptr<state_machine>> m_checkers; logger *m_logger; engine *m_engine; @@ -242,12 +254,12 @@ public: void push_call (exploded_graph &eg, exploded_node *enode, - const gcall *call_stmt, + const gcall &call_stmt, uncertainty_t *uncertainty); void returning_call (exploded_graph &eg, exploded_node *enode, - const gcall *call_stmt, + const gcall &call_stmt, uncertainty_t *uncertainty); @@ -298,7 +310,7 @@ public: bool replay_call_summary (call_summary_replay &r, const program_state &summary); - void impl_call_analyzer_dump_state (const gcall *call, + void impl_call_analyzer_dump_state (const gcall &call, const extrinsic_state &ext_state, region_model_context *ctxt); diff --git a/gcc/analyzer/ranges.cc b/gcc/analyzer/ranges.cc index 4c63ecc..1a960fa 100644 --- a/gcc/analyzer/ranges.cc +++ b/gcc/analyzer/ranges.cc @@ -18,34 +18,13 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" -#include "fold-const.h" -#include "tree-pretty-print.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + +#include "sbitmap.h" #include "ordered-hash-map.h" -#include "options.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/supergraph.h" -#include "sbitmap.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" @@ -53,7 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/constraint-manager.h" #include "analyzer/analyzer-selftests.h" #include "analyzer/ranges.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -158,7 +136,7 @@ symbolic_byte_range::dump (bool simple, region_model_manager &mgr) const std::unique_ptr<json::value> symbolic_byte_range::to_json () const { - auto obj = ::make_unique<json::object> (); + auto obj = std::make_unique<json::object> (); obj->set ("start", m_start.to_json ()); obj->set ("size", m_size.to_json ()); return obj; diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc index 2eb3444..aaf8ccd 100644 --- a/gcc/analyzer/record-layout.cc +++ b/gcc/analyzer/record-layout.cc @@ -18,18 +18,10 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "diagnostic.h" +#include "analyzer/common.h" + #include "tree-diagnostic.h" -#include "analyzer/analyzer.h" + #include "analyzer/record-layout.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc index 0da5cc5..7d7e3b9 100644 --- a/gcc/analyzer/region-model-asm.cc +++ b/gcc/analyzer/region-model-asm.cc @@ -18,26 +18,16 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "pretty-print.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + +#include "stmt.h" + #include "analyzer/analyzer-logging.h" -#include "options.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/region-model-reachability.h" -#include "stmt.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index dfce420..df92503 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -18,34 +18,16 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" +#include "analyzer/common.h" + #include "fold-const.h" -#include "tree-pretty-print.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" #include "analyzer/supergraph.h" #include "sbitmap.h" +#include "target.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" @@ -325,7 +307,7 @@ region_model_manager::get_or_create_initial_value (const region *reg, bool check_poisoned) { if (!reg->can_have_initial_svalue_p () && check_poisoned) - return get_or_create_poisoned_svalue (POISON_KIND_UNINIT, + return get_or_create_poisoned_svalue (poison_kind::uninit, reg->get_type ()); /* The initial value of a cast is a cast of the initial value. */ @@ -962,6 +944,12 @@ region_model_manager::maybe_fold_sub_svalue (tree type, if (!parent_svalue->can_have_associated_state_p ()) return get_or_create_unknown_svalue (type); + /* If we have a subvalue of a zero constant, it's zero. */ + if (tree cst = parent_svalue->maybe_get_constant ()) + if (TREE_CODE (cst) == INTEGER_CST) + if (zerop (cst)) + return get_or_create_cast (type, parent_svalue); + /* If we have a subregion of a zero-fill, it's zero. */ if (const unaryop_svalue *unary = parent_svalue->dyn_cast_unaryop_svalue ()) diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc index 4799ba8..d3bfeb7 100644 --- a/gcc/analyzer/region-model-reachability.cc +++ b/gcc/analyzer/region-model-reachability.cc @@ -18,37 +18,18 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" -#include "fold-const.h" -#include "tree-pretty-print.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "ordered-hash-map.h" -#include "options.h" +#include "diagnostic.h" +#include "tree-diagnostic.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/region-model-reachability.h" -#include "diagnostic.h" -#include "tree-diagnostic.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 84b81e9..1ee882c 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -18,70 +18,53 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" #define INCLUDE_ALGORITHM -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" +#include "analyzer/common.h" + +#include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" -#include "tree-dfa.h" +#include "cfg.h" +#include "sbitmap.h" +#include "diagnostic-event-id.h" +#include "stor-layout.h" #include "stringpool.h" -#include "convert.h" +#include "attribs.h" +#include "tree-object-size.h" +#include "gimple-ssa.h" +#include "tree-phinodes.h" +#include "tree-ssa-operands.h" +#include "ssa-iterators.h" #include "target.h" -#include "fold-const.h" +#include "calls.h" +#include "is-a.h" +#include "gcc-rich-location.h" +#include "gcc-urlifier.h" +#include "diagnostic-format-sarif.h" #include "tree-pretty-print.h" -#include "diagnostic-color.h" -#include "bitmap.h" -#include "selftest.h" +#include "fold-const.h" #include "selftest-tree.h" -#include "analyzer/analyzer.h" + +#include "text-art/tree-widget.h" + #include "analyzer/analyzer-logging.h" -#include "ordered-hash-map.h" -#include "options.h" -#include "cgraph.h" -#include "cfg.h" #include "analyzer/supergraph.h" -#include "sbitmap.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/constraint-manager.h" -#include "diagnostic-event-id.h" -#include "analyzer/sm.h" -#include "diagnostic-event-id.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/region-model-reachability.h" #include "analyzer/analyzer-selftests.h" #include "analyzer/program-state.h" #include "analyzer/call-summary.h" -#include "stor-layout.h" -#include "attribs.h" -#include "tree-object-size.h" -#include "gimple-ssa.h" -#include "tree-phinodes.h" -#include "tree-ssa-operands.h" -#include "ssa-iterators.h" -#include "calls.h" -#include "is-a.h" -#include "gcc-rich-location.h" #include "analyzer/checker-event.h" #include "analyzer/checker-path.h" #include "analyzer/feasible-graph.h" #include "analyzer/record-layout.h" -#include "diagnostic-format-sarif.h" -#include "text-art/tree-widget.h" -#include "gcc-urlifier.h" +#include "analyzer/function-set.h" #if ENABLE_ANALYZER @@ -235,7 +218,7 @@ region_to_value_map::dump (bool simple) const std::unique_ptr<json::object> region_to_value_map::to_json () const { - auto map_obj = ::make_unique<json::object> (); + auto map_obj = std::make_unique<json::object> (); auto_vec<const region *> regs; for (iterator iter = begin (); iter != end (); ++iter) @@ -332,12 +315,97 @@ region_to_value_map::purge_state_involving (const svalue *sval) m_hash_map.remove (iter); } +// struct exception_node + +bool +exception_node::operator== (const exception_node &other) const +{ + return (m_exception_sval == other.m_exception_sval + && m_typeinfo_sval == other.m_typeinfo_sval + && m_destructor_sval == other.m_destructor_sval); +} + +void +exception_node::dump_to_pp (pretty_printer *pp, + bool simple) const +{ + pp_printf (pp, "{exception: "); + m_exception_sval->dump_to_pp (pp, simple); + pp_string (pp, ", typeinfo: "); + m_typeinfo_sval->dump_to_pp (pp, simple); + pp_string (pp, ", destructor: "); + m_destructor_sval->dump_to_pp (pp, simple); + pp_string (pp, "}"); +} + +void +exception_node::dump (FILE *fp, bool simple) const +{ + tree_dump_pretty_printer pp (fp); + dump_to_pp (&pp, simple); + pp_newline (&pp); +} + +/* Dump a multiline representation of this model to stderr. */ + +DEBUG_FUNCTION void +exception_node::dump (bool simple) const +{ + dump (stderr, simple); +} + +DEBUG_FUNCTION void +exception_node::dump () const +{ + text_art::dump (*this); +} + +std::unique_ptr<json::object> +exception_node::to_json () const +{ + auto obj = std::make_unique<json::object> (); + obj->set ("exception", m_exception_sval->to_json ()); + obj->set ("typeinfo", m_typeinfo_sval->to_json ()); + obj->set ("destructor", m_destructor_sval->to_json ()); + return obj; +} + +std::unique_ptr<text_art::tree_widget> +exception_node::make_dump_widget (const text_art::dump_widget_info &dwi) const +{ + using text_art::tree_widget; + std::unique_ptr<tree_widget> w + (tree_widget::from_fmt (dwi, nullptr, "Exception Node")); + + w->add_child (m_exception_sval->make_dump_widget (dwi, "exception")); + w->add_child (m_typeinfo_sval->make_dump_widget (dwi, "typeinfo")); + w->add_child (m_destructor_sval->make_dump_widget (dwi, "destructor")); + + return w; +} + +tree +exception_node::maybe_get_type () const +{ + return m_typeinfo_sval->maybe_get_type_from_typeinfo (); +} + +void +exception_node::add_to_reachable_regions (reachable_regions ®s) const +{ + regs.handle_sval (m_exception_sval); + regs.handle_sval (m_typeinfo_sval); + regs.handle_sval (m_destructor_sval); +} + /* class region_model. */ /* Ctor for region_model: construct an "empty" model. */ region_model::region_model (region_model_manager *mgr) : m_mgr (mgr), m_store (), m_current_frame (NULL), + m_thrown_exceptions_stack (), + m_caught_exceptions_stack (), m_dynamic_extents () { m_constraints = new constraint_manager (mgr); @@ -349,6 +417,8 @@ region_model::region_model (const region_model &other) : m_mgr (other.m_mgr), m_store (other.m_store), m_constraints (new constraint_manager (*other.m_constraints)), m_current_frame (other.m_current_frame), + m_thrown_exceptions_stack (other.m_thrown_exceptions_stack), + m_caught_exceptions_stack (other.m_caught_exceptions_stack), m_dynamic_extents (other.m_dynamic_extents) { } @@ -375,6 +445,9 @@ region_model::operator= (const region_model &other) m_current_frame = other.m_current_frame; + m_thrown_exceptions_stack = other.m_thrown_exceptions_stack; + m_caught_exceptions_stack = other.m_caught_exceptions_stack; + m_dynamic_extents = other.m_dynamic_extents; return *this; @@ -401,6 +474,11 @@ region_model::operator== (const region_model &other) const if (m_current_frame != other.m_current_frame) return false; + if (m_thrown_exceptions_stack != other.m_thrown_exceptions_stack) + return false; + if (m_caught_exceptions_stack != other.m_caught_exceptions_stack) + return false; + if (m_dynamic_extents != other.m_dynamic_extents) return false; @@ -427,7 +505,7 @@ void region_model::dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const { - /* Dump stack. */ + /* Dump frame stack. */ pp_printf (pp, "stack depth: %i", get_stack_depth ()); if (multiline) pp_newline (pp); @@ -448,6 +526,50 @@ region_model::dump_to_pp (pretty_printer *pp, bool simple, if (!multiline) pp_string (pp, "}"); + /* Dump exception stacks. */ + if (m_thrown_exceptions_stack.size () > 0) + { + pp_printf (pp, "thrown exceptions: %i", (int)m_thrown_exceptions_stack.size ()); + if (multiline) + pp_newline (pp); + else + pp_string (pp, " {"); + for (size_t idx = 0; idx < m_thrown_exceptions_stack.size (); ++idx) + { + if (multiline) + pp_string (pp, " "); + else if (idx > 0) + pp_string (pp, ", "); + pp_printf (pp, "exception (index %i): ", (int)idx); + m_thrown_exceptions_stack[idx].dump_to_pp (pp, simple); + if (multiline) + pp_newline (pp); + } + if (!multiline) + pp_string (pp, "}"); + } + if (m_caught_exceptions_stack.size () > 0) + { + pp_printf (pp, "caught exceptions: %i", (int)m_caught_exceptions_stack.size ()); + if (multiline) + pp_newline (pp); + else + pp_string (pp, " {"); + for (size_t idx = 0; idx < m_caught_exceptions_stack.size (); ++idx) + { + if (multiline) + pp_string (pp, " "); + else if (idx > 0) + pp_string (pp, ", "); + pp_printf (pp, "exception (index %i): ", (int)idx); + m_caught_exceptions_stack[idx].dump_to_pp (pp, simple); + if (multiline) + pp_newline (pp); + } + if (!multiline) + pp_string (pp, "}"); + } + /* Dump store. */ if (!multiline) pp_string (pp, ", {"); @@ -515,11 +637,22 @@ region_model::debug () const std::unique_ptr<json::object> region_model::to_json () const { - auto model_obj = ::make_unique<json::object> (); + auto model_obj = std::make_unique<json::object> (); model_obj->set ("store", m_store.to_json ()); model_obj->set ("constraints", m_constraints->to_json ()); if (m_current_frame) model_obj->set ("current_frame", m_current_frame->to_json ()); + + auto thrown_exceptions_arr = std::make_unique<json::array> (); + for (auto &node : m_thrown_exceptions_stack) + thrown_exceptions_arr->append (node.to_json ()); + model_obj->set ("thrown_exception_stack", std::move (thrown_exceptions_arr)); + + auto caught_exceptions_arr = std::make_unique<json::array> (); + for (auto &node : m_caught_exceptions_stack) + caught_exceptions_arr->append (node.to_json ()); + model_obj->set ("caught_exception_stack", std::move (caught_exceptions_arr)); + model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ()); return model_obj; } @@ -543,6 +676,26 @@ region_model::make_dump_widget (const text_art::dump_widget_info &dwi) const m_current_frame->dump_to_pp (pp, simple); model_widget->add_child (tree_widget::make (dwi, pp)); } + + if (m_thrown_exceptions_stack.size () > 0) + { + auto thrown_exceptions_widget + = tree_widget::make (dwi, "Thrown Exceptions"); + for (auto &thrown_exception : m_thrown_exceptions_stack) + thrown_exceptions_widget->add_child + (thrown_exception.make_dump_widget (dwi)); + model_widget->add_child (std::move (thrown_exceptions_widget)); + } + if (m_caught_exceptions_stack.size () > 0) + { + auto caught_exceptions_widget + = tree_widget::make (dwi, "Caught Exceptions"); + for (auto &caught_exception : m_caught_exceptions_stack) + caught_exceptions_widget->add_child + (caught_exception.make_dump_widget (dwi)); + model_widget->add_child (std::move (caught_exceptions_widget)); + } + model_widget->add_child (m_store.make_dump_widget (dwi, m_mgr->get_store_manager ())); @@ -606,7 +759,7 @@ public: bool use_of_uninit_p () const final override { - return m_pkind == POISON_KIND_UNINIT; + return m_pkind == poison_kind::uninit; } bool operator== (const poisoned_value_diagnostic &other) const @@ -622,12 +775,12 @@ public: { default: gcc_unreachable (); - case POISON_KIND_UNINIT: + case poison_kind::uninit: return OPT_Wanalyzer_use_of_uninitialized_value; - case POISON_KIND_FREED: - case POISON_KIND_DELETED: + case poison_kind::freed: + case poison_kind::deleted: return OPT_Wanalyzer_use_after_free; - case POISON_KIND_POPPED_STACK: + case poison_kind::popped_stack: return OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame; } } @@ -640,28 +793,28 @@ public: { default: gcc_unreachable (); - case POISON_KIND_UNINIT: + case poison_kind::uninit: { ctxt.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable". */ return ctxt.warn ("use of uninitialized value %qE", m_expr); } break; - case POISON_KIND_FREED: + case poison_kind::freed: { ctxt.add_cwe (416); /* "CWE-416: Use After Free". */ return ctxt.warn ("use after %<free%> of %qE", m_expr); } break; - case POISON_KIND_DELETED: + case poison_kind::deleted: { ctxt.add_cwe (416); /* "CWE-416: Use After Free". */ return ctxt.warn ("use after %<delete%> of %qE", m_expr); } break; - case POISON_KIND_POPPED_STACK: + case poison_kind::popped_stack: { /* TODO: which CWE? */ return ctxt.warn @@ -680,28 +833,28 @@ public: { default: gcc_unreachable (); - case POISON_KIND_UNINIT: + case poison_kind::uninit: { pp_printf (&pp, "use of uninitialized value %qE here", m_expr); return true; } - case POISON_KIND_FREED: + case poison_kind::freed: { pp_printf (&pp, "use after %<free%> of %qE here", m_expr); return true; } - case POISON_KIND_DELETED: + case poison_kind::deleted: { pp_printf (&pp, "use after %<delete%> of %qE here", m_expr); return true; } - case POISON_KIND_POPPED_STACK: + case poison_kind::popped_stack: { pp_printf (&pp, "dereferencing pointer %qE to within stale stack frame", @@ -956,10 +1109,10 @@ public: { if (reg == m_base_reg_a) emission_path.add_event - (make_unique<ptrdiff_region_creation_event> (loc_info, true)); + (std::make_unique<ptrdiff_region_creation_event> (loc_info, true)); else if (reg == m_base_reg_b) emission_path.add_event - (make_unique<ptrdiff_region_creation_event> (loc_info, false)); + (std::make_unique<ptrdiff_region_creation_event> (loc_info, false)); } bool @@ -1009,11 +1162,12 @@ check_for_invalid_ptrdiff (const gassign *assign, if (base_reg_b->get_kind () == RK_SYMBOLIC) return; - ctxt.warn (make_unique<undefined_ptrdiff_diagnostic> (assign, - sval_a, - sval_b, - base_reg_a, - base_reg_b)); + ctxt.warn + (std::make_unique<undefined_ptrdiff_diagnostic> (assign, + sval_a, + sval_b, + base_reg_a, + base_reg_b)); } /* If ASSIGN is a stmt that can be modelled via @@ -1192,13 +1346,13 @@ region_model::get_gassign_result (const gassign *assign, { if (tree_int_cst_sgn (rhs2_cst) < 0) ctxt->warn - (make_unique<shift_count_negative_diagnostic> + (std::make_unique<shift_count_negative_diagnostic> (assign, rhs2_cst)); else if (compare_tree_int (rhs2_cst, TYPE_PRECISION (TREE_TYPE (rhs1))) >= 0) ctxt->warn - (make_unique<shift_count_overflow_diagnostic> + (std::make_unique<shift_count_overflow_diagnostic> (assign, int (TYPE_PRECISION (TREE_TYPE (rhs1))), rhs2_cst)); @@ -1392,12 +1546,12 @@ region_model::check_for_poison (const svalue *sval, /* Ignore uninitialized uses of empty types; there's nothing to initialize. */ - if (pkind == POISON_KIND_UNINIT + if (pkind == poison_kind::uninit && sval->get_type () && is_empty_type (sval->get_type ())) return sval; - if (pkind == POISON_KIND_UNINIT) + if (pkind == poison_kind::uninit) if (const gimple *curr_stmt = ctxt->get_stmt ()) if (const gassign *assign_stmt = dyn_cast <const gassign *> (curr_stmt)) @@ -1418,7 +1572,7 @@ region_model::check_for_poison (const svalue *sval, the tree other than via the def stmts, using fixup_tree_for_diagnostic. */ tree diag_arg = fixup_tree_for_diagnostic (expr); - if (src_region == NULL && pkind == POISON_KIND_UNINIT) + if (src_region == NULL && pkind == poison_kind::uninit) src_region = get_region_for_poisoned_expr (expr); /* Can we reliably get the poisoned value from "expr"? @@ -1432,10 +1586,11 @@ region_model::check_for_poison (const svalue *sval, check_expr = expr; else check_expr = NULL; - if (ctxt->warn (make_unique<poisoned_value_diagnostic> (diag_arg, - pkind, - src_region, - check_expr))) + if (ctxt->warn + (std::make_unique<poisoned_value_diagnostic> (diag_arg, + pkind, + src_region, + check_expr))) { /* We only want to report use of a poisoned value at the first place it gets used; return an unknown value to avoid generating @@ -1570,13 +1725,15 @@ region_model::on_stmt_pre (const gimple *stmt, { switch (gimple_code (stmt)) { - default: - /* No-op for now. */ - break; - - case GIMPLE_DEBUG: - /* We should have stripped these out when building the supergraph. */ - gcc_unreachable (); + case GIMPLE_COND: + case GIMPLE_EH_DISPATCH: + case GIMPLE_GOTO: + case GIMPLE_LABEL: + case GIMPLE_NOP: + case GIMPLE_PREDICT: + case GIMPLE_RESX: + case GIMPLE_SWITCH: + /* No-ops here. */ break; case GIMPLE_ASSIGN: @@ -1601,7 +1758,7 @@ region_model::on_stmt_pre (const gimple *stmt, anything, for which we don't have a function body, or for which we don't know the fndecl. */ const gcall *call = as_a <const gcall *> (stmt); - *out_unknown_side_effects = on_call_pre (call, ctxt); + *out_unknown_side_effects = on_call_pre (*call, ctxt); } break; @@ -1611,6 +1768,13 @@ region_model::on_stmt_pre (const gimple *stmt, on_return (return_, ctxt); } break; + + /* We don't expect to see any other statement kinds in the analyzer. */ + case GIMPLE_DEBUG: // should have stripped these out when building the supergraph + default: + internal_error ("unexpected gimple stmt code: %qs", + gimple_code_name[gimple_code (stmt)]); + break; } } @@ -1689,7 +1853,7 @@ region_model::check_call_format_attr (const call_details &cd, }; call_arg_details arg_details (m_cd, m_fmt_param_idx); - add_note (make_unique<reason_format_attr> (arg_details)); + add_note (std::make_unique<reason_format_attr> (arg_details)); } private: const call_details &m_cd; @@ -1898,7 +2062,7 @@ region_model::get_known_function (enum internal_fn ifn) const attributes. */ const builtin_known_function * -region_model::get_builtin_kf (const gcall *call, +region_model::get_builtin_kf (const gcall &call, region_model_context *ctxt /* = NULL */) const { region_model *mut_this = const_cast <region_model *> (this); @@ -1913,6 +2077,170 @@ region_model::get_builtin_kf (const gcall *call, return NULL; } +/* Subclass of custom_edge_info for use by exploded_edges that represent + an exception being thrown from a call we don't have the code for. */ + +class exception_thrown_from_unrecognized_call : public custom_edge_info +{ +public: + exception_thrown_from_unrecognized_call (const gcall &call, + tree fndecl) + : m_call (call), + m_fndecl (fndecl) + { + } + + void print (pretty_printer *pp) const + { + if (m_fndecl) + pp_printf (pp, "if %qD throws an exception...", m_fndecl); + else + pp_printf (pp, "if the called function throws an exception..."); + }; + + bool + update_model (region_model *model, + const exploded_edge *, + region_model_context *ctxt) const final override + { + /* Allocate an exception and set it as the current exception. */ + const region *exception_reg + = model->get_or_create_region_for_heap_alloc + (nullptr, /* We don't know the size of the region. */ + ctxt); + + region_model_manager *mgr = model->get_manager (); + conjured_purge p (model, ctxt); + + /* The contents of the region are some conjured svalue. */ + const svalue *exception_sval + = mgr->get_or_create_conjured_svalue (NULL_TREE, + &m_call, + exception_reg, p, 0); + model->set_value (exception_reg, exception_sval, ctxt); + const svalue *exception_ptr_sval + = mgr->get_ptr_svalue (ptr_type_node, exception_reg); + const svalue *tinfo_sval + = mgr->get_or_create_conjured_svalue (ptr_type_node, + &m_call, + exception_reg, p, 1); + const svalue *destructor_sval + = mgr->get_or_create_conjured_svalue (ptr_type_node, + &m_call, + exception_reg, p, 2); + + /* Push a new exception_node on the model's thrown exception stack. */ + exception_node eh_node (exception_ptr_sval, tinfo_sval, destructor_sval); + model->push_thrown_exception (eh_node); + + return true; + } + + void + add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) const final override + { + const exploded_node *dst_node = eedge.m_dest; + const program_point &dst_point = dst_node->get_point (); + const int dst_stack_depth = dst_point.get_stack_depth (); + + emission_path->add_event + (std::make_unique<throw_from_call_to_external_fn_event> + (event_loc_info (m_call.location, + dst_point.get_fndecl (), + dst_stack_depth), + dst_node, + m_call, + m_fndecl)); + } + + exploded_node * + create_enode (exploded_graph &eg, + const program_point &point, + program_state &&state, + exploded_node *enode_for_diag, + region_model_context *ctxt) const final override + { + exploded_node *thrown_enode + = eg.get_or_create_node (point, state, enode_for_diag, + /* Don't add to worklist. */ + false); + if (!thrown_enode) + return nullptr; + + /* Add successor edges for thrown_enode "by hand" for the exception. */ + eg.unwind_from_exception (*thrown_enode, + &m_call, + ctxt); + return thrown_enode; + } + +private: + const gcall &m_call; + tree m_fndecl; // could be null +}; + +/* Get a set of functions that are assumed to not throw exceptions. */ + +static function_set +get_fns_assumed_not_to_throw () +{ + // TODO: populate this list more fully + static const char * const fn_names[] = { + /* This array must be kept sorted. */ + + "fclose" + }; + const size_t count = ARRAY_SIZE (fn_names); + function_set fs (fn_names, count); + return fs; +} + +/* Return true if CALL could throw an exception. + FNDECL could be NULL_TREE. */ + +static bool +can_throw_p (const gcall &call, tree fndecl) +{ + if (!flag_exceptions) + return false; + + if (gimple_call_nothrow_p (&call)) + return false; + + if (fndecl) + { + const function_set fs = get_fns_assumed_not_to_throw (); + if (fs.contains_decl_p (fndecl)) + return false; + } + + return true; +} + +/* Given CALL where we don't know what code is being called + (by not having the body of FNDECL, or having NULL_TREE for FNDECL), + potentially bifurcate control flow to simulate the call throwing + an exception. */ + +void +region_model::check_for_throw_inside_call (const gcall &call, + tree fndecl, + region_model_context *ctxt) +{ + if (!ctxt) + return; + + /* Could this function throw an exception? + If so, add an extra e-edge for that. */ + if (!can_throw_p (call, fndecl)) + return; + + auto throws_exception + = std::make_unique<exception_thrown_from_unrecognized_call> (call, fndecl); + ctxt->bifurcate (std::move (throws_exception)); +} + /* Update this model for the CALL stmt, using CTXT to report any diagnostics - the first half. @@ -1925,7 +2253,7 @@ region_model::get_builtin_kf (const gcall *call, fndecl it is). */ bool -region_model::on_call_pre (const gcall *call, region_model_context *ctxt) +region_model::on_call_pre (const gcall &call, region_model_context *ctxt) { call_details cd (call, this, ctxt); @@ -1935,8 +2263,8 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) Handle IFN_DEFERRED_INIT by treating it as no-op: don't touch the lhs of the call, so that it is still uninitialized from the point of view of the analyzer. */ - if (gimple_call_internal_p (call) - && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT) + if (gimple_call_internal_p (&call) + && gimple_call_internal_fn (&call) == IFN_DEFERRED_INIT) return false; /* No side effects. */ /* Get svalues for all of the arguments at the callsite, to ensure that we @@ -1948,9 +2276,9 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) tree callee_fndecl = get_fndecl_for_call (call, ctxt); - if (gimple_call_internal_p (call)) + if (gimple_call_internal_p (&call)) if (const known_function *kf - = get_known_function (gimple_call_internal_fn (call))) + = get_known_function (gimple_call_internal_fn (&call))) { kf->impl_call_pre (cd); return false; /* No further side effects. */ @@ -1958,6 +2286,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) if (!callee_fndecl) { + check_for_throw_inside_call (call, NULL_TREE, ctxt); cd.set_any_lhs_with_defaults (); return true; /* Unknown side effects. */ } @@ -1978,7 +2307,10 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) return true; /* Unknown side effects. */ if (!fndecl_has_gimple_body_p (callee_fndecl)) - return true; /* Unknown side effects. */ + { + check_for_throw_inside_call (call, callee_fndecl, ctxt); + return true; /* Unknown side effects. */ + } return false; /* No side effects. */ } @@ -1994,7 +2326,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt) to purge state. */ void -region_model::on_call_post (const gcall *call, +region_model::on_call_post (const gcall &call, bool unknown_side_effects, region_model_context *ctxt) { @@ -2102,12 +2434,11 @@ private: attribute. */ void -region_model::check_function_attr_access (const gcall *call, +region_model::check_function_attr_access (const gcall &call, tree callee_fndecl, region_model_context *ctxt, rdwr_map &rdwr_idx) const { - gcc_assert (call); gcc_assert (callee_fndecl); gcc_assert (ctxt); @@ -2145,8 +2476,8 @@ region_model::check_function_attr_access (const gcall *call, } void add_annotations () final override { - add_note (make_unique<reason_attr_access> - (m_callee_fndecl, m_access)); + add_note (std::make_unique<reason_attr_access> + (m_callee_fndecl, m_access)); } private: tree m_callee_fndecl; @@ -2157,7 +2488,7 @@ region_model::check_function_attr_access (const gcall *call, note added to them. */ annotating_ctxt my_ctxt (callee_fndecl, *access, ctxt); - tree ptr_tree = gimple_call_arg (call, access->ptrarg); + tree ptr_tree = gimple_call_arg (&call, access->ptrarg); const svalue *ptr_sval = get_rvalue (ptr_tree, &my_ctxt); const region *reg = deref_rvalue (ptr_sval, ptr_tree, &my_ctxt); check_region_for_write (reg, nullptr, &my_ctxt); @@ -2171,13 +2502,12 @@ region_model::check_function_attr_access (const gcall *call, void region_model:: -check_one_function_attr_null_terminated_string_arg (const gcall *call, +check_one_function_attr_null_terminated_string_arg (const gcall &call, tree callee_fndecl, region_model_context *ctxt, rdwr_map &rdwr_idx, tree attr) { - gcc_assert (call); gcc_assert (callee_fndecl); gcc_assert (ctxt); gcc_assert (attr); @@ -2245,12 +2575,11 @@ check_one_function_attr_null_terminated_string_arg (const gcall *call, void region_model:: -check_function_attr_null_terminated_string_arg (const gcall *call, +check_function_attr_null_terminated_string_arg (const gcall &call, tree callee_fndecl, region_model_context *ctxt, rdwr_map &rdwr_idx) { - gcc_assert (call); gcc_assert (callee_fndecl); gcc_assert (ctxt); @@ -2275,11 +2604,10 @@ check_function_attr_null_terminated_string_arg (const gcall *call, function attributes, complaining to CTXT about any issues. */ void -region_model::check_function_attrs (const gcall *call, +region_model::check_function_attrs (const gcall &call, tree callee_fndecl, region_model_context *ctxt) { - gcc_assert (call); gcc_assert (callee_fndecl); gcc_assert (ctxt); @@ -2310,7 +2638,7 @@ region_model::check_function_attrs (const gcall *call, from their values, and from values that point to them. */ void -region_model::handle_unrecognized_call (const gcall *call, +region_model::handle_unrecognized_call (const gcall &call, region_model_context *ctxt) { tree fndecl = get_fndecl_for_call (call, ctxt); @@ -2331,7 +2659,8 @@ region_model::handle_unrecognized_call (const gcall *call, tree iter_param_types = NULL_TREE; if (fndecl) iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); - for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++) + for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call); + arg_idx++) { /* Track expected param type, where available. */ tree param_type = NULL_TREE; @@ -2342,7 +2671,7 @@ region_model::handle_unrecognized_call (const gcall *call, iter_param_types = TREE_CHAIN (iter_param_types); } - tree parm = gimple_call_arg (call, arg_idx); + tree parm = gimple_call_arg (&call, arg_idx); const svalue *parm_sval = get_rvalue (parm, ctxt); reachable_regs.handle_parm (parm_sval, param_type); } @@ -2466,11 +2795,11 @@ region_model::on_return (const greturn *return_stmt, region_model_context *ctxt) 0), as opposed to any second return due to longjmp/sigsetjmp. */ void -region_model::on_setjmp (const gcall *call, const exploded_node *enode, +region_model::on_setjmp (const gcall &call, const exploded_node *enode, region_model_context *ctxt) { - const svalue *buf_ptr = get_rvalue (gimple_call_arg (call, 0), ctxt); - const region *buf_reg = deref_rvalue (buf_ptr, gimple_call_arg (call, 0), + const svalue *buf_ptr = get_rvalue (gimple_call_arg (&call, 0), ctxt); + const region *buf_reg = deref_rvalue (buf_ptr, gimple_call_arg (&call, 0), ctxt); /* Create a setjmp_svalue for this call and store it in BUF_REG's @@ -2484,7 +2813,7 @@ region_model::on_setjmp (const gcall *call, const exploded_node *enode, } /* Direct calls to setjmp return 0. */ - if (tree lhs = gimple_call_lhs (call)) + if (tree lhs = gimple_call_lhs (&call)) { const svalue *new_sval = m_mgr->get_or_create_int_cst (TREE_TYPE (lhs), 0); @@ -2499,11 +2828,11 @@ region_model::on_setjmp (const gcall *call, const exploded_node *enode, done, and should be done by the caller. */ void -region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call, +region_model::on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call, int setjmp_stack_depth, region_model_context *ctxt) { /* Evaluate the val, using the frame of the "longjmp". */ - tree fake_retval = gimple_call_arg (longjmp_call, 1); + tree fake_retval = gimple_call_arg (&longjmp_call, 1); const svalue *fake_retval_sval = get_rvalue (fake_retval, ctxt); /* Pop any frames until we reach the stack depth of the function where @@ -2515,7 +2844,7 @@ region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call, gcc_assert (get_stack_depth () == setjmp_stack_depth); /* Assign to LHS of "setjmp" in new_state. */ - if (tree lhs = gimple_call_lhs (setjmp_call)) + if (tree lhs = gimple_call_lhs (&setjmp_call)) { /* Passing 0 as the val to longjmp leads to setjmp returning 1. */ const svalue *zero_sval @@ -3092,7 +3421,7 @@ region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree, const poisoned_svalue *poisoned_sval = as_a <const poisoned_svalue *> (ptr_sval); enum poison_kind pkind = poisoned_sval->get_poison_kind (); - ctxt->warn (::make_unique<poisoned_value_diagnostic> + ctxt->warn (std::make_unique<poisoned_value_diagnostic> (ptr, pkind, nullptr, nullptr)); } } @@ -3263,16 +3592,18 @@ region_model::check_for_writable_region (const region* dest_reg, { const function_region *func_reg = as_a <const function_region *> (base_reg); tree fndecl = func_reg->get_fndecl (); - ctxt->warn (make_unique<write_to_const_diagnostic> - (func_reg, fndecl)); + ctxt->warn + (std::make_unique<write_to_const_diagnostic> + (func_reg, fndecl)); } break; case RK_LABEL: { const label_region *label_reg = as_a <const label_region *> (base_reg); tree label = label_reg->get_label (); - ctxt->warn (make_unique<write_to_const_diagnostic> - (label_reg, label)); + ctxt->warn + (std::make_unique<write_to_const_diagnostic> + (label_reg, label)); } break; case RK_DECL: @@ -3285,11 +3616,13 @@ region_model::check_for_writable_region (const region* dest_reg, "this" param is "T* const"). */ if (TREE_READONLY (decl) && is_global_var (decl)) - ctxt->warn (make_unique<write_to_const_diagnostic> (dest_reg, decl)); + ctxt->warn + (std::make_unique<write_to_const_diagnostic> (dest_reg, decl)); } break; case RK_STRING: - ctxt->warn (make_unique<write_to_string_literal_diagnostic> (dest_reg)); + ctxt->warn + (std::make_unique<write_to_string_literal_diagnostic> (dest_reg)); break; } } @@ -3367,10 +3700,10 @@ region_model::check_region_access (const region *reg, { default: gcc_unreachable (); - case DIR_READ: + case access_direction::read: /* Currently a no-op. */ break; - case DIR_WRITE: + case access_direction::write: check_for_writable_region (reg, ctxt); break; } @@ -3384,7 +3717,7 @@ region_model::check_region_for_write (const region *dest_reg, const svalue *sval_hint, region_model_context *ctxt) const { - check_region_access (dest_reg, DIR_WRITE, sval_hint, ctxt); + check_region_access (dest_reg, access_direction::write, sval_hint, ctxt); } /* If CTXT is non-NULL, use it to warn about any problems reading from REG. @@ -3394,7 +3727,7 @@ bool region_model::check_region_for_read (const region *src_reg, region_model_context *ctxt) const { - return check_region_access (src_reg, DIR_READ, NULL, ctxt); + return check_region_access (src_reg, access_direction::read, NULL, ctxt); } /* Concrete subclass for casts of pointers that lead to trailing bytes. */ @@ -3491,7 +3824,8 @@ public: checker_path &emission_path) final override { emission_path.add_event - (make_unique<region_creation_event_allocation_size> (capacity, loc_info)); + (std::make_unique<region_creation_event_allocation_size> + (capacity, loc_info)); m_has_allocation_event = true; } @@ -3827,9 +4161,10 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, if (TREE_CODE (cst_cap) == INTEGER_CST && !capacity_compatible_with_type (cst_cap, pointee_size_tree, is_struct)) - ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg, rhs_reg, - capacity, cst_cap, - ctxt->get_stmt ())); + ctxt->warn + (std::make_unique <dubious_allocation_size> (lhs_reg, rhs_reg, + capacity, cst_cap, + ctxt->get_stmt ())); } break; default: @@ -3841,10 +4176,11 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, m_constraints)) { tree expr = get_representative_tree (capacity); - ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg, - rhs_reg, - capacity, expr, - ctxt->get_stmt ())); + ctxt->warn + (std::make_unique <dubious_allocation_size> (lhs_reg, + rhs_reg, + capacity, expr, + ctxt->get_stmt ())); } } break; @@ -4637,9 +4973,11 @@ region_model::check_for_null_terminated_string_arg (const call_details &cd, m_cd.get_model ()->get_current_function ()->decl, m_cd.get_model ()->get_stack_depth ()); - add_event (make_unique<null_terminator_check_event> (loc_info, - arg_details)); - add_note (make_unique <null_terminator_check_decl_note> (arg_details)); + add_event + (std::make_unique<null_terminator_check_event> (loc_info, + arg_details)); + add_note + (std::make_unique <null_terminator_check_decl_note> (arg_details)); } private: const call_details &m_cd; @@ -5385,7 +5723,7 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs, { bool sat = add_constraint (lhs, op, rhs, ctxt); if (!sat && out) - *out = make_unique <rejected_op_constraint> (*this, lhs, op, rhs); + *out = std::make_unique <rejected_op_constraint> (*this, lhs, op, rhs); return sat; } @@ -5885,17 +6223,22 @@ region_model::maybe_update_for_edge (const superedge &edge, ctxt, out); } + if (const geh_dispatch *eh_dispatch_stmt + = dyn_cast <const geh_dispatch *> (last_stmt)) + { + const eh_dispatch_cfg_superedge *eh_dispatch_cfg_sedge + = as_a <const eh_dispatch_cfg_superedge *> (&edge); + return apply_constraints_for_eh_dispatch (*eh_dispatch_cfg_sedge, + eh_dispatch_stmt, + ctxt, out); + } + if (const ggoto *goto_stmt = dyn_cast <const ggoto *> (last_stmt)) { const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge); return apply_constraints_for_ggoto (*cfg_sedge, goto_stmt, ctxt); } - /* Apply any constraints due to an exception being thrown. */ - if (const cfg_superedge *cfg_sedge = dyn_cast <const cfg_superedge *> (&edge)) - if (cfg_sedge->get_flags () & EDGE_EH) - return apply_constraints_for_exception (last_stmt, ctxt, out); - return true; } @@ -5905,29 +6248,29 @@ region_model::maybe_update_for_edge (const superedge &edge, caller's frame. */ void -region_model::update_for_gcall (const gcall *call_stmt, +region_model::update_for_gcall (const gcall &call_stmt, region_model_context *ctxt, function *callee) { /* Build a vec of argument svalues, using the current top frame for resolving tree expressions. */ - auto_vec<const svalue *> arg_svals (gimple_call_num_args (call_stmt)); + auto_vec<const svalue *> arg_svals (gimple_call_num_args (&call_stmt)); - for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++) + for (unsigned i = 0; i < gimple_call_num_args (&call_stmt); i++) { - tree arg = gimple_call_arg (call_stmt, i); + tree arg = gimple_call_arg (&call_stmt, i); arg_svals.quick_push (get_rvalue (arg, ctxt)); } if(!callee) { /* Get the function * from the gcall. */ - tree fn_decl = get_fndecl_for_call (call_stmt,ctxt); + tree fn_decl = get_fndecl_for_call (call_stmt, ctxt); callee = DECL_STRUCT_FUNCTION (fn_decl); } gcc_assert (callee); - push_frame (*callee, &arg_svals, ctxt); + push_frame (*callee, &call_stmt, &arg_svals, ctxt); } /* Pop the top-most frame_region from the stack, and copy the return @@ -5935,14 +6278,14 @@ region_model::update_for_gcall (const gcall *call_stmt, the call (if any). */ void -region_model::update_for_return_gcall (const gcall *call_stmt, +region_model::update_for_return_gcall (const gcall &call_stmt, region_model_context *ctxt) { /* Get the lvalue for the result of the call, passing it to pop_frame, so that pop_frame can determine the region with respect to the *caller* frame. */ - tree lhs = gimple_call_lhs (call_stmt); - pop_frame (lhs, NULL, ctxt, call_stmt); + tree lhs = gimple_call_lhs (&call_stmt); + pop_frame (lhs, NULL, ctxt, &call_stmt); } /* Extract calling information from the superedge and update the model for the @@ -5952,7 +6295,7 @@ void region_model::update_for_call_superedge (const call_superedge &call_edge, region_model_context *ctxt) { - const gcall *call_stmt = call_edge.get_call_stmt (); + const gcall &call_stmt = call_edge.get_call_stmt (); update_for_gcall (call_stmt, ctxt, call_edge.get_callee_function ()); } @@ -5963,7 +6306,7 @@ void region_model::update_for_return_superedge (const return_superedge &return_edge, region_model_context *ctxt) { - const gcall *call_stmt = return_edge.get_call_stmt (); + const gcall &call_stmt = return_edge.get_call_stmt (); update_for_return_gcall (call_stmt, ctxt); } @@ -6156,7 +6499,7 @@ apply_constraints_for_gswitch (const switch_cfg_superedge &edge, && !ctxt->possibly_tainted_p (index_sval)) { if (out) - *out = make_unique <rejected_default_case> (*this); + *out = std::make_unique <rejected_default_case> (*this); return false; } @@ -6165,12 +6508,180 @@ apply_constraints_for_gswitch (const switch_cfg_superedge &edge, = ranges_mgr->get_or_create_ranges_for_switch (&edge, switch_stmt); bool sat = m_constraints->add_bounded_ranges (index_sval, all_cases_ranges); if (!sat && out) - *out = make_unique <rejected_ranges_constraint> (*this, index, all_cases_ranges); + *out = std::make_unique <rejected_ranges_constraint> + (*this, index, all_cases_ranges); if (sat && ctxt && !all_cases_ranges->empty_p ()) ctxt->on_bounded_ranges (*index_sval, *all_cases_ranges); return sat; } +class rejected_eh_dispatch : public rejected_constraint +{ +public: + rejected_eh_dispatch (const region_model &model) + : rejected_constraint (model) + {} + + void dump_to_pp (pretty_printer *pp) const final override + { + pp_printf (pp, "rejected_eh_dispatch"); + } +}; + +static bool +exception_matches_type_p (tree exception_type, + tree catch_type) +{ + if (catch_type == exception_type) + return true; + + /* TODO (PR analyzer/119697): we should also handle subclasses etc; + see the rules in https://en.cppreference.com/w/cpp/language/catch + + It looks like we should be calling (or emulating) + can_convert_eh from the C++ FE, but that's specific to the C++ FE. */ + + return false; +} + +static bool +matches_any_exception_type_p (eh_catch ehc, tree exception_type) +{ + if (ehc->type_list == NULL_TREE) + /* All exceptions are caught here. */ + return true; + + for (tree iter = ehc->type_list; iter; iter = TREE_CHAIN (iter)) + if (exception_matches_type_p (TREE_VALUE (iter), + exception_type)) + return true; + return false; +} + +bool +region_model:: +apply_constraints_for_eh_dispatch (const eh_dispatch_cfg_superedge &edge, + const geh_dispatch *, + region_model_context *ctxt, + std::unique_ptr<rejected_constraint> *out) +{ + const exception_node *current_node = get_current_thrown_exception (); + gcc_assert (current_node); + tree curr_exception_type = current_node->maybe_get_type (); + if (!curr_exception_type) + /* We don't know the specific type. */ + return true; + + return edge.apply_constraints (this, ctxt, curr_exception_type, out); +} + +bool +region_model:: +apply_constraints_for_eh_dispatch_try (const eh_dispatch_try_cfg_superedge &edge, + region_model_context */*ctxt*/, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) +{ + /* TODO: can we rely on this ordering? + or do we need to iterate through prev_catch ? */ + /* The exception must not match any of the previous edges. */ + for (auto sibling_sedge : edge.m_src->m_succs) + { + if (sibling_sedge == &edge) + break; + + const eh_dispatch_try_cfg_superedge *sibling_eh_sedge + = as_a <const eh_dispatch_try_cfg_superedge *> (sibling_sedge); + if (eh_catch ehc = sibling_eh_sedge->get_eh_catch ()) + if (matches_any_exception_type_p (ehc, exception_type)) + { + /* The earlier sibling matches, so the "unhandled" edge is + not taken. */ + if (out) + *out = std::make_unique<rejected_eh_dispatch> (*this); + return false; + } + } + + if (eh_catch ehc = edge.get_eh_catch ()) + { + /* We have an edge that tried to match one or more types. */ + + /* The exception must not match any of the previous edges. */ + + /* It must match this type. */ + if (matches_any_exception_type_p (ehc, exception_type)) + return true; + else + { + /* Exception type doesn't match. */ + if (out) + *out = std::make_unique<rejected_eh_dispatch> (*this); + return false; + } + } + else + { + /* This is the "unhandled exception" edge. + If we get here then no sibling edges matched; + we will follow this edge. */ + return true; + } +} + +bool +region_model:: +apply_constraints_for_eh_dispatch_allowed (const eh_dispatch_allowed_cfg_superedge &edge, + region_model_context */*ctxt*/, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) +{ + auto curr_thrown_exception_node = get_current_thrown_exception (); + gcc_assert (curr_thrown_exception_node); + tree curr_exception_type = curr_thrown_exception_node->maybe_get_type (); + eh_region eh_reg = edge.get_eh_region (); + tree type_list = eh_reg->u.allowed.type_list; + + switch (edge.get_eh_kind ()) + { + default: + gcc_unreachable (); + case eh_dispatch_allowed_cfg_superedge::eh_kind::expected: + if (!curr_exception_type) + { + /* We don't know the specific type; + assume we have one of an expected type. */ + return true; + } + for (tree iter = type_list; iter; iter = TREE_CHAIN (iter)) + if (exception_matches_type_p (TREE_VALUE (iter), + exception_type)) + return true; + if (out) + *out = std::make_unique<rejected_eh_dispatch> (*this); + return false; + + case eh_dispatch_allowed_cfg_superedge::eh_kind::unexpected: + if (!curr_exception_type) + { + /* We don't know the specific type; + assume we don't have one of an expected type. */ + if (out) + *out = std::make_unique<rejected_eh_dispatch> (*this); + return false; + } + for (tree iter = type_list; iter; iter = TREE_CHAIN (iter)) + if (exception_matches_type_p (TREE_VALUE (iter), + exception_type)) + { + if (out) + *out = std::make_unique<rejected_eh_dispatch> (*this); + return false; + } + return true; + } +} + /* Given an edge reached by GOTO_STMT, determine appropriate constraints for the edge to be taken. @@ -6202,38 +6713,6 @@ region_model::apply_constraints_for_ggoto (const cfg_superedge &edge, return true; } -/* Apply any constraints due to an exception being thrown at LAST_STMT. - - If they are feasible, add the constraints and return true. - - Return false if the constraints contradict existing knowledge - (and so the edge should not be taken). - When returning false, if OUT is non-NULL, write a new rejected_constraint - to it. */ - -bool -region_model:: -apply_constraints_for_exception (const gimple *last_stmt, - region_model_context *ctxt, - std::unique_ptr<rejected_constraint> *out) -{ - gcc_assert (last_stmt); - if (const gcall *call = dyn_cast <const gcall *> (last_stmt)) - if (tree callee_fndecl = get_fndecl_for_call (call, ctxt)) - if (is_named_call_p (callee_fndecl, "operator new", call, 1) - || is_named_call_p (callee_fndecl, "operator new []", call, 1)) - { - /* We have an exception thrown from operator new. - Add a constraint that the result was NULL, to avoid a false - leak report due to the result being lost when following - the EH edge. */ - if (tree lhs = gimple_call_lhs (call)) - return add_constraint (lhs, EQ_EXPR, null_pointer_node, ctxt, out); - return true; - } - return true; -} - /* For use with push_frame when handling a top-level call within the analysis. PARAM has a defined but unknown initial value. Anything it points to has escaped, since the calling context "knows" @@ -6265,6 +6744,10 @@ region_model::on_top_level_param (tree param, /* Update this region_model to reflect pushing a frame onto the stack for a call to FUN. + If CALL_STMT is non-NULL, this is for the interprocedural case where + we already have an execution path into the caller. It can be NULL for + top-level entrypoints into the analysis, or in selftests. + If ARG_SVALS is non-NULL, use it to populate the parameters in the new frame. Otherwise, the params have their initial_svalues. @@ -6273,14 +6756,32 @@ region_model::on_top_level_param (tree param, const region * region_model::push_frame (const function &fun, + const gcall *call_stmt, const vec<const svalue *> *arg_svals, region_model_context *ctxt) { - m_current_frame = m_mgr->get_frame_region (m_current_frame, fun); + tree fndecl = fun.decl; if (arg_svals) { + /* If the result of the callee is DECL_BY_REFERENCE, then + we'll need to store a reference to the caller's lhs of + CALL_STMT within callee's result. + If so, determine the region of CALL_STMT's lhs within + the caller's frame before updating m_current_frame. */ + const region *caller_return_by_reference_reg = nullptr; + if (tree result = DECL_RESULT (fndecl)) + if (DECL_BY_REFERENCE (result)) + { + gcc_assert (call_stmt); + tree lhs = gimple_call_lhs (call_stmt); + gcc_assert (lhs); + caller_return_by_reference_reg = get_lvalue (lhs, ctxt); + } + + /* Update m_current_frame. */ + m_current_frame = m_mgr->get_frame_region (m_current_frame, fun); + /* Arguments supplied from a caller frame. */ - tree fndecl = fun.decl; unsigned idx = 0; for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm; iter_parm = DECL_CHAIN (iter_parm), ++idx) @@ -6308,13 +6809,39 @@ region_model::push_frame (const function &fun, va_arg_idx); set_value (var_arg_reg, arg_sval, ctxt); } + + /* If the result of the callee is DECL_BY_REFERENCE, then above + we should have determined the region within the + caller's frame that the callee will be writing back to. + Use this now to initialize the reference in callee's frame. */ + if (tree result = DECL_RESULT (fndecl)) + if (DECL_BY_REFERENCE (result)) + { + /* Get reference to the caller lhs. */ + gcc_assert (caller_return_by_reference_reg); + const svalue *ref_sval + = m_mgr->get_ptr_svalue (TREE_TYPE (result), + caller_return_by_reference_reg); + + /* Get region for default val of DECL_RESULT within the + callee. */ + tree result_default_ssa = get_ssa_default_def (fun, result); + gcc_assert (result_default_ssa); + const region *callee_result_reg + = get_lvalue (result_default_ssa, ctxt); + + /* Set the callee's reference to refer to the caller's lhs. */ + set_value (callee_result_reg, ref_sval, ctxt); + } } else { /* Otherwise we have a top-level call within the analysis. The params have defined but unknown initial values. Anything they point to has escaped. */ - tree fndecl = fun.decl; + + /* Update m_current_frame. */ + m_current_frame = m_mgr->get_frame_region (m_current_frame, fun); /* Handle "__attribute__((nonnull))". */ tree fntype = TREE_TYPE (fndecl); @@ -6382,7 +6909,7 @@ public: {} std::unique_ptr<stmt_finder> clone () const override { - return ::make_unique<my_finder> (m_call_stmt, m_caller_frame); + return std::make_unique<my_finder> (m_call_stmt, m_caller_frame); } const gimple *find_stmt (const exploded_path &) override { @@ -6433,7 +6960,7 @@ private: Purge the frame region and all its descendent regions. Convert any pointers that point into such regions into - POISON_KIND_POPPED_STACK svalues. */ + poison_kind::popped_stack svalues. */ void region_model::pop_frame (tree result_lvalue, @@ -6467,7 +6994,11 @@ region_model::pop_frame (tree result_lvalue, /* Pop the frame. */ m_current_frame = m_current_frame->get_calling_frame (); - if (result_lvalue && retval) + if (result_lvalue + && retval + /* Don't write back for DECL_BY_REFERENCE; the writes + should have happened within the callee already. */ + && !DECL_BY_REFERENCE (result)) { gcc_assert (eval_return_svalue); @@ -6483,7 +7014,7 @@ region_model::pop_frame (tree result_lvalue, set_value (result_dst_reg, retval, call_stmt ? &caller_ctxt : ctxt); } - unbind_region_and_descendents (frame_reg,POISON_KIND_POPPED_STACK); + unbind_region_and_descendents (frame_reg,poison_kind::popped_stack); notify_on_pop_frame (this, &pre_popped_model, retval, ctxt); } @@ -6640,6 +7171,14 @@ region_model::can_merge_with_p (const region_model &other_model, for (auto iter : m.m_svals_changing_meaning) out_model->m_constraints->purge_state_involving (iter); + if (m_thrown_exceptions_stack != other_model.m_thrown_exceptions_stack) + return false; + out_model->m_thrown_exceptions_stack = m_thrown_exceptions_stack; + + if (m_caught_exceptions_stack != other_model.m_caught_exceptions_stack) + return false; + out_model->m_caught_exceptions_stack = m_caught_exceptions_stack; + return true; } @@ -6647,10 +7186,10 @@ region_model::can_merge_with_p (const region_model &other_model, otherwise. */ tree -region_model::get_fndecl_for_call (const gcall *call, +region_model::get_fndecl_for_call (const gcall &call, region_model_context *ctxt) { - tree fn_ptr = gimple_call_fn (call); + tree fn_ptr = gimple_call_fn (&call); if (fn_ptr == NULL_TREE) return NULL_TREE; const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt); @@ -6825,7 +7364,7 @@ region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes, if (const svalue *float_sval = v.get_svalue_to_report ()) { tree diag_arg = get_representative_tree (float_sval); - ctxt->warn (make_unique<float_as_size_arg> (diag_arg)); + ctxt->warn (std::make_unique<float_as_size_arg> (diag_arg)); } } @@ -6894,6 +7433,12 @@ region_model::get_referenced_base_regions (auto_bitmap &out_ids) const reachable_regs.add (base_reg, false); } + for (auto &eh_node : m_thrown_exceptions_stack) + eh_node.add_to_reachable_regions (reachable_regs); + for (auto &eh_node : m_caught_exceptions_stack) + eh_node.add_to_reachable_regions (reachable_regs); + + bitmap_clear (out_ids); for (auto iter_reg : reachable_regs) bitmap_set_bit (out_ids, iter_reg->get_id ()); @@ -7077,7 +7622,7 @@ private: { const poisoned_svalue *poisoned_sval = as_a <const poisoned_svalue *> (m_copied_sval); - gcc_assert (poisoned_sval->get_poison_kind () == POISON_KIND_UNINIT); + gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit); /* Give up if don't have type information. */ if (m_copied_sval->get_type () == NULL_TREE) @@ -7102,7 +7647,7 @@ private: const svalue *sval = iter.second; if (const poisoned_svalue *psval = sval->dyn_cast_poisoned_svalue ()) - if (psval->get_poison_kind () == POISON_KIND_UNINIT) + if (psval->get_poison_kind () == poison_kind::uninit) { const binding_key *key = iter.first; const concrete_binding *ckey @@ -7154,7 +7699,7 @@ private: const svalue *sval = iter.second; if (const poisoned_svalue *psval = sval->dyn_cast_poisoned_svalue ()) - if (psval->get_poison_kind () == POISON_KIND_UNINIT) + if (psval->get_poison_kind () == poison_kind::uninit) { const binding_key *key = iter.first; const concrete_binding *ckey @@ -7171,8 +7716,7 @@ private: tree type = m_copied_sval->get_type (); if (type && TREE_CODE (type) == RECORD_TYPE) { - // (std::make_unique is C++14) - layout = std::unique_ptr<record_layout> (new record_layout (type)); + layout = std::make_unique<record_layout> (type); if (0) layout->dump (); @@ -7358,7 +7902,7 @@ contains_uninit_p (const svalue *sval) { const poisoned_svalue *psval = as_a <const poisoned_svalue *> (sval); - return psval->get_poison_kind () == POISON_KIND_UNINIT; + return psval->get_poison_kind () == poison_kind::uninit; } case SK_COMPOUND: { @@ -7370,7 +7914,7 @@ contains_uninit_p (const svalue *sval) const svalue *sval = iter.second; if (const poisoned_svalue *psval = sval->dyn_cast_poisoned_svalue ()) - if (psval->get_poison_kind () == POISON_KIND_UNINIT) + if (psval->get_poison_kind () == poison_kind::uninit) return true; } @@ -7397,9 +7941,10 @@ region_model::maybe_complain_about_infoleak (const region *dst_reg, { /* Check for exposure. */ if (contains_uninit_p (copied_sval)) - ctxt->warn (make_unique<exposure_through_uninit_copy> (src_reg, - dst_reg, - copied_sval)); + ctxt->warn + (std::make_unique<exposure_through_uninit_copy> (src_reg, + dst_reg, + copied_sval)); } /* Set errno to a positive symbolic int, as if some error has occurred. */ @@ -7411,7 +7956,7 @@ region_model::set_errno (const call_details &cd) conjured_purge p (this, cd.get_ctxt ()); const svalue *new_errno_sval = m_mgr->get_or_create_conjured_svalue (integer_type_node, - cd.get_call_stmt (), + &cd.get_call_stmt (), errno_reg, p); const svalue *zero = m_mgr->get_or_create_int_cst (integer_type_node, 0); @@ -8432,7 +8977,7 @@ test_stack_frames () /* Push stack frame for "parent_fn". */ const region *parent_frame_reg = model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl), - NULL, &ctxt); + nullptr, nullptr, &ctxt); ASSERT_EQ (model.get_current_frame (), parent_frame_reg); ASSERT_TRUE (model.region_exists_p (parent_frame_reg)); const region *a_in_parent_reg = model.get_lvalue (a, &ctxt); @@ -8447,7 +8992,8 @@ test_stack_frames () /* Push stack frame for "child_fn". */ const region *child_frame_reg - = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt); + = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), + nullptr, nullptr, &ctxt); ASSERT_EQ (model.get_current_frame (), child_frame_reg); ASSERT_TRUE (model.region_exists_p (child_frame_reg)); const region *x_in_child_reg = model.get_lvalue (x, &ctxt); @@ -8488,7 +9034,7 @@ test_stack_frames () const svalue *new_p_sval = model.get_rvalue (p, NULL); ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED); ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (), - POISON_KIND_POPPED_STACK); + poison_kind::popped_stack); /* Verify that q still points to p, in spite of the region renumbering. */ @@ -8540,7 +9086,8 @@ test_get_representative_path_var () for (int depth = 0; depth < 5; depth++) { const region *frame_n_reg - = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt); + = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), + nullptr, nullptr, &ctxt); const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt); parm_regs.safe_push (parm_n_reg); @@ -8786,9 +9333,11 @@ test_state_merging () region_model model0 (&mgr); region_model model1 (&mgr); ASSERT_EQ (model0.get_stack_depth (), 0); - model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt); + model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), + nullptr, nullptr, &ctxt); ASSERT_EQ (model0.get_stack_depth (), 1); - model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt); + model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), + nullptr, nullptr, &ctxt); placeholder_svalue test_sval (mgr.alloc_symbol_id (), integer_type_node, "test sval"); @@ -8880,7 +9429,8 @@ test_state_merging () /* Pointers: non-NULL and non-NULL: ptr to a local. */ { region_model model0 (&mgr); - model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL); + model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), + nullptr, nullptr, nullptr); model0.set_value (model0.get_lvalue (p, NULL), model0.get_rvalue (addr_of_a, NULL), NULL); @@ -9019,12 +9569,14 @@ test_state_merging () frame points to a local in a more recent stack frame. */ { region_model model0 (&mgr); - model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL); + model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), + nullptr, nullptr, nullptr); const region *q_in_first_frame = model0.get_lvalue (q, NULL); /* Push a second frame. */ const region *reg_2nd_frame - = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL); + = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), + nullptr, nullptr, nullptr); /* Have a pointer in the older frame point to a local in the more recent frame. */ @@ -9051,7 +9603,8 @@ test_state_merging () /* Verify that we can merge a model in which a local points to a global. */ { region_model model0 (&mgr); - model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL); + model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), + nullptr, nullptr, nullptr); model0.set_value (model0.get_lvalue (q, NULL), model0.get_rvalue (addr_of_y, NULL), NULL); @@ -9583,7 +10136,7 @@ test_alloca () /* Push stack frame. */ const region *frame_reg = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), - NULL, &ctxt); + nullptr, nullptr, &ctxt); /* "p = alloca (n * 4);". */ const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt); const region *reg = model.create_region_for_alloca (size_sval, &ctxt); diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index d8e508d..2c7f737 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -250,6 +250,41 @@ typedef void (*pop_frame_callback) (const region_model *model, const svalue *retval, region_model_context *ctxt); +/* Roughly equivalent to a struct __cxa_exception, except we store a std::vector + rather than a linked list. */ + +struct exception_node +{ + exception_node (const svalue *exception_sval, + const svalue *typeinfo_sval, + const svalue *destructor_sval) + : m_exception_sval (exception_sval), + m_typeinfo_sval (typeinfo_sval), + m_destructor_sval (destructor_sval) + { + } + + bool operator== (const exception_node &other) const; + + void dump_to_pp (pretty_printer *pp, bool simple) const; + void dump (FILE *fp, bool simple) const; + void dump (bool simple) const; + void dump () const; + + std::unique_ptr<json::object> to_json () const; + + std::unique_ptr<text_art::tree_widget> + make_dump_widget (const text_art::dump_widget_info &dwi) const; + + tree maybe_get_type () const; + + void add_to_reachable_regions (reachable_regions &) const; + + const svalue *m_exception_sval; + const svalue *m_typeinfo_sval; + const svalue *m_destructor_sval; +}; + /* A region_model encapsulates a representation of the state of memory, with a tree of regions, along with their associated values. The representation is graph-like because values can be pointers to @@ -305,8 +340,8 @@ class region_model const svalue *get_gassign_result (const gassign *assign, region_model_context *ctxt); void on_asm_stmt (const gasm *asm_stmt, region_model_context *ctxt); - bool on_call_pre (const gcall *stmt, region_model_context *ctxt); - void on_call_post (const gcall *stmt, + bool on_call_pre (const gcall &stmt, region_model_context *ctxt); + void on_call_post (const gcall &stmt, bool unknown_side_effects, region_model_context *ctxt); @@ -323,16 +358,16 @@ class region_model bool unmergeable); void update_for_nonzero_return (const call_details &cd); - void handle_unrecognized_call (const gcall *call, + void handle_unrecognized_call (const gcall &call, region_model_context *ctxt); void get_reachable_svalues (svalue_set *out, const svalue *extra_sval, const uncertainty_t *uncertainty); void on_return (const greturn *stmt, region_model_context *ctxt); - void on_setjmp (const gcall *stmt, const exploded_node *enode, + void on_setjmp (const gcall &stmt, const exploded_node *enode, region_model_context *ctxt); - void on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call, + void on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call, int setjmp_stack_depth, region_model_context *ctxt); void update_for_phis (const supernode *snode, @@ -349,14 +384,16 @@ class region_model region_model_context *ctxt, std::unique_ptr<rejected_constraint> *out); - void update_for_gcall (const gcall *call_stmt, + void update_for_gcall (const gcall &call_stmt, region_model_context *ctxt, function *callee = NULL); - void update_for_return_gcall (const gcall *call_stmt, + void update_for_return_gcall (const gcall &call_stmt, region_model_context *ctxt); - const region *push_frame (const function &fun, const vec<const svalue *> *arg_sids, + const region *push_frame (const function &fun, + const gcall *call_stmt, + const vec<const svalue *> *arg_sids, region_model_context *ctxt); const frame_region *get_current_frame () const { return m_current_frame; } const function *get_current_function () const; @@ -484,7 +521,7 @@ class region_model const program_state *state_a = NULL, const program_state *state_b = NULL) const; - tree get_fndecl_for_call (const gcall *call, + tree get_fndecl_for_call (const gcall &call, region_model_context *ctxt); void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const; @@ -562,7 +599,7 @@ class region_model const svalue **out_sval) const; const builtin_known_function * - get_builtin_kf (const gcall *call, + get_builtin_kf (const gcall &call, region_model_context *ctxt = NULL) const; static void @@ -583,6 +620,56 @@ class region_model bool called_from_main_p () const; + void push_thrown_exception (const exception_node &node) + { + m_thrown_exceptions_stack.push_back (node); + } + const exception_node *get_current_thrown_exception () const + { + if (m_thrown_exceptions_stack.empty ()) + return nullptr; + return &m_thrown_exceptions_stack.back (); + } + exception_node pop_thrown_exception () + { + gcc_assert (!m_thrown_exceptions_stack.empty ()); + const exception_node retval = m_thrown_exceptions_stack.back (); + m_thrown_exceptions_stack.pop_back (); + return retval; + } + + void push_caught_exception (const exception_node &node) + { + m_caught_exceptions_stack.push_back (node); + } + const exception_node *get_current_caught_exception () const + { + if (m_caught_exceptions_stack.empty ()) + return nullptr; + return &m_caught_exceptions_stack.back (); + } + exception_node pop_caught_exception () + { + gcc_assert (!m_caught_exceptions_stack.empty ()); + const exception_node retval = m_caught_exceptions_stack.back (); + m_caught_exceptions_stack.pop_back (); + return retval; + } + + bool + apply_constraints_for_eh_dispatch_try + (const eh_dispatch_try_cfg_superedge &edge, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out); + + bool + apply_constraints_for_eh_dispatch_allowed + (const eh_dispatch_allowed_cfg_superedge &edge, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out); + private: const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const; const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const; @@ -621,9 +708,12 @@ private: bool apply_constraints_for_ggoto (const cfg_superedge &edge, const ggoto *goto_stmt, region_model_context *ctxt); - bool apply_constraints_for_exception (const gimple *last_stmt, - region_model_context *ctxt, - std::unique_ptr<rejected_constraint> *out); + + bool + apply_constraints_for_eh_dispatch (const eh_dispatch_cfg_superedge &edge, + const geh_dispatch *eh_dispatch_stmt, + region_model_context *ctxt, + std::unique_ptr<rejected_constraint> *out); int poison_any_pointers_to_descendents (const region *reg, enum poison_kind pkind); @@ -672,23 +762,27 @@ private: void check_call_args (const call_details &cd) const; void check_call_format_attr (const call_details &cd, tree format_attr) const; - void check_function_attr_access (const gcall *call, + void check_function_attr_access (const gcall &call, tree callee_fndecl, region_model_context *ctxt, rdwr_map &rdwr_idx) const; - void check_function_attr_null_terminated_string_arg (const gcall *call, + void check_function_attr_null_terminated_string_arg (const gcall &call, tree callee_fndecl, region_model_context *ctxt, rdwr_map &rdwr_idx); - void check_one_function_attr_null_terminated_string_arg (const gcall *call, + void check_one_function_attr_null_terminated_string_arg (const gcall &call, tree callee_fndecl, region_model_context *ctxt, rdwr_map &rdwr_idx, tree attr); - void check_function_attrs (const gcall *call, + void check_function_attrs (const gcall &call, tree callee_fndecl, region_model_context *ctxt); + void check_for_throw_inside_call (const gcall &call, + tree fndecl, + region_model_context *ctxt); + static auto_vec<pop_frame_callback> pop_frame_callbacks; /* Storing this here to avoid passing it around everywhere. */ region_model_manager *const m_mgr; @@ -699,6 +793,9 @@ private: const frame_region *m_current_frame; + std::vector<exception_node> m_thrown_exceptions_stack; + std::vector<exception_node> m_caught_exceptions_stack; + /* Map from base region to size in bytes, for tracking the sizes of dynamically-allocated regions. This is part of the region_model rather than the region to allow for diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index d464153..efbbca0 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -18,38 +18,19 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" -#include "fold-const.h" -#include "tree-pretty-print.h" -#include "diagnostic-color.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" #include "cfg.h" #include "digraph.h" -#include "analyzer/supergraph.h" #include "sbitmap.h" +#include "fold-const.h" +#include "tree-ssa.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/supergraph.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" @@ -58,7 +39,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/sm.h" #include "analyzer/program-state.h" #include "text-art/dump.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -567,15 +547,12 @@ region::can_have_initial_svalue_p () const case SSA_NAME: { + /* Some SSA names have an implicit default defined value. */ tree ssa_name = decl; - /* SSA names that are the default defn of a PARM_DECL - have initial_svalues; other SSA names don't. */ - if (SSA_NAME_IS_DEFAULT_DEF (ssa_name) - && SSA_NAME_VAR (ssa_name) - && TREE_CODE (SSA_NAME_VAR (ssa_name)) == PARM_DECL) - return true; - else - return false; + if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)) + return ssa_defined_default_def_p (ssa_name); + /* Others don't. */ + return false; } } } @@ -1039,7 +1016,7 @@ std::unique_ptr<json::value> region::to_json () const { label_text desc = get_desc (true); - auto reg_js = ::make_unique<json::string> (desc.get ()); + auto reg_js = std::make_unique<json::string> (desc.get ()); return reg_js; } diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index e9016f1..cee8d2d 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -18,32 +18,21 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-event-id.h" +#include "stringpool.h" +#include "attribs.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/function-set.h" #include "analyzer/analyzer-selftests.h" -#include "stringpool.h" -#include "attribs.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" -#include "bitmap.h" #include "analyzer/program-state.h" #include "analyzer/supergraph.h" #include "analyzer/analyzer-language.h" @@ -230,17 +219,17 @@ public: private: void on_open (sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call) const; + const gcall &call) const; void on_creat (sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call) const; + const gcall &call) const; void on_close (sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call) const; + const gcall &call) const; void on_read (sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call, const tree callee_fndecl) const; + const gcall &call, const tree callee_fndecl) const; void on_write (sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call, const tree callee_fndecl) const; + const gcall &call, const tree callee_fndecl) const; void check_for_open_fd (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call, + const gimple *stmt, const gcall &call, const tree callee_fndecl, enum access_directions access_fn) const; @@ -253,11 +242,11 @@ private: const gimple *stmt, const svalue *lhs) const; void check_for_fd_attrs (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call, + const gimple *stmt, const gcall &call, const tree callee_fndecl, const char *attr_name, access_directions fd_attr_access_dir) const; void check_for_dup (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call, const tree callee_fndecl, + const gimple *stmt, const gcall &call, const tree callee_fndecl, enum dup kind) const; state_t get_state_for_socket_type (const svalue *socket_type_sval) const; @@ -1324,70 +1313,70 @@ fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node, const gimple *stmt) const { if (const gcall *call = dyn_cast<const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call)) { - if (is_named_call_p (callee_fndecl, "open", call, 2)) + if (is_named_call_p (callee_fndecl, "open", *call, 2)) { - on_open (sm_ctxt, node, stmt, call); + on_open (sm_ctxt, node, stmt, *call); return true; } // "open" - if (is_named_call_p (callee_fndecl, "creat", call, 2)) + if (is_named_call_p (callee_fndecl, "creat", *call, 2)) { - on_creat (sm_ctxt, node, stmt, call); + on_creat (sm_ctxt, node, stmt, *call); return true; } // "creat" - if (is_named_call_p (callee_fndecl, "close", call, 1)) + if (is_named_call_p (callee_fndecl, "close", *call, 1)) { - on_close (sm_ctxt, node, stmt, call); + on_close (sm_ctxt, node, stmt, *call); return true; } // "close" - if (is_named_call_p (callee_fndecl, "write", call, 3)) + if (is_named_call_p (callee_fndecl, "write", *call, 3)) { - on_write (sm_ctxt, node, stmt, call, callee_fndecl); + on_write (sm_ctxt, node, stmt, *call, callee_fndecl); return true; } // "write" - if (is_named_call_p (callee_fndecl, "read", call, 3)) + if (is_named_call_p (callee_fndecl, "read", *call, 3)) { - on_read (sm_ctxt, node, stmt, call, callee_fndecl); + on_read (sm_ctxt, node, stmt, *call, callee_fndecl); return true; } // "read" - if (is_named_call_p (callee_fndecl, "dup", call, 1)) + if (is_named_call_p (callee_fndecl, "dup", *call, 1)) { - check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1); + check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_1); return true; } - if (is_named_call_p (callee_fndecl, "dup2", call, 2)) + if (is_named_call_p (callee_fndecl, "dup2", *call, 2)) { - check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2); + check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_2); return true; } - if (is_named_call_p (callee_fndecl, "dup3", call, 3)) + if (is_named_call_p (callee_fndecl, "dup3", *call, 3)) { - check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3); + check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_3); return true; } { // Handle __attribute__((fd_arg)) - check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl, + check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl, "fd_arg", DIRS_READ_WRITE); // Handle __attribute__((fd_arg_read)) - check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl, + check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl, "fd_arg_read", DIRS_READ); // Handle __attribute__((fd_arg_write)) - check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl, + check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl, "fd_arg_write", DIRS_WRITE); } } @@ -1398,7 +1387,7 @@ fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node, void fd_state_machine::check_for_fd_attrs ( sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call, const tree callee_fndecl, const char *attr_name, + const gcall &call, const tree callee_fndecl, const char *attr_name, access_directions fd_attr_access_dir) const { /* Handle interesting fd attributes of the callee_fndecl, @@ -1431,9 +1420,9 @@ fd_state_machine::check_for_fd_attrs ( if (bitmap_empty_p (argmap)) return; - for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++) + for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call); arg_idx++) { - tree arg = gimple_call_arg (call, arg_idx); + tree arg = gimple_call_arg (&call, arg_idx); tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); state_t state = sm_ctxt.get_state (stmt, arg); bool bit_set = bitmap_bit_p (argmap, arg_idx); @@ -1449,7 +1438,7 @@ fd_state_machine::check_for_fd_attrs ( { sm_ctxt.warn (node, stmt, arg, - make_unique<fd_use_after_close> + std::make_unique<fd_use_after_close> (*this, diag_arg, fndecl, attr_name, arg_idx)); @@ -1461,7 +1450,7 @@ fd_state_machine::check_for_fd_attrs ( if (!is_constant_fd_p (state)) { sm_ctxt.warn (node, stmt, arg, - make_unique<fd_use_without_check> + std::make_unique<fd_use_without_check> (*this, diag_arg, fndecl, attr_name, arg_idx)); @@ -1477,13 +1466,13 @@ fd_state_machine::check_for_fd_attrs ( if (is_writeonly_fd_p (state)) { - sm_ctxt.warn ( - node, stmt, arg, - make_unique<fd_access_mode_mismatch> (*this, diag_arg, - DIRS_WRITE, - fndecl, - attr_name, - arg_idx)); + sm_ctxt.warn + (node, stmt, arg, + std::make_unique<fd_access_mode_mismatch> (*this, diag_arg, + DIRS_WRITE, + fndecl, + attr_name, + arg_idx)); } break; @@ -1491,13 +1480,13 @@ fd_state_machine::check_for_fd_attrs ( if (is_readonly_fd_p (state)) { - sm_ctxt.warn ( - node, stmt, arg, - make_unique<fd_access_mode_mismatch> (*this, diag_arg, - DIRS_READ, - fndecl, - attr_name, - arg_idx)); + sm_ctxt.warn + (node, stmt, arg, + std::make_unique<fd_access_mode_mismatch> (*this, diag_arg, + DIRS_READ, + fndecl, + attr_name, + arg_idx)); } break; @@ -1509,12 +1498,12 @@ fd_state_machine::check_for_fd_attrs ( void fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call) const + const gimple *stmt, const gcall &call) const { - tree lhs = gimple_call_lhs (call); + tree lhs = gimple_call_lhs (&call); if (lhs) { - tree arg = gimple_call_arg (call, 1); + tree arg = gimple_call_arg (&call, 1); enum access_mode mode = READ_WRITE; if (TREE_CODE (arg) == INTEGER_CST) { @@ -1539,29 +1528,29 @@ fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node, else { sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<fd_leak> (*this, NULL_TREE)); + std::make_unique<fd_leak> (*this, NULL_TREE)); } } void fd_state_machine::on_creat (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call) const + const gimple *stmt, const gcall &call) const { - tree lhs = gimple_call_lhs (call); + tree lhs = gimple_call_lhs (&call); if (lhs) sm_ctxt.on_transition (node, stmt, lhs, m_start, m_unchecked_write_only); else sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<fd_leak> (*this, NULL_TREE)); + std::make_unique<fd_leak> (*this, NULL_TREE)); } void fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call, + const gimple *stmt, const gcall &call, const tree callee_fndecl, enum dup kind) const { - tree lhs = gimple_call_lhs (call); - tree arg_1 = gimple_call_arg (call, 0); + tree lhs = gimple_call_lhs (&call); + tree arg_1 = gimple_call_arg (&call, 0); state_t state_arg_1 = sm_ctxt.get_state (stmt, arg_1); if (state_arg_1 == m_stop) return; @@ -1587,7 +1576,7 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node, case DUP_2: case DUP_3: - tree arg_2 = gimple_call_arg (call, 1); + tree arg_2 = gimple_call_arg (&call, 1); state_t state_arg_2 = sm_ctxt.get_state (stmt, arg_2); tree diag_arg_2 = sm_ctxt.get_diagnostic_tree (arg_2); if (state_arg_2 == m_stop) @@ -1598,8 +1587,8 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node, { sm_ctxt.warn ( node, stmt, arg_2, - make_unique<fd_use_without_check> (*this, diag_arg_2, - callee_fndecl)); + std::make_unique<fd_use_without_check> (*this, diag_arg_2, + callee_fndecl)); return; } /* dup2 returns value of its second argument on success.But, the @@ -1620,9 +1609,9 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node, void fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call) const + const gimple *stmt, const gcall &call) const { - tree arg = gimple_call_arg (call, 0); + tree arg = gimple_call_arg (&call, 0); state_t state = sm_ctxt.get_state (stmt, arg); tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); @@ -1646,20 +1635,20 @@ fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node, if (is_closed_fd_p (state)) { sm_ctxt.warn (node, stmt, arg, - make_unique<fd_double_close> (*this, diag_arg)); + std::make_unique<fd_double_close> (*this, diag_arg)); sm_ctxt.set_next_state (stmt, arg, m_stop); } } void fd_state_machine::on_read (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call, + const gimple *stmt, const gcall &call, const tree callee_fndecl) const { check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ); } void fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node, - const gimple *stmt, const gcall *call, + const gimple *stmt, const gcall &call, const tree callee_fndecl) const { check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE); @@ -1668,18 +1657,18 @@ fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node, void fd_state_machine::check_for_open_fd ( sm_context &sm_ctxt, const supernode *node, const gimple *stmt, - const gcall *call, const tree callee_fndecl, + const gcall &call, const tree callee_fndecl, enum access_directions callee_fndecl_dir) const { - tree arg = gimple_call_arg (call, 0); + tree arg = gimple_call_arg (&call, 0); tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); state_t state = sm_ctxt.get_state (stmt, arg); if (is_closed_fd_p (state)) { sm_ctxt.warn (node, stmt, arg, - make_unique<fd_use_after_close> (*this, diag_arg, - callee_fndecl)); + std::make_unique<fd_use_after_close> (*this, diag_arg, + callee_fndecl)); } else @@ -1690,10 +1679,10 @@ fd_state_machine::check_for_open_fd ( /* Complain about fncall on socket in wrong phase. */ sm_ctxt.warn (node, stmt, arg, - make_unique<fd_phase_mismatch> (*this, diag_arg, - callee_fndecl, - state, - EXPECTED_PHASE_CAN_TRANSFER)); + std::make_unique<fd_phase_mismatch> (*this, diag_arg, + callee_fndecl, + state, + EXPECTED_PHASE_CAN_TRANSFER)); else if (!(is_valid_fd_p (state) || state == m_new_datagram_socket || state == m_bound_unknown_socket @@ -1704,8 +1693,8 @@ fd_state_machine::check_for_open_fd ( if (!is_constant_fd_p (state)) sm_ctxt.warn ( node, stmt, arg, - make_unique<fd_use_without_check> (*this, diag_arg, - callee_fndecl)); + std::make_unique<fd_use_without_check> (*this, diag_arg, + callee_fndecl)); } switch (callee_fndecl_dir) { @@ -1716,8 +1705,8 @@ fd_state_machine::check_for_open_fd ( { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<fd_access_mode_mismatch> ( - *this, diag_arg, DIRS_WRITE, callee_fndecl)); + std::make_unique<fd_access_mode_mismatch> + (*this, diag_arg, DIRS_WRITE, callee_fndecl)); } break; @@ -1727,8 +1716,8 @@ fd_state_machine::check_for_open_fd ( { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<fd_access_mode_mismatch> ( - *this, diag_arg, DIRS_READ, callee_fndecl)); + std::make_unique<fd_access_mode_mismatch> + (*this, diag_arg, DIRS_READ, callee_fndecl)); } break; } @@ -1775,21 +1764,21 @@ fd_state_machine::on_socket (const call_details &cd, sm_context &sm_ctxt, const extrinsic_state &ext_state) const { - const gcall *stmt = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); engine *eng = ext_state.get_engine (); const supergraph *sg = eng->get_supergraph (); - const supernode *node = sg->get_supernode_for_stmt (stmt); + const supernode *node = sg->get_supernode_for_stmt (&call); region_model *model = cd.get_model (); if (successful) { - if (gimple_call_lhs (stmt)) + if (gimple_call_lhs (&call)) { conjured_purge p (model, cd.get_ctxt ()); region_model_manager *mgr = model->get_manager (); const svalue *new_fd = mgr->get_or_create_conjured_svalue (integer_type_node, - stmt, + &call, cd.get_lhs_region (), p); if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ())) @@ -1798,12 +1787,12 @@ fd_state_machine::on_socket (const call_details &cd, const svalue *socket_type_sval = cd.get_arg_svalue (1); state_machine::state_t new_state = get_state_for_socket_type (socket_type_sval); - sm_ctxt.on_transition (node, stmt, new_fd, m_start, new_state); + sm_ctxt.on_transition (node, &call, new_fd, m_start, new_state); model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ()); } else - sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<fd_leak> (*this, NULL_TREE)); + sm_ctxt.warn (node, &call, NULL_TREE, + std::make_unique<fd_leak> (*this, NULL_TREE)); } else { @@ -1833,15 +1822,15 @@ fd_state_machine::check_for_socket_fd (const call_details &cd, state_t old_state, bool *complained) const { - const gcall *stmt = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); if (is_closed_fd_p (old_state)) { tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval); sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_use_after_close> (*this, diag_arg, - cd.get_fndecl_for_call ())); + (node, &call, fd_sval, + std::make_unique<fd_use_after_close> (*this, diag_arg, + cd.get_fndecl_for_call ())); if (complained) *complained = true; if (successful) @@ -1852,11 +1841,11 @@ fd_state_machine::check_for_socket_fd (const call_details &cd, /* Complain about non-socket. */ tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval); sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_type_mismatch> (*this, diag_arg, - cd.get_fndecl_for_call (), - old_state, - EXPECTED_TYPE_SOCKET)); + (node, &call, fd_sval, + std::make_unique<fd_type_mismatch> (*this, diag_arg, + cd.get_fndecl_for_call (), + old_state, + EXPECTED_TYPE_SOCKET)); if (complained) *complained = true; if (successful) @@ -1866,9 +1855,9 @@ fd_state_machine::check_for_socket_fd (const call_details &cd, { tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval); sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_use_without_check> (*this, diag_arg, - cd.get_fndecl_for_call ())); + (node, &call, fd_sval, + std::make_unique<fd_use_without_check> (*this, diag_arg, + cd.get_fndecl_for_call ())); if (complained) *complained = true; if (successful) @@ -1929,11 +1918,11 @@ fd_state_machine::check_for_new_socket_fd (const call_details &cd, /* Complain about "bind" or "connect" in wrong phase. */ tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval); sm_ctxt.warn - (node, cd.get_call_stmt (), fd_sval, - make_unique<fd_phase_mismatch> (*this, diag_arg, - cd.get_fndecl_for_call (), - old_state, - expected_phase)); + (node, &cd.get_call_stmt (), fd_sval, + std::make_unique<fd_phase_mismatch> (*this, diag_arg, + cd.get_fndecl_for_call (), + old_state, + expected_phase)); if (successful) return false; } @@ -1941,7 +1930,7 @@ fd_state_machine::check_for_new_socket_fd (const call_details &cd, { /* If we were in the start state, assume we had a new socket. */ if (old_state == m_start) - sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, + sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, m_new_unknown_socket); } @@ -1963,13 +1952,13 @@ fd_state_machine::on_bind (const call_details &cd, sm_context &sm_ctxt, const extrinsic_state &ext_state) const { - const gcall *stmt = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); engine *eng = ext_state.get_engine (); const supergraph *sg = eng->get_supergraph (); - const supernode *node = sg->get_supernode_for_stmt (stmt); + const supernode *node = sg->get_supernode_for_stmt (&call); const svalue *fd_sval = cd.get_arg_svalue (0); region_model *model = cd.get_model (); - state_t old_state = sm_ctxt.get_state (stmt, fd_sval); + state_t old_state = sm_ctxt.get_state (&call, fd_sval); if (!check_for_new_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state, @@ -1992,7 +1981,7 @@ fd_state_machine::on_bind (const call_details &cd, next_state = m_stop; else gcc_unreachable (); - sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state); + sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, next_state); model->update_for_zero_return (cd, true); } else @@ -2015,13 +2004,13 @@ fd_state_machine::on_listen (const call_details &cd, sm_context &sm_ctxt, const extrinsic_state &ext_state) const { - const gcall *stmt = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); engine *eng = ext_state.get_engine (); const supergraph *sg = eng->get_supergraph (); - const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ()); + const supernode *node = sg->get_supernode_for_stmt (&cd.get_call_stmt ()); const svalue *fd_sval = cd.get_arg_svalue (0); region_model *model = cd.get_model (); - state_t old_state = sm_ctxt.get_state (stmt, fd_sval); + state_t old_state = sm_ctxt.get_state (&call, fd_sval); /* We expect a stream socket that's had "bind" called on it. */ if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state)) @@ -2039,18 +2028,18 @@ fd_state_machine::on_listen (const call_details &cd, tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval); if (is_stream_socket_fd_p (old_state)) sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_phase_mismatch> (*this, diag_arg, - cd.get_fndecl_for_call (), - old_state, - EXPECTED_PHASE_CAN_LISTEN)); + (node, &call, fd_sval, + std::make_unique<fd_phase_mismatch> (*this, diag_arg, + cd.get_fndecl_for_call (), + old_state, + EXPECTED_PHASE_CAN_LISTEN)); else sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_type_mismatch> (*this, diag_arg, - cd.get_fndecl_for_call (), - old_state, - EXPECTED_TYPE_STREAM_SOCKET)); + (node, &call, fd_sval, + std::make_unique<fd_type_mismatch> (*this, diag_arg, + cd.get_fndecl_for_call (), + old_state, + EXPECTED_TYPE_STREAM_SOCKET)); if (successful) return false; } @@ -2058,7 +2047,7 @@ fd_state_machine::on_listen (const call_details &cd, if (successful) { model->update_for_zero_return (cd, true); - sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, + sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, m_listening_stream_socket); } else @@ -2067,7 +2056,7 @@ fd_state_machine::on_listen (const call_details &cd, model->update_for_int_cst_return (cd, -1, true); model->set_errno (cd); if (old_state == m_start) - sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, + sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, m_bound_stream_socket); } @@ -2084,15 +2073,15 @@ fd_state_machine::on_accept (const call_details &cd, sm_context &sm_ctxt, const extrinsic_state &ext_state) const { - const gcall *stmt = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); engine *eng = ext_state.get_engine (); const supergraph *sg = eng->get_supergraph (); - const supernode *node = sg->get_supernode_for_stmt (stmt); + const supernode *node = sg->get_supernode_for_stmt (&call); const svalue *fd_sval = cd.get_arg_svalue (0); const svalue *address_sval = cd.get_arg_svalue (1); const svalue *len_ptr_sval = cd.get_arg_svalue (2); region_model *model = cd.get_model (); - state_t old_state = sm_ctxt.get_state (stmt, fd_sval); + state_t old_state = sm_ctxt.get_state (&call, fd_sval); if (!address_sval->all_zeroes_p ()) { @@ -2127,14 +2116,14 @@ fd_state_machine::on_accept (const call_details &cd, old_len_sval); const svalue *new_addr_sval = mgr->get_or_create_conjured_svalue (NULL_TREE, - stmt, + &call, old_sized_address_reg, p); model->set_value (old_sized_address_reg, new_addr_sval, cd.get_ctxt ()); const svalue *new_addr_len = mgr->get_or_create_conjured_svalue (NULL_TREE, - stmt, + &call, len_reg, p); model->set_value (len_reg, new_addr_len, cd.get_ctxt ()); @@ -2148,7 +2137,7 @@ fd_state_machine::on_accept (const call_details &cd, if (old_state == m_start || old_state == m_constant_fd) /* If we were in the start state (or a constant), assume we had the expected state. */ - sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, + sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, m_listening_stream_socket); else if (old_state == m_stop) { @@ -2160,18 +2149,18 @@ fd_state_machine::on_accept (const call_details &cd, tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval); if (is_stream_socket_fd_p (old_state)) sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_phase_mismatch> (*this, diag_arg, - cd.get_fndecl_for_call (), - old_state, - EXPECTED_PHASE_CAN_ACCEPT)); + (node, &call, fd_sval, + std::make_unique<fd_phase_mismatch> (*this, diag_arg, + cd.get_fndecl_for_call (), + old_state, + EXPECTED_PHASE_CAN_ACCEPT)); else sm_ctxt.warn - (node, stmt, fd_sval, - make_unique<fd_type_mismatch> (*this, diag_arg, - cd.get_fndecl_for_call (), - old_state, - EXPECTED_TYPE_STREAM_SOCKET)); + (node, &call, fd_sval, + std::make_unique<fd_type_mismatch> (*this, diag_arg, + cd.get_fndecl_for_call (), + old_state, + EXPECTED_TYPE_STREAM_SOCKET)); if (successful) return false; } @@ -2179,24 +2168,24 @@ fd_state_machine::on_accept (const call_details &cd, if (successful) { /* Return new conjured FD in "connected" state. */ - if (gimple_call_lhs (stmt)) + if (gimple_call_lhs (&call)) { conjured_purge p (model, cd.get_ctxt ()); region_model_manager *mgr = model->get_manager (); const svalue *new_fd = mgr->get_or_create_conjured_svalue (integer_type_node, - stmt, + &call, cd.get_lhs_region (), p); if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ())) return false; - sm_ctxt.on_transition (node, stmt, new_fd, + sm_ctxt.on_transition (node, &call, new_fd, m_start, m_connected_stream_socket); model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ()); } else - sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<fd_leak> (*this, NULL_TREE)); + sm_ctxt.warn (node, &call, NULL_TREE, + std::make_unique<fd_leak> (*this, NULL_TREE)); } else { @@ -2218,13 +2207,13 @@ fd_state_machine::on_connect (const call_details &cd, sm_context &sm_ctxt, const extrinsic_state &ext_state) const { - const gcall *stmt = cd.get_call_stmt (); + const gcall &call = cd.get_call_stmt (); engine *eng = ext_state.get_engine (); const supergraph *sg = eng->get_supergraph (); - const supernode *node = sg->get_supernode_for_stmt (stmt); + const supernode *node = sg->get_supernode_for_stmt (&call); const svalue *fd_sval = cd.get_arg_svalue (0); region_model *model = cd.get_model (); - state_t old_state = sm_ctxt.get_state (stmt, fd_sval); + state_t old_state = sm_ctxt.get_state (&call, fd_sval); if (!check_for_new_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state, @@ -2250,7 +2239,7 @@ fd_state_machine::on_connect (const call_details &cd, next_state = m_stop; else gcc_unreachable (); - sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state); + sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, next_state); } else { @@ -2334,14 +2323,14 @@ fd_state_machine::can_purge_p (state_t s) const std::unique_ptr<pending_diagnostic> fd_state_machine::on_leak (tree var) const { - return make_unique<fd_leak> (*this, var); + return std::make_unique<fd_leak> (*this, var); } } // namespace -state_machine * +std::unique_ptr<state_machine> make_fd_state_machine (logger *logger) { - return new fd_state_machine (logger); + return std::make_unique<fd_state_machine> (logger); } static bool @@ -2426,8 +2415,10 @@ public: { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_socket> (cd, false)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_socket> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2478,8 +2469,10 @@ public: { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_bind> (cd, false)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_bind> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2530,8 +2523,10 @@ class kf_listen : public known_function { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_listen> (cd, false)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_listen> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2584,8 +2579,10 @@ class kf_accept : public known_function { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_accept> (cd, false)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_accept> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2638,8 +2635,10 @@ public: { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_connect> (cd, false)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_connect> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2696,7 +2695,7 @@ class kf_isatty : public known_function const svalue *fd_sval = cd.get_arg_svalue (0); state_machine::state_t old_state - = sm_ctxt->get_state (cd.get_call_stmt (), fd_sval); + = sm_ctxt->get_state (&cd.get_call_stmt (), fd_sval); if (fd_sm->is_closed_fd_p (old_state) || old_state == fd_sm->m_invalid) @@ -2716,8 +2715,10 @@ public: { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, false)); - cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, true)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_isatty> (cd, false)); + cd.get_ctxt ()->bifurcate + (std::make_unique<outcome_of_isatty> (cd, true)); cd.get_ctxt ()->terminate_path (); } } @@ -2773,7 +2774,7 @@ class kf_pipe : public known_function conjured_purge p (model, cd.get_ctxt ()); const svalue *fd_sval = mgr->get_or_create_conjured_svalue (integer_type_node, - cd.get_call_stmt (), + &cd.get_call_stmt (), element_reg, p); model->set_value (element_reg, fd_sval, cd.get_ctxt ()); @@ -2799,8 +2800,10 @@ public: { if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<failure> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success> (cd)); + cd.get_ctxt ()->bifurcate + (std::make_unique<failure> (cd)); + cd.get_ctxt ()->bifurcate + (std::make_unique<success> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -2848,15 +2851,15 @@ public: void register_known_fd_functions (known_function_manager &kfm) { - kfm.add ("accept", make_unique<kf_accept> ()); - kfm.add ("bind", make_unique<kf_bind> ()); - kfm.add ("connect", make_unique<kf_connect> ()); - kfm.add ("isatty", make_unique<kf_isatty> ()); - kfm.add ("listen", make_unique<kf_listen> ()); - kfm.add ("pipe", make_unique<kf_pipe> (1)); - kfm.add ("pipe2", make_unique<kf_pipe> (2)); - kfm.add ("read", make_unique<kf_read> ()); - kfm.add ("socket", make_unique<kf_socket> ()); + kfm.add ("accept", std::make_unique<kf_accept> ()); + kfm.add ("bind", std::make_unique<kf_bind> ()); + kfm.add ("connect", std::make_unique<kf_connect> ()); + kfm.add ("isatty", std::make_unique<kf_isatty> ()); + kfm.add ("listen", std::make_unique<kf_listen> ()); + kfm.add ("pipe", std::make_unique<kf_pipe> (1)); + kfm.add ("pipe2", std::make_unique<kf_pipe> (2)); + kfm.add ("read", std::make_unique<kf_read> ()); + kfm.add ("socket", std::make_unique<kf_socket> ()); } } // namespace ana diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index 1e41dc9..d7dbe2f 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -18,26 +18,16 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-event-id.h" +#include "selftest.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/function-set.h" #include "analyzer/analyzer-selftests.h" -#include "selftest.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" @@ -403,9 +393,9 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt, const gimple *stmt) const { if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call)) { - if (is_named_call_p (callee_fndecl, "fopen", call, 2)) + if (is_named_call_p (callee_fndecl, "fopen", *call, 2)) { tree lhs = gimple_call_lhs (call); if (lhs) @@ -417,7 +407,7 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt, return true; } - if (is_named_call_p (callee_fndecl, "fclose", call, 1)) + if (is_named_call_p (callee_fndecl, "fclose", *call, 1)) { tree arg = gimple_call_arg (call, 0); @@ -433,7 +423,8 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt, { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<double_fclose> (*this, diag_arg)); + std::make_unique<double_fclose> (*this, + diag_arg)); sm_ctxt.set_next_state (stmt, arg, m_stop); } return true; @@ -503,17 +494,17 @@ fileptr_state_machine::can_purge_p (state_t s) const std::unique_ptr<pending_diagnostic> fileptr_state_machine::on_leak (tree var) const { - return make_unique<file_leak> (*this, var); + return std::make_unique<file_leak> (*this, var); } } // anonymous namespace /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_fileptr_state_machine (logger *logger) { - return new fileptr_state_machine (logger); + return std::make_unique<fileptr_state_machine> (logger); } /* Handler for various stdio-related builtins that merely have external @@ -655,40 +646,40 @@ public: void register_known_file_functions (known_function_manager &kfm) { - kfm.add (BUILT_IN_FPRINTF, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FPRINTF_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FPUTC, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FPUTC_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FPUTS, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FPUTS_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FWRITE, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_FWRITE_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PRINTF, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PRINTF_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PUTC, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PUTCHAR, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PUTCHAR_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PUTC_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PUTS, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_PUTS_UNLOCKED, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_VFPRINTF, make_unique<kf_stdio_output_fn> ()); - kfm.add (BUILT_IN_VPRINTF, make_unique<kf_stdio_output_fn> ()); - - kfm.add ("ferror", make_unique<kf_ferror> ()); - kfm.add ("fgets", make_unique<kf_fgets> ()); - kfm.add ("fgets_unlocked", make_unique<kf_fgets> ()); // non-standard - kfm.add ("fileno", make_unique<kf_fileno> ()); - kfm.add ("fread", make_unique<kf_fread> ()); - kfm.add ("getc", make_unique<kf_getc> ()); - kfm.add ("getchar", make_unique<kf_getchar> ()); + kfm.add (BUILT_IN_FPRINTF, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FPRINTF_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FPUTC, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FPUTC_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FPUTS, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FPUTS_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FWRITE, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_FWRITE_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PRINTF, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PRINTF_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PUTC, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PUTCHAR, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PUTCHAR_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PUTC_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PUTS, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_PUTS_UNLOCKED, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_VFPRINTF, std::make_unique<kf_stdio_output_fn> ()); + kfm.add (BUILT_IN_VPRINTF, std::make_unique<kf_stdio_output_fn> ()); + + kfm.add ("ferror", std::make_unique<kf_ferror> ()); + kfm.add ("fgets", std::make_unique<kf_fgets> ()); + kfm.add ("fgets_unlocked", std::make_unique<kf_fgets> ()); // non-standard + kfm.add ("fileno", std::make_unique<kf_fileno> ()); + kfm.add ("fread", std::make_unique<kf_fread> ()); + kfm.add ("getc", std::make_unique<kf_getc> ()); + kfm.add ("getchar", std::make_unique<kf_getchar> ()); /* Some C++ implementations use the std:: copies of these functions from <cstdio> for <stdio.h>, so we must match against these too. */ - kfm.add_std_ns ("ferror", make_unique<kf_ferror> ()); - kfm.add_std_ns ("fgets", make_unique<kf_fgets> ()); - kfm.add_std_ns ("fread", make_unique<kf_fread> ()); - kfm.add_std_ns ("getc", make_unique<kf_getc> ()); - kfm.add_std_ns ("getchar", make_unique<kf_getchar> ()); + kfm.add_std_ns ("ferror", std::make_unique<kf_ferror> ()); + kfm.add_std_ns ("fgets", std::make_unique<kf_fgets> ()); + kfm.add_std_ns ("fread", std::make_unique<kf_fread> ()); + kfm.add_std_ns ("getc", std::make_unique<kf_getc> ()); + kfm.add_std_ns ("getchar", std::make_unique<kf_getchar> ()); } #if CHECKING_P diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index 6972a55..0186268 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -18,21 +18,12 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "bitmap.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-event-id.h" +#include "stringpool.h" +#include "attribs.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -41,8 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" -#include "stringpool.h" -#include "attribs.h" #include "analyzer/function-set.h" #include "analyzer/program-state.h" #include "analyzer/checker-event.h" @@ -482,22 +471,22 @@ private: tree ptr) const; void on_allocator_call (sm_context &sm_ctxt, - const gcall *call, + const gcall &call, const deallocator_set *deallocators, bool returns_nonnull = false) const; void handle_free_of_non_heap (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree arg, const deallocator *d) const; void on_deallocator_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, const deallocator *d, unsigned argno) const; void on_realloc_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_zero_assignment (sm_context &sm_ctxt, const gimple *stmt, tree lhs) const; @@ -1955,7 +1944,7 @@ get_or_create_assumed_non_null_state_for_frame (const frame_region *frame) builtin. */ static bool -known_allocator_p (const_tree fndecl, const gcall *call) +known_allocator_p (const_tree fndecl, const gcall &call) { /* Either it is a function we know by name and number of arguments... */ if (is_named_call_p (fndecl, "malloc", call, 1) @@ -2029,9 +2018,10 @@ malloc_state_machine::handle_nonnull (sm_context &sm_ctxt, if (unchecked_p (state)) { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); - sm_ctxt.warn (node, stmt, arg, - make_unique<possible_null_arg> (*this, diag_arg, fndecl, - i)); + sm_ctxt.warn + (node, stmt, arg, + std::make_unique<possible_null_arg> (*this, diag_arg, fndecl, + i)); const allocation_state *astate = as_a_allocation_state (state); sm_ctxt.set_next_state (stmt, arg, astate->get_nonnull ()); @@ -2040,7 +2030,7 @@ malloc_state_machine::handle_nonnull (sm_context &sm_ctxt, { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<null_arg> (*this, diag_arg, fndecl, i)); + std::make_unique<null_arg> (*this, diag_arg, fndecl, i)); sm_ctxt.set_next_state (stmt, arg, m_stop); } else if (state == m_start) @@ -2054,9 +2044,11 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node, const gimple *stmt) const { - if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call_stmt)) { + const gcall &call = *call_stmt; + if (known_allocator_p (callee_fndecl, call)) { on_allocator_call (sm_ctxt, call, &m_free); @@ -2092,7 +2084,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt, if (is_named_call_p (callee_fndecl, "alloca", call, 1) || is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1)) { - tree lhs = gimple_call_lhs (call); + tree lhs = gimple_call_lhs (&call); if (lhs) sm_ctxt.on_transition (node, stmt, lhs, m_start, m_non_heap); return true; @@ -2260,8 +2252,8 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt, { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<possible_null_deref> (*this, - diag_arg)); + std::make_unique<possible_null_deref> (*this, + diag_arg)); const allocation_state *astate = as_a_allocation_state (state); sm_ctxt.set_next_state (stmt, arg, astate->get_nonnull ()); } @@ -2269,7 +2261,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt, { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<null_deref> (*this, diag_arg)); + std::make_unique<null_deref> (*this, diag_arg)); sm_ctxt.set_next_state (stmt, arg, m_stop); } else if (freed_p (state)) @@ -2277,7 +2269,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt, tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); const allocation_state *astate = as_a_allocation_state (state); sm_ctxt.warn (node, stmt, arg, - make_unique<use_after_free> + std::make_unique<use_after_free> (*this, diag_arg, astate->m_deallocator)); sm_ctxt.set_next_state (stmt, arg, m_stop); } @@ -2339,7 +2331,7 @@ maybe_complain_about_deref_before_check (sm_context &sm_ctxt, if (diag_ptr) sm_ctxt.warn (node, stmt, ptr, - make_unique<deref_before_check> (*this, diag_ptr)); + std::make_unique<deref_before_check> (*this, diag_ptr)); sm_ctxt.set_next_state (stmt, ptr, m_stop); } @@ -2349,15 +2341,15 @@ maybe_complain_about_deref_before_check (sm_context &sm_ctxt, void malloc_state_machine::on_allocator_call (sm_context &sm_ctxt, - const gcall *call, + const gcall &call, const deallocator_set *deallocators, bool returns_nonnull) const { - tree lhs = gimple_call_lhs (call); + tree lhs = gimple_call_lhs (&call); if (lhs) { - if (sm_ctxt.get_state (call, lhs) == m_start) - sm_ctxt.set_next_state (call, lhs, + if (sm_ctxt.get_state (&call, lhs) == m_start) + sm_ctxt.set_next_state (&call, lhs, (returns_nonnull ? deallocators->m_nonnull : deallocators->m_unchecked)); @@ -2374,7 +2366,7 @@ malloc_state_machine::on_allocator_call (sm_context &sm_ctxt, void malloc_state_machine::handle_free_of_non_heap (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree arg, const deallocator *d) const { @@ -2386,28 +2378,28 @@ malloc_state_machine::handle_free_of_non_heap (sm_context &sm_ctxt, const svalue *ptr_sval = old_model->get_rvalue (arg, NULL); freed_reg = old_model->deref_rvalue (ptr_sval, arg, NULL); } - sm_ctxt.warn (node, call, arg, - make_unique<free_of_non_heap> + sm_ctxt.warn (node, &call, arg, + std::make_unique<free_of_non_heap> (*this, diag_arg, freed_reg, d->m_name)); - sm_ctxt.set_next_state (call, arg, m_stop); + sm_ctxt.set_next_state (&call, arg, m_stop); } void malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, const deallocator *d, unsigned argno) const { - if (argno >= gimple_call_num_args (call)) + if (argno >= gimple_call_num_args (&call)) return; - tree arg = gimple_call_arg (call, argno); + tree arg = gimple_call_arg (&call, argno); - state_t state = sm_ctxt.get_state (call, arg); + state_t state = sm_ctxt.get_state (&call, arg); /* start/assumed_non_null/unchecked/nonnull -> freed. */ if (state == m_start || assumed_non_null_p (state)) - sm_ctxt.set_next_state (call, arg, d->m_freed); + sm_ctxt.set_next_state (&call, arg, d->m_freed); else if (unchecked_p (state) || nonnull_p (state)) { const allocation_state *astate = as_a_allocation_state (state); @@ -2416,13 +2408,13 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt, { /* Wrong allocator. */ tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); - sm_ctxt.warn (node, call, arg, - make_unique<mismatching_deallocation> + sm_ctxt.warn (node, &call, arg, + std::make_unique<mismatching_deallocation> (*this, diag_arg, astate->m_deallocators, d)); } - sm_ctxt.set_next_state (call, arg, d->m_freed); + sm_ctxt.set_next_state (&call, arg, d->m_freed); } /* Keep state "null" as-is, rather than transitioning to "freed"; @@ -2431,9 +2423,9 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt, { /* freed -> stop, with warning. */ tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); - sm_ctxt.warn (node, call, arg, - make_unique<double_free> (*this, diag_arg, d->m_name)); - sm_ctxt.set_next_state (call, arg, m_stop); + sm_ctxt.warn (node, &call, arg, + std::make_unique<double_free> (*this, diag_arg, d->m_name)); + sm_ctxt.set_next_state (&call, arg, m_stop); } else if (state == m_non_heap) { @@ -2453,14 +2445,14 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt, void malloc_state_machine::on_realloc_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const unsigned argno = 0; const deallocator *d = &m_realloc; - tree arg = gimple_call_arg (call, argno); + tree arg = gimple_call_arg (&call, argno); - state_t state = sm_ctxt.get_state (call, arg); + state_t state = sm_ctxt.get_state (&call, arg); if (unchecked_p (state) || nonnull_p (state)) { @@ -2470,11 +2462,11 @@ malloc_state_machine::on_realloc_call (sm_context &sm_ctxt, { /* Wrong allocator. */ tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); - sm_ctxt.warn (node, call, arg, - make_unique<mismatching_deallocation> + sm_ctxt.warn (node, &call, arg, + std::make_unique<mismatching_deallocation> (*this, diag_arg, astate->m_deallocators, d)); - sm_ctxt.set_next_state (call, arg, m_stop); + sm_ctxt.set_next_state (&call, arg, m_stop); if (path_context *path_ctxt = sm_ctxt.get_path_context ()) path_ctxt->terminate_path (); } @@ -2483,9 +2475,9 @@ malloc_state_machine::on_realloc_call (sm_context &sm_ctxt, { /* freed -> stop, with warning. */ tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); - sm_ctxt.warn (node, call, arg, - make_unique<double_free> (*this, diag_arg, "free")); - sm_ctxt.set_next_state (call, arg, m_stop); + sm_ctxt.warn (node, &call, arg, + std::make_unique<double_free> (*this, diag_arg, "free")); + sm_ctxt.set_next_state (&call, arg, m_stop); if (path_context *path_ctxt = sm_ctxt.get_path_context ()) path_ctxt->terminate_path (); } @@ -2594,7 +2586,7 @@ malloc_state_machine::can_purge_p (state_t s) const std::unique_ptr<pending_diagnostic> malloc_state_machine::on_leak (tree var) const { - return make_unique<malloc_leak> (*this, var); + return std::make_unique<malloc_leak> (*this, var); } /* Implementation of state_machine::reset_when_passed_to_unknown_fn_p vfunc @@ -2707,10 +2699,10 @@ malloc_state_machine::transition_ptr_sval_non_null (region_model *model, /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_malloc_state_machine (logger *logger) { - return new malloc_state_machine (logger); + return std::make_unique<malloc_state_machine> (logger); } /* Specialcase hook for handling realloc, for use by diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc index 5b98067..f05ffe0 100644 --- a/gcc/analyzer/sm-pattern-test.cc +++ b/gcc/analyzer/sm-pattern-test.cc @@ -20,19 +20,11 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" +#include "analyzer/common.h" + #include "tree-pretty-print.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" #include "diagnostic-event-id.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -140,7 +132,7 @@ pattern_test_state_machine::on_condition (sm_context &sm_ctxt, if (tree lhs_expr = sm_ctxt.get_diagnostic_tree (lhs)) { sm_ctxt.warn (node, stmt, lhs_expr, - make_unique<pattern_match> (lhs_expr, op, rhs_cst)); + std::make_unique<pattern_match> (lhs_expr, op, rhs_cst)); } } @@ -154,10 +146,10 @@ pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_pattern_test_state_machine (logger *logger) { - return new pattern_test_state_machine (logger); + return std::make_unique<pattern_test_state_machine> (logger); } } // namespace ana diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc index 6e185cb..7bd5ef6 100644 --- a/gcc/analyzer/sm-sensitive.cc +++ b/gcc/analyzer/sm-sensitive.cc @@ -19,19 +19,10 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-event-id.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -196,8 +187,8 @@ sensitive_state_machine::warn_for_any_exposure (sm_context &sm_ctxt, { tree diag_arg = sm_ctxt.get_diagnostic_tree (arg); sm_ctxt.warn (node, stmt, arg, - make_unique<exposure_through_output_file> (*this, - diag_arg)); + std::make_unique<exposure_through_output_file> (*this, + diag_arg)); } } @@ -210,9 +201,9 @@ sensitive_state_machine::on_stmt (sm_context &sm_ctxt, const gimple *stmt) const { if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call)) { - if (is_named_call_p (callee_fndecl, "getpass", call, 1)) + if (is_named_call_p (callee_fndecl, "getpass", *call, 1)) { tree lhs = gimple_call_lhs (call); if (lhs) @@ -230,7 +221,7 @@ sensitive_state_machine::on_stmt (sm_context &sm_ctxt, } return true; } - else if (is_named_call_p (callee_fndecl, "fwrite", call, 4)) + else if (is_named_call_p (callee_fndecl, "fwrite", *call, 4)) { tree arg = gimple_call_arg (call, 0); warn_for_any_exposure (sm_ctxt, node, stmt, arg); @@ -251,10 +242,10 @@ sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_sensitive_state_machine (logger *logger) { - return new sensitive_state_machine (logger); + return std::make_unique<sensitive_state_machine> (logger); } } // namespace ana diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc index f8b378f..83f2808 100644 --- a/gcc/analyzer/sm-signal.cc +++ b/gcc/analyzer/sm-signal.cc @@ -20,39 +20,28 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "bitmap.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "diagnostic-event-id.h" -#include "analyzer/analyzer-logging.h" -#include "analyzer/sm.h" -#include "analyzer/pending-diagnostic.h" #include "sbitmap.h" #include "ordered-hash-map.h" #include "selftest.h" +#include "cfg.h" +#include "gimple-iterator.h" +#include "cgraph.h" +#include "shortest-paths.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/sm.h" +#include "analyzer/pending-diagnostic.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/checker-path.h" -#include "cfg.h" -#include "gimple-iterator.h" -#include "cgraph.h" #include "analyzer/supergraph.h" #include "analyzer/diagnostic-manager.h" -#include "shortest-paths.h" #include "analyzer/exploded-graph.h" #include "analyzer/function-set.h" #include "analyzer/analyzer-selftests.h" @@ -95,7 +84,7 @@ class signal_unsafe_call : public pending_diagnostic_subclass<signal_unsafe_call> { public: - signal_unsafe_call (const signal_state_machine &sm, const gcall *unsafe_call, + signal_unsafe_call (const signal_state_machine &sm, const gcall &unsafe_call, tree unsafe_fndecl) : m_sm (sm), m_unsafe_call (unsafe_call), m_unsafe_fndecl (unsafe_fndecl) { @@ -106,7 +95,7 @@ public: bool operator== (const signal_unsafe_call &other) const { - return m_unsafe_call == other.m_unsafe_call; + return &m_unsafe_call == &other.m_unsafe_call; } int get_controlling_option () const final override @@ -126,7 +115,7 @@ public: suggesting the replacement. */ if (const char *replacement = get_replacement_fn ()) { - location_t note_loc = gimple_location (m_unsafe_call); + location_t note_loc = gimple_location (&m_unsafe_call); /* It would be nice to add a fixit, but the gimple call location covers the whole call expression. It isn't currently possible to cut this down to just the call @@ -170,7 +159,7 @@ public: private: const signal_state_machine &m_sm; - const gcall *m_unsafe_call; + const gcall &m_unsafe_call; tree m_unsafe_fndecl; /* Returns a replacement function as text if it exists. Currently @@ -207,7 +196,7 @@ update_model_for_signal_handler (region_model *model, gcc_assert (model); /* Purge all state within MODEL. */ *model = region_model (model->get_manager ()); - model->push_frame (handler_fun, NULL, NULL); + model->push_frame (handler_fun, nullptr, nullptr, nullptr); } /* Custom exploded_edge info: entry into a signal-handler. */ @@ -236,10 +225,10 @@ public: const final override { emission_path->add_event - (make_unique<precanned_custom_event> - (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0), - "later on," - " when the signal is delivered to the process")); + (std::make_unique<precanned_custom_event> + (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0), + "later on," + " when the signal is delivered to the process")); } }; @@ -282,7 +271,7 @@ public: if (dst_enode) eg->add_edge (src_enode, dst_enode, NULL, /*state_change (),*/ true, /* assume does work */ - make_unique<signal_delivery_edge_info_t> ()); + std::make_unique<signal_delivery_edge_info_t> ()); } const signal_state_machine &m_sm; @@ -342,9 +331,9 @@ signal_state_machine::on_stmt (sm_context &sm_ctxt, if (global_state == m_start) { if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) - if (is_named_call_p (callee_fndecl, "signal", call, 2) - || is_std_named_call_p (callee_fndecl, "signal", call, 2)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call)) + if (is_named_call_p (callee_fndecl, "signal", *call, 2) + || is_std_named_call_p (callee_fndecl, "signal", *call, 2)) { tree handler = gimple_call_arg (call, 1); if (TREE_CODE (handler) == ADDR_EXPR @@ -359,12 +348,12 @@ signal_state_machine::on_stmt (sm_context &sm_ctxt, else if (global_state == m_in_signal_handler) { if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call)) if (signal_unsafe_p (callee_fndecl)) if (sm_ctxt.get_global_state () == m_in_signal_handler) sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<signal_unsafe_call> - (*this, call, callee_fndecl)); + std::make_unique<signal_unsafe_call> + (*this, *call, callee_fndecl)); } return false; @@ -380,10 +369,10 @@ signal_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_signal_state_machine (logger *logger) { - return new signal_state_machine (logger); + return std::make_unique<signal_state_machine> (logger); } #if CHECKING_P diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index 5d0aec3..e782081 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -20,20 +20,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "gimple-iterator.h" #include "ordered-hash-map.h" #include "cgraph.h" @@ -42,6 +30,10 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "fold-const.h" +#include "diagnostic-format-sarif.h" +#include "gcc-urlifier.h" + +#include "analyzer/analyzer-logging.h" #include "analyzer/supergraph.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" @@ -51,8 +43,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/program-state.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/constraint-manager.h" -#include "diagnostic-format-sarif.h" -#include "gcc-urlifier.h" #if ENABLE_ANALYZER @@ -140,7 +130,7 @@ private: void check_for_tainted_size_arg (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree callee_fndecl) const; void check_for_tainted_divisor (sm_context &sm_ctxt, const supernode *node, @@ -1099,9 +1089,9 @@ taint_state_machine::on_stmt (sm_context &sm_ctxt, const gimple *stmt) const { if (const gcall *call = dyn_cast <const gcall *> (stmt)) - if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) + if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call)) { - if (is_named_call_p (callee_fndecl, "fread", call, 4)) + if (is_named_call_p (callee_fndecl, "fread", *call, 4)) { tree arg = gimple_call_arg (call, 0); @@ -1117,14 +1107,14 @@ taint_state_machine::on_stmt (sm_context &sm_ctxt, /* External function with "access" attribute. */ if (sm_ctxt.unknown_side_effects_p ()) - check_for_tainted_size_arg (sm_ctxt, node, call, callee_fndecl); + check_for_tainted_size_arg (sm_ctxt, node, *call, callee_fndecl); if (is_assertion_failure_handler_p (callee_fndecl) && sm_ctxt.get_global_state () == m_tainted_control_flow) { sm_ctxt.warn (node, call, NULL_TREE, - make_unique<tainted_assertion> (*this, NULL_TREE, - callee_fndecl)); + std::make_unique<tainted_assertion> (*this, NULL_TREE, + callee_fndecl)); } } // TODO: ...etc; many other sources of untrusted data @@ -1433,7 +1423,7 @@ taint_state_machine::combine_states (state_t s0, state_t s1) const void taint_state_machine::check_for_tainted_size_arg (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree callee_fndecl) const { tree fntype = TREE_TYPE (callee_fndecl); @@ -1464,17 +1454,17 @@ taint_state_machine::check_for_tainted_size_arg (sm_context &sm_ctxt, if (access->sizarg == UINT_MAX) continue; - tree size_arg = gimple_call_arg (call, access->sizarg); + tree size_arg = gimple_call_arg (&call, access->sizarg); - state_t state = sm_ctxt.get_state (call, size_arg); + state_t state = sm_ctxt.get_state (&call, size_arg); enum bounds b; if (get_taint (state, TREE_TYPE (size_arg), &b)) { const char* const access_str = TREE_STRING_POINTER (access->to_external_string ()); tree diag_size = sm_ctxt.get_diagnostic_tree (size_arg); - sm_ctxt.warn (node, call, size_arg, - make_unique<tainted_access_attrib_size> + sm_ctxt.warn (node, &call, size_arg, + std::make_unique<tainted_access_attrib_size> (*this, diag_size, b, callee_fndecl, access->sizarg, @@ -1518,8 +1508,9 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt, return; tree diag_divisor = sm_ctxt.get_diagnostic_tree (divisor_expr); - sm_ctxt.warn (node, assign, divisor_expr, - make_unique <tainted_divisor> (*this, diag_divisor, b)); + sm_ctxt.warn + (node, assign, divisor_expr, + std::make_unique <tainted_divisor> (*this, diag_divisor, b)); sm_ctxt.set_next_state (assign, divisor_sval, m_stop); } } @@ -1528,10 +1519,10 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt, /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_taint_state_machine (logger *logger) { - return new taint_state_machine (logger); + return std::make_unique<taint_state_machine> (logger); } /* A closed concrete range. */ @@ -1682,8 +1673,8 @@ region_model::check_region_for_taint (const region *reg, if (index_can_be_out_of_bounds_p (element_reg)) { tree arg = get_representative_tree (index); - ctxt->warn (make_unique<tainted_array_index> (taint_sm, - arg, b)); + ctxt->warn (std::make_unique<tainted_array_index> (taint_sm, + arg, b)); } else if (ctxt->get_logger ()) ctxt->get_logger ()->log ("rejecting tainted_array_index as" @@ -1709,8 +1700,8 @@ region_model::check_region_for_taint (const region *reg, if (taint_sm.get_taint (state, effective_type, &b)) { tree arg = get_representative_tree (offset); - ctxt->warn (make_unique<tainted_offset> (taint_sm, arg, b, - offset)); + ctxt->warn (std::make_unique<tainted_offset> (taint_sm, arg, b, + offset)); } } break; @@ -1727,7 +1718,7 @@ region_model::check_region_for_taint (const region *reg, if (taint_sm.get_taint (state, size_sval->get_type (), &b)) { tree arg = get_representative_tree (size_sval); - ctxt->warn (make_unique<tainted_size> (taint_sm, arg, b)); + ctxt->warn (std::make_unique<tainted_size> (taint_sm, arg, b)); } } break; @@ -1773,7 +1764,7 @@ region_model::check_dynamic_size_for_taint (enum memory_space mem_space, if (taint_sm.get_taint (state, size_in_bytes->get_type (), &b)) { tree arg = get_representative_tree (size_in_bytes); - ctxt->warn (make_unique<tainted_allocation_size> + ctxt->warn (std::make_unique<tainted_allocation_size> (taint_sm, arg, size_in_bytes, b, mem_space)); } } diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc index 3e7fa66..0abbdd6 100644 --- a/gcc/analyzer/sm.cc +++ b/gcc/analyzer/sm.cc @@ -18,21 +18,11 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "options.h" -#include "function.h" -#include "diagnostic-core.h" -#include "pretty-print.h" -#include "diagnostic.h" +#define INCLUDE_LIST +#include "analyzer/common.h" + #include "tree-diagnostic.h" -#include "analyzer/analyzer.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/call-string.h" @@ -41,7 +31,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/svalue.h" #include "analyzer/program-state.h" #include "analyzer/pending-diagnostic.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -83,7 +72,7 @@ state_machine::state::to_json () const pretty_printer pp; pp_format_decoder (&pp) = default_tree_printer; dump_to_pp (&pp); - return ::make_unique<json::string> (pp_formatted_text (&pp)); + return std::make_unique<json::string> (pp_formatted_text (&pp)); } /* class state_machine. */ @@ -154,11 +143,11 @@ state_machine::dump_to_pp (pretty_printer *pp) const std::unique_ptr<json::object> state_machine::to_json () const { - auto sm_obj = ::make_unique<json::object> (); + auto sm_obj = std::make_unique<json::object> (); sm_obj->set_string ("name", m_name); { - auto states_arr = ::make_unique<json::array> (); + auto states_arr = std::make_unique<json::array> (); unsigned i; state *s; FOR_EACH_VEC_ELT (m_states, i, s) @@ -181,35 +170,40 @@ sm_context::get_old_region_model () const } /* Create instances of the various state machines, each using LOGGER, - and populate OUT with them. */ + returning a vector of them. */ -void -make_checkers (auto_delete_vec <state_machine> &out, logger *logger) +std::vector<std::unique_ptr<state_machine>> +make_checkers (logger *logger) { - out.safe_push (make_malloc_state_machine (logger)); - out.safe_push (make_fileptr_state_machine (logger)); - out.safe_push (make_fd_state_machine (logger)); - out.safe_push (make_taint_state_machine (logger)); - out.safe_push (make_sensitive_state_machine (logger)); - out.safe_push (make_signal_state_machine (logger)); - out.safe_push (make_va_list_state_machine (logger)); + /* Start with a list so that we can filter it. */ + std::list<std::unique_ptr<state_machine>> out; + out.push_back (make_malloc_state_machine (logger)); + out.push_back (make_fileptr_state_machine (logger)); + out.push_back (make_fd_state_machine (logger)); + out.push_back (make_taint_state_machine (logger)); + out.push_back (make_sensitive_state_machine (logger)); + out.push_back (make_signal_state_machine (logger)); + out.push_back (make_va_list_state_machine (logger)); /* We only attempt to run the pattern tests if it might have been manually enabled (for DejaGnu purposes). */ if (flag_analyzer_checker) - out.safe_push (make_pattern_test_state_machine (logger)); + out.push_back (make_pattern_test_state_machine (logger)); if (flag_analyzer_checker) { - unsigned read_index, write_index; - state_machine **sm; - - /* TODO: this leaks the machines - Would be nice to log the things that were removed. */ - VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm, - 0 != strcmp (flag_analyzer_checker, - (*sm)->get_name ())); + out.remove_if ([] (auto &sm) + { + return 0 != strcmp (flag_analyzer_checker, + sm->get_name ()); + }); } + + std::vector<std::unique_ptr<state_machine>> out_vec; + for (auto &iter: out) + out_vec.push_back (std::move (iter)); + + return out_vec; } } // namespace ana diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h index a1f96e2..a932765 100644 --- a/gcc/analyzer/sm.h +++ b/gcc/analyzer/sm.h @@ -235,7 +235,7 @@ public: Use in preference to gimple_call_fndecl (and gimple_call_addr_fndecl), since it can look through function pointer assignments and other callback handling. */ - virtual tree get_fndecl_for_call (const gcall *call) = 0; + virtual tree get_fndecl_for_call (const gcall &call) = 0; /* Get the old state of VAR at STMT. */ virtual state_machine::state_t get_state (const gimple *stmt, @@ -341,17 +341,17 @@ protected: /* The various state_machine subclasses are hidden in their respective implementation files. */ -extern void make_checkers (auto_delete_vec <state_machine> &out, - logger *logger); - -extern state_machine *make_malloc_state_machine (logger *logger); -extern state_machine *make_fileptr_state_machine (logger *logger); -extern state_machine *make_taint_state_machine (logger *logger); -extern state_machine *make_sensitive_state_machine (logger *logger); -extern state_machine *make_signal_state_machine (logger *logger); -extern state_machine *make_pattern_test_state_machine (logger *logger); -extern state_machine *make_va_list_state_machine (logger *logger); -extern state_machine *make_fd_state_machine (logger *logger); +extern std::vector<std::unique_ptr<state_machine>> +make_checkers (logger *logger); + +extern std::unique_ptr<state_machine> make_malloc_state_machine (logger *); +extern std::unique_ptr<state_machine> make_fileptr_state_machine (logger *); +extern std::unique_ptr<state_machine> make_taint_state_machine (logger *); +extern std::unique_ptr<state_machine> make_sensitive_state_machine (logger *); +extern std::unique_ptr<state_machine> make_signal_state_machine (logger *); +extern std::unique_ptr<state_machine> make_pattern_test_state_machine (logger *); +extern std::unique_ptr<state_machine> make_va_list_state_machine (logger *); +extern std::unique_ptr<state_machine> make_fd_state_machine (logger *); } // namespace ana diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc index b7a5260..7a93cee 100644 --- a/gcc/analyzer/state-purge.cc +++ b/gcc/analyzer/state-purge.cc @@ -18,26 +18,21 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" +#include "analyzer/common.h" + #include "timevar.h" -#include "tree-ssa-alias.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "stringpool.h" +#include "gimple-pretty-print.h" #include "tree-vrp.h" #include "gimple-ssa.h" +#include "stringpool.h" #include "tree-ssanames.h" #include "tree-phinodes.h" #include "options.h" #include "ssa-iterators.h" -#include "diagnostic-core.h" -#include "gimple-pretty-print.h" -#include "analyzer/analyzer.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "cgraph.h" + #include "analyzer/call-string.h" #include "analyzer/supergraph.h" #include "analyzer/program-point.h" @@ -45,8 +40,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/state-purge.h" #include "analyzer/store.h" #include "analyzer/region-model.h" -#include "gimple-walk.h" -#include "cgraph.h" #if ENABLE_ANALYZER @@ -737,7 +730,7 @@ state_purge_per_decl::process_worklists (const state_purge_map &map, worklist.safe_push (iter); region_model model (mgr); - model.push_frame (get_function (), NULL, NULL); + model.push_frame (get_function (), nullptr, nullptr, nullptr); /* Process worklist by walking backwards until we reach a stmt that fully overwrites the decl. */ diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index ab469dd..e6723c7 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -18,44 +18,23 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" -#include "fold-const.h" -#include "tree-pretty-print.h" -#include "diagnostic-color.h" -#include "bitmap.h" -#include "selftest.h" -#include "analyzer/analyzer.h" -#include "analyzer/analyzer-logging.h" +#include "analyzer/common.h" + #include "ordered-hash-map.h" -#include "options.h" #include "cfg.h" -#include "analyzer/supergraph.h" #include "sbitmap.h" +#include "stor-layout.h" + +#include "text-art/tree-widget.h" + +#include "analyzer/analyzer-logging.h" +#include "analyzer/supergraph.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" -#include "stor-layout.h" -#include "text-art/tree-widget.h" -#include "make-unique.h" #if ENABLE_ANALYZER @@ -234,7 +213,7 @@ bit_range::dump () const std::unique_ptr<json::object> bit_range::to_json () const { - auto obj = ::make_unique<json::object> (); + auto obj = std::make_unique<json::object> (); obj->set ("start_bit_offset", bit_offset_to_json (m_start_bit_offset)); obj->set ("size_in_bits", @@ -508,7 +487,7 @@ byte_range::dump () const std::unique_ptr<json::object> byte_range::to_json () const { - auto obj = ::make_unique<json::object> (); + auto obj = std::make_unique<json::object> (); obj->set ("start_byte_offset", byte_offset_to_json (m_start_byte_offset)); obj->set ("size_in_bytes", @@ -773,7 +752,7 @@ binding_map::dump (bool simple) const std::unique_ptr<json::object> binding_map::to_json () const { - auto map_obj = ::make_unique<json::object> (); + auto map_obj = std::make_unique<json::object> (); auto_vec <const binding_key *> binding_keys; for (map_t::iterator iter = m_map.begin (); @@ -1455,7 +1434,7 @@ binding_cluster::validate () const std::unique_ptr<json::object> binding_cluster::to_json () const { - auto cluster_obj = ::make_unique<json::object> (); + auto cluster_obj = std::make_unique<json::object> (); cluster_obj->set_bool ("escaped", m_escaped); cluster_obj->set_bool ("touched", m_touched); @@ -2208,7 +2187,7 @@ binding_cluster::mark_as_escaped () Use P to purge state involving conjured_svalues. */ void -binding_cluster::on_unknown_fncall (const gcall *call, +binding_cluster::on_unknown_fncall (const gcall &call, store_manager *mgr, const conjured_purge &p) { @@ -2221,7 +2200,7 @@ binding_cluster::on_unknown_fncall (const gcall *call, /* Bind it to a new "conjured" value using CALL. */ const svalue *sval = mgr->get_svalue_manager ()->get_or_create_conjured_svalue - (m_base_region->get_type (), call, m_base_region, p); + (m_base_region->get_type (), &call, m_base_region, p); bind (mgr, m_base_region, sval); } @@ -2672,7 +2651,7 @@ store::validate () const std::unique_ptr<json::object> store::to_json () const { - auto store_obj = ::make_unique<json::object> (); + auto store_obj = std::make_unique<json::object> (); /* Sort into some deterministic order. */ auto_vec<const region *> base_regions; @@ -2695,7 +2674,7 @@ store::to_json () const { gcc_assert (parent_reg); - auto clusters_in_parent_reg_obj = ::make_unique<json::object> (); + auto clusters_in_parent_reg_obj = std::make_unique<json::object> (); const region *base_reg; unsigned j; @@ -3259,7 +3238,7 @@ store::mark_as_escaped (const region *base_reg) (either in this fncall, or in a prior one). */ void -store::on_unknown_fncall (const gcall *call, store_manager *mgr, +store::on_unknown_fncall (const gcall &call, store_manager *mgr, const conjured_purge &p) { m_called_unknown_fn = true; diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index 6c84812..171324c 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -666,7 +666,7 @@ public: store_manager *mgr); void mark_as_escaped (); - void on_unknown_fncall (const gcall *call, store_manager *mgr, + void on_unknown_fncall (const gcall &call, store_manager *mgr, const conjured_purge &p); void on_asm (const gasm *stmt, store_manager *mgr, const conjured_purge &p); @@ -800,7 +800,7 @@ public: model_merger *merger); void mark_as_escaped (const region *base_reg); - void on_unknown_fncall (const gcall *call, store_manager *mgr, + void on_unknown_fncall (const gcall &call, store_manager *mgr, const conjured_purge &p); bool escaped_p (const region *reg) const; diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index f35adf0..de2c330 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -18,42 +18,23 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "tm.h" -#include "toplev.h" -#include "hash-table.h" -#include "vec.h" -#include "ggc.h" -#include "basic-block.h" -#include "function.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "gimple-fold.h" -#include "tree-eh.h" -#include "gimple-expr.h" -#include "is-a.h" +#include "analyzer/common.h" + #include "timevar.h" #include "gimple-pretty-print.h" -#include "tree-pretty-print.h" -#include "graphviz.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "bitmap.h" -#include "cfganal.h" -#include "function.h" -#include "analyzer/analyzer.h" #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" #include "cfg.h" #include "digraph.h" #include "tree-cfg.h" +#include "tree-dfa.h" +#include "cfganal.h" +#include "except.h" + #include "analyzer/supergraph.h" #include "analyzer/analyzer-logging.h" -#include "make-unique.h" +#include "analyzer/region-model.h" #if ENABLE_ANALYZER @@ -465,11 +446,11 @@ supergraph::dump_dot (const char *path, const dump_args_t &dump_args) const std::unique_ptr<json::object> supergraph::to_json () const { - auto sgraph_obj = ::make_unique<json::object> (); + auto sgraph_obj = std::make_unique<json::object> (); /* Nodes. */ { - auto nodes_arr = ::make_unique<json::array> (); + auto nodes_arr = std::make_unique<json::array> (); unsigned i; supernode *n; FOR_EACH_VEC_ELT (m_nodes, i, n) @@ -479,7 +460,7 @@ supergraph::to_json () const /* Edges. */ { - auto edges_arr = ::make_unique<json::array> (); + auto edges_arr = std::make_unique<json::array> (); unsigned i; superedge *n; FOR_EACH_VEC_ELT (m_edges, i, n) @@ -511,21 +492,25 @@ supergraph::add_node (function *fun, basic_block bb, gcall *returning_call, /* Create a new cfg_superedge from SRC to DEST for the underlying CFG edge E, adding it to this supergraph. - If the edge is for a switch statement, create a switch_cfg_superedge - subclass. */ + If the edge is for a switch or eh_dispatch statement, create a + switch_cfg_superedge or eh_dispatch_cfg_superedge subclass, + respectively */ cfg_superedge * supergraph::add_cfg_edge (supernode *src, supernode *dest, ::edge e) { - /* Special-case switch edges. */ + /* Special-case switch and eh_dispatch edges. */ gimple *stmt = src->get_last_stmt (); - cfg_superedge *new_edge; + std::unique_ptr<cfg_superedge> new_edge; if (stmt && stmt->code == GIMPLE_SWITCH) - new_edge = new switch_cfg_superedge (src, dest, e); + new_edge = std::make_unique<switch_cfg_superedge> (src, dest, e); + else if (stmt && stmt->code == GIMPLE_EH_DISPATCH) + new_edge = eh_dispatch_cfg_superedge::make (src, dest, e, + as_a <geh_dispatch *> (stmt)); else - new_edge = new cfg_superedge (src, dest, e); - add_edge (new_edge); - return new_edge; + new_edge = std::make_unique<cfg_superedge> (src, dest, e); + add_edge (new_edge.get ()); + return new_edge.release (); } /* Create and add a call_superedge representing an interprocedural call @@ -720,7 +705,7 @@ supernode::dump_dot_id (pretty_printer *pp) const std::unique_ptr<json::object> supernode::to_json () const { - auto snode_obj = ::make_unique<json::object> (); + auto snode_obj = std::make_unique<json::object> (); snode_obj->set_integer ("idx", m_index); snode_obj->set_integer ("bb_idx", m_bb->index); @@ -737,7 +722,7 @@ supernode::to_json () const /* Phi nodes. */ { - auto phi_arr = ::make_unique<json::array> (); + auto phi_arr = std::make_unique<json::array> (); for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis (); !gsi_end_p (gpi); gsi_next (&gpi)) { @@ -752,7 +737,7 @@ supernode::to_json () const /* Statements. */ { - auto stmt_arr = ::make_unique<json::array> (); + auto stmt_arr = std::make_unique<json::array> (); int i; gimple *stmt; FOR_EACH_VEC_ELT (m_stmts, i, stmt) @@ -983,7 +968,7 @@ superedge::dump_dot (graphviz_out *gv, const dump_args_t &) const std::unique_ptr<json::object> superedge::to_json () const { - auto sedge_obj = ::make_unique<json::object> (); + auto sedge_obj = std::make_unique<json::object> (); sedge_obj->set_string ("kind", edge_kind_to_string (m_kind)); sedge_obj->set_integer ("src_idx", m_src->m_index); sedge_obj->set_integer ("dst_idx", m_dest->m_index); @@ -1030,6 +1015,7 @@ label_text superedge::get_description (bool user_facing) const { pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; dump_label_to_pp (&pp, user_facing); return label_text::take (xstrdup (pp_formatted_text (&pp))); } @@ -1099,6 +1085,8 @@ cfg_superedge::get_phi_arg (const gphi *phi) const return gimple_phi_arg_def (phi, index); } +/* class switch_cfg_superedge : public cfg_superedge. */ + switch_cfg_superedge::switch_cfg_superedge (supernode *src, supernode *dst, ::edge e) @@ -1206,6 +1194,203 @@ switch_cfg_superedge::implicitly_created_default_p () const return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION; } +/* class eh_dispatch_cfg_superedge : public cfg_superedge. */ + +/* Given an ERT_TRY region, get the eh_catch corresponding to + the label of DST_SNODE, if any. */ + +static eh_catch +get_catch (eh_region eh_reg, supernode *dst_snode) +{ + gcc_assert (eh_reg->type == ERT_TRY); + + tree dst_snode_label = dst_snode->get_label (); + if (!dst_snode_label) + return nullptr; + + for (eh_catch iter = eh_reg->u.eh_try.first_catch; + iter; + iter = iter->next_catch) + if (iter->label == dst_snode_label) + return iter; + + return nullptr; +} + +std::unique_ptr<eh_dispatch_cfg_superedge> +eh_dispatch_cfg_superedge::make (supernode *src_snode, + supernode *dst_snode, + ::edge e, + const geh_dispatch *eh_dispatch_stmt) +{ + const eh_status *eh = src_snode->get_function ()->eh; + gcc_assert (eh); + int region_idx = gimple_eh_dispatch_region (eh_dispatch_stmt); + gcc_assert (region_idx > 0); + gcc_assert ((*eh->region_array)[region_idx]); + eh_region eh_reg = (*eh->region_array)[region_idx]; + gcc_assert (eh_reg); + switch (eh_reg->type) + { + default: + gcc_unreachable (); + case ERT_CLEANUP: + // TODO + gcc_unreachable (); + break; + case ERT_TRY: + { + eh_catch ehc = get_catch (eh_reg, dst_snode); + return std::make_unique<eh_dispatch_try_cfg_superedge> + (src_snode, dst_snode, + e, eh_dispatch_stmt, + eh_reg, ehc); + } + break; + case ERT_ALLOWED_EXCEPTIONS: + return std::make_unique<eh_dispatch_allowed_cfg_superedge> + (src_snode, dst_snode, + e, eh_dispatch_stmt, + eh_reg); + break; + case ERT_MUST_NOT_THROW: + // TODO + gcc_unreachable (); + break; + } +} + +eh_dispatch_cfg_superedge:: +eh_dispatch_cfg_superedge (supernode *src, + supernode *dst, + ::edge e, + const geh_dispatch *eh_dispatch_stmt, + eh_region eh_reg) +: cfg_superedge (src, dst, e), + m_eh_dispatch_stmt (eh_dispatch_stmt), + m_eh_region (eh_reg) +{ + gcc_assert (m_eh_region); +} + +const eh_status & +eh_dispatch_cfg_superedge::get_eh_status () const +{ + const eh_status *eh = m_src->get_function ()->eh; + gcc_assert (eh); + return *eh; +} + +// class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge + +/* Implementation of superedge::dump_label_to_pp for CFG superedges for + "eh_dispatch" statements for ERT_TRY regions. */ + +void +eh_dispatch_try_cfg_superedge::dump_label_to_pp (pretty_printer *pp, + bool user_facing) const +{ + if (!user_facing) + pp_string (pp, "ERT_TRY: "); + if (m_eh_catch) + { + bool first = true; + for (tree iter = m_eh_catch->type_list; iter; iter = TREE_CHAIN (iter)) + { + if (!first) + pp_string (pp, ", "); + pp_printf (pp, "on catch %qT", TREE_VALUE (iter)); + first = false; + } + } + else + pp_string (pp, "on uncaught exception"); +} + +bool +eh_dispatch_try_cfg_superedge:: +apply_constraints (region_model *model, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) const +{ + return model->apply_constraints_for_eh_dispatch_try + (*this, ctxt, exception_type, out); +} + +// class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge + +eh_dispatch_allowed_cfg_superedge:: +eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e, + const geh_dispatch *eh_dispatch_stmt, + eh_region eh_reg) +: eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg) +{ + gcc_assert (eh_reg->type == ERT_ALLOWED_EXCEPTIONS); + + /* We expect two sibling out-edges at an eh_dispatch from such a region: + + - one to a bb without a gimple label, with a resx, + for exceptions of expected types + + - one to a bb with a gimple label, with a call to __cxa_unexpected, + for exceptions of unexpected types. + + Set m_kind for this edge accordingly. */ + gcc_assert (e->src->succs->length () == 2); + tree label_for_unexpected_exceptions = eh_reg->u.allowed.label; + tree label_for_dest_enode = dst->get_label (); + if (label_for_dest_enode == label_for_unexpected_exceptions) + m_kind = eh_kind::unexpected; + else + { + gcc_assert (label_for_dest_enode == nullptr); + m_kind = eh_kind::expected; + } +} + +void +eh_dispatch_allowed_cfg_superedge::dump_label_to_pp (pretty_printer *pp, + bool user_facing) const +{ + if (!user_facing) + { + switch (m_kind) + { + default: + gcc_unreachable (); + case eh_dispatch_allowed_cfg_superedge::eh_kind::expected: + pp_string (pp, "expected: "); + break; + case eh_dispatch_allowed_cfg_superedge::eh_kind::unexpected: + pp_string (pp, "unexpected: "); + break; + } + pp_string (pp, "ERT_ALLOWED_EXCEPTIONS: "); + eh_region eh_reg = get_eh_region (); + bool first = true; + for (tree iter = eh_reg->u.allowed.type_list; iter; + iter = TREE_CHAIN (iter)) + { + if (!first) + pp_string (pp, ", "); + pp_printf (pp, "%qT", TREE_VALUE (iter)); + first = false; + } + } +} + +bool +eh_dispatch_allowed_cfg_superedge:: +apply_constraints (region_model *model, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) const +{ + return model->apply_constraints_for_eh_dispatch_allowed + (*this, ctxt, exception_type, out); +} + /* Implementation of superedge::dump_label_to_pp for interprocedural superedges. */ @@ -1261,13 +1446,13 @@ callgraph_superedge::get_callee_decl () const /* Get the gcall * of this interprocedural call/return edge. */ -gcall * +const gcall & callgraph_superedge::get_call_stmt () const { if (m_cedge) - return m_cedge->call_stmt; + return *m_cedge->call_stmt; - return m_src->get_final_call (); + return *m_src->get_final_call (); } /* Get the calling fndecl at this interprocedural call/return edge. */ @@ -1289,19 +1474,19 @@ callgraph_superedge::get_arg_for_parm (tree parm_to_find, gcc_assert (TREE_CODE (parm_to_find) == PARM_DECL); tree callee = get_callee_decl (); - const gcall *call_stmt = get_call_stmt (); + const gcall &call_stmt = get_call_stmt (); unsigned i = 0; for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm; iter_parm = DECL_CHAIN (iter_parm), ++i) { - if (i >= gimple_call_num_args (call_stmt)) + if (i >= gimple_call_num_args (&call_stmt)) return NULL_TREE; if (iter_parm == parm_to_find) { if (out) *out = callsite_expr::from_zero_based_param (i); - return gimple_call_arg (call_stmt, i); + return gimple_call_arg (&call_stmt, i); } } @@ -1319,15 +1504,15 @@ callgraph_superedge::get_parm_for_arg (tree arg_to_find, callsite_expr *out) const { tree callee = get_callee_decl (); - const gcall *call_stmt = get_call_stmt (); + const gcall &call_stmt = get_call_stmt (); unsigned i = 0; for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm; iter_parm = DECL_CHAIN (iter_parm), ++i) { - if (i >= gimple_call_num_args (call_stmt)) + if (i >= gimple_call_num_args (&call_stmt)) return NULL_TREE; - tree param = gimple_call_arg (call_stmt, i); + tree param = gimple_call_arg (&call_stmt, i); if (arg_to_find == param) { if (out) @@ -1353,7 +1538,7 @@ callgraph_superedge::map_expr_from_caller_to_callee (tree caller_expr, if (parm) return parm; /* Otherwise try return value. */ - if (caller_expr == gimple_call_lhs (get_call_stmt ())) + if (caller_expr == gimple_call_lhs (&get_call_stmt ())) { if (out) *out = callsite_expr::from_return_value (); @@ -1388,7 +1573,7 @@ callgraph_superedge::map_expr_from_callee_to_caller (tree callee_expr, { if (out) *out = callsite_expr::from_return_value (); - return gimple_call_lhs (get_call_stmt ()); + return gimple_call_lhs (&get_call_stmt ()); } return NULL_TREE; diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h index 6f94f99..8796ab7 100644 --- a/gcc/analyzer/supergraph.h +++ b/gcc/analyzer/supergraph.h @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "gimple-iterator.h" #include "digraph.h" +#include "except.h" using namespace ana; @@ -42,6 +43,9 @@ class superedge; class return_superedge; class cfg_superedge; class switch_cfg_superedge; + class eh_dispatch_cfg_superedge; + class eh_dispatch_try_cfg_superedge; + class eh_dispatch_allowed_cfg_superedge; class supercluster; class dot_annotator; @@ -126,7 +130,7 @@ public: return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (bb); } - /* Get the supernode containing the second half of the gcall * + /* Get the supernode containing the second half of the gcall & at an interprocedural call, within the caller. */ supernode *get_caller_next_node (cgraph_edge *edge) const { @@ -330,6 +334,9 @@ class superedge : public dedge<supergraph_traits> virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; } virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; } virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; } + virtual const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const { return nullptr; } + virtual const eh_dispatch_try_cfg_superedge *dyn_cast_eh_dispatch_try_cfg_superedge () const { return nullptr; } + virtual const eh_dispatch_allowed_cfg_superedge *dyn_cast_eh_dispatch_allowed_cfg_superedge () const { return nullptr; } virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; } virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; } virtual call_superedge *dyn_cast_call_superedge () { return NULL; } @@ -415,7 +422,7 @@ class callgraph_superedge : public superedge function *get_caller_function () const; tree get_callee_decl () const; tree get_caller_decl () const; - gcall *get_call_stmt () const; + const gcall &get_call_stmt () const; tree get_arg_for_parm (tree parm, callsite_expr *out) const; tree get_parm_for_arg (tree arg, callsite_expr *out) const; tree map_expr_from_caller_to_callee (tree caller_expr, @@ -592,6 +599,164 @@ is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge) namespace ana { +/* A subclass for edges from eh_dispatch statements, retaining enough + information to identify the various types being caught, vs the + "unhandled type" case, and for adding labels when rendering + via graphviz. + This is abstract; there are concrete subclasses based on the type + of the eh_region. */ + +class eh_dispatch_cfg_superedge : public cfg_superedge +{ + public: + static std::unique_ptr<eh_dispatch_cfg_superedge> + make (supernode *src, + supernode *dest, + ::edge e, + const geh_dispatch *eh_dispatch_stmt); + + const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const + final override + { + return this; + } + + const geh_dispatch * + get_eh_dispatch_stmt () const + { + return m_eh_dispatch_stmt; + } + + const eh_status &get_eh_status () const; + eh_region get_eh_region () const { return m_eh_region; } + + virtual bool + apply_constraints (region_model *model, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) const = 0; + +protected: + eh_dispatch_cfg_superedge (supernode *src, supernode *dst, ::edge e, + const geh_dispatch *eh_dispatch_stmt, + eh_region eh_reg); + +private: + const geh_dispatch *m_eh_dispatch_stmt; + eh_region m_eh_region; +}; + +} // namespace ana + +template <> +template <> +inline bool +is_a_helper <const eh_dispatch_cfg_superedge *>::test (const superedge *sedge) +{ + return sedge->dyn_cast_eh_dispatch_cfg_superedge () != NULL; +} + +namespace ana { + +/* A concrete subclass for edges from an eh_dispatch statements + for ERT_TRY regions. */ + +class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge +{ + public: + eh_dispatch_try_cfg_superedge (supernode *src, supernode *dst, ::edge e, + const geh_dispatch *eh_dispatch_stmt, + eh_region eh_reg, + eh_catch ehc) + : eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg), + m_eh_catch (ehc) + { + gcc_assert (eh_reg->type == ERT_TRY); + } + + const eh_dispatch_try_cfg_superedge * + dyn_cast_eh_dispatch_try_cfg_superedge () const final override + { + return this; + } + + void dump_label_to_pp (pretty_printer *pp, + bool user_facing) const final override; + + eh_catch get_eh_catch () const { return m_eh_catch; } + + bool + apply_constraints (region_model *model, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) + const final override; + +private: + eh_catch m_eh_catch; +}; + +} // namespace ana + +template <> +template <> +inline bool +is_a_helper <const eh_dispatch_try_cfg_superedge *>::test (const superedge *sedge) +{ + return sedge->dyn_cast_eh_dispatch_try_cfg_superedge () != NULL; +} + +namespace ana { + +/* A concrete subclass for edges from an eh_dispatch statements + for ERT_ALLOWED_EXCEPTIONS regions. */ + +class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge +{ + public: + enum eh_kind + { + expected, + unexpected + }; + + eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e, + const geh_dispatch *eh_dispatch_stmt, + eh_region eh_reg); + + const eh_dispatch_allowed_cfg_superedge * + dyn_cast_eh_dispatch_allowed_cfg_superedge () const final override + { + return this; + } + + void dump_label_to_pp (pretty_printer *pp, + bool user_facing) const final override; + + bool + apply_constraints (region_model *model, + region_model_context *ctxt, + tree exception_type, + std::unique_ptr<rejected_constraint> *out) + const final override; + + enum eh_kind get_eh_kind () const { return m_kind; } + +private: + enum eh_kind m_kind; +}; + +} // namespace ana + +template <> +template <> +inline bool +is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test (const superedge *sedge) +{ + return sedge->dyn_cast_eh_dispatch_allowed_cfg_superedge () != NULL; +} + +namespace ana { /* Base class for adding additional content to the .dot output for a supergraph. */ diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index 2e3f051..f3f80d1 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -18,39 +18,22 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "diagnostic-core.h" +#include "analyzer/common.h" + +#include "tree-pretty-print.h" #include "gimple-pretty-print.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "diagnostic-core.h" -#include "graphviz.h" -#include "options.h" -#include "cgraph.h" -#include "tree-dfa.h" -#include "stringpool.h" -#include "convert.h" -#include "target.h" #include "fold-const.h" -#include "tree-pretty-print.h" -#include "bitmap.h" -#include "analyzer/analyzer.h" +#include "diagnostic.h" +#include "tree-diagnostic.h" + +#include "text-art/dump.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/svalue.h" #include "analyzer/region-model.h" -#include "diagnostic.h" -#include "tree-diagnostic.h" -#include "make-unique.h" -#include "text-art/dump.h" #if ENABLE_ANALYZER @@ -107,7 +90,7 @@ std::unique_ptr<json::value> svalue::to_json () const { label_text desc = get_desc (true); - auto sval_js = ::make_unique<json::string> (desc.get ()); + auto sval_js = std::make_unique<json::string> (desc.get ()); return sval_js; } @@ -572,8 +555,8 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2) { const poisoned_svalue *poisoned_sval1 = (const poisoned_svalue *)sval1; const poisoned_svalue *poisoned_sval2 = (const poisoned_svalue *)sval2; - return (poisoned_sval1->get_poison_kind () - - poisoned_sval2->get_poison_kind ()); + return (static_cast<int> (poisoned_sval1->get_poison_kind ()) + - static_cast<int> (poisoned_sval2->get_poison_kind ())); } break; case SK_SETJMP: @@ -877,6 +860,19 @@ svalue::maybe_get_deref_base_region () const } } +/* If this svalue is a pointer to the typeinfo instance for a particular + type, return that type. Otherwise return NULL_TREE. */ + +tree +svalue::maybe_get_type_from_typeinfo () const +{ + if (const region *reg = maybe_get_region ()) + if (const decl_region *decl_reg = reg->dyn_cast_decl_region ()) + return TREE_TYPE (DECL_NAME (decl_reg->get_decl ())); + + return NULL_TREE; +} + /* class region_svalue : public svalue. */ /* Implementation of svalue::dump_to_pp vfunc for region_svalue. */ @@ -1234,13 +1230,13 @@ poison_kind_to_str (enum poison_kind kind) { default: gcc_unreachable (); - case POISON_KIND_UNINIT: + case poison_kind::uninit: return "uninit"; - case POISON_KIND_FREED: + case poison_kind::freed: return "freed"; - case POISON_KIND_DELETED: + case poison_kind::deleted: return "deleted"; - case POISON_KIND_POPPED_STACK: + case poison_kind::popped_stack: return "popped stack"; } } diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h index bf9e12b..7a27cb6 100644 --- a/gcc/analyzer/svalue.h +++ b/gcc/analyzer/svalue.h @@ -188,6 +188,8 @@ public: const region_model &model, const svalue *outer_sval = nullptr) const; + tree maybe_get_type_from_typeinfo () const; + protected: svalue (complexity c, symbol::id_t id, tree type) : symbol (c, id), m_type (type) @@ -421,19 +423,19 @@ public: /* An enum describing a particular kind of "poisoned" value. */ -enum poison_kind +enum class poison_kind { /* For use to describe uninitialized memory. */ - POISON_KIND_UNINIT, + uninit, /* For use to describe freed memory. */ - POISON_KIND_FREED, + freed, /* For use to describe deleted memory. */ - POISON_KIND_DELETED, + deleted, /* For use on pointers to regions within popped stack frames. */ - POISON_KIND_POPPED_STACK + popped_stack }; extern const char *poison_kind_to_str (enum poison_kind); @@ -454,7 +456,7 @@ public: hashval_t hash () const { inchash::hash hstate; - hstate.add_int (m_kind); + hstate.add_int (static_cast<int> (m_kind)); hstate.add_ptr (m_type); return hstate.end (); } @@ -528,8 +530,8 @@ namespace ana { struct setjmp_record { setjmp_record (const exploded_node *enode, - const gcall *setjmp_call) - : m_enode (enode), m_setjmp_call (setjmp_call) + const gcall &setjmp_call) + : m_enode (enode), m_setjmp_call (&setjmp_call) { } @@ -549,6 +551,7 @@ struct setjmp_record const exploded_node *m_enode; const gcall *m_setjmp_call; + // non-null, but we can't use a reference since we're putting these in a hash_map }; /* Concrete subclass of svalue representing buffers for setjmp/sigsetjmp, diff --git a/gcc/analyzer/symbol.cc b/gcc/analyzer/symbol.cc index 068801a..8643284 100644 --- a/gcc/analyzer/symbol.cc +++ b/gcc/analyzer/symbol.cc @@ -18,11 +18,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "analyzer/symbol.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/trimmed-graph.cc b/gcc/analyzer/trimmed-graph.cc index 993084c..bdf378a 100644 --- a/gcc/analyzer/trimmed-graph.cc +++ b/gcc/analyzer/trimmed-graph.cc @@ -18,21 +18,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "pretty-print.h" -#include "gcc-rich-location.h" -#include "gimple-pretty-print.h" -#include "function.h" -#include "diagnostic-core.h" -#include "diagnostic-event-id.h" -#include "diagnostic-path.h" -#include "bitmap.h" -#include "ordered-hash-map.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 0cacc9b..6ea0d29 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -18,18 +18,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -167,10 +157,10 @@ get_va_list_diag_arg (tree va_list_tree) static const svalue * get_va_copy_arg (const region_model *model, region_model_context *ctxt, - const gcall *call, + const gcall &call, unsigned arg_idx) { - tree arg = gimple_call_arg (call, arg_idx); + tree arg = gimple_call_arg (&call, arg_idx); const svalue *arg_sval = model->get_rvalue (arg, ctxt); if (const svalue *cast = arg_sval->maybe_undo_cast ()) arg_sval = cast; @@ -225,16 +215,16 @@ public: private: void on_va_start (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_va_copy (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_va_arg (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_va_end (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void check_for_ended_va_list (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, const svalue *arg, const char *usage_fnname) const; }; @@ -256,10 +246,12 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node, const gimple *stmt) const { - if (const gcall *call = dyn_cast <const gcall *> (stmt)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) { - if (gimple_call_internal_p (call) - && gimple_call_internal_fn (call) == IFN_VA_ARG) + const gcall &call = *call_stmt; + + if (gimple_call_internal_p (call_stmt) + && gimple_call_internal_fn (call_stmt) == IFN_VA_ARG) { on_va_arg (sm_ctxt, node, call); return false; @@ -267,7 +259,7 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt, if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) if (fndecl_built_in_p (callee_fndecl, BUILT_IN_NORMAL) - && gimple_builtin_call_types_compatible_p (call, callee_fndecl)) + && gimple_builtin_call_types_compatible_p (&call, callee_fndecl)) switch (DECL_UNCHECKED_FUNCTION_CODE (callee_fndecl)) { default: @@ -293,9 +285,9 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt, IDX to CALL. */ static const svalue * -get_stateful_arg (sm_context &sm_ctxt, const gcall *call, unsigned arg_idx) +get_stateful_arg (sm_context &sm_ctxt, const gcall &call, unsigned arg_idx) { - tree ap = gimple_call_arg (call, arg_idx); + tree ap = gimple_call_arg (&call, arg_idx); if (ap && POINTER_TYPE_P (TREE_TYPE (ap))) { @@ -542,14 +534,14 @@ private: void va_list_state_machine::on_va_start (sm_context &sm_ctxt, const supernode *, - const gcall *call) const + const gcall &call) const { const svalue *arg = get_stateful_arg (sm_ctxt, call, 0); if (arg) { /* Transition from start state to "started". */ - if (sm_ctxt.get_state (call, arg) == m_start) - sm_ctxt.set_next_state (call, arg, m_started); + if (sm_ctxt.get_state (&call, arg) == m_start) + sm_ctxt.set_next_state (&call, arg, m_started); } } @@ -558,13 +550,13 @@ va_list_state_machine::on_va_start (sm_context &sm_ctxt, void va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, const svalue *arg, const char *usage_fnname) const { - if (sm_ctxt.get_state (call, arg) == m_ended) - sm_ctxt.warn (node, call, arg, - make_unique<va_list_use_after_va_end> + if (sm_ctxt.get_state (&call, arg) == m_ended) + sm_ctxt.warn (node, &call, arg, + std::make_unique<va_list_use_after_va_end> (*this, arg, NULL_TREE, usage_fnname)); } @@ -574,7 +566,7 @@ va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt, static const svalue * get_stateful_va_copy_arg (sm_context &sm_ctxt, - const gcall *call, + const gcall &call, unsigned arg_idx) { if (const program_state *new_state = sm_ctxt.get_new_program_state ()) @@ -591,7 +583,7 @@ get_stateful_va_copy_arg (sm_context &sm_ctxt, void va_list_state_machine::on_va_copy (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const svalue *src_arg = get_stateful_va_copy_arg (sm_ctxt, call, 1); if (src_arg) @@ -601,8 +593,8 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt, if (dst_arg) { /* Transition from start state to "started". */ - if (sm_ctxt.get_state (call, dst_arg) == m_start) - sm_ctxt.set_next_state (call, dst_arg, m_started); + if (sm_ctxt.get_state (&call, dst_arg) == m_start) + sm_ctxt.set_next_state (&call, dst_arg, m_started); } } @@ -611,7 +603,7 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt, void va_list_state_machine::on_va_arg (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const svalue *arg = get_stateful_arg (sm_ctxt, call, 0); if (arg) @@ -623,15 +615,15 @@ va_list_state_machine::on_va_arg (sm_context &sm_ctxt, void va_list_state_machine::on_va_end (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const svalue *arg = get_stateful_arg (sm_ctxt, call, 0); if (arg) { - state_t s = sm_ctxt.get_state (call, arg); + state_t s = sm_ctxt.get_state (&call, arg); /* Transition from "started" to "ended". */ if (s == m_started) - sm_ctxt.set_next_state (call, arg, m_ended); + sm_ctxt.set_next_state (&call, arg, m_ended); else if (s == m_ended) check_for_ended_va_list (sm_ctxt, node, call, arg, "va_end"); } @@ -643,17 +635,17 @@ va_list_state_machine::on_va_end (sm_context &sm_ctxt, std::unique_ptr<pending_diagnostic> va_list_state_machine::on_leak (tree var) const { - return make_unique<va_list_leak> (*this, nullptr, var); + return std::make_unique<va_list_leak> (*this, nullptr, var); } } // anonymous namespace /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_va_list_state_machine (logger *logger) { - return new va_list_state_machine (logger); + return std::make_unique<va_list_state_machine> (logger); } /* Handler for "__builtin_va_start". */ @@ -757,13 +749,13 @@ kf_va_copy::impl_call_pre (const call_details &cd) const static int get_num_variadic_arguments (tree callee_fndecl, - const gcall *call_stmt) + const gcall &call_stmt) { int num_positional = 0; for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm; iter_parm = DECL_CHAIN (iter_parm)) num_positional++; - return gimple_call_num_args (call_stmt) - num_positional; + return gimple_call_num_args (&call_stmt) - num_positional; } /* An abstract subclass of pending_diagnostic for diagnostics relating @@ -817,12 +809,12 @@ public: const program_point &src_point = src_node->get_point (); const int src_stack_depth = src_point.get_stack_depth (); const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt (); - const gcall *call_stmt = as_a <const gcall *> (last_stmt); + const gcall &call_stmt = *as_a <const gcall *> (last_stmt); int num_variadic_arguments = get_num_variadic_arguments (dst_node->get_function ()->decl, call_stmt); emission_path->add_event - (make_unique<va_arg_call_event> + (std::make_unique<va_arg_call_event> (eedge, event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION, src_point.get_fndecl (), @@ -1078,7 +1070,7 @@ kf_va_arg::impl_call_pre (const call_details &cd) const else { if (ctxt) - ctxt->warn (make_unique <va_arg_type_mismatch> + ctxt->warn (std::make_unique <va_arg_type_mismatch> (va_list_tree, arg_reg, lhs_type, @@ -1089,8 +1081,9 @@ kf_va_arg::impl_call_pre (const call_details &cd) const else { if (ctxt) - ctxt->warn (make_unique <va_list_exhausted> (va_list_tree, - arg_reg)); + ctxt->warn + (std::make_unique <va_list_exhausted> (va_list_tree, + arg_reg)); saw_problem = true; } } @@ -1139,10 +1132,10 @@ public: void register_varargs_builtins (known_function_manager &kfm) { - kfm.add (BUILT_IN_VA_START, make_unique<kf_va_start> ()); - kfm.add (BUILT_IN_VA_COPY, make_unique<kf_va_copy> ()); - kfm.add (IFN_VA_ARG, make_unique<kf_va_arg> ()); - kfm.add (BUILT_IN_VA_END, make_unique<kf_va_end> ()); + kfm.add (BUILT_IN_VA_START, std::make_unique<kf_va_start> ()); + kfm.add (BUILT_IN_VA_COPY, std::make_unique<kf_va_copy> ()); + kfm.add (IFN_VA_ARG, std::make_unique<kf_va_arg> ()); + kfm.add (BUILT_IN_VA_END, std::make_unique<kf_va_end> ()); } } // namespace ana diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 732b2c9..1572c8b 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,20 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * c-pretty-print.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * name-hint.h (name_hint::name_hint): Use std::unique_ptr for + param. + +2025-04-28 Lewis Hyatt <lhyatt@gmail.com> + + PR c/118838 + * c-lex.cc (cb_def_pragma): Call cpp_get_diagnostic_override_loc() + to get a valid location at which to issue -Wunknown-pragmas, in case + it was triggered from a _Pragma. + 2025-04-25 Jason Merrill <jason@redhat.com> * c-opts.cc (c_common_post_options): Bump default ABI to 21 diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index e450c9a..fef6ae6 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -248,7 +248,12 @@ cb_def_pragma (cpp_reader *pfile, location_t loc) { const unsigned char *space, *name; const cpp_token *s; - location_t fe_loc = loc; + + /* If we are processing a _Pragma, LOC is not a valid location, but libcpp + will provide a good location via this function instead. */ + location_t fe_loc = cpp_get_diagnostic_override_loc (pfile); + if (fe_loc == UNKNOWN_LOCATION) + fe_loc = loc; space = name = (const unsigned char *) ""; diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc index 1ce19f5..fad6b5e 100644 --- a/gcc/c-family/c-pretty-print.cc +++ b/gcc/c-family/c-pretty-print.cc @@ -36,7 +36,6 @@ along with GCC; see the file COPYING3. If not see #include "function.h" #include "basic-block.h" #include "gimple.h" -#include "make-unique.h" /* The pretty-printer code is primarily designed to closely follow (GNU) C and C++ grammars. That is to be contrasted with spaghetti @@ -2994,7 +2993,7 @@ c_pretty_printer::c_pretty_printer (dump_flags_t dump_flags) std::unique_ptr<pretty_printer> c_pretty_printer::clone () const { - return ::make_unique<c_pretty_printer> (*this); + return std::make_unique<c_pretty_printer> (*this); } /* Print the tree T in full, on file FILE. */ diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h index 3d4f2f5..13ade71 100644 --- a/gcc/c-family/name-hint.h +++ b/gcc/c-family/name-hint.h @@ -85,8 +85,10 @@ class name_hint public: name_hint () : m_suggestion (NULL), m_deferred () {} - name_hint (const char *suggestion, deferred_diagnostic *deferred) - : m_suggestion (suggestion), m_deferred (deferred) + name_hint (const char *suggestion, + std::unique_ptr<deferred_diagnostic> deferred) + : m_suggestion (suggestion), + m_deferred (std::move (deferred)) { } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index f75a0f6..4c8fde7 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,43 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * c-decl.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * c-objc-common.cc: Likewise. + * c-parser.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * c-decl.cc: Include "make-unique.h". + (lookup_name_fuzzy): Use ::make_unique rather than "new" when + making suggest_missing_header and suggest_missing_option. + * c-parser.cc: Include "make-unique.h" + (c_parser_error_richloc): Use ::make_unique rather than "new" when + making suggest_missing_header. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR c/119432 + * gimple-parser.cc (gimple_binary_identifier_code): Add + __ROTATE_LEFT and __ROTATE_RIGHT. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + * gimple-parser.cc (gimple_binary_identifier_code): New variable. + (c_parser_gimple_binary_expression): Use gimple_binary_identifier_code + instead of doing if statements on the strings. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR c/48274 + PR middle-end/112877 + PR middle-end/118288 + * c-decl.cc (start_decl): Remove the + targetm.calls.promote_prototypes call. + (store_parm_decls_oldstyle): Likewise. + (finish_function): Likewise. + * c-typeck.cc (convert_argument): Likewise. + (c_safe_arg_type_equiv_p): Likewise. + 2025-04-15 Qing Zhao <qing.zhao@oracle.com> PR c/119717 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index e7aee8a..4e200f9 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4547,10 +4547,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) = get_c_stdlib_header_for_name (IDENTIFIER_POINTER (name)); if (header_hint) - return name_hint (NULL, - new suggest_missing_header (loc, - IDENTIFIER_POINTER (name), - header_hint)); + return name_hint + (nullptr, + std::make_unique<suggest_missing_header> (loc, + IDENTIFIER_POINTER (name), + header_hint)); /* Next, look for exact matches for builtin defines that would have been defined if the user had passed a command-line option (e.g. -fopenmp @@ -4558,10 +4559,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) diagnostic_option_id option_id = get_option_for_builtin_define (IDENTIFIER_POINTER (name)); if (option_id.m_idx > 0) - return name_hint (nullptr, - new suggest_missing_option (loc, - IDENTIFIER_POINTER (name), - option_id)); + return name_hint + (nullptr, + std::make_unique<suggest_missing_option> (loc, + IDENTIFIER_POINTER (name), + option_id)); /* Only suggest names reserved for the implementation if NAME begins with an underscore. */ diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index 7e227d3..2016eae 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "dwarf2.h" -#include "make-unique.h" static bool c_tree_printer (pretty_printer *, text_info *, const char *, int, bool, bool, bool, bool *, pp_token_list &); @@ -412,7 +411,7 @@ has_c_linkage (const_tree decl ATTRIBUTE_UNUSED) void c_initialize_diagnostics (diagnostic_context *context) { - context->set_pretty_printer (::make_unique<c_pretty_printer> ()); + context->set_pretty_printer (std::make_unique<c_pretty_printer> ()); c_common_diagnostics_set_defaults (context); context->set_format_decoder (&c_tree_printer); } diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 22ec0f8..8a63dc5 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1072,9 +1072,11 @@ c_parser_error_richloc (c_parser *parser, const char *gmsgid, const char *header_hint = get_c_stdlib_header_for_string_macro_name (token_name); if (header_hint != NULL) - h = name_hint (NULL, new suggest_missing_header (token->location, - token_name, - header_hint)); + h = name_hint (nullptr, + std::make_unique<suggest_missing_header> + (token->location, + token_name, + header_hint)); } c_parse_error (gmsgid, diff --git a/gcc/c/gimple-parser.cc b/gcc/c/gimple-parser.cc index 90b9beb..5fd1db8 100644 --- a/gcc/c/gimple-parser.cc +++ b/gcc/c/gimple-parser.cc @@ -963,6 +963,29 @@ c_parser_gimple_statement (gimple_parser &parser, gimple_seq *seq) return; } +/* A mapping between an identifier to a tree code for binary operations. */ +static const std::pair<const char *, tree_code> gimple_binary_identifier_code[] = + { + {"__MULT_HIGHPART", MULT_HIGHPART_EXPR}, + {"__UNLT", UNLT_EXPR}, + {"__UNLE", UNLE_EXPR}, + {"__UNGT", UNGT_EXPR}, + {"__UNGE", UNGE_EXPR}, + {"__UNEQ", UNEQ_EXPR}, + {"__UNORDERED", UNORDERED_EXPR}, + {"__ORDERED", ORDERED_EXPR}, + {"__LTGT", LTGT_EXPR}, + {"__FLOOR_DIV", FLOOR_DIV_EXPR}, + {"__ROUND_DIV", ROUND_DIV_EXPR}, + {"__EXACT_DIV", EXACT_DIV_EXPR}, + {"__CEIL_DIV", CEIL_DIV_EXPR}, + {"__FLOOR_MOD", FLOOR_MOD_EXPR}, + {"__ROUND_MOD", ROUND_MOD_EXPR}, + {"__CEIL_MOD", CEIL_MOD_EXPR}, + {"__ROTATE_LEFT", LROTATE_EXPR}, + {"__ROTATE_RIGHT", RROTATE_EXPR}, + }; + /* Parse gimple binary expr. gimple-binary-expression: @@ -1061,86 +1084,16 @@ c_parser_gimple_binary_expression (gimple_parser &parser, tree ret_type) case CPP_NAME: { tree id = c_parser_peek_token (parser)->value; - if (strcmp (IDENTIFIER_POINTER (id), "__MULT_HIGHPART") == 0) - { - code = MULT_HIGHPART_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__UNLT") == 0) - { - code = UNLT_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__UNLE") == 0) - { - code = UNLE_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__UNGT") == 0) - { - code = UNGT_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__UNGE") == 0) - { - code = UNGE_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__UNEQ") == 0) - { - code = UNEQ_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__UNORDERED") == 0) - { - code = UNORDERED_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__ORDERED") == 0) - { - code = ORDERED_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__LTGT") == 0) + for (auto &p : gimple_binary_identifier_code) { - code = LTGT_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__FLOOR_DIV") == 0) - { - code = FLOOR_DIV_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__ROUND_DIV") == 0) - { - code = ROUND_DIV_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__EXACT_DIV") == 0) - { - code = EXACT_DIV_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__CEIL_DIV") == 0) - { - code = CEIL_DIV_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__FLOOR_MOD") == 0) - { - code = FLOOR_MOD_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__ROUND_MOD") == 0) - { - code = ROUND_MOD_EXPR; - break; - } - else if (strcmp (IDENTIFIER_POINTER (id), "__CEIL_MOD") == 0) - { - code = CEIL_MOD_EXPR; - break; + if (strcmp (IDENTIFIER_POINTER (id), p.first) == 0) + { + code = p.second; + break; + } } + if (code != ERROR_MARK) + break; } /* Fallthru. */ default: diff --git a/gcc/common.opt b/gcc/common.opt index d10a6b7..3edc590 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -53,12 +53,6 @@ bool in_lto_p = false Variable enum incremental_link flag_incremental_link = INCREMENTAL_LINK_NONE -; 0 means straightforward implementation of complex divide acceptable. -; 1 means wide ranges of inputs must work for complex divide. -; 2 means C99-like requirements for complex multiply and divide. -Variable -int flag_complex_method = 1 - Variable int flag_default_complex_method = 1 @@ -1315,12 +1309,30 @@ fcse-skip-blocks Common Ignore Does nothing. Preserved for backward compatibility. +fcx-method= +Common Joined RejectNegative Enum(complex_method) Var(flag_complex_method) Optimization SetByCombined + +Enum +Name(complex_method) Type(int) + +; straightforward implementation of complex divide acceptable. +EnumValue +Enum(complex_method) String(limited-range) Value(0) + +; wide ranges of inputs must work for complex divide. +EnumValue +Enum(complex_method) String(fortran) Value(1) + +; C99-like requirements for complex multiply and divide. +EnumValue +Enum(complex_method) String(stdc) Value(2) + fcx-limited-range -Common Var(flag_cx_limited_range) Optimization SetByCombined +Common Alias(fcx-method=,limited-range,stdc) Omit range reduction step when performing complex division. fcx-fortran-rules -Common Var(flag_cx_fortran_rules) Optimization +Common Alias(fcx-method=,fortran,stdc) Complex multiplication and division follow Fortran rules. fdata-sections diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index 3ddcbec..d587d25 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see /* 32-bit Windows aligns the stack on a 4-byte boundary but SSE instructions may require 16-byte alignment. */ #undef STACK_REALIGN_DEFAULT -#define STACK_REALIGN_DEFAULT TARGET_SSE +#define STACK_REALIGN_DEFAULT (TARGET_64BIT ? 0 : 1) /* Support hooks for SEH. */ #undef TARGET_ASM_UNWIND_EMIT diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 3171d6e..dd07624 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -8473,6 +8473,123 @@ output_probe_stack_range (rtx reg, rtx end) return ""; } +/* Data passed to ix86_update_stack_alignment. */ +struct stack_access_data +{ + /* The stack access register. */ + const_rtx reg; + /* Pointer to stack alignment. */ + unsigned int *stack_alignment; +}; + +/* Update the maximum stack slot alignment from memory alignment in PAT. */ + +static void +ix86_update_stack_alignment (rtx, const_rtx pat, void *data) +{ + /* This insn may reference stack slot. Update the maximum stack slot + alignment if the memory is referenced by the stack access register. */ + stack_access_data *p = (stack_access_data *) data; + + subrtx_iterator::array_type array; + FOR_EACH_SUBRTX (iter, array, pat, ALL) + { + auto op = *iter; + if (MEM_P (op) && reg_mentioned_p (p->reg, op)) + { + unsigned int alignment = MEM_ALIGN (op); + + if (alignment > *p->stack_alignment) + *p->stack_alignment = alignment; + break; + } + } +} + +/* Helper function for ix86_find_all_reg_uses. */ + +static void +ix86_find_all_reg_uses_1 (HARD_REG_SET ®set, + rtx set, unsigned int regno, + auto_bitmap &worklist) +{ + rtx dest = SET_DEST (set); + + if (!REG_P (dest)) + return; + + /* Reject non-Pmode modes. */ + if (GET_MODE (dest) != Pmode) + return; + + unsigned int dst_regno = REGNO (dest); + + if (TEST_HARD_REG_BIT (regset, dst_regno)) + return; + + const_rtx src = SET_SRC (set); + + subrtx_iterator::array_type array; + FOR_EACH_SUBRTX (iter, array, src, ALL) + { + auto op = *iter; + + if (MEM_P (op)) + iter.skip_subrtxes (); + + if (REG_P (op) && REGNO (op) == regno) + { + /* Add this register to register set. */ + add_to_hard_reg_set (®set, Pmode, dst_regno); + bitmap_set_bit (worklist, dst_regno); + break; + } + } +} + +/* Find all registers defined with register REGNO. */ + +static void +ix86_find_all_reg_uses (HARD_REG_SET ®set, + unsigned int regno, auto_bitmap &worklist) +{ + for (df_ref ref = DF_REG_USE_CHAIN (regno); + ref != NULL; + ref = DF_REF_NEXT_REG (ref)) + { + if (DF_REF_IS_ARTIFICIAL (ref)) + continue; + + rtx_insn *insn = DF_REF_INSN (ref); + + if (!NONJUMP_INSN_P (insn)) + continue; + + unsigned int ref_regno = DF_REF_REGNO (ref); + + rtx set = single_set (insn); + if (set) + { + ix86_find_all_reg_uses_1 (regset, set, + ref_regno, worklist); + continue; + } + + rtx pat = PATTERN (insn); + if (GET_CODE (pat) != PARALLEL) + continue; + + for (int i = 0; i < XVECLEN (pat, 0); i++) + { + rtx exp = XVECEXP (pat, 0, i); + + if (GET_CODE (exp) == SET) + ix86_find_all_reg_uses_1 (regset, exp, + ref_regno, worklist); + } + } +} + /* Set stack_frame_required to false if stack frame isn't required. Update STACK_ALIGNMENT to the largest alignment, in bits, of stack slot used if stack frame is required and CHECK_STACK_SLOT is true. */ @@ -8491,10 +8608,6 @@ ix86_find_max_used_stack_alignment (unsigned int &stack_alignment, add_to_hard_reg_set (&set_up_by_prologue, Pmode, HARD_FRAME_POINTER_REGNUM); - /* The preferred stack alignment is the minimum stack alignment. */ - if (stack_alignment > crtl->preferred_stack_boundary) - stack_alignment = crtl->preferred_stack_boundary; - bool require_stack_frame = false; FOR_EACH_BB_FN (bb, cfun) @@ -8506,27 +8619,67 @@ ix86_find_max_used_stack_alignment (unsigned int &stack_alignment, set_up_by_prologue)) { require_stack_frame = true; - - if (check_stack_slot) - { - /* Find the maximum stack alignment. */ - subrtx_iterator::array_type array; - FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL) - if (MEM_P (*iter) - && (reg_mentioned_p (stack_pointer_rtx, - *iter) - || reg_mentioned_p (frame_pointer_rtx, - *iter))) - { - unsigned int alignment = MEM_ALIGN (*iter); - if (alignment > stack_alignment) - stack_alignment = alignment; - } - } + break; } } cfun->machine->stack_frame_required = require_stack_frame; + + /* Stop if we don't need to check stack slot. */ + if (!check_stack_slot) + return; + + /* The preferred stack alignment is the minimum stack alignment. */ + if (stack_alignment > crtl->preferred_stack_boundary) + stack_alignment = crtl->preferred_stack_boundary; + + HARD_REG_SET stack_slot_access; + CLEAR_HARD_REG_SET (stack_slot_access); + + /* Stack slot can be accessed by stack pointer, frame pointer or + registers defined by stack pointer or frame pointer. */ + auto_bitmap worklist; + + add_to_hard_reg_set (&stack_slot_access, Pmode, STACK_POINTER_REGNUM); + bitmap_set_bit (worklist, STACK_POINTER_REGNUM); + + if (frame_pointer_needed) + { + add_to_hard_reg_set (&stack_slot_access, Pmode, + HARD_FRAME_POINTER_REGNUM); + bitmap_set_bit (worklist, HARD_FRAME_POINTER_REGNUM); + } + + unsigned int regno; + + do + { + regno = bitmap_clear_first_set_bit (worklist); + ix86_find_all_reg_uses (stack_slot_access, regno, worklist); + } + while (!bitmap_empty_p (worklist)); + + hard_reg_set_iterator hrsi; + stack_access_data data; + + data.stack_alignment = &stack_alignment; + + EXECUTE_IF_SET_IN_HARD_REG_SET (stack_slot_access, 0, regno, hrsi) + for (df_ref ref = DF_REG_USE_CHAIN (regno); + ref != NULL; + ref = DF_REF_NEXT_REG (ref)) + { + if (DF_REF_IS_ARTIFICIAL (ref)) + continue; + + rtx_insn *insn = DF_REF_INSN (ref); + + if (!NONJUMP_INSN_P (insn)) + continue; + + data.reg = DF_REF_REG (ref); + note_stores (insn, ix86_update_stack_alignment, &data); + } } /* Finalize stack_realign_needed and frame_pointer_needed flags, which diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d092553..480e9c4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,53 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * parser.cc: Include "analyzer/analyzer-language.h". + (ana::cp_translation_unit): New class. + (cp_parser_translation_unit): Add call to + ana::on_finish_translation_unit. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * cxx-pretty-print.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * error.cc: Likewise. + * name-lookup.cc: Likewise. + * parser.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * name-lookup.cc: Include "make-unique.h". + (namespace_hints::convert_candidates_to_name_hint): Use + ::make_unique rather than "new" when making + show_candidate_location and suggest_alternatives. + (namespace_hints::maybe_decorate_with_limit): Likewise when making + namespace_limit_reached. + (suggest_alternatives_for_1): Likewise when making + suggest_missing_option. + (maybe_suggest_missing_std_header): Likewise when making + missing_std_header. + (macro_use_before_def::maybe_make): Use std::unique_ptr. + (macro_use_before_def::macro_use_before_def): Make public. + (lookup_name_fuzzy): Use ::make_unique rather than "new" when + making suggest_missing_header. + * parser.cc: Include "make-unique.h". + (cp_parser_error_1): Use ::make_unique rather than "new" when + making suggest_missing_header. + +2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119939 + * module.cc (trees_out::lang_decl_vals): Also stream + lang->u.fn.context when DECL_UNIQUE_FRIEND_P. + (trees_in::lang_decl_vals): Likewise. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * call.cc (type_passed_as): Remove the + targetm.calls.promote_prototypes call. + (convert_for_arg_passing): Likewise. + * typeck.cc (cxx_safe_arg_type_equiv_p): Likewise. + 2025-04-25 Jason Merrill <jason@redhat.com> PR c++/119764 diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index cf301bd..5f24015 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "cp-tree.h" #include "cxx-pretty-print.h" #include "tree-pretty-print.h" -#include "make-unique.h" static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree); static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree); @@ -2954,5 +2953,5 @@ cxx_pretty_printer::cxx_pretty_printer () std::unique_ptr<pretty_printer> cxx_pretty_printer::clone () const { - return ::make_unique<cxx_pretty_printer> (*this); + return std::make_unique<cxx_pretty_printer> (*this); } diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 499eb1b..75bf7dc 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -38,7 +38,6 @@ along with GCC; see the file COPYING3. If not see #include "cp-name-hint.h" #include "attribs.h" #include "pretty-print-format-impl.h" -#include "make-unique.h" #include "diagnostic-format-text.h" #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 5ff5c46..a2e0d6d 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -7386,7 +7386,7 @@ trees_out::lang_decl_vals (tree t) WU (lang->u.fn.ovl_op_code); } - if (DECL_CLASS_SCOPE_P (t)) + if (DECL_CLASS_SCOPE_P (t) || DECL_UNIQUE_FRIEND_P (t)) WT (lang->u.fn.context); if (lang->u.fn.thunk_p) @@ -7470,7 +7470,7 @@ trees_in::lang_decl_vals (tree t) lang->u.fn.ovl_op_code = code; } - if (DECL_CLASS_SCOPE_P (t)) + if (DECL_CLASS_SCOPE_P (t) || DECL_UNIQUE_FRIEND_P (t)) RT (lang->u.fn.context); if (lang->u.fn.thunk_p) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index aa2dc0e..9b317c4 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -7085,13 +7085,16 @@ namespace_hints::convert_candidates_to_name_hint () /* Clean up CANDIDATES. */ m_candidates.release (); return name_hint (expr_to_string (candidate), - new show_candidate_location (m_loc, candidate)); + std::make_unique<show_candidate_location> (m_loc, + candidate)); } else if (m_candidates.length () > 1) /* If we have more than one candidate, issue a name_hint without a single "suggestion", but with a deferred diagnostic that lists the various candidates. This takes ownership of m_candidates. */ - return name_hint (NULL, new suggest_alternatives (m_loc, m_candidates)); + return name_hint (NULL, + std::make_unique<suggest_alternatives> (m_loc, + m_candidates)); /* Otherwise, m_candidates ought to be empty, so no cleanup is necessary. */ gcc_assert (m_candidates.length () == 0); @@ -7111,10 +7114,11 @@ name_hint namespace_hints::maybe_decorate_with_limit (name_hint hint) { if (m_limited) - return name_hint (hint.suggestion (), - new namespace_limit_reached (m_loc, m_limit, - m_name, - hint.take_deferred ())); + return name_hint + (hint.suggestion (), + std::make_unique<namespace_limit_reached> (m_loc, m_limit, + m_name, + hint.take_deferred ())); else return hint; } @@ -7191,10 +7195,11 @@ suggest_alternatives_for_1 (location_t location, tree name, diagnostic_option_id option_id = get_option_for_builtin_define (IDENTIFIER_POINTER (name)); if (option_id.m_idx > 0) - return name_hint (nullptr, - new suggest_missing_option (location, - IDENTIFIER_POINTER (name), - option_id)); + return name_hint + (nullptr, + std::make_unique<suggest_missing_option> (location, + IDENTIFIER_POINTER (name), + option_id)); /* Otherwise, consider misspellings. */ if (!suggest_misspellings) @@ -7322,8 +7327,9 @@ maybe_suggest_missing_std_header (location_t location, tree name) if (!header_hint) return name_hint (); - return name_hint (NULL, new missing_std_header (location, name_str, - header_hint)); + return name_hint (nullptr, + std::make_unique<missing_std_header> (location, name_str, + header_hint)); } /* Attempt to generate a name_hint that suggests a missing header file @@ -7705,12 +7711,12 @@ class macro_use_before_def : public deferred_diagnostic public: /* Factory function. Return a new macro_use_before_def instance if appropriate, or return NULL. */ - static macro_use_before_def * + static std::unique_ptr<macro_use_before_def> maybe_make (location_t use_loc, cpp_hashnode *macro) { location_t def_loc = cpp_macro_definition_location (macro); if (def_loc == UNKNOWN_LOCATION) - return NULL; + return nullptr; /* We only want to issue a note if the macro was used *before* it was defined. @@ -7718,12 +7724,11 @@ class macro_use_before_def : public deferred_diagnostic used, leaving it unexpanded (e.g. by using the wrong argument count). */ if (!linemap_location_before_p (line_table, use_loc, def_loc)) - return NULL; + return nullptr; - return new macro_use_before_def (use_loc, macro); + return std::make_unique<macro_use_before_def> (use_loc, macro); } - private: /* Ctor. LOC is the location of the usage. MACRO is the macro that was used. */ macro_use_before_def (location_t loc, cpp_hashnode *macro) @@ -7790,10 +7795,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) const char *header_hint = get_cp_stdlib_header_for_name (IDENTIFIER_POINTER (name)); if (header_hint) - return name_hint (NULL, - new suggest_missing_header (loc, - IDENTIFIER_POINTER (name), - header_hint)); + return name_hint + (nullptr, + std::make_unique<suggest_missing_header> (loc, + IDENTIFIER_POINTER (name), + header_hint)); best_match <tree, const char *> bm (name); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3628cfe..1fb9e7f 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "contracts.h" #include "bitmap.h" #include "builtins.h" +#include "analyzer/analyzer-language.h" /* The lexer. */ @@ -286,6 +287,37 @@ static FILE *cp_lexer_debug_stream; sizeof, typeof, or alignof. */ int cp_unevaluated_operand; +#if ENABLE_ANALYZER + +namespace ana { + +/* Concrete implementation of ana::translation_unit for the C++ frontend. */ + +class cp_translation_unit : public translation_unit +{ +public: + tree lookup_constant_by_id (tree /*id*/) const final override + { + return NULL_TREE; + } + + tree + lookup_type_by_id (tree /*id*/) const final override + { + return NULL_TREE; + } + + tree + lookup_global_var_by_id (tree /*id*/) const final override + { + return NULL_TREE; + } +}; + +} // namespace ana + +#endif /* #if ENABLE_ANALYZER */ + /* Dump up to NUM tokens in BUFFER to FILE starting with token START_TOKEN. If START_TOKEN is NULL, the dump starts with the first token in BUFFER. If NUM is 0, dump all the tokens. If @@ -3434,9 +3466,11 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid, const char *header_hint = get_cp_stdlib_header_for_string_macro_name (token_name); if (header_hint != NULL) - h = name_hint (NULL, new suggest_missing_header (token->location, - token_name, - header_hint)); + h = name_hint + (nullptr, + std::make_unique<suggest_missing_header> (token->location, + token_name, + header_hint)); } /* Actually emit the error. */ @@ -5469,6 +5503,14 @@ cp_parser_translation_unit (cp_parser* parser) cp_parser_toplevel_declaration (parser); } +#if ENABLE_ANALYZER + if (flag_analyzer) + { + ana::cp_translation_unit tu; + ana::on_finish_translation_unit (tu); + } +#endif + /* Get rid of the token array; we don't need it any more. */ cp_lexer_destroy (parser->lexer); parser->lexer = NULL; diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc index 883b0ea..c28804e 100644 --- a/gcc/diagnostic-format-json.cc +++ b/gcc/diagnostic-format-json.cc @@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "json.h" #include "selftest.h" #include "logical-location.h" -#include "make-unique.h" class json_output_format; @@ -74,7 +73,7 @@ public: std::unique_ptr<diagnostic_per_format_buffer> make_per_format_buffer () final override { - return ::make_unique<diagnostic_json_format_buffer> (*this); + return std::make_unique<diagnostic_json_format_buffer> (*this); } void set_buffer (diagnostic_per_format_buffer *base_buffer) final override { @@ -118,7 +117,7 @@ protected: bool formatted) : diagnostic_output_format (context), m_buffer (nullptr), - m_toplevel_array (::make_unique<json::array> ()), + m_toplevel_array (std::make_unique<json::array> ()), m_cur_group (nullptr), m_cur_children_array (nullptr), m_formatted (formatted) @@ -156,7 +155,7 @@ static std::unique_ptr<json::object> json_from_expanded_location (diagnostic_context &context, location_t loc) { expanded_location exploc = expand_location (loc); - std::unique_ptr<json::object> result = ::make_unique <json::object> (); + std::unique_ptr<json::object> result = std::make_unique <json::object> (); if (exploc.file) result->set_string ("file", exploc.file); result->set_integer ("line", exploc.line); @@ -200,7 +199,7 @@ json_from_location_range (diagnostic_context &context, location_t start_loc = get_start (loc_range->m_loc); location_t finish_loc = get_finish (loc_range->m_loc); - std::unique_ptr<json::object> result = ::make_unique <json::object> (); + std::unique_ptr<json::object> result = std::make_unique <json::object> (); result->set ("caret", json_from_expanded_location (context, caret_loc)); if (start_loc != caret_loc @@ -227,7 +226,7 @@ json_from_location_range (diagnostic_context &context, static std::unique_ptr<json::object> json_from_fixit_hint (diagnostic_context &context, const fixit_hint *hint) { - std::unique_ptr<json::object> fixit_obj = ::make_unique <json::object> (); + std::unique_ptr<json::object> fixit_obj = std::make_unique <json::object> (); location_t start_loc = hint->get_start_loc (); fixit_obj->set ("start", @@ -245,7 +244,7 @@ json_from_fixit_hint (diagnostic_context &context, const fixit_hint *hint) static std::unique_ptr<json::object> json_from_metadata (const diagnostic_metadata *metadata) { - std::unique_ptr<json::object> metadata_obj = ::make_unique <json::object> (); + std::unique_ptr<json::object> metadata_obj = std::make_unique <json::object> (); if (metadata->get_cwe ()) metadata_obj->set_integer ("cwe", metadata->get_cwe ()); @@ -260,12 +259,12 @@ make_json_for_path (diagnostic_context &context, pretty_printer *ref_pp, const diagnostic_path *path) { - std::unique_ptr<json::array> path_array = ::make_unique<json::array> (); + std::unique_ptr<json::array> path_array = std::make_unique<json::array> (); for (unsigned i = 0; i < path->num_events (); i++) { const diagnostic_event &event = path->get_event (i); - std::unique_ptr<json::object> event_obj = ::make_unique <json::object> (); + std::unique_ptr<json::object> event_obj = std::make_unique <json::object> (); if (event.get_location ()) event_obj->set ("location", json_from_expanded_location (context, @@ -395,7 +394,7 @@ json_output_format::on_report_diagnostic (const diagnostic_info &diagnostic, add a "children" array and record the column origin. */ m_cur_group = diag_obj; std::unique_ptr<json::array> children_array - = ::make_unique<json::array> (); + = std::make_unique<json::array> (); m_cur_children_array = children_array.get (); // borrowed diag_obj->set ("children", std::move (children_array)); diag_obj->set_integer ("column-origin", m_context.m_column_origin); @@ -409,7 +408,7 @@ json_output_format::on_report_diagnostic (const diagnostic_info &diagnostic, const rich_location *richloc = diagnostic.richloc; { - std::unique_ptr<json::array> loc_array = ::make_unique<json::array> (); + std::unique_ptr<json::array> loc_array = std::make_unique<json::array> (); for (unsigned int i = 0; i < richloc->get_num_locations (); i++) { const location_range *loc_range = richloc->get_range (i); @@ -422,7 +421,7 @@ json_output_format::on_report_diagnostic (const diagnostic_info &diagnostic, if (richloc->get_num_fixit_hints ()) { - std::unique_ptr<json::array> fixit_array = ::make_unique<json::array> (); + std::unique_ptr<json::array> fixit_array = std::make_unique<json::array> (); for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++) { const fixit_hint *hint = richloc->get_fixit_hint (i); @@ -524,8 +523,8 @@ diagnostic_output_format_init_json_stderr (diagnostic_context &context, { diagnostic_output_format_init_json (context, - ::make_unique<json_stderr_output_format> (context, - formatted)); + std::make_unique<json_stderr_output_format> (context, + formatted)); } /* Populate CONTEXT in preparation for JSON output to a file named @@ -538,9 +537,9 @@ diagnostic_output_format_init_json_file (diagnostic_context &context, { diagnostic_output_format_init_json (context, - ::make_unique<json_file_output_format> (context, - formatted, - base_file_name)); + std::make_unique<json_file_output_format> (context, + formatted, + base_file_name)); } #if CHECKING_P diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 8dbc91e..f322991 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -41,7 +41,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-format-text.h" #include "ordered-hash-map.h" #include "sbitmap.h" -#include "make-unique.h" #include "selftest.h" #include "selftest-diagnostic.h" #include "selftest-diagnostic-show-locus.h" @@ -158,7 +157,7 @@ make_date_time_string_for_current_time () "%02i:%02i:%02iZ"), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - return ::make_unique<json::string> (buf); + return std::make_unique<json::string> (buf); } /* Subclass of sarif_object for SARIF "invocation" objects @@ -689,7 +688,7 @@ public: const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version); + const sarif_generation_options &sarif_gen_opts); ~sarif_builder (); void set_printer (pretty_printer &printer) @@ -743,7 +742,7 @@ public: diagnostic_context &get_context () const { return m_context; } pretty_printer *get_printer () const { return m_printer; } token_printer &get_token_printer () { return m_token_printer; } - enum sarif_version get_version () const { return m_version; } + enum sarif_version get_version () const { return m_sarif_gen_opts.m_version; } size_t num_results () const { return m_results_array->size (); } sarif_result &get_result (size_t idx) @@ -753,6 +752,8 @@ public: return *static_cast<sarif_result *> (element); } + const sarif_generation_options &get_opts () const { return m_sarif_gen_opts; } + private: class sarif_token_printer : public token_printer { @@ -865,7 +866,6 @@ private: pretty_printer *m_printer; const line_maps *m_line_maps; sarif_token_printer m_token_printer; - enum sarif_version m_version; /* The JSON object for the invocation object. */ std::unique_ptr<sarif_invocation> m_invocation_obj; @@ -892,6 +892,7 @@ private: int m_tabstop; bool m_formatted; + const sarif_generation_options m_sarif_gen_opts; unsigned m_next_result_idx; sarif_code_flow *m_current_code_flow; @@ -918,13 +919,13 @@ sarif_object::get_or_create_properties () sarif_invocation::sarif_invocation (sarif_builder &builder, const char * const *original_argv) -: m_notifications_arr (::make_unique<json::array> ()), +: m_notifications_arr (std::make_unique<json::array> ()), m_success (true) { // "arguments" property (SARIF v2.1.0 section 3.20.2) if (original_argv) { - auto arguments_arr = ::make_unique<json::array> (); + auto arguments_arr = std::make_unique<json::array> (); for (size_t i = 0; original_argv[i]; ++i) arguments_arr->append_string (original_argv[i]); set<json::array> ("arguments", std::move (arguments_arr)); @@ -951,9 +952,9 @@ sarif_invocation::add_notification_for_ice (const diagnostic_info &diagnostic, m_success = false; auto notification - = ::make_unique<sarif_ice_notification> (diagnostic, - builder, - std::move (backtrace)); + = std::make_unique<sarif_ice_notification> (diagnostic, + builder, + std::move (backtrace)); /* Support for related locations within a notification was added in SARIF 2.2; see https://github.com/oasis-tcs/sarif-spec/issues/540 */ @@ -1068,7 +1069,7 @@ sarif_artifact::populate_roles () { if (bitmap_empty_p (m_roles)) return; - auto roles_arr (::make_unique<json::array> ()); + auto roles_arr (std::make_unique<json::array> ()); for (int i = 0; i < (int)diagnostic_artifact_role::NUM_ROLES; i++) if (bitmap_bit_p (m_roles, i)) { @@ -1245,7 +1246,7 @@ void sarif_result::on_diagram (const diagnostic_diagram &diagram, sarif_builder &builder) { - auto location_obj = ::make_unique<sarif_location> (); + auto location_obj = std::make_unique<sarif_location> (); auto message_obj = builder.make_message_object_for_diagram (diagram); location_obj->set<sarif_message> ("message", std::move (message_obj)); @@ -1344,7 +1345,7 @@ sarif_location::lazily_add_relationship_object (sarif_location &target, /* No existing locationRelationship from THIS to TARGET; make one, record it, and add it to the "relationships" array. */ auto relationship_obj - = ::make_unique<sarif_location_relationship> (target, loc_mgr); + = std::make_unique<sarif_location_relationship> (target, loc_mgr); sarif_location_relationship *relationship = relationship_obj.get (); auto kv = std::pair<sarif_location *, @@ -1472,7 +1473,7 @@ sarif_code_flow::sarif_code_flow (sarif_result &parent, m_idx_within_parent (idx_within_parent) { /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */ - auto thread_flows_arr = ::make_unique<json::array> (); + auto thread_flows_arr = std::make_unique<json::array> (); m_thread_flows_arr = thread_flows_arr.get (); // borrowed set<json::array> ("threadFlows", std::move (thread_flows_arr)); } @@ -1487,7 +1488,7 @@ sarif_code_flow::get_or_append_thread_flow (const diagnostic_thread &thread, unsigned next_thread_flow_idx = m_thread_flows_arr->size (); auto thread_flow_obj - = ::make_unique<sarif_thread_flow> (*this, thread, next_thread_flow_idx); + = std::make_unique<sarif_thread_flow> (*this, thread, next_thread_flow_idx); m_thread_id_map.put (thread_id, thread_flow_obj.get ()); // borrowed sarif_thread_flow *result = thread_flow_obj.get (); m_thread_flows_arr->append<sarif_thread_flow> (std::move (thread_flow_obj)); @@ -1561,15 +1562,14 @@ sarif_builder::sarif_builder (diagnostic_context &context, const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version) + const sarif_generation_options &sarif_gen_opts) : m_context (context), m_printer (&printer), m_line_maps (line_maps), m_token_printer (*this), - m_version (version), m_invocation_obj - (::make_unique<sarif_invocation> (*this, - context.get_original_argv ())), + (std::make_unique<sarif_invocation> (*this, + context.get_original_argv ())), m_results_array (new json::array ()), m_cur_group_result (nullptr), m_seen_any_relative_paths (false), @@ -1577,6 +1577,7 @@ sarif_builder::sarif_builder (diagnostic_context &context, m_rules_arr (new json::array ()), m_tabstop (context.m_tabstop), m_formatted (formatted), + m_sarif_gen_opts (sarif_gen_opts), m_next_result_idx (0), m_current_code_flow (nullptr) { @@ -1685,7 +1686,7 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, } } - auto frame_obj = ::make_unique<json::object> (); + auto frame_obj = std::make_unique<json::object> (); /* I tried using sarifStack and sarifStackFrame for this but it's not a good fit e.g. PC information. */ @@ -1711,7 +1712,7 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, std::unique_ptr<json::object> sarif_builder::make_stack_from_backtrace () { - auto frames_arr = ::make_unique<json::array> (); + auto frames_arr = std::make_unique<json::array> (); backtrace_state *state = nullptr; state = backtrace_create_state (nullptr, 0, nullptr, nullptr); @@ -1724,7 +1725,7 @@ sarif_builder::make_stack_from_backtrace () if (frames_arr->size () == 0) return nullptr; - auto stack = ::make_unique<json::object> (); + auto stack = std::make_unique<json::object> (); stack->set ("frames", std::move (frames_arr)); return stack; } @@ -1873,7 +1874,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic, diagnostic_t orig_diag_kind, unsigned idx_within_parent) { - auto result_obj = ::make_unique<sarif_result> (idx_within_parent); + auto result_obj = std::make_unique<sarif_result> (idx_within_parent); /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */ /* Ideally we'd have an option_name for these. */ @@ -1914,7 +1915,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic, /* "taxa" property (SARIF v2.1.0 section 3.27.8). */ if (int cwe_id = diagnostic.metadata->get_cwe ()) { - auto taxa_arr = ::make_unique<json::array> (); + auto taxa_arr = std::make_unique<json::array> (); taxa_arr->append<sarif_reporting_descriptor_reference> (make_reporting_descriptor_reference_object_for_cwe_id (cwe_id)); result_obj->set<json::array> ("taxa", std::move (taxa_arr)); @@ -1945,7 +1946,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic, /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */ if (const diagnostic_path *path = diagnostic.richloc->get_path ()) { - auto code_flows_arr = ::make_unique<json::array> (); + auto code_flows_arr = std::make_unique<json::array> (); const unsigned code_flow_index = 0; code_flows_arr->append<sarif_code_flow> (make_code_flow_object (*result_obj.get (), @@ -1962,7 +1963,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic, const rich_location *richloc = diagnostic.richloc; if (richloc->get_num_fixit_hints ()) { - auto fix_arr = ::make_unique<json::array> (); + auto fix_arr = std::make_unique<json::array> (); fix_arr->append<sarif_fix> (make_fix_object (*richloc)); result_obj->set<json::array> ("fixes", std::move (fix_arr)); } @@ -1979,7 +1980,7 @@ make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic, diagnostic_t /*orig_diag_kind*/, const char *option_text) { - auto reporting_desc = ::make_unique<sarif_reporting_descriptor> (); + auto reporting_desc = std::make_unique<sarif_reporting_descriptor> (); /* "id" property (SARIF v2.1.0 section 3.49.3). */ reporting_desc->set_string ("id", option_text); @@ -2003,7 +2004,7 @@ make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic, std::unique_ptr<sarif_reporting_descriptor> sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id) const { - auto reporting_desc = ::make_unique<sarif_reporting_descriptor> (); + auto reporting_desc = std::make_unique<sarif_reporting_descriptor> (); /* "id" property (SARIF v2.1.0 section 3.49.3). */ { @@ -2030,7 +2031,7 @@ std::unique_ptr<sarif_reporting_descriptor_reference> sarif_builder:: make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id) { - auto desc_ref_obj = ::make_unique<sarif_reporting_descriptor_reference> (); + auto desc_ref_obj = std::make_unique<sarif_reporting_descriptor_reference> (); /* "id" property (SARIF v2.1.0 section 3.52.4). */ { @@ -2057,7 +2058,7 @@ std::unique_ptr<sarif_tool_component_reference> sarif_builder:: make_tool_component_reference_object_for_cwe () const { - auto comp_ref_obj = ::make_unique<sarif_tool_component_reference> (); + auto comp_ref_obj = std::make_unique<sarif_tool_component_reference> (); /* "name" property (SARIF v2.1.0 section 3.54.3). */ comp_ref_obj->set_string ("name", "cwe"); @@ -2075,7 +2076,7 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr, const diagnostic_info &diagnostic, enum diagnostic_artifact_role role) { - auto locations_arr = ::make_unique<json::array> (); + auto locations_arr = std::make_unique<json::array> (); const logical_location *logical_loc = nullptr; if (auto client_data_hooks = m_context.get_client_data_hooks ()) logical_loc = client_data_hooks->get_current_logical_location (); @@ -2099,7 +2100,7 @@ set_any_logical_locs_arr (sarif_location &location_obj, { if (!logical_loc) return; - auto location_locs_arr = ::make_unique<json::array> (); + auto location_locs_arr = std::make_unique<json::array> (); location_locs_arr->append<sarif_logical_location> (make_sarif_logical_location_object (*logical_loc)); location_obj.set<json::array> ("logicalLocations", @@ -2159,7 +2160,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr, } the_renderer (rich_loc, m_context.get_escape_format ()); - auto location_obj = ::make_unique<sarif_location> (); + auto location_obj = std::make_unique<sarif_location> (); /* Get primary loc from RICH_LOC. */ location_t loc = rich_loc.get_loc (); @@ -2197,7 +2198,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr, if (region) { if (!annotations_arr) - annotations_arr = ::make_unique<json::array> (); + annotations_arr = std::make_unique<json::array> (); region->set<sarif_message> ("message", make_message_object (text.get ())); annotations_arr->append<sarif_region> (std::move (region)); @@ -2277,7 +2278,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr, location_t loc, enum diagnostic_artifact_role role) { - auto location_obj = ::make_unique<sarif_location> (); + auto location_obj = std::make_unique<sarif_location> (); /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */ if (auto phs_loc_obj @@ -2298,7 +2299,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr, const diagnostic_event &event, enum diagnostic_artifact_role role) { - auto location_obj = ::make_unique<sarif_location> (); + auto location_obj = std::make_unique<sarif_location> (); /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */ location_t loc = event.get_location (); @@ -2342,7 +2343,7 @@ maybe_make_physical_location_object (location_t loc, if (loc <= BUILTINS_LOCATION || LOCATION_FILE (loc) == nullptr) return nullptr; - auto phys_loc_obj = ::make_unique<sarif_physical_location> (); + auto phys_loc_obj = std::make_unique<sarif_physical_location> (); /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */ phys_loc_obj->set<sarif_artifact_location> @@ -2386,7 +2387,7 @@ sarif_builder::make_artifact_location_object (location_t loc) std::unique_ptr<sarif_artifact_location> sarif_builder::make_artifact_location_object (const char *filename) { - auto artifact_loc_obj = ::make_unique<sarif_artifact_location> (); + auto artifact_loc_obj = std::make_unique<sarif_artifact_location> (); /* "uri" property (SARIF v2.1.0 section 3.4.3). */ artifact_loc_obj->set_string ("uri", filename); @@ -2432,7 +2433,7 @@ make_pwd_uri_str () std::unique_ptr<sarif_artifact_location> sarif_builder::make_artifact_location_object_for_pwd () const { - auto artifact_loc_obj = ::make_unique<sarif_artifact_location> (); + auto artifact_loc_obj = std::make_unique<sarif_artifact_location> (); /* "uri" property (SARIF v2.1.0 section 3.4.3). */ if (char *pwd = make_pwd_uri_str ()) @@ -2492,7 +2493,7 @@ sarif_builder::maybe_make_region_object (location_t loc, if (exploc_start.line <= 0) return nullptr; - auto region_obj = ::make_unique<sarif_region> (); + auto region_obj = std::make_unique<sarif_region> (); /* "startLine" property (SARIF v2.1.0 section 3.30.5) */ region_obj->set_integer ("startLine", exploc_start.line); @@ -2569,7 +2570,7 @@ maybe_make_region_object_for_context (location_t loc, if (exploc_start.line <= 0) return nullptr; - auto region_obj = ::make_unique<sarif_region> (); + auto region_obj = std::make_unique<sarif_region> (); /* "startLine" property (SARIF v2.1.0 section 3.30.5) */ region_obj->set_integer ("startLine", exploc_start.line); @@ -2603,7 +2604,7 @@ sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const expanded_location exploc_start = expand_location (start_loc); expanded_location exploc_next = expand_location (next_loc); - auto region_obj = ::make_unique<sarif_region> (); + auto region_obj = std::make_unique<sarif_region> (); /* "startLine" property (SARIF v2.1.0 section 3.30.5) */ region_obj->set_integer ("startLine", exploc_start.line); @@ -2663,7 +2664,7 @@ maybe_get_sarif_kind (enum logical_location_kind kind) std::unique_ptr<sarif_logical_location> make_sarif_logical_location_object (const logical_location &logical_loc) { - auto logical_loc_obj = ::make_unique<sarif_logical_location> (); + auto logical_loc_obj = std::make_unique<sarif_logical_location> (); /* "name" property (SARIF v2.1.0 section 3.33.4). */ if (const char *short_name = logical_loc.get_short_name ()) @@ -2724,7 +2725,7 @@ sarif_builder::make_code_flow_object (sarif_result &result, const diagnostic_path &path) { auto code_flow_obj - = ::make_unique <sarif_code_flow> (result, idx_within_parent); + = std::make_unique <sarif_code_flow> (result, idx_within_parent); /* First pass: Create threadFlows and threadFlowLocation objects within them, @@ -2809,7 +2810,7 @@ sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const && m.m_property == diagnostic_event::PROPERTY_unknown) return nullptr; - auto kinds_arr = ::make_unique<json::array> (); + auto kinds_arr = std::make_unique<json::array> (); if (const char *verb_str = diagnostic_event::meaning::maybe_get_verb_str (m.m_verb)) kinds_arr->append_string (verb_str); @@ -2859,7 +2860,7 @@ set_string_property_escaping_braces (json::object &obj, std::unique_ptr<sarif_message> sarif_builder::make_message_object (const char *msg) const { - auto message_obj = ::make_unique<sarif_message> (); + auto message_obj = std::make_unique<sarif_message> (); /* "text" property (SARIF v2.1.0 section 3.11.8). */ set_string_property_escaping_braces (*message_obj, @@ -2875,7 +2876,7 @@ sarif_builder::make_message_object (const char *msg) const std::unique_ptr<sarif_message> sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagram) { - auto message_obj = ::make_unique<sarif_message> (); + auto message_obj = std::make_unique<sarif_message> (); /* "text" property (SARIF v2.1.0 section 3.11.8). */ set_string_property_escaping_braces (*message_obj, @@ -2906,7 +2907,7 @@ sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagra std::unique_ptr<sarif_multiformat_message_string> sarif_builder::make_multiformat_message_string (const char *msg) const { - auto message_obj = ::make_unique<sarif_multiformat_message_string> (); + auto message_obj = std::make_unique<sarif_multiformat_message_string> (); /* "text" property (SARIF v2.1.0 section 3.12.3). */ set_string_property_escaping_braces (*message_obj, @@ -2958,16 +2959,16 @@ sarif_builder:: make_top_level_object (std::unique_ptr<sarif_invocation> invocation_obj, std::unique_ptr<json::array> results) { - auto log_obj = ::make_unique<sarif_log> (); + auto log_obj = std::make_unique<sarif_log> (); /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */ - log_obj->set_string ("$schema", sarif_version_to_url (m_version)); + log_obj->set_string ("$schema", sarif_version_to_url (get_version ())); /* "version" property (SARIF v2.1.0 section 3.13.2). */ - log_obj->set_string ("version", sarif_version_to_property (m_version)); + log_obj->set_string ("version", sarif_version_to_property (get_version ())); /* "runs" property (SARIF v2.1.0 section 3.13.4). */ - auto run_arr = ::make_unique<json::array> (); + auto run_arr = std::make_unique<json::array> (); auto run_obj = make_run_object (std::move (invocation_obj), std::move (results)); run_arr->append<sarif_run> (std::move (run_obj)); @@ -2983,7 +2984,7 @@ sarif_builder:: make_run_object (std::unique_ptr<sarif_invocation> invocation_obj, std::unique_ptr<json::array> results) { - auto run_obj = ::make_unique<sarif_run> (); + auto run_obj = std::make_unique<sarif_run> (); /* "tool" property (SARIF v2.1.0 section 3.14.6). */ run_obj->set<sarif_tool> ("tool", make_tool_object ()); @@ -2994,7 +2995,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj, /* "invocations" property (SARIF v2.1.0 section 3.14.11). */ { - auto invocations_arr = ::make_unique<json::array> (); + auto invocations_arr = std::make_unique<json::array> (); invocations_arr->append (std::move (invocation_obj)); run_obj->set<json::array> ("invocations", std::move (invocations_arr)); } @@ -3002,7 +3003,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj, /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */ if (m_seen_any_relative_paths) { - auto orig_uri_base_ids = ::make_unique<json::object> (); + auto orig_uri_base_ids = std::make_unique<json::object> (); orig_uri_base_ids->set<sarif_artifact_location> (PWD_PROPERTY_NAME, make_artifact_location_object_for_pwd ()); run_obj->set<json::object> ("originalUriBaseIds", @@ -3010,7 +3011,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj, } /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */ - auto artifacts_arr = ::make_unique<json::array> (); + auto artifacts_arr = std::make_unique<json::array> (); for (auto iter : m_filename_to_artifact_map) { sarif_artifact *artifact_obj = iter.second; @@ -3033,7 +3034,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj, std::unique_ptr<sarif_tool> sarif_builder::make_tool_object () { - auto tool_obj = ::make_unique<sarif_tool> (); + auto tool_obj = std::make_unique<sarif_tool> (); /* "driver" property (SARIF v2.1.0 section 3.18.2). */ tool_obj->set<sarif_tool_component> ("driver", @@ -3052,7 +3053,7 @@ sarif_builder::make_tool_object () { /* Create a "toolComponent" object (SARIF v2.1.0 section 3.19) for the plugin. */ - auto plugin_obj = ::make_unique<sarif_tool_component> (); + auto plugin_obj = std::make_unique<sarif_tool_component> (); /* "name" property (SARIF v2.1.0 section 3.19.8). */ if (const char *short_name = p.get_short_name ()) @@ -3074,7 +3075,7 @@ sarif_builder::make_tool_object () vinfo->for_each_plugin (v); if (v.m_plugin_objs.size () > 0) { - auto extensions_arr = ::make_unique<json::array> (); + auto extensions_arr = std::make_unique<json::array> (); for (auto &iter : v.m_plugin_objs) extensions_arr->append<sarif_tool_component> (std::move (iter)); tool_obj->set<json::array> ("extensions", @@ -3094,7 +3095,7 @@ sarif_builder::make_tool_object () std::unique_ptr<sarif_tool_component> sarif_builder::make_driver_tool_component_object () { - auto driver_obj = ::make_unique<sarif_tool_component> (); + auto driver_obj = std::make_unique<sarif_tool_component> (); if (auto client_data_hooks = m_context.get_client_data_hooks ()) if (const client_version_info *vinfo @@ -3143,7 +3144,7 @@ sarif_builder::maybe_make_taxonomies_array () const return nullptr; /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */ - auto taxonomies_arr = ::make_unique<json::array> (); + auto taxonomies_arr = std::make_unique<json::array> (); taxonomies_arr->append<sarif_tool_component> (std::move (cwe_obj)); return taxonomies_arr; } @@ -3160,7 +3161,7 @@ sarif_builder::maybe_make_cwe_taxonomy_object () const if (m_cwe_id_set.is_empty ()) return nullptr; - auto taxonomy_obj = ::make_unique<sarif_tool_component> (); + auto taxonomy_obj = std::make_unique<sarif_tool_component> (); /* "name" property (SARIF v2.1.0 section 3.19.8). */ taxonomy_obj->set_string ("name", "CWE"); @@ -3178,7 +3179,7 @@ sarif_builder::maybe_make_cwe_taxonomy_object () const " Common Weakness Enumeration")); /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */ - auto taxa_arr = ::make_unique<json::array> (); + auto taxa_arr = std::make_unique<json::array> (); for (auto cwe_id : m_cwe_id_set) taxa_arr->append<sarif_reporting_descriptor> (make_reporting_descriptor_object_for_cwe_id (cwe_id)); @@ -3252,10 +3253,10 @@ sarif_builder::maybe_make_artifact_content_object (const char *filename) const if (!cpp_valid_utf8_p(utf8_content.get_buffer (), utf8_content.length ())) return nullptr; - auto artifact_content_obj = ::make_unique<sarif_artifact_content> (); + auto artifact_content_obj = std::make_unique<sarif_artifact_content> (); artifact_content_obj->set<json::string> ("text", - ::make_unique <json::string> (utf8_content.get_buffer (), + std::make_unique <json::string> (utf8_content.get_buffer (), utf8_content.length ())); return artifact_content_obj; } @@ -3310,7 +3311,7 @@ maybe_make_artifact_content_object (const char *filename, return nullptr; } - auto artifact_content_obj = ::make_unique<sarif_artifact_content> (); + auto artifact_content_obj = std::make_unique<sarif_artifact_content> (); artifact_content_obj->set_string ("text", text_utf8); free (text_utf8); @@ -3328,11 +3329,11 @@ maybe_make_artifact_content_object (const char *filename, std::unique_ptr<sarif_fix> sarif_builder::make_fix_object (const rich_location &richloc) { - auto fix_obj = ::make_unique<sarif_fix> (); + auto fix_obj = std::make_unique<sarif_fix> (); /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */ /* We assume that all fix-it hints in RICHLOC affect the same file. */ - auto artifact_change_arr = ::make_unique<json::array> (); + auto artifact_change_arr = std::make_unique<json::array> (); artifact_change_arr->append<sarif_artifact_change> (make_artifact_change_object (richloc)); fix_obj->set<json::array> ("artifactChanges", @@ -3346,7 +3347,7 @@ sarif_builder::make_fix_object (const rich_location &richloc) std::unique_ptr<sarif_artifact_change> sarif_builder::make_artifact_change_object (const rich_location &richloc) { - auto artifact_change_obj = ::make_unique<sarif_artifact_change> (); + auto artifact_change_obj = std::make_unique<sarif_artifact_change> (); /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */ artifact_change_obj->set<sarif_artifact_location> @@ -3354,7 +3355,7 @@ sarif_builder::make_artifact_change_object (const rich_location &richloc) make_artifact_location_object (richloc.get_loc ())); /* "replacements" property (SARIF v2.1.0 section 3.56.3). */ - auto replacement_arr = ::make_unique<json::array> (); + auto replacement_arr = std::make_unique<json::array> (); for (unsigned int i = 0; i < richloc.get_num_fixit_hints (); i++) { const fixit_hint *hint = richloc.get_fixit_hint (i); @@ -3372,7 +3373,7 @@ sarif_builder::make_artifact_change_object (const rich_location &richloc) std::unique_ptr<sarif_replacement> sarif_builder::make_replacement_object (const fixit_hint &hint) const { - auto replacement_obj = ::make_unique<sarif_replacement> (); + auto replacement_obj = std::make_unique<sarif_replacement> (); /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */ replacement_obj->set<sarif_region> ("deletedRegion", @@ -3391,7 +3392,7 @@ sarif_builder::make_replacement_object (const fixit_hint &hint) const std::unique_ptr<sarif_artifact_content> sarif_builder::make_artifact_content_object (const char *text) const { - auto content_obj = ::make_unique<sarif_artifact_content> (); + auto content_obj = std::make_unique<sarif_artifact_content> (); /* "text" property (SARIF v2.1.0 section 3.3.2). */ content_obj->set_string ("text", text); @@ -3470,7 +3471,7 @@ public: std::unique_ptr<diagnostic_per_format_buffer> make_per_format_buffer () final override { - return ::make_unique<diagnostic_sarif_format_buffer> (m_builder); + return std::make_unique<diagnostic_sarif_format_buffer> (m_builder); } void set_buffer (diagnostic_per_format_buffer *base_buffer) final override { @@ -3534,10 +3535,10 @@ protected: const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version) + const sarif_generation_options &sarif_gen_opts) : diagnostic_output_format (context), m_builder (context, *get_printer (), line_maps, main_input_filename_, - formatted, version), + formatted, sarif_gen_opts), m_buffer (nullptr) {} @@ -3552,10 +3553,11 @@ public: const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version, + const sarif_generation_options &sarif_gen_opts, FILE *stream) : sarif_output_format (context, line_maps, main_input_filename_, - formatted, version), + formatted, + sarif_gen_opts), m_stream (stream) { } @@ -3578,10 +3580,10 @@ public: const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version, + const sarif_generation_options &sarif_gen_opts, diagnostic_output_file output_file) : sarif_output_format (context, line_maps, main_input_filename_, - formatted, version), + formatted, sarif_gen_opts), m_output_file (std::move (output_file)) { gcc_assert (m_output_file.get_open_file ()); @@ -3741,18 +3743,18 @@ void diagnostic_output_format_init_sarif_stderr (diagnostic_context &context, const line_maps *line_maps, const char *main_input_filename_, - bool formatted, - enum sarif_version version) + bool formatted) { gcc_assert (line_maps); + const sarif_generation_options sarif_gen_opts; diagnostic_output_format_init_sarif (context, - ::make_unique<sarif_stream_output_format> (context, - line_maps, - main_input_filename_, - formatted, - version, - stderr)); + std::make_unique<sarif_stream_output_format> (context, + line_maps, + main_input_filename_, + formatted, + sarif_gen_opts, + stderr)); } /* Attempt to open BASE_FILE_NAME.sarif for writing. @@ -3798,7 +3800,6 @@ diagnostic_output_format_init_sarif_file (diagnostic_context &context, line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version, const char *base_file_name) { gcc_assert (line_maps); @@ -3808,14 +3809,15 @@ diagnostic_output_format_init_sarif_file (diagnostic_context &context, line_maps, base_file_name); + const sarif_generation_options sarif_gen_opts; diagnostic_output_format_init_sarif (context, - ::make_unique<sarif_file_output_format> (context, - line_maps, - main_input_filename_, - formatted, - version, - std::move (output_file))); + std::make_unique<sarif_file_output_format> (context, + line_maps, + main_input_filename_, + formatted, + sarif_gen_opts, + std::move (output_file))); } /* Populate CONTEXT in preparation for SARIF output to STREAM. */ @@ -3825,37 +3827,46 @@ diagnostic_output_format_init_sarif_stream (diagnostic_context &context, const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version, FILE *stream) { gcc_assert (line_maps); + const sarif_generation_options sarif_gen_opts; diagnostic_output_format_init_sarif (context, - ::make_unique<sarif_stream_output_format> (context, - line_maps, - main_input_filename_, - formatted, - version, - stream)); + std::make_unique<sarif_stream_output_format> (context, + line_maps, + main_input_filename_, + formatted, + sarif_gen_opts, + stream)); } std::unique_ptr<diagnostic_output_format> make_sarif_sink (diagnostic_context &context, const line_maps &line_maps, const char *main_input_filename_, - enum sarif_version version, + bool formatted, + const sarif_generation_options &sarif_gen_opts, diagnostic_output_file output_file) { - auto sink = ::make_unique<sarif_file_output_format> (context, - &line_maps, - main_input_filename_, - true, - version, - std::move (output_file)); + auto sink + = std::make_unique<sarif_file_output_format> (context, + &line_maps, + main_input_filename_, + formatted, + sarif_gen_opts, + std::move (output_file)); sink->update_printer (); return sink; } +// struct sarif_generation_options + +sarif_generation_options::sarif_generation_options () +: m_version (sarif_version::v2_1_0) +{ +} + #if CHECKING_P namespace selftest { @@ -3868,13 +3879,13 @@ class test_sarif_diagnostic_context : public test_diagnostic_context { public: test_sarif_diagnostic_context (const char *main_input_filename, - enum sarif_version version) + const sarif_generation_options &sarif_gen_opts) { - auto format = ::make_unique<buffered_output_format> (*this, - line_table, - main_input_filename, - true, - version); + auto format = std::make_unique<buffered_output_format> (*this, + line_table, + main_input_filename, + true, + sarif_gen_opts); m_format = format.get (); // borrowed diagnostic_output_format_init_sarif (*this, std::move (format)); } @@ -3895,9 +3906,9 @@ private: const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version) + const sarif_generation_options &sarif_gen_opts) : sarif_output_format (context, line_maps, main_input_filename_, - formatted, version) + formatted, sarif_gen_opts) { } bool machine_readable_stderr_p () const final override @@ -3917,8 +3928,8 @@ private: with labels and escape-on-output. */ static void -test_make_location_object (const line_table_case &case_, - enum sarif_version version) +test_make_location_object (const sarif_generation_options &sarif_gen_opts, + const line_table_case &case_) { diagnostic_show_locus_fixture_one_liner_utf8 f (case_); location_t line_end = linemap_position_for_column (line_table, 31); @@ -3930,7 +3941,7 @@ test_make_location_object (const line_table_case &case_, test_diagnostic_context dc; pretty_printer pp; sarif_builder builder (dc, pp, line_table, "MAIN_INPUT_FILENAME", - true, version); + true, sarif_gen_opts); /* These "columns" are byte offsets, whereas later on the columns in the generated SARIF use sarif_builder::get_sarif_column and @@ -4041,9 +4052,9 @@ test_make_location_object (const line_table_case &case_, Verify various basic properties. */ static void -test_simple_log (enum sarif_version version) +test_simple_log (const sarif_generation_options &sarif_gen_opts) { - test_sarif_diagnostic_context dc ("MAIN_INPUT_FILENAME", version); + test_sarif_diagnostic_context dc ("MAIN_INPUT_FILENAME", sarif_gen_opts); rich_location richloc (line_table, UNKNOWN_LOCATION); dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42); @@ -4052,6 +4063,7 @@ test_simple_log (enum sarif_version version) // 3.13 sarifLog: auto log = log_ptr.get (); + const enum sarif_version version = sarif_gen_opts.m_version; ASSERT_JSON_STRING_PROPERTY_EQ (log, "$schema", sarif_version_to_url (version)); ASSERT_JSON_STRING_PROPERTY_EQ (log, "version", @@ -4158,8 +4170,8 @@ test_simple_log (enum sarif_version version) /* As above, but with a "real" location_t. */ static void -test_simple_log_2 (const line_table_case &case_, - enum sarif_version version) +test_simple_log_2 (const sarif_generation_options &sarif_gen_opts, + const line_table_case &case_) { auto_fix_quotes fix_quotes; @@ -4174,7 +4186,7 @@ test_simple_log_2 (const line_table_case &case_, if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS) return; - test_sarif_diagnostic_context dc (f.get_filename (), version); + test_sarif_diagnostic_context dc (f.get_filename (), sarif_gen_opts); const location_t typo_loc = make_location (linemap_position_for_column (line_table, 1), @@ -4304,11 +4316,11 @@ get_message_from_log (const sarif_log *log) /* Tests of messages with embedded links; see SARIF v2.1.0 3.11.6. */ static void -test_message_with_embedded_link (enum sarif_version version) +test_message_with_embedded_link (const sarif_generation_options &sarif_gen_opts) { auto_fix_quotes fix_quotes; { - test_sarif_diagnostic_context dc ("test.c", version); + test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts); rich_location richloc (line_table, UNKNOWN_LOCATION); dc.report (DK_ERROR, richloc, nullptr, 0, "before %{text%} after", @@ -4324,7 +4336,7 @@ test_message_with_embedded_link (enum sarif_version version) /* Escaping in message text. This is "EXAMPLE 1" from 3.11.6. */ { - test_sarif_diagnostic_context dc ("test.c", version); + test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts); rich_location richloc (line_table, UNKNOWN_LOCATION); /* Disable "unquoted sequence of 2 consecutive punctuation @@ -4364,8 +4376,8 @@ test_message_with_embedded_link (enum sarif_version version) } }; - test_sarif_diagnostic_context dc ("test.c", version); - dc.push_owned_urlifier (::make_unique<test_urlifier> ()); + test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts); + dc.push_owned_urlifier (std::make_unique<test_urlifier> ()); rich_location richloc (line_table, UNKNOWN_LOCATION); dc.report (DK_ERROR, richloc, nullptr, 0, "foo %<-foption%> %<unrecognized%> bar"); @@ -4382,11 +4394,11 @@ test_message_with_embedded_link (enum sarif_version version) 3.11.5 ("Messages with placeholders"). */ static void -test_message_with_braces (enum sarif_version version) +test_message_with_braces (const sarif_generation_options &sarif_gen_opts) { auto_fix_quotes fix_quotes; { - test_sarif_diagnostic_context dc ("test.c", version); + test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts); rich_location richloc (line_table, UNKNOWN_LOCATION); dc.report (DK_ERROR, richloc, nullptr, 0, "open brace: %qs close brace: %qs", @@ -4401,9 +4413,9 @@ test_message_with_braces (enum sarif_version version) } static void -test_buffering (enum sarif_version version) +test_buffering (const sarif_generation_options &sarif_gen_opts) { - test_sarif_diagnostic_context dc ("test.c", version); + test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts); diagnostic_buffer buf_a (dc); diagnostic_buffer buf_b (dc); @@ -4487,41 +4499,45 @@ test_buffering (enum sarif_version version) } } +template <class ...ArgTypes> static void -run_tests_per_version (const line_table_case &case_) +for_each_sarif_gen_option (void (*callback) (const sarif_generation_options &, + ArgTypes ...), + ArgTypes ...args) { + sarif_generation_options sarif_gen_opts; for (int version_idx = 0; version_idx < (int)sarif_version::num_versions; ++version_idx) { - enum sarif_version version - = static_cast<enum sarif_version> (version_idx); + sarif_gen_opts.m_version = static_cast<enum sarif_version> (version_idx); - test_make_location_object (case_, version); - test_simple_log_2 (case_, version); + callback (sarif_gen_opts, args...); } } +static void +run_line_table_case_tests_per_version (const line_table_case &case_) +{ + for_each_sarif_gen_option<const line_table_case &> + (test_make_location_object, case_); + + for_each_sarif_gen_option<const line_table_case &> + (test_simple_log_2, case_); +} + /* Run all of the selftests within this file. */ void diagnostic_format_sarif_cc_tests () { - for (int version_idx = 0; - version_idx < (int)sarif_version::num_versions; - ++version_idx) - { - enum sarif_version version - = static_cast<enum sarif_version> (version_idx); - - test_simple_log (version); - test_message_with_embedded_link (version); - test_message_with_braces (version); - test_buffering (version); - } + for_each_sarif_gen_option (test_simple_log); + for_each_sarif_gen_option (test_message_with_embedded_link); + for_each_sarif_gen_option (test_message_with_braces); + for_each_sarif_gen_option (test_buffering); - /* Run tests per (line-table-case, SARIF version) pair. */ - for_each_line_table_case (run_tests_per_version); + /* Run tests per (SARIF gen-option, line-table-case) pair. */ + for_each_line_table_case (run_line_table_case_tests_per_version); } } // namespace selftest diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostic-format-sarif.h index 5dc6176..524a0c7 100644 --- a/gcc/diagnostic-format-sarif.h +++ b/gcc/diagnostic-format-sarif.h @@ -27,14 +27,6 @@ along with GCC; see the file COPYING3. If not see class logical_location; -enum class sarif_version -{ - v2_1_0, - v2_2_prerelease_2024_08_08, - - num_versions -}; - extern diagnostic_output_file diagnostic_output_format_open_sarif_file (diagnostic_context &context, line_maps *line_maps, @@ -44,27 +36,45 @@ extern void diagnostic_output_format_init_sarif_stderr (diagnostic_context &context, const line_maps *line_maps, const char *main_input_filename_, - bool formatted, - enum sarif_version version); + bool formatted); extern void diagnostic_output_format_init_sarif_file (diagnostic_context &context, line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version, const char *base_file_name); extern void diagnostic_output_format_init_sarif_stream (diagnostic_context &context, const line_maps *line_maps, const char *main_input_filename_, bool formatted, - enum sarif_version version, FILE *stream); + +enum class sarif_version +{ + v2_1_0, + v2_2_prerelease_2024_08_08, + + num_versions +}; + +/* A bundle of state for controlling what to put in SARIF output, + such as which version of SARIF to generate + (as opposed to SARIF *serialization* options, such as formatting). */ + +struct sarif_generation_options +{ + sarif_generation_options (); + + enum sarif_version m_version; +}; + extern std::unique_ptr<diagnostic_output_format> make_sarif_sink (diagnostic_context &context, const line_maps &line_maps, const char *main_input_filename_, - enum sarif_version version, + bool formatted, + const sarif_generation_options &sarif_gen_opts, diagnostic_output_file output_file); /* Concrete subclass of json::object for SARIF property bags diff --git a/gcc/diagnostic-format-text.cc b/gcc/diagnostic-format-text.cc index 9273973..5df3894 100644 --- a/gcc/diagnostic-format-text.cc +++ b/gcc/diagnostic-format-text.cc @@ -34,7 +34,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-format-text.h" #include "diagnostic-buffer.h" #include "text-art/theme.h" -#include "make-unique.h" /* Disable warnings about quoting issues in the pp_xxx calls below that (intentionally) don't follow GCC diagnostic conventions. */ @@ -193,7 +192,7 @@ diagnostic_text_output_format::set_buffer (diagnostic_per_format_buffer *base) std::unique_ptr<diagnostic_per_format_buffer> diagnostic_text_output_format::make_per_format_buffer () { - return ::make_unique<diagnostic_text_format_buffer> (*this); + return std::make_unique<diagnostic_text_format_buffer> (*this); } /* Implementation of diagnostic_output_format::on_report_diagnostic vfunc diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index 07c76b6..429c4b1 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -49,7 +49,6 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print-urlifier.h" #include "logical-location.h" #include "diagnostic-buffer.h" -#include "make-unique.h" #ifdef HAVE_TERMIOS_H # include <termios.h> @@ -223,7 +222,7 @@ diagnostic_context::initialize (int n_opts) { /* Allocate a basic pretty-printer. Clients will replace this a much more elaborated pretty-printer if they wish. */ - m_reference_printer = ::make_unique<pretty_printer> ().release (); + m_reference_printer = std::make_unique<pretty_printer> ().release (); m_file_cache = new file_cache (); m_diagnostic_counters.clear (); @@ -1830,8 +1829,7 @@ diagnostic_output_format_init (diagnostic_context &context, diagnostic_output_format_init_sarif_stderr (context, line_table, main_input_filename_, - json_formatting, - sarif_version::v2_1_0); + json_formatting); break; case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE: @@ -1839,7 +1837,6 @@ diagnostic_output_format_init (diagnostic_context &context, line_table, main_input_filename_, json_formatting, - sarif_version::v2_1_0, base_file_name); break; } diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 62bffd2..36f4a1c 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -772,6 +772,13 @@ public: bool supports_fnotice_on_stderr_p () const; + /* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher. */ + void + set_abort_on_error (bool val) + { + m_abort_on_error = val; + } + private: void error_recursion () ATTRIBUTE_NORETURN; @@ -828,10 +835,10 @@ private: each diagnostic, if known. */ bool m_show_option_requested; -public: /* True if we should raise a SIGABRT on errors. */ bool m_abort_on_error; +public: /* True if we should show the column number on diagnostics. */ bool m_show_column; @@ -841,9 +848,9 @@ public: /* True if permerrors are warnings. */ bool m_permissive; - /* The index of the option to associate with turning permerrors into - warnings. */ - int m_opt_permissive; + /* The option to associate with turning permerrors into warnings, + if any. */ + diagnostic_option_id m_opt_permissive; /* True if errors are fatal. */ bool m_fatal_errors; @@ -1042,13 +1049,6 @@ diagnostic_text_finalizer (diagnostic_context *context) #define diagnostic_context_auxiliary_data(DC) (DC)->m_client_aux_data #define diagnostic_info_auxiliary_data(DI) (DI)->x_data -/* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher. */ -inline void -diagnostic_abort_on_error (diagnostic_context *context) -{ - context->m_abort_on_error = true; -} - /* This diagnostic_context is used by front-ends that directly output diagnostic messages without going through `error', `warning', and similar functions. */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a0f60e7..d5a2bf6 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -513,6 +513,7 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-tainted-divisor -Wno-analyzer-tainted-offset -Wno-analyzer-tainted-size +-Wno-analyzer-throw-of-unexpected-type -Wanalyzer-symbol-too-complex -Wanalyzer-too-complex -Wno-analyzer-undefined-behavior-ptrdiff @@ -578,7 +579,7 @@ Objective-C and Objective-C++ Dialects}. -ffold-mem-offsets -fcompare-elim -fcprop-registers -fcrossjumping -fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules --fcx-limited-range +-fcx-limited-range -fcx-method -fdata-sections -fdce -fdelayed-branch -fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively -fdevirtualize-at-ltrans -fdse @@ -11008,6 +11009,7 @@ Enabling this option effectively enables the following warnings: -Wanalyzer-tainted-divisor -Wanalyzer-tainted-offset -Wanalyzer-tainted-size +-Wanalyzer-throw-of-unexpected-type -Wanalyzer-undefined-behavior-ptrdiff -Wanalyzer-undefined-behavior-strtok -Wanalyzer-unsafe-call-within-signal-handler @@ -11659,6 +11661,17 @@ attacker could inject an out-of-bounds access. See @uref{https://cwe.mitre.org/data/definitions/129.html, CWE-129: Improper Validation of Array Index}. +@opindex Wanalyzer-throw-of-unexpected-type +@opindex Wno-analyzer-throw-of-unexpected-type +@item -Wno-analyzer-throw-of-unexpected-type +This warning requires @option{-fanalyzer} which enables it; +use @option{-Wno-analyzer-throw-of-unexpected-type} to disable it. +Dynamic exception specifications are only available in C++14 and earlier. + +This diagnostic warns for paths through the code in which a an exception +is thrown from a function with a dynamic exception specification where +the exception does not comply with the specification. + @opindex Wanalyzer-undefined-behavior-ptrdiff @opindex Wno-analyzer-undefined-behavior-ptrdiff @item -Wno-analyzer-undefined-behavior-ptrdiff @@ -15603,8 +15616,7 @@ When enabled, this option states that a range reduction step is not needed when performing complex division. Also, there is no checking whether the result of a complex multiplication or division is @code{NaN + I*NaN}, with an attempt to rescue the situation in that case. The -default is @option{-fno-cx-limited-range}, but is enabled by -@option{-ffast-math}. +option is enabled by @option{-ffast-math}. This option controls the default setting of the ISO C99 @code{CX_LIMITED_RANGE} pragma. Nevertheless, the option applies to @@ -15617,7 +15629,14 @@ reduction is done as part of complex division, but there is no checking whether the result of a complex multiplication or division is @code{NaN + I*NaN}, with an attempt to rescue the situation in that case. -The default is @option{-fno-cx-fortran-rules}. +@opindex fcx-method +@item -fcx-method=@var{method} +Complex multiplication and division follow the stated @var{method}. The +@var{method} argument should be one of @samp{limited-range}, @samp{fortran} +or @samp{stdc}. + +The default is to honor language specific constraints which means +@samp{fortran} for Fortran and @samp{stdc} otherwise. @end table @@ -17225,9 +17244,6 @@ this parameter. The default value of this parameter is 50. @item vect-induction-float Enable loop vectorization of floating point inductions. -@item vect-force-slp -Force the use of SLP when vectorizing, fail if not possible. - @item vrp-block-limit Maximum number of basic blocks before VRP switches to a lower memory algorithm. diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc index 65bd5c5..ebee8e5 100644 --- a/gcc/dumpfile.cc +++ b/gcc/dumpfile.cc @@ -40,7 +40,6 @@ along with GCC; see the file COPYING3. If not see #include "optinfo-emit-json.h" #include "stringpool.h" /* for get_identifier. */ #include "spellcheck.h" -#include "make-unique.h" #include "pretty-print-format-impl.h" /* If non-NULL, return one past-the-end of the matching SUBPART of @@ -638,9 +637,9 @@ make_item_for_dump_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags) pp_newline (&pp); std::unique_ptr<optinfo_item> item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE, - gimple_location (stmt), - xstrdup (pp_formatted_text (&pp))); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE, + gimple_location (stmt), + xstrdup (pp_formatted_text (&pp))); return item; } @@ -686,9 +685,9 @@ make_item_for_dump_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags) pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags); std::unique_ptr<optinfo_item> item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE, - gimple_location (stmt), - xstrdup (pp_formatted_text (&pp))); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE, + gimple_location (stmt), + xstrdup (pp_formatted_text (&pp))); return item; } @@ -740,8 +739,8 @@ make_item_for_dump_generic_expr (tree node, dump_flags_t dump_flags) loc = EXPR_LOCATION (node); std::unique_ptr<optinfo_item> item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TREE, loc, - xstrdup (pp_formatted_text (&pp))); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TREE, loc, + xstrdup (pp_formatted_text (&pp))); return item; } @@ -785,8 +784,8 @@ make_item_for_dump_symtab_node (symtab_node *node) { location_t loc = DECL_SOURCE_LOCATION (node->decl); std::unique_ptr<optinfo_item> item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc, - xstrdup (node->dump_name ())); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc, + xstrdup (node->dump_name ())); return item; } @@ -847,7 +846,7 @@ dump_pretty_printer::stash_item (pp_token_list &formatted_tok_list, gcc_assert (item.get ()); auto custom_data - = ::make_unique<wrapped_optinfo_item> (std::move (item)); + = std::make_unique<wrapped_optinfo_item> (std::move (item)); formatted_tok_list.push_back<pp_token_custom_data> (std::move (custom_data)); } @@ -1013,8 +1012,8 @@ emit_any_pending_textual_chunks () char *formatted_text = xstrdup (pp_formatted_text (pp)); std::unique_ptr<optinfo_item> item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, - formatted_text); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, + formatted_text); pp->emit_item (std::move (item), m_optinfo); /* Clear the pending text by unwinding formatted_text back to the start @@ -1085,8 +1084,8 @@ make_item_for_dump_dec (const poly_int<N, C> &value) } auto item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, - xstrdup (pp_formatted_text (&pp))); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, + xstrdup (pp_formatted_text (&pp))); return item; } @@ -1164,8 +1163,8 @@ dump_context::begin_scope (const char *name, pp_printf (&pp, "%s %s %s", "===", name, "==="); pp_newline (&pp); std::unique_ptr<optinfo_item> item - = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, - xstrdup (pp_formatted_text (&pp))); + = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, + xstrdup (pp_formatted_text (&pp))); emit_item (*item.get (), MSG_NOTE); if (optinfo_enabled_p ()) diff --git a/gcc/gcc-attribute-urlifier.cc b/gcc/gcc-attribute-urlifier.cc index d066624..fd3d629 100644 --- a/gcc/gcc-attribute-urlifier.cc +++ b/gcc/gcc-attribute-urlifier.cc @@ -29,7 +29,6 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "diagnostic.h" #include "selftest.h" -#include "make-unique.h" #include "target.h" /* class attribute_urlifier : public urlifier. */ diff --git a/gcc/gcc-urlifier.cc b/gcc/gcc-urlifier.cc index a409458..677720b 100644 --- a/gcc/gcc-urlifier.cc +++ b/gcc/gcc-urlifier.cc @@ -28,7 +28,6 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "diagnostic.h" #include "selftest.h" -#include "make-unique.h" char * make_doc_url (const char *doc_url_suffix) @@ -215,7 +214,7 @@ gcc_urlifier::get_url_suffix_for_option (const char *p, size_t sz) const std::unique_ptr<urlifier> make_gcc_urlifier (unsigned int lang_mask) { - return ::make_unique<gcc_urlifier> (lang_mask); + return std::make_unique<gcc_urlifier> (lang_mask); } /* class auto_override_urlifier. */ diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 85bd77a..c6097cd 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -1485,7 +1485,7 @@ public: virtual void gen_transform (FILE *, int, const char *, bool, int, const char *, capture_info *, dt_operand ** = 0, - int = 0) + int = 0, const char * = nullptr) { gcc_unreachable (); } }; @@ -1538,8 +1538,8 @@ public: /* If non-zero, the group for optional handling. */ unsigned char opt_grp; void gen_transform (FILE *f, int, const char *, bool, int, - const char *, capture_info *, - dt_operand ** = 0, int = 0) override; + const char *, capture_info *, dt_operand ** = 0, + int = 0, const char * = nullptr) override; }; /* An operator that is represented by native C code. This is always @@ -1572,8 +1572,8 @@ public: /* The identifier replacement vector. */ vec<id_tab> ids; void gen_transform (FILE *f, int, const char *, bool, int, - const char *, capture_info *, - dt_operand ** = 0, int = 0) final override; + const char *, capture_info *, dt_operand ** = 0, + int = 0, const char * = nullptr) final override; }; /* A wrapper around another operand that captures its value. */ @@ -1593,8 +1593,8 @@ public: /* The captured value. */ operand *what; void gen_transform (FILE *f, int, const char *, bool, int, - const char *, capture_info *, - dt_operand ** = 0, int = 0) final override; + const char *, capture_info *, dt_operand ** = 0, + int = 0, const char * = nullptr) final override; }; /* if expression. */ @@ -3196,6 +3196,14 @@ is_conversion (id_base *op) || *op == VIEW_CONVERT_EXPR); } +bool +possible_noop_convert (id_base *op) +{ + return (*op == CONVERT_EXPR + || *op == NOP_EXPR + || *op == VIEW_CONVERT_EXPR); +} + /* Get the type to be used for generating operand POS of OP from the various sources. */ @@ -3249,7 +3257,7 @@ get_operand_type (id_base *op, unsigned pos, void expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, - dt_operand **indexes, int) + dt_operand **indexes, int, const char *in_place) { id_base *opr = operation; /* When we delay operator substituting during lowering of fors we @@ -3307,10 +3315,23 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, if (!type) fatal_at (location, "cannot determine type of operand"); + bool child_in_place = (!in_place + && gimple + && possible_noop_convert (opr) + && is_a <expr *> (ops[0])); + fprintf_indent (f, indent, "{\n"); indent += 2; - fprintf_indent (f, indent, - "tree _o%d[%u], _r%d;\n", depth, ops.length (), depth); + if (child_in_place) + { + fprintf_indent (f, indent, "tree _r%d;\n", depth); + fprintf_indent (f, indent, + "gimple_match_op tem_op (res_op->cond.any_else (), " + "ERROR_MARK, error_mark_node, 1);\n"); + } + else + fprintf_indent (f, indent, + "tree _o%d[%u], _r%d;\n", depth, ops.length (), depth); char op0type[64]; snprintf (op0type, sizeof (op0type), "TREE_TYPE (_o%d[0])", depth); for (unsigned i = 0; i < ops.length (); ++i) @@ -3322,7 +3343,8 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, i == 0 ? NULL : op0type); ops[i]->gen_transform (f, indent, dest1, gimple, depth + 1, optype1, cinfo, indexes, - *opr == COND_EXPR && i == 0 ? 1 : 2); + *opr == COND_EXPR && i == 0 ? 1 : 2, + child_in_place ? "tem_op" : NULL); } const char *opr_name; @@ -3333,45 +3355,95 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, if (gimple) { - if (*opr == CONVERT_EXPR) + if (child_in_place) { + gcc_assert (!in_place); fprintf_indent (f, indent, - "if (%s != TREE_TYPE (_o%d[0])\n", - type, depth); + "if (%s != tem_op.type\n", type); fprintf_indent (f, indent, - " && !useless_type_conversion_p (%s, TREE_TYPE " - "(_o%d[0])))\n", - type, depth); + " && !useless_type_conversion_p (%s, tem_op.type))\n", + type); fprintf_indent (f, indent + 2, "{\n"); indent += 4; + fprintf_indent (f, indent, + "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", + depth, (!as_a <expr *> (ops[0])->force_leaf + ? "lseq" : "NULL")); + fprintf_indent (f, indent, + "if (!_r%d) goto %s;\n", depth, fail_label); + fprintf_indent (f, indent, + "tem_op.set_op (%s, %s, 1);\n", opr_name, type); + fprintf_indent (f, indent, + "tem_op.ops[0] = _r%d;\n", depth); + fprintf_indent (f, indent, + "tem_op.resimplify (%s, valueize);\n", + !force_leaf ? "lseq" : "NULL"); + indent -= 4; + fprintf_indent (f, indent + 2, "}\n"); + fprintf_indent (f, indent, + "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", + depth, !force_leaf ? "lseq" : "NULL"); + fprintf_indent (f, indent, + "if (!_r%d) goto %s;\n", depth, fail_label); } - /* ??? Building a stmt can fail for various reasons here, seq being - NULL or the stmt referencing SSA names occuring in abnormal PHIs. - So if we fail here we should continue matching other patterns. */ - fprintf_indent (f, indent, "gimple_match_op tem_op " - "(res_op->cond.any_else (), %s, %s", opr_name, type); - for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", _o%d[%u]", depth, i); - fprintf (f, ");\n"); - fprintf_indent (f, indent, "tem_op.resimplify (%s, valueize);\n", - !force_leaf ? "lseq" : "NULL"); - fprintf_indent (f, indent, - "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", depth, - !force_leaf ? "lseq" : "NULL"); - fprintf_indent (f, indent, - "if (!_r%d) goto %s;\n", - depth, fail_label); - if (*opr == CONVERT_EXPR) + else if (in_place) { - indent -= 4; - fprintf_indent (f, indent, " }\n"); - fprintf_indent (f, indent, "else\n"); - fprintf_indent (f, indent, " _r%d = _o%d[0];\n", depth, depth); + gcc_assert (!child_in_place); + fprintf_indent (f, indent, + "%s.set_op (%s, %s, %d);\n", in_place, + opr_name, type, ops.length ()); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf_indent (f, indent, + "%s.ops[%u] = _o%d[%u];\n", in_place, i, depth, i); + fprintf_indent (f, indent, + "%s.resimplify (%s, valueize);\n", + in_place, !force_leaf ? "lseq" : "NULL"); + indent -= 2; + fprintf_indent (f, indent, "}\n"); + return; + } + else + { + if (possible_noop_convert (opr)) + { + fprintf_indent (f, indent, + "if (%s != TREE_TYPE (_o%d[0]) /* XXX */\n", + type, depth); + fprintf_indent (f, indent, + " && !useless_type_conversion_p (%s, TREE_TYPE " + "(_o%d[0])))\n", + type, depth); + fprintf_indent (f, indent + 2, "{\n"); + indent += 4; + } + /* ??? Building a stmt can fail for various reasons here, seq being + NULL or the stmt referencing SSA names occuring in abnormal PHIs. + So if we fail here we should continue matching other patterns. */ + fprintf_indent (f, indent, "gimple_match_op tem_op " + "(res_op->cond.any_else (), %s, %s", opr_name, type); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf (f, ", _o%d[%u]", depth, i); + fprintf (f, ");\n"); + fprintf_indent (f, indent, "tem_op.resimplify (%s, valueize);\n", + !force_leaf ? "lseq" : "NULL"); + fprintf_indent (f, indent, + "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", + depth, !force_leaf ? "lseq" : "NULL"); + fprintf_indent (f, indent, + "if (!_r%d) goto %s;\n", + depth, fail_label); + if (possible_noop_convert (opr)) + { + indent -= 4; + fprintf_indent (f, indent, " }\n"); + fprintf_indent (f, indent, "else\n"); + fprintf_indent (f, indent, " _r%d = _o%d[0];\n", depth, depth); + } } } else { - if (*opr == CONVERT_EXPR) + if (possible_noop_convert (opr)) { fprintf_indent (f, indent, "if (TREE_TYPE (_o%d[0]) != %s)\n", depth, type); @@ -3397,7 +3469,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, fprintf_indent (f, indent, "if (EXPR_P (_r%d))\n", depth); fprintf_indent (f, indent, " goto %s;\n", fail_label); } - if (*opr == CONVERT_EXPR) + if (possible_noop_convert (opr)) { fprintf_indent (f, indent - 2, "}\n"); indent -= 4; @@ -3417,8 +3489,10 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, void c_expr::gen_transform (FILE *f, int indent, const char *dest, bool, int, const char *, capture_info *, - dt_operand **, int) + dt_operand **, int, const char *in_place) { + gcc_assert (!in_place); + if (dest && nr_stmts == 1) fprintf_indent (f, indent, "%s = ", dest); @@ -3501,8 +3575,11 @@ c_expr::gen_transform (FILE *f, int indent, const char *dest, void capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, - dt_operand **indexes, int cond_handling) + dt_operand **indexes, int cond_handling, + const char *in_place) { + gcc_assert (!in_place); + if (what && is_a<expr *> (what)) { if (indexes[where] == 0) @@ -4353,7 +4430,8 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) if (s->kind == simplify::SIMPLIFY) { - fprintf_indent (f, indent, "if (UNLIKELY (!dbg_cnt (match))) goto %s;\n", fail_label); + fprintf_indent (f, indent, "if (UNLIKELY (!dbg_cnt (match))) goto %s;\n", + fail_label); needs_label = true; } @@ -4408,16 +4486,45 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) if (!is_predicate) cond_handling = (*opr == COND_EXPR && j == 0) ? 1 : 2; e->ops[j]->gen_transform (f, indent, dest, true, 1, optype, - &cinfo, indexes, cond_handling); + &cinfo, indexes, cond_handling, + (possible_noop_convert (opr) + && is_a <expr *> (e->ops[j])) + ? "(*res_op)" : NULL); } /* Re-fold the toplevel result. It's basically an embedded gimple_build w/o actually building the stmt. */ if (!is_predicate) { - fprintf_indent (f, indent, - "res_op->resimplify (%s, valueize);\n", - !e->force_leaf ? "lseq" : "NULL"); + if (possible_noop_convert (opr) + && is_a <expr *> (e->ops[0])) + { + fprintf_indent (f, indent, + "if (type != res_op->type\n"); + fprintf_indent (f, indent, + " && !useless_type_conversion_p (type, res_op->type))\n"); + fprintf_indent (f, indent, + " {\n"); + indent += 4; + fprintf_indent (f, indent, + "if (!(res_op->ops[0] = maybe_push_res_to_seq (res_op, %s))) goto %s;\n", + !as_a <expr *> (e->ops[0])->force_leaf + ? "lseq" : "NULL", fail_label); + needs_label = true; + fprintf_indent (f, indent, + "res_op->set_op (%s, type, 1);\n", + *opr == CONVERT_EXPR ? "NOP_EXPR" : opr->id); + fprintf_indent (f, indent, + "res_op->resimplify (%s, valueize);\n", + !e->force_leaf ? "lseq" : "NULL"); + indent -= 4; + fprintf_indent (f, indent, + " }\n"); + } + else + fprintf_indent (f, indent, + "res_op->resimplify (%s, valueize);\n", + !e->force_leaf ? "lseq" : "NULL"); if (e->force_leaf) { fprintf_indent (f, indent, diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 818b801..ecf0331 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -1861,7 +1861,7 @@ ranger_cache::apply_inferred_ranges (gimple *s) bool update = true; basic_block bb = gimple_bb (s); - gimple_infer_range infer(s); + gimple_infer_range infer(s, this); if (infer.num () == 0) return; diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 3bb24d5..aed5c7d 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -759,15 +759,17 @@ fold_using_range::range_of_range_op (vrange &r, } if (gimple_range_ssa_p (op1)) { - rel = handler.lhs_op1_relation (r, range1, range2, rel); - if (rel != VREL_VARYING) - src.register_relation (s, rel, lhs, op1); + relation_kind rel2 = handler.lhs_op1_relation (r, range1, + range2, rel); + if (rel2 != VREL_VARYING) + src.register_relation (s, rel2, lhs, op1); } if (gimple_range_ssa_p (op2)) { - rel = handler.lhs_op2_relation (r, range1, range2, rel); - if (rel != VREL_VARYING) - src.register_relation (s, rel, lhs, op2); + relation_kind rel2 = handler.lhs_op2_relation (r, range1, + range2, rel); + if (rel2 != VREL_VARYING) + src.register_relation (s, rel2, lhs, op2); } } // Check for an existing BB, as we maybe asked to fold an diff --git a/gcc/gimple.h b/gcc/gimple.h index 7e3086f..032365f 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -3561,7 +3561,7 @@ gimple_call_set_nothrow (gcall *s, bool nothrow_p) /* Return true if S is a nothrow call. */ inline bool -gimple_call_nothrow_p (gcall *s) +gimple_call_nothrow_p (const gcall *s) { return (gimple_call_flags (s) & ECF_NOTHROW) != 0; } diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc index 2885975..8c4fb3c 100644 --- a/gcc/ipa-free-lang-data.cc +++ b/gcc/ipa-free-lang-data.cc @@ -150,7 +150,12 @@ fld_type_variant (tree first, tree t, class free_lang_data_d *fld, return t; for (tree v = first; v; v = TYPE_NEXT_VARIANT (v)) if (fld_type_variant_equal_p (t, v, inner_type)) - return v; + { + if (flag_checking) + for (tree v2 = TYPE_NEXT_VARIANT (v); v2; v2 = TYPE_NEXT_VARIANT (v2)) + gcc_assert (!fld_type_variant_equal_p (t, v2, inner_type)); + return v; + } tree v = build_variant_type_copy (first); TYPE_READONLY (v) = TYPE_READONLY (t); TYPE_VOLATILE (v) = TYPE_VOLATILE (t); diff --git a/gcc/ipa-inline-transform.cc b/gcc/ipa-inline-transform.cc index d2c9a2d..e00887b 100644 --- a/gcc/ipa-inline-transform.cc +++ b/gcc/ipa-inline-transform.cc @@ -438,8 +438,8 @@ inline_call (struct cgraph_edge *e, bool update_original, != opt_for_fn (to->decl, flag_finite_math_only) || opt_for_fn (callee->decl, flag_signaling_nans) != opt_for_fn (to->decl, flag_signaling_nans) - || opt_for_fn (callee->decl, flag_cx_limited_range) - != opt_for_fn (to->decl, flag_cx_limited_range) + || opt_for_fn (callee->decl, flag_complex_method) + != opt_for_fn (to->decl, flag_complex_method) || opt_for_fn (callee->decl, flag_signed_zeros) != opt_for_fn (to->decl, flag_signed_zeros) || opt_for_fn (callee->decl, flag_associative_math) @@ -465,8 +465,8 @@ inline_call (struct cgraph_edge *e, bool update_original, = opt_for_fn (callee->decl, flag_finite_math_only); opts.x_flag_signaling_nans = opt_for_fn (callee->decl, flag_signaling_nans); - opts.x_flag_cx_limited_range - = opt_for_fn (callee->decl, flag_cx_limited_range); + opts.x_flag_complex_method + = opt_for_fn (callee->decl, flag_complex_method); opts.x_flag_signed_zeros = opt_for_fn (callee->decl, flag_signed_zeros); opts.x_flag_associative_math diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc index d9fc111..7c2feee 100644 --- a/gcc/ipa-inline.cc +++ b/gcc/ipa-inline.cc @@ -587,7 +587,7 @@ can_inline_edge_by_limits_p (struct cgraph_edge *e, int flags) || check_maybe_down (flag_unsafe_math_optimizations) || check_maybe_down (flag_finite_math_only) || check_maybe_up (flag_signaling_nans) - || check_maybe_down (flag_cx_limited_range) + || check_maybe_up (flag_complex_method) || check_maybe_up (flag_signed_zeros) || check_maybe_down (flag_associative_math) || check_maybe_down (flag_reciprocal_math) diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index f0b70c2..adee3de 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,8 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * dummy-frontend.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + 2025-03-29 Iain Sandoe <iain@sandoe.co.uk> * libgccjit.exports: Add symbols for ABI 28 to 34. diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 88784ec..bf31a9d 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -33,7 +33,6 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "target.h" #include "diagnostic-format-text.h" -#include "make-unique.h" #include "print-tree.h" #include <mpfr.h> @@ -1085,8 +1084,9 @@ jit_langhook_init (void) diagnostic_text_starter (global_dc) = jit_begin_diagnostic; diagnostic_text_finalizer (global_dc) = jit_end_diagnostic; auto sink - = ::make_unique<jit_diagnostic_listener> (*global_dc, - *gcc::jit::active_playback_ctxt); + = std::make_unique<jit_diagnostic_listener> + (*global_dc, + *gcc::jit::active_playback_ctxt); global_dc->set_output_format (std::move (sink)); build_common_tree_nodes (flag_signed_char); diff --git a/gcc/json-parsing.cc b/gcc/json-parsing.cc index 0b9715c..fc78500 100644 --- a/gcc/json-parsing.cc +++ b/gcc/json-parsing.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "json-parsing.h" #include "pretty-print.h" #include "math.h" -#include "make-unique.h" #include "selftest.h" using namespace json; @@ -1037,7 +1036,7 @@ lexer::make_error (const char *msg) location_map::range r; r.m_start = p; r.m_end = p; - return ::make_unique<error> (r, xstrdup (msg)); + return std::make_unique<error> (r, xstrdup (msg)); } /* parser's ctor. */ @@ -1092,7 +1091,7 @@ parser::parse_value (int depth) case TOK_STRING: { - auto val = ::make_unique<string> (tok->u.string); + auto val = std::make_unique<string> (tok->u.string); m_lexer.consume (); maybe_record_range (val.get (), tok->range); return parser_result_t (std::move (val)); @@ -1103,7 +1102,7 @@ parser::parse_value (int depth) case TOK_FLOAT_NUMBER: { - auto val = ::make_unique<float_number> (tok->u.float_number); + auto val = std::make_unique<float_number> (tok->u.float_number); m_lexer.consume (); maybe_record_range (val.get (), tok->range); return parser_result_t (std::move (val)); @@ -1111,7 +1110,7 @@ parser::parse_value (int depth) case TOK_INTEGER_NUMBER: { - auto val = ::make_unique<integer_number> (tok->u.integer_number); + auto val = std::make_unique<integer_number> (tok->u.integer_number); m_lexer.consume (); maybe_record_range (val.get (), tok->range); return parser_result_t (std::move (val)); @@ -1119,7 +1118,7 @@ parser::parse_value (int depth) case TOK_TRUE: { - auto val = ::make_unique<literal> (JSON_TRUE); + auto val = std::make_unique<literal> (JSON_TRUE); m_lexer.consume (); maybe_record_range (val.get (), tok->range); return parser_result_t (std::move (val)); @@ -1127,7 +1126,7 @@ parser::parse_value (int depth) case TOK_FALSE: { - auto val = ::make_unique<literal> (JSON_FALSE); + auto val = std::make_unique<literal> (JSON_FALSE); m_lexer.consume (); maybe_record_range (val.get (), tok->range); return parser_result_t (std::move (val)); @@ -1135,7 +1134,7 @@ parser::parse_value (int depth) case TOK_NULL: { - auto val = ::make_unique<literal> (JSON_NULL); + auto val = std::make_unique<literal> (JSON_NULL); m_lexer.consume (); maybe_record_range (val.get (), tok->range); return parser_result_t (std::move (val)); @@ -1160,7 +1159,7 @@ parser::parse_object (int depth) require (TOK_OPEN_CURLY); - auto obj = ::make_unique<object> (); + auto obj = std::make_unique<object> (); const token *tok = m_lexer.peek (); if (tok->id == TOK_CLOSE_CURLY) @@ -1223,7 +1222,7 @@ parser::parse_array (int depth) if (auto err = require (TOK_OPEN_SQUARE)) return parser_result_t (std::move (err)); - auto arr = ::make_unique<array> (); + auto arr = std::make_unique<array> (); const token *tok = m_lexer.peek (); if (tok->id == TOK_CLOSE_SQUARE) @@ -1340,7 +1339,7 @@ parser::error_at (const location_map::range &r, const char *fmt, ...) char *formatted_msg = xvasprintf (fmt, ap); va_end (ap); - return ::make_unique<error> (r, formatted_msg); + return std::make_unique<error> (r, formatted_msg); } /* Record that JV has range R within the input file. */ diff --git a/gcc/json.cc b/gcc/json.cc index 4cf962f..e66a7ae 100644 --- a/gcc/json.cc +++ b/gcc/json.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "json.h" #include "pretty-print.h" #include "math.h" -#include "make-unique.h" #include "selftest.h" using namespace json; @@ -510,7 +509,7 @@ test_formatting () { object obj; object *child = new object; - std::unique_ptr<object> grandchild = ::make_unique<object> (); + std::unique_ptr<object> grandchild = std::make_unique<object> (); obj.set_string ("str", "bar"); obj.set ("child", child); @@ -518,7 +517,7 @@ test_formatting () array *arr = new array; for (int i = 0; i < 3; i++) - arr->append (::make_unique<integer_number> (i)); + arr->append (std::make_unique<integer_number> (i)); grandchild->set ("arr", arr); grandchild->set_integer ("int", 1066); diff --git a/gcc/lazy-diagnostic-path.cc b/gcc/lazy-diagnostic-path.cc index ba62097..1474f70 100644 --- a/gcc/lazy-diagnostic-path.cc +++ b/gcc/lazy-diagnostic-path.cc @@ -28,7 +28,6 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "diagnostic.h" #include "lazy-diagnostic-path.h" -#include "make-unique.h" #include "selftest.h" #include "selftest-diagnostic.h" #include "simple-diagnostic-path.h" @@ -100,7 +99,7 @@ public: tree fntype_void_void = build_function_type_array (void_type_node, 0, NULL); tree fndecl_foo = build_fn_decl ("foo", fntype_void_void); - auto path = ::make_unique<simple_diagnostic_path> (&m_pp); + auto path = std::make_unique<simple_diagnostic_path> (&m_pp); path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free"); path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free"); return path; @@ -167,7 +166,7 @@ test_emission (pretty_printer *event_pp) is skipped. */ { test_diagnostic_context dc; - dc.set_option_manager (::make_unique<all_warnings_disabled> (), 0); + dc.set_option_manager (std::make_unique<all_warnings_disabled> (), 0); test_rich_location rich_loc (*event_pp); ASSERT_FALSE (rich_loc.m_path.generated_p ()); diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc index d274283..49524cc 100644 --- a/gcc/libgdiagnostics.cc +++ b/gcc/libgdiagnostics.cc @@ -33,7 +33,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-format-text.h" #include "logical-location.h" #include "edit-context.h" -#include "make-unique.h" #include "libgdiagnostics.h" class owned_nullable_string @@ -298,7 +297,7 @@ public: sarif_sink (diagnostic_manager &mgr, FILE *dst_stream, const diagnostic_file *main_input_file, - enum sarif_version version); + const sarif_generation_options &sarif_gen_opts); }; /* Helper for the linemap code. */ @@ -398,11 +397,11 @@ public: m_dc.m_client_aux_data = this; m_dc.set_client_data_hooks - (::make_unique<impl_diagnostic_client_data_hooks> (*this)); + (std::make_unique<impl_diagnostic_client_data_hooks> (*this)); diagnostic_text_starter (&m_dc) = diagnostic_text_sink::text_starter; - m_edit_context = ::make_unique <edit_context> (m_dc.get_file_cache ()); + m_edit_context = std::make_unique <edit_context> (m_dc.get_file_cache ()); } ~diagnostic_manager () @@ -503,11 +502,11 @@ public: return (*iter).second.get (); std::unique_ptr<diagnostic_logical_location> logical_loc - = ::make_unique<diagnostic_logical_location> (kind, - parent, - short_name, - fully_qualified_name, - decorated_name); + = std::make_unique<diagnostic_logical_location> (kind, + parent, + short_name, + fully_qualified_name, + decorated_name); const diagnostic_logical_location *result = logical_loc.get (); m_logical_locs.insert (logical_locs_map_t::value_type (std::move (key), @@ -785,11 +784,12 @@ struct diagnostic_execution_path : public diagnostic_path const char *gmsgid, va_list *args) { - m_events.push_back (::make_unique<libgdiagnostics_path_event> (physical_loc, - logical_loc, - stack_depth, - gmsgid, - args)); + m_events.push_back + (std::make_unique<libgdiagnostics_path_event> (physical_loc, + logical_loc, + stack_depth, + gmsgid, + args)); return m_events.size () - 1; } @@ -860,7 +860,7 @@ public: void add_rule (const char *title, const char *url) { - std::unique_ptr<impl_rule> rule = ::make_unique<impl_rule> (title, url); + std::unique_ptr<impl_rule> rule = std::make_unique<impl_rule> (title, url); m_metadata.add_rule (*rule.get ()); m_rules.push_back (std::move (rule)); } @@ -882,7 +882,7 @@ public: const char *text) { std::unique_ptr<range_label> label - = ::make_unique <impl_range_label> (text); + = std::make_unique <impl_range_label> (text); m_rich_loc.add_range (as_location_t (loc), SHOW_RANGE_WITHOUT_CARET, label.get ()); @@ -902,7 +902,7 @@ public: diagnostic_execution_path * add_execution_path () { - m_path = ::make_unique<diagnostic_execution_path> (); + m_path = std::make_unique<diagnostic_execution_path> (); m_rich_loc.set_path (m_path.get ()); return m_path.get (); } @@ -946,7 +946,7 @@ diagnostic_t_from_diagnostic_level (enum diagnostic_level level) void diagnostic_file::set_buffered_content (const char *buf, size_t sz) { - m_content = ::make_unique<content_buffer> (buf, sz); + m_content = std::make_unique<content_buffer> (buf, sz); // Populate file_cache: file_cache &fc = m_mgr.get_dc ().get_file_cache (); @@ -1004,8 +1004,8 @@ diagnostic_text_sink::diagnostic_text_sink (diagnostic_manager &mgr, m_source_printing (mgr.get_dc ().m_source_printing) { auto inner_sink - = ::make_unique<diagnostic_text_output_format> (mgr.get_dc (), - &m_source_printing); + = std::make_unique<diagnostic_text_output_format> (mgr.get_dc (), + &m_source_printing); inner_sink->get_printer ()->set_output_stream (dst_stream); m_inner_sink = inner_sink.get (); set_colorize (colorize); @@ -1071,7 +1071,7 @@ diagnostic_text_sink::text_starter (diagnostic_text_output_format &text_output, sarif_sink::sarif_sink (diagnostic_manager &mgr, FILE *dst_stream, const diagnostic_file *main_input_file, - enum sarif_version version) + const sarif_generation_options &sarif_gen_opts) : sink (mgr) { diagnostic_output_file output_file (dst_stream, false, @@ -1079,7 +1079,8 @@ sarif_sink::sarif_sink (diagnostic_manager &mgr, auto inner_sink = make_sarif_sink (mgr.get_dc (), *mgr.get_line_table (), main_input_file->get_name (), - version, + true, + sarif_gen_opts, std::move (output_file)); mgr.get_dc ().add_sink (std::move (inner_sink)); } @@ -1271,7 +1272,7 @@ diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr, FAIL_IF_NULL (dst_stream); FAIL_IF_NULL (main_input_file); - enum sarif_version internal_version; + sarif_generation_options sarif_gen_opts; switch (version) { default: @@ -1279,17 +1280,17 @@ diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr, __func__, (int)version); abort (); case DIAGNOSTIC_SARIF_VERSION_2_1_0: - internal_version = sarif_version::v2_1_0; + sarif_gen_opts.m_version = sarif_version::v2_1_0; break; case DIAGNOSTIC_SARIF_VERSION_2_2_PRERELEASE: - internal_version = sarif_version::v2_2_prerelease_2024_08_08; + sarif_gen_opts.m_version = sarif_version::v2_2_prerelease_2024_08_08; break; } - diag_mgr->add_sink (make_unique<sarif_sink> (*diag_mgr, - dst_stream, - main_input_file, - internal_version)); + diag_mgr->add_sink (std::make_unique<sarif_sink> (*diag_mgr, + dst_stream, + main_input_file, + sarif_gen_opts)); } /* Public entrypoint. */ diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc index ce42bda..f5f1f20 100644 --- a/gcc/libsarifreplay.cc +++ b/gcc/libsarifreplay.cc @@ -25,7 +25,6 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_STRING #include "system.h" #include "coretypes.h" -#include "make-unique.h" #include "libgdiagnostics++.h" #include "json-parsing.h" #include "intl.h" @@ -51,7 +50,7 @@ read_file (const char *path, libgdiagnostics::manager &mgr) } /* Read content, allocating a buffer for it. */ - auto result = ::make_unique<std::vector<char>> (); + auto result = std::make_unique<std::vector<char>> (); char buf[4096]; size_t iter_sz_in; @@ -1350,7 +1349,7 @@ maybe_consume_embedded_link (const char *&iter_src) } iter_src = iter; - return ::make_unique<embedded_link> (std::move (result)); + return std::make_unique<embedded_link> (std::move (result)); } /* Lookup the plain text string within a result.message (§3.27.11), diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc index a980b20..27405e8 100644 --- a/gcc/lto-wrapper.cc +++ b/gcc/lto-wrapper.cc @@ -55,7 +55,6 @@ along with GCC; see the file COPYING3. If not see #include "opts-diagnostic.h" #include "opt-suggestions.h" #include "opts-jobserver.h" -#include "make-unique.h" #include "lto-ltrans-cache.h" /* Environment variable, used for passing the names of offload targets from GCC diff --git a/gcc/make-unique.h b/gcc/make-unique.h deleted file mode 100644 index 6f5aeee..0000000 --- a/gcc/make-unique.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Minimal implementation of make_unique for C++11 compatibility. - Copyright (C) 2022-2025 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef GCC_MAKE_UNIQUE -#define GCC_MAKE_UNIQUE - -#include <type_traits> - -/* Minimal implementation of make_unique for C++11 compatibility - (std::make_unique is C++14). */ - -template<typename T, typename... Args> -inline typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type -make_unique(Args&&... args) -{ - return std::unique_ptr<T> (new T (std::forward<Args> (args)...)); -} - -#endif /* ! GCC_MAKE_UNIQUE */ diff --git a/gcc/match.pd b/gcc/match.pd index 0fe90a6e..a150de5 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5701,11 +5701,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (part (convert?:s@2 (op:s @0 @1))) (convert (op (part @0) (part @1)))))) (simplify - (realpart (convert?:s (CEXPI:s @0))) - (convert (COS @0))) + (realpart (convert?@2 (CEXPI@1 @0))) + (if (single_use (@1) && single_use (@2)) + (convert (COS @0)))) (simplify - (imagpart (convert?:s (CEXPI:s @0))) - (convert (SIN @0))) + (imagpart (convert?@2 (CEXPI@1 @0))) + (if (single_use (@1) && single_use (@2)) + (convert (SIN @0)))) /* conj(conj(x)) -> x */ (simplify diff --git a/gcc/opts-diagnostic.cc b/gcc/opts-diagnostic.cc index cab7925..b51c8a8 100644 --- a/gcc/opts-diagnostic.cc +++ b/gcc/opts-diagnostic.cc @@ -39,7 +39,6 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print-markup.h" #include "opts.h" #include "options.h" -#include "make-unique.h" /* A namespace for handling the DSL of the arguments of -fdiagnostics-add-output= and -fdiagnostics-set-output=. */ @@ -308,7 +307,7 @@ parse (const context &ctxt, const char *unparsed_arg) } else result.m_scheme_name = unparsed_arg; - return ::make_unique<scheme_name_and_params> (std::move (result)); + return std::make_unique<scheme_name_and_params> (std::move (result)); } /* class output_factory::scheme_handler. */ @@ -317,8 +316,8 @@ parse (const context &ctxt, const char *unparsed_arg) output_factory::output_factory () { - m_scheme_handlers.push_back (::make_unique<text_scheme_handler> ()); - m_scheme_handlers.push_back (::make_unique<sarif_scheme_handler> ()); + m_scheme_handlers.push_back (std::make_unique<text_scheme_handler> ()); + m_scheme_handlers.push_back (std::make_unique<sarif_scheme_handler> ()); } const output_factory::scheme_handler * @@ -405,7 +404,7 @@ text_scheme_handler::make_sink (const context &ctxt, return nullptr; } - auto sink = ::make_unique<diagnostic_text_output_format> (ctxt.m_dc); + auto sink = std::make_unique<diagnostic_text_output_format> (ctxt.m_dc); sink->set_show_nesting (show_nesting); sink->set_show_locations_in_nesting (show_locations_in_nesting); sink->set_show_nesting_levels (show_levels); @@ -485,10 +484,14 @@ sarif_scheme_handler::make_sink (const context &ctxt, if (!output_file) return nullptr; + sarif_generation_options sarif_gen_opts; + sarif_gen_opts.m_version = version; + auto sink = make_sarif_sink (ctxt.m_dc, *line_table, ctxt.m_opts.x_main_input_filename, - version, + true, + sarif_gen_opts, std::move (output_file)); return sink; } diff --git a/gcc/opts.cc b/gcc/opts.cc index ffcbdfe..a9b9b91 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1384,16 +1384,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, || opts->x_flag_peel_loops || opts->x_optimize >= 3); - /* With -fcx-limited-range, we do cheap and quick complex arithmetic. */ - if (opts->x_flag_cx_limited_range) - opts->x_flag_complex_method = 0; - else if (opts_set->x_flag_cx_limited_range) - opts->x_flag_complex_method = opts->x_flag_default_complex_method; - - /* With -fcx-fortran-rules, we do something in-between cheap and C99. */ - if (opts->x_flag_cx_fortran_rules) - opts->x_flag_complex_method = 1; - else if (opts_set->x_flag_cx_fortran_rules) + /* Use a frontend provided default for the complex eval method. */ + if (!opts_set->x_flag_complex_method) opts->x_flag_complex_method = opts->x_flag_default_complex_method; /* Use -fvect-cost-model=cheap instead of -fvect-cost-mode=very-cheap @@ -3465,8 +3457,8 @@ set_fast_math_flags (struct gcc_options *opts, int set) opts->x_flag_signaling_nans = 0; if (!opts->frontend_set_flag_rounding_math) opts->x_flag_rounding_math = 0; - if (!opts->frontend_set_flag_cx_limited_range) - opts->x_flag_cx_limited_range = 1; + if (!opts->frontend_set_flag_complex_method) + opts->x_flag_complex_method = 0; } } @@ -3636,7 +3628,7 @@ setup_core_dumping (diagnostic_context *dc) "setting core file size limit to maximum: %m"); } #endif - diagnostic_abort_on_error (dc); + dc->set_abort_on_error (true); } /* Parse a -d<ARG> command line switch for OPTS, location LOC, diff --git a/gcc/params.opt b/gcc/params.opt index ef19051..1f0abec 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -1253,10 +1253,6 @@ The maximum factor which the loop vectorizer applies to the cost of statements i Common Joined UInteger Var(param_vect_induction_float) Init(1) IntegerRange(0, 1) Param Optimization Enable loop vectorization of floating point inductions. --param=vect-force-slp= -Common Joined UInteger Var(param_vect_force_slp) Init(1) IntegerRange(0, 1) Param Optimization -Force the use of SLP when vectorizing, fail if not possible. - -param=vrp-block-limit= Common Joined UInteger Var(param_vrp_block_limit) Init(150000) Optimization Param Maximum number of basic blocks before VRP switches to a fast model with less memory requirements. diff --git a/gcc/pass_manager.h b/gcc/pass_manager.h index 5fb7b09..d4f8900 100644 --- a/gcc/pass_manager.h +++ b/gcc/pass_manager.h @@ -67,13 +67,13 @@ public: /* Various passes are manually cloned by avr and epiphany. */ opt_pass *get_pass_split_all_insns () const { - return pass_split_all_insns_1; + return m_pass_split_all_insns_1; } opt_pass *get_pass_mode_switching () const { - return pass_mode_switching_1; + return m_pass_mode_switching_1; } - opt_pass *get_pass_peephole2 () const { return pass_peephole2_1; } - opt_pass *get_pass_profile () const { return pass_profile_1; } + opt_pass *get_pass_peephole2 () const { return m_pass_peephole2_1; } + opt_pass *get_pass_profile () const { return m_pass_profile_1; } void register_pass_name (opt_pass *pass, const char *name); @@ -81,9 +81,9 @@ public: opt_pass *get_rest_of_compilation () const { - return pass_rest_of_compilation_1; + return m_pass_rest_of_compilation_1; } - opt_pass *get_clean_slate () const { return pass_clean_state_1; } + opt_pass *get_clean_slate () const { return m_pass_clean_state_1; } public: /* The root of the compilation pass tree, once constructed. */ @@ -114,21 +114,21 @@ private: For example: NEXT_PASS (pass_build_cfg, 1); within pass-instances.def means that there is a field: - opt_pass *pass_build_cfg_1; + opt_pass *m_pass_build_cfg_1; Similarly, the various: NEXT_PASS (pass_copy_prop, 1); ... NEXT_PASS (pass_copy_prop, 8); in pass-instances.def lead to fields: - opt_pass *pass_copy_prop_1; + opt_pass *m_pass_copy_prop_1; ... - opt_pass *pass_copy_prop_8; */ + opt_pass *m_pass_copy_prop_8; */ #define INSERT_PASSES_AFTER(PASS) #define PUSH_INSERT_PASSES_WITHIN(PASS, NUM) #define POP_INSERT_PASSES() -#define NEXT_PASS(PASS, NUM) opt_pass *PASS ## _ ## NUM +#define NEXT_PASS(PASS, NUM) opt_pass *m_ ## PASS ## _ ## NUM #define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) NEXT_PASS (PASS, NUM) #define NEXT_PASS_WITH_ARGS(PASS, NUM, ...) NEXT_PASS (PASS, NUM) #define TERMINATE_PASS_LIST(PASS) diff --git a/gcc/passes.cc b/gcc/passes.cc index 3c28db7..0482de0 100644 --- a/gcc/passes.cc +++ b/gcc/passes.cc @@ -116,14 +116,14 @@ opt_pass::opt_pass (const pass_data &data, context *ctxt) void pass_manager::execute_early_local_passes () { - execute_pass_list (cfun, pass_build_ssa_passes_1->sub); - execute_pass_list (cfun, pass_local_optimization_passes_1->sub); + execute_pass_list (cfun, m_pass_build_ssa_passes_1->sub); + execute_pass_list (cfun, m_pass_local_optimization_passes_1->sub); } unsigned int pass_manager::execute_pass_mode_switching () { - return pass_mode_switching_1->execute (cfun); + return m_pass_mode_switching_1->execute (cfun); } @@ -355,9 +355,9 @@ finish_optimization_passes (void) if (coverage_instrumentation_p () || flag_test_coverage || flag_branch_probabilities) { - dumps->dump_start (pass_profile_1->static_pass_number, NULL); + dumps->dump_start (m_pass_profile_1->static_pass_number, NULL); end_branch_prob (); - dumps->dump_finish (pass_profile_1->static_pass_number); + dumps->dump_finish (m_pass_profile_1->static_pass_number); } /* Do whatever is necessary to finish printing the graphs. */ @@ -1587,7 +1587,7 @@ pass_manager::pass_manager (context *ctxt) #define INSERT_PASSES_AFTER(PASS) #define PUSH_INSERT_PASSES_WITHIN(PASS, NUM) #define POP_INSERT_PASSES() -#define NEXT_PASS(PASS, NUM) PASS ## _ ## NUM = NULL +#define NEXT_PASS(PASS, NUM) m_ ## PASS ## _ ## NUM = NULL #define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) NEXT_PASS (PASS, NUM) #define NEXT_PASS_WITH_ARGS(PASS, NUM, ...) NEXT_PASS (PASS, NUM) #define TERMINATE_PASS_LIST(PASS) @@ -1612,28 +1612,28 @@ pass_manager::pass_manager (context *ctxt) #define PUSH_INSERT_PASSES_WITHIN(PASS, NUM) \ { \ - opt_pass **p = &(PASS ## _ ## NUM)->sub; + opt_pass **p = &(m_ ## PASS ## _ ## NUM)->sub; #define POP_INSERT_PASSES() \ } #define NEXT_PASS(PASS, NUM) \ do { \ - gcc_assert (PASS ## _ ## NUM == NULL); \ + gcc_assert (m_ ## PASS ## _ ## NUM == NULL); \ if ((NUM) == 1) \ - PASS ## _1 = make_##PASS (m_ctxt); \ + m_ ## PASS ## _1 = make_##PASS (m_ctxt); \ else \ { \ - gcc_assert (PASS ## _1); \ - PASS ## _ ## NUM = PASS ## _1->clone (); \ + gcc_assert (m_ ## PASS ## _1); \ + m_ ## PASS ## _ ## NUM = m_ ## PASS ## _1->clone (); \ } \ - p = next_pass_1 (p, PASS ## _ ## NUM, PASS ## _1); \ + p = next_pass_1 (p, m_ ## PASS ## _ ## NUM, m_ ## PASS ## _1); \ } while (0) #define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) \ do { \ NEXT_PASS (PASS, NUM); \ - PASS ## _ ## NUM->set_pass_param (0, ARG); \ + m_ ## PASS ## _ ## NUM->set_pass_param (0, ARG); \ } while (0) #define NEXT_PASS_WITH_ARGS(PASS, NUM, ...) \ @@ -1643,7 +1643,7 @@ pass_manager::pass_manager (context *ctxt) unsigned i = 0; \ for (bool value : values) \ { \ - PASS ## _ ## NUM->set_pass_param (i, value); \ + m_ ## PASS ## _ ## NUM->set_pass_param (i, value); \ i++; \ } \ } while (0) @@ -2020,7 +2020,7 @@ pass_manager::dump_profile_report () const fprintf (dump_file, " "); /* Size/time units change across gimple and RTL. */ - if (i == pass_expand_1->static_pass_number) + if (i == m_pass_expand_1->static_pass_number) fprintf (dump_file, "|-------------------|--------------------------"); else @@ -2032,8 +2032,8 @@ pass_manager::dump_profile_report () const fprintf (dump_file, " "); fprintf (dump_file, "| %12.0f", profile_record[i].time); /* Time units changes with profile estimate and feedback. */ - if (i == pass_profile_1->static_pass_number - || i == pass_ipa_tree_profile_1->static_pass_number) + if (i == m_pass_profile_1->static_pass_number + || i == m_pass_ipa_tree_profile_1->static_pass_number) fprintf (dump_file, "-------------"); else if (rel_time_change) fprintf (dump_file, " %+11.1f%%", rel_time_change); diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc index abd6c0b..1f38702 100644 --- a/gcc/pretty-print.cc +++ b/gcc/pretty-print.cc @@ -30,7 +30,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-color.h" #include "diagnostic-event-id.h" #include "diagnostic-highlight-colors.h" -#include "make-unique.h" #include "selftest.h" #if HAVE_ICONV @@ -2521,7 +2520,7 @@ pretty_printer::~pretty_printer () std::unique_ptr<pretty_printer> pretty_printer::clone () const { - return ::make_unique<pretty_printer> (*this); + return std::make_unique<pretty_printer> (*this); } /* Append a string delimited by START and END to the output area of @@ -3542,7 +3541,7 @@ test_custom_tokens_1 () void add_to_phase_2 (pp_markup::context &ctxt) final override { - auto val_ptr = make_unique<value> (*this); + auto val_ptr = std::make_unique<value> (*this); ctxt.m_formatted_token_list->push_back<pp_token_custom_data> (std::move (val_ptr)); } @@ -3622,7 +3621,7 @@ test_custom_tokens_2 () void add_to_phase_2 (pp_markup::context &ctxt) final override { - auto val_ptr = make_unique<value> (*this); + auto val_ptr = std::make_unique<value> (*this); ctxt.m_formatted_token_list->push_back<pp_token_custom_data> (std::move (val_ptr)); } diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index dd51c2e..36e9dfc 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -218,6 +218,15 @@ range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED, return VREL_VARYING; } +relation_kind +range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED, + const prange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return VREL_VARYING; +} + void range_operator::update_bitmask (irange &, const prange &, @@ -293,6 +302,7 @@ class pointer_plus_operator : public range_operator using range_operator::update_bitmask; using range_operator::fold_range; using range_operator::op2_range; + using range_operator::lhs_op1_relation; public: virtual bool fold_range (prange &r, tree type, const prange &op1, @@ -302,6 +312,10 @@ public: const prange &lhs, const prange &op1, relation_trio = TRIO_VARYING) const final override; + virtual relation_kind lhs_op1_relation (const prange &lhs, + const prange &op1, + const irange &op2, + relation_kind) const; void update_bitmask (prange &r, const prange &lh, const irange &rh) const { update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); } } op_pointer_plus; @@ -379,6 +393,51 @@ pointer_plus_operator::op2_range (irange &r, tree type, return true; } +// Return the relation between the LHS and OP1 based on the value of the +// operand being added. Pointer_plus is define to have a size_type for +// operand 2 which can be interpreted as negative, so always used SIGNED. +// Any overflow is considered UB and thus ignored. + +relation_kind +pointer_plus_operator::lhs_op1_relation (const prange &lhs, + const prange &op1, + const irange &op2, + relation_kind) const +{ + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ()) + return VREL_VARYING; + + unsigned prec = TYPE_PRECISION (op2.type ()); + + // LHS = OP1 + 0 indicates LHS == OP1. + if (op2.zero_p ()) + return VREL_EQ; + + tree val; + // Only deal with singletons for now. + if (TYPE_OVERFLOW_UNDEFINED (lhs.type ()) && op2.singleton_p (&val)) + { + // Always interpret VALUE as a signed value. Positive will increase + // the pointer value, and negative will decrease the poiinter value. + // It cannot be zero or the earlier zero_p () condition will catch it. + wide_int value = wi::to_wide (val); + + // Positive op2 means lhs > op1. + if (wi::gt_p (value, wi::zero (prec), SIGNED)) + return VREL_GT; + + // Negative op2 means lhs < op1. + if (wi::lt_p (value, wi::zero (prec), SIGNED)) + return VREL_LT; + } + + // If op2 does not contain 0, then LHS and OP1 can never be equal. + if (!range_includes_zero_p (op2)) + return VREL_NE; + + return VREL_VARYING; +} + bool operator_bitwise_or::fold_range (prange &r, tree type, const prange &op1, diff --git a/gcc/range-op.cc b/gcc/range-op.cc index f72b4ae..35b3e18 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -390,6 +390,10 @@ range_op_handler::lhs_op1_relation (const vrange &lhs, return m_operator->lhs_op1_relation (as_a <prange> (lhs), as_a <irange> (op1), as_a <irange> (op2), rel); + case RO_PPI: + return m_operator->lhs_op1_relation (as_a <prange> (lhs), + as_a <prange> (op1), + as_a <irange> (op2), rel); case RO_IFF: return m_operator->lhs_op1_relation (as_a <irange> (lhs), as_a <frange> (op1), @@ -2415,8 +2419,11 @@ operator_widen_mult_unsigned::wi_fold (irange &r, tree type, class operator_div : public cross_product_operator { using range_operator::update_bitmask; + using range_operator::op2_range; public: operator_div (tree_code div_kind) { m_code = div_kind; } + bool op2_range (irange &r, tree type, const irange &lhs, const irange &, + relation_trio) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2436,6 +2443,19 @@ static operator_div op_floor_div (FLOOR_DIV_EXPR); static operator_div op_round_div (ROUND_DIV_EXPR); static operator_div op_ceil_div (CEIL_DIV_EXPR); +// Set OP2 to non-zero if the LHS isn't UNDEFINED. +bool +operator_div::op2_range (irange &r, tree type, const irange &lhs, + const irange &, relation_trio) const +{ + if (!lhs.undefined_p ()) + { + r.set_nonzero (type); + return true; + } + return false; +} + bool operator_div::wi_op_overflows (wide_int &res, tree type, const wide_int &w0, const wide_int &w1) const diff --git a/gcc/range-op.h b/gcc/range-op.h index 5dcb3fb..594e678 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -189,6 +189,10 @@ public: const prange &op1, const prange &op2, relation_kind = VREL_VARYING) const; + virtual relation_kind lhs_op1_relation (const prange &lhs, + const prange &op1, + const irange &op2, + relation_kind = VREL_VARYING) const; virtual relation_kind lhs_op1_relation (const frange &lhs, const frange &op1, const frange &op2, @@ -2443,6 +2443,8 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int, struct full_rtx_costs *); extern bool native_encode_rtx (machine_mode, rtx, vec<target_unit> &, unsigned int, unsigned int); +extern wide_int native_decode_int (const vec<target_unit> &, unsigned int, + unsigned int, unsigned int); extern rtx native_decode_rtx (machine_mode, const vec<target_unit> &, unsigned int); extern rtx native_decode_vector_rtx (machine_mode, const vec<target_unit> &, diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index 453b9f7..5cb9311 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,356 @@ +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/borrowck/rust-bir-place.h + (IndexVec::size_type): Add. + (IndexVec::MAX_INDEX): Add. + (IndexVec::size): Change the return type to the type of the + internal value used by the index type. + (PlaceDB::lookup_or_add_variable): Use the return value from the + PlaceDB::add_place call. + * checks/errors/borrowck/rust-bir.h + (struct BasicBlockId): Move this definition before the + definition of the struct Function. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit visibility. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Visit the loop labels of + WhileLetLoopExpr instances before visiting their scrutinee + expressions. + * resolve/rust-early-name-resolver-2.0.cc + (Early::resolve_glob_import): Pass the glob import's path + directly to NameResolutionContext::resolve_path. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Remove unnecessary call to + Identifier::as_string. + (flatten_glob): Improve handling of cases where a glob use tree + has no path. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::clone_enum_struct): Clone + path to avoid using the same nodeid. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit_function_params): + Add specialized function to visit function parameters. + (DefaultASTVisitor::visit): Remove parameter visit and call specialized + function instead. + * ast/rust-ast-visitor.h: Add function prototye. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove + function. + (Late::visit_function_params): Override specialized visit function. + * resolve/rust-late-name-resolver-2.0.h: Add overriden function + prototype. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-name-resolution-context.h: Use BindingLayer instead. + * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer): + Add new constructor for binding layer. + (BindingLayer::bind_test): Add a function to test a binding constraint. + (BindingLayer::push): Push a new binding group. + (BindingLayer::and_binded): Add function to test and-binding + constraint. + (BindingLayer::or_binded): Add function to test or-binding constraints. + (BindingLayer::insert_ident): Insert a new identifier in the current + binding group. + (BindingLayer::merge): Merge current binding group with it's parent. + (BindingLayer::get_source): Get the source of the current binding + group. + * resolve/rust-late-name-resolver-2.0.cc: Use stacked context for + binding group. + * util/rust-stacked-contexts.h: Add mutable peek function. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add binding + creation in visitor. + * resolve/rust-late-name-resolver-2.0.h: Add function prototypes. + * resolve/rust-name-resolution-context.h: Add binding context. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-name-resolution-context.h (struct Binding): Add Binding + struct to differentiate Or and Product bindings in patterns. + (enum class): Add Binding kind. + (class BindingContext): Add binding context with Binding stack. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.h: Add hash function. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.h: Add equality operator. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Add visit + function for TypeParam. + * resolve/rust-default-resolver.h: Add function prototype. + * resolve/rust-forever-stack.h: Add function to check for forward + declaration ban. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Check forward + declarations. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Remove error kind + and change function call. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Change call name. + * ast/rust-path.cc (ConstGenericParam::as_string): Likewise. + * ast/rust-path.h: Remove error kind. + * hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): Change call + name. + * parse/rust-parse-impl.h (Parser::parse_generic_param): Use optional + on parsing failure. + (Parser::parse_generic_arg): Likewise. + (Parser::parse_path_generic_args): Likewise. + * parse/rust-parse.h: Likewise. + * resolve/rust-ast-resolve-type.h: Change call name. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Change error + message. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::build_import_mapping): Avoid outputting an "unresolved + import" error if other errors are outputted during resolution. + * resolve/rust-early-name-resolver-2.0.h + (Early::resolve_path_in_all_ns): Collect path resolution errors + while avoiding duplicate errors for resolutions in each + namespace. + * resolve/rust-forever-stack.h + (ForeverStack::resolve_path): Add parameter for collecting + errors. + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_segments): Likewise. + * resolve/rust-forever-stack.hxx + (check_leading_kw_at_start): Likewise. + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_segments): Likewise. + (ForeverStack::resolve_path): Likewise. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::resolve_path): Add optional parameter + for collecting errors. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::array_copied_expr): prealloc the vector + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): add guard + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): add guard + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-path.cc + (ResolvePath::resolve_path): Adjust error messages. + * resolve/rust-ast-resolve-type.cc + (ResolveRelativeTypePath::go): Likewise. + * resolve/rust-forever-stack.hxx + (check_leading_kw_at_start): Likewise. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): fix bad assertion + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx + (ForeverStack::resolve_path): Pass instance of Node to lambda by + reference instead of by value. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-struct-field.h: keep reference to parent expression + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::TypeCheckStructExpr): + update ctor + (TypeCheckStructExpr::resolve): remove bad rust_fatal_errors + (TypeCheckStructExpr::visit): cleanup errors + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Handle StructPatternFieldIdent. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Dump llvm inline + asm tokens. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Remove unreachable + code. + * ast/rust-expr.h (struct LlvmOperand): Add LlvmOperand struct to + represent input and outputs. + (class LlvmInlineAsm): Add input, output and clobber operands. + (struct TupleTemplateStr): Add locus getter. + * backend/rust-compile-block.h: Add visit for LlvmInlineAsm. + * backend/rust-compile-expr.cc (CompileExpr::visit): Add llvm inline + asm stmt compilation. + * backend/rust-compile-expr.h: Add function prototype. + * backend/rust-compile-asm.h (class CompileLlvmAsm): Add llvm asm hir + not to gimple. + * backend/rust-compile-asm.cc (CompileLlvmAsm::CompileLlvmAsm): Add + constructor. + (CompileLlvmAsm::construct_operands): Add function to construct operand + tree. + (CompileLlvmAsm::construct_clobbers): Add function to construct clobber + tree. + (CompileLlvmAsm::tree_codegen_asm): Generate the whole tree for a given + llvm inline assembly node. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): + Add visit function. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Add function + prototype. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Add visit + function. + * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. + * checks/errors/borrowck/rust-function-collector.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): + Likewise. + * checks/errors/privacy/rust-privacy-reporter.h: Add visit function + prototype. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Add visit + function. + * checks/errors/rust-const-checker.h: Add visit function prototype. + * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit): + Add visit function. + * checks/errors/rust-hir-pattern-analysis.h: Add visit function + prototype. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Add + visit function. + * checks/errors/rust-unsafe-checker.h: Add function prototype. + * expand/rust-macro-builtins-asm.cc (parse_llvm_templates): Parse + templates. + (parse_llvm_arguments): Add function to parse non template tokens. + (parse_llvm_operands): Add function to parse operands, either input or + output. + (parse_llvm_outputs): Add function to parse and collect llvm asm + outputs. + (parse_llvm_inputs): Likewise with inputs. + (parse_llvm_clobbers): Add function to parse llvm asm clobbers. + (parse_llvm_options): Add function to parse llvm asm options. + (parse_llvm_asm): Add function to parse llvm asm. + * expand/rust-macro-builtins-asm.h (class LlvmAsmContext): Add context + for llvm asm parser. + (parse_llvm_outputs): Add function prototype. + (parse_llvm_inputs): Likewise. + (parse_llvm_clobbers): Likewise. + (parse_llvm_options): Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Lower AST llvm + asm node to HIR. + * hir/rust-ast-lower-expr.h: Add function prototype. + * hir/rust-hir-dump.cc (Dump::visit): Add visit function. + * hir/rust-hir-dump.h: Add function prototype. + * hir/tree/rust-hir-expr-abstract.h: Add HIR llvm asm node kind. + * hir/tree/rust-hir-expr.h (struct LlvmOperand): Add LlvmOperand type + to represent input and outputs. + (class LlvmInlineAsm): Add LlvmInlineAsm hir node. + * hir/tree/rust-hir-full-decls.h (class LlvmInlineAsm): Add + LlvmInlineAsm hir node forward declaration. + * hir/tree/rust-hir-visitor.h: Add visit functions for LlvmInlineAsm + hir node. + * hir/tree/rust-hir.cc (LlvmInlineAsm::accept_vis): Add hir node + visitor related functions. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Type check input and output operands. + * typecheck/rust-hir-type-check-expr.h: Add function prototype. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit input and + output operand expressions. + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Resolve input + and output expressions. + * resolve/rust-ast-resolve-expr.h: Add function prototypes. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Make visitor + unreachable. + * ast/rust-ast-collector.h: Add visit for LlvmInlineAsmNode. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Add visit + function for the default ast visitor. + * ast/rust-ast-visitor.h: Add function prototype. + * ast/rust-ast.cc (LlvmInlineAsm::accept_vis): Add accept_vis to + LlvmInlineAsm node. + * ast/rust-ast.h: Add LlvmInlineAsm node kind. + * ast/rust-expr.h (class LlvmInlineAsm): Add LlvmInlineAsm node. + * expand/rust-derive.h: Add visit function for LlvmInlineAsm node. + * expand/rust-macro-builtins-asm.cc (MacroBuiltin::llvm_asm_handler): + Add handler for llvm inline assembly nodes. + (parse_llvm_asm): Add function to parse llvm assembly nodes. + * expand/rust-macro-builtins-asm.h (parse_llvm_asm): Add function + prototypes. + * expand/rust-macro-builtins.cc (inline_llvm_asm_maker): Add macro + transcriber. + * expand/rust-macro-builtins.h: Add transcriber function prototype. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Add visit + function for LlvmInlineAsm node. + * hir/rust-ast-lower-base.h: Add visit function prototype. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Add visit + function for LlvmInlineAsm node. + * resolve/rust-ast-resolve-base.h: Add visit function prototype. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-macro-builtins-asm.cc (parse_asm_arg): Emit error + message. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): add diagnostic + * typecheck/rust-tyty.cc (BaseType::contains_infer): new helper to grab first infer var + * typecheck/rust-tyty.h: prototype + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust-gcc.cc (arithmetic_or_logical_expression): Ensure this is an integer + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): add guard for optional label + +2025-04-28 Yap Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-tyty.h: Remove extra redundant comment. + * typecheck/rust-hir-type-check-base.cc: Update comment on repr + handling. + +2025-04-28 Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-base.cc: Set enum representing + type properly if repr is an integer type. + * typecheck/rust-hir-type-check-item.cc: Update comments. + +2025-04-28 Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-tyty.h: Add new `ReprKind` enum to + `ReprOptions`. + * typecheck/rust-hir-type-check-base.cc: Handle setting of + `repr_kind`. + * typecheck/rust-hir-type-check-item.cc: New check for + zero-variant enums. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): add null check + * hir/tree/rust-hir-item.h: add has_type helper + * typecheck/rust-hir-trait-resolve.cc (TraitItemReference::resolve_item): + add missing type checking + 2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> * util/rust-lang-item.h: Add new manually_drop lang item. diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 8ee6375..c850e96 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -491,7 +491,7 @@ TokenCollector::visit (ConstGenericParam ¶m) if (param.has_default_value ()) { push (Rust::Token::make (EQUAL, UNDEF_LOCATION)); - visit (param.get_default_value ()); + visit (param.get_default_value_unchecked ()); } } @@ -639,8 +639,6 @@ TokenCollector::visit (GenericArg &arg) push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path))); } break; - case GenericArg::Kind::Error: - rust_unreachable (); } } @@ -1522,6 +1520,47 @@ void TokenCollector::visit (InlineAsm &expr) {} +void +TokenCollector::visit (LlvmInlineAsm &expr) +{ + push (Rust::Token::make_identifier (expr.get_locus (), "llvm_asm")); + push (Rust::Token::make (EXCLAM, expr.get_locus ())); + push (Rust::Token::make (LEFT_PAREN, expr.get_locus ())); + for (auto &template_str : expr.get_templates ()) + push (Rust::Token::make_string (template_str.get_locus (), + std::move (template_str.symbol))); + + push (Rust::Token::make (COLON, expr.get_locus ())); + for (auto output : expr.get_outputs ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (output.constraint))); + visit (output.expr); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (COLON, expr.get_locus ())); + for (auto input : expr.get_inputs ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (input.constraint))); + visit (input.expr); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (COLON, expr.get_locus ())); + for (auto &clobber : expr.get_clobbers ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (clobber.symbol))); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + push (Rust::Token::make (COLON, expr.get_locus ())); + // Dump options + + push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ())); +} + // rust-item.h void diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h index b014c23..f45e3cc 100644 --- a/gcc/rust/ast/rust-ast-collector.h +++ b/gcc/rust/ast/rust-ast-collector.h @@ -303,6 +303,7 @@ public: void visit (AwaitExpr &expr); void visit (AsyncBlockExpr &expr); void visit (InlineAsm &expr); + void visit (LlvmInlineAsm &expr); // rust-item.h void visit (TypeParam ¶m); void visit (LifetimeWhereClauseItem &item); diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index 9d524c3..b6833f6 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -82,7 +82,7 @@ DefaultASTVisitor::visit (AST::ConstGenericParam &const_param) if (const_param.has_type ()) visit (const_param.get_type ()); if (const_param.has_default_value ()) - visit (const_param.get_default_value ()); + visit (const_param.get_default_value_unchecked ()); } void @@ -108,7 +108,8 @@ DefaultASTVisitor::visit (GenericArgsBinding &binding) void DefaultASTVisitor::visit (AST::TypePathSegmentGeneric &segment) { - visit (segment.get_generic_args ()); + if (segment.has_generic_args ()) + visit (segment.get_generic_args ()); } void @@ -581,8 +582,8 @@ DefaultASTVisitor::visit (AST::WhileLetLoopExpr &expr) visit_outer_attrs (expr); for (auto &pattern : expr.get_patterns ()) visit (pattern); - visit (expr.get_scrutinee_expr ()); visit (expr.get_loop_label ()); + visit (expr.get_scrutinee_expr ()); visit (expr.get_loop_block ()); } @@ -714,6 +715,16 @@ DefaultASTVisitor::visit (AST::InlineAsm &expr) } void +DefaultASTVisitor::visit (AST::LlvmInlineAsm &expr) +{ + for (auto &output : expr.get_outputs ()) + visit (output.expr); + + for (auto &input : expr.get_inputs ()) + visit (input.expr); +} + +void DefaultASTVisitor::visit (AST::TypeParam ¶m) { visit_outer_attrs (param); @@ -817,10 +828,18 @@ DefaultASTVisitor::visit (AST::UseTreeRebind &use_tree) void DefaultASTVisitor::visit (AST::UseDeclaration &use_decl) { + visit (use_decl.get_visibility ()); visit (use_decl.get_tree ()); } void +DefaultASTVisitor::visit_function_params (AST::Function &function) +{ + for (auto ¶m : function.get_function_params ()) + visit (param); +} + +void DefaultASTVisitor::visit (AST::Function &function) { visit_outer_attrs (function); @@ -828,8 +847,9 @@ DefaultASTVisitor::visit (AST::Function &function) visit (function.get_qualifiers ()); for (auto &generic : function.get_generic_params ()) visit (generic); - for (auto ¶m : function.get_function_params ()) - visit (param); + + visit_function_params (function); + if (function.has_return_type ()) visit (function.get_return_type ()); if (function.has_where_clause ()) diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index 51661df..b1fc504 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -131,6 +131,7 @@ public: virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; virtual void visit (InlineAsm &expr) = 0; + virtual void visit (LlvmInlineAsm &expr) = 0; // rust-item.h virtual void visit (TypeParam ¶m) = 0; @@ -241,6 +242,8 @@ public: class DefaultASTVisitor : public ASTVisitor { public: + virtual void visit_function_params (AST::Function &function); + virtual void visit (AST::Crate &crate); virtual void visit (AST::Token &tok) override; @@ -314,6 +317,7 @@ public: virtual void visit (AST::AwaitExpr &expr) override; virtual void visit (AST::AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (AST::TypeParam ¶m) override; virtual void visit (AST::LifetimeWhereClauseItem &item) override; diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 06e0e7b..4e82be4 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -4651,6 +4651,12 @@ InlineAsm::accept_vis (ASTVisitor &vis) } void +LlvmInlineAsm::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void TypeParam::accept_vis (ASTVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 91611ec..aa6ad50 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -57,6 +57,11 @@ public: bool empty () const { return ident.empty (); } + bool operator== (const Identifier &other) const + { + return ident == other.ident; + } + private: std::string ident; location_t loc; @@ -1264,6 +1269,7 @@ public: Await, AsyncBlock, InlineAsm, + LlvmInlineAsm, Identifier, FormatArgs, MacroInvocation, @@ -2096,6 +2102,19 @@ template <> struct less<Rust::Identifier> return lhs.as_string () < rhs.as_string (); } }; + +template <> struct hash<Rust::Identifier> +{ + std::size_t operator() (const Rust::Identifier &k) const + { + using std::hash; + using std::size_t; + using std::string; + + return hash<string> () (k.as_string ()) ^ (hash<int> () (k.get_locus ())); + } +}; + } // namespace std #endif diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 69538df..fdb6360 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -4885,6 +4885,27 @@ struct InlineAsmRegOrRegClass location_t locus; }; +struct LlvmOperand +{ + std::string constraint; + std::unique_ptr<Expr> expr; + + LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr) + : constraint (constraint), expr (std::move (expr)) + {} + + LlvmOperand (const LlvmOperand &other) + : constraint (other.constraint), expr (other.expr->clone_expr ()) + {} + LlvmOperand &operator= (const LlvmOperand &other) + { + constraint = other.constraint; + expr = other.expr->clone_expr (); + + return *this; + } +}; + class InlineAsmOperand { public: @@ -5258,6 +5279,7 @@ struct TupleTemplateStr location_t loc; std::string symbol; + location_t get_locus () { return loc; } TupleTemplateStr (location_t loc, const std::string &symbol) : loc (loc), symbol (symbol) {} @@ -5330,6 +5352,77 @@ public: Expr::Kind get_expr_kind () const override { return Expr::Kind::InlineAsm; } }; +class LlvmInlineAsm : public ExprWithoutBlock +{ + // llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); + // Asm, Outputs, Inputs, Clobbers, Options, + +public: + enum class Dialect + { + Att, + Intel, + }; + +private: + location_t locus; + std::vector<Attribute> outer_attrs; + std::vector<LlvmOperand> inputs; + std::vector<LlvmOperand> outputs; + std::vector<TupleTemplateStr> templates; + std::vector<TupleClobber> clobbers; + bool volatility; + bool align_stack; + Dialect dialect; + +public: + LlvmInlineAsm (location_t locus) : locus (locus) {} + + Dialect get_dialect () { return dialect; } + + location_t get_locus () const override { return locus; } + + void mark_for_strip () override {} + + bool is_marked_for_strip () const override { return false; } + + std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } + + void accept_vis (ASTVisitor &vis) override; + + std::string as_string () const override { return "InlineAsm AST Node"; } + + void set_outer_attrs (std::vector<Attribute> v) override { outer_attrs = v; } + + LlvmInlineAsm *clone_expr_without_block_impl () const override + { + return new LlvmInlineAsm (*this); + } + + std::vector<TupleTemplateStr> &get_templates () { return templates; } + + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::LlvmInlineAsm; + } + + void set_align_stack (bool align_stack) { this->align_stack = align_stack; } + bool is_stack_aligned () { return align_stack; } + + void set_volatile (bool volatility) { this->volatility = volatility; } + bool is_volatile () { return volatility; } + + void set_dialect (Dialect dialect) { this->dialect = dialect; } + + void set_inputs (std::vector<LlvmOperand> operands) { inputs = operands; } + void set_outputs (std::vector<LlvmOperand> operands) { outputs = operands; } + + std::vector<LlvmOperand> &get_inputs () { return inputs; } + std::vector<LlvmOperand> &get_outputs () { return outputs; } + + std::vector<TupleClobber> &get_clobbers () { return clobbers; } +}; + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc index 69627be8..8e43ddf 100644 --- a/gcc/rust/ast/rust-path.cc +++ b/gcc/rust/ast/rust-path.cc @@ -119,7 +119,7 @@ ConstGenericParam::as_string () const str += "const " + name.as_string () + ": " + type->as_string (); if (has_default_value ()) - str += " = " + get_default_value ().as_string (); + str += " = " + get_default_value_unchecked ().as_string (); return str; } diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 805be8e..a4ba93b 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -167,17 +167,11 @@ public: */ enum class Kind { - Error, Const, // A const value Type, // A type argument (not discernable during parsing) Either, // Either a type or a const value, cleared up during resolving }; - static GenericArg create_error () - { - return GenericArg (nullptr, nullptr, {""}, Kind::Error, UNDEF_LOCATION); - } - static GenericArg create_const (std::unique_ptr<Expr> expression) { auto locus = expression->get_locus (); @@ -222,8 +216,6 @@ public: GenericArg (GenericArg &&other) = default; GenericArg &operator= (GenericArg &&other) = default; - bool is_error () const { return kind == Kind::Error; } - Kind get_kind () const { return kind; } location_t get_locus () const { return locus; } @@ -239,8 +231,6 @@ public: break; case Kind::Either: break; - case Kind::Error: - rust_unreachable (); } } @@ -283,8 +273,6 @@ public: { switch (get_kind ()) { - case Kind::Error: - rust_unreachable (); case Kind::Either: return "Ambiguous: " + path.as_string (); case Kind::Const: @@ -355,15 +343,15 @@ class ConstGenericParam : public GenericParam /** * Default value for the const generic parameter */ - GenericArg default_value; + tl::optional<GenericArg> default_value; AST::AttrVec outer_attrs; location_t locus; public: ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type, - GenericArg default_value, AST::AttrVec outer_attrs, - location_t locus) + tl::optional<GenericArg> default_value, + AST::AttrVec outer_attrs, location_t locus) : name (name), type (std::move (type)), default_value (std::move (default_value)), outer_attrs (outer_attrs), locus (locus) @@ -376,7 +364,7 @@ public: {} bool has_type () const { return type != nullptr; } - bool has_default_value () const { return !default_value.is_error (); } + bool has_default_value () const { return default_value.has_value (); } const Identifier &get_name () const { return name; } @@ -389,18 +377,18 @@ public: return *type; } - GenericArg &get_default_value () + GenericArg &get_default_value_unchecked () { rust_assert (has_default_value ()); - return default_value; + return default_value.value (); } - const GenericArg &get_default_value () const + const GenericArg &get_default_value_unchecked () const { rust_assert (has_default_value ()); - return default_value; + return default_value.value (); } std::string as_string () const override; diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc index 22498bc..7351cf0 100644 --- a/gcc/rust/backend/rust-compile-asm.cc +++ b/gcc/rust/backend/rust-compile-asm.cc @@ -1,5 +1,7 @@ #include "rust-compile-asm.h" #include "rust-compile-expr.h" +#include "rust-system.h" + namespace Rust { namespace Compile { @@ -141,5 +143,57 @@ CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr) return NULL_TREE; } +CompileLlvmAsm::CompileLlvmAsm (Context *ctx) : HIRCompileBase (ctx) {} + +tree +CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands) +{ + tree head = NULL_TREE; + for (auto &operand : operands) + { + tree t = CompileExpr::Compile (*operand.expr, this->ctx); + auto name = build_string (operand.constraint.size () + 1, + operand.constraint.c_str ()); + head = chainon (head, + build_tree_list (build_tree_list (NULL_TREE, name), t)); + } + return head; +} + +tree +CompileLlvmAsm::construct_clobbers (std::vector<AST::TupleClobber> clobbers) +{ + tree head = NULL_TREE; + for (auto &clobber : clobbers) + { + auto name + = build_string (clobber.symbol.size () + 1, clobber.symbol.c_str ()); + head = chainon (head, build_tree_list (NULL_TREE, name)); + } + return head; +} + +tree +CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr) +{ + tree ret = make_node (ASM_EXPR); + TREE_TYPE (ret) = void_type_node; + SET_EXPR_LOCATION (ret, expr.get_locus ()); + ASM_VOLATILE_P (ret) = expr.options.is_volatile; + + std::stringstream ss; + for (const auto &template_str : expr.templates) + { + ss << template_str.symbol << "\n"; + } + + ASM_STRING (ret) = Backend::string_constant_expression (ss.str ()); + ASM_INPUTS (ret) = construct_operands (expr.inputs); + ASM_OUTPUTS (ret) = construct_operands (expr.outputs); + ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ()); + + return ret; +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-asm.h b/gcc/rust/backend/rust-compile-asm.h index 4abd24e..22be94a 100644 --- a/gcc/rust/backend/rust-compile-asm.h +++ b/gcc/rust/backend/rust-compile-asm.h @@ -56,6 +56,20 @@ public: tree tree_codegen_asm (HIR::InlineAsm &); }; + +class CompileLlvmAsm : private HIRCompileBase +{ +private: + tree construct_operands (std::vector<HIR::LlvmOperand> operands); + + tree construct_clobbers (std::vector<AST::TupleClobber>); + +public: + CompileLlvmAsm (Context *ctx); + + tree tree_codegen_asm (HIR::LlvmInlineAsm &); +}; + } // namespace Compile } // namespace Rust #endif // RUST_COMPILE_ASM diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index 37e3980..3f38d08 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -100,6 +100,7 @@ public: void visit (HIR::AwaitExpr &) override {} void visit (HIR::AsyncBlockExpr &) override {} void visit (HIR::InlineAsm &) override {} + void visit (HIR::LlvmInlineAsm &) override {} private: CompileConditionalBlocks (Context *ctx, Bvariable *result) @@ -182,6 +183,7 @@ public: void visit (HIR::AwaitExpr &) override {} void visit (HIR::AsyncBlockExpr &) override {} void visit (HIR::InlineAsm &) override {} + void visit (HIR::LlvmInlineAsm &) override {} private: CompileExprWithBlock (Context *ctx, Bvariable *result) diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 37856a7..dd3420f 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -368,6 +368,13 @@ CompileExpr::visit (HIR::InlineAsm &expr) } void +CompileExpr::visit (HIR::LlvmInlineAsm &expr) +{ + CompileLlvmAsm asm_codegen (ctx); + ctx->add_statement (asm_codegen.tree_codegen_asm (expr)); +} + +void CompileExpr::visit (HIR::IfExprConseqElse &expr) { TyTy::BaseType *if_type = nullptr; @@ -1965,8 +1972,12 @@ CompileExpr::array_copied_expr (location_t expr_locus, if (ctx->const_context_p ()) { size_t idx = 0; + std::vector<unsigned long> indexes; std::vector<tree> constructor; + + indexes.reserve (len); + constructor.reserve (len); for (unsigned HOST_WIDE_INT i = 0; i < len; i++) { constructor.push_back (translated_expr); diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index dc78dee..65ed4b3 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -69,6 +69,7 @@ public: void visit (HIR::RangeFromToInclExpr &expr) override; void visit (HIR::ClosureExpr &expr) override; void visit (HIR::InlineAsm &expr) override; + void visit (HIR::LlvmInlineAsm &expr) override; // TODO void visit (HIR::ErrorPropagationExpr &) override {} diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc index d6acc6a..6b8b2e9 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -325,6 +325,10 @@ ExprStmtBuilder::visit (HIR::InlineAsm &expr) {} void +ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr) +{} + +void ExprStmtBuilder::visit (HIR::MethodCallExpr &expr) {} diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h index daedb68..5cab3c4 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -100,6 +100,7 @@ protected: // Expr void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::InlineAsm &expr) override; + void visit (HIR::LlvmInlineAsm &expr) override; void visit (HIR::MatchExpr &expr) override; void visit (HIR::AwaitExpr &expr) override; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index 3bc622c..b7a1555 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -207,6 +207,7 @@ public: } void visit (HIR::InlineAsm &expr) override {} + void visit (HIR::LlvmInlineAsm &expr) override {} protected: // Illegal at this position. void visit (HIR::StructExprFieldIdentifier &field) override diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 94fcecd..84311cc 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -153,6 +153,7 @@ protected: void visit (HIR::AwaitExpr &expr) override { rust_unreachable (); } void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); } void visit (HIR::InlineAsm &expr) override { rust_unreachable (); } + void visit (HIR::LlvmInlineAsm &expr) override { rust_unreachable (); } void visit (HIR::TypeParam ¶m) override { rust_unreachable (); } void visit (HIR::ConstGenericParam ¶m) override { rust_unreachable (); } void visit (HIR::LifetimeWhereClauseItem &item) override diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h index 67ca90b..dd9e672 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h @@ -204,6 +204,9 @@ template <typename I, typename T> class IndexVec { std::vector<T> internal_vector; + typedef decltype (std::declval<I> ().value) size_type; + static constexpr auto MAX_INDEX = std::numeric_limits<size_type>::max (); + public: IndexVec () = default; IndexVec (size_t size) { internal_vector.reserve (size); } @@ -219,7 +222,11 @@ public: internal_vector.emplace_back (std::forward<Args> (args)...); } - size_t size () const { return internal_vector.size (); } + size_type size () const + { + rust_assert (internal_vector.size () < MAX_INDEX); + return static_cast<size_type> (internal_vector.size ()); + } std::vector<T> &get_vector () { return internal_vector; } }; @@ -418,8 +425,7 @@ public: if (lookup != INVALID_PLACE) return lookup; - add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}); - return {places.size () - 1}; + return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}); }; template <typename FN> void for_each_path_from_root (PlaceId var, FN fn) const diff --git a/gcc/rust/checks/errors/borrowck/rust-bir.h b/gcc/rust/checks/errors/borrowck/rust-bir.h index e90e508..8a5f7be 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir.h @@ -35,6 +35,26 @@ using BasicBlocks = IndexVec<BasicBlockId, BasicBlock>; class Statement; class AbstractExpr; +/** Unique identifier for a basic block in the BIR. */ +struct BasicBlockId +{ + uint32_t value; + // some overloads for comparision + bool operator== (const BasicBlockId &rhs) const { return value == rhs.value; } + bool operator!= (const BasicBlockId &rhs) const + { + return !(operator== (rhs)); + } + bool operator< (const BasicBlockId &rhs) const { return value < rhs.value; } + bool operator> (const BasicBlockId &rhs) const { return value > rhs.value; } + bool operator<= (const BasicBlockId &rhs) const { return !(operator> (rhs)); } + bool operator>= (const BasicBlockId &rhs) const { return !(operator< (rhs)); } +}; + +static constexpr BasicBlockId INVALID_BB + = {std::numeric_limits<uint32_t>::max ()}; +static constexpr BasicBlockId ENTRY_BASIC_BLOCK = {0}; + /** * Top-level entity of the Borrow-checker IR (BIR). * It represents a single function (method, closure, etc.), which is the @@ -132,26 +152,6 @@ public: WARN_UNUSED_RESULT location_t get_location () const { return location; } }; -/** Unique identifier for a basic block in the BIR. */ -struct BasicBlockId -{ - uint32_t value; - // some overloads for comparision - bool operator== (const BasicBlockId &rhs) const { return value == rhs.value; } - bool operator!= (const BasicBlockId &rhs) const - { - return !(operator== (rhs)); - } - bool operator< (const BasicBlockId &rhs) const { return value < rhs.value; } - bool operator> (const BasicBlockId &rhs) const { return value > rhs.value; } - bool operator<= (const BasicBlockId &rhs) const { return !(operator> (rhs)); } - bool operator>= (const BasicBlockId &rhs) const { return !(operator< (rhs)); } -}; - -static constexpr BasicBlockId INVALID_BB - = {std::numeric_limits<uint32_t>::max ()}; -static constexpr BasicBlockId ENTRY_BASIC_BLOCK = {0}; - struct BasicBlock { // BIR "instructions". diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index cdb20e8..7cf0952 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -123,6 +123,7 @@ public: void visit (HIR::AwaitExpr &expr) override {} void visit (HIR::AsyncBlockExpr &expr) override {} void visit (HIR::InlineAsm &expr) override {} + void visit (HIR::LlvmInlineAsm &expr) override {} void visit (HIR::TypeParam ¶m) override {} void visit (HIR::ConstGenericParam ¶m) override {} void visit (HIR::LifetimeWhereClauseItem &item) override {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index a537c42..2a10053 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -306,6 +306,10 @@ PrivacyReporter::visit (HIR::InlineAsm &) {} void +PrivacyReporter::visit (HIR::LlvmInlineAsm &) +{} + +void PrivacyReporter::visit (HIR::TypePath &path) { check_for_privacy_violation (path.get_mappings ().get_nodeid (), diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index 5111a3e..7df2cf4 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -125,6 +125,7 @@ types virtual void visit (HIR::AwaitExpr &expr); virtual void visit (HIR::AsyncBlockExpr &expr); virtual void visit (HIR::InlineAsm &expr); + virtual void visit (HIR::LlvmInlineAsm &expr); virtual void visit (HIR::EnumItemTuple &); virtual void visit (HIR::EnumItemStruct &); diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 4c2257a..3716ea5 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -537,6 +537,10 @@ ConstChecker::visit (InlineAsm &) {} void +ConstChecker::visit (LlvmInlineAsm &) +{} + +void ConstChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index 00f57988..b954330 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -132,6 +132,7 @@ private: virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc index 257f4cd..648bc07 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -423,6 +423,10 @@ PatternChecker::visit (InlineAsm &expr) {} void +PatternChecker::visit (LlvmInlineAsm &expr) +{} + +void PatternChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 2171340..6d60ced 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -106,6 +106,7 @@ private: virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; virtual void visit (LifetimeWhereClauseItem &item) override; diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 8aa59ee..46eef11 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -481,9 +481,14 @@ UnsafeChecker::visit (MethodCallExpr &expr) TyTy::BaseType *method_type; context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (), &method_type); + if (!method_type || !method_type->is<TyTy::FnType> ()) + return; auto &fn = static_cast<TyTy::FnType &> (*method_type); + // FIXME + // should probably use the defid lookup instead + // tl::optional<HIR::Item *> lookup_defid (DefId id); auto method = mappings.lookup_hir_implitem (fn.get_ref ()); if (!unsafe_context.is_in_context () && method) check_unsafe_call (static_cast<Function *> (method->first), @@ -666,6 +671,17 @@ UnsafeChecker::visit (InlineAsm &expr) } void +UnsafeChecker::visit (LlvmInlineAsm &expr) +{ + if (unsafe_context.is_in_context ()) + return; + + rust_error_at ( + expr.get_locus (), ErrorCode::E0133, + "use of inline assembly is unsafe and requires unsafe function or block"); +} + +void UnsafeChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 63098fe..9a8fb7c 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -114,6 +114,7 @@ private: virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; virtual void visit (LifetimeWhereClauseItem &item) override; diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc index a955b58..321fa00 100644 --- a/gcc/rust/expand/rust-derive-clone.cc +++ b/gcc/rust/expand/rust-derive-clone.cc @@ -293,8 +293,14 @@ DeriveClone::clone_enum_struct (PathInExpression variant_path, new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( variant_path, loc, pattern_elts)), false, false, loc)); + + PathInExpression new_path (variant_path.get_segments (), + variant_path.get_outer_attrs (), + variant_path.get_locus (), + variant_path.opening_scope_resolution ()); + auto expr = std::unique_ptr<Expr> ( - new StructExprStructFields (variant_path, std::move (cloned_fields), loc)); + new StructExprStructFields (new_path, std::move (cloned_fields), loc)); return builder.match_case (std::move (pattern), std::move (expr)); } diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h index d8cc0a4..5fca49c 100644 --- a/gcc/rust/expand/rust-derive.h +++ b/gcc/rust/expand/rust-derive.h @@ -171,6 +171,7 @@ private: virtual void visit (AwaitExpr &expr) override final{}; virtual void visit (AsyncBlockExpr &expr) override final{}; virtual void visit (InlineAsm &expr) override final{}; + virtual void visit (LlvmInlineAsm &expr) override final{}; virtual void visit (TypeParam ¶m) override final{}; virtual void visit (LifetimeWhereClauseItem &item) override final{}; virtual void visit (TypeBoundWhereClauseItem &item) override final{}; diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc index d4db313..42df5e1 100644 --- a/gcc/rust/expand/rust-expand-visitor.cc +++ b/gcc/rust/expand/rust-expand-visitor.cc @@ -489,7 +489,8 @@ ExpandVisitor::visit (AST::PathInExpression &path) void ExpandVisitor::visit (AST::TypePathSegmentGeneric &segment) { - expand_generic_args (segment.get_generic_args ()); + if (segment.has_generic_args ()) + expand_generic_args (segment.get_generic_args ()); } void diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc index 4d02604..e255729 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.cc +++ b/gcc/rust/expand/rust-macro-builtins-asm.cc @@ -22,6 +22,7 @@ #include "rust-ast.h" #include "rust-fmt.h" #include "rust-stmt.h" +#include "rust-parse.h" namespace Rust { std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{ @@ -660,6 +661,15 @@ MacroBuiltin::asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc, return parse_asm (invoc_locus, invoc, semicolon, is_global_asm); } +tl::optional<AST::Fragment> +MacroBuiltin::llvm_asm_handler (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon, + AST::AsmKind is_global_asm) +{ + return parse_llvm_asm (invoc_locus, invoc, semicolon, is_global_asm); +} + tl::expected<InlineAsmContext, InlineAsmParseError> parse_asm_arg (InlineAsmContext inline_asm_ctx) { @@ -671,6 +681,14 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx) { token = parser.peek_current_token (); + if (token->get_id () == COLON || token->get_id () == SCOPE_RESOLUTION) + { + rust_error_at ( + token->get_locus (), + "the legacy LLVM-style %<asm!%> syntax is no longer supported"); + return tl::unexpected<InlineAsmParseError> (COMMITTED); + } + // We accept a comma token here. if (token->get_id () != COMMA && inline_asm_ctx.consumed_comma_without_formatted_string) @@ -962,4 +980,223 @@ validate (InlineAsmContext inline_asm_ctx) { return tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx); } + +tl::optional<LlvmAsmContext> +parse_llvm_templates (LlvmAsmContext ctx) +{ + auto &parser = ctx.parser; + + auto token = parser.peek_current_token (); + + if (token->get_id () == ctx.last_token_id + || token->get_id () != STRING_LITERAL) + { + return tl::nullopt; + } + + ctx.llvm_asm.get_templates ().emplace_back (token->get_locus (), + strip_double_quotes ( + token->as_string ())); + ctx.parser.skip_token (); + + token = parser.peek_current_token (); + if (token->get_id () != ctx.last_token_id && token->get_id () != COLON + && token->get_id () != SCOPE_RESOLUTION) + { + // We do not handle multiple template string, we provide minimal support + // for the black_box intrinsics. + rust_unreachable (); + } + + return ctx; +} + +tl::optional<LlvmAsmContext> +parse_llvm_arguments (LlvmAsmContext ctx) +{ + auto &parser = ctx.parser; + enum State + { + Templates = 0, + Output, + Input, + Clobbers, + Options + } current_state + = State::Templates; + + while (parser.peek_current_token ()->get_id () != ctx.last_token_id + && parser.peek_current_token ()->get_id () != END_OF_FILE) + { + if (parser.peek_current_token ()->get_id () == SCOPE_RESOLUTION) + { + parser.skip_token (SCOPE_RESOLUTION); + current_state = static_cast<State> (current_state + 2); + } + else + { + parser.skip_token (COLON); + current_state = static_cast<State> (current_state + 1); + } + + switch (current_state) + { + case State::Output: + parse_llvm_outputs (ctx); + break; + case State::Input: + parse_llvm_inputs (ctx); + break; + case State::Clobbers: + parse_llvm_clobbers (ctx); + break; + case State::Options: + parse_llvm_options (ctx); + break; + case State::Templates: + default: + rust_unreachable (); + } + } + + return ctx; +} + +void +parse_llvm_operands (LlvmAsmContext &ctx, std::vector<AST::LlvmOperand> &result) +{ + auto &parser = ctx.parser; + auto token = parser.peek_current_token (); + while (token->get_id () != COLON && token->get_id () != SCOPE_RESOLUTION + && token->get_id () != ctx.last_token_id) + { + std::string constraint; + if (token->get_id () == STRING_LITERAL) + { + constraint = strip_double_quotes (token->as_string ()); + } + parser.skip_token (STRING_LITERAL); + parser.skip_token (LEFT_PAREN); + + token = parser.peek_current_token (); + + ParseRestrictions restrictions; + restrictions.expr_can_be_null = true; + auto expr = parser.parse_expr (); + + parser.skip_token (RIGHT_PAREN); + + result.emplace_back (constraint, std::move (expr)); + + if (parser.peek_current_token ()->get_id () == COMMA) + parser.skip_token (COMMA); + + token = parser.peek_current_token (); + } +} + +void +parse_llvm_outputs (LlvmAsmContext &ctx) +{ + parse_llvm_operands (ctx, ctx.llvm_asm.get_outputs ()); +} + +void +parse_llvm_inputs (LlvmAsmContext &ctx) +{ + parse_llvm_operands (ctx, ctx.llvm_asm.get_inputs ()); +} + +void +parse_llvm_clobbers (LlvmAsmContext &ctx) +{ + auto &parser = ctx.parser; + auto token = parser.peek_current_token (); + while (token->get_id () != COLON && token->get_id () != ctx.last_token_id) + { + if (token->get_id () == STRING_LITERAL) + { + ctx.llvm_asm.get_clobbers ().push_back ( + {strip_double_quotes (token->as_string ()), token->get_locus ()}); + } + parser.skip_token (STRING_LITERAL); + token = parser.peek_current_token (); + } +} + +void +parse_llvm_options (LlvmAsmContext &ctx) +{ + auto &parser = ctx.parser; + auto token = parser.peek_current_token (); + + while (token->get_id () != ctx.last_token_id) + { + if (token->get_id () == STRING_LITERAL) + { + auto token_str = strip_double_quotes (token->as_string ()); + + if (token_str == "volatile") + ctx.llvm_asm.set_volatile (true); + else if (token_str == "alignstack") + ctx.llvm_asm.set_align_stack (true); + else if (token_str == "intel") + ctx.llvm_asm.set_dialect (AST::LlvmInlineAsm::Dialect::Intel); + else + rust_error_at (token->get_locus (), + "Unknown llvm assembly option %qs", + token_str.c_str ()); + } + parser.skip_token (STRING_LITERAL); + + token = parser.peek_current_token (); + + if (token->get_id () == ctx.last_token_id) + continue; + parser.skip_token (COMMA); + } + + parser.skip_token (); +} + +tl::optional<AST::Fragment> +parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon, AST::AsmKind is_global_asm) +{ + MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); + Parser<MacroInvocLexer> parser (lex); + auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser); + + AST::LlvmInlineAsm llvm_asm{invoc_locus}; + + auto asm_ctx = LlvmAsmContext (llvm_asm, parser, last_token_id); + + auto resulting_context + = parse_llvm_templates (asm_ctx).and_then (parse_llvm_arguments); + + if (resulting_context) + { + auto node = (*resulting_context).llvm_asm.clone_expr_without_block (); + + std::vector<AST::SingleASTNode> single_vec = {}; + + // If the macro invocation has a semicolon (`asm!("...");`), then we + // need to make it a statement. This way, it will be expanded + // properly. + if (semicolon == AST::InvocKind::Semicoloned) + single_vec.emplace_back (AST::SingleASTNode ( + std::make_unique<AST::ExprStmt> (std::move (node), invoc_locus, + semicolon + == AST::InvocKind::Semicoloned))); + else + single_vec.emplace_back (AST::SingleASTNode (std::move (node))); + + AST::Fragment fragment_ast + = AST::Fragment (single_vec, + std::vector<std::unique_ptr<AST::Token>> ()); + return fragment_ast; + } + return tl::nullopt; +} + } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h index 8081dae..bd64a7f 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.h +++ b/gcc/rust/expand/rust-macro-builtins-asm.h @@ -172,4 +172,36 @@ tl::optional<std::string> parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id, InlineAsmContext &inline_asm_ctx); +// LLVM ASM bits + +class LlvmAsmContext +{ +public: + AST::LlvmInlineAsm &llvm_asm; + Parser<MacroInvocLexer> &parser; + int last_token_id; + +public: + LlvmAsmContext (AST::LlvmInlineAsm &llvm_asm, Parser<MacroInvocLexer> &parser, + int last_token_id) + : llvm_asm (llvm_asm), parser (parser), last_token_id (last_token_id) + {} +}; + +void +parse_llvm_outputs (LlvmAsmContext &ctx); + +void +parse_llvm_inputs (LlvmAsmContext &ctx); + +void +parse_llvm_clobbers (LlvmAsmContext &ctx); + +void +parse_llvm_options (LlvmAsmContext &ctx); + +WARN_UNUSED_RESULT tl::optional<AST::Fragment> +parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon, AST::AsmKind is_global_asm); + } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 8b406ff..b58ed71 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -103,6 +103,15 @@ inline_asm_maker (AST::AsmKind global_asm) }; } +AST::MacroTranscriberFunc +inline_llvm_asm_maker (AST::AsmKind global_asm) +{ + return [global_asm] (location_t loc, AST::MacroInvocData &invoc, + AST::InvocKind semicolon) { + return MacroBuiltin::llvm_asm_handler (loc, invoc, semicolon, global_asm); + }; +} + std::unordered_map<std::string, AST::MacroTranscriberFunc> MacroBuiltin::builtin_transcribers = { {"assert", MacroBuiltin::assert_handler}, @@ -121,7 +130,7 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"format_args_nl", format_args_maker (AST::FormatArgs::Newline::Yes)}, {"asm", inline_asm_maker (AST::AsmKind::Inline)}, // FIXME: Is that okay? - {"llvm_asm", inline_asm_maker (AST::AsmKind::Inline)}, + {"llvm_asm", inline_llvm_asm_maker (AST::AsmKind::Inline)}, {"global_asm", inline_asm_maker (AST::AsmKind::Global)}, {"option_env", MacroBuiltin::option_env_handler}, /* Unimplemented macro builtins */ diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h index ff06ebf..541e956 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -181,6 +181,10 @@ public: AST::AsmKind is_global_asm); static tl::optional<AST::Fragment> + llvm_asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon, AST::AsmKind is_global_asm); + + static tl::optional<AST::Fragment> format_args_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon, AST::FormatArgs::Newline nl); diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 5039798..2d9a445 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -267,6 +267,10 @@ void ASTLoweringBase::visit (AST::InlineAsm &) {} +void +ASTLoweringBase::visit (AST::LlvmInlineAsm &) +{} + // void ASTLoweringBase::visit(MatchCasematch_case) {} // void ASTLoweringBase:: (AST::MatchCaseBlockExpr &) {} // void ASTLoweringBase:: (AST::MatchCaseExpr &) {} diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index b3bb174..3116181 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -152,6 +152,7 @@ public: virtual void visit (AST::IfLetExpr &expr) override; virtual void visit (AST::IfLetExprConseqElse &expr) override; virtual void visit (AST::InlineAsm &expr) override; + virtual void visit (AST::LlvmInlineAsm &expr) override; // virtual void visit(MatchCase& match_case) override; // virtual void visit (AST::MatchCaseBlockExpr &match_case) override; // virtual void visit (AST::MatchCaseExpr &match_case) override; diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index 3784e74..07d0c835 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -955,6 +955,50 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr) hir_operands, expr.get_clobber_abi (), expr.get_options (), mapping); } + +void +ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr) +{ + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + mappings.get_next_localdef_id (crate_num)); + + std::vector<LlvmOperand> inputs; + std::vector<LlvmOperand> outputs; + + for (auto i : expr.get_inputs ()) + { + std::unique_ptr<Expr> inner_expr + = std::unique_ptr<Expr> (translate (*i.expr.get ())); + inputs.emplace_back (i.constraint, std::move (inner_expr)); + } + + for (auto o : expr.get_outputs ()) + { + std::unique_ptr<Expr> inner_expr + = std::unique_ptr<Expr> (translate (*o.expr.get ())); + outputs.emplace_back (o.constraint, std::move (inner_expr)); + } + + HIR::LlvmInlineAsm::Options options{expr.is_volatile (), + expr.is_stack_aligned (), + expr.get_dialect ()}; + + // We're not really supporting llvm_asm, only the bare minimum + // we're quite conservative here as the current code support more usecase. + rust_assert (outputs.size () == 0); + rust_assert (inputs.size () <= 1); + rust_assert (expr.get_clobbers ().size () <= 1); + rust_assert (expr.get_templates ().size () == 1); + rust_assert (expr.get_templates ()[0].symbol == ""); + + translated + = new HIR::LlvmInlineAsm (expr.get_locus (), inputs, outputs, + expr.get_templates (), expr.get_clobbers (), + options, expr.get_outer_attrs (), mapping); +} + void ASTLoweringExpr::visit (AST::FormatArgs &fmt) { diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index af60e01..adedeb3 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -122,6 +122,7 @@ public: void visit (AST::ClosureExprInner &expr) override; void visit (AST::ClosureExprInnerTyped &expr) override; void visit (AST::InlineAsm &expr) override; + void visit (AST::LlvmInlineAsm &expr) override; // Extra visitor for FormatArgs nodes void visit (AST::FormatArgs &fmt) override; diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc index d3e528d..a678f18 100644 --- a/gcc/rust/hir/rust-ast-lower-type.cc +++ b/gcc/rust/hir/rust-ast-lower-type.cc @@ -557,7 +557,7 @@ ASTLowerGenericParam::visit (AST::ConstGenericParam ¶m) HIR::Expr *default_expr = nullptr; if (param.has_default_value ()) default_expr = ASTLoweringExpr::translate ( - param.get_default_value ().get_expression ()); + param.get_default_value_unchecked ().get_expression ()); translated = new HIR::ConstGenericParam (param.get_name ().as_string (), std::unique_ptr<Type> (type), diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index dafa823..cb32f68 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -1284,7 +1284,9 @@ Dump::visit (BlockExpr &e) do_expr (e); do_inner_attrs (e); put_field ("tail_reachable", std::to_string (e.is_tail_reachable ())); - put_field ("label", e.get_label ().as_string ()); + + if (e.has_label ()) + put_field ("label", e.get_label ().as_string ()); visit_collection ("statements", e.get_statements ()); @@ -1508,6 +1510,10 @@ Dump::visit (InlineAsm &e) {} void +Dump::visit (LlvmInlineAsm &e) +{} + +void Dump::visit (TypeParam &e) { begin ("TypeParam"); diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index afcd668..45b1708 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -166,6 +166,7 @@ private: virtual void visit (AwaitExpr &) override; virtual void visit (AsyncBlockExpr &) override; virtual void visit (InlineAsm &) override; + virtual void visit (LlvmInlineAsm &) override; virtual void visit (TypeParam &) override; virtual void visit (ConstGenericParam &) override; diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h index ecf9bd1..5bc5d89 100644 --- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h +++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h @@ -71,6 +71,7 @@ public: AsyncBlock, Path, InlineAsm, + LlvmInlineAsm, }; BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; } diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 96f0cf6..375f474 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -3118,6 +3118,80 @@ public: AST::AttrVec outer_attribs = AST::AttrVec ()); }; +struct LlvmOperand +{ + std::string constraint; + std::unique_ptr<Expr> expr; + + LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr) + : constraint (constraint), expr (std::move (expr)) + {} + + LlvmOperand (const LlvmOperand &other) + : constraint (other.constraint), expr (other.expr->clone_expr ()) + {} + LlvmOperand &operator= (const LlvmOperand &other) + { + constraint = other.constraint; + expr = other.expr->clone_expr (); + + return *this; + } +}; + +class LlvmInlineAsm : public ExprWithoutBlock +{ +public: + struct Options + { + bool is_volatile; + bool align_stack; + AST::LlvmInlineAsm::Dialect dialect; + }; + + location_t locus; + AST::AttrVec outer_attrs; + std::vector<LlvmOperand> inputs; + std::vector<LlvmOperand> outputs; + std::vector<AST::TupleTemplateStr> templates; + std::vector<AST::TupleClobber> clobbers; + Options options; + + LlvmInlineAsm (location_t locus, std::vector<LlvmOperand> inputs, + std::vector<LlvmOperand> outputs, + std::vector<AST::TupleTemplateStr> templates, + std::vector<AST::TupleClobber> clobbers, Options options, + AST::AttrVec outer_attrs, Analysis::NodeMapping mappings) + : ExprWithoutBlock (mappings, std::move (outer_attrs)), locus (locus), + inputs (std::move (inputs)), outputs (std::move (outputs)), + templates (std::move (templates)), clobbers (std::move (clobbers)), + options (options) + {} + + AST::LlvmInlineAsm::Dialect get_dialect () { return options.dialect; } + + location_t get_locus () const override { return locus; } + + std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; } + + void accept_vis (HIRFullVisitor &vis) override; + void accept_vis (HIRExpressionVisitor &vis) override; + + LlvmInlineAsm *clone_expr_without_block_impl () const override + { + return new LlvmInlineAsm (*this); + } + + std::vector<AST::TupleTemplateStr> &get_templates () { return templates; } + + Expr::ExprType get_expression_type () const override + { + return Expr::ExprType::LlvmInlineAsm; + } + + std::vector<AST::TupleClobber> get_clobbers () { return clobbers; } +}; + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index 6c19f24..1e313ec 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -126,6 +126,7 @@ class InlineAsmRegClass; struct AnonConst; class InlineAsmOperand; class InlineAsm; +class LlvmInlineAsm; // rust-stmt.h class EmptyStmt; diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index b9b105b..37f599c 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -2070,6 +2070,8 @@ public: Identifier get_name () const { return name; } + bool has_type () const { return expr != nullptr; } + bool has_expr () const { return expr != nullptr; } Type &get_type () diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 800e647..283cc34 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -84,6 +84,7 @@ public: virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; virtual void visit (InlineAsm &expr) = 0; + virtual void visit (LlvmInlineAsm &expr) = 0; virtual void visit (TypeParam ¶m) = 0; virtual void visit (ConstGenericParam ¶m) = 0; virtual void visit (LifetimeWhereClauseItem &item) = 0; @@ -220,6 +221,7 @@ public: virtual void visit (AwaitExpr &) override {} virtual void visit (AsyncBlockExpr &) override {} virtual void visit (InlineAsm &) override {} + virtual void visit (LlvmInlineAsm &) override {} virtual void visit (TypeParam &) override {} virtual void visit (ConstGenericParam &) override {} @@ -441,6 +443,7 @@ public: virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &expr) = 0; virtual void visit (InlineAsm &expr) = 0; + virtual void visit (LlvmInlineAsm &expr) = 0; virtual void visit (MatchExpr &expr) = 0; virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index c8bf9da..093d8d5 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -3822,6 +3822,17 @@ InlineAsm::accept_vis (HIRFullVisitor &vis) } void +LlvmInlineAsm::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} +void +LlvmInlineAsm::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void BorrowExpr::accept_vis (HIRExpressionVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 3bb758e..9dda231 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -3174,24 +3174,28 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) return nullptr; // optional default value - auto default_expr = AST::GenericArg::create_error (); + tl::optional<AST::GenericArg> default_expr = tl::nullopt; if (lexer.peek_token ()->get_id () == EQUAL) { lexer.skip_token (); auto tok = lexer.peek_token (); default_expr = parse_generic_arg (); - if (default_expr.is_error ()) - rust_error_at (tok->get_locus (), - "invalid token for start of default value for " - "const generic parameter: expected %<block%>, " - "%<identifier%> or %<literal%>, got %qs", - token_id_to_str (tok->get_id ())); + if (!default_expr) + { + rust_error_at (tok->get_locus (), + "invalid token for start of default value for " + "const generic parameter: expected %<block%>, " + "%<identifier%> or %<literal%>, got %qs", + token_id_to_str (tok->get_id ())); + return nullptr; + } // At this point, we *know* that we are parsing a const // expression - if (default_expr.get_kind () == AST::GenericArg::Kind::Either) - default_expr = default_expr.disambiguate_to_const (); + if (default_expr.value ().get_kind () + == AST::GenericArg::Kind::Either) + default_expr = default_expr.value ().disambiguate_to_const (); } param = std::unique_ptr<AST::ConstGenericParam> ( @@ -6249,7 +6253,7 @@ Parser<ManagedTokenSource>::parse_type_path () } template <typename ManagedTokenSource> -AST::GenericArg +tl::optional<AST::GenericArg> Parser<ManagedTokenSource>::parse_generic_arg () { auto tok = lexer.peek_token (); @@ -6270,7 +6274,7 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } else if (next_tok->get_id () == COLON) { @@ -6287,7 +6291,7 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } lexer.skip_token (); return AST::GenericArg::create_ambiguous (tok->get_str (), @@ -6313,12 +6317,12 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } } if (!expr) - return AST::GenericArg::create_error (); + return tl::nullopt; return AST::GenericArg::create_const (std::move (expr)); } @@ -6383,9 +6387,9 @@ Parser<ManagedTokenSource>::parse_path_generic_args () break; auto arg = parse_generic_arg (); - if (!arg.is_error ()) + if (arg) { - generic_args.emplace_back (std::move (arg)); + generic_args.emplace_back (std::move (arg.value ())); } // FIXME: Do we need to break if we encounter an error? diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index ff79879..827d91d 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -226,7 +226,7 @@ private: AST::TypePath parse_type_path (); std::unique_ptr<AST::TypePathSegment> parse_type_path_segment (); AST::PathIdentSegment parse_path_ident_segment (); - AST::GenericArg parse_generic_arg (); + tl::optional<AST::GenericArg> parse_generic_arg (); AST::GenericArgs parse_path_generic_args (); AST::GenericArgsBinding parse_generic_args_binding (); AST::TypePathFunction parse_type_path_function (location_t locus); diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index 6c35a22..b781ce33 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -328,6 +328,10 @@ ResolverBase::visit (AST::InlineAsm &) {} void +ResolverBase::visit (AST::LlvmInlineAsm &) +{} + +void ResolverBase::visit (AST::TypeParam &) {} diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index ab74e84..5bb9e4f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -110,6 +110,7 @@ public: void visit (AST::AwaitExpr &); void visit (AST::AsyncBlockExpr &); void visit (AST::InlineAsm &); + void visit (AST::LlvmInlineAsm &); void visit (AST::TypeParam &); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 8070fc1..6242235 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -368,6 +368,17 @@ ResolveExpr::visit (AST::InlineAsm &expr) { translate_operand (expr, prefix, canonical_prefix); } + +void +ResolveExpr::visit (AST::LlvmInlineAsm &expr) +{ + for (auto &output : expr.get_outputs ()) + ResolveExpr::go (*output.expr, prefix, canonical_prefix); + + for (auto &input : expr.get_inputs ()) + ResolveExpr::go (*input.expr, prefix, canonical_prefix); +} + void ResolveExpr::visit (AST::UnsafeBlockExpr &expr) { diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 562a3bd..b296d66 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -57,6 +57,7 @@ public: void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; void visit (AST::InlineAsm &expr) override; + void visit (AST::LlvmInlineAsm &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; void visit (AST::ArrayElemsValues &elems) override; void visit (AST::ArrayExpr &expr) override; diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index 530926d..fb6715d 100644 --- a/gcc/rust/resolve/rust-ast-resolve-path.cc +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -68,8 +68,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) if (in_middle_of_path && segment.is_lower_self_seg ()) { rust_error_at (segment.get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the " - "beginning of a path", + "%qs in paths can only be used in start position", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -372,8 +371,9 @@ ResolvePath::resolve_path (AST::SimplePath &expr) { if (!is_first_segment) { - rust_error_at (segment.get_locus (), - "%<super%> can only be used in start position"); + rust_error_at ( + segment.get_locus (), ErrorCode::E0433, + "%<super%> in paths can only be used in start position"); return UNKNOWN_NODEID; } if (module_scope_id == crate_scope_id) diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 606141c..8fd69c3 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -176,8 +176,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) if (in_middle_of_path && segment->is_lower_self_seg ()) { rust_error_at (segment->get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the " - "beginning of a path", + "%qs in paths can only be used in start position", segment->as_string ().c_str ()); return false; } diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 8379d0e..f1481fc 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -141,8 +141,8 @@ public: if (first_pass) ResolveType::go (param.get_type ()); else if (param.has_default_value ()) - ResolveExpr::go (param.get_default_value ().get_expression (), prefix, - canonical_prefix); + ResolveExpr::go (param.get_default_value_unchecked ().get_expression (), + prefix, canonical_prefix); } void visit (AST::TypeParam ¶m) override diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 7528e79..480034c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -179,5 +179,13 @@ DefaultResolver::visit (AST::StaticItem &item) ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); } +void +DefaultResolver::visit (AST::TypeParam ¶m) +{ + auto expr_vis = [this, ¶m] () { AST::DefaultASTVisitor::visit (param); }; + + ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index 587d7d4..2a987ef 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -50,6 +50,8 @@ public: void visit (AST::InherentImpl &) override; void visit (AST::TraitImpl &) override; + void visit (AST::TypeParam &) override; + // type dec nodes, which visit their fields or variants by default void visit (AST::StructStruct &) override; void visit (AST::TupleStruct &) override; diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 36456e1..3390f09 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -70,8 +70,7 @@ Early::go (AST::Crate &crate) bool Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) { - auto resolved - = ctx.resolve_path (glob.to_resolve.get_segments (), Namespace::Types); + auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types); if (!resolved.has_value ()) return false; @@ -141,6 +140,10 @@ Early::build_import_mapping ( // be moved into the newly created import mappings auto path = import.to_resolve; + // used to skip the "unresolved import" error + // if we output other errors during resolution + size_t old_error_count = macro_resolve_errors.size (); + switch (import.kind) { case TopLevel::ImportKind::Kind::Glob: @@ -154,7 +157,7 @@ Early::build_import_mapping ( break; } - if (!found) + if (!found && old_error_count == macro_resolve_errors.size ()) collect_error (Error (path.get_final_segment ().get_locus (), ErrorCode::E0433, "unresolved import %qs", path.as_string ().c_str ())); diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index c4226fe..e78bec0 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -218,7 +218,6 @@ private: std::vector<std::pair<Rib::Definition, Namespace>> resolve_path_in_all_ns (const P &path) { - const auto &segments = path.get_segments (); std::vector<std::pair<Rib::Definition, Namespace>> resolved; // Pair a definition with the namespace it was found in @@ -229,13 +228,22 @@ private: }; }; - ctx.resolve_path (segments, Namespace::Values) + std::vector<Error> value_errors; + std::vector<Error> type_errors; + std::vector<Error> macro_errors; + + ctx.resolve_path (path, value_errors, Namespace::Values) .map (pair_with_ns (Namespace::Values)); - ctx.resolve_path (segments, Namespace::Types) + ctx.resolve_path (path, type_errors, Namespace::Types) .map (pair_with_ns (Namespace::Types)); - ctx.resolve_path (segments, Namespace::Macros) + ctx.resolve_path (path, macro_errors, Namespace::Macros) .map (pair_with_ns (Namespace::Macros)); + if (!value_errors.empty () && !type_errors.empty () + && !macro_errors.empty ()) + for (auto &ent : value_errors) + collect_error (std::move (ent)); + return resolved; } diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index cf02651..81468e5 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -673,7 +673,8 @@ public: template <typename S> tl::optional<Rib::Definition> resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); // FIXME: Documentation tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; @@ -792,13 +793,15 @@ private: tl::optional<SegIterator<S>> find_starting_point ( const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); template <typename S> tl::optional<Node &> resolve_segments ( Node &starting_point, const std::vector<S> &segments, SegIterator<S> iterator, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); tl::optional<Rib::Definition> resolve_final_segment (Node &final_node, std::string &seg_name, @@ -828,6 +831,21 @@ private: tl::optional<Node &> dfs_node (Node &starting_point, NodeId to_find); tl::optional<const Node &> dfs_node (const Node &starting_point, NodeId to_find) const; + +public: + bool forward_declared (NodeId definition, NodeId usage) + { + if (peek ().kind != Rib::Kind::ForwardTypeParamBan) + return false; + + const auto &definition_rib = dfs_rib (cursor (), definition); + + if (!definition_rib) + return false; + + return (definition_rib + && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan); + } }; } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 993e2d4..069111ee 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -398,12 +398,13 @@ ForeverStack<N>::find_closest_module (Node &starting_point) * segments */ template <typename S> static inline bool -check_leading_kw_at_start (const S &segment, bool condition) +check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment, + bool condition) { if (condition) - rust_error_at ( + collect_errors.emplace_back ( segment.get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the beginning of a path", + "%qs in paths can only be used in start position", segment.as_string ().c_str ()); return condition; @@ -419,7 +420,8 @@ template <typename S> tl::optional<typename std::vector<S>::const_iterator> ForeverStack<N>::find_starting_point ( const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { auto iterator = segments.begin (); @@ -436,8 +438,9 @@ ForeverStack<N>::find_starting_point ( // if we're after the first path segment and meet `self` or `crate`, it's // an error - we should only be seeing `super` keywords at this point - if (check_leading_kw_at_start (seg, !is_start (iterator, segments) - && is_self_or_crate)) + if (check_leading_kw_at_start (collect_errors, seg, + !is_start (iterator, segments) + && is_self_or_crate)) return tl::nullopt; if (seg.is_crate_path_seg ()) @@ -460,8 +463,9 @@ ForeverStack<N>::find_starting_point ( starting_point = find_closest_module (starting_point); if (starting_point.get ().is_root ()) { - rust_error_at (seg.get_locus (), ErrorCode::E0433, - "too many leading %<super%> keywords"); + collect_errors.emplace_back ( + seg.get_locus (), ErrorCode::E0433, + "too many leading %<super%> keywords"); return tl::nullopt; } @@ -487,7 +491,8 @@ tl::optional<typename ForeverStack<N>::Node &> ForeverStack<N>::resolve_segments ( Node &starting_point, const std::vector<S> &segments, typename std::vector<S>::const_iterator iterator, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { Node *current_node = &starting_point; for (; !is_last (iterator, segments); iterator++) @@ -509,9 +514,10 @@ ForeverStack<N>::resolve_segments ( rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ()); // check that we don't encounter *any* leading keywords afterwards - if (check_leading_kw_at_start (seg, seg.is_crate_path_seg () - || seg.is_super_path_seg () - || seg.is_lower_self_seg ())) + if (check_leading_kw_at_start (collect_errors, seg, + seg.is_crate_path_seg () + || seg.is_super_path_seg () + || seg.is_lower_self_seg ())) return tl::nullopt; tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt; @@ -620,7 +626,8 @@ template <typename S> tl::optional<Rib::Definition> ForeverStack<N>::resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { // TODO: What to do if segments.empty() ? @@ -668,15 +675,16 @@ ForeverStack<N>::resolve_path ( std::reference_wrapper<Node> starting_point = cursor (); auto res - = find_starting_point (segments, starting_point, insert_segment_resolution) + = find_starting_point (segments, starting_point, insert_segment_resolution, + collect_errors) .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution] ( - typename std::vector<S>::const_iterator iterator) { + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector<S>::const_iterator iterator) { return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution); + insert_segment_resolution, collect_errors); }) .and_then ([this, &segments, &insert_segment_resolution] ( - Node final_node) -> tl::optional<Rib::Definition> { + Node &final_node) -> tl::optional<Rib::Definition> { // leave resolution within impl blocks to type checker if (final_node.rib.kind == Rib::Kind::TraitOrImpl) return tl::nullopt; diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index f743e1e..6ec0422 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -129,6 +129,54 @@ Late::new_label (Identifier name, NodeId id) } void +Late::visit (AST::ForLoopExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::For); + + visit (expr.get_pattern ()); + + ctx.bindings.exit (); + + visit (expr.get_iterator_expr ()); + visit (expr.get_loop_label ()); + visit (expr.get_loop_block ()); +} + +void +Late::visit (AST::IfLetExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::Let); + + for (auto &pattern : expr.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + visit (expr.get_value_expr ()); + visit (expr.get_if_block ()); +} + +void +Late::visit (AST::MatchArm &arm) +{ + visit_outer_attrs (arm); + + ctx.bindings.enter (BindingSource::Match); + + for (auto &pattern : arm.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + if (arm.has_match_arm_guard ()) + visit (arm.get_guard_expr ()); +} + +void Late::visit (AST::LetStmt &let) { DefaultASTVisitor::visit_outer_attrs (let); @@ -138,8 +186,13 @@ Late::visit (AST::LetStmt &let) // this makes variable shadowing work properly if (let.has_init_expr ()) visit (let.get_init_expr ()); + + ctx.bindings.enter (BindingSource::Let); + visit (let.get_pattern ()); + ctx.bindings.exit (); + if (let.has_else_expr ()) visit (let.get_init_expr ()); @@ -167,9 +220,68 @@ Late::visit (AST::IdentifierPattern &identifier) // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? + if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ())) + { + if (ctx.bindings.peek ().get_source () == BindingSource::Param) + rust_error_at ( + identifier.get_locus (), ErrorCode::E0415, + "identifier %qs is bound more than once in the same parameter list", + identifier.as_string ().c_str ()); + else + rust_error_at ( + identifier.get_locus (), ErrorCode::E0416, + "identifier %qs is bound more than once in the same pattern", + identifier.as_string ().c_str ()); + return; + } + + ctx.bindings.peek ().insert_ident (identifier.get_ident ()); + + if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ())) + { + // FIXME: map usage instead + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } + else + { + // We do want to ignore duplicated data because some situations rely on + // it. + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } +} + +void +Late::visit (AST::AltPattern &pattern) +{ + ctx.bindings.peek ().push (Binding::Kind::Or); + for (auto &alt : pattern.get_alts ()) + { + ctx.bindings.peek ().push (Binding::Kind::Product); + visit (alt); + ctx.bindings.peek ().merge (); + } + ctx.bindings.peek ().merge (); +} + +void +Late::visit_function_params (AST::Function &function) +{ + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : function.get_function_params ()) + visit (param); + + ctx.bindings.exit (); +} + +void +Late::visit (AST::StructPatternFieldIdent &field) +{ // We do want to ignore duplicated data because some situations rely on it. - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + std::ignore = ctx.values.insert_shadowable (field.get_identifier (), + field.get_node_id ()); } void @@ -347,8 +459,8 @@ Late::visit (AST::PathInExpression &expr) if (!resolved) { if (!ctx.lookup (expr.get_segments ().front ().get_node_id ())) - rust_error_at (expr.get_locus (), - "could not resolve path expression: %qs", + rust_error_at (expr.get_locus (), ErrorCode::E0433, + "Cannot find path %qs in this scope", expr.as_simple_path ().as_string ().c_str ()); return; } @@ -393,6 +505,14 @@ Late::visit (AST::TypePath &type) return; } + if (ctx.types.forward_declared (resolved->get_node_id (), + type.get_node_id ())) + { + rust_error_at (type.get_locus (), ErrorCode::E0128, + "type parameters with a default cannot use forward " + "declared identifiers"); + } + ctx.map_usage (Usage (type.get_node_id ()), Definition (resolved->get_node_id ())); } @@ -509,14 +629,35 @@ void Late::visit (AST::ClosureExprInner &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); + + visit (closure.get_definition_expr ()); } void Late::visit (AST::ClosureExprInnerTyped &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); + + visit (closure.get_return_type ()); + visit (closure.get_definition_block ()); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 5703b15..171d9bf 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -37,12 +37,20 @@ public: void new_label (Identifier name, NodeId id); + // Specialized visit bits + void visit_function_params (AST::Function &function) override; + // some more label declarations void visit (AST::LetStmt &) override; // TODO: Do we need this? // void visit (AST::Method &) override; void visit (AST::IdentifierPattern &) override; + void visit (AST::StructPatternFieldIdent &) override; + void visit (AST::AltPattern &) override; void visit (AST::SelfParam &) override; + void visit (AST::MatchArm &) override; + void visit (AST::ForLoopExpr &) override; + void visit (AST::IfLetExpr &) override; // resolutions void visit (AST::IdentifierExpr &) override; diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 92c4863..f098e48 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -23,6 +23,65 @@ namespace Rust { namespace Resolver2_0 { +BindingLayer::BindingLayer (BindingSource source) : source (source) +{ + push (Binding::Kind::Product); +} + +bool +BindingLayer::bind_test (Identifier ident, Binding::Kind kind) +{ + for (auto &bind : bindings) + { + if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + { + return true; + } + } + return false; +} + +void +BindingLayer::push (Binding::Kind kind) +{ + bindings.push_back (Binding (kind)); +} + +bool +BindingLayer::is_and_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Product); +} + +bool +BindingLayer::is_or_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Or); +} + +void +BindingLayer::insert_ident (Identifier ident) +{ + bindings.back ().set.insert (ident); +} + +void +BindingLayer::merge () +{ + auto last_binding = bindings.back (); + bindings.pop_back (); + for (auto &value : last_binding.set) + { + bindings.back ().set.insert (value); + } +} + +BindingSource +BindingLayer::get_source () const +{ + return source; +} + NameResolutionContext::NameResolutionContext () : mappings (Analysis::Mappings::get ()) {} diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 84c0800..19ba750 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -23,6 +23,7 @@ #include "rust-forever-stack.h" #include "rust-hir-map.h" #include "rust-rib.h" +#include "rust-stacked-contexts.h" namespace Rust { namespace Resolver2_0 { @@ -156,6 +157,62 @@ public: NodeId id; }; +struct Binding +{ + enum class Kind + { + Product, + Or, + } kind; + + std::unordered_set<Identifier> set; + + Binding (Binding::Kind kind) : kind (kind) {} +}; + +/** + * Used to identify the source of a binding, and emit the correct error message. + */ +enum class BindingSource +{ + Match, + Let, + For, + /* Closure param or function param */ + Param +}; + +class BindingLayer +{ + BindingSource source; + std::vector<Binding> bindings; + + bool bind_test (Identifier ident, Binding::Kind kind); + +public: + void push (Binding::Kind kind); + + BindingLayer (BindingSource source); + + /** + * Identifies if the identifier has been used in a product binding context. + * eg. `let (a, a) = test();` + */ + bool is_and_bound (Identifier ident); + + /** + * Identifies if the identifier has been used in a or context. + * eg. `let (a, 1) | (a, 2) = test()` + */ + bool is_or_bound (Identifier ident); + + void insert_ident (Identifier ident); + + void merge (); + + BindingSource get_source () const; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -212,6 +269,7 @@ public: ForeverStack<Namespace::Labels> labels; Analysis::Mappings &mappings; + StackedContexts<BindingLayer> bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition @@ -220,9 +278,10 @@ public: tl::optional<NodeId> lookup (NodeId usage) const; template <typename S> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, - Namespace ns) + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + std::vector<Error> &collect_errors, Namespace ns) { std::function<void (const S &, NodeId)> insert_segment_resolution = [this] (const S &seg, NodeId id) { @@ -234,60 +293,102 @@ public: { case Namespace::Values: return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Types: return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Macros: return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Labels: return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); default: rust_unreachable (); } } template <typename S, typename... Args> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { - std::initializer_list<Namespace> namespaces = {ns_args...}; + std::initializer_list<Namespace> namespaces = {ns_first, ns_args...}; for (auto ns : namespaces) { - if (auto ret - = resolve_path (segments, has_opening_scope_resolution, ns)) + std::vector<Error> collect_errors_inner; + if (auto ret = resolve_path (segments, has_opening_scope_resolution, + collect_errors_inner, ns)) return ret; + if (!collect_errors_inner.empty ()) + { + if (collect_errors.has_value ()) + { + std::move (collect_errors_inner.begin (), + collect_errors_inner.end (), + std::back_inserter (collect_errors.value ())); + } + else + { + for (auto &e : collect_errors_inner) + e.emit (); + } + return tl::nullopt; + } } return tl::nullopt; } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::SimplePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), ns_args...); + path.has_opening_scope_resolution (), collect_errors, + ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::PathInExpression &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), path.opening_scope_resolution (), - ns_args...); + collect_errors, ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::TypePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), ns_args...); + path.has_opening_scope_resolution_op (), + collect_errors, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first, + Args... ns_args) + { + return resolve_path (path, tl::nullopt, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const P &path_segments, bool has_opening_scope_resolution, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } private: diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index ba37dee..2f036fe 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -135,8 +135,7 @@ TopLevel::visit (AST::Module &module) void TopLevel::visit (AST::Trait &trait) { - insert_or_error_out (trait.get_identifier ().as_string (), trait, - Namespace::Types); + insert_or_error_out (trait.get_identifier (), trait, Namespace::Types); DefaultResolver::visit (trait); } @@ -548,6 +547,8 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths, { if (glob.has_path ()) paths.emplace_back (glob.get_path ()); + else + paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ())); } void diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 234721c..e5319d3 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -1109,6 +1109,7 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, rust_error_at (location, "division by zero"); } else if (op == ArithmeticOrLogicalOperator::LEFT_SHIFT + && TREE_CODE (right) == INTEGER_CST && (compare_tree_int (right, TYPE_PRECISION (TREE_TYPE (ret))) >= 0)) { rust_error_at (location, "left shift count >= width of type"); diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index e78c192..032bb58 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -384,7 +384,26 @@ TraitItemReference::resolve_item (HIR::TraitItemType &type) void TraitItemReference::resolve_item (HIR::TraitItemConst &constant) { - // TODO + TyTy::BaseType *ty = nullptr; + if (constant.has_type ()) + ty = TypeCheckType::Resolve (constant.get_type ()); + + TyTy::BaseType *expr = nullptr; + if (constant.has_expr ()) + expr = TypeCheckExpr::Resolve (constant.get_expr ()); + + bool have_specified_ty = ty != nullptr && !ty->is<TyTy::ErrorType> (); + bool have_expr_ty = expr != nullptr && !expr->is<TyTy::ErrorType> (); + + if (have_specified_ty && have_expr_ty) + { + coercion_site (constant.get_mappings ().get_hirid (), + TyTy::TyWithLocation (ty, + constant.get_type ().get_locus ()), + TyTy::TyWithLocation (expr, + constant.get_expr ().get_locus ()), + constant.get_locus ()); + } } void diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index beee91e..14b8ab8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -308,7 +308,8 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) repr.pack = 0; repr.align = 0; - // FIXME handle repr types.... + // Default repr for enums is isize, but we now check for other repr in the + // attributes. bool ok = context->lookup_builtin ("isize", &repr.repr); rust_assert (ok); @@ -353,13 +354,29 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) // manually parsing the string "packed(2)" here. size_t oparen = inline_option.find ('(', 0); - bool is_pack = false, is_align = false; + bool is_pack = false; + bool is_align = false; + bool is_c = false; + bool is_integer = false; unsigned char value = 1; if (oparen == std::string::npos) { is_pack = inline_option.compare ("packed") == 0; is_align = inline_option.compare ("align") == 0; + is_c = inline_option.compare ("C") == 0; + is_integer = (inline_option.compare ("isize") == 0 + || inline_option.compare ("i8") == 0 + || inline_option.compare ("i16") == 0 + || inline_option.compare ("i32") == 0 + || inline_option.compare ("i64") == 0 + || inline_option.compare ("i128") == 0 + || inline_option.compare ("usize") == 0 + || inline_option.compare ("u8") == 0 + || inline_option.compare ("u16") == 0 + || inline_option.compare ("u32") == 0 + || inline_option.compare ("u64") == 0 + || inline_option.compare ("u128") == 0); } else @@ -379,9 +396,28 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) } if (is_pack) - repr.pack = value; + { + repr.repr_kind = TyTy::ADTType::ReprKind::PACKED; + repr.pack = value; + } else if (is_align) - repr.align = value; + { + repr.repr_kind = TyTy::ADTType::ReprKind::ALIGN; + repr.align = value; + } + else if (is_c) + { + repr.repr_kind = TyTy::ADTType::ReprKind::C; + } + else if (is_integer) + { + repr.repr_kind = TyTy::ADTType::ReprKind::INT; + bool ok = context->lookup_builtin (inline_option, &repr.repr); + if (!ok) + { + rust_error_at (attr.get_locus (), "Invalid repr type"); + } + } delete meta_items; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index b2bcac0..cbf529a7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -844,6 +844,19 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr) } void +TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr) +{ + for (auto &i : expr.inputs) + TypeCheckExpr::Resolve (*i.expr); + + for (auto &o : expr.outputs) + TypeCheckExpr::Resolve (*o.expr); + + // Black box hint is unit type + infered = TyTy::TupleType::get_unit_type (); +} + +void TypeCheckExpr::visit (HIR::RangeFullExpr &expr) { auto lang_item_type = LangItem::Kind::RANGE_FULL; @@ -1129,27 +1142,25 @@ TypeCheckExpr::visit (HIR::FieldAccessExpr &expr) bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT; if (!is_valid_type) { - rust_error_at (expr.get_locus (), - "expected algebraic data type got: [%s]", - struct_base->as_string ().c_str ()); + rust_error_at (expr.get_locus (), "expected algebraic data type got %qs", + struct_base->get_name ().c_str ()); return; } TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base); - rust_assert (!adt->is_enum ()); - rust_assert (adt->number_of_variants () == 1); - + rust_assert (adt->number_of_variants () > 0); TyTy::VariantDef *vaiant = adt->get_variants ().at (0); TyTy::StructFieldType *lookup = nullptr; bool found = vaiant->lookup_field (expr.get_field_name ().as_string (), &lookup, nullptr); - if (!found) + if (!found || adt->is_enum ()) { - rust_error_at (expr.get_locus (), ErrorCode::E0609, - "no field %qs on type %qs", + rich_location r (line_table, expr.get_locus ()); + r.add_range (expr.get_field_name ().get_locus ()); + rust_error_at (r, ErrorCode::E0609, "no field %qs on type %qs", expr.get_field_name ().as_string ().c_str (), - adt->as_string ().c_str ()); + adt->get_name ().c_str ()); return; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 2a0022c..79121b3 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -70,6 +70,7 @@ public: void visit (HIR::WhileLoopExpr &expr) override; void visit (HIR::ClosureExpr &expr) override; void visit (HIR::InlineAsm &expr) override; + void visit (HIR::LlvmInlineAsm &expr) override; // TODO void visit (HIR::ErrorPropagationExpr &) override {} diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 9774921..aaa04af 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -355,6 +355,18 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) variants.push_back (field_type); } + // Check for zero-variant enum compatibility + if (enum_decl.is_zero_variant ()) + { + if (repr.repr_kind == TyTy::ADTType::ReprKind::INT + || repr.repr_kind == TyTy::ADTType::ReprKind::C) + { + rust_error_at (enum_decl.get_locus (), + "unsupported representation for zero-variant enum"); + return; + } + } + // get the path tl::optional<CanonicalPath> canonical_path; @@ -637,6 +649,38 @@ TypeCheckItem::visit (HIR::Function &function) context->switch_to_fn_body (); auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ()); + // emit check for + // error[E0121]: the type placeholder `_` is not allowed within types on item + const auto placeholder = ret_type->contains_infer (); + if (placeholder != nullptr && function.has_return_type ()) + { + // FIXME + // this will be a great place for the Default Hir Visitor we want to + // grab the locations of the placeholders (HIR::InferredType) their + // location, for now maybe we can use their hirid to lookup the location + location_t placeholder_locus + = mappings.lookup_location (placeholder->get_ref ()); + location_t type_locus = function.get_return_type ().get_locus (); + rich_location r (line_table, placeholder_locus); + + bool have_expected_type + = block_expr_ty != nullptr && !block_expr_ty->is<TyTy::ErrorType> (); + if (!have_expected_type) + { + r.add_range (type_locus); + } + else + { + std::string fixit + = "replace with the correct type " + block_expr_ty->get_name (); + r.add_fixit_replace (type_locus, fixit.c_str ()); + } + + rust_error_at (r, ErrorCode::E0121, + "the type placeholder %<_%> is not allowed within types " + "on item signatures"); + } + location_t fn_return_locus = function.has_function_return_type () ? function.get_return_type ().get_locus () : function.get_locus (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h index 800f7ca..7e3a57a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -60,6 +60,9 @@ private: TyTy::BaseType *resolved_field_value_expr; std::set<std::string> fields_assigned; std::map<size_t, HIR::StructExprField *> adtFieldIndexToField; + + // parent + HIR::Expr &parent; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc index 40c42b2..df1636a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -28,7 +28,7 @@ TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr &e) : TypeCheckBase (), resolved (new TyTy::ErrorType (e.get_mappings ().get_hirid ())), struct_path_resolved (nullptr), - variant (&TyTy::VariantDef::get_error_node ()) + variant (&TyTy::VariantDef::get_error_node ()), parent (e) {} TyTy::BaseType * @@ -65,7 +65,7 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) if (base_unify->get_kind () != struct_path_ty->get_kind ()) { - rust_fatal_error ( + rust_error_at ( struct_expr.get_struct_base ().get_base ().get_locus (), "incompatible types for base struct reference"); return; @@ -82,7 +82,16 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) bool ok = context->lookup_variant_definition ( struct_expr.get_struct_name ().get_mappings ().get_hirid (), &variant_id); - rust_assert (ok); + if (!ok) + { + rich_location r (line_table, struct_expr.get_locus ()); + r.add_range (struct_expr.get_struct_name ().get_locus ()); + rust_error_at ( + struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574, + "expected a struct, variant or union type, found enum %qs", + struct_path_resolved->get_name ().c_str ()); + return; + } ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant); rust_assert (ok); @@ -118,29 +127,14 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) break; } - if (!ok) - { - return; - } - - if (resolved_field_value_expr == nullptr) - { - rust_fatal_error (field->get_locus (), - "failed to resolve type for field"); - ok = false; - break; - } - - context->insert_type (field->get_mappings (), resolved_field_value_expr); + if (ok) + context->insert_type (field->get_mappings (), + resolved_field_value_expr); } - // something failed setting up the fields + // something failed setting up the fields and error's emitted if (!ok) - { - rust_error_at (struct_expr.get_locus (), - "constructor type resolution failure"); - return; - } + return; // check the arguments are all assigned and fix up the ordering std::vector<std::string> missing_field_names; @@ -271,8 +265,11 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) &field_index); if (!ok) { - rust_error_at (field.get_locus (), "unknown field"); - return true; + rich_location r (line_table, parent.get_locus ()); + r.add_range (field.get_locus ()); + rust_error_at (r, ErrorCode::E0560, "unknown field %qs", + field.field_name.as_string ().c_str ()); + return false; } auto it = adtFieldIndexToField.find (field_index); @@ -317,8 +314,11 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) bool ok = variant->lookup_field (field_name, &field_type, &field_index); if (!ok) { - rust_error_at (field.get_locus (), "unknown field"); - return true; + rich_location r (line_table, parent.get_locus ()); + r.add_range (field.get_locus ()); + rust_error_at (r, ErrorCode::E0560, "unknown field %qs", + field_name.c_str ()); + return false; } auto it = adtFieldIndexToField.find (field_index); diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index efad5f6..f0f4a07 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -682,6 +682,91 @@ BaseType::debug () const debug_str ().c_str ()); } +const TyTy::BaseType * +BaseType::contains_infer () const +{ + const TyTy::BaseType *x = destructure (); + + if (auto fn = x->try_as<const FnType> ()) + { + for (const auto ¶m : fn->get_params ()) + { + auto infer = param.get_type ()->contains_infer (); + if (infer) + return infer; + } + return fn->get_return_type ()->contains_infer (); + } + else if (auto fn = x->try_as<const FnPtr> ()) + { + for (const auto ¶m : fn->get_params ()) + { + auto infer = param.get_tyty ()->contains_infer (); + if (infer) + return infer; + } + return fn->get_return_type ()->contains_infer (); + } + else if (auto adt = x->try_as<const ADTType> ()) + { + for (auto &variant : adt->get_variants ()) + { + bool is_num_variant + = variant->get_variant_type () == VariantDef::VariantType::NUM; + if (is_num_variant) + continue; + + for (auto &field : variant->get_fields ()) + { + const BaseType *field_type = field->get_field_type (); + auto infer = (field_type->contains_infer ()); + if (infer) + return infer; + } + } + return nullptr; + } + else if (auto arr = x->try_as<const ArrayType> ()) + { + return arr->get_element_type ()->contains_infer (); + } + else if (auto slice = x->try_as<const SliceType> ()) + { + return slice->get_element_type ()->contains_infer (); + } + else if (auto ptr = x->try_as<const PointerType> ()) + { + return ptr->get_base ()->contains_infer (); + } + else if (auto ref = x->try_as<const ReferenceType> ()) + { + return ref->get_base ()->contains_infer (); + } + else if (auto tuple = x->try_as<const TupleType> ()) + { + for (size_t i = 0; i < tuple->num_fields (); i++) + { + auto infer = (tuple->get_field (i)->contains_infer ()); + if (infer) + return infer; + } + return nullptr; + } + else if (auto closure = x->try_as<const ClosureType> ()) + { + auto infer = (closure->get_parameters ().contains_infer ()); + if (infer) + return infer; + return closure->get_result_type ().contains_infer (); + } + else if (x->is<InferType> ()) + { + return x; + } + + return nullptr; +} + bool BaseType::is_concrete () const { diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index e814f07..1cada9a 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -137,6 +137,9 @@ public: void inherit_bounds ( const std::vector<TyTy::TypeBoundPredicate> &specified_bounds); + // contains_infer checks if there is an inference variable inside the type + const TyTy::BaseType *contains_infer () const; + // is_unit returns whether this is just a unit-struct bool is_unit () const; @@ -711,12 +714,22 @@ public: ENUM }; + enum ReprKind + { + RUST, + C, + INT, + ALIGN, + PACKED, + // TRANSPARENT, + // SIMD, + // ... + }; + // Representation options, specified via attributes e.g. #[repr(packed)] struct ReprOptions { - // bool is_c; - // bool is_transparent; - //... + ReprKind repr_kind = ReprKind::RUST; // For align and pack: 0 = unspecified. Nonzero = byte alignment. // It is an error for both to be nonzero, this should be caught when diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h index fe0bc8a..b263d75 100644 --- a/gcc/rust/util/rust-stacked-contexts.h +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -71,7 +71,14 @@ public: return last; } - const T &peek () + const T &peek () const + { + rust_assert (!stack.empty ()); + + return stack.back (); + } + + T &peek () { rust_assert (!stack.empty ()); diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index 06b52ca..d9aa049 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -7713,6 +7713,28 @@ native_decode_vector_rtx (machine_mode mode, const vec<target_unit> &bytes, return builder.build (); } +/* Extract a PRECISION-bit integer from bytes [FIRST_BYTE, FIRST_BYTE + SIZE) + of target memory image BYTES. */ + +wide_int +native_decode_int (const vec<target_unit> &bytes, unsigned int first_byte, + unsigned int size, unsigned int precision) +{ + /* Pull the bytes msb first, so that we can use simple + shift-and-insert wide_int operations. */ + wide_int result (wi::zero (precision)); + for (unsigned int i = 0; i < size; ++i) + { + unsigned int lsb = (size - i - 1) * BITS_PER_UNIT; + /* Always constant because the inputs are. */ + unsigned int subbyte + = subreg_size_offset_from_lsb (1, size, lsb).to_constant (); + result <<= BITS_PER_UNIT; + result |= bytes[first_byte + subbyte]; + } + return result; +} + /* Read an rtx of mode MODE from the target memory image given by BYTES, starting at byte FIRST_BYTE. Each element of BYTES contains BITS_PER_UNIT bits and the bytes are in target memory order. The image has enough @@ -7738,19 +7760,9 @@ native_decode_rtx (machine_mode mode, const vec<target_unit> &bytes, if (is_a <scalar_int_mode> (mode, &imode) && GET_MODE_PRECISION (imode) <= MAX_BITSIZE_MODE_ANY_INT) { - /* Pull the bytes msb first, so that we can use simple - shift-and-insert wide_int operations. */ - unsigned int size = GET_MODE_SIZE (imode); - wide_int result (wi::zero (GET_MODE_PRECISION (imode))); - for (unsigned int i = 0; i < size; ++i) - { - unsigned int lsb = (size - i - 1) * BITS_PER_UNIT; - /* Always constant because the inputs are. */ - unsigned int subbyte - = subreg_size_offset_from_lsb (1, size, lsb).to_constant (); - result <<= BITS_PER_UNIT; - result |= bytes[first_byte + subbyte]; - } + auto result = native_decode_int (bytes, first_byte, + GET_MODE_SIZE (imode), + GET_MODE_PRECISION (imode)); return immed_wide_int_const (result, imode); } diff --git a/gcc/stor-layout.cc b/gcc/stor-layout.cc index 18b5af5..12071c9 100644 --- a/gcc/stor-layout.cc +++ b/gcc/stor-layout.cc @@ -2591,16 +2591,21 @@ layout_type (tree type) /* Several boolean vector elements may fit in a single unit. */ if (VECTOR_BOOLEAN_TYPE_P (type) && type->type_common.mode != BLKmode) - TYPE_SIZE_UNIT (type) - = size_int (GET_MODE_SIZE (type->type_common.mode)); + { + TYPE_SIZE_UNIT (type) + = size_int (GET_MODE_SIZE (type->type_common.mode)); + TYPE_SIZE (type) + = bitsize_int (GET_MODE_BITSIZE (type->type_common.mode)); + } else - TYPE_SIZE_UNIT (type) = int_const_binop (MULT_EXPR, - TYPE_SIZE_UNIT (innertype), - size_int (nunits)); - TYPE_SIZE (type) = int_const_binop - (MULT_EXPR, - bits_from_bytes (TYPE_SIZE_UNIT (type)), - bitsize_int (BITS_PER_UNIT)); + { + TYPE_SIZE_UNIT (type) + = size_int (GET_MODE_SIZE (SCALAR_TYPE_MODE (innertype)) + * nunits); + TYPE_SIZE (type) + = bitsize_int (GET_MODE_BITSIZE (SCALAR_TYPE_MODE (innertype)) + * nunits); + } /* For vector types, we do not default to the mode's alignment. Instead, query a target hook, defaulting to natural alignment. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9896f7f..053765b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,354 @@ +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/111536 + * c-c++-common/analyzer/hard-reg-1.c: New test. + * g++.dg/analyzer/nrvo-1.C: New test. + * g++.dg/analyzer/nrvo-2.C: New test. + * g++.dg/analyzer/nrvo-pr111536-1.C: New test. + * g++.dg/analyzer/nrvo-pr111536-1b.C: New test. + * g++.dg/analyzer/nrvo-pr111536-2.C: New test. + * g++.dg/analyzer/nrvo-pr111536-2b.C: New test. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/109366 + * g++.dg/analyzer/unique_ptr-1.C: New test. + * g++.dg/analyzer/unique_ptr-2.C: New test. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/97111 + * c-c++-common/analyzer/analyzer-verbosity-2a.c: Add + -fno-exceptions. + * c-c++-common/analyzer/analyzer-verbosity-3a.c: Likewise. + * c-c++-common/analyzer/attr-const-2.c: Add + __attribute__((nothrow)). + * c-c++-common/analyzer/attr-malloc-4.c: Likewise. + * c-c++-common/analyzer/attr-malloc-5.c: Likewise. + * c-c++-common/analyzer/attr-malloc-6.c: Add -fno-exceptions. + * c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c: + Likewise. + * c-c++-common/analyzer/attr-malloc-exception.c: New test. + * c-c++-common/analyzer/call-summaries-pr107158-2.c: Add + -fno-exceptions. + * c-c++-common/analyzer/call-summaries-pr107158.c: Likewise. + * c-c++-common/analyzer/capacity-2.c: Likewise. + * c-c++-common/analyzer/coreutils-sum-pr108666.c: Likewise. + * c-c++-common/analyzer/data-model-22.c: Likewise. + * c-c++-common/analyzer/data-model-5d.c: Likewise. + * c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c: + Likewise. + * c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c: + Likewise. + * c-c++-common/analyzer/edges-2.c: Likewise. + * c-c++-common/analyzer/fd-2.c: Likewise. + * c-c++-common/analyzer/fd-3.c: Likewise. + * c-c++-common/analyzer/fd-meaning.c: Likewise. + * c-c++-common/analyzer/file-1.c: Likewise. + * c-c++-common/analyzer/file-3.c: Likewise. + * c-c++-common/analyzer/file-meaning-1.c: Likewise. + * c-c++-common/analyzer/infinite-recursion.c: Likewise. + * c-c++-common/analyzer/leak-3.c: Likewise. + * c-c++-common/analyzer/malloc-dedupe-1.c: Likewise. + * c-c++-common/analyzer/malloc-in-loop.c: Likewise. + * c-c++-common/analyzer/malloc-many-paths-3.c: Likewise. + * c-c++-common/analyzer/malloc-paths-5.c: Likewise. + * c-c++-common/analyzer/malloc-paths-7.c: Likewise. + * c-c++-common/analyzer/malloc-paths-8.c: Likewise. + * c-c++-common/analyzer/malloc-vs-local-1a.c: Likewise. + * c-c++-common/analyzer/malloc-vs-local-2.c: Likewise. + * c-c++-common/analyzer/malloc-vs-local-3.c: Likewise. + * c-c++-common/analyzer/paths-7.c: Likewise. + * c-c++-common/analyzer/pr110830.c: Likewise. + * c-c++-common/analyzer/pr93032-mztools-simplified.c: Likewise. + * c-c++-common/analyzer/pr93355-localealias-feasibility-3.c: + Likewise. + * c-c++-common/analyzer/pr93355-localealias-simplified.c: + Likewise. + * c-c++-common/analyzer/pr96650-1-trans.c: Likewise. + * c-c++-common/analyzer/pr97072.c: Add __attribute__((nothrow)). + * c-c++-common/analyzer/pr98575-1.c: Likewise. + * c-c++-common/analyzer/pr99716-1.c: Add -fno-exceptions. + * c-c++-common/analyzer/pr99716-2.c: Likewise. + * c-c++-common/analyzer/pr99716-3.c: Likewise. + * c-c++-common/analyzer/pragma-2.c: Likewise. + * c-c++-common/analyzer/rhbz1878600.c: Likewise. + * c-c++-common/analyzer/strndup-1.c: Likewise. + * c-c++-common/analyzer/write-to-string-literal-4-disabled.c: + Likewise. + * c-c++-common/analyzer/write-to-string-literal-4.c: Likewise. + * c-c++-common/analyzer/write-to-string-literal-5.c: Likewise. + * c-c++-common/analyzer/zlib-5.c: Likewise. + * g++.dg/analyzer/exception-could-throw-1.C: New test. + * g++.dg/analyzer/exception-could-throw-2.C: New test. + * g++.dg/analyzer/exception-dynamic-spec.C: New test. + * g++.dg/analyzer/exception-leak-1.C: New test. + * g++.dg/analyzer/exception-leak-2.C: New test. + * g++.dg/analyzer/exception-leak-3.C: New test. + * g++.dg/analyzer/exception-leak-4.C: New test. + * g++.dg/analyzer/exception-leak-5.C: New test. + * g++.dg/analyzer/exception-leak-6.C: New test. + * g++.dg/analyzer/exception-nothrow.C: New test. + * g++.dg/analyzer/exception-path-1.C: New test. + * g++.dg/analyzer/exception-path-catch-all-1.C: New test. + * g++.dg/analyzer/exception-path-catch-all-2.C: New test. + * g++.dg/analyzer/exception-path-unwind-multiple-2.C: New test. + * g++.dg/analyzer/exception-path-unwind-multiple.C: New test. + * g++.dg/analyzer/exception-path-unwind-single.C: New test. + * g++.dg/analyzer/exception-path-with-cleanups.C: New test. + * g++.dg/analyzer/exception-rethrow-1.C: New test. + * g++.dg/analyzer/exception-rethrow-2.C: New test. + * g++.dg/analyzer/exception-stack-1.C: New test. + * g++.dg/analyzer/exception-stack-2.C: New test. + * g++.dg/analyzer/exception-subclass-1.C: New test. + * g++.dg/analyzer/exception-subclass-2.C: New test. + * g++.dg/analyzer/exception-value-1.C: New test. + * g++.dg/analyzer/exception-value-2.C: New test. + * g++.dg/analyzer/fno-exception.C: New test. + * g++.dg/analyzer/pr94028.C: Drop xfail. + * g++.dg/analyzer/std-unexpected.C: New test. + * g++.dg/coroutines/pr105287.C: Drop dg-excess-errors. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/plugin/analyzer_cpython_plugin.cc: Drop include of + "make-unique.h". Replace uses of ::make_unique with + std::make_unique. + * gcc.dg/plugin/analyzer_gil_plugin.cc: Likewise. + * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise. + * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise. + * gcc.dg/plugin/diagnostic_group_plugin.cc: Likewise. + * gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/plugin/analyzer_gil_plugin.cc: Convert gcall * to gcall & + where we know the pointer must be non-null. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/plugin/analyzer_cpython_plugin.cc: Convert + enum poison_kind to "enum class". + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/plugin/analyzer_cpython_plugin.cc: Update for renaming + of analyzer/analyzer.h to analyzer/common.h. + * gcc.dg/plugin/analyzer_gil_plugin.cc: Likewise. + * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise. + * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/95801 + * gcc.dg/tree-ssa/pr95801.c: New. + +2025-04-28 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/119712 + * gcc.dg/pr119712.c: New. + * gcc.dg/pr83072-2.c: Adjust. + * gcc.dg/tree-ssa/phi-opt-value-5.c: Adjust. + * gcc.dg/tree-ssa/vrp122.c: Adjust + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/67797 + * gcc.dg/tree-ssa/tailcall-14.c: New test. + * gcc.dg/tree-ssa/tailcall-15.c: New test. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR c/119432 + * gcc.dg/gimplefe-57.c: New test. + +2025-04-28 Andrew Pinski <quic_apinski@quicinc.com> + + PR tree-optimization/100038 + * g++.dg/tree-ssa/pr100038.C: New test. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/nr2/exclude: Remove now passing test from exclusion + list. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/nr2/exclude: Remove passing test from exclusion list. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/multiple_bindings1.rs: Add missing lang items. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/nr2/exclude: Remove test from exclusion list. + * rust/compile/use_1.rs: Change expected output and remove test from + nr1. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/generics9.rs: Change expected error message. + * rust/compile/nr2/exclude: Remove test from exclusion list. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/nr2/exclude: Remove passing test from exclusion list. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entry. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/derive-debug1.rs: Adjust a path. + * rust/compile/nr2/exclude: Remove derive-debug1.rs. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/nr2/exclude: nr2 is missing error for this + * rust/compile/issue-3649.rs: New test. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/issue-3568.rs: Adjust expected errors. + * rust/compile/name_resolution9.rs: Likewise. + * rust/compile/self-path2.rs: Likewise. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/nonexistent-field.rs: fix bad error message + * rust/compile/issue-3581-1.rs: New test. + * rust/compile/issue-3581-2.rs: New test. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/nr2/exclude: nr2 does not error on the T it should require Self::T + * rust/compile/issue-3652.rs: New test. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/macros/mbe/macro-issue2983_2984.rs: cleanup error diagnotics + * rust/compile/struct_init1.rs: likewise + * rust/compile/issue-3628.rs: New test. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entry. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3662.rs: New test. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3711.rs: New test. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/black_box.rs: New test. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/execute/black_box.rs: New test. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-402.rs: New test. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3664.rs: New test. + +2025-04-28 Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/issue-3530-1.rs: New file. + * rust/compile/issue-3530-2.rs: New file. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3612.rs: New test. + +2025-04-28 H.J. Lu <hjl.tools@gmail.com> + Uros Bizjak <ubizjak@gmail.com> + + PR target/109780 + PR target/109093 + * g++.target/i386/pr109780-1.C: New test. + * gcc.target/i386/pr109093-1.c: Likewise. + * gcc.target/i386/pr109780-1.c: Likewise. + * gcc.target/i386/pr109780-2.c: Likewise. + * gcc.target/i386/pr109780-3.c: Likewise. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR ipa/119973 + * gcc.dg/torture/pr119973.c: New testcase. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR tree-optimization/119103 + * gcc.target/i386/pr119103.c: New testcase. + +2025-04-28 Richard Biener <rguenther@suse.de> + + PR middle-end/60779 + * gcc.dg/lto/pr60779_0.c: New testcase. + * gcc.dg/lto/pr60779_1.c: Likewise. + +2025-04-28 Lewis Hyatt <lhyatt@gmail.com> + + PR c/118838 + * c-c++-common/cpp/pragma-diagnostic-loc-2.c: New test. + * g++.dg/gomp/macro-4.C: Adjust expected output. + * gcc.dg/gomp/macro-4.c: Likewise. + * gcc.dg/cpp/Wunknown-pragmas-1.c: Likewise. + +2025-04-28 Jonathan Yong <10walls@gmail.com> + + * gcc.dg/graphite/id-15.c: Use __SIZE_TYPE__ instead of + unsigned long. + * gcc.dg/plugin/infoleak-net-ethtool-ioctl.c: ditto. + +2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119939 + * g++.dg/modules/concept-11_a.H: New test. + * g++.dg/modules/concept-11_b.C: New test. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * gcc.dg/tree-ssa/ssa-fre-4.c: Enable for all targets and adjust + scan match. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * gcc.dg/tree-ssa/scev-cast.c: Enable for all targets and adjust + scan match. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * gcc.dg/vect/vect-simd-clone-16c.c: Expect in-branch clones for + x86. + * gcc.dg/vect/vect-simd-clone-16d.c: Likewise. + * gcc.dg/vect/vect-simd-clone-17c.c: Likewise. + * gcc.dg/vect/vect-simd-clone-17d.c: Likewise. + * gcc.dg/vect/vect-simd-clone-18c.c: Likewise. + * gcc.dg/vect/vect-simd-clone-18d.c: Likewise. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * gcc.target/i386/apx-ndd.c: Adjusted. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * gfortran.dg/pr112877-1.f90: New test. + 2025-04-25 Dimitar Dimitrov <dimitar@dinux.eu> * g++.dg/ipa/pr83549.C: Require effective target diff --git a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c index cf014b0..175d9c3 100644 --- a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c +++ b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fanalyzer-verbosity=2" } */ +/* { dg-additional-options "-fanalyzer-verbosity=2 -fno-exceptions" } */ typedef struct FILE FILE; diff --git a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c index b0ece20..8d66c8f 100644 --- a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c +++ b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fanalyzer-verbosity=3" } */ +/* { dg-additional-options "-fanalyzer-verbosity=3 -fno-exceptions" } */ typedef struct FILE FILE; diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c b/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c index ab79514..5329a89 100644 --- a/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c @@ -1,5 +1,5 @@ extern int const_p (int) __attribute__((const)); -extern void do_stuff (void); +extern void do_stuff (void) __attribute__((nothrow)); void test (int a) { diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c index 1517667..1e2e1f9 100644 --- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c @@ -2,7 +2,7 @@ struct foo; extern void foo_release (struct foo *) - __attribute__((nonnull)); + __attribute__((nonnull, nothrow)); extern struct foo *foo_acquire (void) __attribute__ ((malloc (foo_release))); diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c index 7ff4e57..8b7ffc1 100644 --- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c @@ -1,7 +1,7 @@ /* Example of extra argument to "malloc" attribute. */ struct foo; -extern void foo_release (int, struct foo *); +extern void foo_release (int, struct foo *) __attribute__((nothrow)); extern struct foo *foo_acquire (void) __attribute__ ((malloc (foo_release, 2))); diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c index 1665d41..45ee406f 100644 --- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c @@ -1,4 +1,5 @@ /* Adapted from gcc.dg/Wmismatched-dealloc.c. */ +/* { dg-additional-options "-fno-exceptions" } */ #define A(...) __attribute__ ((malloc (__VA_ARGS__))) diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c index 87ad42a..fd51630 100644 --- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c @@ -1,6 +1,8 @@ /* Adapted from linux 5.3.11: drivers/net/wireless/ath/ath10k/usb.c Reduced reproducer for CVE-2019-19078 (leak of struct urb). */ +/* { dg-additional-options "-fno-exceptions" } */ + typedef unsigned char u8; typedef unsigned short u16; diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c new file mode 100644 index 0000000..9f5e2e8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c @@ -0,0 +1,17 @@ +/* { dg-additional-options "-fexceptions" } */ + +extern void free (void *); + +/* Not marked "nothrow", so assume it could throw. */ +char *xstrdup (const char *) + __attribute__((malloc (free), returns_nonnull)); + +void test_1 (const char *s, const char *t) +{ + char *p = xstrdup (s); /* { dg-message "allocated here" } */ + char *q = xstrdup (t); /* { dg-warning "leak of 'p'" } */ + /* { dg-message "if .* throws an exception\.\.\." "" { target *-*-* } .-1 } */ + + free (q); + free (p); +} diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c index b395623..a15ab65 100644 --- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ +/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex -fno-exceptions" } */ /* { dg-skip-if "c++98 has no noreturn attribute" { c++98_only } } */ #ifdef __cplusplus diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c index de70583..6fbbce4 100644 --- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c +++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-symbol-too-complex" } */ +/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-symbol-too-complex -fno-exceptions" } */ typedef __SIZE_TYPE__ size_t; enum { _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)) }; diff --git a/gcc/testsuite/c-c++-common/analyzer/capacity-2.c b/gcc/testsuite/c-c++-common/analyzer/capacity-2.c index 7d2de4e..3846239 100644 --- a/gcc/testsuite/c-c++-common/analyzer/capacity-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/capacity-2.c @@ -1,5 +1,6 @@ /* { dg-skip-if "" { powerpc*-*-aix* } } */ /* { dg-skip-if "requires hosted libstdc++ for stdlib size_t" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c b/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c index c41b61d..95091e7 100644 --- a/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c +++ b/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c @@ -1,5 +1,7 @@ /* Reduced from coreutils's sum.c: bsd_sum_stream */ +/* { dg-additional-options "-fno-exceptions" } */ + typedef __SIZE_TYPE__ size_t; typedef unsigned char __uint8_t; typedef unsigned long int __uintmax_t; diff --git a/gcc/testsuite/c-c++-common/analyzer/data-model-22.c b/gcc/testsuite/c-c++-common/analyzer/data-model-22.c index 8429b2f..65bf346 100644 --- a/gcc/testsuite/c-c++-common/analyzer/data-model-22.c +++ b/gcc/testsuite/c-c++-common/analyzer/data-model-22.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + #include <string.h> #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c b/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c index a86d506..bb45917 100644 --- a/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c +++ b/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ /* A toy re-implementation of CPython's object model. */ diff --git a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c index 7431bd1..b790997 100644 --- a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c @@ -1,4 +1,5 @@ /* Reduced from git-2.39.0's pack-revindex.c */ +/* { dg-additional-options "-fno-exceptions" } */ typedef unsigned int __uint32_t; typedef unsigned long int __uintmax_t; diff --git a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c index 7123cf5..a7f8049 100644 --- a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c @@ -1,6 +1,7 @@ /* Reduced from haproxy-2.7.1: src/tcpcheck.c. */ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-fno-exceptions" } */ typedef __SIZE_TYPE__ size_t; diff --git a/gcc/testsuite/c-c++-common/analyzer/edges-2.c b/gcc/testsuite/c-c++-common/analyzer/edges-2.c index 7e4543c..df4bfaa 100644 --- a/gcc/testsuite/c-c++-common/analyzer/edges-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/edges-2.c @@ -1,5 +1,7 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ + #include <stdlib.h> int foo (); diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-2.c b/gcc/testsuite/c-c++-common/analyzer/fd-2.c index 10c9ecd..b6b0a57 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-2.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + int open(const char *, int mode); void close(int fd); #define O_RDONLY 0 @@ -61,4 +63,4 @@ test_5 (const char *path, mode_t mode) int fd = creat (path, mode); close(fd); close(fd); /* { dg-warning "double 'close' of file descriptor 'fd' \\\[CWE-1341\\\]" "warning" } */ -}
\ No newline at end of file +} diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-3.c b/gcc/testsuite/c-c++-common/analyzer/fd-3.c index 8e71b14..4894b64 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-3.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + int open(const char *, int mode); void close(int fd); int write (int fd, void *buf, int nbytes); diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c b/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c index 6a9ec92..bd0d458a 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c @@ -1,4 +1,5 @@ - /* { dg-additional-options "-fanalyzer-verbose-state-changes" } */ +/* { dg-additional-options "-fno-exceptions" } */ +/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */ int open(const char *, int mode); void close(int fd); @@ -34,4 +35,4 @@ void test_3 (const char* path) close(fd); /* { dg-message "meaning: \\{verb: 'release', noun: 'resource'\\}" } */ close(fd); /* { dg-warning "double 'close' of file descriptor 'fd' \\\[CWE-1341\\\]" } */ } -}
\ No newline at end of file +} diff --git a/gcc/testsuite/c-c++-common/analyzer/file-1.c b/gcc/testsuite/c-c++-common/analyzer/file-1.c index 316cbb3..e87cf73 100644 --- a/gcc/testsuite/c-c++-common/analyzer/file-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/file-1.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + typedef struct FILE FILE; FILE* fopen (const char*, const char*); diff --git a/gcc/testsuite/c-c++-common/analyzer/file-3.c b/gcc/testsuite/c-c++-common/analyzer/file-3.c index 8f93a98..ca992bf 100644 --- a/gcc/testsuite/c-c++-common/analyzer/file-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/file-3.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + typedef struct _IO_FILE FILE; extern struct _IO_FILE *stderr; diff --git a/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c b/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c index 66b72a7..c9aee5e 100644 --- a/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c @@ -1,3 +1,4 @@ +/* { dg-additional-options "-fno-exceptions" } */ /* { dg-additional-options "-fanalyzer-verbose-state-changes" } */ typedef struct FILE FILE; diff --git a/gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c b/gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c new file mode 100644 index 0000000..d22a5b5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +void * +get_from_hard_reg (void) +{ + register void *sp asm ("sp"); + return sp; +} diff --git a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c index 6b7d25c..bbbb68e 100644 --- a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c +++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + extern void marker_A(void); extern void marker_B(void); extern void marker_C(void); diff --git a/gcc/testsuite/c-c++-common/analyzer/leak-3.c b/gcc/testsuite/c-c++-common/analyzer/leak-3.c index a386d88..19d7501 100644 --- a/gcc/testsuite/c-c++-common/analyzer/leak-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/leak-3.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c b/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c index 8653c67..c296061 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c b/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c index e7179f0..0d86801 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> #include "../../gcc.dg/analyzer/analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c b/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c index 6ee30f3..5daa696 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c index f03f978..4a1870d 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdio.h> #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c index 766bbe7..12b93b2 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c index 77e3e02..8af84ed 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c @@ -1,3 +1,4 @@ +/* { dg-additional-options "-fno-exceptions" } */ /* { dg-additional-options "-fanalyzer-transitivity" } */ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c index 4e40833..ffb0ffe 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c @@ -1,3 +1,4 @@ +/* { dg-additional-options "-fno-exceptions" } */ /* { dg-additional-options "-fno-analyzer-call-summaries -fanalyzer-transitivity" } */ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c index 36ec510..052b401 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c index 70b3edd..258706c 100644 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/paths-7.c b/gcc/testsuite/c-c++-common/analyzer/paths-7.c index 2743de5..f7c5cbf 100644 --- a/gcc/testsuite/c-c++-common/analyzer/paths-7.c +++ b/gcc/testsuite/c-c++-common/analyzer/paths-7.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/pr110830.c b/gcc/testsuite/c-c++-common/analyzer/pr110830.c index f5a39b7..ebfd38d 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr110830.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr110830.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + typedef __SIZE_TYPE__ size_t; void free(void *); diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c b/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c index 4a08f0f1..e389e43 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c @@ -1,4 +1,5 @@ /* { dg-do "compile" } */ +/* { dg-additional-options "-fno-exceptions" } */ /* Minimal replacement of system headers. */ #define NULL ((void *) 0) diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c index 50d3388..19a3023 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c @@ -3,6 +3,7 @@ Adapted from intl/localealias.c, with all #includes removed. */ /* { dg-do "compile" } */ +/* { dg-additional-options "-fno-exceptions" } */ /* Handle aliases for locale names. Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc. diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c index 6f65add..45517468 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c @@ -3,6 +3,7 @@ Adapted from intl/localealias.c, with all #includes removed. */ /* { dg-do "compile" } */ +/* { dg-additional-options "-fno-exceptions" } */ /* Handle aliases for locale names. Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc. diff --git a/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c b/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c index b20630b..fb194ad 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c @@ -1,4 +1,5 @@ /* { dg-additional-options "-O2 -fanalyzer-transitivity" } */ +/* { dg-additional-options "-fno-exceptions" } */ int *wf; diff --git a/gcc/testsuite/c-c++-common/analyzer/pr97072.c b/gcc/testsuite/c-c++-common/analyzer/pr97072.c index 4024124..82411a1 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr97072.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr97072.c @@ -1,4 +1,4 @@ -void unknown_fn_1 (void *); +void unknown_fn_1 (void *) __attribute__((nothrow)); void test_1 (int co, int y) { diff --git a/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c b/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c index 6472e76..b8ddf77c 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c @@ -4,7 +4,7 @@ void **g; -extern void unknown_fn (void); +extern void unknown_fn (void) __attribute__((nothrow)); /* Without a call to unknown_fn. */ diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c index 41be8ca..60f3a598 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + typedef struct FILE FILE; FILE* fopen (const char*, const char*); diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c index ef7cc5f..caf5c86 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib rand" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ /* Reduced from https://github.com/libguestfs/libguestfs/blob/e0a11061035d47b118c95706240bcc17fd576edc/tests/mount-local/test-parallel-mount-local.c#L299-L335 diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c index 414d57e..98f656f 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/pragma-2.c b/gcc/testsuite/c-c++-common/analyzer/pragma-2.c index bd96a25..f309876 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pragma-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/pragma-2.c @@ -1,6 +1,7 @@ /* { dg-skip-if "" { powerpc*-*-aix* } } */ /* Verify that we can disable -Wanalyzer-too-complex via pragmas. */ /* { dg-additional-options "-Wanalyzer-too-complex -Werror=analyzer-too-complex -fno-analyzer-state-merge -g" } */ +/* { dg-additional-options "-fno-exceptions" } */ /* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */ #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c b/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c index 9f6ccb6..9606044 100644 --- a/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c +++ b/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + #include <stdio.h> #define INI_MAX_LINE 200 diff --git a/gcc/testsuite/c-c++-common/analyzer/strndup-1.c b/gcc/testsuite/c-c++-common/analyzer/strndup-1.c index 3f90afe..915f220 100644 --- a/gcc/testsuite/c-c++-common/analyzer/strndup-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/strndup-1.c @@ -1,6 +1,7 @@ /* { dg-skip-if "no strndup in libc" { *-*-darwin[789]* *-*-darwin10* hppa*-*-hpux* *-*-mingw* *-*-vxworks* } } */ /* { dg-additional-options "-D_POSIX_C_SOURCE=200809L" } */ /* { dg-skip-if "requires hosted libstdc++ for stdlib free" { ! hostedlib } } */ +/* { dg-additional-options "-fno-exceptions" } */ #include <string.h> #include <stdlib.h> diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c index 868c393..1aa4159e 100644 --- a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c @@ -2,6 +2,7 @@ region_model_context_decorator::add_note. */ /* { dg-additional-options "-Wno-analyzer-write-to-string-literal" } */ +/* { dg-additional-options "-fno-exceptions" } */ typedef __SIZE_TYPE__ size_t; diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c index 971e8f3..b60fba0 100644 --- a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-fno-exceptions" } */ + typedef __SIZE_TYPE__ size_t; int getrandom (void *__buffer, size_t __length, /* { dg-line getrandom } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c index 2ecad8c..78b2204 100644 --- a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c @@ -2,6 +2,7 @@ notes) works. */ /* { dg-additional-options "-fanalyzer-show-duplicate-count" } */ +/* { dg-additional-options "-fno-exceptions" } */ #include "../../gcc.dg/analyzer/analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/zlib-5.c b/gcc/testsuite/c-c++-common/analyzer/zlib-5.c index 1e3746d..fa82e43 100644 --- a/gcc/testsuite/c-c++-common/analyzer/zlib-5.c +++ b/gcc/testsuite/c-c++-common/analyzer/zlib-5.c @@ -1,4 +1,5 @@ /* { dg-additional-options "-O3" } */ +/* { dg-additional-options "-fno-exceptions" } */ #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c b/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c new file mode 100644 index 0000000..734da21 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/pragma-diagnostic-loc-2.c @@ -0,0 +1,15 @@ +/* PR c/118838 */ +/* { dg-do compile } */ +/* { dg-additional-options "-Wunknown-pragmas" } */ + +/* Make sure the warnings are suppressed as expected. */ + +/* The tokens need to be all on the same line here. */ +_Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic ignored \"-Wunknown-pragmas\"") _Pragma ("__unknown__") _Pragma ("GCC diagnostic pop") + +#define MACRO \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wunknown-pragmas\"") \ + _Pragma ("__unknown__") \ + _Pragma ("GCC diagnostic pop") +MACRO diff --git a/gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C new file mode 100644 index 0000000..4671e62 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C @@ -0,0 +1,37 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +extern void do_something (); +extern void do_something_nothrow () __attribute__ ((nothrow));; + +int test () +{ + try + { + do_something (); + } + catch (int i) + { + int j = i; + __analyzer_eval (i == 42); // { dg-warning "UNKNOWN" } + __analyzer_eval (i == j); // { dg-warning "TRUE" } + __analyzer_dump_path (); // { dg-message "path" } + return 1; + } + __analyzer_dump_path (); // { dg-message "path" } + return 0; +} + +int test_nothrow () +{ + try + { + do_something_nothrow (); + } + catch (int i) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + __analyzer_dump_path (); // { dg-message "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C new file mode 100644 index 0000000..6572113 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C @@ -0,0 +1,32 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +extern void do_something (); + +int test () +{ + try + { + do_something (); + } + catch (const io_error &err) + { + __analyzer_dump_path (); // { dg-message "path" } + return 1; + } + catch (const value_error &err) + { + __analyzer_dump_path (); // { dg-message "path" } + return 2; + } + catch (const runtime_error &err) + { + __analyzer_dump_path (); // { dg-message "path" } + return 3; + } + __analyzer_dump_path (); // { dg-message "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C b/gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C new file mode 100644 index 0000000..9847203 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C @@ -0,0 +1,62 @@ +// Tests of dynamic exception specifications +// { dg-require-effective-target c++14_down } +// { dg-prune-output "dynamic exception specifications are deprecated" } + +struct io_error {}; +struct file_io_error : public io_error {}; +struct mem_error {}; + +// Valid intraprocedural: + +void test_1 (int flag) throw (io_error) +{ + if (flag) + throw io_error(); +} + +// Invalid intraprocedural: + +void test_2 (int flag) throw (io_error) // { dg-warning "throwing exception of unexpected type 'mem_error' from 'test_2'" } +// { dg-message "exception of unexpected type 'mem_error' thrown from 'test_2'" "" { target *-*-* } .-1 } +// { dg-message "'test_2' declared here" "" { target *-*-* } .-2 } +{ + if (flag) + throw mem_error(); // { dg-message "throwing exception of type 'mem_error' here\.\.\." } +} + +// Valid intraprocedural with subclass: + +void test_3 (int flag) throw (io_error) // { dg-bogus "throwing exception of unexpected type 'file_io_error' from 'test_3'" "PR analyzer/119697" { xfail *-*-* } } +{ + if (flag) + throw file_io_error(); +} + +// Valid interprocedural: + +void test_4_inner (int flag) +{ + if (flag) + throw io_error (); +} + +void test_4_outer (int flag) throw (io_error) +{ + test_4_inner (flag); +} + +// Invalid interprocedural: + +void test_5_inner (int flag) +{ + if (flag) + throw mem_error (); // { dg-message "throwing exception of type 'mem_error' here\.\.\." } + // { dg-message "unwinding stack frame" "" { target *-*-* } .-1 } +} + +void test_5_outer (int flag) throw (io_error) // { dg-warning "throwing exception of unexpected type 'mem_error' from 'test_5_outer'" } +// { dg-message "exception of unexpected type 'mem_error' thrown from 'test_5_outer'" "" { target *-*-* } .-1 } +// { dg-message "'test_5_outer' declared here" "" { target *-*-* } .-2 } +{ + test_5_inner (flag); +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-1.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-1.C new file mode 100644 index 0000000..25467ea --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-1.C @@ -0,0 +1,8 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" } + + throw 42; // { dg-warning "leak of 'ptr'" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-2.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-2.C new file mode 100644 index 0000000..0e0eef8 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-2.C @@ -0,0 +1,18 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" } + + try + { + throw 42; + } + catch (int i) // { dg-message "\.\.\.catching exception of type 'int' here" } + { + return -1; + } // { dg-warning "leak of 'ptr'" } + + __builtin_free (ptr); + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-3.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-3.C new file mode 100644 index 0000000..3684d66 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-3.C @@ -0,0 +1,12 @@ +extern void do_something (); + +int test () +{ + void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" } + + do_something (); // { dg-message "if 'void do_something\\(\\)' throws an exception\.\.\." } + // { dg-warning "leak of 'ptr'" "" { target *-*-* } .-1 } + + __builtin_free (ptr); + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-4.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-4.C new file mode 100644 index 0000000..7280d32 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-4.C @@ -0,0 +1,16 @@ +static void +do_something (int flag) +{ + if (flag) + throw 42; // { dg-warning "leak of 'ptr'" } +} + +int test (int flag) +{ + void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" } + + do_something (flag); + + __builtin_free (ptr); + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-5.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-5.C new file mode 100644 index 0000000..d99e53c --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-5.C @@ -0,0 +1,51 @@ +/* Verify that we detect a leak when unwinding multiple frames. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +int inner (int flag) +{ + if (flag) + throw value_error (); // { dg-warning "leak" } + // { dg-message "throwing exception of type 'value_error' here\.\.\." "" { target *-*-* } .-1 } + + return 0; +} + +int __analyzer_middle (int flag) +{ + void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" } + + int rval = inner (flag); + + __builtin_free (ptr); + + return rval; +} + +int outer () +{ + try + { + __analyzer_middle (1); + } + catch (const io_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + catch (const value_error &err) + { + return 2; + } + catch (const runtime_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 3; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-6.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-6.C new file mode 100644 index 0000000..cb70230 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-6.C @@ -0,0 +1,22 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +extern void do_something (int x); + +int inner (int x) +{ + do_something (x); // { dg-warning "leak" } + // { dg-message "if 'void do_something\\(int\\)' throws an exception\.\.\." "" { target *-*-* } .-1 } + + return 0; +} + +int outer (int x) +{ + void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" } + + int rval = inner (x); + + __builtin_free (ptr); + + return rval; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-nothrow.C b/gcc/testsuite/g++.dg/analyzer/exception-nothrow.C new file mode 100644 index 0000000..9625748 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-nothrow.C @@ -0,0 +1,26 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +extern void do_something () __attribute__((nothrow)); + +/* A wrapper function to stop the try/catch being optimized away. */ + +void wrapper () __attribute__((noinline)); +void wrapper () +{ + do_something (); +} + +int test () +{ + try + { + wrapper (); + } + catch (int i) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + __analyzer_dump_path (); // { dg-message "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-1.C b/gcc/testsuite/g++.dg/analyzer/exception-path-1.C new file mode 100644 index 0000000..486ca193 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-1.C @@ -0,0 +1,34 @@ +/* Verify that we follow the correct paths when we know the typeinfo of + an exception. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +int test () +{ + try + { + throw value_error (); // { dg-message "\\(1\\) throwing exception of type 'value_error' here..." } + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (const io_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + catch (const value_error &err) // { dg-message "\\(2\\) \.\.\.catching exception of type 'value_error' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + return 2; + } + catch (const runtime_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 3; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C new file mode 100644 index 0000000..8aa9814 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C @@ -0,0 +1,16 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + try + { + throw 42; + } + catch (...) + { + __analyzer_dump_path (); + return -1; + } + __analyzer_dump_path (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C new file mode 100644 index 0000000..d185056 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C @@ -0,0 +1,22 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + try + { + throw 42; // { dg-message "throwing exception of type 'int' here\.\.\." } + } + catch (int i) // { dg-message "\.\.\.catching exception of type 'int' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + __analyzer_eval (i == 42); // { dg-warning "TRUE" } + return -2; + } + catch (...) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return -1; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C new file mode 100644 index 0000000..2608f17 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C @@ -0,0 +1,55 @@ +/* Verify that we follow the correct paths when we know the typeinfo of + an exception: interprocedural case where unwind multiple frame, + failing to match the type. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +int inner (int flag) +{ + if (flag) + throw value_error (); // { dg-message "throwing exception of type 'value_error' here..." } + // { dg-message "unwinding 2 stack frames" "" { target *-*-* } .-1 } + + return 0; +} + +int middle (int flag) +{ + try + { + return inner (flag); + } + catch (const io_error &err) // this shouldn't be matched + { + return -1; + } +} + +int outer () +{ + try + { + middle (1); + } + catch (const io_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + catch (const value_error &err) // { dg-message "\.\.\.catching exception of type 'value_error' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + return 2; + } + catch (const runtime_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 3; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C new file mode 100644 index 0000000..a52312a --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C @@ -0,0 +1,48 @@ +/* Verify that we follow the correct paths when we know the typeinfo of + an exception: interprocedural case where we unwind one frame. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +int inner (int flag) +{ + if (flag) + throw value_error (); // { dg-message "throwing exception of type 'value_error' here..." } + + return 0; +} + +int middle (int flag) +{ + return inner (flag); +} + +int outer () +{ + try + { + middle (1); + } + catch (const io_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + catch (const value_error &err) // { dg-message "\.\.\.catching exception of type 'value_error' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + return 2; + } + catch (const runtime_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 3; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} + +// TODO: test coverage for unwinding stack frame events diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C new file mode 100644 index 0000000..055fe27 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C @@ -0,0 +1,43 @@ +/* Verify that we follow the correct paths when we know the typeinfo of + an exception: interprocedural case where we unwind two frames. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +int inner (int flag) +{ + if (flag) + throw value_error (); // { dg-message "throwing exception of type 'value_error' here..." } + + return 0; +} + +int outer () +{ + try + { + inner (1); + } + catch (const io_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 1; + } + catch (const value_error &err) // { dg-message "\.\.\.catching exception of type 'value_error' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + return 2; + } + catch (const runtime_error &err) + { + __analyzer_dump_path (); // { dg-bogus "path" } + return 3; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} + +// TODO: test coverage for unwinding stack frame events diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C b/gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C new file mode 100644 index 0000000..fc18a21 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C @@ -0,0 +1,27 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct foo +{ + foo (int x) : m_x (x) {} + ~foo () __attribute__((nothrow)); + + int m_x; +}; + +int test (bool flag) +{ + foo outside (1); + try + { + foo inside_try (2); + if (flag) + throw foo (3); // { dg-message "throwing exception of type 'foo' here\.\.\." } + } + catch (foo &f) // { dg-message "\.\.\.catching exception of type 'foo' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + __analyzer_eval (f.m_x == 3); // { dg-warning "TRUE" } + return f.m_x; + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C new file mode 100644 index 0000000..10484fd --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C @@ -0,0 +1,13 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + try + { + throw 42; + } + catch (...) + { + throw; + } +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C new file mode 100644 index 0000000..22242a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C @@ -0,0 +1,25 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + try + { + try + { + throw 42; // { dg-message "\\(1\\) throwing exception of type 'int' here\.\.\." } + } + catch (...) // { dg-message "\\(2\\) \.\.\.catching exception of type 'int' here" } + { + throw; // { dg-message "\\(3\\) rethrowing exception of type 'int' here\.\.\." } + } + } + catch (int i) // { dg-message "\\(4\\) \.\.\.catching exception of type 'int' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + __analyzer_eval (i == 42); // { dg-warning "TRUE" } + return -1; + } + + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-stack-1.C b/gcc/testsuite/g++.dg/analyzer/exception-stack-1.C new file mode 100644 index 0000000..c6aa415 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-stack-1.C @@ -0,0 +1,35 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +void test (void) +{ + try + { + try + { + throw 42; + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (...) + { + try + { + throw 1066; // throw an inner exception + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (int i) + { + __analyzer_eval (i == 1066); // { dg-warning "TRUE" } + } + throw; // rethrow the outer exception + __analyzer_dump_path (); // { dg-bogus "path" } + } + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (int j) + { + __analyzer_eval (j == 42); // { dg-warning "TRUE" } + __analyzer_dump_path (); // { dg-message "path" } + throw; + } + __analyzer_dump_path (); // { dg-bogus "path" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-stack-2.C b/gcc/testsuite/g++.dg/analyzer/exception-stack-2.C new file mode 100644 index 0000000..5e6a3c0 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-stack-2.C @@ -0,0 +1,44 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct io_error {}; +struct value_error {}; +struct runtime_error {}; + +void test (void) +{ + try + { + try + { + throw value_error (); // { dg-message "\\(1\\) throwing exception of type 'value_error' here..." } + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (...) // { dg-message "\\(2\\) \.\.\.catching exception of type 'value_error' here" } + { + try + { + throw io_error (); // { dg-message "\\(3\\) throwing exception of type 'io_error' here..." } + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (const io_error &err) // { dg-message "\\(4\\) \.\.\.catching exception of type 'io_error' here" } + { + /* discard it */ + } + + // rethrow the outer exception + throw; // { dg-message "\\(5\\) rethrowing exception of type 'value_error' here..." } + __analyzer_dump_path (); // { dg-bogus "path" } + } + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (const value_error &err) // { dg-message "\\(6\\) \.\.\.catching exception of type 'value_error' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + throw; + } + catch (...) + { + __analyzer_dump_path (); // { dg-bogus "path" } + } + __analyzer_dump_path (); // { dg-bogus "path" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C b/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C new file mode 100644 index 0000000..79df330 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C @@ -0,0 +1,21 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +class exception +{ +}; + +class io_error : public exception +{ +}; + +int test () +{ + try { + throw io_error(); + } catch (exception &exc) { + __analyzer_dump_path (); // { dg-message "path" "PR analyzer/119697" { xfail *-*-* } } + return -1; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C b/gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C new file mode 100644 index 0000000..e9fb617 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C @@ -0,0 +1,25 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +class exception +{ +}; + +class io_error : public exception +{ +}; + +int __analyzer_inner () +{ + try { + throw io_error(); + } catch (exception &exc) { + return -1; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} + +int test () +{ + return __analyzer_inner (); // { dg-message "path" "PR analyzer/119697" { xfail *-*-* } } +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-value-1.C b/gcc/testsuite/g++.dg/analyzer/exception-value-1.C new file mode 100644 index 0000000..0d06dd8 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-value-1.C @@ -0,0 +1,20 @@ +/* Verify that we can access values in exceptions. */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +int test () +{ + try + { + throw 42; // { dg-message "\\(1\\) throwing exception of type 'int' here..." } + __analyzer_dump_path (); // { dg-bogus "path" } + } + catch (int i) // { dg-message "\\(2\\) \.\.\.catching exception of type 'int' here" } + { + __analyzer_dump_path (); // { dg-message "path" } + __analyzer_eval (i == 42); // { dg-warning "TRUE" } + return 1; + } + __analyzer_dump_path (); // { dg-bogus "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/exception-value-2.C b/gcc/testsuite/g++.dg/analyzer/exception-value-2.C new file mode 100644 index 0000000..ef9dd46 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/exception-value-2.C @@ -0,0 +1,36 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct foo {}; + +int inner (bool flag) +{ + try + { + if (flag) + throw 42; + } + catch (foo &f) + { + return 1; + } + return 0; +} + +int middle (bool flag) +{ + try + { + int rval = inner (flag); + return rval; + } + catch (int ei) + { + return ei; + } +} + +void outer (void) +{ + __analyzer_eval (middle (false) == 0); // { dg-warning "TRUE" } + __analyzer_eval (middle (true) == 42); // { dg-warning "TRUE" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/fno-exception.C b/gcc/testsuite/g++.dg/analyzer/fno-exception.C new file mode 100644 index 0000000..2ec4e06e2 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/fno-exception.C @@ -0,0 +1,12 @@ +/* { dg-additional-options "-fno-exceptions" } */ + +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +extern void do_something (); + +int test () +{ + do_something (); + __analyzer_dump_path (); // { dg-message "path" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-1.C b/gcc/testsuite/g++.dg/analyzer/nrvo-1.C new file mode 100644 index 0000000..146b80a --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/nrvo-1.C @@ -0,0 +1,18 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +struct s1 +{ + s1 (int x) : m_x (x) {} + int m_x; +}; + +s1 make_s1 (int x) +{ + return s1 (x); +} + +void test_1 (int x) +{ + s1 s = make_s1 (x); + __analyzer_eval (s.m_x == x); // { dg-warning "TRUE" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-2.C b/gcc/testsuite/g++.dg/analyzer/nrvo-2.C new file mode 100644 index 0000000..e0567c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/nrvo-2.C @@ -0,0 +1,26 @@ +#include "../../gcc.dg/analyzer/analyzer-decls.h" + +// { dg-do compile { target c++11 } } + +struct s1 +{ + int t; + s1() { t = 42; } + s1(const s1& other) { t = other.t; } +}; + +s1 inner() +{ + return s1{}; // { dg-bogus "uninitialized" } +} + +s1 middle() +{ + return inner(); +} + +void outer() +{ + s1 obj = middle(); + __analyzer_eval (obj.t == 42); // { dg-warning "TRUE" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C new file mode 100644 index 0000000..de447ae --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C @@ -0,0 +1,11 @@ +struct Guard { + int i; + ~Guard() {} +}; +Guard lock() { + return Guard(); // { dg-bogus "uninitialized" } +} +void bar() { + Guard foo = lock(); +} + diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C new file mode 100644 index 0000000..681795d --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } + +struct Guard { + int i; + ~Guard() {} +}; +Guard lock() { + return Guard(); // { dg-bogus "uninitialized" } +} +void bar() { + auto foo = lock(); +} diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C new file mode 100644 index 0000000..aa011e2 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C @@ -0,0 +1,10 @@ +struct g +{ + int t; + g(); +}; + +g foo1() +{ + return g(); // { dg-bogus "uninitialized" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C new file mode 100644 index 0000000..31df5a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } + +struct g +{ + int t; + g(); + g(const g&); +}; + +g foo1() +{ + return g{}; // { dg-bogus "uninitialized" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/pr94028.C b/gcc/testsuite/g++.dg/analyzer/pr94028.C index 0573d30..53bfa29 100644 --- a/gcc/testsuite/g++.dg/analyzer/pr94028.C +++ b/gcc/testsuite/g++.dg/analyzer/pr94028.C @@ -19,7 +19,7 @@ struct j throw() #endif { - return calloc (b, sizeof (int)); // { dg-bogus "leak" "" { xfail c++98_only } } + return calloc (b, sizeof (int)); } j (B *, int) { diff --git a/gcc/testsuite/g++.dg/analyzer/std-unexpected.C b/gcc/testsuite/g++.dg/analyzer/std-unexpected.C new file mode 100644 index 0000000..4eb2672 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/std-unexpected.C @@ -0,0 +1,9 @@ +// { dg-require-effective-target c++14_down } +// { dg-additional-options "-Wno-deprecated-declarations" } + +#include <exception> + +void test_1 () +{ + std::unexpected (); +} diff --git a/gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C b/gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C new file mode 100644 index 0000000..cc9cf71 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C @@ -0,0 +1,13 @@ +// Verify that we complain about trivial uses of NULL unique_ptr. + +// { dg-do compile { target c++11 } } + +#include <memory> + +struct A {int x; int y;}; + +int main() { + std::unique_ptr<A> a; + a->x = 12; // { dg-warning "dereference of NULL" } + return 0; +} diff --git a/gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C b/gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C new file mode 100644 index 0000000..e8d3e7e --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-analyzer-too-complex" } */ + +#include <memory> + +struct A {int x; int y;}; + +extern std::unique_ptr<A> make_ptr (); + +int test (int flag) { + std::unique_ptr<A> a; + if (flag) + a = make_ptr (); + a->x = 12; // { dg-warning "dereference of NULL" "" { xfail *-*-*} } + // TODO: this is failing due to "too complex" warnings + return 0; +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr105287.C b/gcc/testsuite/g++.dg/coroutines/pr105287.C index c54d1fd..0436572 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr105287.C +++ b/gcc/testsuite/g++.dg/coroutines/pr105287.C @@ -1,5 +1,5 @@ // { dg-additional-options "-fanalyzer" } -// { dg-excess-errors "lots of analyzer output, but no ICE" } + namespace std { template <typename _Result> struct coroutine_traits : _Result {}; template <typename = void> struct coroutine_handle { diff --git a/gcc/testsuite/g++.dg/gomp/macro-4.C b/gcc/testsuite/g++.dg/gomp/macro-4.C index dcc8bcb..5aa6d97 100644 --- a/gcc/testsuite/g++.dg/gomp/macro-4.C +++ b/gcc/testsuite/g++.dg/gomp/macro-4.C @@ -3,7 +3,7 @@ // { dg-options "-fopenmp -Wunknown-pragmas" } #define p _Pragma ("omp parallel") -#define omp_p _Pragma ("omp p") +#define omp_p _Pragma ("omp p") // { dg-warning "ignoring '#pragma omp _Pragma'" } void bar (void); @@ -12,18 +12,18 @@ foo (void) { #pragma omp p // { dg-warning "-:ignoring '#pragma omp _Pragma'" } bar (); - omp_p // { dg-warning "-:ignoring '#pragma omp _Pragma'" } + omp_p // { dg-note "in expansion of macro 'omp_p'" } bar (); } #define parallel serial -#define omp_parallel _Pragma ("omp parallel") +#define omp_parallel _Pragma ("omp parallel") // { dg-warning "ignoring '#pragma omp serial'" } void baz (void) { #pragma omp parallel // { dg-warning "-:ignoring '#pragma omp serial'" } bar (); - omp_parallel // { dg-warning "-:ignoring '#pragma omp serial'" } + omp_parallel // { dg-note "in expansion of macro 'omp_parallel'" } bar (); } diff --git a/gcc/testsuite/g++.dg/modules/concept-11_a.H b/gcc/testsuite/g++.dg/modules/concept-11_a.H new file mode 100644 index 0000000..4512768 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/concept-11_a.H @@ -0,0 +1,9 @@ +// PR c++/119939 +// { dg-additional-options "-fmodule-header -std=c++20" } +// { dg-module-cmi {} } + +template <typename T> concept A = true; +template <typename T> concept B = requires { T{}; }; +template <typename T> struct S { + friend bool operator==(const S&, const S&) requires B<T> = default; +}; diff --git a/gcc/testsuite/g++.dg/modules/concept-11_b.C b/gcc/testsuite/g++.dg/modules/concept-11_b.C new file mode 100644 index 0000000..3f6676f --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/concept-11_b.C @@ -0,0 +1,9 @@ +// PR c++/119939 +// { dg-additional-options "-fmodules -std=c++20" } + +import "concept-11_a.H"; + +int main() { + S<int> s; + s == s; +} diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr100038.C b/gcc/testsuite/g++.dg/tree-ssa/pr100038.C new file mode 100644 index 0000000..7024c4d --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr100038.C @@ -0,0 +1,17 @@ +// { dg-do compile } +// { dg-options "-O2 -Wextra -Wall -Warray-bounds" } + +struct SparseBitVectorElement { + long Bits[2]; + int find_first() const; +}; + +// we should not get an `array subscript 2 is above array bounds of` +// warning here because we have an unreachable at that point + +int SparseBitVectorElement::find_first() const { + for (unsigned i = 0; i < 2; ++i) + if (Bits[i]) // { dg-bogus "is above array bounds of" } + return i; + __builtin_unreachable(); +} diff --git a/gcc/testsuite/g++.target/i386/pr109780-1.C b/gcc/testsuite/g++.target/i386/pr109780-1.C new file mode 100644 index 0000000..7e3eabd --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr109780-1.C @@ -0,0 +1,72 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target c++17 } */ +/* { dg-options "-O2 -mavx2 -mtune=haswell" } */ + +template <typename _Tp> struct remove_reference { + using type = __remove_reference(_Tp); +}; +template <typename T> struct MaybeStorageBase { + T val; + struct Union { + ~Union(); + } mStorage; +}; +template <typename T> struct MaybeStorage : MaybeStorageBase<T> { + char mIsSome; +}; +template <typename T, typename U = typename remove_reference<T>::type> +constexpr MaybeStorage<U> Some(T &&); +template <typename T, typename U> constexpr MaybeStorage<U> Some(T &&aValue) { + return {aValue}; +} +template <class> struct Span { + int operator[](long idx) { + int *__trans_tmp_4; + if (__builtin_expect(idx, 0)) + *(int *)__null = false; + __trans_tmp_4 = storage_.data(); + return __trans_tmp_4[idx]; + } + struct { + int *data() { return data_; } + int *data_; + } storage_; +}; +struct Variant { + template <typename RefT> Variant(RefT) {} +}; +long from_i, from___trans_tmp_9; +namespace js::intl { +struct DecimalNumber { + Variant string_; + unsigned long significandStart_; + unsigned long significandEnd_; + bool zero_ = false; + bool negative_; + template <typename CharT> DecimalNumber(CharT string) : string_(string) {} + template <typename CharT> + static MaybeStorage<DecimalNumber> from(Span<const CharT>); + void from(); +}; +} // namespace js::intl +void js::intl::DecimalNumber::from() { + Span<const char16_t> __trans_tmp_3; + from(__trans_tmp_3); +} +template <typename CharT> +MaybeStorage<js::intl::DecimalNumber> +js::intl::DecimalNumber::from(Span<const CharT> chars) { + DecimalNumber number(chars); + if (auto ch = chars[from_i]) { + from_i++; + number.negative_ = ch == '-'; + } + while (from___trans_tmp_9 && chars[from_i]) + ; + if (chars[from_i]) + while (chars[from_i - 1]) + number.zero_ = true; + return Some(number); +} + +/* { dg-final { scan-assembler-not "and\[lq\]?\[^\\n\]*-32,\[^\\n\]*sp" } } */ diff --git a/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c b/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c index 06a244e..f3c7901 100644 --- a/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c +++ b/gcc/testsuite/gcc.dg/cpp/Wunknown-pragmas-1.c @@ -8,21 +8,25 @@ #pragma unknown1 /* { dg-warning "-:unknown1" "unknown1" } */ #define COMMA , -#define FOO(x) x -#define BAR(x) _Pragma("unknown_before") x -#define BAZ(x) x _Pragma("unknown_after") +#define FOO(x) x /* { dg-note "in definition of macro 'FOO'" } */ -int _Pragma("unknown2") bar1; /* { dg-warning "-:unknown2" "unknown2" } */ +#define BAR1(x) _Pragma("unknown_before1") x /* { dg-warning "unknown_before1" } */ +#define BAR2(x) _Pragma("unknown_before2") x /* { dg-warning "unknown_before2" } */ -FOO(int _Pragma("unknown3") bar2); /* { dg-warning "-:unknown3" "unknown3" } */ +#define BAZ1(x) x _Pragma("unknown_after1") /* { dg-warning "unknown_after1" } */ +#define BAZ2(x) x _Pragma("unknown_after2") /* { dg-warning "unknown_after2" } */ -int BAR(bar3); /* { dg-warning "-:unknown_before" "unknown_before 1" } */ +int _Pragma("unknown2") bar1; /* { dg-warning "unknown2" "unknown2" } */ -BAR(int bar4); /* { dg-warning "-:unknown_before" "unknown_before 2" } */ +FOO(int _Pragma("unknown3") bar2); /* { dg-warning "unknown3" "unknown3" } */ -int BAZ(bar5); /* { dg-warning "-:unknown_after" "unknown_after 1" } */ +int BAR1(bar3); /* { dg-note "in expansion of macro 'BAR1'" } */ -int BAZ(bar6;) /* { dg-warning "-:unknown_after" "unknown_after 2" } */ +BAR2(int bar4); /* { dg-note "in expansion of macro 'BAR2'" } */ + +int BAZ1(bar5); /* { dg-note "in expansion of macro 'BAZ1'" } */ + +int BAZ2(bar6;) /* { dg-note "in expansion of macro 'BAZ2'" } */ FOO(int bar7; _Pragma("unknown4")) /* { dg-warning "-:unknown4" "unknown4" } */ diff --git a/gcc/testsuite/gcc.dg/gimplefe-57.c b/gcc/testsuite/gcc.dg/gimplefe-57.c new file mode 100644 index 0000000..d3eca56 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-57.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int __GIMPLE +foo (int a, int b) +{ + int tem; + tem = a __ROTATE_LEFT b; + tem = tem __ROTATE_RIGHT b; + return tem; +} diff --git a/gcc/testsuite/gcc.dg/gomp/macro-4.c b/gcc/testsuite/gcc.dg/gomp/macro-4.c index a4ed9a3..961c599 100644 --- a/gcc/testsuite/gcc.dg/gomp/macro-4.c +++ b/gcc/testsuite/gcc.dg/gomp/macro-4.c @@ -3,7 +3,7 @@ /* { dg-options "-fopenmp -Wunknown-pragmas" } */ #define p _Pragma ("omp parallel") -#define omp_p _Pragma ("omp p") +#define omp_p _Pragma ("omp p") /* { dg-warning "ignoring '#pragma omp _Pragma'" } */ void bar (void); @@ -12,18 +12,18 @@ foo (void) { #pragma omp p /* { dg-warning "-:ignoring '#pragma omp _Pragma'" } */ bar (); - omp_p /* { dg-warning "-:ignoring '#pragma omp _Pragma'" } */ + omp_p /* { dg-note "in expansion of macro 'omp_p'" } */ bar (); } #define parallel serial -#define omp_parallel _Pragma ("omp parallel") +#define omp_parallel _Pragma ("omp parallel") /* { dg-warning "ignoring '#pragma omp serial'" } */ void baz (void) { #pragma omp parallel /* { dg-warning "-:ignoring '#pragma omp serial'" } */ bar (); - omp_parallel /* { dg-warning "-:ignoring '#pragma omp serial'" } */ + omp_parallel /* { dg-note "in expansion of macro 'omp_parallel'" } */ bar (); } diff --git a/gcc/testsuite/gcc.dg/graphite/id-15.c b/gcc/testsuite/gcc.dg/graphite/id-15.c index d0a804c..d258ef5 100644 --- a/gcc/testsuite/gcc.dg/graphite/id-15.c +++ b/gcc/testsuite/gcc.dg/graphite/id-15.c @@ -1,7 +1,7 @@ /* { dg-additional-options "-Wno-old-style-definition" } */ /* { dg-require-effective-target int32plus } */ -typedef long unsigned int size_t; +typedef __SIZE_TYPE__ size_t; extern void *memset (void *__s, int __c, size_t __n) __attribute__ ((__nothrow__)) __attribute__ ((__nonnull__ (1))); static void diff --git a/gcc/testsuite/gcc.dg/lto/pr60779_0.c b/gcc/testsuite/gcc.dg/lto/pr60779_0.c new file mode 100644 index 0000000..360cdc9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr60779_0.c @@ -0,0 +1,21 @@ +/* { dg-lto-do link } */ +/* { dg-lto-options { { -O -flto -fdump-tree-optimized } } } */ + +_Complex double bar (_Complex double x, _Complex double y); + +_Complex double foo (_Complex double x, _Complex double y) +{ + return x / y; +} + +volatile double r; + +int main () +{ + _Complex double x = r + 1.0iF * r; + _Complex double y = r + 1.0iF * r; + _Complex double z = foo (x, y); + volatile _Complex double w = bar (z, x); +} + +/* { dg-final { scan-ltrans-tree-dump-times "divdc3" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/lto/pr60779_1.c b/gcc/testsuite/gcc.dg/lto/pr60779_1.c new file mode 100644 index 0000000..caad903 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr60779_1.c @@ -0,0 +1,6 @@ +/* { dg-options "-fcx-limited-range" } */ + +_Complex double bar (_Complex double x, _Complex double y) +{ + return x / y; +} diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc index 467af16..0f1f864 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc @@ -29,7 +29,7 @@ #include "selftest.h" #include "function.h" #include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-language.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" @@ -46,7 +46,6 @@ #include "analyzer/call-details.h" #include "analyzer/call-info.h" #include "analyzer/exploded-graph.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -207,7 +206,7 @@ public: std::unique_ptr<stmt_finder> clone () const final override { - return make_unique<refcnt_stmt_finder> (m_eg, m_var); + return std::make_unique<refcnt_stmt_finder> (m_eg, m_var); } const gimple * @@ -451,8 +450,9 @@ check_refcnt (const region_model *model, const auto &eg = ctxt->get_eg (); refcnt_stmt_finder finder (*eg, reg_tree); - auto pd = make_unique<refcnt_mismatch> (curr_region, ob_refcnt_sval, - actual_refcnt_sval, reg_tree); + auto pd = std::make_unique<refcnt_mismatch> (curr_region, ob_refcnt_sval, + actual_refcnt_sval, + reg_tree); if (pd && eg) ctxt->warn (std::move (pd), &finder); } @@ -680,7 +680,7 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const = old_ptr_sval->dyn_cast_region_svalue ()) { const region *freed_reg = old_reg->get_pointee (); - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, poison_kind::freed); model->unset_dynamic_extents (freed_reg); } @@ -885,7 +885,7 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const model->mark_region_as_unknown (freed_reg, cd.get_uncertainty ()); } - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, poison_kind::freed); model->unset_dynamic_extents (freed_reg); } @@ -943,9 +943,9 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const /* Body of kf_PyList_Append::impl_call_post. */ if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<realloc_failure> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<realloc_success_no_move> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<realloc_success_move> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<realloc_failure> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<realloc_success_no_move> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<realloc_success_move> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1078,8 +1078,8 @@ kf_PyList_New::impl_call_post (const call_details &cd) const if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<pyobj_init_fail> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<pyobj_init_fail> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<success> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1147,8 +1147,8 @@ kf_PyLong_FromLong::impl_call_post (const call_details &cd) const if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<pyobj_init_fail> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<pyobj_init_fail> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<success> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1290,14 +1290,14 @@ cpython_analyzer_init_cb (void *gcc_data, void * /*user_data */) } iface->register_known_function ("PyList_Append", - make_unique<kf_PyList_Append> ()); - iface->register_known_function ("PyList_New", make_unique<kf_PyList_New> ()); + std::make_unique<kf_PyList_Append> ()); + iface->register_known_function ("PyList_New", std::make_unique<kf_PyList_New> ()); iface->register_known_function ("PyLong_FromLong", - make_unique<kf_PyLong_FromLong> ()); + std::make_unique<kf_PyLong_FromLong> ()); iface->register_known_function ( "__analyzer_cpython_dump_refcounts", - make_unique<kf_analyzer_cpython_dump_refcounts> ()); + std::make_unique<kf_analyzer_cpython_dump_refcounts> ()); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc index 77767c8..3cac3f8f 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc @@ -10,14 +10,13 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "make-unique.h" #include "diagnostic.h" #include "tree.h" #include "gimple.h" #include "gimple-iterator.h" #include "gimple-walk.h" #include "diagnostic-event-id.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-logging.h" #include "json.h" #include "analyzer/sm.h" @@ -66,7 +65,7 @@ public: private: void check_for_pyobject_in_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree callee_fndecl) const; public: @@ -147,7 +146,7 @@ public: class double_save_thread : public gil_diagnostic { public: - double_save_thread (const gil_state_machine &sm, const gcall *call) + double_save_thread (const gil_state_machine &sm, const gcall &call) : gil_diagnostic (sm), m_call (call) {} @@ -160,7 +159,7 @@ class double_save_thread : public gil_diagnostic { const double_save_thread &sub_other = (const double_save_thread &)base_other; - return m_call == sub_other.m_call; + return &m_call == &sub_other.m_call; } bool emit (diagnostic_emission_context &ctxt) final override @@ -179,13 +178,13 @@ class double_save_thread : public gil_diagnostic } private: - const gcall *m_call; + const gcall &m_call; }; class fncall_without_gil : public gil_diagnostic { public: - fncall_without_gil (const gil_state_machine &sm, const gcall *call, + fncall_without_gil (const gil_state_machine &sm, const gcall &call, tree callee_fndecl, unsigned arg_idx) : gil_diagnostic (sm), m_call (call), m_callee_fndecl (callee_fndecl), m_arg_idx (arg_idx) @@ -200,7 +199,7 @@ class fncall_without_gil : public gil_diagnostic { const fncall_without_gil &sub_other = (const fncall_without_gil &)base_other; - return (m_call == sub_other.m_call + return (&m_call == &sub_other.m_call && m_callee_fndecl == sub_other.m_callee_fndecl && m_arg_idx == sub_other.m_arg_idx); } @@ -233,7 +232,7 @@ class fncall_without_gil : public gil_diagnostic } private: - const gcall *m_call; + const gcall &m_call; tree m_callee_fndecl; unsigned m_arg_idx; }; @@ -313,21 +312,21 @@ check_for_pyobject (gimple *, tree op, tree, void *data) void gil_state_machine::check_for_pyobject_in_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree callee_fndecl) const { - for (unsigned i = 0; i < gimple_call_num_args (call); i++) + for (unsigned i = 0; i < gimple_call_num_args (&call); i++) { - tree arg = gimple_call_arg (call, i); + tree arg = gimple_call_arg (&call, i); if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) continue; tree type = TREE_TYPE (TREE_TYPE (arg)); if (type_based_on_pyobject_p (type)) { - sm_ctxt.warn (node, call, NULL_TREE, - make_unique<fncall_without_gil> (*this, call, - callee_fndecl, - i)); + sm_ctxt.warn (node, &call, NULL_TREE, + std::make_unique<fncall_without_gil> (*this, call, + callee_fndecl, + i)); sm_ctxt.set_global_state (m_stop); } } @@ -341,8 +340,9 @@ gil_state_machine::on_stmt (sm_context &sm_ctxt, const gimple *stmt) const { const state_t global_state = sm_ctxt.get_global_state (); - if (const gcall *call = dyn_cast <const gcall *> (stmt)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) { + const gcall &call = *call_stmt; if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) { if (is_named_call_p (callee_fndecl, "PyEval_SaveThread", call, 0)) @@ -353,7 +353,7 @@ gil_state_machine::on_stmt (sm_context &sm_ctxt, if (global_state == m_released_gil) { sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<double_save_thread> (*this, call)); + std::make_unique<double_save_thread> (*this, call)); sm_ctxt.set_global_state (m_stop); } else @@ -409,7 +409,7 @@ gil_state_machine::check_for_pyobject_usage_without_gil (sm_context &sm_ctxt, if (type_based_on_pyobject_p (type)) { sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<pyobject_usage_without_gil> (*this, op)); + std::make_unique<pyobject_usage_without_gil> (*this, op)); sm_ctxt.set_global_state (m_stop); } } @@ -425,7 +425,7 @@ gil_analyzer_init_cb (void *gcc_data, void */*user_data*/) if (0) inform (input_location, "got here: gil_analyzer_init_cb"); iface->register_state_machine - (make_unique<gil_state_machine> (iface->get_logger ())); + (std::make_unique<gil_state_machine> (iface->get_logger ())); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc index 7f2158e..771ff75 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc @@ -29,7 +29,7 @@ #include "selftest.h" #include "function.h" #include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" @@ -44,7 +44,6 @@ #include "analyzer/region-model.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -106,7 +105,7 @@ class copy_across_boundary_fn : public known_function if (ctxt) { /* Bifurcate state, creating a "failure" out-edge. */ - ctxt->bifurcate (make_unique<copy_failure> (cd)); + ctxt->bifurcate (std::make_unique<copy_failure> (cd)); /* The "unbifurcated" state is the "success" case. */ copy_success success (cd, @@ -238,11 +237,13 @@ kernel_analyzer_init_cb (void *gcc_data, void */*user_data*/) inform (input_location, "got here: kernel_analyzer_init_cb"); iface->register_known_function ("copy_from_user", - make_unique<known_function_copy_from_user> ()); - iface->register_known_function ("copy_to_user", - make_unique<known_function_copy_to_user> ()); - iface->register_known_function ("__check_object_size", - make_unique<known_function___check_object_size> ()); + std::make_unique<known_function_copy_from_user> ()); + iface->register_known_function + ("copy_to_user", + std::make_unique<known_function_copy_to_user> ()); + iface->register_known_function + ("__check_object_size", + std::make_unique<known_function___check_object_size> ()); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc index c060407..c7087f0 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc @@ -29,7 +29,7 @@ #include "selftest.h" #include "function.h" #include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" @@ -44,7 +44,6 @@ #include "analyzer/region-model.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -168,7 +167,7 @@ public: if (cd.get_ctxt ()) { /* Bifurcate state, creating a "failure" out-edge. */ - cd.get_ctxt ()->bifurcate (make_unique<copy_failure> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<copy_failure> (cd)); /* The "unbifurcated" state is the "success" case. */ copy_success success (cd, @@ -189,11 +188,12 @@ known_fn_analyzer_init_cb (void *gcc_data, void */*user_data*/) LOG_SCOPE (iface->get_logger ()); if (0) inform (input_location, "got here: known_fn_analyzer_init_cb"); - iface->register_known_function ("returns_42", - make_unique<known_function_returns_42> ()); + iface->register_known_function + ("returns_42", + std::make_unique<known_function_returns_42> ()); iface->register_known_function ("attempt_to_copy", - make_unique<known_function_attempt_to_copy> ()); + std::make_unique<known_function_attempt_to_copy> ()); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc index 7e6d7e1..5ec3418 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc @@ -29,7 +29,6 @@ #include "diagnostic.h" #include "diagnostic-format-text.h" #include "context.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -230,7 +229,8 @@ plugin_init (struct plugin_name_args *plugin_info, diagnostic_text_starter (global_dc) = test_diagnostic_text_starter; diagnostic_start_span (global_dc) = test_diagnostic_start_span_fn; - global_dc->set_output_format (::make_unique<test_output_format> (*global_dc)); + global_dc->set_output_format + (::std::make_unique<test_output_format> (*global_dc)); pass_info.pass = new pass_test_groups (g); pass_info.reference_pass_name = "*warn_function_noreturn"; diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc index 2ce267c..24c6f8c 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc @@ -39,7 +39,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-buffer.h" #include "ordered-hash-map.h" #include "sbitmap.h" -#include "make-unique.h" #include "selftest.h" #include "selftest-diagnostic.h" #include "selftest-diagnostic-show-locus.h" @@ -179,7 +178,7 @@ void node_with_children::add_text (label_text str) { gcc_assert (str.get ()); - add_child (::make_unique <text> (std::move (str))); + add_child (std::make_unique <text> (std::move (str))); } @@ -338,7 +337,7 @@ private: static std::unique_ptr<xml::element> make_div (label_text class_) { - auto div = ::make_unique<xml::element> ("div", false); + auto div = std::make_unique<xml::element> ("div", false); div->set_attr ("class", std::move (class_)); return div; } @@ -346,7 +345,7 @@ make_div (label_text class_) static std::unique_ptr<xml::element> make_span (label_text class_) { - auto span = ::make_unique<xml::element> ("span", true); + auto span = std::make_unique<xml::element> ("span", true); span->set_attr ("class", std::move (class_)); return span; } @@ -410,24 +409,24 @@ xhtml_builder::xhtml_builder (diagnostic_context &context, { gcc_assert (m_line_maps); - m_document = ::make_unique<xml::document> (); + m_document = std::make_unique<xml::document> (); { - auto html_element = ::make_unique<xml::element> ("html", false); + auto html_element = std::make_unique<xml::element> ("html", false); html_element->set_attr ("xmlns", label_text::borrow ("http://www.w3.org/1999/xhtml")); { { - auto head_element = ::make_unique<xml::element> ("head", false); + auto head_element = std::make_unique<xml::element> ("head", false); { - auto title_element = ::make_unique<xml::element> ("title", true); + auto title_element = std::make_unique<xml::element> ("title", true); label_text title (label_text::borrow ("Title goes here")); // TODO title_element->add_text (std::move (title)); head_element->add_child (std::move (title_element)); } html_element->add_child (std::move (head_element)); - auto body_element = ::make_unique<xml::element> ("body", false); + auto body_element = std::make_unique<xml::element> ("body", false); { auto diagnostics_element = make_div (label_text::borrow ("gcc-diagnostic-list")); @@ -531,7 +530,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, case pp_token::kind::begin_url: { pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter); - auto anchor = ::make_unique<xml::element> ("a", true); + auto anchor = std::make_unique<xml::element> ("a", true); anchor->set_attr ("href", std::move (sub->m_value)); push_element (std::move (anchor)); } @@ -585,7 +584,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, auto cwe_span = make_span (label_text::borrow ("gcc-cwe-metadata")); cwe_span->add_text (label_text::borrow ("[")); { - auto anchor = ::make_unique<xml::element> ("a", true); + auto anchor = std::make_unique<xml::element> ("a", true); anchor->set_attr ("href", label_text::take (get_cwe_url (cwe))); pretty_printer pp; pp_printf (&pp, "CWE-%i", cwe); @@ -614,7 +613,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, { if (option_url.get ()) { - auto anchor = ::make_unique<xml::element> ("a", true); + auto anchor = std::make_unique<xml::element> ("a", true); anchor->set_attr ("href", std::move (option_url)); anchor->add_text (std::move (option_text)); option_span->add_child (std::move (anchor)); @@ -627,7 +626,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, } { - auto pre = ::make_unique<xml::element> ("pre", true); + auto pre = std::make_unique<xml::element> ("pre", true); pre->set_attr ("class", label_text::borrow ("gcc-annotated-source")); // TODO: ideally we'd like to capture elements within the following: diagnostic_show_locus (&m_context, m_context.m_source_printing, @@ -698,7 +697,7 @@ public: std::unique_ptr<diagnostic_per_format_buffer> make_per_format_buffer () final override { - return ::make_unique<diagnostic_xhtml_format_buffer> (m_builder); + return std::make_unique<diagnostic_xhtml_format_buffer> (m_builder); } void set_buffer (diagnostic_per_format_buffer *base_buffer) final override { @@ -844,9 +843,9 @@ diagnostic_output_format_init_xhtml_stderr (diagnostic_context &context, const line_maps *line_maps) { gcc_assert (line_maps); - auto format = ::make_unique<xhtml_stream_output_format> (context, - line_maps, - stderr); + auto format = std::make_unique<xhtml_stream_output_format> (context, + line_maps, + stderr); diagnostic_output_format_init_xhtml (context, std::move (format)); } @@ -859,9 +858,9 @@ diagnostic_output_format_init_xhtml_file (diagnostic_context &context, const char *base_file_name) { gcc_assert (line_maps); - auto format = ::make_unique<xhtml_file_output_format> (context, - line_maps, - base_file_name); + auto format = std::make_unique<xhtml_file_output_format> (context, + line_maps, + base_file_name); diagnostic_output_format_init_xhtml (context, std::move (format)); } @@ -878,8 +877,8 @@ class test_xhtml_diagnostic_context : public test_diagnostic_context public: test_xhtml_diagnostic_context () { - auto format = ::make_unique<xhtml_buffered_output_format> (*this, - line_table); + auto format = std::make_unique<xhtml_buffered_output_format> (*this, + line_table); m_format = format.get (); // borrowed diagnostic_output_format_init_xhtml (*this, std::move (format)); } @@ -974,9 +973,9 @@ plugin_init (struct plugin_name_args *plugin_info, return 1; global_dc->set_output_format - (::make_unique<xhtml_stream_output_format> (*global_dc, - line_table, - stderr)); + (std::make_unique<xhtml_stream_output_format> (*global_dc, + line_table, + stderr)); #if CHECKING_P selftest::xhtml_format_selftests (); diff --git a/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c b/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c index 52846c4..afb4a57 100644 --- a/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c +++ b/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c @@ -11,8 +11,7 @@ typedef unsigned int __u32; typedef __s8 s8; typedef __u32 u32; enum { false = 0, true = 1 }; -typedef unsigned long __kernel_ulong_t; -typedef __kernel_ulong_t __kernel_size_t; +typedef __SIZE_TYPE__ __kernel_size_t; typedef _Bool bool; typedef __kernel_size_t size_t; diff --git a/gcc/testsuite/gcc.dg/pr119712.c b/gcc/testsuite/gcc.dg/pr119712.c new file mode 100644 index 0000000..e845dd9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119712.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +int a, b, c, d, e, f; +int main() { + f--; + goto q; +j: + if (-1642776935 * c + 7 >= 0) + goto l; +m: + if (4 * a - c - 21 >= 0) + goto i; + return 0; +i: + if (d) + goto l; +q: + c = 4 * c - 3; + if (c - f) + goto m; + goto j; +l: + e = b + 1958960196 * c - 1016458303; + if (20 * e + 1 >= 0) + return 0; + goto j; +} diff --git a/gcc/testsuite/gcc.dg/pr83072-2.c b/gcc/testsuite/gcc.dg/pr83072-2.c index dff6b50..485e804 100644 --- a/gcc/testsuite/gcc.dg/pr83072-2.c +++ b/gcc/testsuite/gcc.dg/pr83072-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-evrp-details" } */ +/* { dg-options "-O2 -fdump-tree-evrp-details -fno-tree-forwprop" } */ int f1(int a, int b, int c){ if(c==0)__builtin_unreachable(); diff --git a/gcc/testsuite/gcc.dg/torture/pr119973.c b/gcc/testsuite/gcc.dg/torture/pr119973.c new file mode 100644 index 0000000..a9661a3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr119973.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fipa-pta" } */ + +static int +is_valid_domain_name (const char *string) +{ + const char *s; + + for (s=string; *s; s++) + if (*s == '.') + { + if (string == s) + return 0; + } + + return !!*string; +} + +int +main (void) +{ + static struct + { + const char *name; + int valid; + } testtbl[] = + { + { ".", 0 }, + { nullptr, 0 } + }; + int idx; + + for (idx=0; testtbl[idx].name; idx++) + { + if (is_valid_domain_name (testtbl[idx].name) != testtbl[idx].valid) + __builtin_abort (); + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c index 12ba475..ed8ee3a 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c @@ -31,9 +31,7 @@ int fdiv1(int a, int b) return a != 0 ? c : 0; } -/* fdiv1 requires until later than phiopt2 to be able to detect that - d is non-zero. to be able to remove the conditional. */ -/* { dg-final { scan-tree-dump-times "goto" 2 "phiopt2" } } */ +/* { dg-final { scan-tree-dump-not "goto" "phiopt2" } } */ /* { dg-final { scan-tree-dump-not "goto" "phiopt3" } } */ /* { dg-final { scan-tree-dump-not "goto" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr95801.c b/gcc/testsuite/gcc.dg/tree-ssa/pr95801.c new file mode 100644 index 0000000..c3c80a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr95801.c @@ -0,0 +1,13 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-evrp" } + +int always1(int a, int b) { + if (a / b) + return b != 0; + return 1; +} + +// If b != 0 is optimized by recognizing divide by 0 cannot happen, +// there should be no PHI node. + +// { dg-final { scan-tree-dump-not "PHI" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c new file mode 100644 index 0000000..6fadff8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +/* PR tree-optimization/67797 */ + +void *my_func(void *s, int n) +{ + __builtin_memset(s, 0, n); + return s; +} +void *my_func1(void *d, void *s, int n) +{ + __builtin_memcpy(d, s, n); + return d; +} +void *my_func2(void *s, void *p1, int n) +{ + if (p1) + __builtin_memcpy(s, p1, n); + else + __builtin_memset(s, 0, n); + return s; +} + +/* { dg-final { scan-tree-dump-times "Found tail call" 4 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c new file mode 100644 index 0000000..bf24fd8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +/* PR tree-optimization/67797 */ + +/* We should not get a tail call here since the + types don't match and we don't know how the argument + truncation will work. */ + +unsigned char my_func(int n) +{ + __builtin_memset((void*)0, 0, n); + return 0; +} + +/* { dg-final { scan-tree-dump-not "Found tail call" "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c index 5a4ca85..def2b89 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-options "-O2 -fdump-tree-evrp-details" } +// { dg-options "-O2 -fdump-tree-ccp1-details" } void gg(void); int f(unsigned t) @@ -16,4 +16,4 @@ int f(unsigned t) return 0; } -// { dg-final { scan-tree-dump "Global Exported: g_.* MASK 0x1 VALUE 0x0" "evrp" } } +// { dg-final { scan-tree-dump "Global Exported: g_.*MASK.*0 VALUE 0x0" "ccp1" } } diff --git a/gcc/testsuite/gcc.target/i386/pr109093-1.c b/gcc/testsuite/gcc.target/i386/pr109093-1.c new file mode 100644 index 0000000..58a7b00 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr109093-1.c @@ -0,0 +1,33 @@ +/* { dg-do run { target avx2_runtime } } */ +/* { dg-options "-O2 -mavx2 -mtune=znver1 -ftrivial-auto-var-init=zero -fno-stack-protector" } */ + +int a, b, c, d; +char e, f = 1; +short g, h, i; + +__attribute__ ((weak)) +void +run (void) +{ + short j; + + for (; g >= 0; --g) + { + int *k[10]; + + for (d = 0; d < 10; d++) + k[d] = &b; + + c = *k[1]; + + for (; a;) + j = i - c / f || (e ^= h); + } +} + +int +main (void) +{ + run (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr109780-1.c b/gcc/testsuite/gcc.target/i386/pr109780-1.c new file mode 100644 index 0000000..6b06947 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr109780-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=skylake" } */ + +char perm[64]; + +void +__attribute__((noipa)) +foo (int n) +{ + for (int i = 0; i < n; ++i) + perm[i] = i; +} + +/* { dg-final { scan-assembler-not "and\[lq\]?\[^\\n\]*-32,\[^\\n\]*sp" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr109780-2.c b/gcc/testsuite/gcc.target/i386/pr109780-2.c new file mode 100644 index 0000000..152da06 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr109780-2.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=skylake" } */ + +#define N 9 + +void +f (double x, double y, double *res) +{ + y = -y; + for (int i = 0; i < N; ++i) + { + double tmp = y; + y = x; + x = tmp; + res[i] = i; + } + res[N] = y * y; + res[N + 1] = x; +} + +/* { dg-final { scan-assembler-not "and\[lq\]?\[^\\n\]*-32,\[^\\n\]*sp" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr109780-3.c b/gcc/testsuite/gcc.target/i386/pr109780-3.c new file mode 100644 index 0000000..a3a770a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr109780-3.c @@ -0,0 +1,46 @@ +/* { dg-do run { target avx2_runtime } } */ +/* { dg-options "-O2 -mavx2 -mtune=znver1 -fno-stack-protector -fno-stack-clash-protection" } */ + +char a; +static int b, c, f; +char *d = &a; +static char *e = &a; + +__attribute__ ((weak)) +void +g (int h, int i) +{ + int j = 1; + for (; c != -3; c = c - 1) + { + int k[10]; + f = 0; + for (; f < 10; f++) + k[f] = 0; + *d = k[1]; + if (i < *d) + { + *e = h; + for (; j < 9; j++) + { + b = 1; + for (; b < 7; b++) + ; + } + } + } +} + +__attribute__ ((weak)) +void +run (void) +{ + g (1, 1); +} + +int +main (void) +{ + run (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr119103.c b/gcc/testsuite/gcc.target/i386/pr119103.c new file mode 100644 index 0000000..57210dc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr119103.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx2" } */ + +void lshift(unsigned short *x, unsigned char amount) +{ + if (amount > 15) + __builtin_unreachable(); + + for (int i = 0; i < 16; i++) + x[i] <<= amount; +} + +/* { dg-final { scan-assembler "vpsllw" } } */ diff --git a/gcc/testsuite/rust/compile/black_box.rs b/gcc/testsuite/rust/compile/black_box.rs new file mode 100644 index 0000000..80615af --- /dev/null +++ b/gcc/testsuite/rust/compile/black_box.rs @@ -0,0 +1,28 @@ +// { dg-options "-fdump-tree-gimple" } +#![feature(rustc_attrs)] + +#[lang = "sized"] +pub trait Sized {} + +#[rustc_builtin_macro] +macro_rules! llvm_asm { + () => {}; +} + +pub fn black_box<T>(mut dummy: T) -> T { + unsafe { + // { dg-final { scan-tree-dump-times {memory} 1 gimple } } + llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); + } + + dummy +} + +fn my_function(a: i32) -> i32 { + a +} + +fn main() { + let dummy: i32 = 42; + let _ = black_box(my_function(dummy)); +} diff --git a/gcc/testsuite/rust/compile/derive-debug1.rs b/gcc/testsuite/rust/compile/derive-debug1.rs index 2596a37..cf2187d 100644 --- a/gcc/testsuite/rust/compile/derive-debug1.rs +++ b/gcc/testsuite/rust/compile/derive-debug1.rs @@ -15,7 +15,7 @@ mod core { struct Formatter; // { dg-warning "is never constructed" } struct Error; // { dg-warning "is never constructed" } - type Result = core::result::Result<(), Error>; + type Result = crate::core::result::Result<(), Error>; trait Debug { fn fmt(&self, fmt: &mut Formatter) -> Result; diff --git a/gcc/testsuite/rust/compile/generics9.rs b/gcc/testsuite/rust/compile/generics9.rs index 3c787aa..56c6198 100644 --- a/gcc/testsuite/rust/compile/generics9.rs +++ b/gcc/testsuite/rust/compile/generics9.rs @@ -1,5 +1,6 @@ +// { dg-additional-options "-frust-name-resolution-2.0" } struct Foo<A, B = (A, B)>(A, B); -// { dg-error "could not resolve type path .B." "" { target *-*-* } .-1 } +// { dg-error "type parameters with a default cannot use forward declared identifiers" "" { target *-*-* } .-1 } fn main() { let a: Foo<bool>; diff --git a/gcc/testsuite/rust/compile/issue-3530-1.rs b/gcc/testsuite/rust/compile/issue-3530-1.rs new file mode 100644 index 0000000..b38b5cd --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3530-1.rs @@ -0,0 +1,2 @@ +#[repr(i32)] +enum NightsWatch {} // { dg-error "unsupported representation for zero-variant enum" } diff --git a/gcc/testsuite/rust/compile/issue-3530-2.rs b/gcc/testsuite/rust/compile/issue-3530-2.rs new file mode 100644 index 0000000..7432730 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3530-2.rs @@ -0,0 +1,2 @@ +#[repr(C)] +enum NightsWatch {} // { dg-error "unsupported representation for zero-variant enum" } diff --git a/gcc/testsuite/rust/compile/issue-3568.rs b/gcc/testsuite/rust/compile/issue-3568.rs index 222a174..fef43b5 100644 --- a/gcc/testsuite/rust/compile/issue-3568.rs +++ b/gcc/testsuite/rust/compile/issue-3568.rs @@ -4,4 +4,4 @@ mod foo { } pub use foo::super::foo::S as T; -// { dg-error ".super. can only be used in start position" "" { target *-*-* } .-1 } +// { dg-error ".super. in paths can only be used in start position" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-3581-1.rs b/gcc/testsuite/rust/compile/issue-3581-1.rs new file mode 100644 index 0000000..eb2f5f0 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3581-1.rs @@ -0,0 +1,12 @@ +enum Foo { + Bar, +} + +struct Baz; + +fn main() { + Foo::Bar.a; + // { dg-error "no field .a. on type .Foo. .E0609." "" { target *-*-* } .-1 } + Baz.a; + // { dg-error "no field .a. on type .Baz. .E0609." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3581-2.rs b/gcc/testsuite/rust/compile/issue-3581-2.rs new file mode 100644 index 0000000..5059784 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3581-2.rs @@ -0,0 +1,9 @@ +enum A { + X { inner: i32 }, + Y, +} + +pub fn test() { + let _ = A::Y.inner; + // { dg-error "no field .inner. on type .A. .E0609." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3612.rs b/gcc/testsuite/rust/compile/issue-3612.rs new file mode 100644 index 0000000..5256d0a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3612.rs @@ -0,0 +1,7 @@ +trait _St1 { + pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; + // { dg-error "no method named .as_ptr. found in the current scope .E0599." "" { target *-*-* } .-1 } + // { dg-error "failed to resolve receiver in MethodCallExpr" "" { target *-*-* } .-2 } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-3628.rs b/gcc/testsuite/rust/compile/issue-3628.rs new file mode 100644 index 0000000..5f59789 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3628.rs @@ -0,0 +1,10 @@ +pub enum Enum { + Variant1(isize), +} + +impl Enum { + fn static_meth_enum() -> Enum { + Enum { x: 1 } + // { dg-error "expected a struct, variant or union type, found enum .Enum. .E0574." "" { target *-*-* } .-1 } + } +} diff --git a/gcc/testsuite/rust/compile/issue-3649.rs b/gcc/testsuite/rust/compile/issue-3649.rs new file mode 100644 index 0000000..b85b193 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3649.rs @@ -0,0 +1,2 @@ +struct T(Box<>); +// { dg-error "could not resolve type path .Box. .E0412." "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-3652.rs b/gcc/testsuite/rust/compile/issue-3652.rs new file mode 100644 index 0000000..537ca9f --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3652.rs @@ -0,0 +1,7 @@ +trait Foo { + type T; + fn foo() -> T<<Self as Foo>::T>; + // { dg-error "could not resolve type path .T. .E0412." "" { target *-*-* } .-1 } +} + +fn foo() {} diff --git a/gcc/testsuite/rust/compile/issue-3662.rs b/gcc/testsuite/rust/compile/issue-3662.rs new file mode 100644 index 0000000..88baa2e --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3662.rs @@ -0,0 +1,8 @@ +pub fn rlib() { + let _ = ((-1 as i8) << 8 - 1) as f32; + let _ = 0u8 as char; + let _ = true > false; + let _ = true >= false; + let _ = true < false; + let _ = true >= false; +} diff --git a/gcc/testsuite/rust/compile/issue-3664.rs b/gcc/testsuite/rust/compile/issue-3664.rs new file mode 100644 index 0000000..c52a758 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3664.rs @@ -0,0 +1,5 @@ +const ARR: [usize; 1] = [2]; + +pub fn l8() { + let _ = 5 << ARR[0]; +} diff --git a/gcc/testsuite/rust/compile/issue-3711.rs b/gcc/testsuite/rust/compile/issue-3711.rs new file mode 100644 index 0000000..a3f9c39 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3711.rs @@ -0,0 +1,17 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +fn returns_closure() -> _ { + // { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 } + || 0 +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-402.rs b/gcc/testsuite/rust/compile/issue-402.rs new file mode 100644 index 0000000..2c99fc8 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-402.rs @@ -0,0 +1,14 @@ +#[lang = "sized"] +pub trait Sized {} + +struct GenericStruct<T>(T, usize); + +pub fn test() -> GenericStruct<_> { + // { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 } + GenericStruct(1, 2) +} + +fn square(num: i32) -> _ { + // { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 } + num * num +} diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs index 637d572..eeae6eb 100644 --- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs @@ -18,10 +18,9 @@ fn main() { // Error let _ = ReadDir { + // { dg-error "unknown field .end_of_stream_but_different. .E0560." "" { target *-*-* } .-1 } inner: 14, end_of_stream: false, - end_of_stream_but_different: false, // { dg-error "failed to resolve type for field" } - // { dg-error "unknown field" "" { target *-*-* } .-1 } - // { dg-prune-output "compilation terminated" } + end_of_stream_but_different: false, }; } diff --git a/gcc/testsuite/rust/compile/multiple_bindings1.rs b/gcc/testsuite/rust/compile/multiple_bindings1.rs index e73dc2a..8a2e18c 100644 --- a/gcc/testsuite/rust/compile/multiple_bindings1.rs +++ b/gcc/testsuite/rust/compile/multiple_bindings1.rs @@ -1,29 +1,38 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +trait FnOnce<Args> { + type Output; + + fn call_once(self, args: Args) -> Self::Output; +} + fn f1(i: i32, i: i32) {} // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } trait Foo { - fn f2(i: i32, i: i32) {} - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + fn f2(i: i32, i: i32) {} + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } trait Bar { - fn f3(i: i32, j: i32) {} + fn f3(i: i32, j: i32) {} } struct S; impl S { - fn f4(i: i32, i: i32) {} - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + fn f4(i: i32, i: i32) {} + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } impl Bar for S { - fn f3(i: i32, i: i32) {} - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + fn f3(i: i32, i: i32) {} + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } fn main() { - let _ = |i, i| {}; - // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } + let _ = |i, i| {}; + // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 } } - diff --git a/gcc/testsuite/rust/compile/name_resolution9.rs b/gcc/testsuite/rust/compile/name_resolution9.rs index 93adb46..792b3bd 100644 --- a/gcc/testsuite/rust/compile/name_resolution9.rs +++ b/gcc/testsuite/rust/compile/name_resolution9.rs @@ -6,11 +6,11 @@ pub mod foo { super::super::super::foo!(); // { dg-error "too many leading .super. keywords" } // { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 } - super::crate::foo!(); // { dg-error "leading path segment .crate. can only be used" } + super::crate::foo!(); // { dg-error ".crate. in paths can only be used" } // { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 } - crate::foo::bar::super::foo!(); // { dg-error "leading path segment .super. can only be used" } + crate::foo::bar::super::foo!(); // { dg-error ".super. in paths can only be used" } // { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 } } } diff --git a/gcc/testsuite/rust/compile/nonexistent-field.rs b/gcc/testsuite/rust/compile/nonexistent-field.rs index e20c49d..9bcfb2f 100644 --- a/gcc/testsuite/rust/compile/nonexistent-field.rs +++ b/gcc/testsuite/rust/compile/nonexistent-field.rs @@ -6,7 +6,7 @@ fn main() { let s = StructWithFields { x: 0 }; s.foo; - // { dg-error "no field .foo. on type .StructWithFields.StructWithFields .x.u32... .E0609." "" { target *-*-* } .-1 } + // { dg-error "no field .foo. on type .StructWithFields. .E0609." "" { target *-*-* } .-1 } let numbers = (1, 2, 3); numbers.3; diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index 4772517..c020e36 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -1,25 +1,17 @@ canonical_paths1.rs -cfg1.rs -generics9.rs issue-3315-2.rs -lookup_err1.rs -multiple_bindings1.rs -multiple_bindings2.rs privacy5.rs privacy8.rs pub_restricted_1.rs pub_restricted_2.rs pub_restricted_3.rs -use_1.rs issue-2905-2.rs -derive_clone_enum3.rs -derive-debug1.rs derive-default1.rs derive-eq-invalid.rs -derive-hash1.rs torture/alt_patterns1.rs torture/name_resolve1.rs -issue-3568.rs issue-3663.rs issue-3671.rs +issue-3652.rs +issue-3649.rs # please don't delete the trailing newline diff --git a/gcc/testsuite/rust/compile/self-path2.rs b/gcc/testsuite/rust/compile/self-path2.rs index 6441c33..d955ed0 100644 --- a/gcc/testsuite/rust/compile/self-path2.rs +++ b/gcc/testsuite/rust/compile/self-path2.rs @@ -11,11 +11,11 @@ fn baz() { crate::bar(); crate::self::foo(); - // { dg-error "leading path segment .self. can only be used at the beginning of a path" "" { target *-*-* } .-1 } + // { dg-error ".self. in paths can only be used in start position" "" { target *-*-* } .-1 } } type a = foo; type b = crate::foo; type c = self::foo; type d = crate::self::foo; -// { dg-error "leading path segment .self. can only be used at the beginning of a path" "" { target *-*-* } .-1 } +// { dg-error ".self. in paths can only be used in start position" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/struct_init1.rs b/gcc/testsuite/rust/compile/struct_init1.rs index 1875fb4..38f6f38 100644 --- a/gcc/testsuite/rust/compile/struct_init1.rs +++ b/gcc/testsuite/rust/compile/struct_init1.rs @@ -4,7 +4,7 @@ struct Foo { } fn main() { - let a = Foo { 0: 10.0, 1: 20.0 }; // { dg-error "failed to resolve type for field" } - // { dg-error "unknown field" "" { target *-*-* } .-1 } - // { dg-prune-output "compilation terminated" } + let a = Foo { 0: 10.0, 1: 20.0 }; + // { dg-error "unknown field .0. .E0560." "" { target *-*-* } .-1 } + // { dg-error "unknown field .1. .E0560." "" { target *-*-* } .-2 } } diff --git a/gcc/testsuite/rust/compile/use_1.rs b/gcc/testsuite/rust/compile/use_1.rs index 94b9632..e8e2037 100644 --- a/gcc/testsuite/rust/compile/use_1.rs +++ b/gcc/testsuite/rust/compile/use_1.rs @@ -1,7 +1,8 @@ +// { dg-additional-options "-frust-name-resolution-2.0" } mod frob {} -use foo::bar::baz; // { dg-error "cannot find simple path segment .foo." } -use frob::ulator; // { dg-error "cannot find simple path segment .ulator." } +use foo::bar::baz; // { dg-error "unresolved import .foo::bar::baz." } +use frob::ulator; // { dg-error "unresolved import .frob::ulator." } mod sain { mod doux {} @@ -9,8 +10,8 @@ mod sain { mod dron {} } -use not_sain::*; // { dg-error "cannot find simple path segment .not_sain." } +use not_sain::*; // { dg-error "unresolved import .not_sain." } use sain::*; use sain::{doux, dron}; -use sain::{doux, dron, graal}; // { dg-error "cannot find simple path segment .graal." } +use sain::{doux, dron, graal}; // { dg-error "unresolved import .sain::graal." } diff --git a/gcc/testsuite/rust/execute/black_box.rs b/gcc/testsuite/rust/execute/black_box.rs new file mode 100644 index 0000000..7a9920e --- /dev/null +++ b/gcc/testsuite/rust/execute/black_box.rs @@ -0,0 +1,30 @@ +/* { dg-output "Value is: 42\r*\n" } */ +#![feature(rustc_attrs)] + +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "sized"] +pub trait Sized {} + +#[rustc_builtin_macro] +macro_rules! llvm_asm { + () => {}; +} + +pub fn black_box<T>(mut dummy: T) -> T { + unsafe { + llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); + } + + dummy +} + +fn main() { + let dummy: i32 = 42; + let result = black_box(dummy); + unsafe { + printf("Value is: %i\n\0" as *const str as *const i8, result); + } +} diff --git a/gcc/text-art/style.cc b/gcc/text-art/style.cc index 1793405..ffc75b6 100644 --- a/gcc/text-art/style.cc +++ b/gcc/text-art/style.cc @@ -23,7 +23,6 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" -#include "make-unique.h" #include "pretty-print.h" #include "intl.h" #include "selftest.h" diff --git a/gcc/text-art/styled-string.cc b/gcc/text-art/styled-string.cc index e13278b..3b7145f 100644 --- a/gcc/text-art/styled-string.cc +++ b/gcc/text-art/styled-string.cc @@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" -#include "make-unique.h" #include "pretty-print.h" #include "intl.h" #include "diagnostic.h" diff --git a/gcc/text-art/table.cc b/gcc/text-art/table.cc index 4b73bff..d3ddae0 100644 --- a/gcc/text-art/table.cc +++ b/gcc/text-art/table.cc @@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" -#include "make-unique.h" #include "pretty-print.h" #include "diagnostic.h" #include "selftest.h" diff --git a/gcc/text-art/tree-widget.cc b/gcc/text-art/tree-widget.cc index 597374f..33c918d 100644 --- a/gcc/text-art/tree-widget.cc +++ b/gcc/text-art/tree-widget.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "pretty-print.h" #include "selftest.h" -#include "make-unique.h" #include "text-art/selftests.h" #include "text-art/tree-widget.h" #include "text-art/dump-widget-info.h" @@ -38,8 +37,8 @@ static const int margin_width = 3; std::unique_ptr<tree_widget> tree_widget::make (styled_string str, const theme &theme, style::id_t style_id) { - return ::make_unique <tree_widget> - (::make_unique <text_widget> (std::move (str)), + return std::make_unique <tree_widget> + (std::make_unique <text_widget> (std::move (str)), theme, style_id); } diff --git a/gcc/text-art/widget.cc b/gcc/text-art/widget.cc index d980b53..3c68018 100644 --- a/gcc/text-art/widget.cc +++ b/gcc/text-art/widget.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "pretty-print.h" #include "selftest.h" -#include "make-unique.h" #include "text-art/selftests.h" #include "text-art/widget.h" @@ -191,7 +190,7 @@ static void test_wrapper_widget () { style_manager sm; - wrapper_widget w (::make_unique<test_widget> (canvas::size_t (3, 3), 'B')); + wrapper_widget w (std::make_unique<test_widget> (canvas::size_t (3, 3), 'B')); canvas c (w.to_canvas (sm)); ASSERT_CANVAS_STREQ (c, false, @@ -207,7 +206,7 @@ test_vbox_1 () vbox_widget w; for (int i = 0; i < 5; i++) w.add_child - (::make_unique <text_widget> + (std::make_unique <text_widget> (styled_string::from_fmt (sm, nullptr, "this is line %i", i))); canvas c (w.to_canvas (sm)); @@ -225,9 +224,9 @@ test_vbox_2 () { style_manager sm; vbox_widget w; - w.add_child (::make_unique<test_widget> (canvas::size_t (1, 3), 'A')); - w.add_child (::make_unique<test_widget> (canvas::size_t (4, 1), 'B')); - w.add_child (::make_unique<test_widget> (canvas::size_t (1, 2), 'C')); + w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 3), 'A')); + w.add_child (std::make_unique<test_widget> (canvas::size_t (4, 1), 'B')); + w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 2), 'C')); canvas c (w.to_canvas (sm)); ASSERT_CANVAS_STREQ (c, false, diff --git a/gcc/timevar.cc b/gcc/timevar.cc index 2e11be9..16ae5c8 100644 --- a/gcc/timevar.cc +++ b/gcc/timevar.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "options.h" #include "json.h" -#include "make-unique.h" /* Non-NULL if timevars should be used. In GCC, this happens with the -ftime-report flag. */ @@ -139,7 +138,7 @@ timer::named_items::print (FILE *fp, const timevar_time_def *total) std::unique_ptr<json::value> timer::named_items::make_json () const { - auto arr = ::make_unique<json::array> (); + auto arr = std::make_unique<json::array> (); for (const char *item_name : m_names) { hash_map_t &mut_map = const_cast <hash_map_t &> (m_hash_map); @@ -703,7 +702,7 @@ timer::print (FILE *fp) std::unique_ptr<json::object> make_json_for_timevar_time_def (const timevar_time_def &ttd) { - auto obj = ::make_unique<json::object> (); + auto obj = std::make_unique<json::object> (); obj->set_float ("wall", nanosec_to_floating_sec (ttd.wall)); obj->set_integer ("ggc_mem", ttd.ggc_mem); return obj; @@ -717,7 +716,7 @@ make_json_for_timevar_time_def (const timevar_time_def &ttd) std::unique_ptr<json::value> timer::timevar_def::make_json () const { - auto timevar_obj = ::make_unique<json::object> (); + auto timevar_obj = std::make_unique<json::object> (); timevar_obj->set_string ("name", name); timevar_obj->set ("elapsed", make_json_for_timevar_time_def (elapsed)); @@ -732,14 +731,14 @@ timer::timevar_def::make_json () const } if (any_children_with_time) { - auto children_arr = ::make_unique<json::array> (); + auto children_arr = std::make_unique<json::array> (); for (auto i : *children) { /* Don't emit timing variables if we're going to get a row of zeroes. */ if (all_zero (i.second)) continue; - auto child_obj = ::make_unique<json::object> (); + auto child_obj = std::make_unique<json::object> (); child_obj->set_string ("name", i.first->name); child_obj->set ("elapsed", make_json_for_timevar_time_def (i.second)); @@ -759,7 +758,7 @@ std::unique_ptr<json::value> timer::make_json () const { #if defined (HAVE_WALL_TIME) - auto report_obj = ::make_unique<json::object> (); + auto report_obj = std::make_unique<json::object> (); json::array *json_arr = new json::array (); report_obj->set ("timevars", json_arr); @@ -803,7 +802,7 @@ timer::make_json () const get_time (&total_now); timevar_diff (&total_elapsed, m_timevars[TV_TOTAL].start_time, total_now); - auto total_obj = ::make_unique<json::object> (); + auto total_obj = std::make_unique<json::object> (); total_obj->set_string ("name", "TOTAL"); total_obj->set ("elapsed", make_json_for_timevar_time_def (total_elapsed)); json_arr->append (std::move (total_obj)); diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 6d8b885..7e457b5 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -94,7 +94,6 @@ along with GCC; see the file COPYING3. If not see #include "dbgcnt.h" #include "gcc-urlifier.h" #include "unique-argv.h" -#include "make-unique.h" #include "selftest.h" @@ -1095,9 +1094,9 @@ general_init (const char *argv0, bool init_signals, unique_argv original_argv) global_dc->m_internal_error = internal_error_function; const unsigned lang_mask = lang_hooks.option_lang_mask (); global_dc->set_option_manager - (::make_unique<compiler_diagnostic_option_manager> (*global_dc, - lang_mask, - &global_options), + (std::make_unique<compiler_diagnostic_option_manager> (*global_dc, + lang_mask, + &global_options), lang_mask); global_dc->push_owned_urlifier (make_gcc_urlifier (lang_mask)); diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index ecf19d2..6a95b82 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -5104,6 +5104,19 @@ verify_gimple_cond (gcond *stmt) return true; } + tree lhs = gimple_cond_lhs (stmt); + + /* GIMPLE_CONDs condition may not throw. */ + if (flag_exceptions + && cfun->can_throw_non_call_exceptions + && operation_could_trap_p (gimple_cond_code (stmt), + FLOAT_TYPE_P (TREE_TYPE (lhs)), + false, NULL_TREE)) + { + error ("gimple cond condition cannot throw"); + return true; + } + return verify_gimple_comparison (boolean_type_node, gimple_cond_lhs (stmt), gimple_cond_rhs (stmt), diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc index 80717c1..11701f5 100644 --- a/gcc/tree-diagnostic-client-data-hooks.cc +++ b/gcc/tree-diagnostic-client-data-hooks.cc @@ -31,7 +31,6 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "plugin.h" #include "timevar.h" -#include "make-unique.h" /* Concrete class for supplying a diagnostic_context with information about a specific plugin within the client, when the client is the @@ -169,5 +168,5 @@ private: std::unique_ptr<diagnostic_client_data_hooks> make_compiler_data_hooks () { - return ::make_unique<compiler_data_hooks> (); + return std::make_unique<compiler_data_hooks> (); } diff --git a/gcc/tree-predcom.cc b/gcc/tree-predcom.cc index d45aa38..509d112 100644 --- a/gcc/tree-predcom.cc +++ b/gcc/tree-predcom.cc @@ -234,6 +234,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-affine.h" #include "builtins.h" #include "opts.h" +#include "tree-ssa-address.h" /* The maximum number of iterations between the considered memory references. */ @@ -1824,6 +1825,7 @@ ref_at_iteration (data_reference_p dr, int iter, tree type = build_aligned_type (TREE_TYPE (ref), get_object_alignment (ref)); ref = build2 (MEM_REF, type, addr, alias_ptr); + copy_ref_info (ref, DR_REF (dr)); if (ref_type) ref = build3 (ref_code, ref_type, ref, ref_op1, ref_op2); return ref; diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index c1a21e7..359359d 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -4795,10 +4795,10 @@ op_symbol_code (enum tree_code code, dump_flags_t flags) return ">>"; case LROTATE_EXPR: - return "r<<"; + return (flags & TDF_GIMPLE) ? "__ROTATE_LEFT" : "r<<"; case RROTATE_EXPR: - return "r>>"; + return (flags & TDF_GIMPLE) ? "__ROTATE_RIGHT" : "r>>"; case WIDEN_LSHIFT_EXPR: return "w<<"; diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc index 225964c..a3ca5af 100644 --- a/gcc/tree-ssa-loop-im.cc +++ b/gcc/tree-ssa-loop-im.cc @@ -143,6 +143,8 @@ public: different modes. */ }; +static bool in_loop_pipeline; + /* We use six bits per loop in the ref->dep_loop bitmap to record the dep_kind x dep_state combinations. */ @@ -1239,7 +1241,11 @@ compute_invariantness (basic_block bb) lim_data->cost); } - if (lim_data->cost >= LIM_EXPENSIVE) + if (lim_data->cost >= LIM_EXPENSIVE + /* When we run before PRE and PRE is active hoist all expressions + since PRE would do so anyway and we can preserve range info + but PRE cannot. */ + || (flag_tree_pre && !in_loop_pipeline)) set_profitable_level (stmt); } } @@ -3759,7 +3765,7 @@ public: unsigned int pass_lim::execute (function *fun) { - bool in_loop_pipeline = scev_initialized_p (); + in_loop_pipeline = scev_initialized_p (); if (!in_loop_pipeline) loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc index d9356a8..f79b542 100644 --- a/gcc/tree-ssa-structalias.cc +++ b/gcc/tree-ssa-structalias.cc @@ -6529,18 +6529,18 @@ create_variable_info_for (tree decl, const char *name, bool add_id) if (!vnode->all_refs_explicit_p ()) make_copy_constraint (vi, nonlocal_id); - /* If this is a global variable with an initializer and we are in - IPA mode generate constraints for it. */ - ipa_ref *ref; - for (unsigned idx = 0; vnode->iterate_reference (idx, ref); ++idx) + /* While we can in theory walk references for the varpool + node that does not cover zero-initialization or references + to the constant pool. */ + if (DECL_INITIAL (decl)) { auto_vec<ce_s> rhsc; struct constraint_expr lhs, *rhsp; unsigned i; - get_constraint_for_address_of (ref->referred->decl, &rhsc); lhs.var = vi->id; lhs.offset = 0; lhs.type = SCALAR; + get_constraint_for (DECL_INITIAL (decl), &rhsc); FOR_EACH_VEC_ELT (rhsc, i, rhsp) process_constraint (new_constraint (lhs, *rhsp)); /* If this is a variable that escapes from the unit diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc index f593363..10e88d9 100644 --- a/gcc/tree-tailcall.cc +++ b/gcc/tree-tailcall.cc @@ -827,8 +827,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, ? !is_gimple_reg (param) : (!is_gimple_variable (param) || TREE_THIS_VOLATILE (param) - || may_be_aliased (param) - || !gimple_call_must_tail_p (call))) + || may_be_aliased (param))) break; } } @@ -1083,57 +1082,74 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, { bool ok = false; value_range val; - tree valr; - /* If IPA-VRP proves called function always returns a singleton range, - the return value is replaced by the only value in that range. - For tail call purposes, pretend such replacement didn't happen. */ if (ass_var == NULL_TREE && !tail_recursion) - if (tree type = gimple_range_type (call)) - if (tree callee = gimple_call_fndecl (call)) - if ((INTEGRAL_TYPE_P (type) - || SCALAR_FLOAT_TYPE_P (type) - || POINTER_TYPE_P (type)) - && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (callee)), - type) - && useless_type_conversion_p (TREE_TYPE (ret_var), type) - && ipa_return_value_range (val, callee) - && val.singleton_p (&valr)) + { + tree other_value = NULL_TREE; + /* If we have a function call that we know the return value is the same + as the argument, try the argument too. */ + int flags = gimple_call_return_flags (call); + if ((flags & ERF_RETURNS_ARG) != 0 + && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (call)) + { + tree arg = gimple_call_arg (call, flags & ERF_RETURN_ARG_MASK); + if (useless_type_conversion_p (TREE_TYPE (ret_var), TREE_TYPE (arg) )) + other_value = arg; + } + /* If IPA-VRP proves called function always returns a singleton range, + the return value is replaced by the only value in that range. + For tail call purposes, pretend such replacement didn't happen. */ + else if (tree type = gimple_range_type (call)) + if (tree callee = gimple_call_fndecl (call)) { - tree rv = ret_var; - unsigned int i = edges.length (); - /* If ret_var is equal to valr, we can tail optimize. */ - if (operand_equal_p (ret_var, valr, 0)) - ok = true; - else - /* Otherwise, if ret_var is a PHI result, try to find out - if valr isn't propagated through PHIs on the path from - call's bb to SSA_NAME_DEF_STMT (ret_var)'s bb. */ - while (TREE_CODE (rv) == SSA_NAME - && gimple_code (SSA_NAME_DEF_STMT (rv)) == GIMPLE_PHI) - { - tree nrv = NULL_TREE; - gimple *g = SSA_NAME_DEF_STMT (rv); - for (; i; --i) - { - if (edges[i - 1]->dest == gimple_bb (g)) - { - nrv - = gimple_phi_arg_def_from_edge (g, + tree valr; + if ((INTEGRAL_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type) + || POINTER_TYPE_P (type)) + && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (callee)), + type) + && useless_type_conversion_p (TREE_TYPE (ret_var), type) + && ipa_return_value_range (val, callee) + && val.singleton_p (&valr)) + other_value = valr; + } + + if (other_value) + { + tree rv = ret_var; + unsigned int i = edges.length (); + /* If ret_var is equal to other_value, we can tail optimize. */ + if (operand_equal_p (ret_var, other_value, 0)) + ok = true; + else + /* Otherwise, if ret_var is a PHI result, try to find out + if other_value isn't propagated through PHIs on the path from + call's bb to SSA_NAME_DEF_STMT (ret_var)'s bb. */ + while (TREE_CODE (rv) == SSA_NAME + && gimple_code (SSA_NAME_DEF_STMT (rv)) == GIMPLE_PHI) + { + tree nrv = NULL_TREE; + gimple *g = SSA_NAME_DEF_STMT (rv); + for (; i; --i) + { + if (edges[i - 1]->dest == gimple_bb (g)) + { + nrv = gimple_phi_arg_def_from_edge (g, edges[i - 1]); - --i; - break; - } - } - if (nrv == NULL_TREE) + --i; + break; + } + } + if (nrv == NULL_TREE) + break; + if (operand_equal_p (nrv, other_value, 0)) + { + ok = true; break; - if (operand_equal_p (nrv, valr, 0)) - { - ok = true; - break; - } + } rv = nrv; - } - } + } + } + } if (!ok) { maybe_error_musttail (call, _("call and return value are different"), diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 1c9e9b0..3de1ea6 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -2120,13 +2120,9 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) int nbbs = loop->num_nodes; int i; stmt_vec_info stmt_info; - bool need_to_vectorize = false; - bool ok; DUMP_VECT_SCOPE ("vect_analyze_loop_operations"); - auto_vec<stmt_info_for_cost> cost_vec; - for (i = 0; i < nbbs; i++) { basic_block bb = bbs[i]; @@ -2135,7 +2131,6 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) gsi_next (&si)) { gphi *phi = si.phi (); - ok = true; stmt_info = loop_vinfo->lookup_stmt (phi); if (dump_enabled_p ()) @@ -2144,6 +2139,10 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) if (virtual_operand_p (gimple_phi_result (phi))) continue; + /* ??? All of the below unconditional FAILs should be in + done earlier after analyzing cycles, possibly when + determining stmt relevancy? */ + /* Inner-loop loop-closed exit phi in outer-loop vectorization (i.e., a phi in the tail of the outer-loop). */ if (! is_loop_header_bb_p (bb)) @@ -2180,9 +2179,7 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def || (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)) - && ! PURE_SLP_STMT (stmt_info) - && !vectorizable_lc_phi (loop_vinfo, - stmt_info, NULL, NULL)) + && ! PURE_SLP_STMT (stmt_info)) return opt_result::failure_at (phi, "unsupported phi\n"); } @@ -2200,36 +2197,8 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) "not vectorized:" " scalar dependence cycle.\n"); - if (STMT_VINFO_RELEVANT_P (stmt_info)) - { - need_to_vectorize = true; - if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def - && ! PURE_SLP_STMT (stmt_info)) - ok = vectorizable_induction (loop_vinfo, - stmt_info, NULL, NULL, - &cost_vec); - else if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def - || (STMT_VINFO_DEF_TYPE (stmt_info) - == vect_double_reduction_def) - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle) - && ! PURE_SLP_STMT (stmt_info)) - ok = vectorizable_reduction (loop_vinfo, - stmt_info, NULL, NULL, &cost_vec); - else if ((STMT_VINFO_DEF_TYPE (stmt_info) - == vect_first_order_recurrence) - && ! PURE_SLP_STMT (stmt_info)) - ok = vectorizable_recurr (loop_vinfo, stmt_info, NULL, NULL, - &cost_vec); - } - - /* SLP PHIs are tested by vect_slp_analyze_node_operations. */ - if (ok - && STMT_VINFO_LIVE_P (stmt_info) - && !PURE_SLP_STMT (stmt_info)) - ok = vectorizable_live_operation (loop_vinfo, stmt_info, NULL, NULL, - -1, false, &cost_vec); - - if (!ok) + if (STMT_VINFO_RELEVANT_P (stmt_info) + && ! PURE_SLP_STMT (stmt_info)) return opt_result::failure_at (phi, "not vectorized: relevant phi not " "supported: %G", @@ -2243,34 +2212,18 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) if (!gimple_clobber_p (stmt) && !is_gimple_debug (stmt)) { + bool need_to_vectorize = false; opt_result res = vect_analyze_stmt (loop_vinfo, loop_vinfo->lookup_stmt (stmt), &need_to_vectorize, - NULL, NULL, &cost_vec); + NULL, NULL, NULL); if (!res) return res; } } } /* bbs */ - add_stmt_costs (loop_vinfo->vector_costs, &cost_vec); - - /* All operations in the loop are either irrelevant (deal with loop - control, or dead), or only used outside the loop and can be moved - out of the loop (e.g. invariants, inductions). The loop can be - optimized away by scalar optimizations. We're better off not - touching this loop. */ - if (!need_to_vectorize) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "All the computation can be taken out of the loop.\n"); - return opt_result::failure_at - (vect_location, - "not vectorized: redundant loop. no profit to vectorize.\n"); - } - return opt_result::success (); } @@ -2899,45 +2852,37 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, bool saved_can_use_partial_vectors_p = LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo); - /* This is the point where we can re-start analysis with SLP forced off. */ + /* This is the point where we can re-start analysis with single-lane + SLP forced. */ start_over: - if (slp) - { - /* Check the SLP opportunities in the loop, analyze and build - SLP trees. */ - ok = vect_analyze_slp (loop_vinfo, loop_vinfo->stmt_vec_infos.length (), - slp == 1); - if (!ok) - return ok; + /* Check the SLP opportunities in the loop, analyze and build + SLP trees. */ + ok = vect_analyze_slp (loop_vinfo, loop_vinfo->stmt_vec_infos.length (), + slp == 1); + if (!ok) + return ok; - /* If there are any SLP instances mark them as pure_slp. */ - if (vect_make_slp_decision (loop_vinfo)) - { - /* Find stmts that need to be both vectorized and SLPed. */ - vect_detect_hybrid_slp (loop_vinfo); + /* If there are any SLP instances mark them as pure_slp. */ + if (vect_make_slp_decision (loop_vinfo)) + { + /* Find stmts that need to be both vectorized and SLPed. */ + vect_detect_hybrid_slp (loop_vinfo); - /* Update the vectorization factor based on the SLP decision. */ - vect_update_vf_for_slp (loop_vinfo); + /* Update the vectorization factor based on the SLP decision. */ + vect_update_vf_for_slp (loop_vinfo); - /* Optimize the SLP graph with the vectorization factor fixed. */ - vect_optimize_slp (loop_vinfo); + /* Optimize the SLP graph with the vectorization factor fixed. */ + vect_optimize_slp (loop_vinfo); - /* Gather the loads reachable from the SLP graph entries. */ - vect_gather_slp_loads (loop_vinfo); - } + /* Gather the loads reachable from the SLP graph entries. */ + vect_gather_slp_loads (loop_vinfo); } /* We don't expect to have to roll back to anything other than an empty set of rgroups. */ gcc_assert (LOOP_VINFO_MASKS (loop_vinfo).is_empty ()); - /* When we arrive here with SLP disabled and we are supposed - to use SLP for everything fail vectorization. */ - if (!slp && param_vect_force_slp) - return opt_result::failure_at (vect_location, - "may need non-SLP handling\n"); - /* Apply the suggested unrolling factor, this was determined by the backend during finish_cost the first time we ran the analyzis for this vector mode. */ @@ -2992,24 +2937,21 @@ start_over: if (!ok) return ok; - if (slp) + /* Analyze operations in the SLP instances. We can't simply + remove unsupported SLP instances as this makes the above + SLP kind detection invalid and might also affect the VF. */ + if (! vect_slp_analyze_operations (loop_vinfo)) { - /* Analyze operations in the SLP instances. We can't simply - remove unsupported SLP instances as this makes the above - SLP kind detection invalid and might also affect the VF. */ - if (! vect_slp_analyze_operations (loop_vinfo)) - { - ok = opt_result::failure_at (vect_location, - "unsupported SLP instances\n"); - goto again; - } + ok = opt_result::failure_at (vect_location, + "unsupported SLP instances\n"); + goto again; } /* Dissolve SLP-only groups. */ vect_dissolve_slp_only_groups (loop_vinfo); - /* Scan all the remaining operations in the loop that are not subject - to SLP and make sure they are vectorizable. */ + /* Scan all the remaining operations in the loop that we did not catch + during SLP build and make sure we fail. */ ok = vect_analyze_loop_operations (loop_vinfo); if (!ok) { @@ -3268,9 +3210,8 @@ again: /* Ensure that "ok" is false (with an opt_problem if dumping is enabled). */ gcc_assert (!ok); - /* Try again with SLP degraded but if we didn't do any SLP there is - no point in re-trying. */ - if (!slp) + /* Try again with single-lane SLP. */ + if (slp == 1) return ok; /* If we are applying suggested unroll factor, we don't need to @@ -3322,18 +3263,11 @@ again: } } - /* Roll back state appropriately. Degrade SLP this time. From multi- - to single-lane to disabled. */ - --slp; + /* Roll back state appropriately. Force single-lane SLP this time. */ + slp = 1; if (dump_enabled_p ()) - { - if (slp) - dump_printf_loc (MSG_NOTE, vect_location, - "re-trying with single-lane SLP\n"); - else - dump_printf_loc (MSG_NOTE, vect_location, - "re-trying with SLP disabled\n"); - } + dump_printf_loc (MSG_NOTE, vect_location, + "re-trying with single-lane SLP\n"); /* Restore vectorization factor as it were without SLP. */ LOOP_VINFO_VECT_FACTOR (loop_vinfo) = saved_vectorization_factor; @@ -9600,8 +9534,7 @@ vectorizable_phi (vec_info *, vector PHI node and the permute since those together compute the vectorized value of the scalar PHI. We do not yet have the backedge value to fill in there nor into the vec_perm. Those - are filled in maybe_set_vectorized_backedge_value and - vect_schedule_scc. + are filled in vect_schedule_scc. TODO: Since the scalar loop does not have a use of the recurrence outside of the loop the natural way to implement peeling via @@ -11792,45 +11725,6 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info, return true; } -/* Kill any debug uses outside LOOP of SSA names defined in STMT_INFO. */ - -static void -vect_loop_kill_debug_uses (class loop *loop, stmt_vec_info stmt_info) -{ - ssa_op_iter op_iter; - imm_use_iterator imm_iter; - def_operand_p def_p; - gimple *ustmt; - - FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt_info->stmt, op_iter, SSA_OP_DEF) - { - FOR_EACH_IMM_USE_STMT (ustmt, imm_iter, DEF_FROM_PTR (def_p)) - { - basic_block bb; - - if (!is_gimple_debug (ustmt)) - continue; - - bb = gimple_bb (ustmt); - - if (!flow_bb_inside_loop_p (loop, bb)) - { - if (gimple_debug_bind_p (ustmt)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "killing debug use\n"); - - gimple_debug_bind_reset_value (ustmt); - update_stmt (ustmt); - } - else - gcc_unreachable (); - } - } - } -} - /* Given loop represented by LOOP_VINFO, return true if computation of LOOP_VINFO_NITERS (= LOOP_VINFO_NITERSM1 + 1) doesn't overflow, false otherwise. */ @@ -12204,126 +12098,6 @@ scale_profile_for_vect_loop (class loop *loop, edge exit_e, unsigned vf, bool fl get_likely_max_loop_iterations_int (loop)); } -/* For a vectorized stmt DEF_STMT_INFO adjust all vectorized PHI - latch edge values originally defined by it. */ - -static void -maybe_set_vectorized_backedge_value (loop_vec_info loop_vinfo, - stmt_vec_info def_stmt_info) -{ - tree def = gimple_get_lhs (vect_orig_stmt (def_stmt_info)->stmt); - if (!def || TREE_CODE (def) != SSA_NAME) - return; - stmt_vec_info phi_info; - imm_use_iterator iter; - use_operand_p use_p; - FOR_EACH_IMM_USE_FAST (use_p, iter, def) - { - gphi *phi = dyn_cast <gphi *> (USE_STMT (use_p)); - if (!phi) - continue; - if (!(gimple_bb (phi)->loop_father->header == gimple_bb (phi) - && (phi_info = loop_vinfo->lookup_stmt (phi)) - && STMT_VINFO_RELEVANT_P (phi_info))) - continue; - loop_p loop = gimple_bb (phi)->loop_father; - edge e = loop_latch_edge (loop); - if (PHI_ARG_DEF_FROM_EDGE (phi, e) != def) - continue; - - if (VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (phi_info)) - && STMT_VINFO_REDUC_TYPE (phi_info) != FOLD_LEFT_REDUCTION - && STMT_VINFO_REDUC_TYPE (phi_info) != EXTRACT_LAST_REDUCTION) - { - vec<gimple *> &phi_defs = STMT_VINFO_VEC_STMTS (phi_info); - vec<gimple *> &latch_defs = STMT_VINFO_VEC_STMTS (def_stmt_info); - gcc_assert (phi_defs.length () == latch_defs.length ()); - for (unsigned i = 0; i < phi_defs.length (); ++i) - add_phi_arg (as_a <gphi *> (phi_defs[i]), - gimple_get_lhs (latch_defs[i]), e, - gimple_phi_arg_location (phi, e->dest_idx)); - } - else if (STMT_VINFO_DEF_TYPE (phi_info) == vect_first_order_recurrence) - { - /* For first order recurrences we have to update both uses of - the latch definition, the one in the PHI node and the one - in the generated VEC_PERM_EXPR. */ - vec<gimple *> &phi_defs = STMT_VINFO_VEC_STMTS (phi_info); - vec<gimple *> &latch_defs = STMT_VINFO_VEC_STMTS (def_stmt_info); - gcc_assert (phi_defs.length () == latch_defs.length ()); - tree phidef = gimple_assign_rhs1 (phi_defs[0]); - gphi *vphi = as_a <gphi *> (SSA_NAME_DEF_STMT (phidef)); - for (unsigned i = 0; i < phi_defs.length (); ++i) - { - gassign *perm = as_a <gassign *> (phi_defs[i]); - if (i > 0) - gimple_assign_set_rhs1 (perm, gimple_get_lhs (latch_defs[i-1])); - gimple_assign_set_rhs2 (perm, gimple_get_lhs (latch_defs[i])); - update_stmt (perm); - } - add_phi_arg (vphi, gimple_get_lhs (latch_defs.last ()), e, - gimple_phi_arg_location (phi, e->dest_idx)); - } - } -} - -/* Vectorize STMT_INFO if relevant, inserting any new instructions before GSI. - When vectorizing STMT_INFO as a store, set *SEEN_STORE to its - stmt_vec_info. */ - -static bool -vect_transform_loop_stmt (loop_vec_info loop_vinfo, stmt_vec_info stmt_info, - gimple_stmt_iterator *gsi, stmt_vec_info *seen_store) -{ - class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); - poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); - - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "------>vectorizing statement: %G", stmt_info->stmt); - - if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) - vect_loop_kill_debug_uses (loop, stmt_info); - - if (!STMT_VINFO_RELEVANT_P (stmt_info) - && !STMT_VINFO_LIVE_P (stmt_info)) - { - if (is_gimple_call (stmt_info->stmt) - && gimple_call_internal_p (stmt_info->stmt, IFN_MASK_CALL)) - { - gcc_assert (!gimple_call_lhs (stmt_info->stmt)); - *seen_store = stmt_info; - return false; - } - return false; - } - - if (STMT_VINFO_VECTYPE (stmt_info)) - { - poly_uint64 nunits - = TYPE_VECTOR_SUBPARTS (STMT_VINFO_VECTYPE (stmt_info)); - if (!STMT_SLP_TYPE (stmt_info) - && maybe_ne (nunits, vf) - && dump_enabled_p ()) - /* For SLP VF is set according to unrolling factor, and not - to vector size, hence for SLP this print is not valid. */ - dump_printf_loc (MSG_NOTE, vect_location, "multiple-types.\n"); - } - - /* Pure SLP statements have already been vectorized. We still need - to apply loop vectorization to hybrid SLP statements. */ - if (PURE_SLP_STMT (stmt_info)) - return false; - - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, "transform statement.\n"); - - if (vect_transform_stmt (loop_vinfo, stmt_info, gsi, NULL, NULL)) - *seen_store = stmt_info; - - return true; -} - /* Helper function to pass to simplify_replace_tree to enable replacing tree's in the hash_map with its corresponding values. */ @@ -12749,8 +12523,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) } } - /* Schedule the SLP instances first, then handle loop vectorization - below. */ + /* Schedule the SLP instances. */ if (!loop_vinfo->slp_instances.is_empty ()) { DUMP_VECT_SCOPE ("scheduling SLP instances"); @@ -12769,134 +12542,14 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) GSI_CONTINUE_LINKING); } - /* FORNOW: the vectorizer supports only loops which body consist - of one basic block (header + empty latch). When the vectorizer will - support more involved loop forms, the order by which the BBs are - traversed need to be reconsidered. */ - + /* Stub out scalar statements that must not survive vectorization and + were not picked as relevant in any SLP instance. + Doing this here helps with grouped statements, or statements that + are involved in patterns. */ for (i = 0; i < nbbs; i++) { basic_block bb = bbs[i]; stmt_vec_info stmt_info; - - for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); - gsi_next (&si)) - { - gphi *phi = si.phi (); - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "------>vectorizing phi: %G", (gimple *) phi); - stmt_info = loop_vinfo->lookup_stmt (phi); - if (!stmt_info) - continue; - - if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) - vect_loop_kill_debug_uses (loop, stmt_info); - - if (!STMT_VINFO_RELEVANT_P (stmt_info) - && !STMT_VINFO_LIVE_P (stmt_info)) - continue; - - if (STMT_VINFO_VECTYPE (stmt_info) - && (maybe_ne - (TYPE_VECTOR_SUBPARTS (STMT_VINFO_VECTYPE (stmt_info)), vf)) - && dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, "multiple-types.\n"); - - if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_first_order_recurrence - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def) - && ! PURE_SLP_STMT (stmt_info)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, "transform phi.\n"); - vect_transform_stmt (loop_vinfo, stmt_info, NULL, NULL, NULL); - } - } - - for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); - gsi_next (&si)) - { - gphi *phi = si.phi (); - stmt_info = loop_vinfo->lookup_stmt (phi); - if (!stmt_info) - continue; - - if (!STMT_VINFO_RELEVANT_P (stmt_info) - && !STMT_VINFO_LIVE_P (stmt_info)) - continue; - - if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_induction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_first_order_recurrence) - && ! PURE_SLP_STMT (stmt_info)) - maybe_set_vectorized_backedge_value (loop_vinfo, stmt_info); - } - - for (gimple_stmt_iterator si = gsi_start_bb (bb); - !gsi_end_p (si);) - { - stmt = gsi_stmt (si); - - /* Ignore vector stmts created in the outer loop. */ - stmt_info = loop_vinfo->lookup_stmt (stmt); - - /* vector stmts created in the outer-loop during vectorization of - stmts in an inner-loop may not have a stmt_info, and do not - need to be vectorized. */ - stmt_vec_info seen_store = NULL; - if (stmt_info) - { - if (STMT_VINFO_IN_PATTERN_P (stmt_info)) - { - gimple *def_seq = STMT_VINFO_PATTERN_DEF_SEQ (stmt_info); - for (gimple_stmt_iterator subsi = gsi_start (def_seq); - !gsi_end_p (subsi); gsi_next (&subsi)) - { - stmt_vec_info pat_stmt_info - = loop_vinfo->lookup_stmt (gsi_stmt (subsi)); - vect_transform_loop_stmt (loop_vinfo, pat_stmt_info, - &si, &seen_store); - } - stmt_vec_info pat_stmt_info - = STMT_VINFO_RELATED_STMT (stmt_info); - if (vect_transform_loop_stmt (loop_vinfo, pat_stmt_info, - &si, &seen_store)) - maybe_set_vectorized_backedge_value (loop_vinfo, - pat_stmt_info); - } - else - { - if (vect_transform_loop_stmt (loop_vinfo, stmt_info, &si, - &seen_store)) - maybe_set_vectorized_backedge_value (loop_vinfo, - stmt_info); - } - } - gsi_next (&si); - if (seen_store) - { - if (STMT_VINFO_GROUPED_ACCESS (seen_store)) - /* Interleaving. If IS_STORE is TRUE, the - vectorization of the interleaving chain was - completed - free all the stores in the chain. */ - vect_remove_stores (loop_vinfo, - DR_GROUP_FIRST_ELEMENT (seen_store)); - else - /* Free the attached stmt_vec_info and remove the stmt. */ - loop_vinfo->remove_stmt (stmt_info); - } - } - - /* Stub out scalar statements that must not survive vectorization. - Doing this here helps with grouped statements, or statements that - are involved in patterns. */ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -12925,8 +12578,16 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) gsi_replace (&gsi, new_stmt, true); } } + else if (ifn == IFN_MASK_CALL + && (stmt_info = loop_vinfo->lookup_stmt (call)) + && !STMT_VINFO_RELEVANT_P (stmt_info) + && !STMT_VINFO_LIVE_P (stmt_info)) + { + gcc_assert (!gimple_call_lhs (stmt_info->stmt)); + loop_vinfo->remove_stmt (stmt_info); + } } - } /* BBs in loop */ + } /* The vectorization factor is always > 1, so if we use an IV increment of 1. a zero NITERS becomes a nonzero NITERS_VECTOR. */ diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index 4f0a7ea..ca19add 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -6544,10 +6544,22 @@ vect_determine_precisions_from_users (stmt_vec_info stmt_info, gassign *stmt) case RSHIFT_EXPR: { tree shift = gimple_assign_rhs2 (stmt); - if (TREE_CODE (shift) != INTEGER_CST - || !wi::ltu_p (wi::to_widest (shift), precision)) + unsigned int min_const_shift, max_const_shift; + wide_int min_shift, max_shift; + if (TREE_CODE (shift) == SSA_NAME + && vect_get_range_info (shift, &min_shift, &max_shift) + && wi::ge_p (min_shift, 0, TYPE_SIGN (TREE_TYPE (shift))) + && wi::lt_p (max_shift, TYPE_PRECISION (type), + TYPE_SIGN (TREE_TYPE (shift)))) + { + min_const_shift = min_shift.to_uhwi (); + max_const_shift = max_shift.to_uhwi (); + } + else if (TREE_CODE (shift) == INTEGER_CST + && wi::ltu_p (wi::to_widest (shift), precision)) + min_const_shift = max_const_shift = TREE_INT_CST_LOW (shift); + else return; - unsigned int const_shift = TREE_INT_CST_LOW (shift); if (code == LSHIFT_EXPR) { /* Avoid creating an undefined shift. @@ -6559,16 +6571,16 @@ vect_determine_precisions_from_users (stmt_vec_info stmt_info, gassign *stmt) of vectorization. This sort of thing should really be handled before vectorization. */ operation_precision = MAX (stmt_info->min_output_precision, - const_shift + 1); + max_const_shift + 1); /* We need CONST_SHIFT fewer bits of the input. */ - min_input_precision = (MAX (operation_precision, const_shift) - - const_shift); + min_input_precision = (MAX (operation_precision, max_const_shift) + - min_const_shift); } else { /* We need CONST_SHIFT extra bits to do the operation. */ operation_precision = (stmt_info->min_output_precision - + const_shift); + + max_const_shift); min_input_precision = operation_precision; } break; diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 5af1973..38612a1 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -14022,7 +14022,7 @@ vect_analyze_stmt (vec_info *vinfo, /* When we arrive here with a non-SLP statement and we are supposed to use SLP for everything fail vectorization. */ - if (!node && param_vect_force_slp) + if (!node) return opt_result::failure_at (stmt_info->stmt, "needs non-SLP handling\n"); @@ -14131,6 +14131,10 @@ vect_transform_stmt (vec_info *vinfo, gcc_assert (slp_node || !PURE_SLP_STMT (stmt_info)); + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "------>vectorizing statement: %G", stmt_info->stmt); + tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info); if (slp_node) STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (slp_node); diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 5136674..a770b41 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2251,37 +2251,9 @@ irange::invert () verify_range (); } -// Remove trailing ranges that this bitmask indicates can't exist. - -void -irange_bitmask::adjust_range (irange &r) const -{ - if (unknown_p () || r.undefined_p ()) - return; - - int_range_max range; - tree type = r.type (); - int prec = TYPE_PRECISION (type); - // If there are trailing zeros, create a range representing those bits. - gcc_checking_assert (m_mask != 0); - int z = wi::ctz (m_mask); - if (z) - { - wide_int ub = (wi::one (prec) << z) - 1; - range = int_range<5> (type, wi::zero (prec), ub); - // Then remove the specific value these bits contain from the range. - wide_int value = m_value & ub; - range.intersect (int_range<2> (type, value, value, VR_ANTI_RANGE)); - // Inverting produces a list of ranges which can be valid. - range.invert (); - // And finally select R from only those valid values. - r.intersect (range); - return; - } -} - -// If the mask can be trivially converted to a range, do so and -// return TRUE. +// If the mask can be trivially converted to a range, do so. +// Otherwise attempt to remove the lower bits from the range. +// Return true if the range changed in any way. bool irange::set_range_from_bitmask () @@ -2326,7 +2298,28 @@ irange::set_range_from_bitmask () set_zero (type ()); return true; } - return false; + + // If the mask doesn't have any trailing zero, return. + int z = wi::ctz (m_bitmask.mask ()); + if (!z) + return false; + + // Remove trailing ranges that this bitmask indicates can't exist. + int_range_max mask_range; + int prec = TYPE_PRECISION (type ()); + wide_int ub = (wi::one (prec) << z) - 1; + mask_range = int_range<2> (type (), wi::zero (prec), ub); + + // Then remove the specific value these bits contain from the range. + wide_int value = m_bitmask.value () & ub; + mask_range.intersect (int_range<2> (type (), value, value, VR_ANTI_RANGE)); + + // Inverting produces a list of ranges which can be valid. + mask_range.invert (); + + // And finally select R from only those valid values. + intersect (mask_range); + return true; } void @@ -2334,6 +2327,10 @@ irange::update_bitmask (const irange_bitmask &bm) { gcc_checking_assert (!undefined_p ()); + // If masks are the same, there is no change. + if (m_bitmask == bm) + return; + // Drop VARYINGs with known bits to a plain range. if (m_kind == VR_VARYING && !bm.unknown_p ()) m_kind = VR_RANGE; @@ -2408,7 +2405,7 @@ irange::intersect_bitmask (const irange &r) { gcc_checking_assert (!undefined_p () && !r.undefined_p ()); - if (m_bitmask == r.m_bitmask) + if (r.m_bitmask.unknown_p () || m_bitmask == r.m_bitmask) return false; irange_bitmask bm = get_bitmask (); @@ -2427,7 +2424,6 @@ irange::intersect_bitmask (const irange &r) if (!set_range_from_bitmask ()) normalize_kind (); - m_bitmask.adjust_range (*this); if (flag_checking) verify_range (); return true; diff --git a/gcc/value-range.h b/gcc/value-range.h index b50cb89..f694298 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -149,7 +149,6 @@ public: void dump (FILE *) const; bool member_p (const wide_int &val) const; - void adjust_range (irange &r) const; // Convenience functions for nonzero bitmask compatibility. wide_int get_nonzero_bits () const; diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index 08449b7..c7ced44 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -780,15 +780,20 @@ equiv_oracle::dump (FILE *f) const // -------------------------------------------------------------------------- -// Negate the current relation. + +// Adjust the relation by Swapping the operands and relation. void -value_relation::negate () +value_relation::swap () { - related = relation_negate (related); + related = relation_swap (related); + tree tmp = name1; + name1 = name2; + name2 = tmp; } // Perform an intersection between 2 relations. *this &&= p. +// Return false if the relations cannot be intersected. bool value_relation::intersect (value_relation &p) @@ -951,6 +956,79 @@ public: relation_chain *m_next; }; +// Given relation record PTR in block BB, return the next relation in the +// list. If PTR is NULL, retreive the first relation in BB. +// If NAME is sprecified, return only relations which include NAME. +// Return NULL when there are no relations left. + +relation_chain * +dom_oracle::next_relation (basic_block bb, relation_chain *ptr, + tree name) const +{ + relation_chain *p; + // No value_relation pointer is used to intialize the iterator. + if (!ptr) + { + int bbi = bb->index; + if (bbi >= (int)m_relations.length()) + return NULL; + else + p = m_relations[bbi].m_head; + } + else + p = ptr->m_next; + + if (name) + for ( ; p; p = p->m_next) + if (p->op1 () == name || p->op2 () == name) + break; + return p; +} + +// Instatiate a block relation iterator to iterate over the relations +// on exit from block BB in ORACLE. Limit this to relations involving NAME +// if specified. Return the first such relation in VR if there is one. + +block_relation_iterator::block_relation_iterator (const relation_oracle *oracle, + basic_block bb, + value_relation &vr, + tree name) +{ + m_oracle = oracle; + m_bb = bb; + m_name = name; + m_ptr = oracle->next_relation (bb, NULL, m_name); + if (m_ptr) + { + m_done = false; + vr = *m_ptr; + } + else + m_done = true; +} + +// Retreive the next relation from the iterator and return it in VR. + +void +block_relation_iterator::get_next_relation (value_relation &vr) +{ + m_ptr = m_oracle->next_relation (m_bb, m_ptr, m_name); + if (m_ptr) + { + vr = *m_ptr; + if (m_name) + { + if (vr.op1 () != m_name) + { + gcc_checking_assert (vr.op2 () == m_name); + vr.swap (); + } + } + } + else + m_done = true; +} + // ------------------------------------------------------------------------ // Find the relation between any ssa_name in B1 and any name in B2 in LIST. @@ -1441,11 +1519,11 @@ dom_oracle::dump (FILE *f, basic_block bb) const if (!m_relations[bb->index].m_names) return; - relation_chain *ptr = m_relations[bb->index].m_head; - for (; ptr; ptr = ptr->m_next) + value_relation vr; + FOR_EACH_RELATION_BB (this, bb, vr) { fprintf (f, "Relational : "); - ptr->dump (f); + vr.dump (f); fprintf (f, "\n"); } } diff --git a/gcc/value-relation.h b/gcc/value-relation.h index 23cfb41..1081877 100644 --- a/gcc/value-relation.h +++ b/gcc/value-relation.h @@ -114,6 +114,11 @@ public: void debug () const; protected: friend class equiv_relation_iterator; + friend class block_relation_iterator; + virtual class relation_chain *next_relation (basic_block, + relation_chain *, + tree) const + { return NULL; } // Return equivalency set for an SSA name in a basic block. virtual const_bitmap equiv_set (tree, basic_block) { return NULL; } // Return partial equivalency record for an SSA name. @@ -228,7 +233,9 @@ public: void dump (FILE *f, basic_block bb) const final override; void dump (FILE *f) const final override; -private: +protected: + virtual relation_chain *next_relation (basic_block, relation_chain *, + tree) const; bool m_do_trans_p; bitmap m_tmp, m_tmp2; bitmap m_relation_set; // Index by ssa-name. True if a relation exists @@ -431,7 +438,7 @@ public: relation_trio create_trio (tree lhs, tree op1, tree op2); bool union_ (value_relation &p); bool intersect (value_relation &p); - void negate (); + void swap (); bool apply_transitive (const value_relation &rel); void dump (FILE *f) const; @@ -470,6 +477,30 @@ value_relation::value_relation (relation_kind kind, tree n1, tree n2) set_relation (kind, n1, n2); } + +class block_relation_iterator { +public: + block_relation_iterator (const relation_oracle *oracle, basic_block bb, + value_relation &, tree name = NULL); + void get_next_relation (value_relation &vr); + const relation_oracle *m_oracle; + basic_block m_bb; + relation_chain *m_ptr; + bool m_done; + tree m_name; +}; + +#define FOR_EACH_RELATION_BB(oracle, bb, vr) \ + for (block_relation_iterator iter (oracle, bb, vr); \ + !iter.m_done; \ + iter.get_next_relation (vr)) + +#define FOR_EACH_RELATION_NAME(oracle, bb, name, vr) \ + for (block_relation_iterator iter (oracle, bb, vr, name); \ + !iter.m_done; \ + iter.get_next_relation (vr)) + + // Return the number of bits associated with partial equivalency T. // Return 0 if this is not a supported partial equivalency relation. |