diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs index 1abab2f6..8490afb8 100644 --- a/src/Generator/AST/Utils.cs +++ b/src/Generator/AST/Utils.cs @@ -25,7 +25,7 @@ namespace CppSharp.AST if (@class != null && @class.IsValueType && isEmptyCtor) return true; - if (method.IsCopyConstructor || method.IsMoveConstructor) + if (method.IsMoveConstructor) return true; if (method.IsDestructor) diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index c9c3e2e6..b6a50ba2 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -374,6 +374,10 @@ namespace CppSharp.Generators.CLI if (ASTUtils.CheckIgnoreMethod(ctor)) continue; + // C++/CLI does not allow special member funtions for value types. + if (@class.IsValueType && ctor.IsCopyConstructor) + continue; + GenerateMethod(ctor); } diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index 978fc56e..122fdd80 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -142,6 +142,10 @@ namespace CppSharp.Generators.CLI if (ASTUtils.CheckIgnoreMethod(method)) continue; + // C++/CLI does not allow special member funtions for value types. + if (@class.IsValueType && method.IsCopyConstructor) + continue; + GenerateMethod(method, @class); } diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 0f6e2fd8..0008a0d8 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -2159,8 +2159,19 @@ namespace CppSharp.Generators.CSharp WriteLine("{0} = Marshal.AllocHGlobal({1});", Helpers.InstanceIdentifier, @class.Layout.Size); - if (!method.IsDefaultConstructor || @class.HasNonTrivialDefaultConstructor) - GenerateInternalFunctionCall(method); + if (method.IsCopyConstructor) + { + if (@class.HasNonTrivialCopyConstructor) + GenerateInternalFunctionCall(method); + else + WriteLine("*(({0}.Internal*) __Instance) = *(({0}.Internal*) {1}.__Instance);", + @class.Name, method.Parameters[0].Name); + } + else + { + if (!method.IsDefaultConstructor || @class.HasNonTrivialDefaultConstructor) + GenerateInternalFunctionCall(method); + } GenerateVTableClassSetupCall(@class); } diff --git a/src/Generator/Passes/CheckStaticClass.cs b/src/Generator/Passes/CheckStaticClass.cs index 762950fc..92485a08 100644 --- a/src/Generator/Passes/CheckStaticClass.cs +++ b/src/Generator/Passes/CheckStaticClass.cs @@ -59,6 +59,14 @@ namespace CppSharp.Passes // If all the above constraints hold, then we assume the class can be // static. @class.IsStatic = true; + + // Ignore the special methods for static classes. + foreach (var ctor in @class.Constructors) + ctor.IsGenerated = false; + + foreach (var dtor in @class.Destructors) + dtor.IsGenerated = false; + return true; } } diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 983cac43..f55d0d90 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -193,5 +193,19 @@ public class BasicTests : GeneratorTestFixture public void TestChar16() { } + + [Test] + public void TestCopyConstructor() + { + Foo foo = new Foo { A = 5, B = 5.5f }; + var copyFoo = new Foo(foo); + Assert.That(foo.A, Is.EqualTo(copyFoo.A)); + Assert.That(foo.B, Is.EqualTo(copyFoo.B)); + + var testCopyConstructorRef = new TestCopyConstructorRef { A = 10, B = 5 }; + var copyBar = new TestCopyConstructorRef(testCopyConstructorRef); + Assert.That(testCopyConstructorRef.A, Is.EqualTo(copyBar.A)); + Assert.That(testCopyConstructorRef.B, Is.EqualTo(copyBar.B)); + } } \ No newline at end of file diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index 17f6850a..2e266f8f 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -217,3 +217,13 @@ Bar::Item operator |(Bar::Item left, Bar::Item right) { return left | right; } + +TestCopyConstructorRef::TestCopyConstructorRef() +{ +} + +TestCopyConstructorRef::TestCopyConstructorRef(const TestCopyConstructorRef& other) +{ + A = other.A; + B = other.B; +} diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 3dcddc76..cdcad981 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -278,3 +278,12 @@ class DependentTypeWithNestedIndependent long l; }; }; + +class DLL_API TestCopyConstructorRef +{ +public: + TestCopyConstructorRef(); + TestCopyConstructorRef(const TestCopyConstructorRef& other); + int A; + float B; +}; diff --git a/tests/CSharpTemp/CSharpTemp.Tests.cs b/tests/CSharpTemp/CSharpTemp.Tests.cs index b342413a..5d30205f 100644 --- a/tests/CSharpTemp/CSharpTemp.Tests.cs +++ b/tests/CSharpTemp/CSharpTemp.Tests.cs @@ -34,7 +34,7 @@ public class CSharpTempTests : GeneratorTestFixture [Test] public void TestFixedArrays() { - Qux qux = new Qux(null); + Qux qux = new Qux((Foo) null); var array = new[] { 1, 2, 3 }; qux.Array = array; for (int i = 0; i < qux.Array.Length; i++) @@ -64,7 +64,7 @@ public class CSharpTempTests : GeneratorTestFixture Assert.That(proprietor.Value, Is.EqualTo(20)); proprietor.Prop = 50; Assert.That(proprietor.Prop, Is.EqualTo(50)); - var p = new P(null); + var p = new P((IQux) null); p.Value = 20; Assert.That(p.Value, Is.EqualTo(30)); p.Prop = 50; @@ -107,4 +107,13 @@ public class CSharpTempTests : GeneratorTestFixture bar.ArrayOfPrimitivePointers = array; Assert.That(i, Is.EqualTo(*(int*) bar.ArrayOfPrimitivePointers[0])); } + + [Test] + public void TestCopyConstructorValue() + { + var testCopyConstructorVal = new TestCopyConstructorVal { A = 10, B = 5 }; + var copyBar = new TestCopyConstructorVal(testCopyConstructorVal); + Assert.That(testCopyConstructorVal.A, Is.EqualTo(copyBar.A)); + Assert.That(testCopyConstructorVal.B, Is.EqualTo(copyBar.B)); + } } \ No newline at end of file diff --git a/tests/CSharpTemp/CSharpTemp.cpp b/tests/CSharpTemp/CSharpTemp.cpp index b1f0cf4c..acad1852 100644 --- a/tests/CSharpTemp/CSharpTemp.cpp +++ b/tests/CSharpTemp/CSharpTemp.cpp @@ -190,4 +190,14 @@ void P::setIsBool(bool value) } -int TestDestructors::Marker = 0; \ No newline at end of file +int TestDestructors::Marker = 0; + +TestCopyConstructorVal::TestCopyConstructorVal() +{ +} + +TestCopyConstructorVal::TestCopyConstructorVal(const TestCopyConstructorVal& other) +{ + A = other.A; + B = other.B; +} diff --git a/tests/CSharpTemp/CSharpTemp.cs b/tests/CSharpTemp/CSharpTemp.cs index ea18a316..b4a662a0 100644 --- a/tests/CSharpTemp/CSharpTemp.cs +++ b/tests/CSharpTemp/CSharpTemp.cs @@ -64,6 +64,11 @@ namespace CppSharp.Tests driver.TranslationUnitPasses.AddPass(new TestAttributesPass()); } + public override void Preprocess(Driver driver, ASTContext ctx) + { + ctx.SetClassAsValueType("TestCopyConstructorVal"); + } + public override void Postprocess(Driver driver, ASTContext lib) { new CaseRenamePass( diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index 60b6b484..1f967826 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -138,3 +138,12 @@ struct DLL_API TestDestructors TestDestructors() { Marker = 0xf00d; } ~TestDestructors() { Marker = 0xcafe; } }; + +class DLL_API TestCopyConstructorVal +{ +public: + TestCopyConstructorVal(); + TestCopyConstructorVal(const TestCopyConstructorVal& other); + int A; + float B; +};