]> git.saurik.com Git - bison.git/blob - src/complain.c
diagnostics: %empty enables -Wempty-rule
[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 "empty-rule",
67 "precedence",
68 "other",
69 "all",
70 "error",
71 0
72 };
73
74 static const int warnings_types[] =
75 {
76 Wnone,
77 Wmidrule_values,
78 Wyacc,
79 Wconflicts_sr,
80 Wconflicts_rr,
81 Wdeprecated,
82 Wempty_rule,
83 Wprecedence,
84 Wother,
85 Wall,
86 Werror
87 };
88
89 ARGMATCH_VERIFY (warnings_args, warnings_types);
90
91 void
92 warning_argmatch (char const *arg, size_t no, size_t err)
93 {
94 int value = XARGMATCH ("--warning", arg + no + err,
95 warnings_args, warnings_types);
96
97 /* -Wnone == -Wno-all, and -Wno-none == -Wall. */
98 if (!value)
99 {
100 value = Wall;
101 no = !no;
102 }
103
104 if (no)
105 {
106 size_t b;
107 for (b = 0; b < warnings_size; ++b)
108 if (value & 1 << b)
109 {
110 if (err)
111 {
112 /* -Wno-error=foo: if foo enabled as an error,
113 make it a warning. */
114 if (warnings_flag[b] == severity_error)
115 warnings_flag[b] = severity_warning;
116 }
117 else
118 /* -Wno-foo. */
119 warnings_flag[b] = severity_disabled;
120 }
121 }
122 else
123 {
124 size_t b;
125 for (b = 0; b < warnings_size; ++b)
126 if (value & 1 << b)
127 /* -Wfoo and -Werror=foo. */
128 warnings_flag[b] = err ? severity_error : severity_warning;
129 }
130 }
131
132 /** Decode a comma-separated list of arguments from -W.
133 *
134 * \param args comma separated list of effective subarguments to decode.
135 * If 0, then activate all the flags.
136 */
137
138 void
139 warnings_argmatch (char *args)
140 {
141 if (args)
142 for (args = strtok (args, ","); args; args = strtok (NULL, ","))
143 if (STREQ (args, "error"))
144 warnings_are_errors = true;
145 else if (STREQ (args, "no-error"))
146 {
147 warnings_are_errors = false;
148 warning_argmatch ("no-error=all", 3, 6);
149 }
150 else
151 {
152 size_t no = STRPREFIX_LIT ("no-", args) ? 3 : 0;
153 size_t err = STRPREFIX_LIT ("error=", args + no) ? 6 : 0;
154
155 warning_argmatch (args, no, err);
156 }
157 else
158 warning_argmatch ("all", 0, 0);
159 }
160
161
162 /*-----------.
163 | complain. |
164 `-----------*/
165
166 void
167 complain_init (void)
168 {
169 warnings warnings_default =
170 Wconflicts_sr | Wconflicts_rr | Wdeprecated | Wother;
171
172 size_t b;
173 for (b = 0; b < warnings_size; ++b)
174 warnings_flag[b] = (1 << b & warnings_default
175 ? severity_warning
176 : severity_unset);
177 }
178
179 static severity
180 warning_severity (warnings flags)
181 {
182 if (flags & fatal)
183 return severity_fatal;
184 else if (flags & complaint)
185 return severity_error;
186 else
187 {
188 severity res = severity_disabled;
189 size_t b;
190 for (b = 0; b < warnings_size; ++b)
191 if (flags & 1 << b)
192 res = res < warnings_flag[b] ? warnings_flag[b] : res;
193 if (res == severity_warning && warnings_are_errors)
194 res = severity_error;
195 return res;
196 }
197 }
198
199 bool
200 warning_is_unset (warnings flags)
201 {
202 size_t b;
203 for (b = 0; b < warnings_size; ++b)
204 if (flags & 1 << b && warnings_flag[b] != severity_unset)
205 return false;
206 return true;
207 }
208
209 /** Display a "[-Wyacc]" like message on \a f. */
210
211 static void
212 warnings_print_categories (warnings warn_flags, FILE *f)
213 {
214 /* Display only the first match, the second is "-Wall". */
215 size_t i;
216 for (i = 0; warnings_args[i]; ++i)
217 if (warn_flags & warnings_types[i])
218 {
219 severity s = warning_severity (warnings_types[i]);
220 fprintf (f, " [-W%s%s]",
221 s == severity_error ? "error=" : "",
222 warnings_args[i]);
223 return;
224 }
225 }
226
227 /** Report an error message.
228 *
229 * \param loc the location, defaulting to the current file,
230 * or the program name.
231 * \param flags the category for this message.
232 * \param prefix put before the message (e.g., "warning").
233 * \param message the error message, a printf format string. Iff it
234 * ends with ": ", then no trailing newline is printed,
235 * and the caller should print the remaining
236 * newline-terminated message to stderr.
237 * \param args the arguments of the format string.
238 */
239 static
240 void
241 error_message (const location *loc, warnings flags, const char *prefix,
242 const char *message, va_list args)
243 {
244 unsigned pos = 0;
245
246 if (loc)
247 pos += location_print (*loc, stderr);
248 else
249 pos += fprintf (stderr, "%s", current_file ? current_file : program_name);
250 pos += fprintf (stderr, ": ");
251
252 if (indent_ptr)
253 {
254 if (*indent_ptr)
255 prefix = NULL;
256 if (!*indent_ptr)
257 *indent_ptr = pos;
258 else if (*indent_ptr > pos)
259 fprintf (stderr, "%*s", *indent_ptr - pos, "");
260 indent_ptr = 0;
261 }
262
263 if (prefix)
264 fprintf (stderr, "%s: ", prefix);
265
266 vfprintf (stderr, message, args);
267 if (! (flags & silent))
268 warnings_print_categories (flags, stderr);
269 {
270 size_t l = strlen (message);
271 if (l < 2 || message[l - 2] != ':' || message[l - 1] != ' ')
272 {
273 putc ('\n', stderr);
274 fflush (stderr);
275 if (loc && feature_flag & feature_caret && !(flags & no_caret))
276 location_caret (*loc, stderr);
277 }
278 }
279 fflush (stderr);
280 }
281
282 /** Raise a complaint. That can be a fatal error, an error or just a
283 warning. */
284
285 static void
286 complains (const location *loc, warnings flags, const char *message,
287 va_list args)
288 {
289 severity s = warning_severity (flags);
290 if ((flags & complaint) && complaint_status < status_complaint)
291 complaint_status = status_complaint;
292
293 if (severity_warning <= s)
294 {
295 const char* prefix =
296 s == severity_fatal ? _("fatal error")
297 : s == severity_error ? _("error")
298 : _("warning");
299 if (severity_error <= s && ! complaint_status)
300 complaint_status = status_warning_as_error;
301 error_message (loc, flags, prefix, message, args);
302 }
303
304 if (flags & fatal)
305 exit (EXIT_FAILURE);
306 }
307
308 void
309 complain (location const *loc, warnings flags, const char *message, ...)
310 {
311 va_list args;
312 va_start (args, message);
313 complains (loc, flags, message, args);
314 va_end (args);
315 }
316
317 void
318 complain_indent (location const *loc, warnings flags, unsigned *indent,
319 const char *message, ...)
320 {
321 va_list args;
322 indent_ptr = indent;
323 va_start (args, message);
324 complains (loc, flags, message, args);
325 va_end (args);
326 }
327
328 void
329 complain_args (location const *loc, warnings w, unsigned *indent,
330 int argc, char *argv[])
331 {
332 switch (argc)
333 {
334 case 1:
335 complain_indent (loc, w, indent, "%s", _(argv[0]));
336 break;
337 case 2:
338 complain_indent (loc, w, indent, _(argv[0]), argv[1]);
339 break;
340 case 3:
341 complain_indent (loc, w, indent, _(argv[0]), argv[1], argv[2]);
342 break;
343 case 4:
344 complain_indent (loc, w, indent, _(argv[0]), argv[1], argv[2], argv[3]);
345 break;
346 case 5:
347 complain_indent (loc, w, indent, _(argv[0]), argv[1], argv[2], argv[3],
348 argv[4]);
349 break;
350 default:
351 complain (loc, fatal, "too many arguments for complains");
352 break;
353 }
354 }
355
356 void
357 deprecated_directive (location const *loc, char const *old, char const *upd)
358 {
359 if (feature_flag & feature_caret)
360 complain (loc, Wdeprecated,
361 _("deprecated directive, use %s"),
362 quote_n (1, upd));
363 else
364 complain (loc, Wdeprecated,
365 _("deprecated directive: %s, use %s"),
366 quote (old), quote_n (1, upd));
367 }