Skip to content

Commit

Permalink
build default move constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Jan 6, 2025
1 parent 45e4a09 commit c1a2eb6
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 12 deletions.
153 changes: 143 additions & 10 deletions compiler/src/dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -1556,11 +1556,12 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
* Returns:
* The copy constructor declaration for struct `sd`.
*/
private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
private CtorDeclaration generateCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc, bool move)
{
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));
StorageClass stc = move ? 0 : STC.ref_; // the only difference between copy or move
fparams.push(new Parameter(Loc.initial, paramStc | stc | 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);
Expand All @@ -1584,22 +1585,150 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const
* Returns:
* A `CompoundStatement` containing the body of the copy constructor.
*/
private Statement generateCopyCtorBody(StructDeclaration sd)
private Statement generateCtorBody(StructDeclaration sd, bool move)
{
Loc loc;
Expression e;
foreach (v; sd.fields)
{
Expression rhs = new DotVarExp(loc, new IdentifierExp(loc, Id.p), v);
if (move)
rhs.rvalue = true;

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1596

Added line #L1596 was not covered by tests
auto ec = new AssignExp(loc,
new DotVarExp(loc, new ThisExp(loc), v),
new DotVarExp(loc, new IdentifierExp(loc, Id.p), v));
rhs);
e = Expression.combine(e, ec);
//printf("e.toChars = %s\n", e.toChars());
}
Statement s1 = new ExpStatement(loc, e);
return new CompoundStatement(loc, s1);
}

/******************************************
* Find root `this` constructor for struct sd.
* (root is starting position for overloaded constructors)
* Params:
* sd = the `struct` to be searched
* ctor = `this` if found, otherwise null
* Result:
* false means `this` found in overload set
*/
private bool findStructConstructorRoot(StructDeclaration sd, out Dsymbol ctor)
{
ctor = sd.search(sd.loc, Id.ctor); // search Aggregate.searchCtor() ?
if (ctor)
{
if (ctor.isOverloadSet())
return false;
if (auto td = ctor.isTemplateDeclaration())
ctor = td.funcroot;
}
return true;
}

/***********************************************
* Find move and copy constructors (if any) starting at `ctor`
* Params:
* ctor = `this` constructor root
* copyCtor = set to first copy constructor found, or null
* moveCtor = set to first move constructor found, or null
*/
private void findMoveAndCopyConstructors(Dsymbol ctor, out CtorDeclaration copyCtor, out CtorDeclaration moveCtor)
{
overloadApply(ctor, (Dsymbol s)
{
if (s.isTemplateDeclaration())
return 0;
auto ctorDecl = s.isCtorDeclaration();
assert(ctorDecl);
if (ctorDecl.isCpCtor)
{
if (!copyCtor)
copyCtor = ctorDecl;
}
else if (ctorDecl.isMoveCtor)
{
if (!moveCtor)
moveCtor = ctorDecl;
}
return 0;
});
}

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

Dsymbol ctor;
if (!findStructConstructorRoot(sd, ctor))
return;

CtorDeclaration copyCtor;
CtorDeclaration moveCtor;

if (ctor)
findMoveAndCopyConstructors(ctor, copyCtor, moveCtor);

if (moveCtor)
hasMoveCtor = true;

if (copyCtor)
{
hasCopyCtor = true;
return;
}

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

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1706

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

auto ts = v.type.baseElemOf().isTypeStruct();
if (!ts)
continue;
if (ts.sym.hasCopyCtor)
{
fieldWithCpCtor = v;
break;
}
}

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

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/clone.d#L1722-L1725

Added lines #L1722 - L1725 were not covered by tests
}
else if (!fieldWithCpCtor)
return;
needCopyCtor = true;
}

/**
* Determine if a copy constructor is needed for struct sd,
* if the following conditions are met:
Expand Down Expand Up @@ -1723,17 +1852,21 @@ LcheckFields:
* References:
* https://dlang.org/spec/struct.html#struct-copy-constructor
*/
bool buildCopyCtor(StructDeclaration sd, Scope* sc, out bool hasMoveCtor)
bool buildCopyCtor(StructDeclaration sd, Scope* sc/*, out bool hasMoveCtor*/)
{
bool hasCpCtor;
if (!needCopyCtor(sd, hasCpCtor, hasMoveCtor))
return hasCpCtor;
bool hasCopyCtor;
bool hasMoveCtor;
bool needCopyCtor;
bool needMoveCtor;
needCopyOrMoveCtor(sd, hasCopyCtor, hasMoveCtor, needCopyCtor, needMoveCtor);
if (!needCopyCtor)
return hasCopyCtor;

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

//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 copyCtorBody = generateCopyCtorBody(sd);
auto ccd = generateCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod), false);
auto copyCtorBody = generateCtorBody(sd, false);
ccd.fbody = copyCtorBody;
sd.members.push(ccd);
ccd.addMember(sc, sd);
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dmd/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,9 @@ extern (C++) class StructDeclaration : AggregateDeclaration

bool hasCpCtorLocal;
bool hasMoveCtorLocal;
needCopyCtor(this, hasCpCtorLocal, hasMoveCtorLocal);
bool needCopyCtor;
bool needMoveCtor;
needCopyOrMoveCtor(this, hasCpCtorLocal, hasMoveCtorLocal, needCopyCtor, needMoveCtor);

if (enclosing || // is nested
search(this, loc, Id.postblit) || // has postblit
Expand Down
12 changes: 11 additions & 1 deletion compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3007,8 +3007,18 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor

buildDtors(sd, sc2);

bool hasCopyCtor;
bool hasMoveCtor;
sd.hasCopyCtor = buildCopyCtor(sd, sc2, hasMoveCtor);
bool needCopyCtor;
bool needMoveCtor;
needCopyOrMoveCtor(sd, hasCopyCtor, hasMoveCtor, needCopyCtor, needMoveCtor);
if (needCopyCtor)
{
assert(hasCopyCtor == false);
buildCopyCtor(sd, sc2);
hasCopyCtor = true;
}
sd.hasCopyCtor = hasCopyCtor;
sd.hasMoveCtor = hasMoveCtor;

sd.postblit = buildPostBlit(sd, sc2);
Expand Down

0 comments on commit c1a2eb6

Please sign in to comment.