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