Skip to content

Commit 54a6fb0

Browse files
author
Fabio Anderegg
committed
generate calls to cctor when passing paramters by value
1 parent a237171 commit 54a6fb0

File tree

5 files changed

+92
-7
lines changed

5 files changed

+92
-7
lines changed

src/Generator/Generators/CSharp/CSharpMarshal.cs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -767,11 +767,35 @@ private void MarshalRefClass(Class @class)
767767
{
768768
if (Context.Parameter.IsIndirect)
769769
{
770-
Context.Before.WriteLine($"if (ReferenceEquals({Context.Parameter.Name}, null))");
771-
Context.Before.WriteLineIndent(
772-
$@"throw new global::System.ArgumentNullException(""{
773-
Context.Parameter.Name}"", ""Cannot be null because it is passed by value."");");
774-
Context.Return.Write(paramInstance);
770+
Method cctor = @class.HasNonTrivialCopyConstructor ? @class.Methods.First(c => c.IsCopyConstructor) : null;
771+
if (cctor != null && cctor.IsGenerated)
772+
{
773+
Context.Before.WriteLine($"if (ReferenceEquals({Context.Parameter.Name}, null))");
774+
Context.Before.WriteLineIndent(
775+
$@"throw new global::System.ArgumentNullException(""{
776+
Context.Parameter.Name}"", ""Cannot be null because it is passed by value."");");
777+
778+
var nativeClass = typePrinter.PrintNative(@class);
779+
var cctorName = CSharpSources.GetFunctionNativeIdentifier(Context.Context, cctor);
780+
Context.Before.WriteLine($"byte* __{Context.Parameter.Name}Memory = stackalloc byte[sizeof({nativeClass})];");
781+
Context.Before.WriteLine($"__IntPtr __{Context.Parameter.Name}Ptr = (__IntPtr)__{Context.Parameter.Name}Memory;");
782+
Context.Before.WriteLine($"{nativeClass}.{cctorName}(__{Context.Parameter.Name}Ptr, {Context.Parameter.Name}.__Instance);");
783+
Context.Return.Write($"__{Context.Parameter.Name}Ptr");
784+
785+
if (Context.Context.ParserOptions.IsItaniumLikeAbi && @class.HasNonTrivialDestructor)
786+
{
787+
Method dtor = @class.Destructors.FirstOrDefault();
788+
if (dtor != null)
789+
{
790+
// todo: virtual destructors?
791+
Context.Cleanup.WriteLine($"{nativeClass}.dtor(__{Context.Parameter.Name}Ptr);");
792+
}
793+
}
794+
}
795+
else
796+
{
797+
Context.Return.Write(paramInstance);
798+
}
775799
}
776800
else
777801
{

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3436,6 +3436,12 @@ public static string GetFunctionIdentifier(Function function)
34363436

34373437
public string GetFunctionNativeIdentifier(Function function,
34383438
bool isForDelegate = false)
3439+
{
3440+
return GetFunctionNativeIdentifier(Context, function, isForDelegate);
3441+
}
3442+
3443+
public static string GetFunctionNativeIdentifier(BindingContext context, Function function,
3444+
bool isForDelegate = false)
34393445
{
34403446
var identifier = new StringBuilder();
34413447

@@ -3466,12 +3472,12 @@ public string GetFunctionNativeIdentifier(Function function,
34663472
identifier.Append(Helpers.GetSuffixFor(specialization));
34673473

34683474
var internalParams = function.GatherInternalParams(
3469-
Context.ParserOptions.IsItaniumLikeAbi);
3475+
context.ParserOptions.IsItaniumLikeAbi);
34703476
var overloads = function.Namespace.GetOverloads(function)
34713477
.Where(f => (!f.Ignore ||
34723478
(f.OriginalFunction != null && !f.OriginalFunction.Ignore)) &&
34733479
(isForDelegate || internalParams.SequenceEqual(
3474-
f.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi),
3480+
f.GatherInternalParams(context.ParserOptions.IsItaniumLikeAbi),
34753481
new MarshallingParamComparer()))).ToList();
34763482
var index = -1;
34773483
if (overloads.Count > 1)

tests/CSharp/CSharp.Tests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,4 +1984,19 @@ public void TestCallByValueCppToCSharpPointer()
19841984
Assert.That(RuleOfThreeTester.CopyConstructorCalls, Is.EqualTo(0));
19851985
Assert.That(RuleOfThreeTester.CopyAssignmentCalls, Is.EqualTo(0));
19861986
}
1987+
1988+
[Test]
1989+
public void TestObjectPassByValue1451()
1990+
{
1991+
using (var s = new Issue1451())
1992+
{
1993+
s.A = 500;
1994+
Assert.IsTrue(CSharp.CSharp.TestObjectPassByValue(s));
1995+
Assert.That(s.A, Is.EqualTo(500));
1996+
}
1997+
1998+
Assert.That(Issue1451.ConstructorCalls, Is.EqualTo(1));
1999+
Assert.That(Issue1451.CopyConstructorCalls, Is.EqualTo(1));
2000+
Assert.That(Issue1451.DestructorCalls, Is.EqualTo(2));
2001+
}
19872002
}

tests/CSharp/CSharp.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,3 +1750,30 @@ void CallCallByValueInterfacePointer(CallByValueInterface* interface)
17501750
RuleOfThreeTester value;
17511751
interface->CallByPointer(&value);
17521752
}
1753+
1754+
int Issue1451::constructorCalls = 0;
1755+
int Issue1451::destructorCalls = 0;
1756+
int Issue1451::copyConstructorCalls = 0;
1757+
1758+
Issue1451::Issue1451()
1759+
{
1760+
a = 0;
1761+
constructorCalls++;
1762+
}
1763+
1764+
Issue1451::Issue1451(const Issue1451& other)
1765+
{
1766+
a = other.a;
1767+
copyConstructorCalls++;
1768+
}
1769+
1770+
Issue1451::~Issue1451()
1771+
{
1772+
destructorCalls++;
1773+
}
1774+
1775+
bool TestObjectPassByValue(Issue1451 s)
1776+
{
1777+
s.a = 99999;
1778+
return true;
1779+
}

tests/CSharp/CSharp.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,3 +1582,16 @@ struct DLL_API CallByValueInterface {
15821582
void DLL_API CallCallByValueInterfaceValue(CallByValueInterface*);
15831583
void DLL_API CallCallByValueInterfaceReference(CallByValueInterface*);
15841584
void DLL_API CallCallByValueInterfacePointer(CallByValueInterface*);
1585+
1586+
struct DLL_API Issue1451 {
1587+
int a;
1588+
static int constructorCalls;
1589+
static int destructorCalls;
1590+
static int copyConstructorCalls;
1591+
1592+
Issue1451();
1593+
~Issue1451();
1594+
Issue1451(const Issue1451& other);
1595+
};
1596+
1597+
bool DLL_API TestObjectPassByValue(Issue1451 s);

0 commit comments

Comments
 (0)