]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-106905: Use separate structs to track recursion depth in each PyAST_mod2obj call...
authorYilei Yang <yileiyang@google.com>
Mon, 25 Dec 2023 17:36:59 +0000 (09:36 -0800)
committerGitHub <noreply@github.com>
Mon, 25 Dec 2023 17:36:59 +0000 (19:36 +0200)
Co-authored-by: Gregory P. Smith [Google LLC] <greg@krypto.org>
Include/internal/pycore_ast_state.h
Misc/NEWS.d/next/Core and Builtins/2023-12-13-11-45-53.gh-issue-106905.5dslTN.rst [new file with mode: 0644]
Parser/asdl_c.py
Python/Python-ast.c

index 6ffd30aca7b11b7c3c20e52af208b5d7b75735e5..f1b1786264803bee73319f22da988ae498c445f5 100644 (file)
@@ -16,8 +16,6 @@ extern "C" {
 struct ast_state {
     _PyOnceFlag once;
     int finalized;
-    int recursion_depth;
-    int recursion_limit;
     PyObject *AST_type;
     PyObject *Add_singleton;
     PyObject *Add_type;
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-13-11-45-53.gh-issue-106905.5dslTN.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-13-11-45-53.gh-issue-106905.5dslTN.rst
new file mode 100644 (file)
index 0000000..e3a772f
--- /dev/null
@@ -0,0 +1,7 @@
+Use per AST-parser state rather than global state to track recursion depth
+within the AST parser to prevent potential race condition due to
+simultaneous parsing.
+
+The issue primarily showed up in 3.11 by multithreaded users of
+:func:`ast.parse`.  In 3.12 a change to when garbage collection can be
+triggered prevented the race condition from occurring.
index c9bf08ed2e0f6d26e03a22edcc194d8da492e89b..4bb337349748cf7b3c9318edb599726b234526ee 100755 (executable)
@@ -731,7 +731,7 @@ class SequenceConstructorVisitor(EmitVisitor):
 class PyTypesDeclareVisitor(PickleVisitor):
 
     def visitProduct(self, prod, name):
-        self.emit("static PyObject* ast2obj_%s(struct ast_state *state, void*);" % name, 0)
+        self.emit("static PyObject* ast2obj_%s(struct ast_state *state, struct validator *vstate, void*);" % name, 0)
         if prod.attributes:
             self.emit("static const char * const %s_attributes[] = {" % name, 0)
             for a in prod.attributes:
@@ -752,7 +752,7 @@ class PyTypesDeclareVisitor(PickleVisitor):
         ptype = "void*"
         if is_simple(sum):
             ptype = get_c_type(name)
-        self.emit("static PyObject* ast2obj_%s(struct ast_state *state, %s);" % (name, ptype), 0)
+        self.emit("static PyObject* ast2obj_%s(struct ast_state *state, struct validator *vstate, %s);" % (name, ptype), 0)
         for t in sum.types:
             self.visitConstructor(t, name)
 
@@ -984,7 +984,8 @@ add_attributes(struct ast_state *state, PyObject *type, const char * const *attr
 
 /* Conversion AST -> Python */
 
-static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject* (*func)(struct ast_state *state, void*))
+static PyObject* ast2obj_list(struct ast_state *state, struct validator *vstate, asdl_seq *seq,
+                              PyObject* (*func)(struct ast_state *state, struct validator *vstate, void*))
 {
     Py_ssize_t i, n = asdl_seq_LEN(seq);
     PyObject *result = PyList_New(n);
@@ -992,7 +993,7 @@ static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject*
     if (!result)
         return NULL;
     for (i = 0; i < n; i++) {
-        value = func(state, asdl_seq_GET_UNTYPED(seq, i));
+        value = func(state, vstate, asdl_seq_GET_UNTYPED(seq, i));
         if (!value) {
             Py_DECREF(result);
             return NULL;
@@ -1002,7 +1003,7 @@ static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject*
     return result;
 }
 
-static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), void *o)
+static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), struct validator *Py_UNUSED(vstate), void *o)
 {
     PyObject *op = (PyObject*)o;
     if (!op) {
@@ -1014,7 +1015,7 @@ static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), void *o)
 #define ast2obj_identifier ast2obj_object
 #define ast2obj_string ast2obj_object
 
-static PyObject* ast2obj_int(struct ast_state *Py_UNUSED(state), long b)
+static PyObject* ast2obj_int(struct ast_state *Py_UNUSED(state), struct validator *Py_UNUSED(vstate), long b)
 {
     return PyLong_FromLong(b);
 }
@@ -1116,8 +1117,6 @@ static int add_ast_fields(struct ast_state *state)
         for dfn in mod.dfns:
             self.visit(dfn)
         self.file.write(textwrap.dedent('''
-                state->recursion_depth = 0;
-                state->recursion_limit = 0;
                 return 0;
             }
         '''))
@@ -1260,7 +1259,7 @@ class ObjVisitor(PickleVisitor):
     def func_begin(self, name):
         ctype = get_c_type(name)
         self.emit("PyObject*", 0)
-        self.emit("ast2obj_%s(struct ast_state *state, void* _o)" % (name), 0)
+        self.emit("ast2obj_%s(struct ast_state *state, struct validator *vstate, void* _o)" % (name), 0)
         self.emit("{", 0)
         self.emit("%s o = (%s)_o;" % (ctype, ctype), 1)
         self.emit("PyObject *result = NULL, *value = NULL;", 1)
@@ -1268,17 +1267,17 @@ class ObjVisitor(PickleVisitor):
         self.emit('if (!o) {', 1)
         self.emit("Py_RETURN_NONE;", 2)
         self.emit("}", 1)
-        self.emit("if (++state->recursion_depth > state->recursion_limit) {", 1)
+        self.emit("if (++vstate->recursion_depth > vstate->recursion_limit) {", 1)
         self.emit("PyErr_SetString(PyExc_RecursionError,", 2)
         self.emit('"maximum recursion depth exceeded during ast construction");', 3)
         self.emit("return NULL;", 2)
         self.emit("}", 1)
 
     def func_end(self):
-        self.emit("state->recursion_depth--;", 1)
+        self.emit("vstate->recursion_depth--;", 1)
         self.emit("return result;", 1)
         self.emit("failed:", 0)
-        self.emit("state->recursion_depth--;", 1)
+        self.emit("vstate->recursion_depth--;", 1)
         self.emit("Py_XDECREF(value);", 1)
         self.emit("Py_XDECREF(result);", 1)
         self.emit("return NULL;", 1)
@@ -1296,7 +1295,7 @@ class ObjVisitor(PickleVisitor):
             self.visitConstructor(t, i + 1, name)
         self.emit("}", 1)
         for a in sum.attributes:
-            self.emit("value = ast2obj_%s(state, o->%s);" % (a.type, a.name), 1)
+            self.emit("value = ast2obj_%s(state, vstate, o->%s);" % (a.type, a.name), 1)
             self.emit("if (!value) goto failed;", 1)
             self.emit('if (PyObject_SetAttr(result, state->%s, value) < 0)' % a.name, 1)
             self.emit('goto failed;', 2)
@@ -1304,7 +1303,7 @@ class ObjVisitor(PickleVisitor):
         self.func_end()
 
     def simpleSum(self, sum, name):
-        self.emit("PyObject* ast2obj_%s(struct ast_state *state, %s_ty o)" % (name, name), 0)
+        self.emit("PyObject* ast2obj_%s(struct ast_state *state, struct validator *vstate, %s_ty o)" % (name, name), 0)
         self.emit("{", 0)
         self.emit("switch(o) {", 1)
         for t in sum.types:
@@ -1322,7 +1321,7 @@ class ObjVisitor(PickleVisitor):
         for field in prod.fields:
             self.visitField(field, name, 1, True)
         for a in prod.attributes:
-            self.emit("value = ast2obj_%s(state, o->%s);" % (a.type, a.name), 1)
+            self.emit("value = ast2obj_%s(state, vstate, o->%s);" % (a.type, a.name), 1)
             self.emit("if (!value) goto failed;", 1)
             self.emit("if (PyObject_SetAttr(result, state->%s, value) < 0)" % a.name, 1)
             self.emit('goto failed;', 2)
@@ -1363,7 +1362,7 @@ class ObjVisitor(PickleVisitor):
                 self.emit("for(i = 0; i < n; i++)", depth+1)
                 # This cannot fail, so no need for error handling
                 self.emit(
-                    "PyList_SET_ITEM(value, i, ast2obj_{0}(state, ({0}_ty)asdl_seq_GET({1}, i)));".format(
+                    "PyList_SET_ITEM(value, i, ast2obj_{0}(state, vstate, ({0}_ty)asdl_seq_GET({1}, i)));".format(
                         field.type,
                         value
                     ),
@@ -1372,9 +1371,9 @@ class ObjVisitor(PickleVisitor):
                 )
                 self.emit("}", depth)
             else:
-                self.emit("value = ast2obj_list(state, (asdl_seq*)%s, ast2obj_%s);" % (value, field.type), depth)
+                self.emit("value = ast2obj_list(state, vstate, (asdl_seq*)%s, ast2obj_%s);" % (value, field.type), depth)
         else:
-            self.emit("value = ast2obj_%s(state, %s);" % (field.type, value), depth, reflow=False)
+            self.emit("value = ast2obj_%s(state, vstate, %s);" % (field.type, value), depth, reflow=False)
 
 
 class PartingShots(StaticVisitor):
@@ -1394,18 +1393,19 @@ PyObject* PyAST_mod2obj(mod_ty t)
     if (!tstate) {
         return NULL;
     }
-    state->recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
+    struct validator vstate;
+    vstate.recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
     int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
     starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
-    state->recursion_depth = starting_recursion_depth;
+    vstate.recursion_depth = starting_recursion_depth;
 
-    PyObject *result = ast2obj_mod(state, t);
+    PyObject *result = ast2obj_mod(state, &vstate, t);
 
     /* Check that the recursion depth counting balanced correctly */
-    if (result && state->recursion_depth != starting_recursion_depth) {
+    if (result && vstate.recursion_depth != starting_recursion_depth) {
         PyErr_Format(PyExc_SystemError,
             "AST constructor recursion depth mismatch (before=%d, after=%d)",
-            starting_recursion_depth, state->recursion_depth);
+            starting_recursion_depth, vstate.recursion_depth);
         return NULL;
     }
     return result;
@@ -1475,8 +1475,6 @@ def generate_ast_state(module_state, f):
     f.write('struct ast_state {\n')
     f.write('    _PyOnceFlag once;\n')
     f.write('    int finalized;\n')
-    f.write('    int recursion_depth;\n')
-    f.write('    int recursion_limit;\n')
     for s in module_state:
         f.write('    PyObject *' + s + ';\n')
     f.write('};')
@@ -1539,6 +1537,11 @@ def generate_module_def(mod, metadata, f, internal_h):
         #include "pycore_pystate.h"       // _PyInterpreterState_GET()
         #include <stddef.h>
 
+        struct validator {
+            int recursion_depth;            /* current recursion depth */
+            int recursion_limit;            /* recursion limit */
+        };
+
         // Forward declaration
         static int init_types(struct ast_state *state);
 
index 75dc3e156aa945c346ca528add0d9609b962d0eb..699e1c157c591caaa74362d49f92c905c863061c 100644 (file)
@@ -9,6 +9,11 @@
 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
 #include <stddef.h>
 
+struct validator {
+    int recursion_depth;            /* current recursion depth */
+    int recursion_limit;            /* recursion limit */
+};
+
 // Forward declaration
 static int init_types(struct ast_state *state);
 
@@ -383,7 +388,8 @@ GENERATE_ASDL_SEQ_CONSTRUCTOR(pattern, pattern_ty)
 GENERATE_ASDL_SEQ_CONSTRUCTOR(type_ignore, type_ignore_ty)
 GENERATE_ASDL_SEQ_CONSTRUCTOR(type_param, type_param_ty)
 
-static PyObject* ast2obj_mod(struct ast_state *state, void*);
+static PyObject* ast2obj_mod(struct ast_state *state, struct validator *vstate,
+                             void*);
 static const char * const Module_fields[]={
     "body",
     "type_ignores",
@@ -404,7 +410,8 @@ static const char * const stmt_attributes[] = {
     "end_lineno",
     "end_col_offset",
 };
-static PyObject* ast2obj_stmt(struct ast_state *state, void*);
+static PyObject* ast2obj_stmt(struct ast_state *state, struct validator
+                              *vstate, void*);
 static const char * const FunctionDef_fields[]={
     "name",
     "args",
@@ -539,7 +546,8 @@ static const char * const expr_attributes[] = {
     "end_lineno",
     "end_col_offset",
 };
-static PyObject* ast2obj_expr(struct ast_state *state, void*);
+static PyObject* ast2obj_expr(struct ast_state *state, struct validator
+                              *vstate, void*);
 static const char * const BoolOp_fields[]={
     "op",
     "values",
@@ -652,12 +660,18 @@ static const char * const Slice_fields[]={
     "upper",
     "step",
 };
-static PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty);
-static PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty);
-static PyObject* ast2obj_operator(struct ast_state *state, operator_ty);
-static PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty);
-static PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty);
-static PyObject* ast2obj_comprehension(struct ast_state *state, void*);
+static PyObject* ast2obj_expr_context(struct ast_state *state, struct validator
+                                      *vstate, expr_context_ty);
+static PyObject* ast2obj_boolop(struct ast_state *state, struct validator
+                                *vstate, boolop_ty);
+static PyObject* ast2obj_operator(struct ast_state *state, struct validator
+                                  *vstate, operator_ty);
+static PyObject* ast2obj_unaryop(struct ast_state *state, struct validator
+                                 *vstate, unaryop_ty);
+static PyObject* ast2obj_cmpop(struct ast_state *state, struct validator
+                               *vstate, cmpop_ty);
+static PyObject* ast2obj_comprehension(struct ast_state *state, struct
+                                       validator *vstate, void*);
 static const char * const comprehension_fields[]={
     "target",
     "iter",
@@ -670,13 +684,15 @@ static const char * const excepthandler_attributes[] = {
     "end_lineno",
     "end_col_offset",
 };
-static PyObject* ast2obj_excepthandler(struct ast_state *state, void*);
+static PyObject* ast2obj_excepthandler(struct ast_state *state, struct
+                                       validator *vstate, void*);
 static const char * const ExceptHandler_fields[]={
     "type",
     "name",
     "body",
 };
-static PyObject* ast2obj_arguments(struct ast_state *state, void*);
+static PyObject* ast2obj_arguments(struct ast_state *state, struct validator
+                                   *vstate, void*);
 static const char * const arguments_fields[]={
     "posonlyargs",
     "args",
@@ -686,7 +702,8 @@ static const char * const arguments_fields[]={
     "kwarg",
     "defaults",
 };
-static PyObject* ast2obj_arg(struct ast_state *state, void*);
+static PyObject* ast2obj_arg(struct ast_state *state, struct validator *vstate,
+                             void*);
 static const char * const arg_attributes[] = {
     "lineno",
     "col_offset",
@@ -698,7 +715,8 @@ static const char * const arg_fields[]={
     "annotation",
     "type_comment",
 };
-static PyObject* ast2obj_keyword(struct ast_state *state, void*);
+static PyObject* ast2obj_keyword(struct ast_state *state, struct validator
+                                 *vstate, void*);
 static const char * const keyword_attributes[] = {
     "lineno",
     "col_offset",
@@ -709,7 +727,8 @@ static const char * const keyword_fields[]={
     "arg",
     "value",
 };
-static PyObject* ast2obj_alias(struct ast_state *state, void*);
+static PyObject* ast2obj_alias(struct ast_state *state, struct validator
+                               *vstate, void*);
 static const char * const alias_attributes[] = {
     "lineno",
     "col_offset",
@@ -720,12 +739,14 @@ static const char * const alias_fields[]={
     "name",
     "asname",
 };
-static PyObject* ast2obj_withitem(struct ast_state *state, void*);
+static PyObject* ast2obj_withitem(struct ast_state *state, struct validator
+                                  *vstate, void*);
 static const char * const withitem_fields[]={
     "context_expr",
     "optional_vars",
 };
-static PyObject* ast2obj_match_case(struct ast_state *state, void*);
+static PyObject* ast2obj_match_case(struct ast_state *state, struct validator
+                                    *vstate, void*);
 static const char * const match_case_fields[]={
     "pattern",
     "guard",
@@ -737,7 +758,8 @@ static const char * const pattern_attributes[] = {
     "end_lineno",
     "end_col_offset",
 };
-static PyObject* ast2obj_pattern(struct ast_state *state, void*);
+static PyObject* ast2obj_pattern(struct ast_state *state, struct validator
+                                 *vstate, void*);
 static const char * const MatchValue_fields[]={
     "value",
 };
@@ -768,7 +790,8 @@ static const char * const MatchAs_fields[]={
 static const char * const MatchOr_fields[]={
     "patterns",
 };
-static PyObject* ast2obj_type_ignore(struct ast_state *state, void*);
+static PyObject* ast2obj_type_ignore(struct ast_state *state, struct validator
+                                     *vstate, void*);
 static const char * const TypeIgnore_fields[]={
     "lineno",
     "tag",
@@ -779,7 +802,8 @@ static const char * const type_param_attributes[] = {
     "end_lineno",
     "end_col_offset",
 };
-static PyObject* ast2obj_type_param(struct ast_state *state, void*);
+static PyObject* ast2obj_type_param(struct ast_state *state, struct validator
+                                    *vstate, void*);
 static const char * const TypeVar_fields[]={
     "name",
     "bound",
@@ -1008,7 +1032,8 @@ add_attributes(struct ast_state *state, PyObject *type, const char * const *attr
 
 /* Conversion AST -> Python */
 
-static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject* (*func)(struct ast_state *state, void*))
+static PyObject* ast2obj_list(struct ast_state *state, struct validator *vstate, asdl_seq *seq,
+                              PyObject* (*func)(struct ast_state *state, struct validator *vstate, void*))
 {
     Py_ssize_t i, n = asdl_seq_LEN(seq);
     PyObject *result = PyList_New(n);
@@ -1016,7 +1041,7 @@ static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject*
     if (!result)
         return NULL;
     for (i = 0; i < n; i++) {
-        value = func(state, asdl_seq_GET_UNTYPED(seq, i));
+        value = func(state, vstate, asdl_seq_GET_UNTYPED(seq, i));
         if (!value) {
             Py_DECREF(result);
             return NULL;
@@ -1026,7 +1051,7 @@ static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject*
     return result;
 }
 
-static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), void *o)
+static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), struct validator *Py_UNUSED(vstate), void *o)
 {
     PyObject *op = (PyObject*)o;
     if (!op) {
@@ -1038,7 +1063,7 @@ static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), void *o)
 #define ast2obj_identifier ast2obj_object
 #define ast2obj_string ast2obj_object
 
-static PyObject* ast2obj_int(struct ast_state *Py_UNUSED(state), long b)
+static PyObject* ast2obj_int(struct ast_state *Py_UNUSED(state), struct validator *Py_UNUSED(vstate), long b)
 {
     return PyLong_FromLong(b);
 }
@@ -1914,8 +1939,6 @@ init_types(struct ast_state *state)
         "TypeVarTuple(identifier name)");
     if (!state->TypeVarTuple_type) return -1;
 
-    state->recursion_depth = 0;
-    state->recursion_limit = 0;
     return 0;
 }
 
@@ -3770,7 +3793,7 @@ _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int
 
 
 PyObject*
-ast2obj_mod(struct ast_state *state, void* _o)
+ast2obj_mod(struct ast_state *state, struct validator *vstate, void* _o)
 {
     mod_ty o = (mod_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -3778,7 +3801,7 @@ ast2obj_mod(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -3788,12 +3811,14 @@ ast2obj_mod(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Module_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Module.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Module.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Module.type_ignores,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.Module.type_ignores,
                              ast2obj_type_ignore);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_ignores, value) == -1)
@@ -3804,7 +3829,7 @@ ast2obj_mod(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Interactive_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Interactive.body,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Interactive.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
@@ -3815,7 +3840,7 @@ ast2obj_mod(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Expression_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Expression.body);
+        value = ast2obj_expr(state, vstate, o->v.Expression.body);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
@@ -3825,30 +3850,31 @@ ast2obj_mod(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->FunctionType_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.FunctionType.argtypes,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.FunctionType.argtypes,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->argtypes, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.FunctionType.returns);
+        value = ast2obj_expr(state, vstate, o->v.FunctionType.returns);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->returns, value) == -1)
             goto failed;
         Py_DECREF(value);
         break;
     }
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_stmt(struct ast_state *state, void* _o)
+ast2obj_stmt(struct ast_state *state, struct validator *vstate, void* _o)
 {
     stmt_ty o = (stmt_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -3856,7 +3882,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -3866,39 +3892,41 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->FunctionDef_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.FunctionDef.name);
+        value = ast2obj_identifier(state, vstate, o->v.FunctionDef.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_arguments(state, o->v.FunctionDef.args);
+        value = ast2obj_arguments(state, vstate, o->v.FunctionDef.args);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->args, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.body,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.FunctionDef.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.decorator_list,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.FunctionDef.decorator_list,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->decorator_list, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.FunctionDef.returns);
+        value = ast2obj_expr(state, vstate, o->v.FunctionDef.returns);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->returns, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.FunctionDef.type_comment);
+        value = ast2obj_string(state, vstate, o->v.FunctionDef.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.type_params,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.FunctionDef.type_params,
                              ast2obj_type_param);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_params, value) == -1)
@@ -3909,40 +3937,41 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->AsyncFunctionDef_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.AsyncFunctionDef.name);
+        value = ast2obj_identifier(state, vstate, o->v.AsyncFunctionDef.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_arguments(state, o->v.AsyncFunctionDef.args);
+        value = ast2obj_arguments(state, vstate, o->v.AsyncFunctionDef.args);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->args, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFunctionDef.body,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.AsyncFunctionDef.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state,
+        value = ast2obj_list(state, vstate,
                              (asdl_seq*)o->v.AsyncFunctionDef.decorator_list,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->decorator_list, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.AsyncFunctionDef.returns);
+        value = ast2obj_expr(state, vstate, o->v.AsyncFunctionDef.returns);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->returns, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.AsyncFunctionDef.type_comment);
+        value = ast2obj_string(state, vstate, o->v.AsyncFunctionDef.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state,
+        value = ast2obj_list(state, vstate,
                              (asdl_seq*)o->v.AsyncFunctionDef.type_params,
                              ast2obj_type_param);
         if (!value) goto failed;
@@ -3954,36 +3983,38 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->ClassDef_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.ClassDef.name);
+        value = ast2obj_identifier(state, vstate, o->v.ClassDef.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.bases,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.ClassDef.bases,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->bases, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.keywords,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.ClassDef.keywords,
                              ast2obj_keyword);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->keywords, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.body,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.ClassDef.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.decorator_list,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.ClassDef.decorator_list,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->decorator_list, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.type_params,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.ClassDef.type_params,
                              ast2obj_type_param);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_params, value) == -1)
@@ -3994,7 +4025,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Return_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Return.value);
+        value = ast2obj_expr(state, vstate, o->v.Return.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4004,7 +4035,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Delete_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Delete.targets,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Delete.targets,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->targets, value) == -1)
@@ -4015,18 +4046,18 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Assign_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Assign.targets,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Assign.targets,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->targets, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Assign.value);
+        value = ast2obj_expr(state, vstate, o->v.Assign.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.Assign.type_comment);
+        value = ast2obj_string(state, vstate, o->v.Assign.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
@@ -4036,18 +4067,19 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->TypeAlias_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.TypeAlias.name);
+        value = ast2obj_expr(state, vstate, o->v.TypeAlias.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.TypeAlias.type_params,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.TypeAlias.type_params,
                              ast2obj_type_param);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_params, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.TypeAlias.value);
+        value = ast2obj_expr(state, vstate, o->v.TypeAlias.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4057,17 +4089,17 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->AugAssign_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.AugAssign.target);
+        value = ast2obj_expr(state, vstate, o->v.AugAssign.target);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->target, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_operator(state, o->v.AugAssign.op);
+        value = ast2obj_operator(state, vstate, o->v.AugAssign.op);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->op, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.AugAssign.value);
+        value = ast2obj_expr(state, vstate, o->v.AugAssign.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4077,22 +4109,22 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->AnnAssign_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.AnnAssign.target);
+        value = ast2obj_expr(state, vstate, o->v.AnnAssign.target);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->target, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.AnnAssign.annotation);
+        value = ast2obj_expr(state, vstate, o->v.AnnAssign.annotation);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->annotation, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.AnnAssign.value);
+        value = ast2obj_expr(state, vstate, o->v.AnnAssign.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_int(state, o->v.AnnAssign.simple);
+        value = ast2obj_int(state, vstate, o->v.AnnAssign.simple);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->simple, value) == -1)
             goto failed;
@@ -4102,27 +4134,29 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->For_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.For.target);
+        value = ast2obj_expr(state, vstate, o->v.For.target);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->target, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.For.iter);
+        value = ast2obj_expr(state, vstate, o->v.For.iter);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->iter, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.For.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.For.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.For.orelse, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.For.orelse,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.For.type_comment);
+        value = ast2obj_string(state, vstate, o->v.For.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
@@ -4132,29 +4166,29 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->AsyncFor_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.AsyncFor.target);
+        value = ast2obj_expr(state, vstate, o->v.AsyncFor.target);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->target, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.AsyncFor.iter);
+        value = ast2obj_expr(state, vstate, o->v.AsyncFor.iter);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->iter, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFor.body,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.AsyncFor.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFor.orelse,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.AsyncFor.orelse,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.AsyncFor.type_comment);
+        value = ast2obj_string(state, vstate, o->v.AsyncFor.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
@@ -4164,17 +4198,19 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->While_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.While.test);
+        value = ast2obj_expr(state, vstate, o->v.While.test);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->test, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.While.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.While.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.While.orelse, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.While.orelse,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
@@ -4184,17 +4220,19 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->If_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.If.test);
+        value = ast2obj_expr(state, vstate, o->v.If.test);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->test, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.If.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.If.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.If.orelse, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.If.orelse,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
@@ -4204,18 +4242,19 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->With_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.With.items,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.With.items,
                              ast2obj_withitem);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->items, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.With.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.With.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.With.type_comment);
+        value = ast2obj_string(state, vstate, o->v.With.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
@@ -4225,19 +4264,19 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->AsyncWith_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.AsyncWith.items,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.AsyncWith.items,
                              ast2obj_withitem);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->items, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.AsyncWith.body,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.AsyncWith.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.AsyncWith.type_comment);
+        value = ast2obj_string(state, vstate, o->v.AsyncWith.type_comment);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type_comment, value) == -1)
             goto failed;
@@ -4247,12 +4286,12 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Match_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Match.subject);
+        value = ast2obj_expr(state, vstate, o->v.Match.subject);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->subject, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Match.cases,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Match.cases,
                              ast2obj_match_case);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->cases, value) == -1)
@@ -4263,12 +4302,12 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Raise_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Raise.exc);
+        value = ast2obj_expr(state, vstate, o->v.Raise.exc);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->exc, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Raise.cause);
+        value = ast2obj_expr(state, vstate, o->v.Raise.cause);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->cause, value) == -1)
             goto failed;
@@ -4278,23 +4317,25 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Try_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Try.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Try.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Try.handlers,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Try.handlers,
                              ast2obj_excepthandler);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->handlers, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Try.orelse, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Try.orelse,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Try.finalbody,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Try.finalbody,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->finalbody, value) == -1)
@@ -4305,24 +4346,25 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->TryStar_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.body, ast2obj_stmt);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.TryStar.body,
+                             ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.handlers,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.TryStar.handlers,
                              ast2obj_excepthandler);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->handlers, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.orelse,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.TryStar.orelse,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.finalbody,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.TryStar.finalbody,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->finalbody, value) == -1)
@@ -4333,12 +4375,12 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Assert_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Assert.test);
+        value = ast2obj_expr(state, vstate, o->v.Assert.test);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->test, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Assert.msg);
+        value = ast2obj_expr(state, vstate, o->v.Assert.msg);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->msg, value) == -1)
             goto failed;
@@ -4348,7 +4390,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Import_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Import.names,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Import.names,
                              ast2obj_alias);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->names, value) == -1)
@@ -4359,18 +4401,18 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->ImportFrom_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.ImportFrom.module);
+        value = ast2obj_identifier(state, vstate, o->v.ImportFrom.module);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->module, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ImportFrom.names,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.ImportFrom.names,
                              ast2obj_alias);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->names, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_int(state, o->v.ImportFrom.level);
+        value = ast2obj_int(state, vstate, o->v.ImportFrom.level);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->level, value) == -1)
             goto failed;
@@ -4380,7 +4422,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Global_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Global.names,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Global.names,
                              ast2obj_identifier);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->names, value) == -1)
@@ -4391,7 +4433,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Nonlocal_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Nonlocal.names,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Nonlocal.names,
                              ast2obj_identifier);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->names, value) == -1)
@@ -4402,7 +4444,7 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Expr_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Expr.value);
+        value = ast2obj_expr(state, vstate, o->v.Expr.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4424,37 +4466,37 @@ ast2obj_stmt(struct ast_state *state, void* _o)
         if (!result) goto failed;
         break;
     }
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_expr(struct ast_state *state, void* _o)
+ast2obj_expr(struct ast_state *state, struct validator *vstate, void* _o)
 {
     expr_ty o = (expr_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -4462,7 +4504,7 @@ ast2obj_expr(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -4472,12 +4514,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->BoolOp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_boolop(state, o->v.BoolOp.op);
+        value = ast2obj_boolop(state, vstate, o->v.BoolOp.op);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->op, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.BoolOp.values,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.BoolOp.values,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->values, value) == -1)
@@ -4488,12 +4530,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->NamedExpr_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.NamedExpr.target);
+        value = ast2obj_expr(state, vstate, o->v.NamedExpr.target);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->target, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.NamedExpr.value);
+        value = ast2obj_expr(state, vstate, o->v.NamedExpr.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4503,17 +4545,17 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->BinOp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.BinOp.left);
+        value = ast2obj_expr(state, vstate, o->v.BinOp.left);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->left, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_operator(state, o->v.BinOp.op);
+        value = ast2obj_operator(state, vstate, o->v.BinOp.op);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->op, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.BinOp.right);
+        value = ast2obj_expr(state, vstate, o->v.BinOp.right);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->right, value) == -1)
             goto failed;
@@ -4523,12 +4565,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->UnaryOp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_unaryop(state, o->v.UnaryOp.op);
+        value = ast2obj_unaryop(state, vstate, o->v.UnaryOp.op);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->op, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.UnaryOp.operand);
+        value = ast2obj_expr(state, vstate, o->v.UnaryOp.operand);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->operand, value) == -1)
             goto failed;
@@ -4538,12 +4580,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Lambda_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_arguments(state, o->v.Lambda.args);
+        value = ast2obj_arguments(state, vstate, o->v.Lambda.args);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->args, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Lambda.body);
+        value = ast2obj_expr(state, vstate, o->v.Lambda.body);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
@@ -4553,17 +4595,17 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->IfExp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.IfExp.test);
+        value = ast2obj_expr(state, vstate, o->v.IfExp.test);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->test, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.IfExp.body);
+        value = ast2obj_expr(state, vstate, o->v.IfExp.body);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.IfExp.orelse);
+        value = ast2obj_expr(state, vstate, o->v.IfExp.orelse);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->orelse, value) == -1)
             goto failed;
@@ -4573,12 +4615,14 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Dict_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Dict.keys, ast2obj_expr);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Dict.keys,
+                             ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->keys, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Dict.values, ast2obj_expr);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Dict.values,
+                             ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->values, value) == -1)
             goto failed;
@@ -4588,7 +4632,8 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Set_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Set.elts, ast2obj_expr);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Set.elts,
+                             ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->elts, value) == -1)
             goto failed;
@@ -4598,12 +4643,13 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->ListComp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.ListComp.elt);
+        value = ast2obj_expr(state, vstate, o->v.ListComp.elt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->elt, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ListComp.generators,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.ListComp.generators,
                              ast2obj_comprehension);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->generators, value) == -1)
@@ -4614,12 +4660,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->SetComp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.SetComp.elt);
+        value = ast2obj_expr(state, vstate, o->v.SetComp.elt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->elt, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.SetComp.generators,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.SetComp.generators,
                              ast2obj_comprehension);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->generators, value) == -1)
@@ -4630,17 +4676,18 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->DictComp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.DictComp.key);
+        value = ast2obj_expr(state, vstate, o->v.DictComp.key);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->key, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.DictComp.value);
+        value = ast2obj_expr(state, vstate, o->v.DictComp.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.DictComp.generators,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.DictComp.generators,
                              ast2obj_comprehension);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->generators, value) == -1)
@@ -4651,12 +4698,13 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->GeneratorExp_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.GeneratorExp.elt);
+        value = ast2obj_expr(state, vstate, o->v.GeneratorExp.elt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->elt, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.GeneratorExp.generators,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.GeneratorExp.generators,
                              ast2obj_comprehension);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->generators, value) == -1)
@@ -4667,7 +4715,7 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Await_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Await.value);
+        value = ast2obj_expr(state, vstate, o->v.Await.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4677,7 +4725,7 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Yield_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Yield.value);
+        value = ast2obj_expr(state, vstate, o->v.Yield.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4687,7 +4735,7 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->YieldFrom_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.YieldFrom.value);
+        value = ast2obj_expr(state, vstate, o->v.YieldFrom.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -4697,7 +4745,7 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Compare_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Compare.left);
+        value = ast2obj_expr(state, vstate, o->v.Compare.left);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->left, value) == -1)
             goto failed;
@@ -4707,14 +4755,14 @@ ast2obj_expr(struct ast_state *state, void* _o)
             value = PyList_New(n);
             if (!value) goto failed;
             for(i = 0; i < n; i++)
-                PyList_SET_ITEM(value, i, ast2obj_cmpop(state, (cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i)));
+                PyList_SET_ITEM(value, i, ast2obj_cmpop(state, vstate, (cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i)));
         }
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ops, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Compare.comparators,
-                             ast2obj_expr);
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.Compare.comparators, ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->comparators, value) == -1)
             goto failed;
@@ -4724,17 +4772,18 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Call_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Call.func);
+        value = ast2obj_expr(state, vstate, o->v.Call.func);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->func, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Call.args, ast2obj_expr);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Call.args,
+                             ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->args, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.Call.keywords,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Call.keywords,
                              ast2obj_keyword);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->keywords, value) == -1)
@@ -4745,17 +4794,17 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->FormattedValue_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.FormattedValue.value);
+        value = ast2obj_expr(state, vstate, o->v.FormattedValue.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_int(state, o->v.FormattedValue.conversion);
+        value = ast2obj_int(state, vstate, o->v.FormattedValue.conversion);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->conversion, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.FormattedValue.format_spec);
+        value = ast2obj_expr(state, vstate, o->v.FormattedValue.format_spec);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->format_spec, value) == -1)
             goto failed;
@@ -4765,7 +4814,7 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->JoinedStr_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.JoinedStr.values,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.JoinedStr.values,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->values, value) == -1)
@@ -4776,12 +4825,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Constant_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_constant(state, o->v.Constant.value);
+        value = ast2obj_constant(state, vstate, o->v.Constant.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.Constant.kind);
+        value = ast2obj_string(state, vstate, o->v.Constant.kind);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->kind, value) == -1)
             goto failed;
@@ -4791,17 +4840,17 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Attribute_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Attribute.value);
+        value = ast2obj_expr(state, vstate, o->v.Attribute.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_identifier(state, o->v.Attribute.attr);
+        value = ast2obj_identifier(state, vstate, o->v.Attribute.attr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->attr, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr_context(state, o->v.Attribute.ctx);
+        value = ast2obj_expr_context(state, vstate, o->v.Attribute.ctx);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ctx, value) == -1)
             goto failed;
@@ -4811,17 +4860,17 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Subscript_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Subscript.value);
+        value = ast2obj_expr(state, vstate, o->v.Subscript.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Subscript.slice);
+        value = ast2obj_expr(state, vstate, o->v.Subscript.slice);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->slice, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr_context(state, o->v.Subscript.ctx);
+        value = ast2obj_expr_context(state, vstate, o->v.Subscript.ctx);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ctx, value) == -1)
             goto failed;
@@ -4831,12 +4880,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Starred_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Starred.value);
+        value = ast2obj_expr(state, vstate, o->v.Starred.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr_context(state, o->v.Starred.ctx);
+        value = ast2obj_expr_context(state, vstate, o->v.Starred.ctx);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ctx, value) == -1)
             goto failed;
@@ -4846,12 +4895,12 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Name_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.Name.id);
+        value = ast2obj_identifier(state, vstate, o->v.Name.id);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->id, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr_context(state, o->v.Name.ctx);
+        value = ast2obj_expr_context(state, vstate, o->v.Name.ctx);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ctx, value) == -1)
             goto failed;
@@ -4861,12 +4910,13 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->List_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.List.elts, ast2obj_expr);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.List.elts,
+                             ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->elts, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr_context(state, o->v.List.ctx);
+        value = ast2obj_expr_context(state, vstate, o->v.List.ctx);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ctx, value) == -1)
             goto failed;
@@ -4876,12 +4926,13 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Tuple_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.Tuple.elts, ast2obj_expr);
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.Tuple.elts,
+                             ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->elts, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr_context(state, o->v.Tuple.ctx);
+        value = ast2obj_expr_context(state, vstate, o->v.Tuple.ctx);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->ctx, value) == -1)
             goto failed;
@@ -4891,53 +4942,54 @@ ast2obj_expr(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->Slice_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.Slice.lower);
+        value = ast2obj_expr(state, vstate, o->v.Slice.lower);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->lower, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Slice.upper);
+        value = ast2obj_expr(state, vstate, o->v.Slice.upper);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->upper, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.Slice.step);
+        value = ast2obj_expr(state, vstate, o->v.Slice.step);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->step, value) == -1)
             goto failed;
         Py_DECREF(value);
         break;
     }
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
-PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty o)
+PyObject* ast2obj_expr_context(struct ast_state *state, struct validator
+                               *vstate, expr_context_ty o)
 {
     switch(o) {
         case Load:
@@ -4949,7 +5001,8 @@ PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty o)
     }
     Py_UNREACHABLE();
 }
-PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty o)
+PyObject* ast2obj_boolop(struct ast_state *state, struct validator *vstate,
+                         boolop_ty o)
 {
     switch(o) {
         case And:
@@ -4959,7 +5012,8 @@ PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty o)
     }
     Py_UNREACHABLE();
 }
-PyObject* ast2obj_operator(struct ast_state *state, operator_ty o)
+PyObject* ast2obj_operator(struct ast_state *state, struct validator *vstate,
+                           operator_ty o)
 {
     switch(o) {
         case Add:
@@ -4991,7 +5045,8 @@ PyObject* ast2obj_operator(struct ast_state *state, operator_ty o)
     }
     Py_UNREACHABLE();
 }
-PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty o)
+PyObject* ast2obj_unaryop(struct ast_state *state, struct validator *vstate,
+                          unaryop_ty o)
 {
     switch(o) {
         case Invert:
@@ -5005,7 +5060,8 @@ PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty o)
     }
     Py_UNREACHABLE();
 }
-PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty o)
+PyObject* ast2obj_cmpop(struct ast_state *state, struct validator *vstate,
+                        cmpop_ty o)
 {
     switch(o) {
         case Eq:
@@ -5032,7 +5088,8 @@ PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty o)
     Py_UNREACHABLE();
 }
 PyObject*
-ast2obj_comprehension(struct ast_state *state, void* _o)
+ast2obj_comprehension(struct ast_state *state, struct validator *vstate, void*
+                      _o)
 {
     comprehension_ty o = (comprehension_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5040,7 +5097,7 @@ ast2obj_comprehension(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5048,37 +5105,38 @@ ast2obj_comprehension(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->comprehension_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_expr(state, o->target);
+    value = ast2obj_expr(state, vstate, o->target);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->target, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_expr(state, o->iter);
+    value = ast2obj_expr(state, vstate, o->iter);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->iter, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_list(state, (asdl_seq*)o->ifs, ast2obj_expr);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->ifs, ast2obj_expr);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->ifs, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->is_async);
+    value = ast2obj_int(state, vstate, o->is_async);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->is_async, value) == -1)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_excepthandler(struct ast_state *state, void* _o)
+ast2obj_excepthandler(struct ast_state *state, struct validator *vstate, void*
+                      _o)
 {
     excepthandler_ty o = (excepthandler_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5086,7 +5144,7 @@ ast2obj_excepthandler(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5096,17 +5154,17 @@ ast2obj_excepthandler(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->ExceptHandler_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.ExceptHandler.type);
+        value = ast2obj_expr(state, vstate, o->v.ExceptHandler.type);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->type, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_identifier(state, o->v.ExceptHandler.name);
+        value = ast2obj_identifier(state, vstate, o->v.ExceptHandler.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.ExceptHandler.body,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.ExceptHandler.body,
                              ast2obj_stmt);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->body, value) == -1)
@@ -5114,37 +5172,37 @@ ast2obj_excepthandler(struct ast_state *state, void* _o)
         Py_DECREF(value);
         break;
     }
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_arguments(struct ast_state *state, void* _o)
+ast2obj_arguments(struct ast_state *state, struct validator *vstate, void* _o)
 {
     arguments_ty o = (arguments_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5152,7 +5210,7 @@ ast2obj_arguments(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5160,52 +5218,53 @@ ast2obj_arguments(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->arguments_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_list(state, (asdl_seq*)o->posonlyargs, ast2obj_arg);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->posonlyargs, ast2obj_arg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->posonlyargs, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_list(state, (asdl_seq*)o->args, ast2obj_arg);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->args, ast2obj_arg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->args, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_arg(state, o->vararg);
+    value = ast2obj_arg(state, vstate, o->vararg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->vararg, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_list(state, (asdl_seq*)o->kwonlyargs, ast2obj_arg);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->kwonlyargs, ast2obj_arg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->kwonlyargs, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_list(state, (asdl_seq*)o->kw_defaults, ast2obj_expr);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->kw_defaults,
+                         ast2obj_expr);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->kw_defaults, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_arg(state, o->kwarg);
+    value = ast2obj_arg(state, vstate, o->kwarg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->kwarg, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_list(state, (asdl_seq*)o->defaults, ast2obj_expr);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->defaults, ast2obj_expr);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->defaults, value) == -1)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_arg(struct ast_state *state, void* _o)
+ast2obj_arg(struct ast_state *state, struct validator *vstate, void* _o)
 {
     arg_ty o = (arg_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5213,7 +5272,7 @@ ast2obj_arg(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5221,52 +5280,52 @@ ast2obj_arg(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->arg_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_identifier(state, o->arg);
+    value = ast2obj_identifier(state, vstate, o->arg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->arg, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_expr(state, o->annotation);
+    value = ast2obj_expr(state, vstate, o->annotation);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->annotation, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_string(state, o->type_comment);
+    value = ast2obj_string(state, vstate, o->type_comment);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->type_comment, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_keyword(struct ast_state *state, void* _o)
+ast2obj_keyword(struct ast_state *state, struct validator *vstate, void* _o)
 {
     keyword_ty o = (keyword_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5274,7 +5333,7 @@ ast2obj_keyword(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5282,47 +5341,47 @@ ast2obj_keyword(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->keyword_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_identifier(state, o->arg);
+    value = ast2obj_identifier(state, vstate, o->arg);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->arg, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_expr(state, o->value);
+    value = ast2obj_expr(state, vstate, o->value);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->value, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_alias(struct ast_state *state, void* _o)
+ast2obj_alias(struct ast_state *state, struct validator *vstate, void* _o)
 {
     alias_ty o = (alias_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5330,7 +5389,7 @@ ast2obj_alias(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5338,47 +5397,47 @@ ast2obj_alias(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->alias_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_identifier(state, o->name);
+    value = ast2obj_identifier(state, vstate, o->name);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->name, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_identifier(state, o->asname);
+    value = ast2obj_identifier(state, vstate, o->asname);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->asname, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_withitem(struct ast_state *state, void* _o)
+ast2obj_withitem(struct ast_state *state, struct validator *vstate, void* _o)
 {
     withitem_ty o = (withitem_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5386,7 +5445,7 @@ ast2obj_withitem(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5394,27 +5453,27 @@ ast2obj_withitem(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->withitem_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_expr(state, o->context_expr);
+    value = ast2obj_expr(state, vstate, o->context_expr);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->context_expr, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_expr(state, o->optional_vars);
+    value = ast2obj_expr(state, vstate, o->optional_vars);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->optional_vars, value) == -1)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_match_case(struct ast_state *state, void* _o)
+ast2obj_match_case(struct ast_state *state, struct validator *vstate, void* _o)
 {
     match_case_ty o = (match_case_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5422,7 +5481,7 @@ ast2obj_match_case(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5430,32 +5489,32 @@ ast2obj_match_case(struct ast_state *state, void* _o)
     tp = (PyTypeObject *)state->match_case_type;
     result = PyType_GenericNew(tp, NULL, NULL);
     if (!result) return NULL;
-    value = ast2obj_pattern(state, o->pattern);
+    value = ast2obj_pattern(state, vstate, o->pattern);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->pattern, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_expr(state, o->guard);
+    value = ast2obj_expr(state, vstate, o->guard);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->guard, value) == -1)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_list(state, (asdl_seq*)o->body, ast2obj_stmt);
+    value = ast2obj_list(state, vstate, (asdl_seq*)o->body, ast2obj_stmt);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->body, value) == -1)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_pattern(struct ast_state *state, void* _o)
+ast2obj_pattern(struct ast_state *state, struct validator *vstate, void* _o)
 {
     pattern_ty o = (pattern_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5463,7 +5522,7 @@ ast2obj_pattern(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5473,7 +5532,7 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchValue_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.MatchValue.value);
+        value = ast2obj_expr(state, vstate, o->v.MatchValue.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -5483,7 +5542,7 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchSingleton_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_constant(state, o->v.MatchSingleton.value);
+        value = ast2obj_constant(state, vstate, o->v.MatchSingleton.value);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->value, value) == -1)
             goto failed;
@@ -5493,7 +5552,8 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchSequence_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchSequence.patterns,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.MatchSequence.patterns,
                              ast2obj_pattern);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->patterns, value) == -1)
@@ -5504,19 +5564,20 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchMapping_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchMapping.keys,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.MatchMapping.keys,
                              ast2obj_expr);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->keys, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchMapping.patterns,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.MatchMapping.patterns,
                              ast2obj_pattern);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->patterns, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_identifier(state, o->v.MatchMapping.rest);
+        value = ast2obj_identifier(state, vstate, o->v.MatchMapping.rest);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->rest, value) == -1)
             goto failed;
@@ -5526,24 +5587,27 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchClass_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_expr(state, o->v.MatchClass.cls);
+        value = ast2obj_expr(state, vstate, o->v.MatchClass.cls);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->cls, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.patterns,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.MatchClass.patterns,
                              ast2obj_pattern);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->patterns, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.kwd_attrs,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.MatchClass.kwd_attrs,
                              ast2obj_identifier);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->kwd_attrs, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.kwd_patterns,
+        value = ast2obj_list(state, vstate,
+                             (asdl_seq*)o->v.MatchClass.kwd_patterns,
                              ast2obj_pattern);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->kwd_patterns, value) == -1)
@@ -5554,7 +5618,7 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchStar_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.MatchStar.name);
+        value = ast2obj_identifier(state, vstate, o->v.MatchStar.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
@@ -5564,12 +5628,12 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchAs_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_pattern(state, o->v.MatchAs.pattern);
+        value = ast2obj_pattern(state, vstate, o->v.MatchAs.pattern);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->pattern, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_identifier(state, o->v.MatchAs.name);
+        value = ast2obj_identifier(state, vstate, o->v.MatchAs.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
@@ -5579,7 +5643,7 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->MatchOr_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_list(state, (asdl_seq*)o->v.MatchOr.patterns,
+        value = ast2obj_list(state, vstate, (asdl_seq*)o->v.MatchOr.patterns,
                              ast2obj_pattern);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->patterns, value) == -1)
@@ -5587,37 +5651,37 @@ ast2obj_pattern(struct ast_state *state, void* _o)
         Py_DECREF(value);
         break;
     }
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_type_ignore(struct ast_state *state, void* _o)
+ast2obj_type_ignore(struct ast_state *state, struct validator *vstate, void* _o)
 {
     type_ignore_ty o = (type_ignore_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5625,7 +5689,7 @@ ast2obj_type_ignore(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5635,29 +5699,29 @@ ast2obj_type_ignore(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->TypeIgnore_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_int(state, o->v.TypeIgnore.lineno);
+        value = ast2obj_int(state, vstate, o->v.TypeIgnore.lineno);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->lineno, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_string(state, o->v.TypeIgnore.tag);
+        value = ast2obj_string(state, vstate, o->v.TypeIgnore.tag);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->tag, value) == -1)
             goto failed;
         Py_DECREF(value);
         break;
     }
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
 }
 
 PyObject*
-ast2obj_type_param(struct ast_state *state, void* _o)
+ast2obj_type_param(struct ast_state *state, struct validator *vstate, void* _o)
 {
     type_param_ty o = (type_param_ty)_o;
     PyObject *result = NULL, *value = NULL;
@@ -5665,7 +5729,7 @@ ast2obj_type_param(struct ast_state *state, void* _o)
     if (!o) {
         Py_RETURN_NONE;
     }
-    if (++state->recursion_depth > state->recursion_limit) {
+    if (++vstate->recursion_depth > vstate->recursion_limit) {
         PyErr_SetString(PyExc_RecursionError,
             "maximum recursion depth exceeded during ast construction");
         return NULL;
@@ -5675,12 +5739,12 @@ ast2obj_type_param(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->TypeVar_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.TypeVar.name);
+        value = ast2obj_identifier(state, vstate, o->v.TypeVar.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
-        value = ast2obj_expr(state, o->v.TypeVar.bound);
+        value = ast2obj_expr(state, vstate, o->v.TypeVar.bound);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->bound, value) == -1)
             goto failed;
@@ -5690,7 +5754,7 @@ ast2obj_type_param(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->ParamSpec_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.ParamSpec.name);
+        value = ast2obj_identifier(state, vstate, o->v.ParamSpec.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
@@ -5700,37 +5764,37 @@ ast2obj_type_param(struct ast_state *state, void* _o)
         tp = (PyTypeObject *)state->TypeVarTuple_type;
         result = PyType_GenericNew(tp, NULL, NULL);
         if (!result) goto failed;
-        value = ast2obj_identifier(state, o->v.TypeVarTuple.name);
+        value = ast2obj_identifier(state, vstate, o->v.TypeVarTuple.name);
         if (!value) goto failed;
         if (PyObject_SetAttr(result, state->name, value) == -1)
             goto failed;
         Py_DECREF(value);
         break;
     }
-    value = ast2obj_int(state, o->lineno);
+    value = ast2obj_int(state, vstate, o->lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->col_offset);
+    value = ast2obj_int(state, vstate, o->col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_lineno);
+    value = ast2obj_int(state, vstate, o->end_lineno);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_lineno, value) < 0)
         goto failed;
     Py_DECREF(value);
-    value = ast2obj_int(state, o->end_col_offset);
+    value = ast2obj_int(state, vstate, o->end_col_offset);
     if (!value) goto failed;
     if (PyObject_SetAttr(result, state->end_col_offset, value) < 0)
         goto failed;
     Py_DECREF(value);
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     return result;
 failed:
-    state->recursion_depth--;
+    vstate->recursion_depth--;
     Py_XDECREF(value);
     Py_XDECREF(result);
     return NULL;
@@ -13090,18 +13154,19 @@ PyObject* PyAST_mod2obj(mod_ty t)
     if (!tstate) {
         return NULL;
     }
-    state->recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
+    struct validator vstate;
+    vstate.recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
     int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
     starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
-    state->recursion_depth = starting_recursion_depth;
+    vstate.recursion_depth = starting_recursion_depth;
 
-    PyObject *result = ast2obj_mod(state, t);
+    PyObject *result = ast2obj_mod(state, &vstate, t);
 
     /* Check that the recursion depth counting balanced correctly */
-    if (result && state->recursion_depth != starting_recursion_depth) {
+    if (result && vstate.recursion_depth != starting_recursion_depth) {
         PyErr_Format(PyExc_SystemError,
             "AST constructor recursion depth mismatch (before=%d, after=%d)",
-            starting_recursion_depth, state->recursion_depth);
+            starting_recursion_depth, vstate.recursion_depth);
         return NULL;
     }
     return result;