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 move constructor #16876

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/src/dmd/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ class StructDeclaration : public AggregateDeclaration
bool zeroInit(bool v);
bool hasIdentityAssign() const; // true if has identity opAssign
bool hasIdentityAssign(bool v);
bool hasMoveAssign() const; // true if has identity opAssign
bool hasMoveAssign(bool v);
bool hasBlitAssign() const; // true if opAssign is a blit
bool hasBlitAssign(bool v);
bool hasIdentityEquals() const; // true if has identity opEquals
Expand All @@ -185,6 +187,8 @@ class StructDeclaration : public AggregateDeclaration
bool hasNoFields(bool v);
bool hasCopyCtor() const; // copy constructor
bool hasCopyCtor(bool v);
bool hasMoveCtor() const; // copy constructor
bool hasMoveCtor(bool v);
// Even if struct is defined as non-root symbol, some built-in operations
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
// For those, today TypeInfo_Struct is generated in COMDAT.
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@

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

Check warning on line 706 in compiler/src/dmd/astbase.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/astbase.d#L706

Added line #L706 was not covered by tests
{
super(loc, endloc, Id.ctor, stc, type);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/backend/debugprint.d
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@
@trusted
void WRfunc(const char* msg, Symbol* sfunc, block* startblock)
{
printf("............%s...%s().............\n", msg, sfunc.Sident.ptr);
printf("............%s...%s()\n", msg, sfunc.Sident.ptr);

Check warning on line 512 in compiler/src/dmd/backend/debugprint.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/backend/debugprint.d#L512

Added line #L512 was not covered by tests
numberBlocks(startblock);
for (block *b = startblock; b; b = b.Bnext)
WRblock(b);
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/backend/dout.d
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ private void writefunc2(Symbol *sfunc, ref GlobalOptimizer go)
{
func_t *f = sfunc.Sfunc;

//printf("writefunc(%s)\n",sfunc.Sident.ptr);
debugb && printf("===================== writefunc %s =================\n",sfunc.Sident.ptr);
//symbol_print(sfunc);
debug debugy && printf("writefunc(%s)\n",sfunc.Sident.ptr);

Expand Down
216 changes: 213 additions & 3 deletions compiler/src/dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,9 @@
return xpostblit;
}

/* ===================================== Copy Constructor ========================== */
static if (1) {

/**
* Generates a copy constructor declaration with the specified storage
* class for the parameter and the function.
Expand All @@ -1552,18 +1555,19 @@
* sd = the `struct` that contains the copy constructor
* paramStc = the storage class of the copy constructor parameter
* funcStc = the storage class for the copy constructor declaration
* copyCtor = true for copy constructor, false for move constructor
*
* Returns:
* The copy constructor declaration for struct `sd`.
*/
private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc, bool copyCtor)
{
auto fparams = new Parameters();
auto structType = sd.type;
fparams.push(new Parameter(Loc.initial, paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null));
ParameterList pList = ParameterList(fparams);
auto tf = new TypeFunction(pList, structType, LINK.d, STC.ref_);
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, copyCtor, !copyCtor);
ccd.storage_class |= funcStc;
ccd.storage_class |= STC.inference;
ccd.isGenerated = true;
Expand Down Expand Up @@ -1726,7 +1730,7 @@
//printf("generating copy constructor for %s\n", sd.toChars());
const MOD paramMod = MODFlags.wild;
const MOD funcMod = MODFlags.wild;
auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod), true);
auto copyCtorBody = generateCopyCtorBody(sd);
ccd.fbody = copyCtorBody;
sd.members.push(ccd);
Expand All @@ -1747,3 +1751,209 @@
}
return true;
}

}

/* ===================================== Move Constructor ========================== */
static if (1) {

/**
* Generates a move constructor declaration with the specified storage
* class for the parameter and the function.
*
* Params:
* sd = the `struct` that contains the move constructor
* paramStc = the storage class of the move constructor parameter
* funcStc = the storage class for the move constructor declaration
*
* Returns:
* The move constructor declaration for struct `sd`.
*/
private CtorDeclaration generateMoveCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
{
/* Although the move constructor is declared as `=this(S s) { ... }`,
* it is implemented as `=this(ref S s) { ... }`
*/
return generateCopyCtorDeclaration(sd, paramStc, funcStc, false);

Check warning on line 1777 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1777

Added line #L1777 was not covered by tests
}

/**
* Generates a trivial move constructor body that simply does memberwise
* initialization:
*
* this.field1 = rhs.field1;
* this.field2 = rhs.field2;
* ...
*
* Params:
* sd = the `struct` declaration that contains the copy constructor
*
* Returns:
* A `CompoundStatement` containing the body of the copy constructor.
*/
private Statement generateMoveCtorBody(StructDeclaration sd)
{
Loc loc;
Expression e;
foreach (v; sd.fields)

Check warning on line 1798 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1796-L1798

Added lines #L1796 - L1798 were not covered by tests
{
auto ec = new AssignExp(loc,

Check warning on line 1800 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1800

Added line #L1800 was not covered by tests
new DotVarExp(loc, new ThisExp(loc), v),
new DotVarExp(loc, new IdentifierExp(loc, Id.p), v));
e = Expression.combine(e, ec);

Check warning on line 1803 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1803

Added line #L1803 was not covered by tests
//printf("e.toChars = %s\n", e.toChars());
}
Statement s1 = new ExpStatement(loc, e);
return new CompoundStatement(loc, s1);

Check warning on line 1807 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1806-L1807

Added lines #L1806 - L1807 were not covered by tests
}

/**
* Determine if a move constructor is needed for struct sd,
* if the following conditions are met:
*
* 1. sd does not define a move constructor
* 2. at least one field of sd defines a move constructor
*
* Params:
* sd = the `struct` for which the move constructor is generated
* hasMoveCtor = set to true if a move constructor is already present
*
* Returns:
* `true` if one needs to be generated
* `false` otherwise
*/
bool needMoveCtor(StructDeclaration sd, out bool hasMoveCtor)
{
if (global.errors)
return false;

auto ctor = sd.search(sd.loc, Id.moveCtor);
if (ctor)
{
if (ctor.isOverloadSet())
return false;
if (auto td = ctor.isTemplateDeclaration())
ctor = td.funcroot;

Check warning on line 1836 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1833-L1836

Added lines #L1833 - L1836 were not covered by tests
}

CtorDeclaration moveCtor;
CtorDeclaration rvalueCtor;

if (!ctor)
goto LcheckFields;

overloadApply(ctor, (Dsymbol s)

Check warning on line 1845 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1845

Added line #L1845 was not covered by tests
{
if (s.isTemplateDeclaration())
return 0;
auto ctorDecl = s.isCtorDeclaration();
assert(ctorDecl);
if (ctorDecl.isMoveCtor)

Check warning on line 1851 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1847-L1851

Added lines #L1847 - L1851 were not covered by tests
{
if (!moveCtor)
moveCtor = ctorDecl;
return 0;

Check warning on line 1855 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1853-L1855

Added lines #L1853 - L1855 were not covered by tests
}

if (isRvalueConstructor(sd, ctorDecl))
rvalueCtor = ctorDecl;
return 0;

Check warning on line 1860 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1858-L1860

Added lines #L1858 - L1860 were not covered by tests
});

if (moveCtor)

Check warning on line 1863 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1863

Added line #L1863 was not covered by tests
{
if (rvalueCtor)

Check warning on line 1865 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1865

Added line #L1865 was not covered by tests
{
.error(sd.loc, "`struct %s` may not define both a rvalue constructor and a move constructor", sd.toChars());
errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
errorSupplemental(moveCtor.loc, "move constructor defined here");

Check warning on line 1869 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1867-L1869

Added lines #L1867 - L1869 were not covered by tests
}
hasMoveCtor = true;
return false;

Check warning on line 1872 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1871-L1872

Added lines #L1871 - L1872 were not covered by tests
}

LcheckFields:
VarDeclaration fieldWithMoveCtor;
// see if any struct members define a copy constructor
foreach (v; sd.fields)
{
if (v.storage_class & STC.ref_)
continue;

Check warning on line 1881 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1881

Added line #L1881 was not covered by tests
if (v.overlapped)
continue;

auto ts = v.type.baseElemOf().isTypeStruct();
if (!ts)
continue;
if (ts.sym.hasMoveCtor)
{
fieldWithMoveCtor = v;
break;

Check warning on line 1891 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1890-L1891

Added lines #L1890 - L1891 were not covered by tests
}
}

if (fieldWithMoveCtor && rvalueCtor)
{
.error(sd.loc, "`struct %s` may not define a rvalue constructor and have fields with move constructors", sd.toChars());
errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
errorSupplemental(fieldWithMoveCtor.loc, "field with move constructor defined here");
return false;

Check warning on line 1900 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1897-L1900

Added lines #L1897 - L1900 were not covered by tests
}
else if (!fieldWithMoveCtor)
return false;
return true;

Check warning on line 1904 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1904

Added line #L1904 was not covered by tests
}

/**
* Generates a move constructor if needMoveCtor() returns true.
* The generated move constructor will be of the form:
* this(ref return scope inout(S) rhs) inout
* {
* this.field1 = rhs.field1;
* this.field2 = rhs.field2;
* ...
* }
*
* Params:
* sd = the `struct` for which the copy constructor is generated
* sc = the scope where the copy constructor is generated
*
* Returns:
* `true` if `struct` sd defines a copy constructor (explicitly or generated),
* `false` otherwise.
* References:
* https://dlang.org/spec/struct.html#struct-copy-constructor
*/
bool buildMoveCtor(StructDeclaration sd, Scope* sc)
{
//printf("buildMoveCtor() %s\n", sd.toChars());
bool hasMoveCtor;
if (!needMoveCtor(sd, hasMoveCtor))
return hasMoveCtor;

//printf("generating move constructor for %s\n", sd.toChars());
const MOD paramMod = MODFlags.wild;
const MOD funcMod = MODFlags.wild;
auto ccd = generateMoveCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
auto moveCtorBody = generateMoveCtorBody(sd);
ccd.fbody = moveCtorBody;
sd.members.push(ccd);
ccd.addMember(sc, sd);
const errors = global.startGagging();
Scope* sc2 = sc.push();
sc2.stc = 0;
sc2.linkage = LINK.d;
ccd.dsymbolSemantic(sc2);
ccd.semantic2(sc2);
ccd.semantic3(sc2);

Check warning on line 1948 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1935-L1948

Added lines #L1935 - L1948 were not covered by tests
//printf("ccd semantic: %s\n", ccd.type.toChars());
sc2.pop();
if (global.endGagging(errors) || sd.isUnionDeclaration())

Check warning on line 1951 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1950-L1951

Added lines #L1950 - L1951 were not covered by tests
{
ccd.storage_class |= STC.disable;
ccd.fbody = null;

Check warning on line 1954 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1953-L1954

Added lines #L1953 - L1954 were not covered by tests
}
return true;

Check warning on line 1956 in compiler/src/dmd/clone.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1956

Added line #L1956 was not covered by tests
}

}
10 changes: 8 additions & 2 deletions compiler/src/dmd/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,11 @@ extern (C++) class StructDeclaration : AggregateDeclaration
bool zeroInit; // !=0 if initialize with 0 fill
bool hasIdentityAssign; // true if has identity opAssign
bool hasBlitAssign; // true if opAssign is a blit
bool hasMoveAssign; // true if move assignment
bool hasIdentityEquals; // true if has identity opEquals
bool hasNoFields; // has no fields
bool hasCopyCtor; // copy constructor
bool hasMoveCtor; // move constructor
bool hasPointerField; // members with indirections
bool hasVoidInitPointers; // void-initialized unsafe fields
bool hasUnsafeBitpatterns; // @system members, pointers, bool
Expand Down Expand Up @@ -303,7 +305,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
* POD is defined as:
* $(OL
* $(LI not nested)
* $(LI no postblits, destructors, or assignment operators)
* $(LI no postblits, copy constructors, move constructors, destructors, or assignment operators)
* $(LI no `ref` fields or fields that are themselves non-POD)
* )
* The idea being these are compatible with C structs.
Expand All @@ -322,10 +324,14 @@ extern (C++) class StructDeclaration : AggregateDeclaration
bool hasCpCtorLocal;
needCopyCtor(this, hasCpCtorLocal);

bool hasMoveCtorLocal;
needMoveCtor(this, hasMoveCtorLocal);

if (enclosing || // is nested
search(this, loc, Id.postblit) || // has postblit
search(this, loc, Id.dtor) || // has destructor
hasCpCtorLocal) // has copy constructor
hasCpCtorLocal || // has copy constructor
hasMoveCtorLocal) // has move constructor
{
ispod = ThreeState.no;
return false;
Expand Down
Loading
Loading