131
|
1 /* { dg-options "-O" } */
|
|
2
|
|
3 #include "gcc-plugin.h"
|
|
4 #include "config.h"
|
|
5 #include "system.h"
|
|
6 #include "coretypes.h"
|
|
7 #include "tm.h"
|
|
8 #include "tree.h"
|
|
9 #include "stringpool.h"
|
|
10 #include "toplev.h"
|
|
11 #include "basic-block.h"
|
|
12 #include "hash-table.h"
|
|
13 #include "vec.h"
|
|
14 #include "ggc.h"
|
|
15 #include "basic-block.h"
|
|
16 #include "tree-ssa-alias.h"
|
|
17 #include "internal-fn.h"
|
|
18 #include "gimple-fold.h"
|
|
19 #include "tree-eh.h"
|
|
20 #include "gimple-expr.h"
|
|
21 #include "is-a.h"
|
|
22 #include "gimple.h"
|
|
23 #include "gimple-iterator.h"
|
|
24 #include "tree.h"
|
|
25 #include "tree-pass.h"
|
|
26 #include "intl.h"
|
|
27 #include "plugin-version.h"
|
|
28 #include "c-family/c-common.h"
|
|
29 #include "diagnostic.h"
|
|
30 #include "context.h"
|
|
31 #include "print-tree.h"
|
|
32 #include "cpplib.h"
|
|
33 #include "c-family/c-pragma.h"
|
|
34 #include "substring-locations.h"
|
|
35
|
|
36 int plugin_is_GPL_compatible;
|
|
37
|
|
38 /* A custom pass for emitting dummy warnings from the middle-end. */
|
|
39
|
|
40 const pass_data pass_data_test_inlining =
|
|
41 {
|
|
42 GIMPLE_PASS, /* type */
|
|
43 "test_inlining", /* name */
|
|
44 OPTGROUP_NONE, /* optinfo_flags */
|
|
45 TV_NONE, /* tv_id */
|
|
46 PROP_ssa, /* properties_required */
|
|
47 0, /* properties_provided */
|
|
48 0, /* properties_destroyed */
|
|
49 0, /* todo_flags_start */
|
|
50 0, /* todo_flags_finish */
|
|
51 };
|
|
52
|
|
53 class pass_test_inlining : public gimple_opt_pass
|
|
54 {
|
|
55 public:
|
|
56 pass_test_inlining(gcc::context *ctxt)
|
|
57 : gimple_opt_pass(pass_data_test_inlining, ctxt)
|
|
58 {}
|
|
59
|
|
60 /* opt_pass methods: */
|
|
61 bool gate (function *) { return true; }
|
|
62 virtual unsigned int execute (function *);
|
|
63
|
|
64 }; // class pass_test_inlining
|
|
65
|
|
66 /* Determine if STMT is a call with NUM_ARGS arguments to a function
|
|
67 named FUNCNAME.
|
|
68 If so, return STMT as a gcall *. Otherwise return NULL. */
|
|
69
|
|
70 static gcall *
|
|
71 check_for_named_call (gimple *stmt,
|
|
72 const char *funcname, unsigned int num_args)
|
|
73 {
|
|
74 gcc_assert (funcname);
|
|
75
|
|
76 gcall *call = dyn_cast <gcall *> (stmt);
|
|
77 if (!call)
|
|
78 return NULL;
|
|
79
|
|
80 tree fndecl = gimple_call_fndecl (call);
|
|
81 if (!fndecl)
|
|
82 return NULL;
|
|
83
|
|
84 if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
|
|
85 return NULL;
|
|
86
|
|
87 if (gimple_call_num_args (call) != num_args)
|
|
88 {
|
|
89 error_at (stmt->location, "expected number of args: %i (got %i)",
|
|
90 num_args, gimple_call_num_args (call));
|
|
91 return NULL;
|
|
92 }
|
|
93
|
|
94 return call;
|
|
95 }
|
|
96
|
|
97 /* Emit a warning at LOC. */
|
|
98
|
|
99 static void
|
|
100 emit_warning (location_t loc)
|
|
101 {
|
|
102 source_range src_range = get_range_from_loc (line_table, loc);
|
|
103 warning_at (loc, 0, "range %i:%i-%i:%i",
|
|
104 LOCATION_LINE (src_range.m_start),
|
|
105 LOCATION_COLUMN (src_range.m_start),
|
|
106 LOCATION_LINE (src_range.m_finish),
|
|
107 LOCATION_COLUMN (src_range.m_finish));
|
|
108 }
|
|
109
|
|
110 /* Code for simulating the emission of a warning from the middle-end.
|
|
111 Emit a warning for each call to a function named "__emit_warning". */
|
|
112
|
|
113 static void
|
|
114 test_inlining (gimple *stmt)
|
|
115 {
|
|
116 gcall *call = check_for_named_call (stmt, "__emit_warning", 1);
|
|
117 if (!call)
|
|
118 return;
|
|
119
|
|
120 /* We expect an ADDR_EXPR with a STRING_CST inside it for the
|
|
121 initial arg. */
|
|
122 tree t_addr_string = gimple_call_arg (call, 0);
|
|
123 if (TREE_CODE (t_addr_string) != ADDR_EXPR)
|
|
124 {
|
|
125 error_at (call->location, "string literal required for arg 1");
|
|
126 return;
|
|
127 }
|
|
128
|
|
129 tree t_string = TREE_OPERAND (t_addr_string, 0);
|
|
130 if (TREE_CODE (t_string) != STRING_CST)
|
|
131 {
|
|
132 error_at (call->location, "string literal required for arg 1");
|
|
133 return;
|
|
134 }
|
|
135
|
|
136 warning_at (call->location, 0, "%G%s", call,
|
|
137 TREE_STRING_POINTER (t_string));
|
|
138 }
|
|
139
|
|
140 /* Call test_inlining on every statement within FUN. */
|
|
141
|
|
142 unsigned int
|
|
143 pass_test_inlining::execute (function *fun)
|
|
144 {
|
|
145 gimple_stmt_iterator gsi;
|
|
146 basic_block bb;
|
|
147
|
|
148 FOR_EACH_BB_FN (bb, fun)
|
|
149 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
|
150 {
|
|
151 gimple *stmt = gsi_stmt (gsi);
|
|
152 test_inlining (stmt);
|
|
153 }
|
|
154
|
|
155 return 0;
|
|
156 }
|
|
157
|
|
158 /* Entrypoint for the plugin. Create and register the custom pass. */
|
|
159
|
|
160 int
|
|
161 plugin_init (struct plugin_name_args *plugin_info,
|
|
162 struct plugin_gcc_version *version)
|
|
163 {
|
|
164 struct register_pass_info pass_info;
|
|
165 const char *plugin_name = plugin_info->base_name;
|
|
166 int argc = plugin_info->argc;
|
|
167 struct plugin_argument *argv = plugin_info->argv;
|
|
168
|
|
169 if (!plugin_default_version_check (version, &gcc_version))
|
|
170 return 1;
|
|
171
|
|
172 pass_info.pass = new pass_test_inlining (g);
|
|
173 pass_info.reference_pass_name = "*warn_function_noreturn";
|
|
174 pass_info.ref_pass_instance_number = 1;
|
|
175 pass_info.pos_op = PASS_POS_INSERT_AFTER;
|
|
176 register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
|
|
177 &pass_info);
|
|
178
|
|
179 return 0;
|
|
180 }
|