From aba42c0b547e6395c9c268cf98a298d0494cb9df Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:05:00 +0100 Subject: [PATCH] gh-123969: refactor _PyErr_RaiseSyntaxError and _PyErr_EmitSyntaxWarning out of compiler (#123972) --- Include/internal/pycore_compile.h | 2 -- Include/internal/pycore_pyerrors.h | 5 ++++ Python/compile.c | 37 +++++------------------- Python/errors.c | 46 ++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index f089eb05097..9f0ca33892a 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -33,8 +33,6 @@ extern int _PyCompile_AstOptimize( int optimize, struct _arena *arena); -struct _Py_SourceLocation; - extern int _PyAST_Optimize( struct _mod *, struct _arena *arena, diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index 9835e495d17..02945f0e71a 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -120,6 +120,11 @@ extern void _PyErr_SetNone(PyThreadState *tstate, PyObject *exception); extern PyObject* _PyErr_NoMemory(PyThreadState *tstate); +extern int _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset, + int end_lineno, int end_col_offset); +extern void _PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_offset, + int end_lineno, int end_col_offset); + PyAPI_FUNC(void) _PyErr_SetString( PyThreadState *tstate, PyObject *exception, diff --git a/Python/compile.c b/Python/compile.c index cdd48782575..7b3e6f336e4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1112,27 +1112,15 @@ _PyCompile_Error(compiler *c, location loc, const char *format, ...) if (msg == NULL) { return ERROR; } - PyObject *loc_obj = PyErr_ProgramTextObject(c->c_filename, loc.lineno); - if (loc_obj == NULL) { - loc_obj = Py_None; - } - PyObject *args = Py_BuildValue("O(OiiOii)", msg, c->c_filename, - loc.lineno, loc.col_offset + 1, loc_obj, - loc.end_lineno, loc.end_col_offset + 1); + _PyErr_RaiseSyntaxError(msg, c->c_filename, loc.lineno, loc.col_offset + 1, + loc.end_lineno, loc.end_col_offset + 1); Py_DECREF(msg); - if (args == NULL) { - goto exit; - } - PyErr_SetObject(PyExc_SyntaxError, args); - exit: - Py_DECREF(loc_obj); - Py_XDECREF(args); return ERROR; } -/* Emits a SyntaxWarning and returns 1 on success. +/* Emits a SyntaxWarning and returns 0 on success. If a SyntaxWarning raised as error, replaces it with a SyntaxError - and returns 0. + and returns -1. */ int _PyCompile_Warn(compiler *c, location loc, const char *format, ...) @@ -1144,21 +1132,10 @@ _PyCompile_Warn(compiler *c, location loc, const char *format, ...) if (msg == NULL) { return ERROR; } - if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, c->c_filename, - loc.lineno, NULL, NULL) < 0) - { - if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { - /* Replace the SyntaxWarning exception with a SyntaxError - to get a more accurate error report */ - PyErr_Clear(); - assert(PyUnicode_AsUTF8(msg) != NULL); - _PyCompile_Error(c, loc, PyUnicode_AsUTF8(msg)); - } - Py_DECREF(msg); - return ERROR; - } + int ret = _PyErr_EmitSyntaxWarning(msg, c->c_filename, loc.lineno, loc.col_offset + 1, + loc.end_lineno, loc.end_col_offset + 1); Py_DECREF(msg); - return SUCCESS; + return ret; } PyObject * diff --git a/Python/errors.c b/Python/errors.c index ad6b7dbef07..29249ac41c6 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1850,6 +1850,52 @@ PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset) Py_XDECREF(fileobj); } +/* Raises a SyntaxError. + * If something goes wrong, a different exception may be raised. + */ +void +_PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_offset, + int end_lineno, int end_col_offset) +{ + PyObject *text = PyErr_ProgramTextObject(filename, lineno); + if (text == NULL) { + text = Py_NewRef(Py_None); + } + PyObject *args = Py_BuildValue("O(OiiOii)", msg, filename, + lineno, col_offset, text, + end_lineno, end_col_offset); + if (args == NULL) { + goto exit; + } + PyErr_SetObject(PyExc_SyntaxError, args); + exit: + Py_DECREF(text); + Py_XDECREF(args); +} + +/* Emits a SyntaxWarning and returns 0 on success. + If a SyntaxWarning is raised as error, replaces it with a SyntaxError + and returns -1. +*/ +int +_PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset, + int end_lineno, int end_col_offset) +{ + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, filename, + lineno, NULL, NULL) < 0) + { + if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { + /* Replace the SyntaxWarning exception with a SyntaxError + to get a more accurate error report */ + PyErr_Clear(); + _PyErr_RaiseSyntaxError(msg, filename, lineno, col_offset, + end_lineno, end_col_offset); + } + return -1; + } + return 0; +} + /* Attempt to load the line of text that the exception refers to. If it fails, it will return NULL but will not set an exception.