summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkim Demaille <akim@lrde.epita.fr>2013-11-15 09:43:01 +0100
committerAkim Demaille <akim@lrde.epita.fr>2013-11-15 10:13:47 +0100
commit5cf6e669af1b6133e1ec8cb66a5bd5754ee437c2 (patch)
tree3b7a5f541e463545bed7ae4acdec88cb28a540a4
parent16bb9f1647c4666d8f4e55c672e0ee5010df9e51 (diff)
downloadbison-5cf6e669af1b6133e1ec8cb66a5bd5754ee437c2.tar.gz
tests: check $$'s destruction with variant, YYERROR, and no error recovery
When variant are enabled, the yylhs variable (the left-hand side of the rule being reduced, i.e. $$ and @$) is explicitly destroyed when YYERROR is called. This is because before running the user code, $$ is initialized, so that the user can properly use it. However, when quitting yyparse, yylhs is also reclaimed by the C++ compiler: the variable goes out of scope. This was not detected by the test suite because (i) the Object tracker was too weak, and (ii) the problem does not show when there is error recovery. Reported by Paolo Simone Gasparello. <http://lists.gnu.org/archive/html/bug-bison/2013-10/msg00003.html> * tests/c++.at (Exception safety): Improve the objects logger to make sure that we never destroy twice an object. Also track copy-constructors. Use a set instead of a list. Display the logs before running the function body, this is more useful in case of failure. Generalize to track with and without error recovery.
-rw-r--r--THANKS1
-rw-r--r--tests/c++.at58
2 files changed, 38 insertions, 21 deletions
diff --git a/THANKS b/THANKS
index 9b7a8963..ebadb447 100644
--- a/THANKS
+++ b/THANKS
@@ -96,6 +96,7 @@ 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
+Paolo Simone Gasparello djgaspa@gmail.com
Pascal Bart pascal.bart@epita.fr
Paul Eggert eggert@cs.ucla.edu
Paul Hilfinger Hilfinger@CS.Berkeley.EDU
diff --git a/tests/c++.at b/tests/c++.at
index 14a001a4..355e6247 100644
--- a/tests/c++.at
+++ b/tests/c++.at
@@ -649,14 +649,18 @@ AT_CLEANUP
## Exception safety. ##
## ------------------ ##
-# AT_TEST([BISON-DIRECTIVES])
-# ---------------------------
+# AT_TEST([BISON-DIRECTIVES = ''], [WITH-RECOVERY = "with"])
+# ----------------------------------------------------------
# Check that no object is leaked when exceptions are thrown.
+# WITH-RECOVERY = "with" or "without".
m4_pushdef([AT_TEST],
-[AT_SETUP([[Exception safety $1]])
+[AT_SETUP([[Exception safety $2 error recovery $1]])
AT_SKIP_IF_EXCEPTION_SUPPORT_IS_POOR
+m4_if([$1], [], [],
+ [m4_if([$2], [without], [AT_XFAIL_IF([true])])])
+
AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc" $1])
AT_DATA_GRAMMAR([[input.yy]],
@@ -669,43 +673,53 @@ $1
#include <cassert>
#include <cstdlib> // size_t and getenv.
#include <iostream>
- #include <list>
+ #include <set>
bool debug = false;
- /// A class that counts its number of instances.
+ /// A class that tracks its instances.
struct Object
{
char val;
- Object (char v)
- : val (v)
+ Object ()
+ : val ('?')
{
- Object::instances.push_back(this);
log (this, "Object::Object");
+ Object::instances.insert (this);
}
- Object ()
- : val ('?')
+ Object (const Object& that)
+ : val (that.val)
{
- Object::instances.push_back(this);
log (this, "Object::Object");
+ Object::instances.insert (this);
}
- Object& operator= (char v)
+ Object (char v)
+ : val (v)
{
- val = v;
- return *this;
+ log (this, "Object::Object");
+ Object::instances.insert (this);
}
~Object ()
{
- Object::instances.remove (this);
log (this, "Object::~Object");
+ objects::const_iterator i = instances.find (this);
+ // Make sure this object is alive.
+ assert (i != instances.end ());
+ Object::instances.erase (i);
+ }
+
+ Object& operator= (char v)
+ {
+ val = v;
+ return *this;
}
// Static part.
- typedef std::list<const Object*> objects;
+ typedef std::set<const Object*> objects;
static objects instances;
static bool
@@ -800,7 +814,8 @@ item:
| 'p' { $$ = $][1; }
| 's' { $$ = $][1; throw std::runtime_error ("reduction"); }
| 'T' { ]AT_VARIANT_IF([], [$$ = YY_NULLPTR; delete $][1]; )[YYABORT; }
-| error { ]AT_VARIANT_IF([], [$][$ = YY_NULLPTR; ])[yyerrok; }
+]m4_if([$2], [with],
+[[| error { $$ = ]AT_VARIANT_IF([], [new ])[Object ('R'); yyerrok; }]])[
;
%%
@@ -903,16 +918,17 @@ AT_PARSER_CHECK([[./input aaaaE]], [[2]], [[]],
AT_PARSER_CHECK([[./input aaaaT]], [[1]])
-# There is error-recovery, so exit success.
-AT_PARSER_CHECK([[./input aaaaR]], [[0]])
+AT_PARSER_CHECK([[./input aaaaR]], [m4_if([$2], [with], [0], [1])])
AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])
-AT_TEST
-AT_TEST([%define api.value.type variant])
+AT_TEST([], [with])
+AT_TEST([], [without])
+AT_TEST([%define api.value.type variant], [with])
+AT_TEST([%define api.value.type variant], [without])
m4_popdef([AT_TEST])