From: Dag Sverre Seljebotn Date: Thu, 23 Apr 2009 18:03:36 +0000 (+0200) Subject: Packed struct support (#290) X-Git-Tag: 0.11.2.rc1~52^2~1 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=800a0a968c434fee16fd9f46e60f84121638777a;p=cython.git Packed struct support (#290) --- diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 018fb19d..d5f79953 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -655,9 +655,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): type = entry.type scope = type.scope if scope: + kind = type.kind + packed = type.is_struct and type.packed + if packed: + kind = "%s %s" % (type.kind, "__Pyx_PACKED") + code.globalstate.use_utility_code(packed_struct_utility_code) header, footer = \ - self.sue_header_footer(type, type.kind, type.cname) + self.sue_header_footer(type, kind, type.cname) code.putln("") + if packed: + code.putln("#if !defined(__GNUC__)") + code.putln("#pragma pack(push, 1)") + code.putln("#endif") code.putln(header) var_entries = scope.var_entries if not var_entries: @@ -669,6 +678,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): "%s;" % attr.type.declaration_code(attr.cname)) code.putln(footer) + if packed: + code.putln("#if !defined(__GNUC__)") + code.putln("#pragma pack(pop)") + code.putln("#endif") def generate_enum_definition(self, entry, code): code.mark_pos(entry.pos) @@ -2479,3 +2492,11 @@ int main(int argc, char** argv) { return r; } """) + +packed_struct_utility_code = UtilityCode(proto=""" +#if defined(__GNUC__) +#define __Pyx_PACKED __attribute__((__packed__)) +#else +#define __Pyx_PACKED +#endif +""", impl="") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 2b5cef25..1638189d 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -840,16 +840,19 @@ class CStructOrUnionDefNode(StatNode): # in_pxd boolean # attributes [CVarDefNode] or None # entry Entry + # packed boolean child_attrs = ["attributes"] def analyse_declarations(self, env): scope = None + if self.visibility == 'extern' and self.packed: + error(self.pos, "Cannot declare extern struct as 'packed'") if self.attributes is not None: scope = StructOrUnionScope(self.name) self.entry = env.declare_struct_or_union( self.name, self.kind, scope, self.typedef_flag, self.pos, - self.cname, visibility = self.visibility) + self.cname, visibility = self.visibility, packed = self.packed) if self.attributes is not None: if self.in_pxd and not env.in_cinclude: self.entry.defined_in_pxd = 1 diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 62c041aa..85919514 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -2078,7 +2078,7 @@ def p_cdef_statement(s, ctx): #if ctx.api: # error(pos, "'api' not allowed with extension class") return p_c_class_definition(s, pos, ctx) - elif s.sy == 'IDENT' and s.systring in struct_union_or_enum: + elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"): if ctx.level not in ('module', 'module_pxd'): error(pos, "C struct/union/enum definition not allowed here") #if ctx.visibility == 'public': @@ -2114,10 +2114,6 @@ def p_cdef_extern_block(s, pos, ctx): include_file = include_file, body = body) -struct_union_or_enum = ( - "struct", "union", "enum" -) - def p_c_enum_definition(s, pos, ctx): # s.sy == ident 'enum' s.next() @@ -2168,6 +2164,12 @@ def p_c_enum_item(s, items): name = name, cname = cname, value = value)) def p_c_struct_or_union_definition(s, pos, ctx): + packed = False + if s.systring == 'packed': + packed = True + s.next() + if s.sy != 'IDENT' and s.systring != 'struct': + s.expected('struct') # s.sy == ident 'struct' or 'union' kind = s.systring s.next() @@ -2193,7 +2195,7 @@ def p_c_struct_or_union_definition(s, pos, ctx): return Nodes.CStructOrUnionDefNode(pos, name = name, cname = cname, kind = kind, attributes = attributes, typedef_flag = ctx.typedef_flag, visibility = ctx.visibility, - in_pxd = ctx.level == 'module_pxd') + in_pxd = ctx.level == 'module_pxd', packed = packed) def p_visibility(s, prev_visibility): pos = s.position() @@ -2265,7 +2267,7 @@ def p_ctypedef_statement(s, ctx): ctx.api = 1 if s.sy == 'class': return p_c_class_definition(s, pos, ctx) - elif s.sy == 'IDENT' and s.systring in ('struct', 'union', 'enum'): + elif s.sy == 'IDENT' and s.systring in ('packed', 'struct', 'union', 'enum'): if s.systring == 'enum': return p_c_enum_definition(s, pos, ctx) else: diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 1660dec5..7bba4707 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -1023,11 +1023,12 @@ class CStructOrUnionType(CType): # kind string "struct" or "union" # scope StructOrUnionScope, or None if incomplete # typedef_flag boolean + # packed boolean is_struct_or_union = 1 has_attributes = 1 - def __init__(self, name, kind, scope, typedef_flag, cname): + def __init__(self, name, kind, scope, typedef_flag, cname, packed=False): self.name = name self.cname = cname self.kind = kind @@ -1038,6 +1039,7 @@ class CStructOrUnionType(CType): self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname) self.exception_check = True self._convert_code = None + self.packed = packed def create_convert_utility_code(self, env): if env.outer_scope is None: diff --git a/Cython/Compiler/Scanning.py b/Cython/Compiler/Scanning.py index d5eae3b6..fd8d42c9 100644 --- a/Cython/Compiler/Scanning.py +++ b/Cython/Compiler/Scanning.py @@ -466,7 +466,7 @@ class PyrexScanner(Scanner): else: self.expected(what, message) - def expected(self, what, message): + def expected(self, what, message = None): if message: self.error(message) else: diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index ff6db3b1..d972309f 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -353,7 +353,8 @@ class Scope(object): return entry def declare_struct_or_union(self, name, kind, scope, - typedef_flag, pos, cname = None, visibility = 'private'): + typedef_flag, pos, cname = None, visibility = 'private', + packed = False): # Add an entry for a struct or union definition. if not cname: if self.in_cinclude or visibility == 'public': @@ -363,7 +364,7 @@ class Scope(object): entry = self.lookup_here(name) if not entry: type = PyrexTypes.CStructOrUnionType( - name, kind, scope, typedef_flag, cname) + name, kind, scope, typedef_flag, cname, packed) entry = self.declare_type(name, type, pos, cname, visibility = visibility, defining = scope is not None) self.sue_entries.append(entry) diff --git a/tests/errors/e_packedstruct_T290.pyx b/tests/errors/e_packedstruct_T290.pyx new file mode 100644 index 00000000..408246c8 --- /dev/null +++ b/tests/errors/e_packedstruct_T290.pyx @@ -0,0 +1,7 @@ +cdef extern: + cdef packed struct MyStruct: + char a + +_ERRORS = u""" +2:9: Cannot declare extern struct as 'packed' +""" diff --git a/tests/run/packedstruct_T290.pyx b/tests/run/packedstruct_T290.pyx new file mode 100644 index 00000000..a66915f3 --- /dev/null +++ b/tests/run/packedstruct_T290.pyx @@ -0,0 +1,16 @@ +""" +>>> f() +(9, 9) +""" + +cdef packed struct MyCdefStruct: + char a + double b + +ctypedef packed struct MyCTypeDefStruct: + char a + double b + +def f(): + return (sizeof(MyCdefStruct), sizeof(MyCTypeDefStruct)) +