Test case for the existing error message. To see, run rdmd -main tlclass.d
text/x-dsrc
85
Comments
Comment #0 by joseph.wakeling — 2013-12-10T02:45:33Z
If a developer tries to initialize a static/thread-local class instance with a value not knowable at compile time, the compiler will object with an error message as follows:
Error: variable %s is mutable. Only const or immutable class thread local variable are allowed, not %s
This easily leads to the wrong conclusion that thread-local class instances must themselves be const or immutable, rather than the reality that the initialization value must be.
This error message should be replaced with something more friendly, along the lines of
Cannot initialize thread-local class variable %s with a mutable value. Only const or immutable initial values are allowed (e.g. null).
Background: http://forum.dlang.org/post/[email protected]
Comment #1 by joseph.wakeling — 2013-12-10T02:47:36Z
Comment #2 by joseph.wakeling — 2013-12-10T09:13:13Z
Created attachment 1300
Test case for the existing error message. To see, run rdmd -main tlclass.d
Comment #3 by joseph.wakeling — 2013-12-10T09:14:48Z
The attached test case illustrates the error, in this case:
tlclass.d(8): Error: variable tlclass.a2 is mutable. Only const or immutable class thread local variable are allowed, not tlclass.A
Comment #4 by code — 2013-12-11T14:25:36Z
As I mentioned in the pull request, I believe what the error message is supposed to say is something along the lines of: "Thread-local mutable class variable cannot be initialized with reference to compile-time constant, use static constructor instead."
Has been a while since I implemented ClassReferenceExp for LDC, though.
Comment #5 by joseph.wakeling — 2013-12-11T14:52:56Z
OK, but "with reference to compile-time constant" is still not exactly obvious in its meaning (among other things, it's not clear if what is meant is "with reference to" or "with _a_ reference to", but either way I think we can still be clearer).
Comment #6 by code — 2013-12-11T14:55:26Z
(In reply to comment #5)
> OK, but "with reference to compile-time constant" is still not exactly obvious
> in its meaning (among other things, it's not clear if what is meant is "with
> reference to" or "with _a_ reference to", but either way I think we can still
> be clearer).
With *a* reference to – I stripped out the articles trying to make the error message as concise as possible, and missed that it would distort the meaning.
Comment #7 by joseph.wakeling — 2013-12-12T02:18:32Z
(In reply to comment #6)
> With *a* reference to – I stripped out the articles trying to make the error
> message as concise as possible, and missed that it would distort the meaning.
Easier to use "with a reference to" and "with respect to" respectively, for the two different cases (just for future reference:-).
What I'm really concerned about, though, is that to me that message is still pretty much incomprehensible about what it is that I actually did wrong. Even when clarified with instructions about what to do to resolve it (initialize to null or use static this) it's not obvious about what I got wrong or why it's wrong.
If I understand the logic right, the result of "new MyClass" is not knowable at compile time --> hence, a compile time constant; but inferring the former meaning from the latter is not obvious unless one already knows. Rather than requiring the programmer's knowledge and understanding to comprehend the error message, we should aim to use the error message to _increase_ the programmer's knowledge and understanding.
So, I want an error message that idiots like me can read and go, "Oh! THAT's why it's wrong," as well as understanding how to fix it. :-)
Comment #8 by code — 2013-12-12T05:51:44Z
(In reply to comment #7)
> If I understand the logic right, the result of "new MyClass" is not knowable at
> compile time
Actually it is, otherwise you'd get a "cannot be read/evaluated at compile time" error in the constructor.
The issue here is that in D global variables can only be initialized with statically known data (written to the relevant sections of the object file). For everything else, you need to use a static constructor.
While support for converting CTFE class instances into data blobs to write to an object file was implemented a while ago, variables of a class type are of course references and need to point somewhere. Now, if a variable is either immutable or explicitly shared between threads, that's fine, you just emit the data once and then initialize the variable to point to that. However, for mutable, thread-local data, this simple scheme doesn't work, as it would require a new instance to be created for each new thread.
I didn't really think about whether it would be possible to resolve that situation by emitting all the instance data into the TLS section yet, but this certainly isn't implemented in DMD right now. Thus, initializing class references that are (potentially) modified from more than one thread with CTFE instances is disallowed.
Comment #9 by ibuclaw — 2017-12-24T12:52:23Z
Arguably, pointer to struct initializers suffer from the same problem.
---
module diag;
struct S
{
int a;
}
S* s = new S;
---
Error: variable diag.s is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not S*
---
Comment #10 by github-bugzilla — 2017-12-27T18:57:44Z