|
1 /***************************************************************** |
|
2 This file should be kept compatible with Python 2.3, see PEP 291. |
|
3 *****************************************************************/ |
|
4 |
|
5 #include "Python.h" |
|
6 #include <ffi.h> |
|
7 #ifdef MS_WIN32 |
|
8 #include <windows.h> |
|
9 #include <malloc.h> |
|
10 #endif |
|
11 #include "ctypes.h" |
|
12 |
|
13 /******************************************************************/ |
|
14 /* |
|
15 StdDict - a dictionary subclass, containing additional C accessible fields |
|
16 |
|
17 XXX blabla more |
|
18 */ |
|
19 |
|
20 /* Seems we need this, otherwise we get problems when calling |
|
21 * PyDict_SetItem() (ma_lookup is NULL) |
|
22 */ |
|
23 static int |
|
24 StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds) |
|
25 { |
|
26 if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) |
|
27 return -1; |
|
28 self->format = NULL; |
|
29 self->ndim = 0; |
|
30 self->shape = NULL; |
|
31 return 0; |
|
32 } |
|
33 |
|
34 static int |
|
35 StgDict_clear(StgDictObject *self) |
|
36 { |
|
37 Py_CLEAR(self->proto); |
|
38 Py_CLEAR(self->argtypes); |
|
39 Py_CLEAR(self->converters); |
|
40 Py_CLEAR(self->restype); |
|
41 Py_CLEAR(self->checker); |
|
42 return 0; |
|
43 } |
|
44 |
|
45 static void |
|
46 StgDict_dealloc(StgDictObject *self) |
|
47 { |
|
48 StgDict_clear(self); |
|
49 PyMem_Free(self->format); |
|
50 PyMem_Free(self->shape); |
|
51 PyMem_Free(self->ffi_type_pointer.elements); |
|
52 PyDict_Type.tp_dealloc((PyObject *)self); |
|
53 } |
|
54 |
|
55 int |
|
56 StgDict_clone(StgDictObject *dst, StgDictObject *src) |
|
57 { |
|
58 char *d, *s; |
|
59 Py_ssize_t size; |
|
60 |
|
61 StgDict_clear(dst); |
|
62 PyMem_Free(dst->ffi_type_pointer.elements); |
|
63 PyMem_Free(dst->format); |
|
64 dst->format = NULL; |
|
65 PyMem_Free(dst->shape); |
|
66 dst->shape = NULL; |
|
67 dst->ffi_type_pointer.elements = NULL; |
|
68 |
|
69 d = (char *)dst; |
|
70 s = (char *)src; |
|
71 memcpy(d + sizeof(PyDictObject), |
|
72 s + sizeof(PyDictObject), |
|
73 sizeof(StgDictObject) - sizeof(PyDictObject)); |
|
74 |
|
75 Py_XINCREF(dst->proto); |
|
76 Py_XINCREF(dst->argtypes); |
|
77 Py_XINCREF(dst->converters); |
|
78 Py_XINCREF(dst->restype); |
|
79 Py_XINCREF(dst->checker); |
|
80 |
|
81 if (src->format) { |
|
82 dst->format = PyMem_Malloc(strlen(src->format) + 1); |
|
83 if (dst->format == NULL) |
|
84 return -1; |
|
85 strcpy(dst->format, src->format); |
|
86 } |
|
87 if (src->shape) { |
|
88 dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim); |
|
89 if (dst->shape == NULL) |
|
90 return -1; |
|
91 memcpy(dst->shape, src->shape, |
|
92 sizeof(Py_ssize_t) * src->ndim); |
|
93 } |
|
94 |
|
95 if (src->ffi_type_pointer.elements == NULL) |
|
96 return 0; |
|
97 size = sizeof(ffi_type *) * (src->length + 1); |
|
98 dst->ffi_type_pointer.elements = PyMem_Malloc(size); |
|
99 if (dst->ffi_type_pointer.elements == NULL) { |
|
100 PyErr_NoMemory(); |
|
101 return -1; |
|
102 } |
|
103 memcpy(dst->ffi_type_pointer.elements, |
|
104 src->ffi_type_pointer.elements, |
|
105 size); |
|
106 return 0; |
|
107 } |
|
108 |
|
109 PyTypeObject StgDict_Type = { |
|
110 PyVarObject_HEAD_INIT(NULL, 0) |
|
111 "StgDict", |
|
112 sizeof(StgDictObject), |
|
113 0, |
|
114 (destructor)StgDict_dealloc, /* tp_dealloc */ |
|
115 0, /* tp_print */ |
|
116 0, /* tp_getattr */ |
|
117 0, /* tp_setattr */ |
|
118 0, /* tp_compare */ |
|
119 0, /* tp_repr */ |
|
120 0, /* tp_as_number */ |
|
121 0, /* tp_as_sequence */ |
|
122 0, /* tp_as_mapping */ |
|
123 0, /* tp_hash */ |
|
124 0, /* tp_call */ |
|
125 0, /* tp_str */ |
|
126 0, /* tp_getattro */ |
|
127 0, /* tp_setattro */ |
|
128 0, /* tp_as_buffer */ |
|
129 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
|
130 0, /* tp_doc */ |
|
131 0, /* tp_traverse */ |
|
132 0, /* tp_clear */ |
|
133 0, /* tp_richcompare */ |
|
134 0, /* tp_weaklistoffset */ |
|
135 0, /* tp_iter */ |
|
136 0, /* tp_iternext */ |
|
137 0, /* tp_methods */ |
|
138 0, /* tp_members */ |
|
139 0, /* tp_getset */ |
|
140 0, /* tp_base */ |
|
141 0, /* tp_dict */ |
|
142 0, /* tp_descr_get */ |
|
143 0, /* tp_descr_set */ |
|
144 0, /* tp_dictoffset */ |
|
145 (initproc)StgDict_init, /* tp_init */ |
|
146 0, /* tp_alloc */ |
|
147 0, /* tp_new */ |
|
148 0, /* tp_free */ |
|
149 }; |
|
150 |
|
151 /* May return NULL, but does not set an exception! */ |
|
152 StgDictObject * |
|
153 PyType_stgdict(PyObject *obj) |
|
154 { |
|
155 PyTypeObject *type; |
|
156 |
|
157 if (!PyType_Check(obj)) |
|
158 return NULL; |
|
159 type = (PyTypeObject *)obj; |
|
160 if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS)) |
|
161 return NULL; |
|
162 if (!type->tp_dict || !StgDict_CheckExact(type->tp_dict)) |
|
163 return NULL; |
|
164 return (StgDictObject *)type->tp_dict; |
|
165 } |
|
166 |
|
167 /* May return NULL, but does not set an exception! */ |
|
168 /* |
|
169 This function should be as fast as possible, so we don't call PyType_stgdict |
|
170 above but inline the code, and avoid the PyType_Check(). |
|
171 */ |
|
172 StgDictObject * |
|
173 PyObject_stgdict(PyObject *self) |
|
174 { |
|
175 PyTypeObject *type = self->ob_type; |
|
176 if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS)) |
|
177 return NULL; |
|
178 if (!type->tp_dict || !StgDict_CheckExact(type->tp_dict)) |
|
179 return NULL; |
|
180 return (StgDictObject *)type->tp_dict; |
|
181 } |
|
182 |
|
183 /* descr is the descriptor for a field marked as anonymous. Get all the |
|
184 _fields_ descriptors from descr->proto, create new descriptors with offset |
|
185 and index adjusted, and stuff them into type. |
|
186 */ |
|
187 static int |
|
188 MakeFields(PyObject *type, CFieldObject *descr, |
|
189 Py_ssize_t index, Py_ssize_t offset) |
|
190 { |
|
191 Py_ssize_t i; |
|
192 PyObject *fields; |
|
193 PyObject *fieldlist; |
|
194 |
|
195 fields = PyObject_GetAttrString(descr->proto, "_fields_"); |
|
196 if (fields == NULL) |
|
197 return -1; |
|
198 fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence"); |
|
199 Py_DECREF(fields); |
|
200 if (fieldlist == NULL) |
|
201 return -1; |
|
202 |
|
203 for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) { |
|
204 PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */ |
|
205 PyObject *fname, *ftype, *bits; |
|
206 CFieldObject *fdescr; |
|
207 CFieldObject *new_descr; |
|
208 /* Convert to PyArg_UnpackTuple... */ |
|
209 if (!PyArg_ParseTuple(pair, "OO|O", &fname, &ftype, &bits)) { |
|
210 Py_DECREF(fieldlist); |
|
211 return -1; |
|
212 } |
|
213 fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname); |
|
214 if (fdescr == NULL) { |
|
215 Py_DECREF(fieldlist); |
|
216 return -1; |
|
217 } |
|
218 if (Py_TYPE(fdescr) != &CField_Type) { |
|
219 PyErr_SetString(PyExc_TypeError, "unexpected type"); |
|
220 Py_DECREF(fdescr); |
|
221 Py_DECREF(fieldlist); |
|
222 return -1; |
|
223 } |
|
224 if (fdescr->anonymous) { |
|
225 int rc = MakeFields(type, fdescr, |
|
226 index + fdescr->index, |
|
227 offset + fdescr->offset); |
|
228 Py_DECREF(fdescr); |
|
229 if (rc == -1) { |
|
230 Py_DECREF(fieldlist); |
|
231 return -1; |
|
232 } |
|
233 continue; |
|
234 } |
|
235 new_descr = (CFieldObject *)PyObject_CallObject((PyObject *)&CField_Type, NULL); |
|
236 if (new_descr == NULL) { |
|
237 Py_DECREF(fdescr); |
|
238 Py_DECREF(fieldlist); |
|
239 return -1; |
|
240 } |
|
241 assert(Py_TYPE(new_descr) == &CField_Type); |
|
242 new_descr->size = fdescr->size; |
|
243 new_descr->offset = fdescr->offset + offset; |
|
244 new_descr->index = fdescr->index + index; |
|
245 new_descr->proto = fdescr->proto; |
|
246 Py_XINCREF(new_descr->proto); |
|
247 new_descr->getfunc = fdescr->getfunc; |
|
248 new_descr->setfunc = fdescr->setfunc; |
|
249 |
|
250 Py_DECREF(fdescr); |
|
251 |
|
252 if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) { |
|
253 Py_DECREF(fieldlist); |
|
254 Py_DECREF(new_descr); |
|
255 return -1; |
|
256 } |
|
257 Py_DECREF(new_descr); |
|
258 } |
|
259 Py_DECREF(fieldlist); |
|
260 return 0; |
|
261 } |
|
262 |
|
263 /* Iterate over the names in the type's _anonymous_ attribute, if present, |
|
264 */ |
|
265 static int |
|
266 MakeAnonFields(PyObject *type) |
|
267 { |
|
268 PyObject *anon; |
|
269 PyObject *anon_names; |
|
270 Py_ssize_t i; |
|
271 |
|
272 anon = PyObject_GetAttrString(type, "_anonymous_"); |
|
273 if (anon == NULL) { |
|
274 PyErr_Clear(); |
|
275 return 0; |
|
276 } |
|
277 anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence"); |
|
278 Py_DECREF(anon); |
|
279 if (anon_names == NULL) |
|
280 return -1; |
|
281 |
|
282 for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) { |
|
283 PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */ |
|
284 CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname); |
|
285 if (descr == NULL) { |
|
286 Py_DECREF(anon_names); |
|
287 return -1; |
|
288 } |
|
289 assert(Py_TYPE(descr) == &CField_Type); |
|
290 descr->anonymous = 1; |
|
291 |
|
292 /* descr is in the field descriptor. */ |
|
293 if (-1 == MakeFields(type, (CFieldObject *)descr, |
|
294 ((CFieldObject *)descr)->index, |
|
295 ((CFieldObject *)descr)->offset)) { |
|
296 Py_DECREF(descr); |
|
297 Py_DECREF(anon_names); |
|
298 return -1; |
|
299 } |
|
300 Py_DECREF(descr); |
|
301 } |
|
302 |
|
303 Py_DECREF(anon_names); |
|
304 return 0; |
|
305 } |
|
306 |
|
307 /* |
|
308 Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute, |
|
309 and create an StgDictObject. Used for Structure and Union subclasses. |
|
310 */ |
|
311 int |
|
312 StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) |
|
313 { |
|
314 StgDictObject *stgdict, *basedict; |
|
315 Py_ssize_t len, offset, size, align, i; |
|
316 Py_ssize_t union_size, total_align; |
|
317 Py_ssize_t field_size = 0; |
|
318 int bitofs; |
|
319 PyObject *isPacked; |
|
320 int pack = 0; |
|
321 Py_ssize_t ffi_ofs; |
|
322 int big_endian; |
|
323 |
|
324 /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to |
|
325 be a way to use the old, broken sematics: _fields_ are not extended |
|
326 but replaced in subclasses. |
|
327 |
|
328 XXX Remove this in ctypes 1.0! |
|
329 */ |
|
330 int use_broken_old_ctypes_semantics; |
|
331 |
|
332 if (fields == NULL) |
|
333 return 0; |
|
334 |
|
335 #ifdef WORDS_BIGENDIAN |
|
336 big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1; |
|
337 #else |
|
338 big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0; |
|
339 #endif |
|
340 |
|
341 use_broken_old_ctypes_semantics = \ |
|
342 PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_"); |
|
343 |
|
344 isPacked = PyObject_GetAttrString(type, "_pack_"); |
|
345 if (isPacked) { |
|
346 pack = PyInt_AsLong(isPacked); |
|
347 if (pack < 0 || PyErr_Occurred()) { |
|
348 Py_XDECREF(isPacked); |
|
349 PyErr_SetString(PyExc_ValueError, |
|
350 "_pack_ must be a non-negative integer"); |
|
351 return -1; |
|
352 } |
|
353 Py_DECREF(isPacked); |
|
354 } else |
|
355 PyErr_Clear(); |
|
356 |
|
357 len = PySequence_Length(fields); |
|
358 if (len == -1) { |
|
359 PyErr_SetString(PyExc_TypeError, |
|
360 "'_fields_' must be a sequence of pairs"); |
|
361 return -1; |
|
362 } |
|
363 |
|
364 stgdict = PyType_stgdict(type); |
|
365 if (!stgdict) |
|
366 return -1; |
|
367 /* If this structure/union is already marked final we cannot assign |
|
368 _fields_ anymore. */ |
|
369 |
|
370 if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */ |
|
371 PyErr_SetString(PyExc_AttributeError, |
|
372 "_fields_ is final"); |
|
373 return -1; |
|
374 } |
|
375 |
|
376 if (stgdict->format) { |
|
377 PyMem_Free(stgdict->format); |
|
378 stgdict->format = NULL; |
|
379 } |
|
380 |
|
381 if (stgdict->ffi_type_pointer.elements) |
|
382 PyMem_Free(stgdict->ffi_type_pointer.elements); |
|
383 |
|
384 basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base); |
|
385 if (basedict && !use_broken_old_ctypes_semantics) { |
|
386 size = offset = basedict->size; |
|
387 align = basedict->align; |
|
388 union_size = 0; |
|
389 total_align = align ? align : 1; |
|
390 stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; |
|
391 stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); |
|
392 if (stgdict->ffi_type_pointer.elements == NULL) { |
|
393 PyErr_NoMemory(); |
|
394 return -1; |
|
395 } |
|
396 memset(stgdict->ffi_type_pointer.elements, 0, |
|
397 sizeof(ffi_type *) * (basedict->length + len + 1)); |
|
398 memcpy(stgdict->ffi_type_pointer.elements, |
|
399 basedict->ffi_type_pointer.elements, |
|
400 sizeof(ffi_type *) * (basedict->length)); |
|
401 ffi_ofs = basedict->length; |
|
402 } else { |
|
403 offset = 0; |
|
404 size = 0; |
|
405 align = 0; |
|
406 union_size = 0; |
|
407 total_align = 1; |
|
408 stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; |
|
409 stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); |
|
410 if (stgdict->ffi_type_pointer.elements == NULL) { |
|
411 PyErr_NoMemory(); |
|
412 return -1; |
|
413 } |
|
414 memset(stgdict->ffi_type_pointer.elements, 0, |
|
415 sizeof(ffi_type *) * (len + 1)); |
|
416 ffi_ofs = 0; |
|
417 } |
|
418 |
|
419 assert(stgdict->format == NULL); |
|
420 if (isStruct && !isPacked) { |
|
421 stgdict->format = alloc_format_string(NULL, "T{"); |
|
422 } else { |
|
423 /* PEP3118 doesn't support union, or packed structures (well, |
|
424 only standard packing, but we dont support the pep for |
|
425 that). Use 'B' for bytes. */ |
|
426 stgdict->format = alloc_format_string(NULL, "B"); |
|
427 } |
|
428 |
|
429 #define realdict ((PyObject *)&stgdict->dict) |
|
430 for (i = 0; i < len; ++i) { |
|
431 PyObject *name = NULL, *desc = NULL; |
|
432 PyObject *pair = PySequence_GetItem(fields, i); |
|
433 PyObject *prop; |
|
434 StgDictObject *dict; |
|
435 int bitsize = 0; |
|
436 |
|
437 if (!pair || !PyArg_ParseTuple(pair, "OO|i", &name, &desc, &bitsize)) { |
|
438 PyErr_SetString(PyExc_AttributeError, |
|
439 "'_fields_' must be a sequence of pairs"); |
|
440 Py_XDECREF(pair); |
|
441 return -1; |
|
442 } |
|
443 dict = PyType_stgdict(desc); |
|
444 if (dict == NULL) { |
|
445 Py_DECREF(pair); |
|
446 PyErr_Format(PyExc_TypeError, |
|
447 #if (PY_VERSION_HEX < 0x02050000) |
|
448 "second item in _fields_ tuple (index %d) must be a C type", |
|
449 #else |
|
450 "second item in _fields_ tuple (index %zd) must be a C type", |
|
451 #endif |
|
452 i); |
|
453 return -1; |
|
454 } |
|
455 stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer; |
|
456 if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER)) |
|
457 stgdict->flags |= TYPEFLAG_HASPOINTER; |
|
458 dict->flags |= DICTFLAG_FINAL; /* mark field type final */ |
|
459 if (PyTuple_Size(pair) == 3) { /* bits specified */ |
|
460 switch(dict->ffi_type_pointer.type) { |
|
461 case FFI_TYPE_UINT8: |
|
462 case FFI_TYPE_UINT16: |
|
463 case FFI_TYPE_UINT32: |
|
464 case FFI_TYPE_SINT64: |
|
465 case FFI_TYPE_UINT64: |
|
466 break; |
|
467 |
|
468 case FFI_TYPE_SINT8: |
|
469 case FFI_TYPE_SINT16: |
|
470 case FFI_TYPE_SINT32: |
|
471 if (dict->getfunc != getentry("c")->getfunc |
|
472 #ifdef CTYPES_UNICODE |
|
473 && dict->getfunc != getentry("u")->getfunc |
|
474 #endif |
|
475 ) |
|
476 break; |
|
477 /* else fall through */ |
|
478 default: |
|
479 PyErr_Format(PyExc_TypeError, |
|
480 "bit fields not allowed for type %s", |
|
481 ((PyTypeObject *)desc)->tp_name); |
|
482 Py_DECREF(pair); |
|
483 return -1; |
|
484 } |
|
485 if (bitsize <= 0 || bitsize > dict->size * 8) { |
|
486 PyErr_SetString(PyExc_ValueError, |
|
487 "number of bits invalid for bit field"); |
|
488 Py_DECREF(pair); |
|
489 return -1; |
|
490 } |
|
491 } else |
|
492 bitsize = 0; |
|
493 if (isStruct && !isPacked) { |
|
494 char *fieldfmt = dict->format ? dict->format : "B"; |
|
495 char *fieldname = PyString_AsString(name); |
|
496 char *ptr; |
|
497 Py_ssize_t len = strlen(fieldname) + strlen(fieldfmt); |
|
498 char *buf = alloca(len + 2 + 1); |
|
499 |
|
500 sprintf(buf, "%s:%s:", fieldfmt, fieldname); |
|
501 |
|
502 ptr = stgdict->format; |
|
503 stgdict->format = alloc_format_string(stgdict->format, buf); |
|
504 PyMem_Free(ptr); |
|
505 |
|
506 if (stgdict->format == NULL) { |
|
507 Py_DECREF(pair); |
|
508 return -1; |
|
509 } |
|
510 } |
|
511 if (isStruct) { |
|
512 prop = CField_FromDesc(desc, i, |
|
513 &field_size, bitsize, &bitofs, |
|
514 &size, &offset, &align, |
|
515 pack, big_endian); |
|
516 } else /* union */ { |
|
517 size = 0; |
|
518 offset = 0; |
|
519 align = 0; |
|
520 prop = CField_FromDesc(desc, i, |
|
521 &field_size, bitsize, &bitofs, |
|
522 &size, &offset, &align, |
|
523 pack, big_endian); |
|
524 union_size = max(size, union_size); |
|
525 } |
|
526 total_align = max(align, total_align); |
|
527 |
|
528 if (!prop) { |
|
529 Py_DECREF(pair); |
|
530 return -1; |
|
531 } |
|
532 if (-1 == PyObject_SetAttr(type, name, prop)) { |
|
533 Py_DECREF(prop); |
|
534 Py_DECREF(pair); |
|
535 return -1; |
|
536 } |
|
537 Py_DECREF(pair); |
|
538 Py_DECREF(prop); |
|
539 } |
|
540 #undef realdict |
|
541 |
|
542 if (isStruct && !isPacked) { |
|
543 char *ptr = stgdict->format; |
|
544 stgdict->format = alloc_format_string(stgdict->format, "}"); |
|
545 PyMem_Free(ptr); |
|
546 if (stgdict->format == NULL) |
|
547 return -1; |
|
548 } |
|
549 |
|
550 if (!isStruct) |
|
551 size = union_size; |
|
552 |
|
553 /* Adjust the size according to the alignment requirements */ |
|
554 size = ((size + total_align - 1) / total_align) * total_align; |
|
555 |
|
556 stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align, |
|
557 Py_ssize_t, |
|
558 unsigned short); |
|
559 stgdict->ffi_type_pointer.size = size; |
|
560 |
|
561 stgdict->size = size; |
|
562 stgdict->align = total_align; |
|
563 stgdict->length = len; /* ADD ffi_ofs? */ |
|
564 |
|
565 /* We did check that this flag was NOT set above, it must not |
|
566 have been set until now. */ |
|
567 if (stgdict->flags & DICTFLAG_FINAL) { |
|
568 PyErr_SetString(PyExc_AttributeError, |
|
569 "Structure or union cannot contain itself"); |
|
570 return -1; |
|
571 } |
|
572 stgdict->flags |= DICTFLAG_FINAL; |
|
573 |
|
574 return MakeAnonFields(type); |
|
575 } |