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
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 #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
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.