Commit b1e7dd3b authored by Orivej Desh's avatar Orivej Desh Committed by Stefan Behnel

Fix error positions of undefined builtins and constants (GH-3030)

Currently Cython generates code like this:

     int __Pyx_InitCachedBuiltins(void) {
         __pyx_builtin_NAME = __Pyx_GetBuiltinName(...);
         if (!__pyx_builtin_NAME) __PYX_ERR(1, 44, __pyx_L1_error)
     }

     int __pyx_pymod_exec_MODULE(PyObject *__pyx_pyinit_module) {
         if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(1, 1, __pyx_L1_error)
     }

When InitCachedBuiltins and InitCachedConstants call __PYX_ERR, they
pass the file and line where a builtin is used, but then pymod_exec
overwrites it with 1 and 1, and the error message looks like this:

       File "FILE", line 1, in init MODULE.
         import os
     NameError: name 'NAME' is not defined

After this change Cython generates:

     int __pyx_pymod_exec_MODULE(PyObject *__pyx_pyinit_module) {
         if (__Pyx_InitCachedBuiltins() < 0) goto __pyx_L1_error;
     }

and prints:

       File "FILE", line 44, in init MODULE.
         print(NAME)
     NameError: name 'NAME' is not defined
parent 482e17b0
...@@ -2357,6 +2357,8 @@ class CCodeWriter(object): ...@@ -2357,6 +2357,8 @@ class CCodeWriter(object):
def error_goto(self, pos): def error_goto(self, pos):
lbl = self.funcstate.error_label lbl = self.funcstate.error_label
self.funcstate.use_label(lbl) self.funcstate.use_label(lbl)
if not pos:
return 'goto %s;' % lbl
return "__PYX_ERR(%s, %s, %s)" % ( return "__PYX_ERR(%s, %s, %s)" % (
self.lookup_filename(pos[0]), self.lookup_filename(pos[0]),
pos[1], pos[1],
......
...@@ -2416,10 +2416,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2416,10 +2416,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if Options.cache_builtins: if Options.cache_builtins:
code.putln("/*--- Builtin init code ---*/") code.putln("/*--- Builtin init code ---*/")
code.put_error_if_neg(self.pos, "__Pyx_InitCachedBuiltins()") code.put_error_if_neg(None, "__Pyx_InitCachedBuiltins()")
code.putln("/*--- Constants init code ---*/") code.putln("/*--- Constants init code ---*/")
code.put_error_if_neg(self.pos, "__Pyx_InitCachedConstants()") code.put_error_if_neg(None, "__Pyx_InitCachedConstants()")
code.putln("/*--- Global type/function init code ---*/") code.putln("/*--- Global type/function init code ---*/")
......
PYTHON setup.py build_ext --inplace
PYTHON test_error_pos.py
######## setup.py ###########
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("error_pos.pyx"))
######## error_pos.pyx ###########
from os import *
abcdefg(line)
######## test_error_pos.py ###########
import subprocess
import sys
cmd = [sys.executable, '-c', 'import error_pos']
proc = subprocess.Popen(cmd, stderr=subprocess.PIPE)
_, err = proc.communicate()
# The error should contain the line number and the line text where the
# undefined identifier is used.
assert b'line 3, in init error_pos' and b'abcdefg(line)' in err, err
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment