Skip to content

Commit

Permalink
Merge pull request #547 from dpaoliello/uninsttest
Browse files Browse the repository at this point in the history
Fix crash when using a default argument from a base template
  • Loading branch information
tannergooding authored May 12, 2024
2 parents e1a4e13 + a7b4666 commit ce3e5c3
Show file tree
Hide file tree
Showing 20 changed files with 623 additions and 11 deletions.
19 changes: 10 additions & 9 deletions sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1253,30 +1253,31 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl)

var handledDefaultArg = false;
var isExprDefaultValue = false;
var defaultArg = (parmVarDecl.HasDefaultArg && !parmVarDecl.HasUnparsedDefaultArg) ?
(parmVarDecl.HasUninstantiatedDefaultArg ? parmVarDecl.UninstantiatedDefaultArg : parmVarDecl.DefaultArg) :
null;

if (parmVarDecl.HasDefaultArg)
if (defaultArg != null)
{
isExprDefaultValue = IsDefaultValue(parmVarDecl.DefaultArg);
isExprDefaultValue = IsDefaultValue(defaultArg);

if ((_outputBuilder is CSharpOutputBuilder csharpOutputBuilder) && (_config.WithTransparentStructs.ContainsKey(typeName) || parameters.Skip(index).Any((parmVarDecl) => {
var type = parmVarDecl.Type;
var typeName = GetTargetTypeName(parmVarDecl, out var nativeTypeName);
return _config.WithTransparentStructs.ContainsKey(typeName);
})))
{
desc.CustomAttrGeneratorData = (parmVarDecl, this, csharpOutputBuilder, isExprDefaultValue ? null : parmVarDecl.DefaultArg);
desc.CustomAttrGeneratorData = (parmVarDecl, this, csharpOutputBuilder, isExprDefaultValue ? null : defaultArg);
handledDefaultArg = true;
}
}

_outputBuilder.BeginParameter(in desc);

if (parmVarDecl.HasDefaultArg && !handledDefaultArg)
if (defaultArg != null && !handledDefaultArg)
{
_outputBuilder.BeginParameterDefault();

var defaultArg = parmVarDecl.DefaultArg;

if (IsTypePointerOrReference(parmVarDecl) && (defaultArg.Handle.Evaluate.Kind == CXEval_UnExposed))
{
if (!isExprDefaultValue)
Expand All @@ -1290,7 +1291,7 @@ void ForFunctionDecl(ParmVarDecl parmVarDecl, FunctionDecl functionDecl)
}
else
{
Visit(parmVarDecl.DefaultArg);
Visit(defaultArg);
}

_outputBuilder.EndParameterDefault();
Expand Down Expand Up @@ -1341,10 +1342,10 @@ void ForTypedefDecl(ParmVarDecl parmVarDecl, TypedefDecl typedefDecl)

_outputBuilder.BeginParameter(in desc);

if (parmVarDecl.HasDefaultArg)
if (parmVarDecl.HasDefaultArg && !parmVarDecl.HasUnparsedDefaultArg)
{
_outputBuilder.BeginParameterDefault();
Visit(parmVarDecl.DefaultArg);
Visit(parmVarDecl.HasUninstantiatedDefaultArg ? parmVarDecl.UninstantiatedDefaultArg : parmVarDecl.DefaultArg);
_outputBuilder.EndParameterDefault();
}

Expand Down
4 changes: 4 additions & 0 deletions sources/ClangSharp/Cursors/Decls/ParmVarDecl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ internal ParmVarDecl(CXCursor handle) : base(handle, CXCursor_ParmDecl, CX_DeclK

public bool HasDefaultArg => Handle.HasDefaultArg;

public bool HasUnparsedDefaultArg => Handle.HasUnparsedDefaultArg;

public bool HasUninstantiatedDefaultArg => Handle.HasUninstantiatedDefaultArg;

public bool HasInheritedDefaultArg => Handle.HasInheritedDefaultArg;

public Type OriginalType => _originalType.Value;
Expand Down
2 changes: 0 additions & 2 deletions sources/ClangSharp/Cursors/Exprs/CXXDefaultArgExpr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ internal CXXDefaultArgExpr(CXCursor handle) : base(handle, CXCursor_UnexposedExp
_usedContext = new Lazy<IDeclContext?>(() => TranslationUnit.GetOrCreate<Decl>(Handle.UsedContext) as IDeclContext);
}

public Expr Expr => Param.DefaultArg;

public ParmVarDecl Param => _param.Value;

public IDeclContext? UsedContext => _usedContext.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public abstract class CXXMethodDeclarationTest : PInvokeGeneratorTest
[Test]
public Task ConversionTest() => ConversionTestImpl();

[Test]
public Task DefaultParameterInheritedFromTemplateTest() => DefaultParameterInheritedFromTemplateTestImpl();

[Test]
public Task DestructorTest() => DestructorTestImpl();

Expand Down Expand Up @@ -107,6 +110,8 @@ public static int buf_close(void* pContext)

protected abstract Task ConversionTestImpl();

protected abstract Task DefaultParameterInheritedFromTemplateTestImpl();

protected abstract Task DestructorTestImpl();

protected abstract Task InstanceTestImpl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "__ZN8$MyTemplateDoWorkEv" : "_ZN10MyTemplateIiE6DoWorkEPi";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = Environment.Is64BitProcess ? "?DoWork@?$MyTemplate@H@@QEAAPEAHPEAH@Z" : "?DoWork@?$MyTemplate@H@@QEAPEHPEH@Z";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpDefaultUnixBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "__ZN8$MyTemplateDoWorkEv" : "_ZN10MyTemplateIiE6DoWorkEPi";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpDefaultUnixBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpDefaultWindowsBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = Environment.Is64BitProcess ? "?DoWork@?$MyTemplate@H@@QEAAPEAHPEAH@Z" : "?DoWork@?$MyTemplate@H@@QEAPEHPEH@Z";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpDefaultWindowsBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "__ZN8$MyTemplateDoWorkEv" : "_ZN10MyTemplateIiE6DoWorkEPi";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpLatestUnixBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = Environment.Is64BitProcess ? "?DoWork@?$MyTemplate@H@@QEAAPEAHPEAH@Z" : "?DoWork@?$MyTemplate@H@@QEAPEHPEH@Z";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpLatestWindowsBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,40 @@ public int ToInt32()
return ValidateGeneratedCSharpPreviewUnixBindingsAsync(inputContents, expectedOutputContents);
}

protected override Task DefaultParameterInheritedFromTemplateTestImpl()
{
// NOTE: This is a regression test where a struct inherits a function from a template with a default parameter.
const string InputContents = @"template <typename T>
struct MyTemplate
{
int* DoWork(int* value = nullptr)
{
return value;
}
};
struct MyStruct : public MyTemplate<int>
{};
";

var entryPoint = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "__ZN8$MyTemplateDoWorkEv" : "_ZN10MyTemplateIiE6DoWorkEPi";

var expectedOutputContents = $@"using System.Runtime.InteropServices;
namespace ClangSharp.Test
{{
[NativeTypeName(""struct MyStruct : MyTemplate<int>"")]
public unsafe partial struct MyStruct
{{
[DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.ThisCall, EntryPoint = ""{entryPoint}"", ExactSpelling = true)]
public static extern int* DoWork(MyStruct* pThis, int* value = null);
}}
}}
";

return ValidateGeneratedCSharpPreviewUnixBindingsAsync(InputContents, expectedOutputContents);
}

protected override Task DestructorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Loading

0 comments on commit ce3e5c3

Please sign in to comment.