From dc8e535c37dffc57e5bc9f97108db6f5eb7a77ce Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Mon, 28 Jan 2013 16:05:09 +0100 Subject: [PATCH] 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. --- tests/c++.at | 85 +++++++++++++++++++++++++++++++++++++++------------------- tests/local.at | 11 +++++--- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/tests/c++.at b/tests/c++.at index 21f567f..b72954a 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -589,15 +589,19 @@ AT_CLEANUP ## 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]], [[%skeleton "lalr1.cc" %debug %error-verbose - +$1 %code requires { #include @@ -648,6 +652,13 @@ AT_DATA_GRAMMAR([[input.yy]], log (this, "Object::Object"); } + Object () + : val ('?') + { + instances.push_back(this); + log (this, "Object::Object"); + } + ~Object () { instances.remove(this); @@ -666,17 +677,21 @@ AT_DATA_GRAMMAR([[input.yy]], static char const *input; } -%union +]AT_VARIANT_IF([[ +%printer { - Object *obj; -} + yyo << &$$ << " '" << $$.val << '\''; + if ($$.val == 'p') + throw std::runtime_error ("printer"); +} ; -%initial-action +%token 'a' 'E' 'e' 'p' 'R' 's' 'T' +%type list item +]], [[ +%union { - if (strchr (input, 'i')) - throw std::runtime_error ("initial-action"); + Object *obj; } - %destructor { delete $$; } ; %printer { @@ -687,27 +702,35 @@ AT_DATA_GRAMMAR([[input.yy]], %token 'a' 'E' 'e' 'p' 'R' 's' 'T' %type 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: - item { $$ = $1; } -| item list { $$ = $1; delete $2; } // Right recursion to load the stack. + item { $][$ = $][1; } + // Right recursion to load the stack. +| item list { $][$ = $][1; ]AT_VARIANT_IF([], [delete $][2]; )[} ; item: - 'a' { $$ = $1; } -| 'e' { YYUSE ($$); YYUSE($1); error ("syntax error"); } + 'a' { $$][ = $][1; } +| 'e' { YYUSE ($][$); YYUSE($][1); error ("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; } +| 'E' 'a' { YYUSE($][1); $][$ = $][2; } +| 'R' { $][$ = YY_NULL; ]AT_VARIANT_IF([], [delete $][1]; )[YYERROR; } +| 'p' { $][$ = $][1; } +| 's' { $][$ = $][1; throw std::runtime_error ("reduction"); } +| 'T' { $][$ = YY_NULL; ]AT_VARIANT_IF([], [delete $][1]; )[YYABORT; } +| error { $][$ = YY_NULL; yyerrok; } ; %% @@ -724,13 +747,13 @@ yylex (yy::parser::semantic_type *lvalp) // 'T': call YYABORT in the action switch (int res = *input++) { - case 'l': - throw std::runtime_error ("yylex"); - default: - lvalp->obj = new Object (res); - // Fall through. - case 0: - return res; + case 'l': + throw std::runtime_error ("yylex"); + default: + lvalp]AT_VARIANT_IF([->build (res)], [->obj = new Object (res)])[; + // Fall through. + case 0: + return res; } } @@ -815,6 +838,12 @@ AT_PARSER_CHECK([[./input aaaaR]], [[0]]) AT_BISON_OPTION_POPDEFS AT_CLEANUP +]) + +AT_TEST +AT_TEST([%define api.value.type variant]) + +m4_popdef([AT_TEST]) ## ------------------------------------ ## ## C++ GLR parser identifier shadowing ## diff --git a/tests/local.at b/tests/local.at index 103887d..74eea7e 100644 --- a/tests/local.at +++ b/tests/local.at @@ -186,10 +186,12 @@ m4_pushdef([AT_NAME_PREFIX], [m4_bregexp([$3], [\(%define api\.\(namespace\|prefix\)\|%name-prefix\) "\([^""]*\)"], [\3])], [yy])]) 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_bmatch([$3], [%define api.token.prefix ".*"], - [m4_bregexp([$3], [%define api.token.prefix "\(.*\)"], [\1])])]) +[m4_bmatch([$3], [%define api\.token\.prefix ".*"], + [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_bmatch([$3], [%define api\.prefix ".*"], [m4_bregexp([$3], [%define api\.prefix "\([^""]*\)"], [\1])], @@ -203,7 +205,7 @@ m4_pushdef([AT_API_PREFIX], m4_pushdef([AT_YYERROR_ARG_LOC_IF], [AT_LOCATION_IF([AT_PURE_IF([m4_bmatch([$3], m4_quote(m4_join([\|], - [%define api.pure "?full"?], + [%define api\.pure "?full"?], [%glr-parser], [%parse-param], [%skeleton "?glr.c"?])), @@ -288,6 +290,7 @@ m4_popdef([AT_YYERROR_SEES_LOC_IF]) m4_popdef([AT_YYERROR_ARG_LOC_IF]) m4_popdef([AT_API_PREFIX]) m4_popdef([AT_API_prefix]) +m4_popdef([AT_VARIANT_IF]) m4_popdef([AT_TOKEN_PREFIX]) m4_popdef([AT_TOKEN_CTOR_IF]) m4_popdef([AT_NAME_PREFIX]) -- 2.7.4