digitalmars.D.bugs - Template Codegen + Tupleof
- Kyle Furlong (8/8) Feb 06 2007 So I've been trying to write a function that will yield an array of
- Frits van Bommel (37/47) Feb 06 2007 That's a definite bug. Wrong code generation for the second template
- Kyle Furlong (4/60) Feb 06 2007 Yes, thanks for the verification of the bug. But yeah, my code is not
- Frits van Bommel (92/95) Feb 06 2007 By the way, I've got something similar working pretty well (code attache...
- Frits van Bommel (1/1) Feb 06 2007 Bugzilla'd: http://d.puremagic.com/issues/show_bug.cgi?id=932
- Kyle Furlong (2/3) Feb 06 2007 Thanks for doing it.
So I've been trying to write a function that will yield an array of structs containing the types and offsets of each member of a UDT. Naturally, I looked to use tupleof and templating to pull this off. In the process, I think I've come across a bug. Although, since I don't regularly program in D, I'm not sure if what I'm trying to do is the Right Way. Its also why I'm not posting a Bugzilla on this just quite yet. The attachment is a bit lengthy because I couldnt reduce it any more than that. Let me know what you think.
Feb 06 2007
Kyle Furlong wrote:So I've been trying to write a function that will yield an array of structs containing the types and offsets of each member of a UDT. Naturally, I looked to use tupleof and templating to pull this off. In the process, I think I've come across a bug. Although, since I don't regularly program in D, I'm not sure if what I'm trying to do is the Right Way. Its also why I'm not posting a Bugzilla on this just quite yet. The attachment is a bit lengthy because I couldnt reduce it any more than that. Let me know what you think.That's a definite bug. Wrong code generation for the second template instantiation. It seems to think your second struct has the same member types as the first one. The tupleof reports the right tuple, though, so the bug seems to be in the code that implements the static foreach. More reduced version: ----- void Fields(C)() { foreach(i, a; typeof(C.tupleof)) { // fails for second instantiation: // "test.d(7): static assert (is(int == real)) is false" static assert(is(typeof(a) == typeof(C.tupleof)[i])); } } struct MyStruct1 { int afield; } struct MyStruct2 { real afield; } void main() { Fields!(MyStruct1); Fields!(MyStruct2); } ----- P.S. is there any particular reason you're computing offsets manually when you have the type as a template parameter and could just use "C.tupleof[i].offsetof" :P ? That would save you from having to worry about alignment issues, interface vtable pointers and more. Your code also doesn't take base classes into account, but that may just be because you reduced it? If not, be warned that tupleof doesn't seem to return base class members. Use of "static if(is(C Base == super))" and recursion should be able to help you here.
Feb 06 2007
Frits van Bommel wrote:Kyle Furlong wrote:Yes, thanks for the verification of the bug. But yeah, my code is not very sophisticated yet due to frustration with the bug. Once this is fixed I can move on to a complete correct solution.So I've been trying to write a function that will yield an array of structs containing the types and offsets of each member of a UDT. Naturally, I looked to use tupleof and templating to pull this off. In the process, I think I've come across a bug. Although, since I don't regularly program in D, I'm not sure if what I'm trying to do is the Right Way. Its also why I'm not posting a Bugzilla on this just quite yet. The attachment is a bit lengthy because I couldnt reduce it any more than that. Let me know what you think.That's a definite bug. Wrong code generation for the second template instantiation. It seems to think your second struct has the same member types as the first one. The tupleof reports the right tuple, though, so the bug seems to be in the code that implements the static foreach. More reduced version: ----- void Fields(C)() { foreach(i, a; typeof(C.tupleof)) { // fails for second instantiation: // "test.d(7): static assert (is(int == real)) is false" static assert(is(typeof(a) == typeof(C.tupleof)[i])); } } struct MyStruct1 { int afield; } struct MyStruct2 { real afield; } void main() { Fields!(MyStruct1); Fields!(MyStruct2); } ----- P.S. is there any particular reason you're computing offsets manually when you have the type as a template parameter and could just use "C.tupleof[i].offsetof" :P ? That would save you from having to worry about alignment issues, interface vtable pointers and more. Your code also doesn't take base classes into account, but that may just be because you reduced it? If not, be warned that tupleof doesn't seem to return base class members. Use of "static if(is(C Base == super))" and recursion should be able to help you here.
Feb 06 2007
Kyle Furlong wrote:Yes, thanks for the verification of the bug. But yeah, my code is not very sophisticated yet due to frustration with the bug. Once this is fixed I can move on to a complete correct solution.By the way, I've got something similar working pretty well (code attached). I'm not using a function though, just a raw template that aliases to a struct instance with type information. That type information includes pointers to recursively generated type information for any members. The current public interface is basically: ---- /// Represents a type. At most one of fields and base will be non-null. struct RttiData { /** The TypeInfo of the represented type. * * Note: Class references use the TypeInfo of the class, their bodies are * represented by the TypeInfo of ClassBody!(ClassName). */ const TypeInfo typeinfo; /** The type of the data pointed to if this instance represents a pointer * or class reference. */ const RttiData* base; /** The fields of the type. * * If the type is a class body, struct or union, this contains the * _fields of the type. * For dynamic arrays, this contains their length and ptr, * for static arrays their elements, and * for delegates their context pointer and function pointer. */ const FieldData[] fields; // Plus implementations of toString, opEquals, opCmp and toHash } /// Represents a field in a class body, struct or union. struct FieldData { /// A pointer to the type data of the type of the field. const RttiData* rtti; /// The _offset of this field from the start of the data block. const size_t offset; // Plus toString, opEquals, opCmp and toHash } /// Aliases to a const RttiData instance describing T. template Rtti(T); /** RttiData instances for class bodies use the TypeInfo of ClassBody, * templated on the class, as their type. * (the class' own TypeInfo is used for the reference) * * For instance, Rtti!(Object).base.typeinfo == typeid(ClassBody!(Object)). * * This type does not have any members, and its only value is the fact that it * has TypeInfo data associated with it. */ struct ClassBody(T) {} ----- Some notes: * Classes are treated as pointers, their bodies as structs. * Delegates and dynamic arrays are considered equivalent to structs (with void*/void function() or size_t/T* members, respectively). Similarly, associative arrays are treated as void*s. * It requires a static constructor for each aggregate type, and for each of their fields. (Though fields of the same type and offset from different aggregates should be folded together by DMD) * When compiled with version=ShowHiddenClassFields the generated class metadata monitor and vtable pointers (including those for interface vtables). Unportabilities and bugs :(: * It assumes that static constructors of alias member parameters have been run before that of the template itself. Fortunately this seems to be exactly what DMD does. * Unions are used to avoid some extra static constructors. (Unless disabled by removing version=UnionHack, but that of course introduces extra static constructors) These assume that a dynamic array has the exact layout of a struct { size_t length; void* ptr; }. internal ones) from more than one module without getting 'multiple definition' errors. * Generated information 'unfolds' typedefs, aliasing to the information generated for the base type. I haven't found any way around this without using a static constructor, but I don't think it's worth it. * The current version requires Tango, but that can easily be changed. * Assumes the current DMD layout for dynamic arrays and delegates. * The extra data generated with version=ShowHiddenClassFields seems to be correct for DMD, but I have no idea if (a) it is correct in all cases and (b) if it's correct for GDC at all. Another "problem" is that I've yet to find a good way to handle dynamic arrays. Currently they're identical to a struct { size_t length; void* ptr; }, but in this case it's known (at least at run-time) to how many elements that pointer points. I have yet to find a way to express this in my data. Unless you count 'If RttiData.typeinfo.toString() (or toUtf8(), for Tango users) ends in "[]", it's a dynamic array'. *phew* long post. Hope I didn't forget anything...
Feb 06 2007
Bugzilla'd: http://d.puremagic.com/issues/show_bug.cgi?id=932
Feb 06 2007
Frits van Bommel wrote:Bugzilla'd: http://d.puremagic.com/issues/show_bug.cgi?id=932Thanks for doing it.
Feb 06 2007