Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for varargs. #344

Merged
merged 2 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,9 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)

_outputBuilder.BeginFunctionInnerPrototype(in desc);

if (isVirtual || (isCxxMethodDecl && !hasBody && cxxMethodDecl.IsInstance))
bool needsThis = isVirtual || (isCxxMethodDecl && !hasBody && cxxMethodDecl.IsInstance);

if (needsThis)
{
Debug.Assert(cxxRecordDecl != null);

Expand Down Expand Up @@ -612,6 +614,21 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)

Visit(functionDecl.Parameters);

if (functionDecl.IsVariadic)
{
if (needsThis || functionDecl.Parameters.Any())
{
_outputBuilder.WriteParameterSeparator();
}
var parameterDesc = new ParameterDesc
{
Name = "",
Type = "__arglist"
};
_outputBuilder.BeginParameter(in parameterDesc);
_outputBuilder.EndParameter(in parameterDesc);
}

_outputBuilder.EndFunctionInnerPrototype(in desc);

if (hasBody && !isVirtual)
Expand Down Expand Up @@ -650,6 +667,15 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
}
}

if (functionDecl.IsVariadic)
{
if (parameters.Count != 0)
{
outputBuilder.Write(", ");
}
outputBuilder.Write("__arglist");
}

outputBuilder.Write(')');

outputBuilder.NeedsSemicolon = true;
Expand Down
8 changes: 8 additions & 0 deletions sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1922,6 +1922,14 @@ private Type[] GetBitfieldCount(RecordDecl recordDecl)

private CallingConvention GetCallingConvention(Cursor cursor, Cursor context, Type type)
{
if (cursor is FunctionDecl functionDecl)
{
if (functionDecl.IsVariadic)
{
return CallingConvention.Cdecl;
}
}
Comment on lines +1925 to +1931
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to support remapping still. The default should definitely be Cdecl, but ClangSharp supports users doing any kind of remapping, even ones that technically may not make sense.

Copy link
Contributor Author

@Berrysoft Berrysoft Jun 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The document of __stdcall indicates that even the vararg function is marked as __stdcall, the compiler makes it a __cdecl. Therefore I force Cdecl here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but that's not necessarily true for any and all potential platforms. ClangSharp has reasonable defaults and allows devs to override the default to fit their own needs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are generating proper dll imports. If a programmer writes a method like

extern "C" int __stdcall foo(...);

The compiler won't raise errors. However, if we generate bindings like

[DllImport("foo.dll", CallingConvention = CallingConvention.StdCall)]
static extern int foo(__arglist);

The program will raise runtime System.TypeLoadException says that varargs function should use cdecl.


if (cursor is NamedDecl namedDecl)
{
if (TryGetRemappedValue(namedDecl, _config.WithCallConvs, out var callConv, matchStar: true))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ public abstract class FunctionDeclarationDllImportTest : PInvokeGeneratorTest
[Test]
public Task SourceLocationTest() => SourceLocationTestImpl();

[Test]
public Task VarargsTest() => VarargsTestImpl();

protected abstract Task BasicTestImpl();

protected abstract Task ArrayParameterTestImpl();
Expand Down Expand Up @@ -106,5 +109,7 @@ public abstract class FunctionDeclarationDllImportTest : PInvokeGeneratorTest
protected abstract Task WithSetLastErrorStarTestImpl();

protected abstract Task SourceLocationTestImpl();

protected abstract Task VarargsTestImpl();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -396,5 +396,7 @@ public static partial class Methods

return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl() => Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -395,5 +395,24 @@ public static partial class Methods

return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl()
{
const string InputContents = @"extern ""C"" void MyFunction(int value, ...);";

const string ExpectedOutputContents = @"using System.Runtime.InteropServices;

namespace ClangSharp.Test
{
public static partial class Methods
{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void MyFunction(int value, __arglist );
Berrysoft marked this conversation as resolved.
Show resolved Hide resolved
}
}
";

return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(InputContents, ExpectedOutputContents);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,5 +394,7 @@ public static partial class Methods

return ValidateGeneratedCSharpLatestUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl() => Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,5 +394,24 @@ public static partial class Methods

return ValidateGeneratedCSharpLatestWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl()
{
const string InputContents = @"extern ""C"" void MyFunction(int value, ...);";

const string ExpectedOutputContents = @"using System.Runtime.InteropServices;

namespace ClangSharp.Test
{
public static partial class Methods
{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void MyFunction(int value, __arglist );
}
}
";

return ValidateGeneratedCSharpLatestWindowsBindingsAsync(InputContents, ExpectedOutputContents);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl()

return ValidateGeneratedXmlCompatibleUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl() => Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl()

return ValidateGeneratedXmlCompatibleWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl() => Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl()

return ValidateGeneratedXmlLatestUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl() => Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl()

return ValidateGeneratedXmlLatestWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute);
}

protected override Task VarargsTestImpl() => Task.CompletedTask;
}
}