Some code that produces the strange behavior I'm seeing:
shared class MyClass {
this() {}
this(As...)(As args) if (As.length > 0) {}
}
void main() {
pragma(msg, typeof(new MyClass));
pragma(msg, typeof(new MyClass(1, 2, 3, "hello world")));
pragma(msg, typeof(new shared(MyClass)));
pragma(msg, typeof(new shared(MyClass)(1, 2, 3, "hello world")));
}
Expected output of compilation:
shared(MyClass)
shared(MyClass)
shared(MyClass)
shared(MyClass)
Actual output of compilation:
test.d(7): Error: none of the overloads of `__ctor` are callable using a non-shared object, candidates are:
test.d(2): `test.MyClass.this()`
test.d(3): `__ctor(As...)(As args)`
with `As = ()`
must satisfy the following constraint:
` As.length > 0`
_error_
MyClass
shared(MyClass)
test.d(10): Error: none of the overloads of `this` are callable using argument types `(int, int, int, string) shared`, candidates are:
test.d(2): `test.MyClass.this()`
test.d(3): `__ctor(As...)(As args)`
_error_
Compiler version: 64-bit, v2.096.1, on Linux
What this seems to illustrate is that template member functions of a shared class are not implicitly shared. Alarmingly, this example illustrates this is true specifically for template constructors, meaning if a shared class has a template constructor that's not explicitly shared, it's possible to construct a non-shared instance of the shared class.
Why does this happen? Is it intended behavior? I'm still somewhat new to D, so I'm not prepared to submit this as an issue quite yet; for all I know, there might be a good reason it works this way.
This confusing problem really bit me in the patootie in a personal project earlier. Fortunately, although it was difficult to guess what was going on, once I did, it was an easy fix: namely, a template member function explicitly marked as shared is, of course, compiled as shared, as desired.