Sudden-death static asserts were introduced due to comment #2 of bugzilla 77:
http://d.puremagic.com/issues/show_bug.cgi?id=77
However, they make static assert rather useless, since it gives you absolutely no context. To make it useful again,
In staticassert.c, line 68 (in DMD2.027):
error("is false");
if (!global.gag)
fatal();
---
change this to:
error("(%s) is false", exp->toChars());
---
(ie, remove the global.gag test).
Comment #1 by bugzilla — 2009-04-07T04:21:01Z
The static assert does give you file/line, so it does give context. But I'll add the expression print, too.
But I think static assert errors should be fatal. They usually involve misconfigured code, it is pointless to continue.
Comment #2 by clugdbug — 2009-04-07T05:55:51Z
(In reply to comment #1)
> The static assert does give you file/line, so it does give context. But I'll
> add the expression print, too.
>
> But I think static assert errors should be fatal. They usually involve
> misconfigured code, it is pointless to continue.
>
Yes, there will not be any more meaningful errors. But you still need a back trace.
If the static assert occurs in (say) a library template, knowing that it happened in std.functional at line 92 doesn't help very much -- you want to know where the problem is in _your_ code. (That's a real example, BTW).
Actually, I'll have another try, and see if I can create a backtrace, and THEN make it a fatal error. So I'm retracting this patch.
Comment #3 by kamm-removethis — 2009-04-07T10:21:03Z
Don, LDC already implemented template instantiation traces. Check StaticAssert::semantic2 and TemplateInstance::printInstantiationTrace. I emailed Walter about them at the time. If desired, I can provide a patch against DMD.
Comment #4 by clugdbug — 2009-04-07T10:47:27Z
(In reply to comment #3)
> Don, LDC already implemented template instantiation traces. Check
> StaticAssert::semantic2 and TemplateInstance::printInstantiationTrace. I
> emailed Walter about them at the time. If desired, I can provide a patch
> against DMD.
That'd be great!
Comment #5 by shro8822 — 2009-04-07T11:07:20Z
For that matter, if template errors could all be given optional (some flag?) stack traces (not just chained errors) that would be cool.
I'm thinking somthing like:
template error foo bla bla bla.
invoked at file.d:7235 from TBar
invoked at file.d:752 from TBaz
invoked at code.d:7235 from Bling
...
maybe (another flag?) some formatted printing of the args to (limited to 80 columns)
Comment #6 by kamm-removethis — 2009-04-08T07:43:57Z
Created attachment 318
template instantiation trace patch
patch against DMD 1.043, superficially tested
Note that this originated as a hack and might have been possible without adding tinst to Scope and TemplateInstance. There were discussions about including only certain template instantiations in such a trace: http://www.mail-archive.com/[email protected]/msg03614.html
Comment #7 by clugdbug — 2009-04-09T02:43:52Z
Christian -- Thanks, this is fantastic!
I've modified it so that it detects recursive template instantiations -- this dramatically reduces the size of the trace. A patch will follow shortly.
Comment #8 by clugdbug — 2009-04-09T04:18:13Z
Created attachment 319
patch for dmd2.028
I've adjusted the backtrace in two ways:
(1) displays line numbers in what I believe is a more IDE-friendly manner;
(2) detects recursive template instantiations and collapses them into a single line.
I've made no changes other than to the InstantiationTrace function.
Comment #9 by clugdbug — 2009-04-09T04:24:33Z
Error messages generated from my patch for the code below:
bug.d(2): Error: static assert (0) is false
bug.d(9): instantiatied from here: bar!()
bug.d(14): 100 recursive instantiations from here: foo!(196)
bug.d(19): 253 recursive instantiations from here: baz!(300)
(Oops -- just realised I there's a typo in "instantiated" in the non-recursive messages. That's easy to fix).
Note that it detects the recursive instantiation in foo!(), even though it is instantiated from three different places.
--------
template bar() {
static assert(0);
}
template foo(int N) {
static if (N>0) {
static if (N&1) alias foo!(N-3) foo;
else alias foo!(N-1) foo;
} else alias bar!() foo;
}
template baz(int M) {
static if (M<50) {
alias foo!(M*4) baz;
} else alias baz!(M-1) baz;
}
void main() {
int x = baz!(300);
}
Comment #10 by shro8822 — 2009-04-09T12:33:50Z
(In reply to comment #9)
> Note that it detects the recursive instantiation in foo!(), even though it is
> instantiated from three different places.
it would be nice to have (maybe as an "even more verbose" option) a breakdown of recursive invocations:
bug.d(14): 100 recursive instantiations from here: foo!(196) [50 at bug.d(7), 50 at bug.d(8)]
Comment #11 by clugdbug — 2009-04-18T17:13:35Z
Found another bug in this patch. Should start the count from 0, not 1. Otherwise you can get a segfault when the out-by-1 error shows up in the "only show first and last iterations" case.
in TemplateInstance::printInstantiationTrace()
// determine instantiation depth and number of recursive instantiations
int n_instantiations = 0;
Comment #12 by leandro.lucarella — 2009-12-15T07:14:58Z