i386: move alignment defaults to processor_costs.
[official-gcc.git] / gcc / substring-locations.c
blobfaf78845840d01e945b328417493231f3161aeca
1 /* Source locations within string literals.
2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "intl.h"
24 #include "diagnostic.h"
25 #include "cpplib.h"
26 #include "tree.h"
27 #include "langhooks.h"
28 #include "substring-locations.h"
29 #include "gcc-rich-location.h"
31 /* Emit a warning governed by option OPT, using SINGULAR_GMSGID as the
32 format string (or if PLURAL_GMSGID is different from SINGULAR_GMSGID,
33 using SINGULAR_GMSGID, PLURAL_GMSGID and N as arguments to ngettext)
34 and AP as its arguments.
36 Attempt to obtain precise location information within a string
37 literal from FMT_LOC.
39 Case 1: if substring location is available, and is within the range of
40 the format string itself, the primary location of the
41 diagnostic is the substring range obtained from FMT_LOC, with the
42 caret at the *end* of the substring range.
44 For example:
46 test.c:90:10: warning: problem with '%i' here [-Wformat=]
47 printf ("hello %i", msg);
50 Case 2: if the substring location is available, but is not within
51 the range of the format string, the primary location is that of the
52 format string, and an note is emitted showing the substring location.
54 For example:
55 test.c:90:10: warning: problem with '%i' here [-Wformat=]
56 printf("hello " INT_FMT " world", msg);
57 ^~~~~~~~~~~~~~~~~~~~~~~~~
58 test.c:19: note: format string is defined here
59 #define INT_FMT "%i"
62 Case 3: if precise substring information is unavailable, the primary
63 location is that of the whole string passed to FMT_LOC's constructor.
64 For example:
66 test.c:90:10: warning: problem with '%i' here [-Wformat=]
67 printf(fmt, msg);
68 ^~~
70 For each of cases 1-3, if param_loc is not UNKNOWN_LOCATION, then it is used
71 as a secondary range within the warning. For example, here it
72 is used with case 1:
74 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
75 printf ("foo %s bar", long_i + long_j);
76 ~^ ~~~~~~~~~~~~~~~
78 and here with case 2:
80 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
81 printf ("foo " STR_FMT " bar", long_i + long_j);
82 ^~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
83 test.c:89:16: note: format string is defined here
84 #define STR_FMT "%s"
87 and with case 3:
89 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
90 printf(fmt, msg);
91 ^~~ ~~~
93 If non-NULL, then FMT_LABEL will be used to label the location within the
94 string for cases 1 and 2; if non-NULL, then PARAM_LABEL will be used to label
95 the parameter. For example with case 1:
97 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
98 printf ("foo %s bar", long_i + long_j);
99 ~^ ~~~~~~~~~~~~~~~
103 and with case 2:
105 test.c:90:10: warning: problem with '%i' here [-Wformat=]
106 printf("hello " INT_FMT " world", msg);
107 ^~~~~~~~~~~~~~~~~~~~~~~~~
108 test.c:19: note: format string is defined here
109 #define INT_FMT "%i"
114 If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide
115 a fix-it hint, suggesting that it should replace the text within the
116 substring range. For example:
118 test.c:90:10: warning: problem with '%i' here [-Wformat=]
119 printf ("hello %i", msg);
123 Return true if a warning was emitted, false otherwise. */
125 bool
126 format_warning_n_va (const substring_loc &fmt_loc,
127 const range_label *fmt_label,
128 location_t param_loc,
129 const range_label *param_label,
130 const char *corrected_substring,
131 int opt, unsigned HOST_WIDE_INT n,
132 const char *singular_gmsgid,
133 const char *plural_gmsgid, va_list *ap)
135 bool substring_within_range = false;
136 location_t primary_loc;
137 location_t fmt_substring_loc = UNKNOWN_LOCATION;
138 source_range fmt_loc_range
139 = get_range_from_loc (line_table, fmt_loc.get_fmt_string_loc ());
140 const char *err = fmt_loc.get_location (&fmt_substring_loc);
141 source_range fmt_substring_range
142 = get_range_from_loc (line_table, fmt_substring_loc);
143 if (err)
144 /* Case 3: unable to get substring location. */
145 primary_loc = fmt_loc.get_fmt_string_loc ();
146 else
148 if (fmt_substring_range.m_start >= fmt_loc_range.m_start
149 && fmt_substring_range.m_start <= fmt_loc_range.m_finish
150 && fmt_substring_range.m_finish >= fmt_loc_range.m_start
151 && fmt_substring_range.m_finish <= fmt_loc_range.m_finish)
152 /* Case 1. */
154 substring_within_range = true;
155 primary_loc = fmt_substring_loc;
157 else
158 /* Case 2. */
160 substring_within_range = false;
161 primary_loc = fmt_loc.get_fmt_string_loc ();
165 /* Only use fmt_label in the initial warning for case 1. */
166 const range_label *primary_label = NULL;
167 if (substring_within_range)
168 primary_label = fmt_label;
170 auto_diagnostic_group d;
171 gcc_rich_location richloc (primary_loc, primary_label);
173 if (param_loc != UNKNOWN_LOCATION)
174 richloc.add_range (param_loc, SHOW_RANGE_WITHOUT_CARET, param_label);
176 if (!err && corrected_substring && substring_within_range)
177 richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
179 diagnostic_info diagnostic;
180 if (singular_gmsgid != plural_gmsgid)
182 unsigned long gtn;
184 if (sizeof n <= sizeof gtn)
185 gtn = n;
186 else
187 /* Use the largest number ngettext can handle, otherwise
188 preserve the six least significant decimal digits for
189 languages where the plural form depends on them. */
190 gtn = n <= ULONG_MAX ? n : n % 1000000LU + 1000000LU;
192 const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
193 diagnostic_set_info_translated (&diagnostic, text, ap, &richloc,
194 DK_WARNING);
196 else
197 diagnostic_set_info (&diagnostic, singular_gmsgid, ap, &richloc,
198 DK_WARNING);
199 diagnostic.option_index = opt;
200 bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
202 if (!err && fmt_substring_loc && !substring_within_range)
203 /* Case 2. */
204 if (warned)
206 /* Use fmt_label in the note for case 2. */
207 rich_location substring_richloc (line_table, fmt_substring_loc,
208 fmt_label);
209 if (corrected_substring)
210 substring_richloc.add_fixit_replace (fmt_substring_range,
211 corrected_substring);
212 inform (&substring_richloc,
213 "format string is defined here");
216 return warned;
219 /* Singular-only version of the above. */
221 bool
222 format_warning_va (const substring_loc &fmt_loc,
223 const range_label *fmt_label,
224 location_t param_loc,
225 const range_label *param_label,
226 const char *corrected_substring,
227 int opt, const char *gmsgid, va_list *ap)
229 return format_warning_n_va (fmt_loc, fmt_label, param_loc, param_label,
230 corrected_substring, opt,
231 0, gmsgid, gmsgid, ap);
234 /* Variadic call to format_warning_va. */
236 bool
237 format_warning_at_substring (const substring_loc &fmt_loc,
238 const range_label *fmt_label,
239 location_t param_loc,
240 const range_label *param_label,
241 const char *corrected_substring,
242 int opt, const char *gmsgid, ...)
244 va_list ap;
245 va_start (ap, gmsgid);
246 bool warned = format_warning_va (fmt_loc, fmt_label, param_loc, param_label,
247 corrected_substring, opt, gmsgid, &ap);
248 va_end (ap);
250 return warned;
253 /* Variadic call to format_warning_n_va. */
255 bool
256 format_warning_at_substring_n (const substring_loc &fmt_loc,
257 const range_label *fmt_label,
258 location_t param_loc,
259 const range_label *param_label,
260 const char *corrected_substring,
261 int opt, unsigned HOST_WIDE_INT n,
262 const char *singular_gmsgid,
263 const char *plural_gmsgid, ...)
265 va_list ap;
266 va_start (ap, plural_gmsgid);
267 bool warned = format_warning_n_va (fmt_loc, fmt_label, param_loc, param_label,
268 corrected_substring,
269 opt, n, singular_gmsgid, plural_gmsgid,
270 &ap);
271 va_end (ap);
273 return warned;
276 /* Attempt to determine the source location of the substring.
277 If successful, return NULL and write the source location to *OUT_LOC.
278 Otherwise return an error message. Error messages are intended
279 for GCC developers (to help debugging) rather than for end-users. */
281 const char *
282 substring_loc::get_location (location_t *out_loc) const
284 gcc_assert (out_loc);
285 return lang_hooks.get_substring_location (*this, out_loc);