Repository: cython/cython

Issue:
Compiler crash in AnalyseDeclarationsTransform
This is with Cython 0.29.7 and Python 3.6.7.  There are several other issues that report "Compiler crash in AnalyseDeclarationsTransform", but I couldn't tell if this issue is a duplicate of one of those.

Cython code "example.pyx":

```
import math

def func(double x):
    return cfunc(x)

cdef double cfunc(double x) except math.nan:
    return x
```

Result:

```
running build
running build_ext
cythoning example.pyx to example.c
/Users/warren/miniconda36b/lib/python3.6/site-packages/Cython/Compiler/Main.py:367: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /Users/warren/code_snippets/python/cython/exception-in-cdef-function/example.pyx
  tree = Parsing.p_module(s, pxd, full_module_name)

Error compiling Cython file:
------------------------------------------------------------
...
import math

def func(double x):
    return cfunc(x)

cdef double cfunc(double x) except math.nan:
                                      ^
------------------------------------------------------------

example.pyx:8:39: Not allowed in a constant expression

Error compiling Cython file:
------------------------------------------------------------
...
import math

def func(double x):
    return cfunc(x)

cdef double cfunc(double x) except math.nan:
                                      ^
------------------------------------------------------------

example.pyx:8:39: Not allowed in a constant expression

Error compiling Cython file:
------------------------------------------------------------
...
import math

def func(double x):
    return cfunc(x)

cdef double cfunc(double x) except math.nan:
                ^
------------------------------------------------------------

example.pyx:8:17: Compiler crash in AnalyseDeclarationsTransform

File 'ModuleNode.py', line 124, in analyse_declarations: ModuleNode(example.pyx:1:0,
    full_module_name = 'example')
File 'Nodes.py', line 431, in analyse_declarations: StatListNode(example.pyx:3:0)
File 'Nodes.py', line 431, in analyse_declarations: StatListNode(example.pyx:8:5)
File 'Nodes.py', line 2358, in analyse_declarations: CFuncDefNode(example.pyx:8:5,
    modifiers = [...]/0,
    visibility = 'private')
File 'Nodes.py', line 757, in analyse: CFuncDeclaratorNode(example.pyx:8:17,
    calling_convention = '')

Compiler crash traceback from this point on:
  File "/Users/warren/miniconda36b/lib/python3.6/site-packages/Cython/Compiler/Nodes.py", line 757, in analyse
    self.exception_value.__class__.__name__)
InternalError: Internal compiler error: get_constant_c_result_code not implemented for CoerceFromPyTypeNode
building 'example' extension
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/warren/miniconda36b/include -arch x86_64 -I/Users/warren/miniconda36b/include -arch x86_64 -I/Users/warren/miniconda36b/include/python3.6m -c example.c -o build/temp.macosx-10.7-x86_64-3.6/example.o
example.c:1:2: error: Do not use this file, it is the result of a failed Cython compilation.
#error Do not use this file, it is the result of a failed Cython compilation.
 ^
1 error generated.
error: command 'gcc' failed with exit status 1
```



Discussion:

Resolving patch:
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -734,8 +734,8 @@ def analyse(self, return_type, env, nonempty=0, directive_locals=None, visibilit
                         self.exception_value = ConstNode(
                             self.pos, value=return_type.exception_value, type=return_type)
             if self.exception_value:
-                self.exception_value = self.exception_value.analyse_const_expression(env)
                 if self.exception_check == '+':
+                    self.exception_value = self.exception_value.analyse_const_expression(env)
                     exc_val_type = self.exception_value.type
                     if (not exc_val_type.is_error
                             and not exc_val_type.is_pyobject
@@ -748,13 +748,11 @@ def analyse(self, return_type, env, nonempty=0, directive_locals=None, visibilit
                               "Exception value must be a Python exception or cdef function with no arguments or *.")
                     exc_val = self.exception_value
                 else:
-                    self.exception_value = self.exception_value.coerce_to(
+                    self.exception_value = self.exception_value.analyse_types(env).coerce_to(
                         return_type, env).analyse_const_expression(env)
                     exc_val = self.exception_value.get_constant_c_result_code()
                     if exc_val is None:
-                        raise InternalError(
-                            "get_constant_c_result_code not implemented for %s" %
-                            self.exception_value.__class__.__name__)
+                        error(self.exception_value.pos, "Exception value must be constant")
                     if not return_type.assignable_from(self.exception_value.type):
                         error(self.exception_value.pos,
                               "Exception value incompatible with function return type")


Test patch:
diff --git a/tests/errors/nonconst_excval.pyx b/tests/errors/nonconst_excval.pyx
new file mode 100644
--- /dev/null
+++ b/tests/errors/nonconst_excval.pyx
@@ -0,0 +1,12 @@
+# mode: error
+
+import math
+
+cdef double cfunc(double x) except math.nan:
+    return x
+
+
+_ERRORS = """
+5:39: Exception value must be constant
+5:39: Not allowed in a constant expression
+"""