From 45106531e1c6152289eedf52b76f0e98f14865b3 Mon Sep 17 00:00:00 2001 From: Eduard Staniloiu Date: Fri, 2 Aug 2019 14:48:52 +0300 Subject: [PATCH 1/4] Add hasElaborateCopyConstructor trait --- src/dmd/id.d | 1 + src/dmd/traits.d | 13 +++++++++++-- test/compilable/traits.d | 42 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/dmd/id.d b/src/dmd/id.d index 8c66c4c15dfb..16395937d90b 100644 --- a/src/dmd/id.d +++ b/src/dmd/id.d @@ -431,6 +431,7 @@ immutable Msgtable[] msgtable = { "isZeroInit" }, { "getTargetInfo" }, { "getLocation" }, + { "hasElaborateCopyConstructor" }, // For C++ mangling { "allocator" }, diff --git a/src/dmd/traits.d b/src/dmd/traits.d index 1890422f4ba2..7005878463a7 100644 --- a/src/dmd/traits.d +++ b/src/dmd/traits.d @@ -144,6 +144,7 @@ shared static this() "isZeroInit", "getTargetInfo", "getLocation", + "hasElaborateCopyConstructor" ]; traitsStringTable._init(names.length); @@ -596,7 +597,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc) sm => sm.isTemplateDeclaration() !is null) != 0; }); } - if (e.ident == Id.isPOD) + if (e.ident == Id.isPOD || + e.ident == Id.hasElaborateCopyConstructor) { if (dim != 1) return dimError(1); @@ -613,7 +615,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc) Type tb = t.baseElemOf(); if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) { - return sd.isPOD() ? True() : False(); + if (e.ident == Id.isPOD) + { + return sd.isPOD() ? True() : False(); + } + else if (e.ident == Id.hasElaborateCopyConstructor) + { + return sd.hasCopyCtor ? True() : False(); + } } return True(); } diff --git a/test/compilable/traits.d b/test/compilable/traits.d index 27c9595ccd17..d02ef75dd21e 100644 --- a/test/compilable/traits.d +++ b/test/compilable/traits.d @@ -86,3 +86,45 @@ 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) {} + } +} + +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) {} +} + +static assert(__traits(hasElaborateCopyConstructor, S)); +static assert(__traits(hasElaborateCopyConstructor, OuterS.S)); +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)); From f5228664669b25c6648ae9684bf102a804cfc566 Mon Sep 17 00:00:00 2001 From: Eduard Staniloiu Date: Fri, 2 Aug 2019 15:00:57 +0300 Subject: [PATCH 2/4] Postblit is still a form of copy constructor --- src/dmd/traits.d | 33 +++++++++++++++++++++++---------- test/compilable/traits.d | 17 ++++++++++++++--- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/dmd/traits.d b/src/dmd/traits.d index 7005878463a7..142655ae7128 100644 --- a/src/dmd/traits.d +++ b/src/dmd/traits.d @@ -597,8 +597,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) sm => sm.isTemplateDeclaration() !is null) != 0; }); } - if (e.ident == Id.isPOD || - e.ident == Id.hasElaborateCopyConstructor) + if (e.ident == Id.isPOD) { if (dim != 1) return dimError(1); @@ -615,17 +614,31 @@ Expression semanticTraits(TraitsExp e, Scope* sc) Type tb = t.baseElemOf(); if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) { - if (e.ident == Id.isPOD) - { - return sd.isPOD() ? True() : False(); - } - else if (e.ident == Id.hasElaborateCopyConstructor) - { - return sd.hasCopyCtor ? True() : False(); - } + return sd.isPOD() ? True() : False(); } 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.hasCopyCtor || sd.postblit ? True() : False(); + } + return False(); + } if (e.ident == Id.isNested) { if (dim != 1) diff --git a/test/compilable/traits.d b/test/compilable/traits.d index d02ef75dd21e..36dacf4fa2b4 100644 --- a/test/compilable/traits.d +++ b/test/compilable/traits.d @@ -101,6 +101,8 @@ struct OuterS { this (ref S rhs) {} } + + S s; } void foo(T)() @@ -112,19 +114,28 @@ void foo(T)() static assert (__traits(hasElaborateCopyConstructor, S!int)); } -struct U(T) { +struct U(T) +{ this (ref U rhs) {} } -struct SPostblit { +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, SPostblit)); +static assert(!__traits(hasElaborateCopyConstructor, NoCpCtor)); +static assert(!__traits(hasElaborateCopyConstructor, C19902)); +static assert(!__traits(hasElaborateCopyConstructor, int)); From 556ed8a641b5cb5d75309f1eff071d773f4e3f6a Mon Sep 17 00:00:00 2001 From: Eduard Staniloiu Date: Mon, 5 Aug 2019 15:37:26 +0300 Subject: [PATCH 3/4] Increase codecov --- test/compilable/traits.d | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/compilable/traits.d b/test/compilable/traits.d index 36dacf4fa2b4..0240cf44a0df 100644 --- a/test/compilable/traits.d +++ b/test/compilable/traits.d @@ -139,3 +139,7 @@ static assert(__traits(hasElaborateCopyConstructor, SPostblit)); static assert(!__traits(hasElaborateCopyConstructor, NoCpCtor)); 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()))); From b851f363e9b0da8299f8bb119ce2d8444c2cbab8 Mon Sep 17 00:00:00 2001 From: Eduard Staniloiu Date: Mon, 2 Sep 2019 16:22:10 +0300 Subject: [PATCH 4/4] Refactor postblit or hasCopyCtor into a function --- src/dmd/dstruct.d | 17 +++++++++++++++++ src/dmd/expression.d | 2 +- src/dmd/expressionsem.d | 2 +- src/dmd/traits.d | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/dmd/dstruct.d b/src/dmd/dstruct.d index 688e1486244f..0be791207b8d 100644 --- a/src/dmd/dstruct.d +++ b/src/dmd/dstruct.d @@ -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; diff --git a/src/dmd/expression.d b/src/dmd/expression.d index edd428b7590c..f25a29ac4bb2 100644 --- a/src/dmd/expression.d +++ b/src/dmd/expression.d @@ -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 diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index 682856e05903..064fa25d0b94 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -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 */ diff --git a/src/dmd/traits.d b/src/dmd/traits.d index 142655ae7128..aa145a33dbd0 100644 --- a/src/dmd/traits.d +++ b/src/dmd/traits.d @@ -635,7 +635,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) Type tb = t.baseElemOf(); if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) { - return sd.hasCopyCtor || sd.postblit ? True() : False(); + return sd.hasElaborateCopyCtor() ? True() : False(); } return False(); }