With --allow-redefinition-new, mypyc generates invalid C when a nested function rebinds, through nonlocal, a parameter of the enclosing function that is annotated int. The outer function stores the unboxed int parameter straight into the closure environment's PyObject * slot. gcc rejects the C, and an MSVC build compiles with a warning and segfaults at run time.
It builds and prints 2, as it does without --allow-redefinition-new.
Actual Behavior
On Linux (gcc 14.2.0):
build/__native.c:541:49: error: assignment to 'PyObject *' {aka 'struct _object *'} from 'CPyTagged' {aka 'long unsigned int'} makes pointer from integer without a cast [-Wint-conversion]
The generated code, in f:
CPy_INCREF(cpy_r_n);
if (((repro___f_envObject*)cpy_r_r0)->_n!=NULL) {
CPy_DECREF(((repro___f_envObject*)cpy_r_r0)->_n);
}
((repro___f_envObject*)cpy_r_r0)->_n=cpy_r_n;
On Windows (MSVC, Python 3.14.6) the build succeeds and importing the module segfaults.
The same happens when the nested function is a generator or an async def. It does not happen when:
the variable is a local of the enclosing function (n = 3 in its body) rather than a parameter, even with an unannotated nested function;
the parameter is unannotated or annotated Any;
the variable is a str rather than an int;
--allow-redefinition-new is left off.
Annotating the nested function avoids it only in some cases. def inner() -> int: builds, but this still fails with the nested function annotated:
Python version used: 3.12.13 (Linux), 3.14.6 (Windows)
Operating system and version: Debian (the python:3.12 Docker image, gcc 14.2.0); Windows 11 with MSVC
Found while compiling the output of Pyfun, a language that compiles to Python and offers mypyc builds; its generated code relies on --allow-redefinition-new.
changed the title [-][mypyc] Invalid C for an int rebound via nonlocal in an unannotated nested function with --allow-redefinition-new[/-][+][mypyc] Invalid C for an int-annotated parameter rebound via nonlocal with --allow-redefinition-new[/+]on Oct 17, 2026
I've corrected the description. The trigger is a parameter of the enclosing function annotated int, not an unannotated nested function. A local variable of the enclosing function never reproduced it, and annotating the nested function doesn't reliably avoid it: the description now includes an annotated example that still fails. Checked on 2.4.0 and master at 9f5e075.
Activity
native: a parameter rebound through nonlocal stays unannotated (#174)
simontreanor commented on Oct 17, 2026
I've corrected the description. The trigger is a parameter of the enclosing function annotated int, not an unannotated nested function. A local variable of the enclosing function never reproduced it, and annotating the nested function doesn't reliably avoid it: the description now includes an annotated example that still fails. Checked on 2.4.0 and master at 9f5e075.
async: an Async value is cold and runs again on every await (#177)