--- struct S { this(this) {} @disable void opAssign(S); } struct T { S s; } void main() { S s1, s2; static assert(!__traits(compiles, s1 = s2)); T t1, t2; static assert(!__traits(compiles, t1.tupleof = t2.tupleof)); static assert(!__traits(compiles, t1 = t2)); // assert fails } ---
Hum... the issue is that T simply doesn't care about S's opAssign: It generates its own opAssign via "postblit-copy-move" (of all of T at once I mean). This isn't strictly *wrong*, its just a pretty dirty way of doing things, and I'm pretty sure it's inefficient, and it definitly defeats the purpose of having an opAssign to begin with. It *is* the only way to provide *strong* exception guarantees though, for a compiler generated elaborate opAssign, in case one of the member's opAssign throws. *Should* we guarantee strong exception safety though? I'm unsure.
Commit pushed to master at https://github.com/D-Programming-Language/phobos https://github.com/D-Programming-Language/phobos/commit/c930d8bd5e5246653a0300aac791b4c82b0466c5 [Workaround] Disable some tests because of Issue 11202. Issue URL: http://d.puremagic.com/issues/show_bug.cgi?id=11202
*** Issue 11272 has been marked as a duplicate of this issue. ***
opAssign for a struct is used only if it is defined for that particular struct. If the struct defines a postblit, but not an opAssign the compiler steps in and generates an opAssign which basically calls the postblit. The whole point of this design is to avoid declaring both a copy constructor and a postblit when the 2 are identical. In this particular case, the compiler generates a postblit for T and as T does not define an opAssign, it will generate one. This is the intended behavior. If you want to make struct T uncopyable, you should disable its postblit >This isn't strictly *wrong*, its just a pretty dirty way of doing things, and I'm pretty sure it's inefficient, and it definitly defeats the purpose of having an opAssign to begin with. It does not defeat the purpose of opAssign. Postblit and opAssign are 2 different things. Postblit is used for initialization and opAssign for copies, however it is a feature that the compiler generates an opAssign from the postblit when the user does not define one. I suggest closing as wontfix.