From a522dfd7145d99a6a46f9dfb7aab3bc2967cf8f1 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 24 Feb 2011 12:03:13 -0500 Subject: [PATCH] Move Entry.visibility into Binding.* attributes. --- Cython/Compiler/Binding.py | 2 +- Cython/Compiler/Code.py | 14 ++-- Cython/Compiler/ModuleNode.py | 34 +++++----- Cython/Compiler/Nodes.py | 15 +++-- Cython/Compiler/ParseTreeTransforms.py | 10 +-- Cython/Compiler/PyrexTypes.py | 2 +- Cython/Compiler/Symtab.py | 92 ++++++++++++++++++++------ Cython/Compiler/TypeSlots.py | 6 +- 8 files changed, 119 insertions(+), 56 deletions(-) diff --git a/Cython/Compiler/Binding.py b/Cython/Compiler/Binding.py index a14cca17..f2abd89c 100644 --- a/Cython/Compiler/Binding.py +++ b/Cython/Compiler/Binding.py @@ -68,5 +68,5 @@ class PythonBinding(CtxAttribute): class methods. """ name = None - visibility = 'private' + visibility = 'public' #private' overridable = 0 diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 6e87df9d..e5ff8964 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -1112,25 +1112,25 @@ class CCodeWriter(object): #print "Code.put_var_declaration:", entry.python_binding.name, "definition =", definition ### if entry.in_closure: return - visibility = entry.visibility - if visibility == 'private' and not definition: + if entry.c_binding.visibility == 'private' and not definition: #print "...private and not definition, skipping" ### return - if not entry.used and visibility == "private": + if entry.c_binding.visibility == 'private' and not entry.used: #print "not used and private, skipping", entry.c_binding.name ### return storage_class = "" - if visibility == 'extern': + if entry.c_source.extern: storage_class = Naming.extern_c_macro - elif visibility == 'public': + elif entry.c_binding.visibility == 'public': if not definition: storage_class = Naming.extern_c_macro - elif visibility == 'private': + elif entry.c_binding.visibility == 'private': if static: storage_class = "static" if storage_class: self.put("%s " % storage_class) - if visibility != 'public': + if (entry.c_source.extern or + entry.c_binding.visibility != 'public'): dll_linkage = None self.put(entry.type.declaration_code(entry.c_binding.name, dll_linkage = dll_linkage)) diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 6b1e2ae1..9d9124f2 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -98,7 +98,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_h_code(self, env, options, result): def h_entries(entries, pxd = 0): return [entry for entry in entries - if entry.visibility == 'public' or pxd and entry.defined_in_pxd] + if (entry.c_binding.visibility == 'public' and + not entry.c_source.extern) + or pxd and entry.defined_in_pxd] h_types = h_entries(env.type_entries) h_vars = h_entries(env.var_entries) h_funcs = h_entries(env.cfunc_entries) @@ -165,7 +167,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if entry.c_binding.api: api_funcs.append(entry) for entry in env.c_class_entries: - if entry.visibility == 'public': + if entry.c_binding.visibility == 'public': public_extension_types.append(entry) if entry.c_binding.api: has_api_extension_types = 1 @@ -876,11 +878,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("") name = entry.type.typeobj_cname if name: - if entry.visibility == 'extern' and not entry.in_cinclude: + if entry.c_source.extern and not entry.in_cinclude: code.putln("%s DL_IMPORT(PyTypeObject) %s;" % ( Naming.extern_c_macro, name)) - elif entry.visibility == 'public': + elif entry.c_binding.visibility == 'public': code.putln("%s DL_EXPORT(PyTypeObject) %s;" % ( Naming.extern_c_macro, name)) @@ -965,8 +967,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_cfunction_predeclarations(self, env, code, definition): for entry in env.cfunc_entries: if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition - or entry.defined_in_pxd or entry.visibility == 'extern')): - if entry.visibility in ('public', 'extern'): + or entry.defined_in_pxd or entry.c_source.extern)): + if (entry.c_source.extern or + entry.c_binding.visibility == 'public'): dll_linkage = "DL_EXPORT" else: dll_linkage = None @@ -975,9 +978,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): type = CPtrType(type) header = type.declaration_code(entry.c_binding.name, dll_linkage = dll_linkage) - if entry.visibility == 'private': + if entry.c_binding.visibility == 'private': storage_class = "static " - elif entry.visibility == 'public': + elif (entry.c_binding.visibility == 'public' and + not entry.c_source.extern): storage_class = "" else: storage_class = "%s " % Naming.extern_c_macro @@ -995,8 +999,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): full_module_name = env.qualified_name for entry in env.c_class_entries: #print "generate_typeobj_definitions:", entry.python_binding.name - #print "...visibility =", entry.visibility - if entry.visibility != 'extern': + #print "...c_binding.visibility =", entry.c_binding.visibility + if not entry.c_source.extern: type = entry.type scope = type.scope if scope: # could be None if there was an error @@ -1614,7 +1618,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): for suite in TypeSlots.substructures: suite.generate_substructure(scope, code) code.putln("") - if entry.visibility == 'public': + if entry.c_binding.visibility == 'public': header = "DL_EXPORT(PyTypeObject) %s = {" else: header = "static PyTypeObject %s = {" @@ -1868,7 +1872,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): rev_entries = list(env.var_entries) rev_entries.reverse() for entry in rev_entries: - if entry.visibility != 'extern': + if not entry.c_source.extern: if entry.type.is_pyobject and entry.used: code.putln("Py_DECREF(%s); %s = 0;" % ( code.entry_as_pyobject(entry), @@ -1991,7 +1995,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # Generate code to initialise global PyObject * # variables to None. for entry in env.var_entries: - if entry.visibility != 'extern': + if not entry.c_source.extern: if entry.type.is_pyobject and entry.used: code.put_init_var_to_py_none(entry, nanny=False) @@ -2045,7 +2049,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): # Generate type import code for extern extension types # and type ready code for non-extern ones. for entry in env.c_class_entries: - if entry.visibility == 'extern': + if entry.c_source.extern: self.generate_type_import_code(env, entry.type, entry.pos, code) else: self.generate_base_type_import_code(env, entry, code) @@ -2123,7 +2127,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): typeobj_cname = type.typeobj_cname scope = type.scope if scope: # could be None if there was an error - if entry.visibility != 'extern': + if not entry.c_source.extern: for slot in TypeSlots.slot_table: slot.generate_dynamic_init_code(scope, code) code.putln( diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 3a3242cb..6796f26b 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1119,9 +1119,14 @@ class CEnumDefItemNode(StatNode): if not self.value.type.is_int: self.value = self.value.coerce_to(PyrexTypes.c_int_type, env) self.value.analyse_const_expression(env) + visibility = 'private' + if enum_entry.c_source.extern: + visibility = 'extern' + elif enum_entry.c_binding.visibility != 'private': + visibility = enum_entry.c_binding.visibility entry = env.declare_const(self.name, enum_entry.type, self.value, self.pos, cname = self.cname, - visibility = enum_entry.visibility) + visibility = visibility) enum_entry.enum_values.append(entry) @@ -1742,7 +1747,6 @@ class CFuncDefNode(FuncDefNode): def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None): arg_decls = [] type = self.type - visibility = self.entry.visibility for arg in type.args[:len(type.args)-type.optional_arg_count]: arg_decls.append(arg.declaration_code()) if with_dispatch and self.overridable: @@ -1756,15 +1760,16 @@ class CFuncDefNode(FuncDefNode): if cname is None: cname = self.entry.func_cname entity = type.function_header_code(cname, ', '.join(arg_decls)) - if visibility == 'public': + if (self.entry.c_binding.visibility == 'public' and + not self.entry.c_source.extern): dll_linkage = "DL_EXPORT" else: dll_linkage = None header = self.return_type.declaration_code(entity, dll_linkage = dll_linkage) - if visibility == 'extern': + if self.entry.c_source.extern: storage_class = "%s " % Naming.extern_c_macro - elif visibility == 'public': + elif self.entry.c_binding.visibility == 'public': storage_class = "" else: storage_class = "static " diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 8d655890..1d6eab62 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -1127,7 +1127,7 @@ property NAME: def visit_CNameDeclaratorNode(self, node): if node.name in self.seen_vars_stack[-1]: entry = self.env_stack[-1].lookup(node.name) - if entry is None or entry.visibility != 'extern': + if entry is None or not entry.c_source.extern: warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2) self.visitchildren(node) return node @@ -1138,13 +1138,15 @@ property NAME: return None def create_Property(self, entry): - if entry.visibility == 'public': + if entry.python_binding.visibility == 'public': if entry.type.is_pyobject: template = self.basic_pyobject_property else: template = self.basic_property - elif entry.visibility == 'readonly': + elif entry.python_binding.visibility == 'readonly': template = self.basic_property_ro + else: + raise NotImplementedError('private python methods') property = template.substitute({ u"ATTR": ExprNodes.AttributeNode( pos=entry.pos, @@ -1651,7 +1653,7 @@ class DebugTransform(CythonTransform): self.nested_funcdefs.append(node) return node - # node.entry.visibility = 'extern' + # node.entry.c_source.extern if node.py_func is None: pf_cname = '' else: diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index e95b711e..5694f5ef 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -2019,7 +2019,7 @@ class CStructOrUnionType(CType): self.to_py_function = None self._convert_code = False return False - forward_decl = (self.entry.visibility != 'extern') + forward_decl = not self.entry.c_source.extern self._convert_code = StructUtilityCode(self, forward_decl) env.use_utility_code(self._convert_code) diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 1cfec0f1..8344e3ea 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -65,7 +65,6 @@ class Entry(object): # type PyrexType Type of entity # doc string Doc string # init string Initial value - # visibility 'private' or 'public' or 'extern' # is_builtin boolean Is an entry in the Python builtins dict # is_cglobal boolean Is a C global variable # is_pyglobal boolean Is a Python module-level variable @@ -132,7 +131,6 @@ class Entry(object): inline_func_in_pxd = False borrowed = 0 init = "" - visibility = 'private' is_builtin = 0 is_cglobal = 0 is_pyglobal = 0 @@ -357,6 +355,15 @@ class Scope(object): error(pos, "'%s' redeclared " % name) entry = Entry(name, cname, type, pos = pos) entry.in_cinclude = self.in_cinclude + if visibility == 'extern': + entry.c_source.extern = 1 + entry.c_binding.visibility = 'public' + elif self.outer_scope and visibility not in ('readonly',): + entry.c_binding.visibility = visibility + else: + entry.python_binding.visibility = visibility + if entry.python_binding.visibility != 'private': + entry.c_binding.visibility = 'public' if name: entry.qualified_name = self.qualify_name(name) # if name in entries and self.is_cpp(): @@ -365,7 +372,6 @@ class Scope(object): # entries[name] = entry entries[name] = entry entry.scope = self - entry.visibility = visibility return entry def qualify_name(self, name): @@ -488,10 +494,29 @@ class Scope(object): entry.python_binding.name, ("cdef", "ctypedef")[entry.type.typedef_flag])) - def check_previous_visibility(self, entry, visibility, pos): - if entry.visibility != visibility: - error(pos, "'%s' previously declared as '%s'" % ( - entry.python_binding.name, entry.visibility)) + def _check_previous_visibility(self, entry, visibility): + # Compare the visibility of `entry` with a second + # `visibility`. If there is a difference, return a string + # representing the conflicting `entry` visibility, otherwise + # return an empty string. + if visibility == 'extern': + if not entry.c_source.extern: + return 'extern' + elif self.outer_scope: + if visibility != entry.c_binding.visibility: + return entry.c_binding.visibility + elif visibility != entry.python_binding.visibility: + if visibilty != entry.c_binding.visibility: + return entry.python_binding.visibility + + def check_previous_visibility(self, entry, visibility, pos, + type_name=None): + vis_diff = self._check_previous_visibility(entry, visibility) + if vis_diff: + if not type_name: + type_name = type(entry) + error(pos, "%s '%s' previously declared as '%s'" % ( + type_name, entry.python_binding.name, vis_diff)) def declare_enum(self, name, pos, cname, typedef_flag, visibility = 'private'): @@ -586,10 +611,14 @@ class Scope(object): cname = self.mangle(Naming.func_prefix, name) entry = self.lookup_here(name) if entry: - if visibility != 'private' and visibility != entry.visibility: - warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1) + if visibility != 'private': + vis_diff = self._check_previous_visibility(entry, visibility) + if vis_diff: + warning( + pos, "Function '%s' previously declared as '%s'" % ( + name, vis_diff), 1) if not entry.type.same_as(type): - if visibility == 'extern' and entry.visibility == 'extern': + if visibility == 'extern' and entry.c_source.extern: can_override = False if self.is_cpp(): can_override = True @@ -1120,9 +1149,9 @@ class ModuleScope(Scope): entry.defined_in_pxd = 1 if implementing: # So that filenames in runtime exceptions refer to entry.pos = pos # the .pyx file and not the .pxd file - if visibility != 'private' and entry.visibility != visibility: - error(pos, "Class '%s' previously declared as '%s'" - % (name, entry.visibility)) + if visibility != 'private': + self.check_previous_visibility( + entry, visibility, pos, type_name='Class') if api: entry.c_binding.api = 1 if objstruct_cname: @@ -1193,12 +1222,11 @@ class ModuleScope(Scope): def check_c_class(self, entry): type = entry.type name = entry.python_binding.name - visibility = entry.visibility # Check defined if not type.scope: error(entry.pos, "C class '%s' is declared but not defined" % name) # Generate typeobj_cname - if visibility != 'extern' and not type.typeobj_cname: + if not entry.c_source.extern and not type.typeobj_cname: type.typeobj_cname = self.mangle(Naming.typeobj_prefix, name) ## Generate typeptr_cname #type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name) @@ -1235,7 +1263,11 @@ class ModuleScope(Scope): if debug_check_c_classes: print("...entry %s %s" % (entry.python_binding.name, entry)) print("......type = ", entry.type) - print("......visibility = ", entry.visibility) + print("......extern = ", entry.c_source.extern) + print("......c_binding.visibility = ", + entry.c_binding.visibility) + print("......python_binding.visibility = ", + entry.python.binding.visibility) self.check_c_class(entry) def check_c_functions(self): @@ -1245,7 +1277,7 @@ class ModuleScope(Scope): if entry.is_cfunction: if (entry.defined_in_pxd and entry.scope is self - and entry.visibility != 'extern' + and not entry.c_source.extern and not entry.in_cinclude and not entry.is_implemented): error(entry.pos, "Non-extern C function '%s' declared but not defined" % name) @@ -1693,10 +1725,15 @@ class CClassScope(ClassScope): entry.is_variable = 1 self.inherited_var_entries.append(entry) for base_entry in base_scope.cfunc_entries: + visibility = 'private' + if base_entry.c_source.extern: + visibility = 'extern' + elif base_entry.c_binding.visibility != 'private': + visibility = base_entry.c_binding.visibility entry = self.add_cfunction( base_entry.python_binding.name, base_entry.type, base_entry.pos, adapt(base_entry.c_binding.name), - base_entry.visibility, base_entry.func_modifiers) + visibility, base_entry.func_modifiers) entry.is_inherited = 1 @@ -1786,10 +1823,15 @@ class CppClassScope(Scope): entry.is_variable = 1 self.inherited_var_entries.append(entry) for base_entry in base_scope.cfunc_entries: + visibility = 'private' + if base_entry.c_source.extern: + visibility = 'extern' + elif base_entry.c_binding.visibility != 'private': + visibility = base_entry.c_binding.visibility entry = self.declare_cfunction( base_entry.python_binding.name, base_entry.type, base_entry.pos, base_entry.c_binding.name, - base_entry.visibility, base_entry.func_modifiers, + visibility, base_entry.func_modifiers, utility_code = base_entry.utility_code) entry.is_inherited = 1 @@ -1801,10 +1843,20 @@ class CppClassScope(Scope): entry.python_binding.name, entry.type.specialize(values), entry.pos, entry.c_binding.name) else: +# visibility = 'private' +# if entry.c_source.extern: +# visibility = 'extern' +# elif entry.c_binding.visibility != 'private': +# visibility = entry.c_binding.visibility # scope.declare_var( # entry.python_binding.name, entry.type.specialize(values), -# entry.pos, entry.c_binding.name, entry.visibility) +# entry.pos, entry.c_binding.name, visibility) for e in entry.all_alternatives(): +# visibility = 'private' # WTK: bug to not use visibility? +# if e.c_source.extern: +# visibility = 'extern' +# elif e.c_binding.visibility != 'private': +# visibility = base_entry.c_binding.visibility scope.declare_cfunction( e.python_binding.name, e.type.specialize(values), e.pos, e.c_binding.name, utility_code = e.utility_code) diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py index d6bf22e8..7a96883e 100644 --- a/Cython/Compiler/TypeSlots.py +++ b/Cython/Compiler/TypeSlots.py @@ -287,7 +287,7 @@ class GCDependentSlot(InternalMethodSlot): parent_type_scope = scope.parent_type.base_type.scope if scope.parent_scope is parent_type_scope.parent_scope: entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) - if entry.visibility != 'extern': + if not entry.c_source.extern: return self.slot_code(parent_type_scope) return InternalMethodSlot.slot_code(self, scope) @@ -309,7 +309,7 @@ class ConstructorSlot(InternalMethodSlot): parent_type_scope = scope.parent_type.base_type.scope if scope.parent_scope is parent_type_scope.parent_scope: entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) - if entry.visibility != 'extern': + if not entry.c_source.extern: return self.slot_code(parent_type_scope) return InternalMethodSlot.slot_code(self, scope) @@ -468,7 +468,7 @@ def get_base_slot_function(scope, slot): parent_slot = slot.slot_code(base_type.scope) if parent_slot != '0': entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) - if entry.visibility != 'extern': + if not entry.c_source.extern: return parent_slot return None -- 2.26.2