Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
312595ce
Commit
312595ce
authored
May 15, 2013
by
Benjamin Peterson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hide the __class__ closure from the class body (#12370)
parent
fe361dfa
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
221 additions
and
152 deletions
+221
-152
Include/symtable.h
Include/symtable.h
+3
-0
Lib/importlib/_bootstrap.py
Lib/importlib/_bootstrap.py
+2
-1
Lib/test/test_super.py
Lib/test/test_super.py
+26
-2
Misc/NEWS
Misc/NEWS
+3
-0
Python/compile.c
Python/compile.c
+49
-15
Python/importlib.h
Python/importlib.h
+119
-119
Python/symtable.c
Python/symtable.c
+19
-15
No files found.
Include/symtable.h
View file @
312595ce
...
...
@@ -53,6 +53,9 @@ typedef struct _symtable_entry {
unsigned
ste_varkeywords
:
1
;
/* true if block has varkeywords */
unsigned
ste_returns_value
:
1
;
/* true if namespace uses return with
an argument */
unsigned
ste_needs_class_closure
:
1
;
/* for class scopes, true if a
closure over __class__
should be created */
int
ste_lineno
;
/* first line of block */
int
ste_col_offset
;
/* offset of first line of block */
int
ste_opt_lineno
;
/* lineno of last exec or import * */
...
...
Lib/importlib/_bootstrap.py
View file @
312595ce
...
...
@@ -390,12 +390,13 @@ def _call_with_frames_removed(f, *args, **kwds):
# keyword-only defaults)
# Python 3.4a1 3260 (add LOAD_CLASSDEREF; allow locals of class to override
# free vars)
# Python 3.4a1 3270 (various tweaks to the __class_ closure)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually
# due to the addition of new opcodes).
_MAGIC_BYTES
=
(
32
6
0
).
to_bytes
(
2
,
'little'
)
+
b'
\
r
\
n
'
_MAGIC_BYTES
=
(
32
7
0
).
to_bytes
(
2
,
'little'
)
+
b'
\
r
\
n
'
_RAW_MAGIC_NUMBER
=
int
.
from_bytes
(
_MAGIC_BYTES
,
'little'
)
_PYCACHE
=
'__pycache__'
...
...
Lib/test/test_super.py
View file @
312595ce
...
...
@@ -81,8 +81,7 @@ class TestSuper(unittest.TestCase):
self
.
assertEqual
(
E
().
f
(),
'AE'
)
@
unittest
.
expectedFailure
def
test___class___set
(
self
):
def
test_various___class___pathologies
(
self
):
# See issue #12370
class
X
(
A
):
def
f
(
self
):
...
...
@@ -91,6 +90,31 @@ class TestSuper(unittest.TestCase):
x
=
X
()
self
.
assertEqual
(
x
.
f
(),
'A'
)
self
.
assertEqual
(
x
.
__class__
,
413
)
class
X
:
x
=
__class__
def
f
():
__class__
self
.
assertIs
(
X
.
x
,
type
(
self
))
with
self
.
assertRaises
(
NameError
)
as
e
:
exec
(
"""class X:
__class__
def f():
__class__"""
,
globals
(),
{})
self
.
assertIs
(
type
(
e
.
exception
),
NameError
)
# Not UnboundLocalError
class
X
:
global
__class__
__class__
=
42
def
f
():
__class__
self
.
assertEqual
(
globals
()[
"__class__"
],
42
)
del
globals
()[
"__class__"
]
self
.
assertNotIn
(
"__class__"
,
X
.
__dict__
)
class
X
:
nonlocal
__class__
__class__
=
42
def
f
():
__class__
self
.
assertEqual
(
__class__
,
42
)
def
test___class___instancemethod
(
self
):
# See issue #14857
...
...
Misc/NEWS
View file @
312595ce
...
...
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins
-----------------
- Issue #12370: Prevent class bodies from interfering with the __class__
closure.
- Issue #17237: Fix crash in the ASCII decoder on m68k.
- Issue #17927: Frame objects kept arguments alive if they had been
...
...
Python/compile.c
View file @
312595ce
...
...
@@ -535,6 +535,37 @@ compiler_enter_scope(struct compiler *c, identifier name,
compiler_unit_free
(
u
);
return
0
;
}
if
(
u
->
u_ste
->
ste_needs_class_closure
)
{
/* Cook up a implicit __class__ cell. */
_Py_IDENTIFIER
(
__class__
);
PyObject
*
tuple
,
*
name
,
*
zero
;
int
res
;
assert
(
u
->
u_scope_type
==
COMPILER_SCOPE_CLASS
);
assert
(
PyDict_Size
(
u
->
u_cellvars
)
==
0
);
name
=
_PyUnicode_FromId
(
&
PyId___class__
);
if
(
!
name
)
{
compiler_unit_free
(
u
);
return
0
;
}
tuple
=
PyTuple_Pack
(
2
,
name
,
Py_TYPE
(
name
));
if
(
!
tuple
)
{
compiler_unit_free
(
u
);
return
0
;
}
zero
=
PyLong_FromLong
(
0
);
if
(
!
zero
)
{
Py_DECREF
(
tuple
);
compiler_unit_free
(
u
);
return
0
;
}
res
=
PyDict_SetItem
(
u
->
u_cellvars
,
tuple
,
zero
);
Py_DECREF
(
tuple
);
Py_DECREF
(
zero
);
if
(
res
<
0
)
{
compiler_unit_free
(
u
);
return
0
;
}
}
u
->
u_freevars
=
dictbytype
(
u
->
u_ste
->
ste_symbols
,
FREE
,
DEF_FREE_CLASS
,
PyDict_Size
(
u
->
u_cellvars
));
...
...
@@ -1331,6 +1362,9 @@ compiler_mod(struct compiler *c, mod_ty mod)
static
int
get_ref_type
(
struct
compiler
*
c
,
PyObject
*
name
)
{
if
(
c
->
u
->
u_scope_type
==
COMPILER_SCOPE_CLASS
&&
!
PyUnicode_CompareWithASCIIString
(
name
,
"__class__"
))
return
CELL
;
int
scope
=
PyST_GetScope
(
c
->
u
->
u_ste
,
name
);
if
(
scope
==
0
)
{
char
buf
[
350
];
...
...
@@ -1704,24 +1738,24 @@ compiler_class(struct compiler *c, stmt_ty s)
compiler_exit_scope
(
c
);
return
0
;
}
/* return the (empty) __class__ cell */
str
=
PyUnicode_InternFromString
(
"__class__"
);
if
(
str
==
NULL
)
{
compiler_exit_scope
(
c
);
return
0
;
}
i
=
compiler_lookup_arg
(
c
->
u
->
u_cellvars
,
str
);
Py_DECREF
(
str
);
if
(
i
==
-
1
)
{
/* This happens when nobody references the cell */
PyErr_Clear
();
/* Return None */
ADDOP_O
(
c
,
LOAD_CONST
,
Py_None
,
consts
);
}
else
{
if
(
c
->
u
->
u_ste
->
ste_needs_class_closure
)
{
/* return the (empty) __class__ cell */
str
=
PyUnicode_InternFromString
(
"__class__"
);
if
(
str
==
NULL
)
{
compiler_exit_scope
(
c
);
return
0
;
}
i
=
compiler_lookup_arg
(
c
->
u
->
u_cellvars
,
str
);
Py_DECREF
(
str
);
assert
(
i
==
0
);
/* Return the cell where to store __class__ */
ADDOP_I
(
c
,
LOAD_CLOSURE
,
i
);
}
else
{
assert
(
PyDict_Size
(
c
->
u
->
u_cellvars
)
==
0
);
/* This happens when nobody references the cell. Return None. */
ADDOP_O
(
c
,
LOAD_CONST
,
Py_None
,
consts
);
}
ADDOP_IN_SCOPE
(
c
,
RETURN_VALUE
);
/* create the code object */
co
=
assemble
(
c
,
1
);
...
...
Python/importlib.h
View file @
312595ce
This diff is collapsed.
Click to expand it.
Python/symtable.c
View file @
312595ce
...
...
@@ -77,6 +77,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
ste
->
ste_child_free
=
0
;
ste
->
ste_generator
=
0
;
ste
->
ste_returns_value
=
0
;
ste
->
ste_needs_class_closure
=
0
;
if
(
PyDict_SetItem
(
st
->
st_blocks
,
ste
->
ste_id
,
(
PyObject
*
)
ste
)
<
0
)
goto
fail
;
...
...
@@ -514,13 +515,10 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
Note that the current block's free variables are included in free.
That's safe because no name can be free and local in the same scope.
The 'restricted' argument may be set to a string to restrict the analysis
to the one variable whose name equals that string (e.g. "__class__").
*/
static
int
analyze_cells
(
PyObject
*
scopes
,
PyObject
*
free
,
const
char
*
restricted
)
analyze_cells
(
PyObject
*
scopes
,
PyObject
*
free
)
{
PyObject
*
name
,
*
v
,
*
v_cell
;
int
success
=
0
;
...
...
@@ -537,9 +535,6 @@ analyze_cells(PyObject *scopes, PyObject *free, const char *restricted)
continue
;
if
(
!
PySet_Contains
(
free
,
name
))
continue
;
if
(
restricted
!=
NULL
&&
PyUnicode_CompareWithASCIIString
(
name
,
restricted
))
continue
;
/* Replace LOCAL with CELL for this name, and remove
from free. It is safe to replace the value of name
in the dict, because it will not cause a resize.
...
...
@@ -555,6 +550,20 @@ analyze_cells(PyObject *scopes, PyObject *free, const char *restricted)
return
success
;
}
static
int
drop_class_free
(
PySTEntryObject
*
ste
,
PyObject
*
free
)
{
int
res
;
if
(
!
GET_IDENTIFIER
(
__class__
))
return
0
;
res
=
PySet_Discard
(
free
,
__class__
);
if
(
res
<
0
)
return
0
;
if
(
res
)
ste
->
ste_needs_class_closure
=
1
;
return
1
;
}
/* Check for illegal statements in unoptimized namespaces */
static
int
check_unoptimized
(
const
PySTEntryObject
*
ste
)
{
...
...
@@ -785,7 +794,6 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
/* Special-case __class__ */
if
(
!
GET_IDENTIFIER
(
__class__
))
goto
error
;
assert
(
PySet_Contains
(
local
,
__class__
)
==
1
);
if
(
PySet_Add
(
newbound
,
__class__
)
<
0
)
goto
error
;
}
...
...
@@ -818,11 +826,9 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
Py_DECREF
(
temp
);
/* Check if any local variables must be converted to cell variables */
if
(
ste
->
ste_type
==
FunctionBlock
&&
!
analyze_cells
(
scopes
,
newfree
,
NULL
))
if
(
ste
->
ste_type
==
FunctionBlock
&&
!
analyze_cells
(
scopes
,
newfree
))
goto
error
;
else
if
(
ste
->
ste_type
==
ClassBlock
&&
!
analyze_cells
(
scopes
,
newfree
,
"__class__"
))
else
if
(
ste
->
ste_type
==
ClassBlock
&&
!
drop_class_free
(
ste
,
newfree
))
goto
error
;
/* Records the results of the analysis in the symbol table entry */
if
(
!
update_symbols
(
ste
->
ste_symbols
,
scopes
,
bound
,
newfree
,
...
...
@@ -1179,9 +1185,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
if
(
!
symtable_enter_block
(
st
,
s
->
v
.
ClassDef
.
name
,
ClassBlock
,
(
void
*
)
s
,
s
->
lineno
,
s
->
col_offset
))
VISIT_QUIT
(
st
,
0
);
if
(
!
GET_IDENTIFIER
(
__class__
)
||
!
symtable_add_def
(
st
,
__class__
,
DEF_LOCAL
)
||
!
GET_IDENTIFIER
(
__locals__
)
||
if
(
!
GET_IDENTIFIER
(
__locals__
)
||
!
symtable_add_def
(
st
,
__locals__
,
DEF_PARAM
))
{
symtable_exit_block
(
st
,
s
);
VISIT_QUIT
(
st
,
0
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment