diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst index 822c59343ca..3996c1f18d6 100644 --- a/Doc/c-api/reflection.rst +++ b/Doc/c-api/reflection.rst @@ -29,6 +29,11 @@ Reflection currently executing. +.. cfunction:: int PyFrame_GetLineNumber(PyFrameObject *frame) + + Return the line number that *frame* is currently executing. + + .. cfunction:: int PyEval_GetRestricted() If there is a current frame and it is executing in restricted mode, return true, diff --git a/Include/code.h b/Include/code.h index 0167ad4a878..cbf00d8d01d 100644 --- a/Include/code.h +++ b/Include/code.h @@ -75,6 +75,9 @@ PyAPI_FUNC(PyCodeObject *) PyCode_New( PyAPI_FUNC(PyCodeObject *) PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno); +/* Return the line number associated with the specified bytecode index + in this code object. If you just need the line number of a frame, + use PyFrame_GetLineNumber() instead. */ PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); /* for internal use only */ diff --git a/Include/frameobject.h b/Include/frameobject.h index 297b66ddb2d..17e7679ac87 100644 --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -38,8 +38,11 @@ typedef struct _frame { PyThreadState *f_tstate; int f_lasti; /* Last instruction if called */ - /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when - f_trace is set) -- at other times use PyCode_Addr2Line instead. */ + /* Call PyFrame_GetLineNumber() instead of reading this field + directly. As of 2.3 f_lineno is only valid when tracing is + active (i.e. when f_trace is set). At other times we use + PyCode_Addr2Line to calculate the line from the current + bytecode index. */ int f_lineno; /* Current line number */ int f_iblock; /* index in f_blockstack */ PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ @@ -77,6 +80,9 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); PyAPI_FUNC(int) PyFrame_ClearFreeList(void); +/* Return the line of code the frame is currently executing. */ +PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); + #ifdef __cplusplus } #endif diff --git a/Misc/NEWS b/Misc/NEWS index ba721e729e4..fa362fd929b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -927,6 +927,9 @@ Build C-API ----- +- Issue #5954: Add a PyFrame_GetLineNumber() function to replace most uses of + PyCode_Addr2Line(). + - Issue #5959: Add a PyCode_NewEmpty() function to create a new empty code object at a specified file, function, and line number. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 4ac1ab02ddf..7a9d40d8965 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -60,17 +60,19 @@ frame_getlocals(PyFrameObject *f, void *closure) return f->f_locals; } +int +PyFrame_GetLineNumber(PyFrameObject *f) +{ + if (f->f_trace) + return f->f_lineno; + else + return PyCode_Addr2Line(f->f_code, f->f_lasti); +} + static PyObject * frame_getlineno(PyFrameObject *f, void *closure) { - int lineno; - - if (f->f_trace) - lineno = f->f_lineno; - else - lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); - - return PyInt_FromLong(lineno); + return PyInt_FromLong(PyFrame_GetLineNumber(f)); } /* Setter for f_lineno - you can set f_lineno from within a trace function in @@ -351,16 +353,14 @@ frame_gettrace(PyFrameObject *f, void *closure) static int frame_settrace(PyFrameObject *f, PyObject* v, void *closure) { + PyObject* old_value; + /* We rely on f_lineno being accurate when f_trace is set. */ + f->f_lineno = PyFrame_GetLineNumber(f); - PyObject* old_value = f->f_trace; - + old_value = f->f_trace; Py_XINCREF(v); f->f_trace = v; - - if (v != NULL) - f->f_lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); - Py_XDECREF(old_value); return 0; diff --git a/Python/_warnings.c b/Python/_warnings.c index 1a7c2d51e6d..219cfc6ee19 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -454,7 +454,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, } else { globals = f->f_globals; - *lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); + *lineno = PyFrame_GetLineNumber(f); } *module = NULL; diff --git a/Python/ceval.c b/Python/ceval.c index 88b9d0e8882..474a8851db2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2698,7 +2698,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", - PyCode_Addr2Line(f->f_code, f->f_lasti), + PyFrame_GetLineNumber(f), opcode); PyErr_SetString(PyExc_SystemError, "unknown opcode"); why = WHY_EXCEPTION; diff --git a/Python/traceback.c b/Python/traceback.c index c2d7e77a3e5..1c26ba271ab 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -96,8 +96,7 @@ newtracebackobject(PyTracebackObject *next, PyFrameObject *frame) Py_XINCREF(frame); tb->tb_frame = frame; tb->tb_lasti = frame->f_lasti; - tb->tb_lineno = PyCode_Addr2Line(frame->f_code, - frame->f_lasti); + tb->tb_lineno = PyFrame_GetLineNumber(frame); PyObject_GC_Track(tb); } return tb;