# Checking diagnostics. -*- Autotest -*- # Copyright (C) 2019-2020 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . AT_BANNER([[Diagnostics.]]) # AT_TEST($1: TITLE, $2: GRAMMAR, $3: EXIT-STATUS, $4: OUTPUT-WITH-STYLE, # $5: EXTRA_ENV # ----------------------------------------------------------------------- # Run Bison on GRAMMAR with debugging style enabled, and expect # OUTPUT-WITH-STYLE as diagnostics. m4_pushdef([AT_TEST], [ AT_SETUP([$1]) AT_KEYWORDS([diagnostics]) # We need UTF-8 support for correct screen-width computation of UTF-8 # characters. Skip the test if not available. locale=`locale -a | $EGREP '^en_US\.(UTF-8|utf8)$' | sed 1q` AT_SKIP_IF([test x == x"$locale"]) AT_BISON_OPTION_PUSHDEFS AT_DATA_GRAMMAR([[input.y]], [$2]) AT_DATA([experr], [$4]) # For some reason, literal ^M in the input are removed and don't end # in `input.y`. So use the two-character ^M represent it, and let # Perl insert real CR characters. if $EGREP ['\^M|\\[0-9][0-9][0-9]'] input.y experr >/dev/null; then AT_PERL_REQUIRE([-pi -e 's{\^M}{\r}g;s{\\(\d{3}|.)}{$v = $[]1; $v =~ /\A\d+\z/ ? chr($v) : $v}ge' input.y experr]) fi AT_CHECK([LC_ALL="$locale" $5 bison -fcaret --color=debug -Wall input.y], [$3], [], [experr]) # When no style, same messages, but without style. AT_PERL_REQUIRE([-pi -e 's{()}{ $[]1 eq "" ? $[]1 : "" }ge' experr]) # Cannot use AT_BISON_CHECK easily as we need to change the # environment. # FIXME: Enhance AT_BISON_CHECK. AT_CHECK([LC_ALL="$locale" $5 bison -fcaret -Wall input.y], [$3], [], [experr]) AT_BISON_OPTION_POPDEFS AT_CLEANUP ]) ## ---------- ## ## Warnings. ## ## ---------- ## AT_TEST([[Warnings]], [[%token FOO FOO FOO %token FOO FOO FOO %% exp: %empty; ]], [0], [[input.y:9.12-14: warning: symbol FOO redeclared [-Wother] 9 | %token FOO FOO FOO | ^~~ input.y:9.8-10: previous declaration 9 | %token FOO FOO FOO | ^~~ input.y:9.16-18: warning: symbol FOO redeclared [-Wother] 9 | %token FOO FOO FOO | ^~~ input.y:9.8-10: previous declaration 9 | %token FOO FOO FOO | ^~~ input.y:10.8-10: warning: symbol FOO redeclared [-Wother] 10 | %token FOO FOO FOO | ^~~ input.y:9.8-10: previous declaration 9 | %token FOO FOO FOO | ^~~ input.y:10.13-15: warning: symbol FOO redeclared [-Wother] 10 | %token FOO FOO FOO | ^~~ input.y:9.8-10: previous declaration 9 | %token FOO FOO FOO | ^~~ input.y:10.18-20: warning: symbol FOO redeclared [-Wother] 10 | %token FOO FOO FOO | ^~~ input.y:9.8-10: previous declaration 9 | %token FOO FOO FOO | ^~~ ]]) ## ------------------------ ## ## Single point locations. ## ## ------------------------ ## # Single point locations (equal boundaries) are troublesome: it's easy # to mess up the opening/closing of style. They come from the parser, # rules with empty rhs. Their position is therefore debatable # (between the previous token and the next one). AT_TEST([[Single point locations]], [[%% exp: a b c d e a: {} b:{ }; c: d : e: ]], [0], [[input.y:11.4-5: warning: empty rule without %empty [-Wempty-rule] 11 | a: {} | ^~ | %empty input.y:12.3-13.1: warning: empty rule without %empty [-Wempty-rule] 12 | b:{ | ^ | %empty input.y:14.3: warning: empty rule without %empty [-Wempty-rule] 14 | c: | ^ | %empty input.y:16.2: warning: empty rule without %empty [-Wempty-rule] 16 | : | ^ | %empty input.y:17.3: warning: empty rule without %empty [-Wempty-rule] 17 | e: | ^ | %empty input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]]) ## ------------------------------------- ## ## Line is too short, and then you die. ## ## ------------------------------------- ## # We trust the "#line", since that's what allows us to quote the # actual source from which the gramar file was generated. But #line # can also be wrong, and point to a line which is shorter that the bad # one. In which case we can easily forget to close the styling. # # Be sure to have #line point to a line long enough to open the # styling, but not enough to close it. AT_TEST([[Line is too short, and then you die]], [[// Beware that there are 9 lines inserted before (including this one). #line 12 %token foo 123 %token foo 123123 %token foo 123 %% exp: ]], [1], [[input.y:13.8-10: warning: symbol foo redeclared [-Wother] 13 | %token foo 123 | ^~~ input.y:12.8-10: previous declaration 12 | %token foo 123123 | ^~~ input.y:13.12-17: error: redefining user token number of foo 13 | %token foo 123 | ^~~~~~ input.y:14.8-10: warning: symbol foo redeclared [-Wother] 14 | %% | ^~~ input.y:12.8-10: previous declaration 12 | %token foo 123123 | ^~~ ]]) ## ----------------------- ## ## Zero-width characters. ## ## ----------------------- ## # We used to open twice the styling for characters that have a # zero-width on display (e.g., \005). AT_TEST([[Zero-width characters]], [[%% exp: an\005error. ]], [1], [[input.y:10.8: error: invalid character: '\\005' 10 | exp: an\005error. | ^ ]]) ## -------------------------------------- ## ## Tabulations and multibyte characters. ## ## -------------------------------------- ## # Make sure we treat tabulations as eight spaces, and that multibyte # characters have correct width. AT_TEST([[Tabulations and multibyte characters]], [[%% exp: a b c d e f g h a: { } b: { } c: {------------} d: {éééééééééééé} e: {∇⃗×𝐸⃗ = -∂𝐵⃗/∂t} f: { 42 } g: { "฿¥$€₦" } h: { 🐃 } ]], [0], [[input.y:11.4-17: warning: empty rule without %empty [-Wempty-rule] 11 | a: { } | ^~~~~~~~~~~~~~ | %empty input.y:12.4-17: warning: empty rule without %empty [-Wempty-rule] 12 | b: { } | ^~~~~~~~~~~~~~ | %empty input.y:13.4-17: warning: empty rule without %empty [-Wempty-rule] 13 | c: {------------} | ^~~~~~~~~~~~~~ | %empty input.y:14.4-17: warning: empty rule without %empty [-Wempty-rule] 14 | d: {éééééééééééé} | ^~~~~~~~~~~~~~ | %empty input.y:15.4-17: warning: empty rule without %empty [-Wempty-rule] 15 | e: {∇⃗×𝐸⃗ = -∂𝐵⃗/∂t} | ^~~~~~~~~~~~~~ | %empty input.y:16.4-17: warning: empty rule without %empty [-Wempty-rule] 16 | f: { 42 } | ^~~~~~~~~~~~~~ | %empty input.y:17.4-17: warning: empty rule without %empty [-Wempty-rule] 17 | g: { "฿¥$€₦" } | ^~~~~~~~~~~~~~ | %empty input.y:18.4-17: warning: empty rule without %empty [-Wempty-rule] 18 | h: { 🐃 } | ^~~~~~~~~~~~~~ | %empty input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]]) ## --------------- ## ## Special files. ## ## --------------- ## # Don't try to quote special files. # http://lists.gnu.org/archive/html/bug-bison/2019-04/msg00000.html # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90034 AT_TEST([[Special files]], [[%% exp: a b a: {} #line 1 "/dev/stdout" b: {} ]], [0], [[input.y:11.4-5: warning: empty rule without %empty [-Wempty-rule] 11 | a: {} | ^~ | %empty /dev/stdout:1.4-5: warning: empty rule without %empty [-Wempty-rule] | %empty input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]]) ## -------------------- ## ## Complaints from M4. ## ## -------------------- ## # Complaints issued m4 need complete locations (byte and column) for # diagnostics. AT_TEST([[Complaints from M4]], [[%define error1 {e} %define error2 {é} %% exp: %empty; ]], [1], [[input.y:9.1-27: error: %define variable 'error1' is not used 9 | %define error1 {e} | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:10.1-27: error: %define variable 'error2' is not used 10 | %define error2 {é} | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ ]]) ## ----------------- ## ## Carriage return. ## ## ----------------- ## # Carriage-return used to count as a newline in the scanner, and not # in diagnostics. Resulting in all kinds of nice bugs. AT_TEST([[Carriage return]], [[^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M^M %token " %% ]], [1], [[input.y:10.8-11.0: error: missing '"' at end of line 10 | %token " | ^ input.y:10.8-11.0: error: syntax error, unexpected string, expecting character literal or identifier or 10 | %token " | ^ ]]) ## ------- ## ## CR NL. ## ## ------- ## # Check Windows EOLs. AT_TEST([[CR NL]], [[^M %token ^M FOO^M %token ^M FOO^M %%^M exp:^M ]], [0], [[input.y:11.9-11: warning: symbol FOO redeclared [-Wother] 11 | %token FOO | ^~~ input.y:10.9-11: previous declaration 10 | %token FOO | ^~~ input.y:13.5: warning: empty rule without %empty [-Wempty-rule] 13 | exp: | ^ | %empty input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]]) ## -------------- ## ## Screen width. ## ## -------------- ## AT_TEST([[Screen width: 200 columns]], [[%token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ %error-verbose %% exp: ABCDEFGHIJKLMNOPQRSTUVWXYZ ]], [0], [[input.y:9.36-61: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.64-89: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.92-117: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:10.56-69: warning: deprecated directive: '%error-verbose', use '%define parse.error verbose' [-Wdeprecated] 10 | %error-verbose | ^~~~~~~~~~~~~~ | %define parse.error verbose input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]], [[COLUMNS=200]]) AT_TEST([[Screen width: 80 columns]], [[%token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ %error-verbose %% exp: ABCDEFGHIJKLMNOPQRSTUVWXYZ ]], [0], [[input.y:9.36-61: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.64-89: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF... | ^~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.92-117: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | ...TUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:10.56-69: warning: deprecated directive: '%error-verbose', use '%define parse.error verbose' [-Wdeprecated] 10 | %error-verbose | ^~~~~~~~~~~~~~ | %define parse.error verbose input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]], [[COLUMNS=80]]) AT_TEST([[Screen width: 60 columns]], [[%token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ %error-verbose %% exp: ABCDEFGHIJKLMNOPQRSTUVWXYZ ]], [0], [[input.y:9.36-61: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMN... | ^~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMN... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.64-89: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | ...TUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHI... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMN... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.92-117: warning: symbol ABCDEFGHIJKLMNOPQRSTUVWXYZ redeclared [-Wother] 9 | ...TUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:9.8-33: previous declaration 9 | %token ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMN... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input.y:10.56-69: warning: deprecated directive: '%error-verbose', use '%define parse.error verbose' [-Wdeprecated] 10 | ... %error-verbose | ^~~~~~~~~~~~~~ | %define parse.error verbose input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]], [[COLUMNS=60]]) ## ------------- ## ## Suggestions. ## ## ------------- ## # Don't suggest to fix QUX with QUUX and QUUX with QUX... AT_TEST([[Suggestions]], [[%% res: QUX baz bar: QUUX ]], [1], [[input.y:10.6-8: error: symbol 'QUX' is used, but is not defined as a token and has no rules 10 | res: QUX baz | ^~~ input.y:10.10-12: error: symbol 'baz' is used, but is not defined as a token and has no rules; did you mean 'bar'? 10 | res: QUX baz | ^~~ | bar input.y:11.6-9: error: symbol 'QUUX' is used, but is not defined as a token and has no rules 11 | bar: QUUX | ^~~~ ]]) m4_popdef([AT_TEST]) ## -------------------------------------- ## ## Indentation with message suppression. ## ## -------------------------------------- ## AT_SETUP([[Indentation with message suppression]]) # https://lists.gnu.org/archive/html/bug-bison/2019-08/msg00002.html AT_DATA([[input.y]], [[%define api.pure %pure-parser %error-verbose %% exp : '0' ]]) AT_BISON_CHECK([[-fcaret -Wno-other input.y]], [0], [], [[input.y:2.1-12: warning: deprecated directive: '%pure-parser', use '%define api.pure' [-Wdeprecated] 2 | %pure-parser | ^~~~~~~~~~~~ | %define api.pure input.y:3.1-14: warning: deprecated directive: '%error-verbose', use '%define parse.error verbose' [-Wdeprecated] 3 | %error-verbose | ^~~~~~~~~~~~~~ | %define parse.error verbose ]]) AT_CLEANUP