D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 11202 - Copy constructor is called instead of assignment on member
Summary: Copy constructor is called instead of assignment on member
Status: RESOLVED WONTFIX
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords: wrong-code
: 11272 (view as issue list)
Depends on:
Blocks:
 
Reported: 2013-10-09 00:13 UTC by Denis Shelomovskii
Modified: 2020-06-25 08:19 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Denis Shelomovskii 2013-10-09 00:13:52 UTC
---
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
}
---
Comment 1 monarchdodra 2013-10-09 00:52:12 UTC
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.
Comment 3 monarchdodra 2013-10-15 06:03:31 UTC
*** Issue 11272 has been marked as a duplicate of this issue. ***
Comment 4 RazvanN 2018-09-06 12:13:40 UTC
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.