]> git.saurik.com Git - bison.git/commitdiff
c++: variants: don't leak the lookahead in error recovery
authorAkim Demaille <akim@lrde.epita.fr>
Thu, 8 Jan 2015 10:19:57 +0000 (11:19 +0100)
committerAkim Demaille <akim@lrde.epita.fr>
Thu, 8 Jan 2015 15:07:59 +0000 (16:07 +0100)
During error recovery, when discarding the lookeahead, we don't
destroy it, which is caught by parse.assert assertions.

Reported by Antonio Silva Correia.
With an analysis and suggested patch from Michel d'Hooge.
<http://savannah.gnu.org/support/?108481>

* tests/c++.at (Variants): Strengthen the test to try syntax errors
with discarded lookahead.

data/lalr1.cc
tests/c++.at

index 9ab9421e2f799589618deea12ee66161c888a472..d3ab008bb99cd7c15ff4f2bf9d76a4fdc4d00cbb 100644 (file)
@@ -901,6 +901,7 @@ b4_dollar_popdef])[]dnl
         else if (!yyempty)
           {
             yy_destroy_ ("Error: discarding", yyla);
+            yyla.clear ();
             yyempty = true;
           }
       }
index 1aa730f126b56aeaf13cf353b03fd44399f2a8b5..30304019f7ced41305d3528d25df26598e8c63ba 100644 (file)
@@ -175,6 +175,9 @@ AT_CLEANUP
 ## Variants.  ##
 ## ---------- ##
 
+# Check that the variants are properly supported, including in error
+# recovery.
+
 # AT_TEST([DIRECTIVES])
 # ---------------------
 # Check the support of variants in C++, with the additional DIRECTIVES.
@@ -243,6 +246,7 @@ typedef std::list<std::string> strings_type;
 %token <::std::string> TEXT;
 %token <int> NUMBER;
 %token END_OF_FILE 0;
+%token COMMA ","
 
 %type <::std::string> item;
 // Using the template type to exercize its parsing.
@@ -259,13 +263,13 @@ result:
 ;
 
 list:
-  /* nothing */ { /* Generates an empty string list */ }
-| list item     { std::swap ($$,$][1); $$.push_back ($][2); }
-| list error    { std::swap ($$,$][1); }
+  item          { $$.push_back ($][1); }
+| list "," item { std::swap ($$, $][1); $$.push_back ($][3); }
+| list error    { std::swap ($$, $][1); }
 ;
 
 item:
-  TEXT          { std::swap ($$,$][1); }
+  TEXT          { std::swap ($$, $][1); }
 | NUMBER        { if ($][1 == 3) YYERROR; else $$ = to_string ($][1); }
 ;
 %%
@@ -285,30 +289,43 @@ namespace yy
                             parser::location_type* yylloc])[)]])[
   {]AT_LOCATION_IF([
     typedef parser::location_type location;])[
-    static int stage = -1;
-    ++stage;
-    if (stage == STAGE_MAX)
-      {]AT_TOKEN_CTOR_IF([[
+    // The 5 is a syntax error whose recovery requires that we discard
+    // the lookahead.  This tests a regression, see
+    // <http://savannah.gnu.org/support/?108481>.
+    static char const *input = "0,1,2,3,45,6";
+    switch (int stage = *input++)
+    {
+      case 0:]AT_TOKEN_CTOR_IF([[
         return parser::make_END_OF_FILE (]AT_LOCATION_IF([location ()])[);]],
 [AT_LOCATION_IF([
         *yylloc = location ();])[
         return parser::token::END_OF_FILE;]])[
-      }
-    else if (stage % 2)
-      {]AT_TOKEN_CTOR_IF([[
-        return parser::make_NUMBER (stage]AT_LOCATION_IF([, location ()])[);]],
-[[
-        yylval->BUILD (int, stage);]AT_LOCATION_IF([
-        *yylloc = location ();])[
-        return parser::token::NUMBER;]])[
-      }
-    else
-      {]AT_TOKEN_CTOR_IF([[
-        return parser::make_TEXT (to_string (stage)]AT_LOCATION_IF([, location ()])[);]], [[
-        yylval->BUILD (std::string, to_string (stage));]AT_LOCATION_IF([
+
+      case ',':
+        ]AT_TOKEN_CTOR_IF([[
+        return parser::make_COMMA (]AT_LOCATION_IF([location ()])[);]], [[
+]AT_LOCATION_IF([
         *yylloc = location ();])[
-        return parser::token::TEXT;]])[
-      }
+        return parser::token::COMMA;]])[
+
+      default:
+        stage = stage - '0';
+        if (stage % 2)
+         {]AT_TOKEN_CTOR_IF([[
+           return parser::make_NUMBER (stage]AT_LOCATION_IF([, location ()])[);]], [[
+           yylval->BUILD (int, stage);]AT_LOCATION_IF([
+           *yylloc = location ();])[
+           return parser::token::NUMBER;]])[
+         }
+       else
+         {]AT_TOKEN_CTOR_IF([[
+           return parser::make_TEXT (to_string (stage)]AT_LOCATION_IF([, location ()])[);]], [[
+           yylval->BUILD (std::string, to_string (stage));]AT_LOCATION_IF([
+           *yylloc = location ();])[
+           return parser::token::TEXT;]])[
+         }
+    }
+
     abort ();
   }
 }
@@ -319,7 +336,7 @@ namespace yy
 
 AT_FULL_COMPILE([list])
 AT_PARSER_CHECK([./list], 0,
-[(0, 1, 2, 4)
+[(0, 1, 2, 4, 6)
 ])
 
 AT_BISON_OPTION_POPDEFS
@@ -328,11 +345,11 @@ AT_CLEANUP
 
 AT_TEST([[%skeleton "lalr1.cc" ]])
 AT_TEST([[%skeleton "lalr1.cc" %define parse.assert]])
-AT_TEST([[%skeleton "lalr1.cc" %locations %define parse.assert]])
+AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %locations]])
 AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %code {\n#define TWO_STAGE_BUILD\n}]])
 AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define api.token.constructor]])
 AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define api.token.constructor %define api.token.prefix {TOK_}]])
-AT_TEST([[%skeleton "lalr1.cc" %locations %define parse.assert %define api.token.constructor %define api.token.prefix {TOK_}]])
+AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define api.token.constructor %define api.token.prefix {TOK_} %locations]])
 
 m4_popdef([AT_TEST])