tests: check that using variants is exception safe

* tests/local.at: (Slightly) improve the regexp by escaping '.'
when it denotes a point.
(AT_VARIANT_IF): New.
* tests/c++.at (Exception Safety): Run it for variants too.
This commit is contained in:
Akim Demaille
2013-01-28 16:05:09 +01:00
parent 66fb016e1d
commit dc8e535c37
2 changed files with 64 additions and 32 deletions

View File

@@ -589,15 +589,19 @@ AT_CLEANUP
## Exception safety. ## ## Exception safety. ##
## ------------------ ## ## ------------------ ##
AT_SETUP([[Exception safety]]) # AT_TEST([BISON-DIRECTIVES])
# ---------------------------
# Check that no object is leaked when exceptions are thrown.
m4_pushdef([AT_TEST],
[AT_SETUP([[Exception safety $1]])
AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc" $1])
AT_DATA_GRAMMAR([[input.yy]], AT_DATA_GRAMMAR([[input.yy]],
[[%skeleton "lalr1.cc" [[%skeleton "lalr1.cc"
%debug %debug
%error-verbose %error-verbose
$1
%code requires %code requires
{ {
#include <cassert> #include <cassert>
@@ -648,6 +652,13 @@ AT_DATA_GRAMMAR([[input.yy]],
log (this, "Object::Object"); log (this, "Object::Object");
} }
Object ()
: val ('?')
{
instances.push_back(this);
log (this, "Object::Object");
}
~Object () ~Object ()
{ {
instances.remove(this); instances.remove(this);
@@ -666,17 +677,21 @@ AT_DATA_GRAMMAR([[input.yy]],
static char const *input; static char const *input;
} }
]AT_VARIANT_IF([[
%printer
{
yyo << &$$ << " '" << $$.val << '\'';
if ($$.val == 'p')
throw std::runtime_error ("printer");
} <Object>;
%token <Object> 'a' 'E' 'e' 'p' 'R' 's' 'T'
%type <Object> list item
]], [[
%union %union
{ {
Object *obj; Object *obj;
} }
%initial-action
{
if (strchr (input, 'i'))
throw std::runtime_error ("initial-action");
}
%destructor { delete $$; } <obj>; %destructor { delete $$; } <obj>;
%printer %printer
{ {
@@ -687,27 +702,35 @@ AT_DATA_GRAMMAR([[input.yy]],
%token <obj> 'a' 'E' 'e' 'p' 'R' 's' 'T' %token <obj> 'a' 'E' 'e' 'p' 'R' 's' 'T'
%type <obj> list item %type <obj> list item
]])[
%initial-action
{
if (strchr (input, 'i'))
throw std::runtime_error ("initial-action");
}
%% %%
start: list { delete $1; }; start: list {]AT_VARIANT_IF([], [ delete $][1]; )[};
list: list:
item { $$ = $1; } item { $][$ = $][1; }
| item list { $$ = $1; delete $2; } // Right recursion to load the stack. // Right recursion to load the stack.
| item list { $][$ = $][1; ]AT_VARIANT_IF([], [delete $][2]; )[}
; ;
item: item:
'a' { $$ = $1; } 'a' { $$][ = $][1; }
| 'e' { YYUSE ($$); YYUSE($1); error ("syntax error"); } | 'e' { YYUSE ($][$); YYUSE($][1); error ("syntax error"); }
// Not just 'E', otherwise we reduce when 'E' is the lookahead, and // Not just 'E', otherwise we reduce when 'E' is the lookahead, and
// then the stack is emptied, defeating the point of the test. // then the stack is emptied, defeating the point of the test.
| 'E' 'a' { YYUSE($1); $$ = $2; } | 'E' 'a' { YYUSE($][1); $][$ = $][2; }
| 'R' { $$ = YY_NULL; delete $1; YYERROR; } | 'R' { $][$ = YY_NULL; ]AT_VARIANT_IF([], [delete $][1]; )[YYERROR; }
| 'p' { $$ = $1; } | 'p' { $][$ = $][1; }
| 's' { $$ = $1; throw std::runtime_error ("reduction"); } | 's' { $][$ = $][1; throw std::runtime_error ("reduction"); }
| 'T' { $$ = YY_NULL; delete $1; YYABORT; } | 'T' { $][$ = YY_NULL; ]AT_VARIANT_IF([], [delete $][1]; )[YYABORT; }
| error { $$ = YY_NULL; yyerrok; } | error { $][$ = YY_NULL; yyerrok; }
; ;
%% %%
@@ -724,13 +747,13 @@ yylex (yy::parser::semantic_type *lvalp)
// 'T': call YYABORT in the action // 'T': call YYABORT in the action
switch (int res = *input++) switch (int res = *input++)
{ {
case 'l': case 'l':
throw std::runtime_error ("yylex"); throw std::runtime_error ("yylex");
default: default:
lvalp->obj = new Object (res); lvalp]AT_VARIANT_IF([->build (res)], [->obj = new Object (res)])[;
// Fall through. // Fall through.
case 0: case 0:
return res; return res;
} }
} }
@@ -815,6 +838,12 @@ AT_PARSER_CHECK([[./input aaaaR]], [[0]])
AT_BISON_OPTION_POPDEFS AT_BISON_OPTION_POPDEFS
AT_CLEANUP AT_CLEANUP
])
AT_TEST
AT_TEST([%define api.value.type variant])
m4_popdef([AT_TEST])
## ------------------------------------ ## ## ------------------------------------ ##
## C++ GLR parser identifier shadowing ## ## C++ GLR parser identifier shadowing ##

View File

@@ -186,10 +186,12 @@ m4_pushdef([AT_NAME_PREFIX],
[m4_bregexp([$3], [\(%define api\.\(namespace\|prefix\)\|%name-prefix\) "\([^""]*\)"], [\3])], [m4_bregexp([$3], [\(%define api\.\(namespace\|prefix\)\|%name-prefix\) "\([^""]*\)"], [\3])],
[yy])]) [yy])])
m4_pushdef([AT_TOKEN_CTOR_IF], m4_pushdef([AT_TOKEN_CTOR_IF],
[m4_bmatch([$3], [%define api.token.constructor], [$1], [$2])]) [m4_bmatch([$3], [%define api\.token\.constructor], [$1], [$2])])
m4_pushdef([AT_TOKEN_PREFIX], m4_pushdef([AT_TOKEN_PREFIX],
[m4_bmatch([$3], [%define api.token.prefix ".*"], [m4_bmatch([$3], [%define api\.token\.prefix ".*"],
[m4_bregexp([$3], [%define api.token.prefix "\(.*\)"], [\1])])]) [m4_bregexp([$3], [%define api\.token\.prefix "\(.*\)"], [\1])])])
m4_pushdef([AT_VARIANT_IF],
[m4_bmatch([$3], [%define api\.value\.type "?variant"?], [$1], [$2])])
m4_pushdef([AT_API_prefix], m4_pushdef([AT_API_prefix],
[m4_bmatch([$3], [%define api\.prefix ".*"], [m4_bmatch([$3], [%define api\.prefix ".*"],
[m4_bregexp([$3], [%define api\.prefix "\([^""]*\)"], [\1])], [m4_bregexp([$3], [%define api\.prefix "\([^""]*\)"], [\1])],
@@ -203,7 +205,7 @@ m4_pushdef([AT_API_PREFIX],
m4_pushdef([AT_YYERROR_ARG_LOC_IF], m4_pushdef([AT_YYERROR_ARG_LOC_IF],
[AT_LOCATION_IF([AT_PURE_IF([m4_bmatch([$3], [AT_LOCATION_IF([AT_PURE_IF([m4_bmatch([$3],
m4_quote(m4_join([\|], m4_quote(m4_join([\|],
[%define api.pure "?full"?], [%define api\.pure "?full"?],
[%glr-parser], [%glr-parser],
[%parse-param], [%parse-param],
[%skeleton "?glr.c"?])), [%skeleton "?glr.c"?])),
@@ -288,6 +290,7 @@ m4_popdef([AT_YYERROR_SEES_LOC_IF])
m4_popdef([AT_YYERROR_ARG_LOC_IF]) m4_popdef([AT_YYERROR_ARG_LOC_IF])
m4_popdef([AT_API_PREFIX]) m4_popdef([AT_API_PREFIX])
m4_popdef([AT_API_prefix]) m4_popdef([AT_API_prefix])
m4_popdef([AT_VARIANT_IF])
m4_popdef([AT_TOKEN_PREFIX]) m4_popdef([AT_TOKEN_PREFIX])
m4_popdef([AT_TOKEN_CTOR_IF]) m4_popdef([AT_TOKEN_CTOR_IF])
m4_popdef([AT_NAME_PREFIX]) m4_popdef([AT_NAME_PREFIX])