Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement copy constructor #8688

Merged
merged 31 commits into from Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3e77e7a
Parse copy constructor
RazvanN7 Sep 11, 2018
65b3605
Semantic analysis of copy constructor
RazvanN7 Sep 11, 2018
0d561a2
Lower AssignExp to copyCtor call
RazvanN7 Sep 11, 2018
c96eeb6
Add errors messages for wrong usage of implicit and copy ctor with po…
RazvanN7 Sep 11, 2018
3c34b2b
Implement copy consutructor call for arameter passing and function re…
RazvanN7 Sep 11, 2018
e3b4d49
Implement generation of copy constructors
RazvanN7 Sep 11, 2018
bcf8820
Implement opAssign generation
RazvanN7 Sep 11, 2018
f19669a
Add tests
RazvanN7 Sep 11, 2018
530791a
Make structs with copy ctor non-pod
RazvanN7 Sep 11, 2018
14a8117
Fix astbase + line number in tests
RazvanN7 Sep 11, 2018
3434b7a
Update .h files
RazvanN7 Sep 13, 2018
9c63f4d
Address feedback comments
RazvanN7 Sep 13, 2018
02fea7a
[WIP] Remove implicit
RazvanN7 Sep 21, 2018
2e97c40
Fix function overload resolution
RazvanN7 Sep 25, 2018
908b1e9
Postblit precedence
RazvanN7 Sep 28, 2018
1214ce6
Fix error message for argument with copy constructor
RazvanN7 Oct 4, 2018
ec0d6f9
Add copy ctor generation without implicit
RazvanN7 Oct 8, 2018
b85d853
Delete wrongfully added code from rebase
RazvanN7 Oct 8, 2018
912c304
Remove last traces of implicit + update .h files
RazvanN7 Oct 8, 2018
0bdd807
Add scope parameter to all callMatch calls in dmd/dtemplate.d
RazvanN7 Oct 22, 2018
95f2e59
Delete generation of opAssign and tweak generation of field copy cons…
RazvanN7 Dec 17, 2018
69b1cea
Add possiblity of defining default parameters for copy constructors
RazvanN7 Dec 17, 2018
a9e4c1d
Modify generation of copy constructors to match the DIP
RazvanN7 Jan 15, 2019
7c07c3f
solve mir failure
RazvanN7 Jan 16, 2019
30ffb88
Address feedback
RazvanN7 Jan 17, 2019
af93051
Delete isCopyCtor method
RazvanN7 Jan 17, 2019
db88573
Make definition of both rvalue constructor and copy constructor an error
RazvanN7 Jan 30, 2019
4410417
Add changelog entry
RazvanN7 Mar 26, 2019
95777c2
Add return scope for generated copy constructor parameter
RazvanN7 Mar 27, 2019
1aeffd1
Address feedback
RazvanN7 Mar 27, 2019
17b174c
Fix changelog + add tests
RazvanN7 Mar 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
179 changes: 179 additions & 0 deletions changelog/copy_constructor.dd
@@ -0,0 +1,179 @@
Copy Constructor

With this release, the D language compiler implements the full functionality of the
copy constructor described extensively in this DIP [1].

$(P Copy constructors are used to initialize a `struct` instance from
another `struct` of the same type.)

$(P A constructor declaration is a copy constructor declaration if and only if it is a constructor
declaration that takes only one non-default parameter by reference that is
of the same type as `typeof(this)`, followed by any number of default parameters:)

---
struct A
{
this(ref return scope A rhs) {} // copy constructor
this(ref return scope const A rhs, int b = 7) {} // copy constructor with default parameter
}
---

$(P The copy constructor is type checked as a normal constructor.)

$(P If a copy constructor is defined, implicit calls to it will be inserted
in the following situations:)

$(OL
$(LI When a variable is explicitly initialized:)
---
struct A
{
this(ref return scope A rhs) {}
}

void main()
{
A a;
A b = a; // copy constructor gets called
}
---

$(LI When a parameter is passed by value to a function:)
---
struct A
{
this(ref return scope A another) {}
}

void fun(A a) {}

void main()
{
A a;
fun(a); // copy constructor gets called
}
---

$(LI When a parameter is returned by value from a function and Named Returned Value Optiomization (NRVO)
cannot be performed:)
---
struct A
{
this(ref return scope A another) {}
}

A fun()
{
A a;
return a; // NRVO, no copy constructor call
}

A a;
A gun()
{
return a; // cannot perform NRVO, rewrite to: return (A __tmp; __tmp.copyCtor(a));
}

void main()
{
A a = fun();
A b = gun();
}
---
)

$(P When a copy constructor is defined for a `struct`, all
implicit blitting is disabled for that `struct`:
)
---
struct A
{
int[] a;
this(ref return scope A rhs) {}
}

void fun(immutable A) {}

void main()
{
immutable A a;
fun(a); // error: copy constructor cannot be called with types (immutable) immutable
}
---

$(P The copy constructor can be overloaded with different qualifiers applied
to the parameter (copying from a qualified source) or to the copy constructor
itself (copying to a qualified destination):
)
---
struct A
{
this(ref return scope A another) {} // 1 - mutable source, mutable destination
this(ref return scope immutable A another) {} // 2 - immutable source, mutable destination
this(ref return scope A another) immutable {} // 3 - mutable source, immutable destination
this(ref return scope immutable A another) immutable {} // 4 - immutable source, immutable destination
}

void main()
{
A a;
immutable A ia;

A a2 = a; // calls 1
A a3 = ia; // calls 2
immutable A a4 = a; // calls 3
immutable A a5 = ia; // calls 4
}
---

$(P The `inout` qualifier may be applied to the copy constructor parameter in
order to specify that mutable, `const`, or `immutable` types are treated the same:
)
---
struct A
{
this(ref return scope inout A rhs) immutable {}
}

void main()
{
A r1;
const(A) r2;
immutable(A) r3;

// All call the same copy constructor because `inout` acts like a wildcard
immutable(A) a = r1;
immutable(A) b = r2;
immutable(A) c = r3;
}
---

$(P A copy constructor is generated implicitly by the compiler for a `struct S`
if all of the following conditions are met:)

$(OL
$(LI `S` does not explicitly declare any copy constructors;)
$(LI `S` defines at least one direct member that has a copy constructor, and that
member is not overlapped (by means of `union`) with any other member.)
)

$(P If the restrictions above are met, the following copy constructor is generated:)
---
this(ref return scope inout(S) src) inout
{
foreach (i, ref inout field; src.tupleof)
this.tupleof[i] = field;
}
---

$(P If the generated copy constructor fails to type check, it will receive the `@disable` attribute.)

$(P f an `union S` has fields that define a copy constructor, whenever an object of type `S`
is initialized by copy, an error will be issued. The same rule applies to overlapped fields
(anonymous unions).)

$(P A `struct` that defines a copy constructor is not a POD.)

[1] https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1018.md


2 changes: 2 additions & 0 deletions src/dmd/aggregate.h
Expand Up @@ -164,6 +164,8 @@ class StructDeclaration : public AggregateDeclaration
FuncDeclarations postblits; // Array of postblit functions
FuncDeclaration *postblit; // aggregate postblit

bool hasCopyCtor; // copy constructor

FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals
FuncDeclaration *xcmp; // TypeInfo_Struct.xopCmp
FuncDeclaration *xhash; // TypeInfo_Struct.xtoHash
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/astbase.d
Expand Up @@ -830,7 +830,7 @@ struct ASTBase

extern (C++) final class CtorDeclaration : FuncDeclaration
{
extern (D) this(const ref Loc loc, Loc endloc, StorageClass stc, Type type)
extern (D) this(const ref Loc loc, Loc endloc, StorageClass stc, Type type, bool isCopyCtor = false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameters with default values are usually not allowed in DMD.

{
super(loc, endloc, Id.ctor, stc, type);
}
Expand Down
1 change: 1 addition & 0 deletions src/dmd/declaration.h
Expand Up @@ -664,6 +664,7 @@ class FuncLiteralDeclaration : public FuncDeclaration
class CtorDeclaration : public FuncDeclaration
{
public:
bool isCpCtor;
Dsymbol *syntaxCopy(Dsymbol *);
const char *kind() const;
const char *toChars();
Expand Down
4 changes: 3 additions & 1 deletion src/dmd/dstruct.d
Expand Up @@ -207,6 +207,8 @@ extern (C++) class StructDeclaration : AggregateDeclaration
FuncDeclarations postblits; // Array of postblit functions
FuncDeclaration postblit; // aggregate postblit

bool hasCopyCtor; // copy constructor

FuncDeclaration xeq; // TypeInfo_Struct.xopEquals
FuncDeclaration xcmp; // TypeInfo_Struct.xopCmp
FuncDeclaration xhash; // TypeInfo_Struct.xtoHash
Expand Down Expand Up @@ -553,7 +555,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration

ispod = StructPOD.yes;

if (enclosing || postblit || dtor)
if (enclosing || postblit || dtor || hasCopyCtor)
ispod = StructPOD.no;

// Recursively check all fields are POD.
Expand Down