@@ -1714,7 +1714,7 @@ static int
1714
1714
identify_unbound_names (PyThreadState * tstate , PyCodeObject * co ,
1715
1715
PyObject * globalnames , PyObject * attrnames ,
1716
1716
PyObject * globalsns , PyObject * builtinsns ,
1717
- struct co_unbound_counts * counts )
1717
+ struct co_unbound_counts * counts , int * p_numdupes )
1718
1718
{
1719
1719
// This function is inspired by inspect.getclosurevars().
1720
1720
// It would be nicer if we had something similar to co_localspluskinds,
@@ -1729,6 +1729,7 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
1729
1729
assert (builtinsns == NULL || PyDict_Check (builtinsns ));
1730
1730
assert (counts == NULL || counts -> total == 0 );
1731
1731
struct co_unbound_counts unbound = {0 };
1732
+ int numdupes = 0 ;
1732
1733
Py_ssize_t len = Py_SIZE (co );
1733
1734
for (int i = 0 ; i < len ; i += _PyInstruction_GetLength (co , i )) {
1734
1735
_Py_CODEUNIT inst = _Py_GetBaseCodeUnit (co , i );
@@ -1747,6 +1748,12 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
1747
1748
if (PySet_Add (attrnames , name ) < 0 ) {
1748
1749
return -1 ;
1749
1750
}
1751
+ if (PySet_Contains (globalnames , name )) {
1752
+ if (_PyErr_Occurred (tstate )) {
1753
+ return -1 ;
1754
+ }
1755
+ numdupes += 1 ;
1756
+ }
1750
1757
}
1751
1758
else if (inst .op .code == LOAD_GLOBAL ) {
1752
1759
int oparg = GET_OPARG (co , i , inst .op .arg );
@@ -1778,11 +1785,20 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co,
1778
1785
if (PySet_Add (globalnames , name ) < 0 ) {
1779
1786
return -1 ;
1780
1787
}
1788
+ if (PySet_Contains (attrnames , name )) {
1789
+ if (_PyErr_Occurred (tstate )) {
1790
+ return -1 ;
1791
+ }
1792
+ numdupes += 1 ;
1793
+ }
1781
1794
}
1782
1795
}
1783
1796
if (counts != NULL ) {
1784
1797
* counts = unbound ;
1785
1798
}
1799
+ if (p_numdupes != NULL ) {
1800
+ * p_numdupes = numdupes ;
1801
+ }
1786
1802
return 0 ;
1787
1803
}
1788
1804
@@ -1932,20 +1948,24 @@ _PyCode_SetUnboundVarCounts(PyThreadState *tstate,
1932
1948
1933
1949
// Fill in unbound.globals and unbound.numattrs.
1934
1950
struct co_unbound_counts unbound = {0 };
1951
+ int numdupes = 0 ;
1935
1952
Py_BEGIN_CRITICAL_SECTION (co );
1936
1953
res = identify_unbound_names (
1937
1954
tstate , co , globalnames , attrnames , globalsns , builtinsns ,
1938
- & unbound );
1955
+ & unbound , & numdupes );
1939
1956
Py_END_CRITICAL_SECTION ();
1940
1957
if (res < 0 ) {
1941
1958
goto finally ;
1942
1959
}
1943
1960
assert (unbound .numunknown == 0 );
1944
- assert (unbound .total <= counts -> unbound .total );
1961
+ assert (unbound .total - numdupes <= counts -> unbound .total );
1945
1962
assert (counts -> unbound .numunknown == counts -> unbound .total );
1946
- unbound .numunknown = counts -> unbound .total - unbound .total ;
1947
- unbound .total = counts -> unbound .total ;
1963
+ // There may be a name that is both a global and an attr.
1964
+ int totalunbound = counts -> unbound .total + numdupes ;
1965
+ unbound .numunknown = totalunbound - unbound .total ;
1966
+ unbound .total = totalunbound ;
1948
1967
counts -> unbound = unbound ;
1968
+ counts -> total += numdupes ;
1949
1969
res = 0 ;
1950
1970
1951
1971
finally :
0 commit comments