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:
"%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)
return r;
}
""")
+
+packed_struct_utility_code = UtilityCode(proto="""
+#if defined(__GNUC__)
+#define __Pyx_PACKED __attribute__((__packed__))
+#else
+#define __Pyx_PACKED
+#endif
+""", impl="")
# 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
#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':
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()
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()
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()
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:
# 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
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:
else:
self.expected(what, message)
- def expected(self, what, message):
+ def expected(self, what, message = None):
if message:
self.error(message)
else:
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':
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)
--- /dev/null
+cdef extern:
+ cdef packed struct MyStruct:
+ char a
+
+_ERRORS = u"""
+2:9: Cannot declare extern struct as 'packed'
+"""
--- /dev/null
+"""
+>>> 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))
+