Bug 5780 – [patch] std.traits.hasIndirections incorrectly handles static arrays

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2011-03-23T22:05:00Z
Last change time
2011-04-12T16:14:07Z
Keywords
patch
Assigned to
nobody
Creator
sandford
Blocks
5813

Comments

Comment #0 by sandford — 2011-03-23T22:05:38Z
Problem: std.traits.hasIndirections currently does not return true for static arrays of types with indirections. More fundamentally, it's unit tests do not verify it's output for all template instances. I've set the priority of this bug based on the fact that manual memory allocation routines are apt to utilize hasIndirections to determine whether or not to apply the no scan GC attribute and getting this wrong results in memory stomping/corruption. Solution: I've added detection and handling of static arrays to hasIndirectionsImpl. Also, to prevent future unforeseen corner cases, I've added a private template, hasIndirectionsUnittest, which allows each instance of hasIndirections!T to generate a unit test which verifies the value of hasIndirections!T against T's runtime GC flags. Also, a specific unit test for static arrays was added. Patch: (Based on DMD 2.052) /** Returns $(D true) if and only if $(D T)'s representation includes at least one of the following: $(OL $(LI a raw pointer $(D U*);) $(LI an array $(D U[]);) $(LI a reference to a class type $(D C).) $(LI an associative array.) $(LI a delegate.)) */ template hasIndirections(T) { enum hasIndirections = hasIndirectionsUnittest!T.implementation; } // Tests hasIndirections against the GC's runtime info for every T private template hasIndirectionsUnittest(T) { enum implementation = hasIndirectionsImpl!(RepresentationTypeTuple!T); unittest { assert( hasIndirections!T == (typeid(T[]).next.flags & 1) ); } } template hasIndirectionsImpl(T...) { static if (!T.length) { enum hasIndirectionsImpl = false; } else static if(isFunctionPointer!(T[0])) { enum hasIndirectionsImpl = hasIndirectionsImpl!(T[1 .. $]); } else static if(isStaticArray!(T[0])) { enum hasIndirectionsImpl = hasIndirectionsImpl!(T[1 .. $]) || hasIndirectionsImpl!(RepresentationTypeTuple!(typeof(T[0].init[0]))); } else { enum hasIndirectionsImpl = isPointer!(T[0]) || isDynamicArray!(T[0]) || is (T[0] : const(Object)) || isAssociativeArray!(T[0]) || isDelegate!(T[0]) || is(T[0] == interface) || hasIndirectionsImpl!(T[1 .. $]); } } unittest { struct S1 { int a; Object b; } static assert(hasIndirections!(S1)); struct S2 { string a; } static assert(hasIndirections!(S2)); struct S3 { int a; immutable Object b; } static assert(hasIndirections!(S3)); static assert(hasIndirections!(int[string])); static assert(hasIndirections!(void delegate())); interface I; static assert(hasIndirections!I); static assert(!hasIndirections!(void function())); static assert(hasIndirections!(void*[1])); static assert(!hasIndirections!(byte[1])); }
Comment #1 by dsimcha — 2011-04-12T16:14:07Z
https://github.com/D-Programming-Language/phobos/commit/3edf3bf1b77ef883676332aea4fe3d8d6ccba867 I didn't include the hasIndirectionsUnittest stuff, though, because it seems to cause weird linker errors when -unittest is enabled, for reasons I don't understand.