]> git.saurik.com Git - bison.git/blob - src/complain.c
style: move argument handling of -W into the diagnostics module
[bison.git] / src / complain.c
1 /* Declaration for error-reporting function for Bison.
2
3 Copyright (C) 2000-2002, 2004-2006, 2009-2013 Free Software
4 Foundation, Inc.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 /* Based on error.c and error.h,
20 written by David MacKenzie <djm@gnu.ai.mit.edu>. */
21
22 #include <config.h>
23 #include "system.h"
24
25 #include <argmatch.h>
26 #include <stdarg.h>
27 #include <progname.h>
28
29 #include "complain.h"
30 #include "files.h"
31 #include "getargs.h"
32 #include "quote.h"
33
34 err_status complaint_status = status_none;
35
36 bool warnings_are_errors = false;
37
38 /** Diagnostics severity. */
39 typedef enum
40 {
41 severity_disabled = 0,
42 severity_unset = 1,
43 severity_warning = 2,
44 severity_error = 3,
45 severity_fatal = 4
46 } severity;
47
48
49 /** For each warning type, its severity. */
50 static severity warnings_flag[warnings_size];
51
52 static unsigned *indent_ptr = 0;
53
54 /*------------------------.
55 | --warnings's handling. |
56 `------------------------*/
57
58 static const char * const warnings_args[] =
59 {
60 "none",
61 "midrule-values",
62 "yacc",
63 "conflicts-sr",
64 "conflicts-rr",
65 "deprecated",
66 "precedence",
67 "other",
68 "all",
69 "error",
70 0
71 };
72
73 static const int warnings_types[] =
74 {
75 Wnone,
76 Wmidrule_values,
77 Wyacc,
78 Wconflicts_sr,
79 Wconflicts_rr,
80 Wdeprecated,
81 Wprecedence,
82 Wother,
83 Wall,
84 Werror
85 };
86
87 ARGMATCH_VERIFY (warnings_args, warnings_types);
88
89 void
90 warning_argmatch (char const *arg, size_t no, size_t err)
91 {
92 int value = XARGMATCH ("--warning", arg + no + err,
93 warnings_args, warnings_types);
94
95 /* -Wnone == -Wno-all, and -Wno-none == -Wall. */
96 if (!value)
97 {
98 value = Wall;
99 no = !no;
100 }
101
102 if (no)
103 {
104 size_t b;
105 for (b = 0; b < warnings_size; ++b)
106 if (value & 1 << b)
107 {
108 if (err)
109 {
110 /* -Wno-error=foo: if foo enabled as an error,
111 make it a warning. */
112 if (warnings_flag[b] == severity_error)
113 warnings_flag[b] = severity_warning;
114 }
115 else
116 /* -Wno-foo. */
117 warnings_flag[b] = severity_disabled;
118 }
119 }
120 else
121 {
122 size_t b;
123 for (b = 0; b < warnings_size; ++b)
124 if (value & 1 << b)
125 /* -Wfoo and -Werror=foo. */
126 warnings_flag[b] = err ? severity_error : severity_warning;
127 }
128 }
129
130 /** Decode a comma-separated list of arguments from -W.
131 *
132 * \param args comma separated list of effective subarguments to decode.
133 * If 0, then activate all the flags.
134 */
135
136 void
137 warnings_argmatch (char *args)
138 {
139 if (args)
140 for (args = strtok (args, ","); args; args = strtok (NULL, ","))
141 if (STREQ (args, "error"))
142 warnings_are_errors = true;
143 else if (STREQ (args, "no-error"))
144 {
145 warnings_are_errors = false;
146 warning_argmatch ("no-error=all", 3, 6);
147 }
148 else
149 {
150 size_t no = STRPREFIX_LIT ("no-", args) ? 3 : 0;
151 size_t err = STRPREFIX_LIT ("error=", args + no) ? 6 : 0;
152
153 warning_argmatch (args, no, err);
154 }
155 else
156 warning_argmatch ("all", 0, 0);
157 }
158
159
160 /*-----------.
161 | complain. |
162 `-----------*/
163
164 void
165 complain_init (void)
166 {
167 warnings warnings_default =
168 Wconflicts_sr | Wconflicts_rr | Wdeprecated | Wother;
169
170 size_t b;
171 for (b = 0; b < warnings_size; ++b)
172 warnings_flag[b] = (1 << b & warnings_default
173 ? severity_warning
174 : severity_unset);
175 }
176
177 static severity
178 warning_severity (warnings flags)
179 {
180 if (flags & fatal)
181 return severity_fatal;
182 else if (flags & complaint)
183 return severity_error;
184 else
185 {
186 severity res = severity_disabled;
187 size_t b;
188 for (b = 0; b < warnings_size; ++b)
189 if (flags & 1 << b)
190 res = res < warnings_flag[b] ? warnings_flag[b] : res;
191 if (res == severity_warning && warnings_are_errors)
192 res = severity_error;
193 return res;
194 }
195 }
196
197
198 /** Display a "[-Wyacc]" like message on \a f. */
199
200 static void
201 warnings_print_categories (warnings warn_flags, FILE *f)
202 {
203 /* Display only the first match, the second is "-Wall". */
204 size_t i;
205 for (i = 0; warnings_args[i]; ++i)
206 if (warn_flags & warnings_types[i])
207 {
208 severity s = warning_severity (warnings_types[i]);
209 fprintf (f, " [-W%s%s]",
210 s == severity_error ? "error=" : "",
211 warnings_args[i]);
212 return;
213 }
214 }
215
216 /** Report an error message.
217 *
218 * \param loc the location, defaulting to the current file,
219 * or the program name.
220 * \param flags the category for this message.
221 * \param prefix put before the message (e.g., "warning").
222 * \param message the error message, a printf format string. Iff it
223 * ends with ": ", then no trailing newline is printed,
224 * and the caller should print the remaining
225 * newline-terminated message to stderr.
226 * \param args the arguments of the format string.
227 */
228 static
229 void
230 error_message (const location *loc, warnings flags, const char *prefix,
231 const char *message, va_list args)
232 {
233 unsigned pos = 0;
234
235 if (loc)
236 pos += location_print (*loc, stderr);
237 else
238 pos += fprintf (stderr, "%s", current_file ? current_file : program_name);
239 pos += fprintf (stderr, ": ");
240
241 if (indent_ptr)
242 {
243 if (*indent_ptr)
244 prefix = NULL;
245 if (!*indent_ptr)
246 *indent_ptr = pos;
247 else if (*indent_ptr > pos)
248 fprintf (stderr, "%*s", *indent_ptr - pos, "");
249 indent_ptr = 0;
250 }
251
252 if (prefix)
253 fprintf (stderr, "%s: ", prefix);
254
255 vfprintf (stderr, message, args);
256 if (! (flags & silent))
257 warnings_print_categories (flags, stderr);
258 {
259 size_t l = strlen (message);
260 if (l < 2 || message[l - 2] != ':' || message[l - 1] != ' ')
261 {
262 putc ('\n', stderr);
263 fflush (stderr);
264 if (loc && feature_flag & feature_caret && !(flags & no_caret))
265 location_caret (*loc, stderr);
266 }
267 }
268 fflush (stderr);
269 }
270
271 /** Raise a complaint. That can be a fatal error, an error or just a
272 warning. */
273
274 static void
275 complains (const location *loc, warnings flags, const char *message,
276 va_list args)
277 {
278 severity s = warning_severity (flags);
279 if ((flags & complaint) && complaint_status < status_complaint)
280 complaint_status = status_complaint;
281
282 if (severity_warning <= s)
283 {
284 const char* prefix =
285 s == severity_fatal ? _("fatal error")
286 : s == severity_error ? _("error")
287 : _("warning");
288 if (severity_error <= s && ! complaint_status)
289 complaint_status = status_warning_as_error;
290 error_message (loc, flags, prefix, message, args);
291 }
292
293 if (flags & fatal)
294 exit (EXIT_FAILURE);
295 }
296
297 void
298 complain (location const *loc, warnings flags, const char *message, ...)
299 {
300 va_list args;
301 va_start (args, message);
302 complains (loc, flags, message, args);
303 va_end (args);
304 }
305
306 void
307 complain_indent (location const *loc, warnings flags, unsigned *indent,
308 const char *message, ...)
309 {
310 va_list args;
311 indent_ptr = indent;
312 va_start (args, message);
313 complains (loc, flags, message, args);
314 va_end (args);
315 }
316
317 void
318 complain_args (location const *loc, warnings w, unsigned *indent,
319 int argc, char *argv[])
320 {
321 switch (argc)
322 {
323 case 1:
324 complain_indent (loc, w, indent, "%s", _(argv[0]));
325 break;
326 case 2:
327 complain_indent (loc, w, indent, _(argv[0]), argv[1]);
328 break;
329 case 3:
330 complain_indent (loc, w, indent, _(argv[0]), argv[1], argv[2]);
331 break;
332 case 4:
333 complain_indent (loc, w, indent, _(argv[0]), argv[1], argv[2], argv[3]);
334 break;
335 case 5:
336 complain_indent (loc, w, indent, _(argv[0]), argv[1], argv[2], argv[3],
337 argv[4]);
338 break;
339 default:
340 complain (loc, fatal, "too many arguments for complains");
341 break;
342 }
343 }
344
345 void
346 deprecated_directive (location const *loc, char const *old, char const *upd)
347 {
348 if (feature_flag & feature_caret)
349 complain (loc, Wdeprecated,
350 _("deprecated directive, use %s"),
351 quote_n (1, upd));
352 else
353 complain (loc, Wdeprecated,
354 _("deprecated directive: %s, use %s"),
355 quote (old), quote_n (1, upd));
356 }