Bug 3952 – pragma(msg,...) has bugs + alternative idea

Status
RESOLVED
Resolution
WORKSFORME
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-03-13T05:11:28Z
Last change time
2018-05-17T07:44:37Z
Keywords
pull
Assigned to
No Owner
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2010-03-13T05:11:28Z
The D2 docs state about pragma(msg, ...): Prints a message while compiling, the AssignExpressions must be string literals: pragma(msg, "compiling..."); I think that means it must accept string literals only, and produce a syntax error in all the other cases. In practice if you look at the following program the pragma(msg, foo0()); prints the "this is a test" string. This is useful, but in many other cases this doesn't work or works in strange ways: string foo0() { return "this is a test"; } string foo1() { return ""; } string foo2() { string result; return result; } string foo3() { return []; } pragma(msg, foo0()); pragma(msg, foo1()); pragma(msg, foo2()); pragma(msg, foo3()); string hello = "red"; pragma(msg, hello); pragma(msg, 12); void main() {} The compile-timeoutput of that program is: this is a test null [] hello 12 So I think pragma(msg,...) needs some debugging. ------------- This program doesn't compile: enum int x = 10; static if (x) pragma(msg, "true"); else pragma(msg, "false"); void main() {} It prints the error: test.d(4): Declaration expected, not 'else' I can understand the cause of that error, but to improve the usefulness of the pragma and avoid errors like that one I think the compiler can rewrite the pragma(msg, ...) as: {pragma(msg, ...);} ------------- To increase the usefulness of the pragma(msg, ...) I suggest to not let it print a newline after the string. ------------- D2 programs have a better and better CTFE, so the need for good enough printing is growing. So I suggest to add a simple printing function that works in the same way both at compile-time in CTFE and at runtime. To keep things simple it can just print a string (literal or inside a variable) and it does NOT print a newline. It can be used in a loop too, in CTFE too, to print many things (so it's different from a pragma(msg,...): string foo(int i) { foreach (i, 0 .. 10) ctputs(ToString!(i)); } Note that it's a true function, so there is no need for {}. "ctputs" is just one of the possible names of this function. Once such function is present, the pragma(msg,...) can probably be removed from the language.
Comment #1 by bearophile_hugs — 2010-08-06T09:34:59Z
In D1 there were no template constraints, so to test the template arguments I used to add some static asserts inside them. So a wrong template argument shows a error message written by me that explains why the instantiation has failed (unfortunately those error messages show the line number inside the template). When a template constraint is composed of some different parts in &&, it's less easy to understand what condition has failed, so I miss the error messages written by me. This is an example (that probably I will simplify), there are four conditions, and for a person that has not written this code, and is just using Phobos, it's not immediately obvious what part has failed: auto opBinary(string op, TOther)(TOther other) if (op == "~" && is(TOther == struct) && (!__traits(compiles, { void isTuple(U...)(Tuple!U){} isTuple(other); }) || distinctFieldNames!(T, TOther.TypesAndStrings)() )) { ... There is a simple solution. The simple template constraints often don't need extra error messages, so they can be left as they are now. Putting one or more error message inside a template constraints turns them into messy code, so in such cases it's better to move the tests elsewhere, in an external template/CTFE: template IsGoodFoo(T) { static if (...) { enum bool IsGoodFoo = true; } else { ctputs("this is an error message"); return false; } } void foo(T)(T x) if (IsGoodFoo!T) { ... So the ctputs() is usable for the template constraints error messages too.
Comment #2 by bearophile_hugs — 2010-08-07T00:14:07Z
Andrei has asked if just a pragma(msg) is enough for the error template constraints. In some situations it works. But to use pragma(msg) you have to guard it with a static if. So if the template constraint is a CTFE (that uses a normal 'if' instead of a 'static if') you can't use it. While ctputs() can be used, this shows the error message even if it's not required: bool isGoodFoo(int x) { if (x > 10) { return true; } else { pragma(msg, "no good"); // ctputs("no good"); return false; } } void foo(int N)() if (isGoodFoo(N)) { } void main() { foo!(20)(); }
Comment #3 by shro8822 — 2010-08-08T07:23:18Z
What about this case: auto Fn(T...)(T t) { foreach(Te; T) // compile time foreach { pragam(msg, "processing: " ~ Te.stringof) ... ctfe valid code } } void main() { Fn!(int, int, float)(1,2,3.14); // will be evaluated at _run time_ } // expected CT output: processing: int processing: int processing: float // expected runtime output: none
Comment #4 by bearophile_hugs — 2010-08-08T08:17:34Z
I don't understand what you exactly mean, but similar problems can be solved by: if (__ctfe) ctputs("..."); Or: if (!__ctfe) ctputs("...");
Comment #5 by bearophile_hugs — 2011-07-25T08:35:25Z
Comment #6 by shro8822 — 2011-07-25T10:13:37Z
I don't have a github account so I'll comment here: There is use for ways to create output at runtime, CTFE time and static expansion time. For instance this function: int TemplateCTFE(T...)(int j) { for (int i = 0; i < j; i++) { foreach(t; T) { pragma(msg, t.stringof); } } } When called like this from a CTFE context: TemplateCTFE!(int, char, float)(5); will only print "int\nchar\float" once rather than 5 times. IMHO this static-expansion-time ouput is more valuable than a CTFE time output (that would output 15 line from that call). OTOH, having both would be really nice.
Comment #7 by bearophile_hugs — 2011-07-25T10:47:25Z
(In reply to comment #6) > OTOH, having both would be really nice. There are no plans to remove pragma(msg) :-)
Comment #8 by kennytm — 2012-02-19T07:34:07Z
Comment #9 by github-bugzilla — 2012-02-20T13:52:07Z
Commits pushed to master at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/52494246e8f7ac08c3f5f40d379ced763e8103e3 fix Issue 3952 part 4: Add __ctfeWrite and __ctfeWriteln. This is the druntime part of the fix. https://github.com/D-Programming-Language/druntime/commit/58afd8b349567873777387119dc36a9e62e79457 Merge pull request #155 from kennytm/bug3952d_ctfeWriteln_again fix Issue 3952 part 4: Add __ctfeWrite and __ctfeWriteln.
Comment #10 by andrej.mitrovich — 2013-02-05T13:54:53Z
Is this resolved now?
Comment #11 by bearophile_hugs — 2013-02-05T14:57:11Z
(In reply to comment #10) > Is this resolved now? - - - - - - - - - - - - - - - - - This doesn't work: __ctfeWriteln("hello"); void main() {} It gives: temp.d(1): Error: unexpected ( in declarator temp.d(1): Error: basic type expected, not "hello" temp.d(1): Error: found '"hello"' when expecting ')' temp.d(1): Error: no identifier for declarator __ctfeWriteln(int) temp.d(1): Error: semicolon expected following function declaration temp.d(1): Error: Declaration expected, not ')' - - - - - - - - - - - - - - - - - While this gives no errors but prints nothing: int foo() { __ctfeWriteln(1); __ctfeWriteln("hello"); return 0; } enum x = foo(); void main() {} - - - - - - - - - - - - - - - - - I don't like the names __ctfeWriteln and __ctfeWrite, they are ugly. It's much better to call them ctWriteln and ctWrite. They are meant to be a clean and handy feature of the D language, not some temporary compiler-speciic hack. - - - - - - - - - - - - - - - - - I don't see the D docs about those two functions in the D site. They need to be documented. - - - - - - - - - - - - - - - - - So this is not resolved yet.
Comment #12 by andrej.mitrovich — 2013-02-05T15:04:49Z
Ok I can see now the Druntime pull was merged by accident. We're waiting for https://github.com/D-Programming-Language/dmd/pull/692
Comment #13 by bearophile_hugs — 2013-02-05T15:45:38Z
(In reply to comment #12) > Ok I can see now the Druntime pull was merged by accident. We're waiting for > https://github.com/D-Programming-Language/dmd/pull/692 Right. I don't know if this is supposed to work: __ctfeWriteln("hello"); void main() {} Regarding the bad __ctfeWriteln/__ctfeWrite names, I don't know what to do.
Comment #14 by dmitry.olsh — 2018-05-17T07:44:37Z
This is getting out of scope real quick. First the code: string foo0() { return "this is a test"; } string foo1() { return ""; } string foo2() { string result; return result; } string foo3() { return []; } pragma(msg, foo0()); pragma(msg, foo1()); pragma(msg, foo2()); pragma(msg, foo3()); //string hello = "red"; //pragma(msg, hello); pragma(msg, 12); void main() {} Now works as expected no [] literals. Except for static `hello`. __ctfeWrite is a separate issue so no point in doing it here. Lastly any bugs in pragma(msg, ...) are welcome as specific bugs.