1 /* Declaration for error-reporting function for Bison.
3 Copyright (C) 2000-2002, 2004-2006, 2009-2015, 2018-2021 Free
4 Software Foundation, Inc.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19 /* Based on error.c and error.h,
20 written by David MacKenzie <djm@gnu.ai.mit.edu>. */
30 #include <textstyle.h>
38 // The URL of the manual page about diagnostics. Use the per-node
39 // manual, to avoid downloading repeatedly the whole manual over the
41 static const char *diagnostics_url
42 = "https://www.gnu.org/software/bison/manual/html_node/Diagnostics.html";
45 err_status complaint_status
= status_none
;
47 bool warnings_are_errors
= false;
49 /** Whether -Werror/-Wno-error was applied to a warning. */
52 errority_unset
= 0, /** No explicit status. */
53 errority_disabled
= 1, /** Explicitly disabled with -Wno-error=foo. */
54 errority_enabled
= 2 /** Explicitly enabled with -Werror=foo. */
57 /** For each warning type, its errority. */
58 static errority errority_flag
[warnings_size
];
60 /** Diagnostics severity. */
63 severity_disabled
= 0, /**< Explicitly disabled via -Wno-foo. */
64 severity_unset
= 1, /**< Unspecified status. */
65 severity_warning
= 2, /**< A warning. */
66 severity_error
= 3, /**< An error (continue, but die soon). */
67 severity_fatal
= 4 /**< Fatal error (die now). */
71 /** For each warning type, its severity. */
72 static severity warnings_flag
[warnings_size
];
74 styled_ostream_t errstream
= NULL
;
77 begin_use_class (const char *s
, FILE *out
)
82 fprintf (out
, "<%s>", s
);
85 styled_ostream_begin_use_class (errstream
, s
);
86 styled_ostream_flush_to_current_style (errstream
);
92 end_use_class (const char *s
, FILE *out
)
97 fprintf (out
, "</%s>", s
);
100 styled_ostream_end_use_class (errstream
, s
);
101 styled_ostream_flush_to_current_style (errstream
);
107 begin_hyperlink (FILE *out
, const char *ref
)
110 styled_ostream_set_hyperlink (errstream
, ref
, NULL
);
114 end_hyperlink (FILE *out
)
117 styled_ostream_set_hyperlink (errstream
, NULL
, NULL
);
124 ostream_flush (errstream
, FLUSH_THIS_STREAM
);
129 is_styled (FILE *out
)
135 #if HAVE_LIBTEXTSTYLE
136 return (color_mode
== color_yes
137 || color_mode
== color_html
138 || (color_mode
== color_tty
&& isatty (STDERR_FILENO
)));
145 /*------------------------.
146 | --warnings's handling. |
147 `------------------------*/
149 ARGMATCH_DEFINE_GROUP (warning
, warnings
)
151 static const argmatch_warning_doc argmatch_warning_docs
[] =
153 { "conflicts-sr", N_("S/R conflicts (enabled by default)") },
154 { "conflicts-rr", N_("R/R conflicts (enabled by default)") },
155 { "counterexamples", N_("generate conflict counterexamples") },
156 { "dangling-alias", N_("string aliases not attached to a symbol") },
157 { "deprecated", N_("obsolete constructs") },
158 { "empty-rule", N_("empty rules without %empty") },
159 { "midrule-values", N_("unset or unused midrule values") },
160 { "precedence", N_("useless precedence and associativity") },
161 { "yacc", N_("incompatibilities with POSIX Yacc") },
162 { "other", N_("all other warnings (enabled by default)") },
163 { "all", N_("all the warnings except 'counterexamples', 'dangling-alias' and 'yacc'") },
164 { "no-CATEGORY", N_("turn off warnings in CATEGORY") },
165 { "none", N_("turn off all the warnings") },
166 { "error[=CATEGORY]", N_("treat warnings as errors") },
170 static const argmatch_warning_arg argmatch_warning_args
[] =
173 { "conflicts-rr", Wconflicts_rr
},
174 { "conflicts-sr", Wconflicts_sr
},
175 { "counterexamples", Wcounterexamples
}, { "cex", Wcounterexamples
}, // Show cex second.
176 { "dangling-alias", Wdangling_alias
},
177 { "deprecated", Wdeprecated
},
178 { "empty-rule", Wempty_rule
},
179 { "everything", Weverything
},
180 { "midrule-values", Wmidrule_values
},
183 { "precedence", Wprecedence
},
188 const argmatch_warning_group_type argmatch_warning_group
=
190 argmatch_warning_args
,
191 argmatch_warning_docs
,
192 N_("Warning categories include:"),
197 warning_usage (FILE *out
)
199 argmatch_warning_usage (out
);
203 warning_argmatch (char const *arg
, size_t no
, size_t err
)
205 int value
= *argmatch_warning_value ("--warning", arg
+ no
+ err
);
207 /* -Wnone == -Wno-everything, and -Wno-none == -Weverything. */
214 for (size_t b
= 0; b
< warnings_size
; ++b
)
218 /* -Wno-error=foo. */
219 errority_flag
[b
] = errority_disabled
;
222 /* -Werror=foo: enables -Wfoo. */
223 errority_flag
[b
] = errority_enabled
;
224 warnings_flag
[b
] = severity_warning
;
228 warnings_flag
[b
] = severity_disabled
;
231 warnings_flag
[b
] = severity_warning
;
235 /** Decode a comma-separated list of arguments from -W.
237 * \param args comma separated list of effective subarguments to decode.
238 * If 0, then activate all the flags.
242 warnings_argmatch (char *args
)
245 warning_argmatch ("all", 0, 0);
246 else if (STREQ (args
, "help"))
248 warning_usage (stdout
);
252 for (args
= strtok (args
, ","); args
; args
= strtok (NULL
, ","))
253 if (STREQ (args
, "error"))
254 warnings_are_errors
= true;
255 else if (STREQ (args
, "no-error"))
256 warnings_are_errors
= false;
259 /* The length of the possible 'no-' prefix: 3, or 0. */
260 size_t no
= STRPREFIX_LIT ("no-", args
) ? 3 : 0;
261 /* The length of the possible 'error=' (possibly after
262 'no-') prefix: 6, or 0. */
263 size_t err
= STRPREFIX_LIT ("error=", args
+ no
) ? 6 : 0;
265 warning_argmatch (args
, no
, err
);
269 /* Color style for this type of message. */
271 severity_style (severity s
)
275 case severity_disabled
:
278 case severity_warning
:
287 /* Prefix for this type of message. */
289 severity_prefix (severity s
)
293 case severity_disabled
:
296 case severity_warning
:
301 return _("fatal error");
308 severity_print (severity s
, FILE *out
)
310 if (s
!= severity_disabled
)
312 const char* style
= severity_style (s
);
313 begin_use_class (style
, out
);
314 fprintf (out
, "%s:", severity_prefix (s
));
315 end_use_class (style
, out
);
326 complain_init_color (void)
328 #if HAVE_LIBTEXTSTYLE
329 if (is_styled (stderr
))
331 style_file_prepare ("BISON_STYLE", "BISON_STYLEDIR", pkgdatadir (),
332 "bison-default.css");
333 /* As a fallback, use the default in the current directory. */
335 if ((style_file_name
== NULL
|| stat (style_file_name
, &statbuf
) < 0)
336 && stat ("bison-default.css", &statbuf
) == 0)
337 style_file_name
= "bison-default.css";
341 style_file_name
= NULL
;
344 /* Workaround clang's warning (starting at Clang 3.5) about the stub
345 code of html_styled_ostream_create:
347 | src/complain.c:274:7: error: code will never be executed [-Werror,-Wunreachable-code]
348 | ? html_styled_ostream_create (file_ostream_create (stderr),
349 | ^~~~~~~~~~~~~~~~~~~~~~~~~~ */
350 #if defined __clang__
351 # pragma clang diagnostic push
352 # pragma clang diagnostic ignored "-Wunreachable-code"
355 color_mode
== color_html
356 ? html_styled_ostream_create (file_ostream_create (stderr
),
358 : styled_ostream_create (STDERR_FILENO
, "(stderr)", TTYCTL_AUTO
,
360 #if defined __clang__
361 # pragma clang diagnostic pop
370 warnings warnings_default
=
371 Wconflicts_sr
| Wconflicts_rr
| Wdeprecated
| Wother
;
373 for (size_t b
= 0; b
< warnings_size
; ++b
)
375 warnings_flag
[b
] = (1 << b
& warnings_default
378 errority_flag
[b
] = errority_unset
;
386 styled_ostream_free (errstream
);
389 /* A diagnostic with FLAGS is about to be issued. With what severity?
390 (severity_fatal, severity_error, severity_disabled, or
391 severity_warning.) */
394 warning_severity (warnings flags
)
397 /* Diagnostics about fatal errors. */
398 return severity_fatal
;
399 else if (flags
& complaint
)
400 /* Diagnostics about errors. */
401 return severity_error
;
404 /* Diagnostics about warnings. */
405 severity res
= severity_disabled
;
406 for (size_t b
= 0; b
< warnings_size
; ++b
)
409 res
= res
< warnings_flag
[b
] ? warnings_flag
[b
] : res
;
410 /* If the diagnostic is enabled, and -Werror is enabled,
411 and -Wno-error=foo was not explicitly requested, this
413 if (res
== severity_warning
414 && (errority_flag
[b
] == errority_enabled
415 || (warnings_are_errors
416 && errority_flag
[b
] != errority_disabled
)))
417 res
= severity_error
;
424 warning_is_unset (warnings flags
)
426 for (size_t b
= 0; b
< warnings_size
; ++b
)
427 if (flags
& 1 << b
&& warnings_flag
[b
] != severity_unset
)
433 warning_is_enabled (warnings flags
)
435 return severity_warning
<= warning_severity (flags
);
438 /** Display a "[-Wyacc]" like message on \a out. */
441 warnings_print_categories (warnings warn_flags
, FILE *out
)
443 for (int wbit
= 0; wbit
< warnings_size
; ++wbit
)
444 if (warn_flags
& (1 << wbit
))
446 warnings w
= 1 << wbit
;
447 severity s
= warning_severity (w
);
448 const char* style
= severity_style (s
);
450 begin_use_class (style
, out
);
451 // E.g., "counterexamples".
452 const char *warning
= argmatch_warning_argument (&w
);
454 snprintf (ref
, sizeof ref
,
455 "%s#W%s", diagnostics_url
, warning
);
456 begin_hyperlink (out
, ref
);
457 ostream_printf (errstream
,
459 s
== severity_error
? "error=" : "",
462 // Because we mix stdio with ostream I/O, we need to flush
463 // here for sake of color == debug.
465 end_use_class (style
, out
);
467 /* Display only the first match, the second is "-Wall". */
472 /** Report an error message.
474 * \param loc the location, defaulting to the current file,
475 * or the program name.
476 * \param flags the category for this message.
477 * \param sever to decide the prefix to put before the message
479 * \param message the error message, a printf format string. Iff it
480 * ends with ": ", then no trailing newline is printed,
481 * and the caller should print the remaining
482 * newline-terminated message to stderr.
483 * \param args the arguments of the format string.
487 error_message (const location
*loc
, warnings flags
,
488 severity sever
, const char *message
, va_list args
)
490 const char* style
= flags
& note
? "note" : severity_style (sever
);
493 location_print (*loc
, stderr
);
495 fprintf (stderr
, "%s", grammar_file
? grammar_file
: program_name
);
496 fprintf (stderr
, ": ");
498 if (sever
!= severity_disabled
)
500 begin_use_class (style
, stderr
);
501 fprintf (stderr
, "%s:", flags
& note
? _("note") : severity_prefix (sever
));
502 end_use_class (style
, stderr
);
506 vfprintf (stderr
, message
, args
);
507 /* Print the type of warning, only if this is not a sub message
508 (in which case the prefix is null). */
509 if (! (flags
& silent
) && sever
!= severity_disabled
)
510 warnings_print_categories (flags
, stderr
);
512 size_t l
= strlen (message
);
513 if (l
< 2 || message
[l
- 2] != ':' || message
[l
- 1] != ' ')
517 if (loc
&& !(flags
& no_caret
))
518 location_caret (*loc
, style
, stderr
);
523 /** Raise a complaint (fatal error, error or just warning). */
526 complains (const location
*loc
, warnings flags
,
527 const char *message
, va_list args
)
529 if ((flags
& complaint
) && complaint_status
< status_complaint
)
530 complaint_status
= status_complaint
;
532 severity s
= warning_severity (flags
);
533 if (severity_warning
<= s
)
535 if (severity_error
<= s
&& ! complaint_status
)
536 complaint_status
= status_warning_as_error
;
537 error_message (loc
, flags
, s
, message
, args
);
545 complain (location
const *loc
, warnings flags
, const char *message
, ...)
548 va_start (args
, message
);
549 complains (loc
, flags
, message
, args
);
554 subcomplain (location
const *loc
, warnings flags
, const char *message
, ...)
557 va_start (args
, message
);
558 complains (loc
, flags
| note
| silent
, message
, args
);
563 complain_args (location
const *loc
, warnings w
,
564 int argc
, char *argv
[])
569 complain (loc
, w
, "%s", _(argv
[0]));
572 complain (loc
, w
, _(argv
[0]), argv
[1]);
575 complain (loc
, w
, _(argv
[0]), argv
[1], argv
[2]);
578 complain (loc
, w
, _(argv
[0]), argv
[1], argv
[2], argv
[3]);
581 complain (loc
, w
, _(argv
[0]), argv
[1], argv
[2], argv
[3], argv
[4]);
584 complain (loc
, fatal
, "too many arguments for complains");
591 bison_directive (location
const *loc
, char const *directive
)
593 complain (loc
, Wyacc
,
594 _("POSIX Yacc does not support %s"), directive
);
598 deprecated_directive (location
const *loc
, char const *old
, char const *upd
)
600 if (warning_is_enabled (Wdeprecated
))
602 complain (loc
, Wdeprecated
,
603 _("deprecated directive: %s, use %s"),
604 quote (old
), quote_n (1, upd
));
605 location_caret_suggestion (*loc
, upd
, stderr
);
606 /* Register updates only if -Wdeprecated is enabled. */
607 fixits_register (loc
, upd
);
612 duplicate_directive (char const *directive
,
613 location first
, location second
)
615 if (feature_flag
& feature_caret
)
616 complain (&second
, Wother
, _("duplicate directive"));
618 complain (&second
, Wother
, _("duplicate directive: %s"), quote (directive
));
619 subcomplain (&first
, Wother
, _("previous declaration"));
620 fixits_register (&second
, "");
624 duplicate_rule_directive (char const *directive
,
625 location first
, location second
)
627 complain (&second
, complaint
, _("only one %s allowed per rule"), directive
);
628 subcomplain (&first
, complaint
, _("previous declaration"));
629 fixits_register (&second
, "");
633 syntax_error (location loc
,
634 int argc
, const char* argv
[])
636 if (complaint_status
< status_complaint
)
637 complaint_status
= status_complaint
;
639 const char *format
= NULL
;
646 default: /* Avoid compiler warnings. */
647 CASE (0, _("syntax error"));
648 CASE (1, _("unexpected %0$s"));
649 CASE (2, _("expected %1$s before %0$s"));
650 CASE (3, _("expected %1$s or %2$s before %0$s"));
651 CASE (4, _("expected %1$s or %2$s or %3$s before %0$s"));
652 CASE (5, _("expected %1$s or %2$s or %3$s or %4$s before %0$s"));
655 location_print (loc
, stderr
);
656 fputs (": ", stderr
);
657 severity_print (severity_error
, stderr
);
661 && c_isdigit (format
[1])
664 && (format
[1] - '0') < argc
)
666 int i
= format
[1] - '0';
667 const char *style
= i
== 0 ? "unexpected" : "expected";
668 begin_use_class (style
, stderr
);
669 fputs (argv
[i
], stderr
);
670 end_use_class (style
, stderr
);
675 fputc (*format
, stderr
);
678 fputc ('\n', stderr
);
679 location_caret (loc
, "error", stderr
);