diff options
Diffstat (limited to 'gcc')
341 files changed, 9039 insertions, 3316 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5e84f05..eab3231 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,296 @@ +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 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index bd9df64..e697180 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250428 +20250429 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-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 c8f9206..4c8fde7 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,31 @@ +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 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/cp/ChangeLog b/gcc/cp/ChangeLog index 9d5db06..480e9c4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +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 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/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 7fcf7de..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 @@ -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 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/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/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/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 d3e3a2d..a9b9b91 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -3628,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/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/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 314de8d..053765b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,315 @@ +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 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/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/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/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/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/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/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/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-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-tailcall.cc b/gcc/tree-tailcall.cc index fc05928..10e88d9 100644 --- a/gcc/tree-tailcall.cc +++ b/gcc/tree-tailcall.cc @@ -1082,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/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. |