Skip to content
Closed
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
17 changes: 17 additions & 0 deletions src/dmd/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,23 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return (ispod == StructPOD.yes);
}

/***************************************
* Determine if `struct` has an elaborate copy constructor.
*
* A `struct` has an elaborate copy constructor if:
* $(OL
* $(LI has a copy constructor)
* $(LI or has postblit)
* )
*
* Returns:
* `true` if struct has an elaborate copy constructor
*/
final bool hasElaborateCopyCtor()
{
return postblit || hasCopyCtor;
}

override final inout(StructDeclaration) isStructDeclaration() inout
{
return this;
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
if (auto ts = e.type.baseElemOf().isTypeStruct())
{
StructDeclaration sd = ts.sym;
if (sd.postblit || sd.hasCopyCtor)
if (sd.hasElaborateCopyCtor())
{
/* Create a variable tmp, and replace the argument e with:
* (tmp = e),tmp
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -8409,7 +8409,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
return;
}
if (sd.postblit || sd.hasCopyCtor)
if (sd.hasElaborateCopyCtor())
{
/* We have a copy constructor for this
*/
Expand Down
1 change: 1 addition & 0 deletions src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ immutable Msgtable[] msgtable =
{ "isZeroInit" },
{ "getTargetInfo" },
{ "getLocation" },
{ "hasElaborateCopyConstructor" },

// For C++ mangling
{ "allocator" },
Expand Down
22 changes: 22 additions & 0 deletions src/dmd/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ shared static this()
"isZeroInit",
"getTargetInfo",
"getLocation",
"hasElaborateCopyConstructor"
];

traitsStringTable._init(names.length);
Expand Down Expand Up @@ -617,6 +618,27 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
return True();
}
if (e.ident == Id.hasElaborateCopyConstructor)
{
if (dim != 1)
return dimError(1);

auto o = (*e.args)[0];
auto t = isType(o);
if (!t)
{
e.error("type expected as second argument of __traits `%s` instead of `%s`",
e.ident.toChars(), o.toChars());
return new ErrorExp();
}

Type tb = t.baseElemOf();
if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
{
return sd.hasElaborateCopyCtor() ? True() : False();
}
return False();
}
if (e.ident == Id.isNested)
{
if (dim != 1)
Expand Down
57 changes: 57 additions & 0 deletions test/compilable/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,60 @@ struct Outer
static assert(__traits(getLocation, Outer.Nested)[1] == 82);
static assert(__traits(getLocation, Outer.method)[1] == 84);

/******************************************/
// https://issues.dlang.org/show_bug.cgi?id=19902
// Define hasElaborateCopyConstructor trait

struct S
{
this (ref S rhs) {}
}

struct OuterS
{
struct S
{
this (ref S rhs) {}
}

S s;
}

void foo(T)()
{
struct S(U)
{
this (ref S rhs) {}
}
static assert (__traits(hasElaborateCopyConstructor, S!int));
}

struct U(T)
{
this (ref U rhs) {}
}

struct SPostblit
{
this(this) {}
}

struct NoCpCtor { }
class C19902 { }

static assert(__traits(hasElaborateCopyConstructor, S));
static assert(__traits(hasElaborateCopyConstructor, OuterS.S));
static assert(__traits(hasElaborateCopyConstructor, OuterS));
static assert(__traits(compiles, foo!int));
static assert(__traits(compiles, foo!S));
static assert(__traits(hasElaborateCopyConstructor, U!int));
static assert(__traits(hasElaborateCopyConstructor, U!S));
static assert(__traits(hasElaborateCopyConstructor, SPostblit));

static assert(!__traits(hasElaborateCopyConstructor, NoCpCtor));
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a test with a nested struct too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is Outer.S. Am I missing something?

static assert(!__traits(hasElaborateCopyConstructor, C19902));
static assert(!__traits(hasElaborateCopyConstructor, int));

// Check that invalid use cases don't compile
static assert(!__traits(compiles, __traits(hasElaborateCopyConstructor)));
static assert(!__traits(compiles, __traits(hasElaborateCopyConstructor, S())));