The example given by Piotr in

http://lists.gnu.org/archive/html/bug-bison/2017-06/msg00000.html

will actually crash if parse.assert is enabled.  It does show
that something very rotten was going on, but an abort is better
than a SEGV :)

To reproduce the error, try with the attached grammar.  

Attachment: bar.yy
Description: Binary data


This shows that we should forbid the use of ‘$<foo>’ when using
(Bison) variants: the corresponding symbol was not even constructed,
because, since Bison does not know that $2 is an integer, it cannot
build the symbol before handing it over to the user action.  To see
that, have a look at the generated code:

> yyreduce:
> yylen = yyr2_[yyn];
> {
>   stack_symbol_type yylhs;
>   yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]);
>   /* Variants are always initialized to an empty instance of the
>      correct type. The default '$$ = $1' action is NOT applied
>      when using variants.  */
>   switch (yyr1_[yyn])
>     {
>     case 3: // NUMBER
>     case 5: // expr
>       yylhs.value.build< int > ();
>       break;
>       
>     default:
>       break;
>     }
>   
>   // Perform the reduction.
>   YY_REDUCE_PRINT (yyn);
>   try
>     {
>       switch (yyn)
>         {
>         case 2:
> #line 27 "bar.yy" // lalr1.cc:856
>           { yylhs.value.as< int > () = yystack_[0].value.as< int > () * 10; }
> #line 527 "bar.tab.cc" // lalr1.cc:856
>           break;
>           
>         case 3:
> #line 28 "bar.yy" // lalr1.cc:856
>           { yylhs.value.as< int > () = 20; }
> #line 533 "bar.tab.cc" // lalr1.cc:856
>           break;
>           
>         case 4:
> #line 29 "bar.yy" // lalr1.cc:856
>           {
>             std::cerr << "expr: "
>                       << yystack_[2].value.as< int > () << ' '
>                       << yystack_[1].value.as< int > () << ' '
>                       << yystack_[0].value.as< int > () << '\n';
>             yylhs.value.as< int > () = 40;
>           }
> #line 542 "bar.tab.cc" // lalr1.cc:856
>           break;
>           
>           
> #line 546 "bar.tab.cc" // lalr1.cc:856
>         default:
>           break;
>         }
>     }
>   catch (const syntax_error& yyexc)
>     {
>       error (yyexc);
>       YYERROR;
>     }
>   YY_SYMBOL_PRINT ("-> $$ =", yylhs);
>   yypop_ (yylen);
>   yylen = 0;
>   YY_STACK_PRINT ();
>   
>   // Shift the result of the reduction.
>   yypush_ (YY_NULLPTR, yylhs);
> }
> goto yynewstate;


When using a typed midrule, it works properly.


commit 4410084223ae6ea7c0d4808599786078d83fac0b
Author: Akim Demaille <akim.demai...@gmail.com>
Date:   Thu Aug 9 07:33:23 2018 +0200

    c++: variant: add more assertions
    
    * data/variant.hh (variant::as): Check yytypeid_ before
    checking *yytypeid_.

diff --git a/data/variant.hh b/data/variant.hh
index 7a6fbfb9..41ed84ab 100644
--- a/data/variant.hh
+++ b/data/variant.hh
@@ -140,6 +140,7 @@ m4_define([b4_variant_define],
     T&
     as ()
     {]b4_parse_assert_if([
+      YYASSERT (yytypeid_);
       YYASSERT (*yytypeid_ == typeid (T));
       YYASSERT (sizeof (T) <= S);])[
       return *yyas_<T> ();
@@ -150,6 +151,7 @@ m4_define([b4_variant_define],
     const T&
     as () const
     {]b4_parse_assert_if([
+      YYASSERT (yytypeid_);
       YYASSERT (*yytypeid_ == typeid (T));
       YYASSERT (sizeof (T) <= S);])[
       return *yyas_<T> ();

Reply via email to