Bug 5073 – wrong file name in error message for "voids have no value" inside alias templates (affects std.algorithm.map)

Status
RESOLVED
Resolution
WORKSFORME
Severity
regression
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2010-10-18T17:28:00Z
Last change time
2011-07-05T17:14:51Z
Keywords
diagnostic, patch, wrong-code
Assigned to
andrei
Creator
sandford

Comments

Comment #0 by sandford — 2010-10-18T17:28:42Z
There seems to be an issue with the reported filename for alias templates that create a variable of type void. Here is a test case: using DMD 2.049: import std.algorithm; void main(string[] args) { auto foobar = map!( (int i){} )([0]); // using a named delegate also errors } results in the error message hello.d, Line 119 Error: variable hello.main.Map!(__dgliteral1,int[]).Map._cache voids have no value Line 119 of std.algorithm (part of the Map struct): Unqual!ElementType _cache; This may be related to issue 2180. Here is a reduced test case that gives a slightly better set of error messages than the std.algorithm example: hello.d: import std.stdio: writeln; import goodbye; void main(string[] args) { auto foobar = map!( (int i){} )(5); return; } goodbye.d: module goodbye; // line 9 template map(fun...) // { auto map(Range)(Range r) { return Map!(fun)(r); // line 14, must instantiate with fun or r not Range } } struct Map(alias fun) { // Must be an alias template void _cache; // line 19 } Error messages produced: hello.d Line 19 Error: variable hello.main.Map!(delegate void(int i) hello.d Line 14 Error: template instance hello.main.Map!(delegate void(int i) hello.d Line 5 instantiated from here: map!(int)
Comment #1 by sandford — 2011-01-05T13:14:37Z
In DMD 2.051, this error message has ceased to be generated for certain inputs and instead a runtime access violation is generated. Here is a reduced test case: struct Bar(T) { T x; Bar dot(Bar b) { return Bar(x+b.x); } } void main(string[] args) { Bar!real b; Bar!real[] data = new Bar!real[5]; auto foobar = map!((a){return a.dot(b); })(data); return; } Here is a modified to std.algorithm.map that works arounds this specific bug: template map(fun...) { auto map(Range)(Range r) { static if (fun.length > 1) { return Map!( unaryFun!( adjoin!(staticMap!(unaryFun, fun)) ), Range )(r); } else { static if( is(typeof(fun[0]) == delegate) ) { return Map!(fun, Range)(fun[0],r); } else { return Map!(unaryFun!fun, Range)(r); } } } } struct Map(alias fun, Range) if (isInputRange!(Range)) { Unqual!Range _input; static if( is(typeof(fun) == delegate) ) { typeof(fun) _fun; this(typeof(fun) dg, Range input) { _fun = dg; _input = input; } } else { alias fun _fun; this(Range input) { _input = input; } } alias typeof({ return _fun(.ElementType!(Range).init); }()) ElementType; static if (isBidirectionalRange!(Range)) { @property ElementType back() { return _fun(_input.back); } void popBack() { _input.popBack; } } // Propagate infinite-ness. static if (isInfinite!Range) { enum bool empty = false; } else { @property bool empty() { return _input.empty; } } void popFront() { _input.popFront; } @property ElementType front() { return _fun(_input.front); } static if (isRandomAccessRange!Range) { ElementType opIndex(size_t index) { return _fun(_input[index]); } } // hasLength is busted, Bug 2873 static if (is(typeof(_input.length) : size_t) || is(typeof(_input.length()) : size_t)) { @property size_t length() { return _input.length; } } static if (hasSlicing!(Range)) { typeof(this) opSlice(size_t lowerBound, size_t upperBound) { auto result = this; result._input = result._input[lowerBound..upperBound]; return result; } } static if (isForwardRange!Range) @property Map save() { auto result = this; result._input = result._input.save; return result; } }
Comment #2 by andrei — 2011-01-16T14:18:23Z
(In reply to comment #1) > In DMD 2.051, this error message has ceased to be generated for certain inputs > and instead a runtime access violation is generated. Here is a reduced test > case: > > struct Bar(T) { > T x; > Bar dot(Bar b) { return Bar(x+b.x); } > } > > void main(string[] args) { > Bar!real b; > Bar!real[] data = new Bar!real[5]; > auto foobar = map!((a){return a.dot(b); })(data); > return; > } I just tried the example above with 2.051. It compiles and runs. Could you please provide a different example? Thanks!
Comment #3 by sandford — 2011-01-20T09:33:15Z
(In reply to comment #2) > (In reply to comment #1) > > In DMD 2.051, this error message has ceased to be generated for certain inputs > > and instead a runtime access violation is generated. Here is a reduced test > > case: > > > > struct Bar(T) { > > T x; > > Bar dot(Bar b) { return Bar(x+b.x); } > > } > > > > void main(string[] args) { > > Bar!real b; > > Bar!real[] data = new Bar!real[5]; > > auto foobar = map!((a){return a.dot(b); })(data); > > return; > > } > > I just tried the example above with 2.051. It compiles and runs. Could you > please provide a different example? Thanks! While it does compile on my system, when it runs it causes an "object.Error: Access Violation". I'm on an Intel Core-i7 920 (Quad core) running Windows 7 64-bit. Just to double check, here is a more extensive version of the same test which verifies the map is run correctly. void main(string[] args) { Bar!real b = Bar!real(5); Bar!real[] data = new Bar!real[5]; foreach(i,ref d;data) d.x = i; Bar!real[] expected = new Bar!real[5]; foreach(i,ref e;expected) e = data[i].dot(b); auto foobar = map!((a){return a.dot(b); })(data); foreach(z;zip(foobar,expected)) assert(z[0].x == z[1].x); return; } Also, does the example from my first post compile & run for you?
Comment #4 by sandford — 2011-05-19T17:22:16Z
Minor update to handle fixed sized arrays properly. template map(fun...) { auto map(Range)(Range r) { static if (fun.length > 1) { return Map!(unaryFun!(adjoin!(staticMap!(unaryFun,fun))),Range)(r); } else { static if( is(typeof(fun[0]) == delegate) ) { return Map!(fun, Range)(fun[0],r); } static if( is(Range E:E[]) ) { return Map!(unaryFun!fun, E[])(r[]); } else { return Map!(unaryFun!fun, Range)(r); } } } }
Comment #5 by sandford — 2011-05-19T17:36:31Z
*oops* forgot the else statements template map(fun...) { auto map(Range)(Range r) { static if (fun.length > 1) { return Map!(unaryFun!(adjoin!(staticMap!(unaryFun,fun))),Range)(r); } else { static if( is(typeof(fun[0]) == delegate) ) { return Map!(fun, Range)(fun[0],r); } else static if( is(typeof(unaryFun!fun) == delegate) ) { return Map!(unaryFun!fun, Range)(unaryFun!fun,r); } else static if( is(Range E:E[]) ) { return Map!(unaryFun!fun, E[])(r[]); } else { return Map!(unaryFun!fun, Range)(r); } } } }
Comment #6 by yebblies — 2011-07-03T09:57:48Z
None of these examples fail for me with dmd 2.054 head on win32. Can anybody reproduce this with a current dmd?
Comment #7 by sandford — 2011-07-03T17:58:29Z
I've had trouble with map in DMD 2.053 and fixed it with this patch. I've even updated the patch to the new internal struct style being used in std.algorithm. (not-yet posted). But this has been due to map not handling fixed sized arrays: ubyte[12] datum; map!"a"(datum); Which as of this evening's SVN, is still true. I don't know about the original code which spawned this bug report, but once fixed-sized arrays work, I can re-test it.
Comment #8 by bearophile_hugs — 2011-07-03T18:28:49Z
(In reply to comment #7) > I've had trouble with map in DMD 2.053 and fixed it with this patch. I've even > updated the patch to the new internal struct style being used in std.algorithm. > (not-yet posted). But this has been due to map not handling fixed sized arrays: > > ubyte[12] datum; > map!"a"(datum); > > Which as of this evening's SVN, is still true. I don't know about the original > code which spawned this bug report, but once fixed-sized arrays work, I can > re-test it. I'd like map to work on fixed-size arrays too, but I think Andrei doesn't want this to be fixed.
Comment #9 by sandford — 2011-07-05T17:14:51Z
I added a new bug report for the fixed-sized array issue: Issue 6256. But otherwise, this appears to be fixed as of DMD 2.053.