1 /* This plugin uses the diagnostics code to verify tracking of source code
2 locations within string literals. */
3 /* { dg-options "-O" } */
5 #include "gcc-plugin.h"
11 #include "stringpool.h"
13 #include "basic-block.h"
14 #include "hash-table.h"
17 #include "basic-block.h"
18 #include "tree-ssa-alias.h"
19 #include "internal-fn.h"
20 #include "gimple-fold.h"
22 #include "gimple-expr.h"
25 #include "gimple-iterator.h"
27 #include "tree-pass.h"
29 #include "plugin-version.h"
30 #include "c-family/c-common.h"
31 #include "diagnostic.h"
33 #include "print-tree.h"
35 #include "c-family/c-pragma.h"
36 #include "substring-locations.h"
38 int plugin_is_GPL_compatible
;
40 /* A custom pass for printing string literal location information. */
42 const pass_data pass_data_test_string_literals
=
44 GIMPLE_PASS
, /* type */
45 "test_string_literals", /* name */
46 OPTGROUP_NONE
, /* optinfo_flags */
48 PROP_ssa
, /* properties_required */
49 0, /* properties_provided */
50 0, /* properties_destroyed */
51 0, /* todo_flags_start */
52 0, /* todo_flags_finish */
55 class pass_test_string_literals
: public gimple_opt_pass
58 pass_test_string_literals(gcc::context
*ctxt
)
59 : gimple_opt_pass(pass_data_test_string_literals
, ctxt
)
62 /* opt_pass methods: */
63 bool gate (function
*) { return true; }
64 virtual unsigned int execute (function
*);
66 }; // class pass_test_string_literals
68 /* Determine if STMT is a call with NUM_ARGS arguments to a function
70 If so, return STMT as a gcall *. Otherwise return NULL. */
73 check_for_named_call (gimple
*stmt
,
74 const char *funcname
, unsigned int num_args
)
76 gcc_assert (funcname
);
78 gcall
*call
= dyn_cast
<gcall
*> (stmt
);
82 tree fndecl
= gimple_call_fndecl (call
);
86 if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl
)), funcname
))
89 if (gimple_call_num_args (call
) != num_args
)
91 error_at (stmt
->location
, "expected number of args: %i (got %i)",
92 num_args
, gimple_call_num_args (call
));
99 /* Emit a warning at LOC. */
102 emit_warning (location_t loc
)
104 source_range src_range
= get_range_from_loc (line_table
, loc
);
105 warning_at (loc
, 0, "range %i:%i-%i:%i",
106 LOCATION_LINE (src_range
.m_start
),
107 LOCATION_COLUMN (src_range
.m_start
),
108 LOCATION_LINE (src_range
.m_finish
),
109 LOCATION_COLUMN (src_range
.m_finish
));
112 /* Support code for verifying that we are correctly tracking ranges
113 within string literals, for use by diagnostic-test-string-literals-*.c.
114 Emit a warning showing the range of a string literal, for each call to
115 a function named "__emit_string_literal_range".
116 The initial argument should be a string literal; arguments 2, 3, and 4
117 should be integer constants, giving the caret and range within the string
121 test_string_literals (gimple
*stmt
)
123 gcall
*call
= check_for_named_call (stmt
, "__emit_string_literal_range", 4);
127 /* We expect an ADDR_EXPR with a STRING_CST inside it for the
129 tree t_addr_string
= gimple_call_arg (call
, 0);
130 if (TREE_CODE (t_addr_string
) != ADDR_EXPR
)
132 error_at (call
->location
, "string literal required for arg 1");
136 tree t_string
= TREE_OPERAND (t_addr_string
, 0);
137 if (TREE_CODE (t_string
) != STRING_CST
)
139 error_at (call
->location
, "string literal required for arg 1");
143 tree t_caret_idx
= gimple_call_arg (call
, 1);
144 if (TREE_CODE (t_caret_idx
) != INTEGER_CST
)
146 error_at (call
->location
, "integer constant required for arg 2");
149 int caret_idx
= TREE_INT_CST_LOW (t_caret_idx
);
151 tree t_start_idx
= gimple_call_arg (call
, 2);
152 if (TREE_CODE (t_start_idx
) != INTEGER_CST
)
154 error_at (call
->location
, "integer constant required for arg 3");
157 int start_idx
= TREE_INT_CST_LOW (t_start_idx
);
159 tree t_end_idx
= gimple_call_arg (call
, 3);
160 if (TREE_CODE (t_end_idx
) != INTEGER_CST
)
162 error_at (call
->location
, "integer constant required for arg 4");
165 int end_idx
= TREE_INT_CST_LOW (t_end_idx
);
167 /* A STRING_CST doesn't have a location, but the ADDR_EXPR does. */
168 location_t strloc
= EXPR_LOCATION (t_addr_string
);
170 substring_loc
substr_loc (strloc
, TREE_TYPE (t_string
),
171 caret_idx
, start_idx
, end_idx
);
172 const char *err
= substr_loc
.get_location (&loc
);
174 error_at (strloc
, "unable to read substring location: %s", err
);
179 /* Call test_string_literals on every statement within FUN. */
182 pass_test_string_literals::execute (function
*fun
)
184 gimple_stmt_iterator gsi
;
187 FOR_EACH_BB_FN (bb
, fun
)
188 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
190 gimple
*stmt
= gsi_stmt (gsi
);
191 test_string_literals (stmt
);
197 /* Entrypoint for the plugin. Create and register the custom pass. */
200 plugin_init (struct plugin_name_args
*plugin_info
,
201 struct plugin_gcc_version
*version
)
203 struct register_pass_info pass_info
;
204 const char *plugin_name
= plugin_info
->base_name
;
205 int argc
= plugin_info
->argc
;
206 struct plugin_argument
*argv
= plugin_info
->argv
;
208 if (!plugin_default_version_check (version
, &gcc_version
))
211 pass_info
.pass
= new pass_test_string_literals (g
);
212 pass_info
.reference_pass_name
= "ssa";
213 pass_info
.ref_pass_instance_number
= 1;
214 pass_info
.pos_op
= PASS_POS_INSERT_AFTER
;
215 register_callback (plugin_name
, PLUGIN_PASS_MANAGER_SETUP
, NULL
,