[Python-checkins] bpo-31572: Get rid of _PyObject_HasAttrId() in the ASDL parser. (#3725)

Serhiy Storchaka webhook-mailer at python.org
Sat Nov 11 09:41:35 EST 2017


https://github.com/python/cpython/commit/bba2239c17a404fc99524bfbf8126c9b3b7fb343
commit: bba2239c17a404fc99524bfbf8126c9b3b7fb343
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-11-11T16:41:32+02:00
summary:

bpo-31572: Get rid of _PyObject_HasAttrId() in the ASDL parser. (#3725)

Silence only expected AttributeError.

files:
M Parser/asdl_c.py
M Python/Python-ast.c

diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index 0286d6652f5..69583d914f6 100644
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -497,18 +497,15 @@ def isSimpleType(self, field):
 
     def visitField(self, field, name, sum=None, prod=None, depth=0):
         ctype = get_c_type(field.type)
-        if field.opt:
-            check = "exists_not_none(obj, &PyId_%s)" % (field.name,)
+        if not field.opt:
+            self.emit("tmp = _PyObject_GetAttrId(obj, &PyId_%s);" % field.name, depth)
         else:
-            check = "_PyObject_HasAttrId(obj, &PyId_%s)" % (field.name,)
-        self.emit("if (%s) {" % (check,), depth, reflow=False)
+            self.emit("tmp = get_not_none(obj, &PyId_%s);" % field.name, depth)
+        self.emit("if (tmp != NULL) {", depth)
         self.emit("int res;", depth+1)
         if field.seq:
             self.emit("Py_ssize_t len;", depth+1)
             self.emit("Py_ssize_t i;", depth+1)
-        self.emit("tmp = _PyObject_GetAttrId(obj, &PyId_%s);" % field.name, depth+1)
-        self.emit("if (tmp == NULL) goto failed;", depth+1)
-        if field.seq:
             self.emit("if (!PyList_Check(tmp)) {", depth+1)
             self.emit("PyErr_Format(PyExc_TypeError, \"%s field \\\"%s\\\" must "
                       "be a list, not a %%.200s\", tmp->ob_type->tp_name);" %
@@ -542,13 +539,19 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
             self.emit("if (res != 0) goto failed;", depth+1)
 
         self.emit("Py_CLEAR(tmp);", depth+1)
-        self.emit("} else {", depth)
         if not field.opt:
+            self.emit("} else {", depth)
+            self.emit("if (PyErr_ExceptionMatches(PyExc_AttributeError)) {", depth+1)
             message = "required field \\\"%s\\\" missing from %s" % (field.name, name)
             format = "PyErr_SetString(PyExc_TypeError, \"%s\");"
-            self.emit(format % message, depth+1, reflow=False)
+            self.emit(format % message, depth+2, reflow=False)
+            self.emit("}", depth+1)
             self.emit("return 1;", depth+1)
         else:
+            self.emit("} else if (PyErr_Occurred()) {", depth)
+            self.emit("return 1;", depth+1)
+            self.emit("} else {", depth)
+
             if self.isNumeric(field):
                 self.emit("%s = 0;" % field.name, depth+1)
             elif not self.isSimpleType(field):
@@ -660,13 +663,17 @@ def visitModule(self, mod):
     int res = -1;
     PyObject *key, *value, *fields;
     fields = _PyObject_GetAttrId((PyObject*)Py_TYPE(self), &PyId__fields);
-    if (!fields)
-        PyErr_Clear();
     if (fields) {
         numfields = PySequence_Size(fields);
         if (numfields == -1)
             goto cleanup;
     }
+    else if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+        PyErr_Clear();
+    }
+    else {
+        goto cleanup;
+    }
 
     res = 0; /* if no error occurs, this stays 0 to the end */
     if (numfields < PyTuple_GET_SIZE(args)) {
@@ -958,17 +965,20 @@ def visitModule(self, mod):
     return 0;
 }
 
-static int exists_not_none(PyObject *obj, _Py_Identifier *id)
+static PyObject *get_not_none(PyObject *obj, _Py_Identifier *id)
 {
-    int isnone;
     PyObject *attr = _PyObject_GetAttrId(obj, id);
     if (!attr) {
-        PyErr_Clear();
-        return 0;
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_Clear();
+        }
+        return NULL;
+    }
+    else if (attr == Py_None) {
+        Py_DECREF(attr);
+        return NULL;
     }
-    isnone = attr == Py_None;
-    Py_DECREF(attr);
-    return !isnone;
+    return attr;
 }
 
 """, 0, reflow=False)
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 2f1e737ea65..81226c8a060 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -546,13 +546,17 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
     int res = -1;
     PyObject *key, *value, *fields;
     fields = _PyObject_GetAttrId((PyObject*)Py_TYPE(self), &PyId__fields);
-    if (!fields)
-        PyErr_Clear();
     if (fields) {
         numfields = PySequence_Size(fields);
         if (numfields == -1)
             goto cleanup;
     }
+    else if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+        PyErr_Clear();
+    }
+    else {
+        goto cleanup;
+    }
 
     res = 0; /* if no error occurs, this stays 0 to the end */
     if (numfields < PyTuple_GET_SIZE(args)) {
@@ -844,17 +848,20 @@ static int add_ast_fields(void)
     return 0;
 }
 
-static int exists_not_none(PyObject *obj, _Py_Identifier *id)
+static PyObject *get_not_none(PyObject *obj, _Py_Identifier *id)
 {
-    int isnone;
     PyObject *attr = _PyObject_GetAttrId(obj, id);
     if (!attr) {
-        PyErr_Clear();
-        return 0;
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_Clear();
+        }
+        return NULL;
     }
-    isnone = attr == Py_None;
-    Py_DECREF(attr);
-    return !isnone;
+    else if (attr == Py_None) {
+        Py_DECREF(attr);
+        return NULL;
+    }
+    return attr;
 }
 
 
@@ -4005,12 +4012,11 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
         asdl_seq* body;
         string docstring;
 
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4030,16 +4036,19 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_docstring)) {
+        tmp = get_not_none(obj, &PyId_docstring);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_docstring);
-            if (tmp == NULL) goto failed;
             res = obj2ast_string(tmp, &docstring, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             docstring = NULL;
         }
@@ -4054,12 +4063,11 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* body;
 
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4079,7 +4087,9 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive");
+            }
             return 1;
         }
         *out = Interactive(body, arena);
@@ -4093,15 +4103,16 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty body;
 
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &body, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression");
+            }
             return 1;
         }
         *out = Expression(body, arena);
@@ -4115,12 +4126,11 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* body;
 
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Suite field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4140,7 +4150,9 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Suite");
+            }
             return 1;
         }
         *out = Suite(body, arena);
@@ -4167,26 +4179,28 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         *out = NULL;
         return 0;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_lineno)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &lineno, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_col_offset)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &col_offset, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt");
+        }
         return 1;
     }
     isinstance = PyObject_IsInstance(obj, (PyObject*)FunctionDef_type);
@@ -4201,34 +4215,35 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         expr_ty returns;
         string docstring;
 
-        if (_PyObject_HasAttrId(obj, &PyId_name)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_name);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_name);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &name, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_args)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_args);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_args);
-            if (tmp == NULL) goto failed;
             res = obj2ast_arguments(tmp, &args, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4248,15 +4263,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4276,26 +4292,30 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_returns)) {
+        tmp = get_not_none(obj, &PyId_returns);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_returns);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &returns, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             returns = NULL;
         }
-        if (exists_not_none(obj, &PyId_docstring)) {
+        tmp = get_not_none(obj, &PyId_docstring);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_docstring);
-            if (tmp == NULL) goto failed;
             res = obj2ast_string(tmp, &docstring, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             docstring = NULL;
         }
@@ -4316,34 +4336,35 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         expr_ty returns;
         string docstring;
 
-        if (_PyObject_HasAttrId(obj, &PyId_name)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_name);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_name);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &name, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from AsyncFunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from AsyncFunctionDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_args)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_args);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_args);
-            if (tmp == NULL) goto failed;
             res = obj2ast_arguments(tmp, &args, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from AsyncFunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from AsyncFunctionDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4363,15 +4384,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFunctionDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4391,26 +4413,30 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from AsyncFunctionDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from AsyncFunctionDef");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_returns)) {
+        tmp = get_not_none(obj, &PyId_returns);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_returns);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &returns, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             returns = NULL;
         }
-        if (exists_not_none(obj, &PyId_docstring)) {
+        tmp = get_not_none(obj, &PyId_docstring);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_docstring);
-            if (tmp == NULL) goto failed;
             res = obj2ast_string(tmp, &docstring, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             docstring = NULL;
         }
@@ -4431,23 +4457,23 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* decorator_list;
         string docstring;
 
-        if (_PyObject_HasAttrId(obj, &PyId_name)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_name);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_name);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &name, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_bases)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_bases);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_bases);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4467,15 +4493,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_keywords)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_keywords);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_keywords);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4495,15 +4522,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4523,15 +4551,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_decorator_list)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_decorator_list);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4551,16 +4580,19 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_docstring)) {
+        tmp = get_not_none(obj, &PyId_docstring);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_docstring);
-            if (tmp == NULL) goto failed;
             res = obj2ast_string(tmp, &docstring, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             docstring = NULL;
         }
@@ -4576,13 +4608,14 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty value;
 
-        if (exists_not_none(obj, &PyId_value)) {
+        tmp = get_not_none(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             value = NULL;
         }
@@ -4597,12 +4630,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* targets;
 
-        if (_PyObject_HasAttrId(obj, &PyId_targets)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_targets);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_targets);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4622,7 +4654,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete");
+            }
             return 1;
         }
         *out = Delete(targets, lineno, col_offset, arena);
@@ -4637,12 +4671,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* targets;
         expr_ty value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_targets)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_targets);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_targets);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4662,18 +4695,21 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign");
+            }
             return 1;
         }
         *out = Assign(targets, value, lineno, col_offset, arena);
@@ -4689,37 +4725,40 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         operator_ty op;
         expr_ty value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_target)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_target);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_target);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &target, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_op)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_op);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_op);
-            if (tmp == NULL) goto failed;
             res = obj2ast_operator(tmp, &op, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign");
+            }
             return 1;
         }
         *out = AugAssign(target, op, value, lineno, col_offset, arena);
@@ -4736,47 +4775,51 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         expr_ty value;
         int simple;
 
-        if (_PyObject_HasAttrId(obj, &PyId_target)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_target);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_target);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &target, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AnnAssign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AnnAssign");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_annotation)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_annotation);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_annotation);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &annotation, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"annotation\" missing from AnnAssign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"annotation\" missing from AnnAssign");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_value)) {
+        tmp = get_not_none(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             value = NULL;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_simple)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_simple);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_simple);
-            if (tmp == NULL) goto failed;
             res = obj2ast_int(tmp, &simple, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"simple\" missing from AnnAssign");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"simple\" missing from AnnAssign");
+            }
             return 1;
         }
         *out = AnnAssign(target, annotation, value, simple, lineno, col_offset,
@@ -4794,34 +4837,35 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* body;
         asdl_seq* orelse;
 
-        if (_PyObject_HasAttrId(obj, &PyId_target)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_target);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_target);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &target, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_iter)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_iter);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_iter);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &iter, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4841,15 +4885,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4869,7 +4914,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For");
+            }
             return 1;
         }
         *out = For(target, iter, body, orelse, lineno, col_offset, arena);
@@ -4886,34 +4933,35 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* body;
         asdl_seq* orelse;
 
-        if (_PyObject_HasAttrId(obj, &PyId_target)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_target);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_target);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &target, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AsyncFor");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AsyncFor");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_iter)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_iter);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_iter);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &iter, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from AsyncFor");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from AsyncFor");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "AsyncFor field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4933,15 +4981,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFor");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFor");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "AsyncFor field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -4961,7 +5010,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from AsyncFor");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from AsyncFor");
+            }
             return 1;
         }
         *out = AsyncFor(target, iter, body, orelse, lineno, col_offset, arena);
@@ -4977,23 +5028,23 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* body;
         asdl_seq* orelse;
 
-        if (_PyObject_HasAttrId(obj, &PyId_test)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_test);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_test);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &test, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5013,15 +5064,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5041,7 +5093,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While");
+            }
             return 1;
         }
         *out = While(test, body, orelse, lineno, col_offset, arena);
@@ -5057,23 +5111,23 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* body;
         asdl_seq* orelse;
 
-        if (_PyObject_HasAttrId(obj, &PyId_test)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_test);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_test);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &test, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5093,15 +5147,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5121,7 +5176,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If");
+            }
             return 1;
         }
         *out = If(test, body, orelse, lineno, col_offset, arena);
@@ -5136,12 +5193,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* items;
         asdl_seq* body;
 
-        if (_PyObject_HasAttrId(obj, &PyId_items)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_items);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_items);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5161,15 +5217,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5189,7 +5246,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With");
+            }
             return 1;
         }
         *out = With(items, body, lineno, col_offset, arena);
@@ -5204,12 +5263,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* items;
         asdl_seq* body;
 
-        if (_PyObject_HasAttrId(obj, &PyId_items)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_items);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_items);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "AsyncWith field \"items\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5229,15 +5287,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from AsyncWith");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from AsyncWith");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "AsyncWith field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5257,7 +5316,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncWith");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncWith");
+            }
             return 1;
         }
         *out = AsyncWith(items, body, lineno, col_offset, arena);
@@ -5272,23 +5333,25 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         expr_ty exc;
         expr_ty cause;
 
-        if (exists_not_none(obj, &PyId_exc)) {
+        tmp = get_not_none(obj, &PyId_exc);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_exc);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &exc, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             exc = NULL;
         }
-        if (exists_not_none(obj, &PyId_cause)) {
+        tmp = get_not_none(obj, &PyId_cause);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_cause);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &cause, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             cause = NULL;
         }
@@ -5306,12 +5369,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* orelse;
         asdl_seq* finalbody;
 
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5331,15 +5393,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_handlers)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_handlers);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_handlers);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5359,15 +5422,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5387,15 +5451,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_finalbody)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_finalbody);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_finalbody);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5415,7 +5480,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try");
+            }
             return 1;
         }
         *out = Try(body, handlers, orelse, finalbody, lineno, col_offset,
@@ -5431,24 +5498,26 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         expr_ty test;
         expr_ty msg;
 
-        if (_PyObject_HasAttrId(obj, &PyId_test)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_test);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_test);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &test, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_msg)) {
+        tmp = get_not_none(obj, &PyId_msg);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_msg);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &msg, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             msg = NULL;
         }
@@ -5463,12 +5532,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* names;
 
-        if (_PyObject_HasAttrId(obj, &PyId_names)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_names);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_names);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5488,7 +5556,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import");
+            }
             return 1;
         }
         *out = Import(names, lineno, col_offset, arena);
@@ -5504,22 +5574,22 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
         asdl_seq* names;
         int level;
 
-        if (exists_not_none(obj, &PyId_module)) {
+        tmp = get_not_none(obj, &PyId_module);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_module);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &module, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             module = NULL;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_names)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_names);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_names);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5539,16 +5609,19 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_level)) {
+        tmp = get_not_none(obj, &PyId_level);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_level);
-            if (tmp == NULL) goto failed;
             res = obj2ast_int(tmp, &level, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             level = 0;
         }
@@ -5563,12 +5636,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* names;
 
-        if (_PyObject_HasAttrId(obj, &PyId_names)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_names);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_names);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5588,7 +5660,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global");
+            }
             return 1;
         }
         *out = Global(names, lineno, col_offset, arena);
@@ -5602,12 +5676,11 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* names;
 
-        if (_PyObject_HasAttrId(obj, &PyId_names)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_names);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_names);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5627,7 +5700,9 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal");
+            }
             return 1;
         }
         *out = Nonlocal(names, lineno, col_offset, arena);
@@ -5641,15 +5716,16 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr");
+            }
             return 1;
         }
         *out = Expr(value, lineno, col_offset, arena);
@@ -5706,26 +5782,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         *out = NULL;
         return 0;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_lineno)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &lineno, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_col_offset)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &col_offset, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr");
+        }
         return 1;
     }
     isinstance = PyObject_IsInstance(obj, (PyObject*)BoolOp_type);
@@ -5736,23 +5814,23 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         boolop_ty op;
         asdl_seq* values;
 
-        if (_PyObject_HasAttrId(obj, &PyId_op)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_op);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_op);
-            if (tmp == NULL) goto failed;
             res = obj2ast_boolop(tmp, &op, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_values)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_values);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_values);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5772,7 +5850,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp");
+            }
             return 1;
         }
         *out = BoolOp(op, values, lineno, col_offset, arena);
@@ -5788,37 +5868,40 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         operator_ty op;
         expr_ty right;
 
-        if (_PyObject_HasAttrId(obj, &PyId_left)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_left);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_left);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &left, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_op)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_op);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_op);
-            if (tmp == NULL) goto failed;
             res = obj2ast_operator(tmp, &op, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_right)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_right);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_right);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &right, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp");
+            }
             return 1;
         }
         *out = BinOp(left, op, right, lineno, col_offset, arena);
@@ -5833,26 +5916,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         unaryop_ty op;
         expr_ty operand;
 
-        if (_PyObject_HasAttrId(obj, &PyId_op)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_op);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_op);
-            if (tmp == NULL) goto failed;
             res = obj2ast_unaryop(tmp, &op, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_operand)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_operand);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_operand);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &operand, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp");
+            }
             return 1;
         }
         *out = UnaryOp(op, operand, lineno, col_offset, arena);
@@ -5867,26 +5952,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         arguments_ty args;
         expr_ty body;
 
-        if (_PyObject_HasAttrId(obj, &PyId_args)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_args);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_args);
-            if (tmp == NULL) goto failed;
             res = obj2ast_arguments(tmp, &args, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &body, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda");
+            }
             return 1;
         }
         *out = Lambda(args, body, lineno, col_offset, arena);
@@ -5902,37 +5989,40 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         expr_ty body;
         expr_ty orelse;
 
-        if (_PyObject_HasAttrId(obj, &PyId_test)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_test);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_test);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &test, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &body, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_orelse)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_orelse);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &orelse, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp");
+            }
             return 1;
         }
         *out = IfExp(test, body, orelse, lineno, col_offset, arena);
@@ -5947,12 +6037,11 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         asdl_seq* keys;
         asdl_seq* values;
 
-        if (_PyObject_HasAttrId(obj, &PyId_keys)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_keys);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_keys);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -5972,15 +6061,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_values)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_values);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_values);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6000,7 +6090,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict");
+            }
             return 1;
         }
         *out = Dict(keys, values, lineno, col_offset, arena);
@@ -6014,12 +6106,11 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* elts;
 
-        if (_PyObject_HasAttrId(obj, &PyId_elts)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_elts);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_elts);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6039,7 +6130,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set");
+            }
             return 1;
         }
         *out = Set(elts, lineno, col_offset, arena);
@@ -6054,23 +6147,23 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         expr_ty elt;
         asdl_seq* generators;
 
-        if (_PyObject_HasAttrId(obj, &PyId_elt)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_elt);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_elt);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &elt, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_generators)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_generators);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_generators);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6090,7 +6183,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp");
+            }
             return 1;
         }
         *out = ListComp(elt, generators, lineno, col_offset, arena);
@@ -6105,23 +6200,23 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         expr_ty elt;
         asdl_seq* generators;
 
-        if (_PyObject_HasAttrId(obj, &PyId_elt)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_elt);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_elt);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &elt, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_generators)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_generators);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_generators);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6141,7 +6236,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp");
+            }
             return 1;
         }
         *out = SetComp(elt, generators, lineno, col_offset, arena);
@@ -6157,34 +6254,35 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         expr_ty value;
         asdl_seq* generators;
 
-        if (_PyObject_HasAttrId(obj, &PyId_key)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_key);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_key);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &key, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_generators)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_generators);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_generators);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6204,7 +6302,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp");
+            }
             return 1;
         }
         *out = DictComp(key, value, generators, lineno, col_offset, arena);
@@ -6219,23 +6319,23 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         expr_ty elt;
         asdl_seq* generators;
 
-        if (_PyObject_HasAttrId(obj, &PyId_elt)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_elt);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_elt);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &elt, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_generators)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_generators);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_generators);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6255,7 +6355,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp");
+            }
             return 1;
         }
         *out = GeneratorExp(elt, generators, lineno, col_offset, arena);
@@ -6269,15 +6371,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Await");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Await");
+            }
             return 1;
         }
         *out = Await(value, lineno, col_offset, arena);
@@ -6291,13 +6394,14 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty value;
 
-        if (exists_not_none(obj, &PyId_value)) {
+        tmp = get_not_none(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             value = NULL;
         }
@@ -6312,15 +6416,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom");
+            }
             return 1;
         }
         *out = YieldFrom(value, lineno, col_offset, arena);
@@ -6336,23 +6441,23 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         asdl_int_seq* ops;
         asdl_seq* comparators;
 
-        if (_PyObject_HasAttrId(obj, &PyId_left)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_left);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_left);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &left, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ops)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ops);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ops);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6372,15 +6477,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_comparators)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_comparators);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_comparators);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6400,7 +6506,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare");
+            }
             return 1;
         }
         *out = Compare(left, ops, comparators, lineno, col_offset, arena);
@@ -6416,23 +6524,23 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         asdl_seq* args;
         asdl_seq* keywords;
 
-        if (_PyObject_HasAttrId(obj, &PyId_func)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_func);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_func);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &func, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_args)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_args);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_args);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6452,15 +6560,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_keywords)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_keywords);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_keywords);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6480,7 +6589,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call");
+            }
             return 1;
         }
         *out = Call(func, args, keywords, lineno, col_offset, arena);
@@ -6494,15 +6605,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         object n;
 
-        if (_PyObject_HasAttrId(obj, &PyId_n)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_n);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_n);
-            if (tmp == NULL) goto failed;
             res = obj2ast_object(tmp, &n, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"n\" missing from Num");
+            }
             return 1;
         }
         *out = Num(n, lineno, col_offset, arena);
@@ -6516,15 +6628,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         string s;
 
-        if (_PyObject_HasAttrId(obj, &PyId_s)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_s);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_s);
-            if (tmp == NULL) goto failed;
             res = obj2ast_string(tmp, &s, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Str");
+            }
             return 1;
         }
         *out = Str(s, lineno, col_offset, arena);
@@ -6540,34 +6653,37 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         int conversion;
         expr_ty format_spec;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from FormattedValue");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from FormattedValue");
+            }
             return 1;
         }
-        if (exists_not_none(obj, &PyId_conversion)) {
+        tmp = get_not_none(obj, &PyId_conversion);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_conversion);
-            if (tmp == NULL) goto failed;
             res = obj2ast_int(tmp, &conversion, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             conversion = 0;
         }
-        if (exists_not_none(obj, &PyId_format_spec)) {
+        tmp = get_not_none(obj, &PyId_format_spec);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_format_spec);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &format_spec, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             format_spec = NULL;
         }
@@ -6583,12 +6699,11 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* values;
 
-        if (_PyObject_HasAttrId(obj, &PyId_values)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_values);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_values);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "JoinedStr field \"values\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6608,7 +6723,9 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from JoinedStr");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from JoinedStr");
+            }
             return 1;
         }
         *out = JoinedStr(values, lineno, col_offset, arena);
@@ -6622,15 +6739,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         bytes s;
 
-        if (_PyObject_HasAttrId(obj, &PyId_s)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_s);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_s);
-            if (tmp == NULL) goto failed;
             res = obj2ast_bytes(tmp, &s, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes");
+            }
             return 1;
         }
         *out = Bytes(s, lineno, col_offset, arena);
@@ -6644,15 +6762,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         singleton value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_singleton(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NameConstant");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NameConstant");
+            }
             return 1;
         }
         *out = NameConstant(value, lineno, col_offset, arena);
@@ -6676,15 +6795,16 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
     if (isinstance) {
         constant value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_constant(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Constant");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Constant");
+            }
             return 1;
         }
         *out = Constant(value, lineno, col_offset, arena);
@@ -6700,37 +6820,40 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         identifier attr;
         expr_context_ty ctx;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_attr)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_attr);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_attr);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &attr, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ctx)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr_context(tmp, &ctx, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute");
+            }
             return 1;
         }
         *out = Attribute(value, attr, ctx, lineno, col_offset, arena);
@@ -6746,37 +6869,40 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         slice_ty slice;
         expr_context_ty ctx;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_slice)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_slice);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_slice);
-            if (tmp == NULL) goto failed;
             res = obj2ast_slice(tmp, &slice, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ctx)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr_context(tmp, &ctx, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript");
+            }
             return 1;
         }
         *out = Subscript(value, slice, ctx, lineno, col_offset, arena);
@@ -6791,26 +6917,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         expr_ty value;
         expr_context_ty ctx;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ctx)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr_context(tmp, &ctx, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred");
+            }
             return 1;
         }
         *out = Starred(value, ctx, lineno, col_offset, arena);
@@ -6825,26 +6953,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         identifier id;
         expr_context_ty ctx;
 
-        if (_PyObject_HasAttrId(obj, &PyId_id)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_id);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_id);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &id, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ctx)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr_context(tmp, &ctx, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name");
+            }
             return 1;
         }
         *out = Name(id, ctx, lineno, col_offset, arena);
@@ -6859,12 +6989,11 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         asdl_seq* elts;
         expr_context_ty ctx;
 
-        if (_PyObject_HasAttrId(obj, &PyId_elts)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_elts);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_elts);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6884,18 +7013,21 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ctx)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr_context(tmp, &ctx, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List");
+            }
             return 1;
         }
         *out = List(elts, ctx, lineno, col_offset, arena);
@@ -6910,12 +7042,11 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
         asdl_seq* elts;
         expr_context_ty ctx;
 
-        if (_PyObject_HasAttrId(obj, &PyId_elts)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_elts);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_elts);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -6935,18 +7066,21 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple");
+            }
             return 1;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_ctx)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_ctx);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr_context(tmp, &ctx, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple");
+            }
             return 1;
         }
         *out = Tuple(elts, ctx, lineno, col_offset, arena);
@@ -7038,33 +7172,36 @@ obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena)
         expr_ty upper;
         expr_ty step;
 
-        if (exists_not_none(obj, &PyId_lower)) {
+        tmp = get_not_none(obj, &PyId_lower);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_lower);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &lower, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             lower = NULL;
         }
-        if (exists_not_none(obj, &PyId_upper)) {
+        tmp = get_not_none(obj, &PyId_upper);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_upper);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &upper, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             upper = NULL;
         }
-        if (exists_not_none(obj, &PyId_step)) {
+        tmp = get_not_none(obj, &PyId_step);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_step);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &step, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             step = NULL;
         }
@@ -7079,12 +7216,11 @@ obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena)
     if (isinstance) {
         asdl_seq* dims;
 
-        if (_PyObject_HasAttrId(obj, &PyId_dims)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_dims);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_dims);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ExtSlice field \"dims\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -7104,7 +7240,9 @@ obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"dims\" missing from ExtSlice");
+            }
             return 1;
         }
         *out = ExtSlice(dims, arena);
@@ -7118,15 +7256,16 @@ obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena)
     if (isinstance) {
         expr_ty value;
 
-        if (_PyObject_HasAttrId(obj, &PyId_value)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_value);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_value);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &value, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Index");
+            }
             return 1;
         }
         *out = Index(value, arena);
@@ -7421,34 +7560,35 @@ obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena* arena)
     asdl_seq* ifs;
     int is_async;
 
-    if (_PyObject_HasAttrId(obj, &PyId_target)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_target);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_target);
-        if (tmp == NULL) goto failed;
         res = obj2ast_expr(tmp, &target, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_iter)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_iter);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_iter);
-        if (tmp == NULL) goto failed;
         res = obj2ast_expr(tmp, &iter, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_ifs)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_ifs);
+    if (tmp != NULL) {
         int res;
         Py_ssize_t len;
         Py_ssize_t i;
-        tmp = _PyObject_GetAttrId(obj, &PyId_ifs);
-        if (tmp == NULL) goto failed;
         if (!PyList_Check(tmp)) {
             PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", tmp->ob_type->tp_name);
             goto failed;
@@ -7468,18 +7608,21 @@ obj2ast_comprehension(PyObject* obj, comprehension_ty* out, PyArena* arena)
         }
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_is_async)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_is_async);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_is_async);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &is_async, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"is_async\" missing from comprehension");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"is_async\" missing from comprehension");
+        }
         return 1;
     }
     *out = comprehension(target, iter, ifs, is_async, arena);
@@ -7502,26 +7645,28 @@ obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena)
         *out = NULL;
         return 0;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_lineno)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &lineno, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_col_offset)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &col_offset, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler");
+        }
         return 1;
     }
     isinstance = PyObject_IsInstance(obj, (PyObject*)ExceptHandler_type);
@@ -7533,32 +7678,33 @@ obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena)
         identifier name;
         asdl_seq* body;
 
-        if (exists_not_none(obj, &PyId_type)) {
+        tmp = get_not_none(obj, &PyId_type);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_type);
-            if (tmp == NULL) goto failed;
             res = obj2ast_expr(tmp, &type, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             type = NULL;
         }
-        if (exists_not_none(obj, &PyId_name)) {
+        tmp = get_not_none(obj, &PyId_name);
+        if (tmp != NULL) {
             int res;
-            tmp = _PyObject_GetAttrId(obj, &PyId_name);
-            if (tmp == NULL) goto failed;
             res = obj2ast_identifier(tmp, &name, arena);
             if (res != 0) goto failed;
             Py_CLEAR(tmp);
+        } else if (PyErr_Occurred()) {
+            return 1;
         } else {
             name = NULL;
         }
-        if (_PyObject_HasAttrId(obj, &PyId_body)) {
+        tmp = _PyObject_GetAttrId(obj, &PyId_body);
+        if (tmp != NULL) {
             int res;
             Py_ssize_t len;
             Py_ssize_t i;
-            tmp = _PyObject_GetAttrId(obj, &PyId_body);
-            if (tmp == NULL) goto failed;
             if (!PyList_Check(tmp)) {
                 PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", tmp->ob_type->tp_name);
                 goto failed;
@@ -7578,7 +7724,9 @@ obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena)
             }
             Py_CLEAR(tmp);
         } else {
-            PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler");
+            if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler");
+            }
             return 1;
         }
         *out = ExceptHandler(type, name, body, lineno, col_offset, arena);
@@ -7603,12 +7751,11 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
     arg_ty kwarg;
     asdl_seq* defaults;
 
-    if (_PyObject_HasAttrId(obj, &PyId_args)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_args);
+    if (tmp != NULL) {
         int res;
         Py_ssize_t len;
         Py_ssize_t i;
-        tmp = _PyObject_GetAttrId(obj, &PyId_args);
-        if (tmp == NULL) goto failed;
         if (!PyList_Check(tmp)) {
             PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", tmp->ob_type->tp_name);
             goto failed;
@@ -7628,25 +7775,27 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
         }
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments");
+        }
         return 1;
     }
-    if (exists_not_none(obj, &PyId_vararg)) {
+    tmp = get_not_none(obj, &PyId_vararg);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_vararg);
-        if (tmp == NULL) goto failed;
         res = obj2ast_arg(tmp, &vararg, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
+    } else if (PyErr_Occurred()) {
+        return 1;
     } else {
         vararg = NULL;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_kwonlyargs)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_kwonlyargs);
+    if (tmp != NULL) {
         int res;
         Py_ssize_t len;
         Py_ssize_t i;
-        tmp = _PyObject_GetAttrId(obj, &PyId_kwonlyargs);
-        if (tmp == NULL) goto failed;
         if (!PyList_Check(tmp)) {
             PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name);
             goto failed;
@@ -7666,15 +7815,16 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
         }
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_kw_defaults)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_kw_defaults);
+    if (tmp != NULL) {
         int res;
         Py_ssize_t len;
         Py_ssize_t i;
-        tmp = _PyObject_GetAttrId(obj, &PyId_kw_defaults);
-        if (tmp == NULL) goto failed;
         if (!PyList_Check(tmp)) {
             PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name);
             goto failed;
@@ -7694,25 +7844,27 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
         }
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments");
+        }
         return 1;
     }
-    if (exists_not_none(obj, &PyId_kwarg)) {
+    tmp = get_not_none(obj, &PyId_kwarg);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_kwarg);
-        if (tmp == NULL) goto failed;
         res = obj2ast_arg(tmp, &kwarg, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
+    } else if (PyErr_Occurred()) {
+        return 1;
     } else {
         kwarg = NULL;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_defaults)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_defaults);
+    if (tmp != NULL) {
         int res;
         Py_ssize_t len;
         Py_ssize_t i;
-        tmp = _PyObject_GetAttrId(obj, &PyId_defaults);
-        if (tmp == NULL) goto failed;
         if (!PyList_Check(tmp)) {
             PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", tmp->ob_type->tp_name);
             goto failed;
@@ -7732,7 +7884,9 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
         }
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments");
+        }
         return 1;
     }
     *out = arguments(args, vararg, kwonlyargs, kw_defaults, kwarg, defaults,
@@ -7752,47 +7906,51 @@ obj2ast_arg(PyObject* obj, arg_ty* out, PyArena* arena)
     int lineno;
     int col_offset;
 
-    if (_PyObject_HasAttrId(obj, &PyId_arg)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_arg);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_arg);
-        if (tmp == NULL) goto failed;
         res = obj2ast_identifier(tmp, &arg, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg");
+        }
         return 1;
     }
-    if (exists_not_none(obj, &PyId_annotation)) {
+    tmp = get_not_none(obj, &PyId_annotation);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_annotation);
-        if (tmp == NULL) goto failed;
         res = obj2ast_expr(tmp, &annotation, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
+    } else if (PyErr_Occurred()) {
+        return 1;
     } else {
         annotation = NULL;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_lineno)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_lineno);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &lineno, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from arg");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from arg");
+        }
         return 1;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_col_offset)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_col_offset);
-        if (tmp == NULL) goto failed;
         res = obj2ast_int(tmp, &col_offset, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from arg");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from arg");
+        }
         return 1;
     }
     *out = arg(arg, annotation, lineno, col_offset, arena);
@@ -7809,25 +7967,27 @@ obj2ast_keyword(PyObject* obj, keyword_ty* out, PyArena* arena)
     identifier arg;
     expr_ty value;
 
-    if (exists_not_none(obj, &PyId_arg)) {
+    tmp = get_not_none(obj, &PyId_arg);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_arg);
-        if (tmp == NULL) goto failed;
         res = obj2ast_identifier(tmp, &arg, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
+    } else if (PyErr_Occurred()) {
+        return 1;
     } else {
         arg = NULL;
     }
-    if (_PyObject_HasAttrId(obj, &PyId_value)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_value);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_value);
-        if (tmp == NULL) goto failed;
         res = obj2ast_expr(tmp, &value, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword");
+        }
         return 1;
     }
     *out = keyword(arg, value, arena);
@@ -7844,24 +8004,26 @@ obj2ast_alias(PyObject* obj, alias_ty* out, PyArena* arena)
     identifier name;
     identifier asname;
 
-    if (_PyObject_HasAttrId(obj, &PyId_name)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_name);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_name);
-        if (tmp == NULL) goto failed;
         res = obj2ast_identifier(tmp, &name, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias");
+        }
         return 1;
     }
-    if (exists_not_none(obj, &PyId_asname)) {
+    tmp = get_not_none(obj, &PyId_asname);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_asname);
-        if (tmp == NULL) goto failed;
         res = obj2ast_identifier(tmp, &asname, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
+    } else if (PyErr_Occurred()) {
+        return 1;
     } else {
         asname = NULL;
     }
@@ -7879,24 +8041,26 @@ obj2ast_withitem(PyObject* obj, withitem_ty* out, PyArena* arena)
     expr_ty context_expr;
     expr_ty optional_vars;
 
-    if (_PyObject_HasAttrId(obj, &PyId_context_expr)) {
+    tmp = _PyObject_GetAttrId(obj, &PyId_context_expr);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_context_expr);
-        if (tmp == NULL) goto failed;
         res = obj2ast_expr(tmp, &context_expr, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
     } else {
-        PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem");
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem");
+        }
         return 1;
     }
-    if (exists_not_none(obj, &PyId_optional_vars)) {
+    tmp = get_not_none(obj, &PyId_optional_vars);
+    if (tmp != NULL) {
         int res;
-        tmp = _PyObject_GetAttrId(obj, &PyId_optional_vars);
-        if (tmp == NULL) goto failed;
         res = obj2ast_expr(tmp, &optional_vars, arena);
         if (res != 0) goto failed;
         Py_CLEAR(tmp);
+    } else if (PyErr_Occurred()) {
+        return 1;
     } else {
         optional_vars = NULL;
     }



More information about the Python-checkins mailing list