diff --git a/src/dmd/id.d b/src/dmd/id.d index 8c66c4c15dfb..889aa48fd9c3 100644 --- a/src/dmd/id.d +++ b/src/dmd/id.d @@ -431,6 +431,8 @@ immutable Msgtable[] msgtable = { "isZeroInit" }, { "getTargetInfo" }, { "getLocation" }, + { "hasPostblit" }, + { "hasCopyConstructor" }, // For C++ mangling { "allocator" }, diff --git a/src/dmd/traits.d b/src/dmd/traits.d index b033abd19aa6..8c20dedb362b 100644 --- a/src/dmd/traits.d +++ b/src/dmd/traits.d @@ -144,6 +144,8 @@ shared static this() "isZeroInit", "getTargetInfo", "getLocation", + "hasPostblit", + "hasCopyConstructor", ]; StringTable* stringTable = cast(StringTable*) &traitsStringTable; @@ -627,6 +629,29 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } return True(); } + if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit) + { + 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 (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False()) + : (sd.hasCopyCtor ? 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 27c9595ccd17..2f5258064c5f 100644 --- a/test/compilable/traits.d +++ b/test/compilable/traits.d @@ -86,3 +86,69 @@ 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 +// but done as two independent traits per conversation +// in https://github.com/dlang/dmd/pull/10265 + +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(hasCopyConstructor, S!int)); +} + +struct U(T) +{ + this (ref U rhs) {} +} + +struct SPostblit +{ + this(this) {} +} + +struct NoCpCtor { } +class C19902 { } + +static assert(__traits(hasCopyConstructor, S)); +static assert(__traits(hasCopyConstructor, OuterS.S)); +static assert(__traits(hasCopyConstructor, OuterS)); +static assert(__traits(compiles, foo!int)); +static assert(__traits(compiles, foo!S)); +static assert(__traits(hasCopyConstructor, U!int)); +static assert(__traits(hasCopyConstructor, U!S)); +static assert(!__traits(hasPostblit, U!S)); +static assert(__traits(hasPostblit, SPostblit)); +static assert(!__traits(hasCopyConstructor, SPostblit)); + +static assert(!__traits(hasCopyConstructor, NoCpCtor)); +static assert(!__traits(hasCopyConstructor, C19902)); +static assert(!__traits(hasCopyConstructor, int)); +static assert(!__traits(hasPostblit, NoCpCtor)); +static assert(!__traits(hasPostblit, C19902)); +static assert(!__traits(hasPostblit, int)); + +// Check that invalid use cases don't compile +static assert(!__traits(compiles, __traits(hasCopyConstructor))); +static assert(!__traits(compiles, __traits(hasCopyConstructor, S()))); +static assert(!__traits(compiles, __traits(hasPostblit))); +static assert(!__traits(compiles, __traits(hasPostblit, S())));