From a1a77e1fcc32e94aff477f2a98c15172b199d1e0 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Fri, 5 Oct 2012 08:54:15 +0200 Subject: [PATCH 01/18] tests: diff -u is not portable Reported by Didier Godefroy . * tests/existing.at (AT_LALR1_DIFF_CHECK): Skip if diff -u does not work. --- NEWS | 2 +- tests/existing.at | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index c1ab7aa3..c8a4d312 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ GNU Bison NEWS ** Bug fixes - Bugs in the test suite have been fixed. + Bugs and portability issues in the test suite have been fixed. Some errors in translations have been addressed, and --help now directs users to the appropriate place to report them. diff --git a/tests/existing.at b/tests/existing.at index 582f6b3d..149499d4 100644 --- a/tests/existing.at +++ b/tests/existing.at @@ -35,7 +35,10 @@ dnl time comes, just use sed to drop the line numbers. For now, as LR(1) dnl support is rapidly evolving, let's keep that information to be careful. dnl However, we don't do diffs for canonical LR(1) because the diff is huge. m4_pushdef([AT_LALR1_DIFF_CHECK], -[AT_CHECK([[sed 's/^%define lr.type .*$//' input.y > input-lalr.y]]) +[dnl We need diff -u, which is not portable. +AT_CHECK([diff -u /dev/null /dev/null || exit 77], [0], [ignore]) + +AT_CHECK([[sed 's/^%define lr.type .*$//' input.y > input-lalr.y]]) AT_BISON_CHECK([[--report=all input-lalr.y]], [[0]], [ignore], [ignore]) AT_CHECK([[diff -u input-lalr.output input.output \ | sed -n '/^@@/,$p' | sed 's/^ $//']], From a727e7124d0d9f8da52e0f5092b05b356cf03deb Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Fri, 5 Oct 2012 09:20:30 +0200 Subject: [PATCH 02/18] tests: fix sed portability issues Reported by Didier Godefroy, . * tests/calc.at (AT_CHECK_SPACES): Use Perl. --- tests/calc.at | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/calc.at b/tests/calc.at index 3aab8681..a1c11e5f 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -503,12 +503,15 @@ AT_CHECK([cat stderr], 0, [expout]) # Make sure we did not introduce bad spaces. Checked here because all # the skeletons are (or should be) exercized here. m4_define([AT_CHECK_SPACES], -[# No initial empty lines. -AT_CHECK([sed -ne '/./q;=;p;' $1]) -# No trailing spaces. -# FIXME: For 2.7: AT_CHECK([sed -ne '/[ ]$/{=;p;}' $1]) -# No final empty lines. -AT_CHECK([sed -ne '${/^$/{=;p;};}' $1]) +[AT_CHECK([perl -ne ' + chomp; + print "$.: {$_}\n" + if (# No starting/ending empty lines. + (eof || $. == 1) && /^\s*$/ + # No trailing space. FIXME: not ready for "maint". + # || /\s$/ + )' $1 +])dnl ]) From 45fdfd8108084c2c3505d584d8dcc7e534ae77a2 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sun, 8 Apr 2012 08:58:43 +0200 Subject: [PATCH 03/18] build: look for Perl in configure. Bison uses "/usr/bin/perl" or "perl" in several places, and it does not appear to be a problem. But, at least to make it simpler to change PERL on the make command line, check for perl in configure. * configure.ac (PERL): New. * doc/Doxyfile.in, doc/Makefile.am, tests/bison.in: Use it. --- configure.ac | 4 ++++ doc/Doxyfile.in | 2 +- doc/Makefile.am | 2 +- tests/bison.in | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index b9d2ea69..4cc9ef91 100644 --- a/configure.ac +++ b/configure.ac @@ -123,6 +123,10 @@ AC_PROG_GNU_M4 AC_DEFINE_UNQUOTED([M4], ["$M4"], [Define to the GNU M4 executable name.]) AC_DEFINE_UNQUOTED([M4_GNU_OPTION], ["$M4_GNU"], [Define to "-g" if GNU M4 supports -g, otherwise to "".]) +AC_PATH_PROG([PERL], [perl]) +if test -z "$PERL"; then + AC_MSG_ERROR([perl not found]) +fi AM_MISSING_PROG([HELP2MAN], [help2man]) AC_PATH_PROG([XSLTPROC], [xsltproc]) AC_SUBST([XSLTPROC]) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index b5557518..e36a1cee 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -940,7 +940,7 @@ EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). -PERL_PATH = /usr/bin/perl +PERL_PATH = @PERL@ #--------------------------------------------------------------------------- # Configuration options related to the dot tool diff --git a/doc/Makefile.am b/doc/Makefile.am index d87f00f0..f695e22d 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -30,7 +30,7 @@ $(srcdir)/cross-options.texi: $(top_srcdir)/src/getargs.c $(CROSS_OPTIONS_PL) $(AM_V_at)rm -f $@.tmp $(AM_V_at)cd $(top_builddir)/src && $(MAKE) $(AM_MAKEFLAGS) bison $(AM_V_at)$(top_builddir)/src/bison --help \ - | perl $(CROSS_OPTIONS_PL) $(top_srcdir)/src/scan-gram.l >$@.tmp + | $(PERL) $(CROSS_OPTIONS_PL) $(top_srcdir)/src/scan-gram.l >$@.tmp $(AM_V_at)diff -u $@~ $@.tmp || true $(AM_V_at)mv $@.tmp $@ MAINTAINERCLEANFILES = $(srcdir)/cross-options.texi diff --git a/tests/bison.in b/tests/bison.in index 4dfeb791..f21b2bcd 100644 --- a/tests/bison.in +++ b/tests/bison.in @@ -19,7 +19,7 @@ abs_top_srcdir='@abs_top_srcdir@' abs_top_builddir='@abs_top_builddir@' -: ${PERL=perl} +: ${PERL='@PERL@'} # Use the shipped files, not those installed. BISON_PKGDATADIR=$abs_top_srcdir/data From ff020c3061aeab8a20a4a6fd48c434e3e5aeb29b Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Fri, 5 Oct 2012 09:24:59 +0200 Subject: [PATCH 04/18] tests: use $PERL instead of perl * tests/atlocal.in (PERL): New. Sort. * tests/calc.at, tests/input.at, tests/local.at, tests/regression.at, * tests/skeletons.at, tests/synclines.at, tests/torture.at: here. --- tests/atlocal.in | 20 +++++++++++--------- tests/calc.at | 2 +- tests/input.at | 8 ++++---- tests/local.at | 2 +- tests/regression.at | 6 +++--- tests/skeletons.at | 2 +- tests/synclines.at | 2 +- tests/torture.at | 6 +++--- 8 files changed, 25 insertions(+), 23 deletions(-) diff --git a/tests/atlocal.in b/tests/atlocal.in index d059d630..9a2d19f0 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -63,24 +63,26 @@ fi ## Other. ## ## ------- ## -# Are special link options needed? -LDFLAGS='@LDFLAGS@' - -# Are special libraries needed? -LIBS="$abs_top_builddir/lib/libbison.a @LIBS@ @INTLLIBS@" - # Empty if no javac was found CONF_JAVAC='@CONF_JAVAC@' # Empty if no Java VM was found CONF_JAVA='@CONF_JAVA@' -# Empty if no xsltproc was found -: ${XSLTPROC='@XSLTPROC@'} - # We need egrep. : ${EGREP='@EGREP@'} # Use simple quotes (lib/quote.c). LC_CTYPE=C export LC_CTYPE + +# Are special link options needed? +LDFLAGS='@LDFLAGS@' + +# Are special libraries needed? +LIBS="$abs_top_builddir/lib/libbison.a @LIBS@ @INTLLIBS@" + +# Empty if no xsltproc was found +: ${XSLTPROC='@XSLTPROC@'} + +: ${PERL='@PERL@'} diff --git a/tests/calc.at b/tests/calc.at index a1c11e5f..9518c3c3 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -503,7 +503,7 @@ AT_CHECK([cat stderr], 0, [expout]) # Make sure we did not introduce bad spaces. Checked here because all # the skeletons are (or should be) exercized here. m4_define([AT_CHECK_SPACES], -[AT_CHECK([perl -ne ' +[AT_CHECK([$PERL -ne ' chomp; print "$.: {$_}\n" if (# No starting/ending empty lines. diff --git a/tests/input.at b/tests/input.at index 86a955dc..16a9308d 100644 --- a/tests/input.at +++ b/tests/input.at @@ -1195,7 +1195,7 @@ AT_DATA([empty.y], start: ''; start: ' ]]) -AT_CHECK([[perl -e "print 'start: \'';" >> empty.y || exit 77]]) +AT_CHECK([[$PERL -e "print 'start: \'';" >> empty.y || exit 77]]) AT_BISON_CHECK([empty.y], [1], [], [[empty.y:2.8-9: warning: empty character literal @@ -1210,7 +1210,7 @@ AT_DATA([two.y], start: 'ab'; start: 'ab ]]) -AT_CHECK([[perl -e "print 'start: \'ab';" >> two.y || exit 77]]) +AT_CHECK([[$PERL -e "print 'start: \'ab';" >> two.y || exit 77]]) AT_BISON_CHECK([two.y], [1], [], [[two.y:2.8-11: warning: extra characters in character literal @@ -1225,7 +1225,7 @@ AT_DATA([three.y], start: 'abc'; start: 'abc ]]) -AT_CHECK([[perl -e "print 'start: \'abc';" >> three.y || exit 77]]) +AT_CHECK([[$PERL -e "print 'start: \'abc';" >> three.y || exit 77]]) AT_BISON_CHECK([three.y], [1], [], [[three.y:2.8-12: warning: extra characters in character literal @@ -1254,7 +1254,7 @@ start: '\777' '\0' '\xfff' '\x0' # Beside we cannot even expect "echo '\0'" to output two characters # (well three with \n): at least Bash 3.2 converts the two-character # sequence "\0" into a single NUL character. -AT_CHECK([[perl -e 'print "start: \"\\\t\\\f\\\0\\\1\" ;";' >> input.y \ +AT_CHECK([[$PERL -e 'print "start: \"\\\t\\\f\\\0\\\1\" ;";' >> input.y \ || exit 77]]) AT_BISON_CHECK([input.y], [1], [], diff --git a/tests/local.at b/tests/local.at index 5c9b865e..2362e766 100644 --- a/tests/local.at +++ b/tests/local.at @@ -38,7 +38,7 @@ m4_define([m4_null_if], # Expect COUNT matches of the PERL-REGEXP in FILE. The file is # taken in "slurp" mode, i.e., one can match end-of-lines. m4_define([AT_MATCHES_CHECK], -[AT_CHECK([perl -0777 -ne ' +[AT_CHECK([$PERL -0777 -ne ' my $count = 0; s{$2}{ ++$count; "" }gem; printf "$count\n";' $1], [0], [$3 diff --git a/tests/regression.at b/tests/regression.at index 617a6752..c44b9f88 100644 --- a/tests/regression.at +++ b/tests/regression.at @@ -1481,17 +1481,17 @@ AT_CHECK([[grep 'syntax error,' stderr.txt]], [[0]], # Check number of default reductions in inconsistent states to be sure # syntax error is detected before unnecessary reductions are performed. -AT_CHECK([[perl -0777 -ne 'print s/inconsistent default reduction//g;' \ +AT_CHECK([[$PERL -0777 -ne 'print s/inconsistent default reduction//g;' \ < stdout.txt || exit 77]], [[0]], [[14]]) # Check number of default reductions in consistent states to be sure # it is performed before the syntax error is detected. -AT_CHECK([[perl -0777 -ne 'print s/\bconsistent default reduction//g;' \ +AT_CHECK([[$PERL -0777 -ne 'print s/\bconsistent default reduction//g;' \ < stdout.txt || exit 77]], [[0]], [[2]]) # Check number of reallocs to be sure reallocated memory isn't somehow # lost between LAC invocations. -AT_CHECK([[perl -0777 -ne 'print s/\(realloc//g;' < stderr.txt \ +AT_CHECK([[$PERL -0777 -ne 'print s/\(realloc//g;' < stderr.txt \ || exit 77]], [[0]], [[3]]) AT_BISON_OPTION_POPDEFS diff --git a/tests/skeletons.at b/tests/skeletons.at index ec8170ca..7b5b8f27 100644 --- a/tests/skeletons.at +++ b/tests/skeletons.at @@ -315,7 +315,7 @@ print '@output(@,@)', "\n"; (print "garbage"x10, "\n") for (1..1000); print "${M4}_divert_pop(0)\n"; ]]) -AT_CHECK([[perl gen-skel.pl > skel.c || exit 77]]) +AT_CHECK([[$PERL gen-skel.pl > skel.c || exit 77]]) AT_DATA([[input.y]], [[%skeleton "./skel.c" diff --git a/tests/synclines.at b/tests/synclines.at index e2b7005d..041ae194 100644 --- a/tests/synclines.at +++ b/tests/synclines.at @@ -64,7 +64,7 @@ m4_define([AT_SYNCLINES_COMPILE], # distcc[35882] (dcc_connect_by_name) ERROR: failed to look up host "chrisimac": Unknown host # distcc[35882] Warning: failed to distribute input.c to chrisimac/4, running locally instead -AT_CHECK([[perl -p -0777 - stderr <<\EOF +AT_CHECK([[$PERL -p -0777 - stderr <<\EOF s/^distcc\[\d+\] .*\n//gm; s/^([^:]+:\d+)[.:][^:]+:(.+)$/$][1:$][2/gm; s/^([^:]+:\d+):[^#]*( #error)/$][1:$][2/gm; diff --git a/tests/torture.at b/tests/torture.at index 705e131e..a5e244b6 100644 --- a/tests/torture.at +++ b/tests/torture.at @@ -125,7 +125,7 @@ EOF ]]) AT_BISON_OPTION_POPDEFS -AT_CHECK([perl -w ./gengram.pl $2 || exit 77], 0, [stdout]) +AT_CHECK([$PERL -w ./gengram.pl $2 || exit 77], 0, [stdout]) mv stdout $1 ]) @@ -214,7 +214,7 @@ main (void) EOF ]]) -AT_CHECK([perl -w ./gengram.pl $2 || exit 77], 0, [stdout]) +AT_CHECK([$PERL -w ./gengram.pl $2 || exit 77], 0, [stdout]) mv stdout $1 AT_BISON_OPTION_POPDEFS ]) @@ -350,7 +350,7 @@ main (void) EOF ]]) -AT_CHECK([perl -w ./gengram.pl $2 || exit 77], 0, [stdout]) +AT_CHECK([$PERL -w ./gengram.pl $2 || exit 77], 0, [stdout]) mv stdout $1 AT_BISON_OPTION_POPDEFS ]) From 535ee0cb54b7fec32b5dea3433d0e9d993761bf6 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Thu, 20 Sep 2012 11:42:06 +0200 Subject: [PATCH 05/18] tests: minor improvements * tests/c++.at: Space changes. Use AT_YYERROR_DEFINE. * tests/local.at (AT_YYERROR_DEFINE): Issue errors on unknown languages. --- tests/c++.at | 9 ++++----- tests/local.at | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/c++.at b/tests/c++.at index 93675d4d..c44a2a59 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -1,4 +1,4 @@ -# Checking the output filenames. -*- Autotest -*- +# Checking the C++ Features. -*- Autotest -*- # Copyright (C) 2004-2005, 2007, 2009-2012 Free Software Foundation, # Inc. @@ -30,6 +30,7 @@ m4_define([AT_CHECK_DOXYGEN], [m4_fatal([invalid argument: $1])]) AT_SETUP([Doxygen $1 Documentation]) +AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) AT_DATA([input.yy], [[%skeleton "lalr1.cc" %locations @@ -38,10 +39,7 @@ AT_DATA([input.yy], %% exp:; %% -yy::parser::error (const location& l, const std::string& m) -{ - std::cerr << l << s << std::endl; -} +]AT_YYERROR_DEFINE[ ]]) AT_BISON_CHECK([-o input.cc input.yy], 0) @@ -94,6 +92,7 @@ EXTRACT_STATIC = AT_DOXYGEN_PRIVATE AT_CHECK([doxygen --version || exit 77], 0, ignore) AT_CHECK([doxygen], 0, [], [ignore]) +AT_BISON_OPTION_POPDEFS AT_CLEANUP m4_popdef([AT_DOXYGEN_PRIVATE]) diff --git a/tests/local.at b/tests/local.at index 2362e766..036b0a1d 100644 --- a/tests/local.at +++ b/tests/local.at @@ -405,7 +405,8 @@ void public void yyerror (String s) { System.err.println (s); - }]])])dnl + }]])], +[m4_fatal([$0: invalid language: ]AT_LANG)])dnl ]) From 88322b77b174bc1ebd85eef290e41fc001b21f07 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 25 Sep 2012 14:14:57 +0200 Subject: [PATCH 06/18] lalr1.cc: don't leave macros define to nothing * data/lalr1.cc (YY_SYMBOL_PRINT, YY_REDUCE_PRINT, YY_STACK_PRINT): Define to something so that, for instance, "if (foo) YY_SYMBOL_PRINT" is valid even when !YYDEBUG. --- data/lalr1.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/lalr1.cc b/data/lalr1.cc index 82e68244..308290ad 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -335,9 +335,9 @@ do { \ #else /* !]b4_api_PREFIX[DEBUG */ # define YYCDEBUG if (false) std::cerr -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_REDUCE_PRINT(Rule) -# define YY_STACK_PRINT() +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) YYUSE(Type) +# define YY_REDUCE_PRINT(Rule) static_cast(0) +# define YY_STACK_PRINT() static_cast(0) #endif /* !]b4_api_PREFIX[DEBUG */ From 117c7942002c64b0a22079d983cd54d270f529b4 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Thu, 20 Sep 2012 17:04:50 +0200 Subject: [PATCH 07/18] lalr1.cc: indentation fixes. * data/lalr1.cc (yyparse): here. Untabify a block of code. --- data/lalr1.cc | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/data/lalr1.cc b/data/lalr1.cc index 308290ad..846aea1b 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -712,20 +712,19 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; yyerror_range[1] = yylloc; if (yyerrstatus_ == 3) { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= yyeof_) - { - /* Return failure if at end of input. */ - if (yychar == yyeof_) - YYABORT; - } - else - { - yydestruct_ ("Error: discarding", yytoken, &yylval, &yylloc); - yychar = yyempty_; - } + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + if (yychar <= yyeof_) + { + /* Return failure if at end of input. */ + if (yychar == yyeof_) + YYABORT; + } + else + { + yydestruct_ ("Error: discarding", yytoken, &yylval, &yylloc); + yychar = yyempty_; + } } /* Else will try to reuse lookahead token after shifting the error @@ -774,7 +773,7 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; /* Pop the current state because it cannot handle the error token. */ if (yystate_stack_.height () == 1) - YYABORT; + YYABORT; yyerror_range[1] = yylocation_stack_[0]; yydestruct_ ("Error: popping", @@ -824,11 +823,11 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; yypop_ (yylen); while (yystate_stack_.height () != 1) { - yydestruct_ ("Cleanup: popping", - yystos_[yystate_stack_[0]], - &yysemantic_stack_[0], - &yylocation_stack_[0]); - yypop_ (); + yydestruct_ ("Cleanup: popping", + yystos_[yystate_stack_[0]], + &yysemantic_stack_[0], + &yylocation_stack_[0]); + yypop_ (); } return yyresult; From cff926615f1ae4441f60ebeb2992a2d221da910f Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Thu, 20 Sep 2012 11:43:19 +0200 Subject: [PATCH 08/18] lalr1.cc: check exception safety. * tests/c++.at (Exception safety): New. --- tests/c++.at | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/tests/c++.at b/tests/c++.at index c44a2a59..304a72d9 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -181,3 +181,144 @@ AT_CHECK_NAMESPACE([[foo[3]::bar::baz]], [[-]]) AT_CHECK_NAMESPACE([[foo::bar,baz]], [[-]]) AT_CHECK_NAMESPACE([[foo::bar::(baz]], [[-]]) AT_CLEANUP + + +## ------------------ ## +## Exception safety. ## +## ------------------ ## + +AT_SETUP([[Exception safety]]) + +AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) + +AT_DATA_GRAMMAR([[input.yy]], +[[%skeleton "lalr1.cc" +%defines // FIXME: Mandated in 2.6. +%debug + +%code requires +{ + #include // size_t and getenv. + #include + + int debug = 0; + + struct Object + { + static size_t counter; + + Object () + { + ++counter; + if (debug) + std::cerr << "Object::Object() => counter == " << counter << std::endl; + } + + ~Object () + { + --counter; + if (debug) + std::cerr << "Object::~Object() => counter == " << counter << std::endl; + } + }; +} + +%code +{ + #include + #include + int yylex (yy::parser::semantic_type *); + size_t Object::counter = 0; + static char const *input; +} + +%union +{ + Object* obj; +} + +%destructor { delete $$; } ; +%printer { yyo << "counter == " << $$->counter; } ; + +%token 'a' 's' +%type list item + +%% + +start: list { delete $1; }; + +list: + item { $$ = $1; } +| item list { $$ = $1; delete $2; } /* Right recursion to load the stack. */ +; + +item: + 'a' + { + std::swap ($$, $1); + } +| 's' + { + std::swap ($$, $1); + throw std::runtime_error ("invalid expression"); + } + +%% + +int +yylex (yy::parser::semantic_type *lvalp) +{ + // 'l': lexical exception, 's': syntactic exception. + switch (int res = *input++) + { + case 'l': + throw std::runtime_error ("invalid character"); + default: + lvalp->obj = new Object; + // Fall through. + case 0: + return res; + } +} + +]AT_YYERROR_DEFINE[ + +int +main (int argc, const char *argv[]) +{ + assert (argc == 2); + input = argv[1]; + yy::parser parser; + debug = !!getenv ("YYDEBUG"); + parser.set_debug_level (debug); + int res = 2; + try + { + res = parser.parse (); + } + catch (const std::exception& e) + { + std::cerr << "exception caught: " << e.what () << std::endl; + } + catch (...) + { + std::cerr << "unknown exception caught" << std::endl; + } + assert (Object::counter == 0); + return res; +} +]]) +AT_BISON_CHECK([[-o input.cc input.yy]]) +AT_COMPILE_CXX([[input]]) + +AT_PARSER_CHECK([[./input aaaas]], [[2]], [[]], +[[exception caught: invalid expression +]]) + +AT_PARSER_CHECK([[./input aaaal]], [[2]], [[]], +[[exception caught: invalid character +]]) + +AT_BISON_OPTION_POPDEFS + +AT_CLEANUP From 7e1fabbeae9accb48611457f550286f1934ef533 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Thu, 20 Sep 2012 16:59:29 +0200 Subject: [PATCH 09/18] lalr1.cc: fix exception safety lalr1.cc does not reclaim its memory when ended by an exception. Reported by Oleksii Taran: http://lists.gnu.org/archive/html/help-bison/2012-09/msg00000.html * data/lalr1.cc (yyparse): Protect the whole yyparse by a try-catch block that cleans the stack and the lookahead. --- THANKS | 1 + data/lalr1.cc | 45 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/THANKS b/THANKS index f742e8f8..185097f7 100644 --- a/THANKS +++ b/THANKS @@ -80,6 +80,7 @@ Nicolas Tisserand nicolas.tisserand@epita.fr Noah Friedman friedman@gnu.org Odd Arild Olsen oao@fibula.no Oleg Smolsky oleg.smolsky@pacific-simulators.co.nz +Oleksii Taran oleksii.taran@gmail.com Paolo Bonzini bonzini@gnu.org Pascal Bart pascal.bart@epita.fr Paul Eggert eggert@cs.ucla.edu diff --git a/data/lalr1.cc b/data/lalr1.cc index 846aea1b..fe23b3e1 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -533,6 +533,10 @@ do { \ int yyresult; + // FIXME: This shoud be completely indented. It is not yet to + // avoid gratuitous conflicts when merging into the master branch. + try + { YYCDEBUG << "Starting parse" << std::endl; ]m4_ifdef([b4_initial_action], [ @@ -573,14 +577,13 @@ b4_dollar_popdef])[]dnl /* Read a lookahead token. */ if (yychar == yyempty_) { - YYCDEBUG << "Reading a token: "; - yychar = ]b4_c_function_call([yylex], [int], - [b4_api_PREFIX[STYPE*], [&yylval]][]dnl + YYCDEBUG << "Reading a token: "; + yychar = ]b4_c_function_call([yylex], [int], + [b4_api_PREFIX[STYPE*], [&yylval]][]dnl b4_locations_if([, [[location*], [&yylloc]]])dnl m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; } - /* Convert token to internal form. */ if (yychar <= yyeof_) { @@ -651,17 +654,21 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; else yyval = yysemantic_stack_[0]; + // Compute the default @@$. { slice slice (yylocation_stack_, yylen); YYLLOC_DEFAULT (yyloc, slice, yylen); } + + // Perform the reduction. YY_REDUCE_PRINT (yyn); switch (yyn) { - ]b4_user_actions[ - default: - break; + ]b4_user_actions[ + default: + break; } + /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. @@ -831,6 +838,30 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; } return yyresult; + } + catch (...) + { + YYCDEBUG << "Exception caught" << std::endl; + if (yychar != yyempty_) + { + /* Make sure we have latest lookahead translation. See + comments at user semantic actions for why this is + necessary. */ + yytoken = yytranslate_ (yychar); + yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, + &yylloc); + } + + while (yystate_stack_.height () != 1) + { + yydestruct_ ("Cleanup: popping", + yystos_[yystate_stack_[0]], + &yysemantic_stack_[0], + &yylocation_stack_[0]); + yypop_ (); + } + throw; + } } // Generate an error message. From a26424642b1de2c5e237cd69a54f12b2f430321f Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 25 Sep 2012 11:17:55 +0200 Subject: [PATCH 10/18] lalr1.cc: check (and fix) %initial-action exception safety * data/lalr1.cc: Check size > 1, rather than size != 1, when cleaning the stack, as at the beginning, size is 0. * tests/c++.at (Exception safety): Check exception safety in %initial-action. --- data/lalr1.cc | 4 ++-- tests/c++.at | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/data/lalr1.cc b/data/lalr1.cc index fe23b3e1..2ec1d0d7 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -828,7 +828,7 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ yypop_ (yylen); - while (yystate_stack_.height () != 1) + while (1 < yystate_stack_.height ()) { yydestruct_ ("Cleanup: popping", yystos_[yystate_stack_[0]], @@ -852,7 +852,7 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; &yylloc); } - while (yystate_stack_.height () != 1) + while (1 < yystate_stack_.height ()) { yydestruct_ ("Cleanup: popping", yystos_[yystate_stack_[0]], diff --git a/tests/c++.at b/tests/c++.at index 304a72d9..e4a79115 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -226,6 +226,7 @@ AT_DATA_GRAMMAR([[input.yy]], %code { #include + #include // strchr #include int yylex (yy::parser::semantic_type *); size_t Object::counter = 0; @@ -237,6 +238,12 @@ AT_DATA_GRAMMAR([[input.yy]], Object* obj; } +%initial-action +{ + if (strchr (input, 'i')) + throw std::runtime_error ("initial-action"); +} + %destructor { delete $$; } ; %printer { yyo << "counter == " << $$->counter; } ; @@ -260,7 +267,7 @@ item: | 's' { std::swap ($$, $1); - throw std::runtime_error ("invalid expression"); + throw std::runtime_error ("reduction"); } %% @@ -268,11 +275,14 @@ item: int yylex (yy::parser::semantic_type *lvalp) { - // 'l': lexical exception, 's': syntactic exception. + // 'a': no error. + // 'i': initial action throws. + // 'l': yylex throws. + // 's': reduction throws. switch (int res = *input++) { case 'l': - throw std::runtime_error ("invalid character"); + throw std::runtime_error ("yylex"); default: lvalp->obj = new Object; // Fall through. @@ -312,11 +322,15 @@ AT_BISON_CHECK([[-o input.cc input.yy]]) AT_COMPILE_CXX([[input]]) AT_PARSER_CHECK([[./input aaaas]], [[2]], [[]], -[[exception caught: invalid expression +[[exception caught: reduction ]]) AT_PARSER_CHECK([[./input aaaal]], [[2]], [[]], -[[exception caught: invalid character +[[exception caught: yylex +]]) + +AT_PARSER_CHECK([[./input i]], [[2]], [[]], +[[exception caught: initial-action ]]) AT_BISON_OPTION_POPDEFS From 25a6ad2f109cfc8a4683d406054141d1a2210b36 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 25 Sep 2012 11:41:22 +0200 Subject: [PATCH 11/18] lalr1.cc: check (and fix) %printer exception safety * tests/c++.at (Exception safety): Let the parser support the --debug option. On 'p', throw an exception from the %printer. * data/lalr1.cc (yyparse): Do not display the values we discard, as it uses %printer, which might have thrown the exception. --- data/lalr1.cc | 14 +++++++++----- tests/c++.at | 47 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/data/lalr1.cc b/data/lalr1.cc index 2ec1d0d7..3b8c9215 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -227,6 +227,7 @@ b4_user_stype /// \brief Reclaim the memory associated to a symbol. /// \param yymsg Why this token is reclaimed. + /// If null, do not display the symbol, just free it. /// \param yytype The symbol type. /// \param yyvaluep Its semantic value. /// \param yylocationp Its location. @@ -446,7 +447,8 @@ do { \ YYUSE (yymsg); YYUSE (yyvaluep); - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + if (yymsg) + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { @@ -841,20 +843,22 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[; } catch (...) { - YYCDEBUG << "Exception caught" << std::endl; + YYCDEBUG << "Exception caught: cleaning lookahead and stack" + << std::endl; + // Do not try to display the values of the reclaimed symbols, + // as their printer might throw an exception. if (yychar != yyempty_) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yytranslate_ (yychar); - yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, - &yylloc); + yydestruct_ (YY_NULL, yytoken, &yylval, &yylloc); } while (1 < yystate_stack_.height ()) { - yydestruct_ ("Cleanup: popping", + yydestruct_ (YY_NULL, yystos_[yystate_stack_[0]], &yysemantic_stack_[0], &yylocation_stack_[0]); diff --git a/tests/c++.at b/tests/c++.at index e4a79115..9a60bfd8 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -203,11 +203,14 @@ AT_DATA_GRAMMAR([[input.yy]], int debug = 0; + /// A class that counts its number of instances. struct Object { static size_t counter; + int val; - Object () + Object (int v) + : val (v) { ++counter; if (debug) @@ -245,9 +248,14 @@ AT_DATA_GRAMMAR([[input.yy]], } %destructor { delete $$; } ; -%printer { yyo << "counter == " << $$->counter; } ; +%printer +{ + yyo << "counter == " << $$->counter; + if ($$->val == 'p') + throw std::runtime_error ("printer"); +} ; -%token 'a' 's' +%token 'a' 'p' 's' %type list item %% @@ -256,14 +264,12 @@ start: list { delete $1; }; list: item { $$ = $1; } -| item list { $$ = $1; delete $2; } /* Right recursion to load the stack. */ +| item list { $$ = $1; delete $2; } // Right recursion to load the stack. ; item: - 'a' - { - std::swap ($$, $1); - } + 'a' { std::swap ($$, $1); } +| 'p' { std::swap ($$, $1); } | 's' { std::swap ($$, $1); @@ -284,7 +290,7 @@ yylex (yy::parser::semantic_type *lvalp) case 'l': throw std::runtime_error ("yylex"); default: - lvalp->obj = new Object; + lvalp->obj = new Object (res); // Fall through. case 0: return res; @@ -296,10 +302,22 @@ yylex (yy::parser::semantic_type *lvalp) int main (int argc, const char *argv[]) { - assert (argc == 2); - input = argv[1]; + switch (argc) + { + case 2: + input = argv[1]; + break; + case 3: + assert (!strcmp (argv[1], "--debug")); + debug = 1; + input = argv[2]; + break; + default: + abort (); + } + yy::parser parser; - debug = !!getenv ("YYDEBUG"); + debug |= !!getenv ("YYDEBUG"); parser.set_debug_level (debug); int res = 2; try @@ -333,6 +351,11 @@ AT_PARSER_CHECK([[./input i]], [[2]], [[]], [[exception caught: initial-action ]]) +AT_PARSER_CHECK([[./input aaaap]]) + +AT_PARSER_CHECK([[./input --debug aaaap]], [[2]], [[]], [[stderr]]) +AT_PARSER_CHECK([[grep '^exception caught: printer$' stderr]], [], [ignore]) + AT_BISON_OPTION_POPDEFS AT_CLEANUP From e8b86af83dd7dab9bc5c612583d5443c55ee2bb0 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 25 Sep 2012 14:18:04 +0200 Subject: [PATCH 12/18] lalr1.cc: check exception safety of error handling * tests/c++.at (Exception safety): Don't use swap here, it is useless. Cover more test cases: yyerror, YYERROR, YYABORT, and error recovery. (Object): Instead of just keeping a counter of instances, keep a list of them. --- tests/c++.at | 106 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/tests/c++.at b/tests/c++.at index 9a60bfd8..dba7a758 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -195,33 +195,62 @@ AT_DATA_GRAMMAR([[input.yy]], [[%skeleton "lalr1.cc" %defines // FIXME: Mandated in 2.6. %debug +%error-verbose %code requires { + #include #include // size_t and getenv. #include + #include - int debug = 0; + bool debug = false; /// A class that counts its number of instances. struct Object { - static size_t counter; - int val; + typedef std::list objects; + static objects instances; + char val; - Object (int v) + static bool + empty () + { + return instances.empty(); + } + + static void + log (Object const *o, const std::string& msg) + { + if (debug) + { + if (o) + std::cerr << o << "->"; + std::cerr << msg << " {"; + const char* sep = " "; + for (objects::const_iterator i = instances.begin(), + i_end = instances.end(); + i != i_end; + ++i) + { + std::cerr << sep << *i; + sep = ", "; + } + std::cerr << " }" << std::endl; + } + } + + Object (char v) : val (v) { - ++counter; - if (debug) - std::cerr << "Object::Object() => counter == " << counter << std::endl; + instances.push_back(this); + log (this, "Object::Object"); } ~Object () { - --counter; - if (debug) - std::cerr << "Object::~Object() => counter == " << counter << std::endl; + instances.remove(this); + log (this, "Object::~Object"); } }; } @@ -232,13 +261,13 @@ AT_DATA_GRAMMAR([[input.yy]], #include // strchr #include int yylex (yy::parser::semantic_type *); - size_t Object::counter = 0; + Object::objects Object::instances; static char const *input; } %union { - Object* obj; + Object *obj; } %initial-action @@ -250,12 +279,12 @@ AT_DATA_GRAMMAR([[input.yy]], %destructor { delete $$; } ; %printer { - yyo << "counter == " << $$->counter; + yyo << $$ << " '" << $$->val << '\''; if ($$->val == 'p') throw std::runtime_error ("printer"); } ; -%token 'a' 'p' 's' +%token 'a' 'E' 'e' 'p' 'R' 's' 'T' %type list item %% @@ -268,23 +297,30 @@ list: ; item: - 'a' { std::swap ($$, $1); } -| 'p' { std::swap ($$, $1); } -| 's' - { - std::swap ($$, $1); - throw std::runtime_error ("reduction"); - } - + 'a' { $$ = $1; } +| 'e' { YYUSE ($$); YYUSE($1); error (location_type(), "syntax error"); } +// Not just 'E', otherwise we reduce when 'E' is the lookahead, and +// then the stack is emptied, defeating the point of the test. +| 'E' 'a' { YYUSE($1); $$ = $2; } +| 'R' { $$ = YY_NULL; delete $1; YYERROR; } +| 'p' { $$ = $1; } +| 's' { $$ = $1; throw std::runtime_error ("reduction"); } +| 'T' { $$ = YY_NULL; delete $1; YYABORT; } +| error { $$ = YY_NULL; yyerrok; } +; %% int yylex (yy::parser::semantic_type *lvalp) { // 'a': no error. + // 'e': user action calls error. + // 'E': syntax error, with yyerror that throws. // 'i': initial action throws. // 'l': yylex throws. + // 'R': call YYERROR in the action // 's': reduction throws. + // 'T': call YYABORT in the action switch (int res = *input++) { case 'l': @@ -297,7 +333,13 @@ yylex (yy::parser::semantic_type *lvalp) } } -]AT_YYERROR_DEFINE[ +/* A C++ error reporting function. */ +void +yy::parser::error (const location_type& l, const std::string& m) +{ + YYUSE (l); + throw std::runtime_error (m); +} int main (int argc, const char *argv[]) @@ -332,11 +374,12 @@ main (int argc, const char *argv[]) { std::cerr << "unknown exception caught" << std::endl; } - assert (Object::counter == 0); + Object::log (YY_NULL, "end"); + assert (Object::empty()); return res; } ]]) -AT_BISON_CHECK([[-o input.cc input.yy]]) +AT_BISON_CHECK([[-o input.cc --report=all input.yy]]) AT_COMPILE_CXX([[input]]) AT_PARSER_CHECK([[./input aaaas]], [[2]], [[]], @@ -356,6 +399,19 @@ AT_PARSER_CHECK([[./input aaaap]]) AT_PARSER_CHECK([[./input --debug aaaap]], [[2]], [[]], [[stderr]]) AT_PARSER_CHECK([[grep '^exception caught: printer$' stderr]], [], [ignore]) +AT_PARSER_CHECK([[./input aaaae]], [[2]], [[]], +[[exception caught: syntax error +]]) + +AT_PARSER_CHECK([[./input aaaaE]], [[2]], [[]], +[[exception caught: syntax error, unexpected $end, expecting 'a' +]]) + +AT_PARSER_CHECK([[./input aaaaT]], [[1]]) + +# There is error-recovery, so exit success. +AT_PARSER_CHECK([[./input aaaaR]], [[0]]) + AT_BISON_OPTION_POPDEFS AT_CLEANUP From d3e4409ad1da0fe2625a6f77e9a5b93a0a6e6647 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Mon, 1 Oct 2012 11:41:26 +0200 Subject: [PATCH 13/18] lalr1.cc: document exception safety * NEWS: here. * doc/bison.texi (Destructor Decl, C++ Parser Interface): and there. --- NEWS | 9 +++++++++ doc/bison.texi | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/NEWS b/NEWS index c8a4d312..81afe649 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,15 @@ GNU Bison NEWS will use YY_CALC_LIB_PARSE_H_INCLUDED as guard. +** Exception safety (lalr1.cc) + + The parse function now catches exceptions, uses the %destructors to + release memory (the lookahead symbol and the symbols pushed on the stack) + before rethrowing the exception. + + This feature is somewhat experimental. User feedback would be + appreciated. + * Noteworthy changes in release 2.6.2 (2012-08-03) [stable] ** Bug fixes diff --git a/doc/bison.texi b/doc/bison.texi index ba18d9a9..ce1ebd11 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -4701,6 +4701,10 @@ incoming terminals during the second phase of error recovery, the current lookahead and the entire stack (except the current right-hand side symbols) when the parser returns immediately, and @item +the current lookahead and the entire stack (including the current right-hand +side symbols) when the C++ parser (@file{lalr1.cc}) catches an exception in +@code{parse}, +@item the start symbol, when the parser succeeds. @end itemize @@ -9415,6 +9419,11 @@ Build a new parser object. There are no arguments by default, unless @deftypemethod {parser} {int} parse () Run the syntactic analysis, and return 0 on success, 1 otherwise. + +@cindex exceptions +The whole function is wrapped in a @code{try}/@code{catch} block, so that +when an exception is thrown, the @code{%destructor}s are called to release +the lookahead symbol, and the symbols pushed on the stack. @end deftypemethod @deftypemethod {parser} {std::ostream&} debug_stream () From c5178eb75d34ccbf5c543073445f23e8446cae09 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Mon, 8 Oct 2012 09:12:10 +0200 Subject: [PATCH 14/18] skeletons: style changes * data/yacc.c, data/glr.c: Prefer Title case for (CPP) macro arguments. --- data/glr.c | 24 ++++++++++++------------ data/yacc.c | 18 +++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/data/glr.c b/data/glr.c index 97efe894..9b8ff67c 100644 --- a/data/glr.c +++ b/data/glr.c @@ -241,24 +241,24 @@ b4_percent_code_get[]dnl # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ -# define YY_(msgid) msgid +# define YY_(Msgid) Msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) +# define YYUSE(E) ((void) (E)) #else -# define YYUSE(e) /* empty */ +# define YYUSE(E) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint -# define YYID(n) (n) +# define YYID(N) (N) #else ]b4_c_function_def([YYID], [static int], [[int i], [i]])[ { @@ -289,8 +289,8 @@ b4_percent_code_get[]dnl #ifndef YYSETJMP # include # define YYJMP_BUF jmp_buf -# define YYSETJMP(env) setjmp (env) -# define YYLONGJMP(env, val) longjmp (env, val) +# define YYSETJMP(Env) setjmp (Env) +# define YYLONGJMP(Env, Val) longjmp (Env, Val) #endif /*-----------------. @@ -313,7 +313,7 @@ b4_percent_code_get[]dnl #endif])[ #ifndef YYASSERT -# define YYASSERT(condition) ((void) ((condition) || (abort (), 0))) +# define YYASSERT(Condition) ((void) ((Condition) || (abort (), 0))) #endif /* YYFINAL -- State number of the termination state. */ @@ -972,8 +972,8 @@ yylhsNonterm (yyRuleNum yyrule) return yyr1[yyrule]; } -#define yypact_value_is_default(yystate) \ - ]b4_table_value_equals([[pact]], [[yystate]], [b4_pact_ninf])[ +#define yypact_value_is_default(Yystate) \ + ]b4_table_value_equals([[pact]], [[Yystate]], [b4_pact_ninf])[ /** True iff LR state STATE has only a default reduction (regardless * of token). */ @@ -990,8 +990,8 @@ yydefaultAction (yyStateNum yystate) return yydefact[yystate]; } -#define yytable_value_is_error(yytable_value) \ - ]b4_table_value_equals([[table]], [[yytable_value]], [b4_table_ninf])[ +#define yytable_value_is_error(Yytable_value) \ + ]b4_table_value_equals([[table]], [[Yytable_value]], [b4_table_ninf])[ /** Set *YYACTION to the action to take in YYSTATE on seeing YYTOKEN. * Result R means diff --git a/data/yacc.c b/data/yacc.c index 7bcbd7ca..736a9b20 100644 --- a/data/yacc.c +++ b/data/yacc.c @@ -404,24 +404,24 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ -# define YY_(msgid) msgid +# define YY_(Msgid) Msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) +# define YYUSE(E) ((void) (E)) #else -# define YYUSE(e) /* empty */ +# define YYUSE(E) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint -# define YYID(n) (n) +# define YYID(N) (N) #else ]b4_c_function_def([YYID], [static int], [[int yyi], [yyi]])[ { @@ -680,11 +680,11 @@ static const ]b4_int_type_for([b4_table])[ yytable[] = ]b4_table[ }; -#define yypact_value_is_default(yystate) \ - ]b4_table_value_equals([[pact]], [[yystate]], [b4_pact_ninf])[ +#define yypact_value_is_default(Yystate) \ + ]b4_table_value_equals([[pact]], [[Yystate]], [b4_pact_ninf])[ -#define yytable_value_is_error(yytable_value) \ - ]b4_table_value_equals([[table]], [[yytable_value]], [b4_table_ninf])[ +#define yytable_value_is_error(Yytable_value) \ + ]b4_table_value_equals([[table]], [[Yytable_value]], [b4_table_ninf])[ static const ]b4_int_type_for([b4_check])[ yycheck[] = { From e365aa4c3de212d7c6ea8d9b7d142ca3be2db6cd Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 5 Oct 2012 10:55:11 -0700 Subject: [PATCH 15/18] yacc.c: initialize yylval in pure-parser mode See http://lists.gnu.org/archive/html/bison-patches/2012-08/msg00024.html (spreading over September and October). * data/yacc.c (YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN) (YY_IGNORE_MAYBE_UNINITIALIZED_END, YYLVAL_INITIALIZE): New macros. Use them to suppress an unwanted GCC diagnostic. --- data/yacc.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/data/yacc.c b/data/yacc.c index 736a9b20..faf1d786 100644 --- a/data/yacc.c +++ b/data/yacc.c @@ -170,6 +170,28 @@ m4_define([b4_declare_scanner_communication_variables], [[ /* The lookahead symbol. */ int yychar; +]b4_pure_if([[ +#if defined __GNUC__ && (4 < __GNUC__ + (6 <= __GNUC_MINOR__)) +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +static YYSTYPE yyval_default; +# define YYLVAL_INITIALIZE() (yylval = yyval_default) +#endif]])[ +#ifndef YYLVAL_INITIALIZE +# define YYLVAL_INITIALIZE() +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif + /* The semantic value of the lookahead symbol. */ YYSTYPE yylval;]b4_locations_if([[ @@ -1563,8 +1585,9 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[ The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs;]b4_locations_if([[ - yylsp = yyls; + yylsp = yyls;]])[ + YYLVAL_INITIALIZE ();]b4_locations_if([[ #if defined ]b4_api_PREFIX[LTYPE_IS_TRIVIAL && ]b4_api_PREFIX[LTYPE_IS_TRIVIAL /* Initialize the default location before parsing starts. */ yylloc.first_line = yylloc.last_line = ]b4_location_initial_line[; @@ -1750,7 +1773,9 @@ yyread_pushed_token:]])[ YY_LAC_DISCARD ("shift");]])[ yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END ]b4_locations_if([ *++yylsp = yylloc;])[ goto yynewstate; @@ -1970,7 +1995,9 @@ yyerrlab1: current lookahead token, the shift below will for sure. */ YY_LAC_DISCARD ("error recovery");]])[ + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END ]b4_locations_if([[ yyerror_range[2] = yylloc; /* Using YYLLOC is tempting, but would change the location of From 321d3e35d52c3a118e4fd574ec63e667c330a40e Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Mon, 8 Oct 2012 09:02:09 +0200 Subject: [PATCH 16/18] tests: no longer disable -O compiler options Tests are running without -O since f377f69fec28013c79db4efe12bbb9d48987fb2c because some warnings (about yylval not being initialized) show only when GCC is given -O2. The previous patch fixes the warnings. Run the test suite with compiler options unmodified. * tests/atlocal.in (O0CFLAGS, O0CXXFLAGS): Remove, use CFLAGS and CXXFLAGS. --- NEWS | 13 +++++++++++++ tests/atlocal.in | 11 ++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 81afe649..2d4143ad 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,19 @@ GNU Bison NEWS This feature is somewhat experimental. User feedback would be appreciated. +** Fix compiler warnings in the generated parser (yacc.c) + + The compilation of pure parsers (%define api.pure) can trigger GCC + warnings such as: + + input.c: In function 'yyparse': + input.c:1503:12: warning: 'yylval' may be used uninitialized in this + function [-Wmaybe-uninitialized] + *++yyvsp = yylval; + ^ + + This is now fixed; pragmas to avoid these warnings are no longer needed. + * Noteworthy changes in release 2.6.2 (2012-08-03) [stable] ** Bug fixes diff --git a/tests/atlocal.in b/tests/atlocal.in index 9a2d19f0..2f682592 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -29,16 +29,10 @@ CPPFLAGS="-I$abs_top_builddir/lib @CPPFLAGS@" # Is the compiler GCC? GCC='@GCC@' -# We want no optimization, as they uncover warnings (therefore, -# failures) about uninitialized variables in the test suite. FIXME: -# fix the warnings, not the flags. - O0CFLAGS=`echo '@CFLAGS@' | sed 's/-O[0-9s] *//g'` -O0CXXFLAGS=`echo '@CXXFLAGS@' | sed 's/-O[0-9s] *//g'` - # Sometimes a test group needs to ignore gcc warnings, so it locally # sets CFLAGS to this. - NO_WERROR_CFLAGS="$O0CFLAGS @WARN_CFLAGS@ @WARN_CFLAGS_TEST@" -NO_WERROR_CXXFLAGS="$O0CXXFLAGS @WARN_CXXFLAGS@ @WARN_CXXFLAGS_TEST@" + NO_WERROR_CFLAGS='@CFLAGS@ @WARN_CFLAGS@ @WARN_CFLAGS_TEST@' +NO_WERROR_CXXFLAGS='@CXXFLAGS@ @WARN_CXXFLAGS@ @WARN_CXXFLAGS_TEST@' # But most of the time, we want -Werror. CFLAGS="$NO_WERROR_CFLAGS @WERROR_CFLAGS@" @@ -51,7 +45,6 @@ BISON_CXX_WORKS='@BISON_CXX_WORKS@' if "$at_arg_compile_c_with_cxx"; then CC_IS_CXX=1 CC=$CXX - O0CFLAGS=$O0CXXFLAGS NO_WERROR_CFLAGS=$NO_WERROR_CXXFLAGS CFLAGS=$CXXFLAGS else From 34076080cd70857ca371ed8038d81acfe3f68bca Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Mon, 8 Oct 2012 09:17:20 +0200 Subject: [PATCH 17/18] warnings: avoid warnings from clang Fix the following warning parse-gram.c:2078:14: error: equality comparison with extraneous parentheses [-Werror,-Wparentheses-equality] if (((yyn) == (-91))) ~~~~~~^~~~~~~~ parse-gram.c:2078:14: note: remove extraneous parentheses around the comparison to silence this warning if (((yyn) == (-91))) ~ ^ ~ parse-gram.c:2078:14: note: use '=' to turn this equality comparison into an assignment if (((yyn) == (-91))) ^~ = 1 error generated. and the following one: input.cc:740:1: error: function declared 'noreturn' should not return [-Werror,-Winvalid-noreturn] static void yyMemoryExhausted (yyGLRStack* yystackp) __attribute__ ((__noreturn__)); static void yyMemoryExhausted (yyGLRStack* yystackp) { YYLONGJMP (yystackp->yyexception_buffer, 2); } ^ 1 warning and 1 error generated. This is Apple clang version 3.1 (tags/Apple/clang-318.0.61). * data/c.m4 (b4_table_value_equals): Use (!!(A == B)) instead of (A == B) to avoid this warning. Any reasonable compiler should generate the same code. * src/uniqstr.h (UNIQSTR_EQ): Likewise. * data/glr.c (LONGJMP): abort after longjmp to pacify clang. --- data/c.m4 | 2 +- data/glr.c | 3 ++- src/uniqstr.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/data/c.m4 b/data/c.m4 index fd2203eb..994d2964 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -184,7 +184,7 @@ m4_define([b4_table_value_equals], [m4_if(m4_eval($3 < m4_indir([b4_]$1[_min]) || m4_indir([b4_]$1[_max]) < $3), [1], [[YYID (0)]], - [[((]$2[) == (]$3[))]])]) + [(!!(($2) == ($3)))])]) ## ---------## diff --git a/data/glr.c b/data/glr.c index 9b8ff67c..79d6ffd0 100644 --- a/data/glr.c +++ b/data/glr.c @@ -290,7 +290,8 @@ b4_percent_code_get[]dnl # include # define YYJMP_BUF jmp_buf # define YYSETJMP(Env) setjmp (Env) -# define YYLONGJMP(Env, Val) longjmp (Env, Val) +// Pacify clang. +# define YYLONGJMP(Env, Val) (longjmp (Env, Val), YYASSERT (0)) #endif /*-----------------. diff --git a/src/uniqstr.h b/src/uniqstr.h index 913da39f..677ecc42 100644 --- a/src/uniqstr.h +++ b/src/uniqstr.h @@ -36,7 +36,7 @@ uniqstr uniqstr_vsprintf (char const *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); /* Two uniqstr values have the same value iff they are the same. */ -#define UNIQSTR_EQ(USTR1, USTR2) ((USTR1) == (USTR2)) +#define UNIQSTR_EQ(USTR1, USTR2) (!!((USTR1) == (USTR2))) /* Compare two uniqstr a la strcmp: negative for <, nul for =, and positive for >. Undefined order, relies on addresses. */ From c12c4c507deebc142ed04a734fdc3579e95d205f Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Mon, 8 Oct 2012 13:46:50 +0200 Subject: [PATCH 18/18] NEWS: warnings with clang * NEWS: here. --- NEWS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2d4143ad..1fe419f4 100644 --- a/NEWS +++ b/NEWS @@ -48,7 +48,7 @@ GNU Bison NEWS This feature is somewhat experimental. User feedback would be appreciated. -** Fix compiler warnings in the generated parser (yacc.c) +** Fix compiler warnings in the generated parser (yacc.c, glr.c) The compilation of pure parsers (%define api.pure) can trigger GCC warnings such as: @@ -61,6 +61,10 @@ GNU Bison NEWS This is now fixed; pragmas to avoid these warnings are no longer needed. + Warnings from clang ("equality comparison with extraneous parentheses" and + "function declared 'noreturn' should not return") have also been + addressed. + * Noteworthy changes in release 2.6.2 (2012-08-03) [stable] ** Bug fixes