| /* { dg-options "-O" } */ |
| |
| #include "gcc-plugin.h" |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "stringpool.h" |
| #include "toplev.h" |
| #include "basic-block.h" |
| #include "hash-table.h" |
| #include "vec.h" |
| #include "ggc.h" |
| #include "basic-block.h" |
| #include "tree-ssa-alias.h" |
| #include "internal-fn.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 "tree.h" |
| #include "tree-pass.h" |
| #include "intl.h" |
| #include "plugin-version.h" |
| #include "c-family/c-common.h" |
| #include "diagnostic.h" |
| #include "context.h" |
| |
| int plugin_is_GPL_compatible; |
| |
| /* A custom pass for injecting a crash in the middle-end when compiling |
| certain functions. */ |
| |
| const pass_data pass_data_crash_test = |
| { |
| GIMPLE_PASS, /* type */ |
| "crash_test", /* name */ |
| OPTGROUP_NONE, /* optinfo_flags */ |
| TV_NONE, /* tv_id */ |
| PROP_ssa, /* properties_required */ |
| 0, /* properties_provided */ |
| 0, /* properties_destroyed */ |
| 0, /* todo_flags_start */ |
| 0, /* todo_flags_finish */ |
| }; |
| |
| class pass_crash_test : public gimple_opt_pass |
| { |
| public: |
| pass_crash_test (gcc::context *ctxt, bool nested) |
| : gimple_opt_pass (pass_data_crash_test, ctxt), |
| m_nested (nested) |
| {} |
| |
| /* opt_pass methods: */ |
| bool gate (function *) final override { return true; } |
| unsigned int execute (function *) final override; |
| |
| private: |
| /* If true, inject the crash whilst within a nested diagnostic |
| (PR diagnostics/121876). */ |
| bool m_nested; |
| |
| }; // class pass_test_groups |
| |
| /* Determine if STMT is a call to a function named FUNCNAME. |
| If so, return STMT as a gcall *. Otherwise return NULL. */ |
| |
| static gcall * |
| check_for_named_call (gimple *stmt, const char *funcname) |
| { |
| gcc_assert (funcname); |
| |
| gcall *call = dyn_cast <gcall *> (stmt); |
| if (!call) |
| return NULL; |
| |
| tree fndecl = gimple_call_fndecl (call); |
| if (!fndecl) |
| return NULL; |
| |
| if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname)) |
| return NULL; |
| |
| return call; |
| } |
| |
| unsigned int |
| pass_crash_test::execute (function *fun) |
| { |
| gimple_stmt_iterator gsi; |
| basic_block bb; |
| |
| FOR_EACH_BB_FN (bb, fun) |
| for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) |
| { |
| gimple *stmt = gsi_stmt (gsi); |
| if (gcall *call = check_for_named_call (stmt, "inject_ice")) |
| { |
| auto_diagnostic_group d; |
| if (m_nested) |
| { |
| error_at (stmt->location, "placeholder"); |
| global_dc->push_nesting_level (); |
| } |
| |
| input_location = stmt->location; |
| internal_error ("I'm sorry Dave, I'm afraid I can't do that"); |
| |
| if (m_nested) |
| { |
| global_dc->pop_nesting_level (); |
| } |
| } |
| if (gcall *call = check_for_named_call (stmt, |
| "inject_write_through_null")) |
| { |
| auto_diagnostic_group d; |
| if (m_nested) |
| { |
| error_at (stmt->location, "placeholder"); |
| global_dc->push_nesting_level (); |
| } |
| |
| input_location = stmt->location; |
| int *p = NULL; |
| *p = 42; |
| |
| if (m_nested) |
| { |
| global_dc->pop_nesting_level (); |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| /* Entrypoint for the plugin. |
| Create and register the custom pass. */ |
| |
| int |
| plugin_init (struct plugin_name_args *plugin_info, |
| struct plugin_gcc_version *version) |
| { |
| struct register_pass_info pass_info; |
| const char *plugin_name = plugin_info->base_name; |
| int argc = plugin_info->argc; |
| struct plugin_argument *argv = plugin_info->argv; |
| |
| if (!plugin_default_version_check (version, &gcc_version)) |
| return 1; |
| |
| bool nested = false; |
| |
| for (int i = 0; i < argc; i++) |
| { |
| if (!strcmp (argv[i].key, "nested")) |
| nested = true; |
| } |
| |
| pass_info.pass = new pass_crash_test (g, nested); |
| pass_info.reference_pass_name = "*warn_function_noreturn"; |
| pass_info.ref_pass_instance_number = 1; |
| pass_info.pos_op = PASS_POS_INSERT_AFTER; |
| register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, |
| &pass_info); |
| |
| return 0; |
| } |