diff --git a/compiler/src/dmd/target.d b/compiler/src/dmd/target.d index 104cf580ea..fc9c98ea4a 100644 --- a/compiler/src/dmd/target.d +++ b/compiler/src/dmd/target.d @@ -1009,6 +1009,8 @@ extern (C++) struct Target auto sd = ts.sym; if (tf.linkage == LINK.cpp && needsThis) return true; + if (tf.linkage == LINK.cpp && sd.ctor) + return true; if (!sd.isPOD() || sz > 8) return true; if (sd.fields.length == 0) diff --git a/compiler/test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp b/compiler/test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp new file mode 100644 index 0000000000..c320ec5582 --- /dev/null +++ b/compiler/test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp @@ -0,0 +1,74 @@ +extern "C" int printf(const char *, ...); + +#define Foo(T) \ + T fooD(T param); \ + T fooCpp(T param) \ + { \ + printf("fooCpp %d [%p]\n", param.a, ¶m); \ + return fooD(T{2 * param.a}); \ + } + +struct POD +{ + int a; +}; +Foo(POD); + +struct CtorOnly +{ + int a; + CtorOnly() : a(0) {} + CtorOnly(int a) : a(a) {} +}; +Foo(CtorOnly); + +struct DtorOnly +{ + int a; + ~DtorOnly(); // implemented in D +}; +Foo(DtorOnly); + +struct CtorDtor +{ + int a; + CtorDtor(int a) : a(a) {} + ~CtorDtor(); // implemented in D +}; +Foo(CtorDtor); + +struct Copy +{ + int a; + Copy(int a) : a(a) {} + ~Copy(); // implemented in D + Copy(const Copy &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); } +}; +Foo(Copy); + +struct CopyAndMove +{ + int a; + CopyAndMove(int a) : a(a) {} + ~CopyAndMove(); // implemented in D + CopyAndMove(const CopyAndMove &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); } + CopyAndMove(CopyAndMove &&) = default; +}; +Foo(CopyAndMove); + +struct MoveOnly +{ + int a; + MoveOnly(int a) : a(a) {} + ~MoveOnly(); // implemented in D + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) = default; +}; +Foo(MoveOnly); + +struct MemberWithCtor +{ + int a; + CtorOnly m; +}; +Foo(MemberWithCtor); diff --git a/compiler/test/runnable_cxx/nonpod_byval.d b/compiler/test/runnable_cxx/nonpod_byval.d new file mode 100644 index 0000000000..c7fac46a04 --- /dev/null +++ b/compiler/test/runnable_cxx/nonpod_byval.d @@ -0,0 +1,118 @@ +// EXTRA_CPP_SOURCES: cpp_nonpod_byval.cpp +// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11 + +extern (C) int printf(const(char)*, ...); + +extern (C++): + +template Foo(T) +{ + T fooCpp(T param); // calls fooD() with a new, doubled literal + + T fooD(T param) + { + printf("fooD %d [%p]\n", param.a, ¶m); + assert(param.a == 2 * 123); + static if (__traits(compiles, { T copy = param; })) + return param; // invokes postblit + else + return T(param.a); + } +} + +void test(T)() +{ + printf(".: %.*s\n", cast(int) T.stringof.length, T.stringof.ptr); + + { + auto result = fooCpp(T(123)); + assert(result.a == 246); + } + + static if (__traits(hasMember, T, "numDtor")) + { + // fooCpp param + fooD param + result => 3 T instances. + // There may be an additional destruction of the moved-from T literal + // in fooCpp, depending on in-place construction vs. move. + assert(T.numDtor == 3 || T.numDtor == 4); + } +} + +struct POD +{ + int a; +} +mixin Foo!POD; + +struct CtorOnly +{ + int a; + this(int a) { this.a = a; } +} +mixin Foo!CtorOnly; + +struct DtorOnly +{ + static __gshared int numDtor = 0; + int a; + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } +} +mixin Foo!DtorOnly; + +struct CtorDtor +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } +} +mixin Foo!CtorDtor; + +struct Copy +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } + this(this) { printf("post %d [%p]\n", a, &this); } +} +mixin Foo!Copy; + +struct CopyAndMove +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } + this(this) { printf("post %d [%p]\n", a, &this); } +} +mixin Foo!CopyAndMove; + +struct MoveOnly +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } + this(this) @disable; +} +mixin Foo!MoveOnly; + +struct MemberWithCtor +{ + int a; + CtorOnly m; +} +mixin Foo!MemberWithCtor; + +void main() +{ + test!POD(); + test!CtorOnly(); + test!DtorOnly(); + test!CtorDtor(); + test!Copy(); + test!CopyAndMove(); + test!MoveOnly(); + test!MemberWithCtor(); +}