diff --git a/src/AST/Function.cs b/src/AST/Function.cs index 97917a5d..0ae0a203 100644 --- a/src/AST/Function.cs +++ b/src/AST/Function.cs @@ -258,7 +258,7 @@ namespace CppSharp.AST return visitor.VisitFunctionDecl(this); } - public Type Type => OriginalReturnType.Type; - public QualifiedType QualifiedType => OriginalReturnType; + public Type Type => ReturnType.Type; + public QualifiedType QualifiedType => ReturnType; } } \ No newline at end of file diff --git a/src/AST/Type.cs b/src/AST/Type.cs index 5b160f3f..cca7c148 100644 --- a/src/AST/Type.cs +++ b/src/AST/Type.cs @@ -260,6 +260,7 @@ namespace CppSharp.AST ReturnType = new QualifiedType((Type) type.ReturnType.Type.Clone(), type.ReturnType.Qualifiers); Parameters.AddRange(type.Parameters.Select(p => new Parameter(p)).ToList()); CallingConvention = type.CallingConvention; + IsDependent = type.IsDependent; } public override T Visit(ITypeVisitor visitor, TypeQualifiers quals = new TypeQualifiers()) diff --git a/src/Generator/BindingContext.cs b/src/Generator/BindingContext.cs index 8b99aa72..4251c9f3 100644 --- a/src/Generator/BindingContext.cs +++ b/src/Generator/BindingContext.cs @@ -2,7 +2,6 @@ using CppSharp.AST; using CppSharp.Passes; using CppSharp.Types; using CppSharp.Parser; -using System.Collections.Generic; namespace CppSharp.Generators { @@ -20,16 +19,12 @@ namespace CppSharp.Generators public PassBuilder TranslationUnitPasses { get; private set; } public PassBuilder GeneratorOutputPasses { get; private set; } - public Dictionary Delegates { get; private set; } - public BindingContext(DriverOptions options, ParserOptions parserOptions = null) { Options = options; ParserOptions = parserOptions; Symbols = new SymbolContext(); - Delegates = new Dictionary(); - TypeMaps = new TypeMapDatabase(); TranslationUnitPasses = new PassBuilder(this); diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 5c7e04a0..c538e939 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -295,7 +295,6 @@ namespace CppSharp TranslationUnitPasses.AddPass(new CheckStaticClass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); TranslationUnitPasses.AddPass(new MoveFunctionToClassPass()); - TranslationUnitPasses.AddPass(new GenerateAnonymousDelegatesPass()); TranslationUnitPasses.AddPass(new ConstructorToConversionOperatorPass()); TranslationUnitPasses.AddPass(new MarshalPrimitivePointersAsRefTypePass()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); @@ -321,8 +320,8 @@ namespace CppSharp } TranslationUnitPasses.AddPass(new MultipleInheritancePass()); TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass()); - TranslationUnitPasses.AddPass(new DelegatesPass()); } + TranslationUnitPasses.AddPass(new DelegatesPass()); TranslationUnitPasses.AddPass(new GetterSetterToPropertyPass()); TranslationUnitPasses.AddPass(new StripUnusedSystemTypesPass()); diff --git a/src/Generator/Generators/CLI/CLIHeaders.cs b/src/Generator/Generators/CLI/CLIHeaders.cs index ebf63934..64298bda 100644 --- a/src/Generator/Generators/CLI/CLIHeaders.cs +++ b/src/Generator/Generators/CLI/CLIHeaders.cs @@ -745,31 +745,27 @@ namespace CppSharp.Generators.CLI if (!typedef.IsGenerated) return false; - FunctionType function; - if (typedef.Type.IsPointerTo(out function)) + var functionType = typedef.Type as FunctionType; + if (functionType != null || typedef.Type.IsPointerTo(out functionType)) { PushBlock(BlockKind.Typedef, typedef); GenerateDeclarationCommon(typedef); var insideClass = typedef.Namespace is Class; - var attributedType = typedef.Type.GetPointee() as AttributedType; - if (attributedType != null) - { - var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType; - var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv(); - if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) - { - WriteLine("[{0}({1}::{2})] ", - "System::Runtime::InteropServices::UnmanagedFunctionPointer", - "System::Runtime::InteropServices::CallingConvention", - callingConvention); - } - } + var attributedType = typedef.Type.GetPointee().Desugar(); + var callingConvention = attributedType == null && functionType != null + ? functionType.CallingConvention + : ((FunctionType)attributedType).CallingConvention; + var interopCallConv = callingConvention.ToInteropCallConv(); + if (interopCallConv != System.Runtime.InteropServices.CallingConvention.Winapi) + WriteLine("[System::Runtime::InteropServices::UnmanagedFunctionPointer" + + "(System::Runtime::InteropServices::CallingConvention::{0})] ", + interopCallConv); WriteLine("{0}{1};", !insideClass ? "public " : "", - string.Format(TypePrinter.VisitDelegate(function).ToString(), + string.Format(TypePrinter.VisitDelegate(functionType).ToString(), typedef.Name)); PopBlock(NewLineKind.BeforeNextBlock); diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index f78ec12f..fe0e50a1 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -256,8 +256,8 @@ namespace CppSharp.Generators.CSharp var decl = typedef.Declaration; - FunctionType function; - if (decl.Type.IsPointerTo(out function)) + var functionType = decl.Type as FunctionType; + if (functionType != null || decl.Type.IsPointerTo(out functionType)) { var ptrName = Generator.GeneratedIdentifier("ptr") + Context.ParameterIndex; diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 46281cf8..5ae0040a 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -1688,7 +1688,7 @@ namespace CppSharp.Generators.CSharp TypePrinter.PopMarshalKind(); WriteLine("private static {0} {1}Instance;", - Context.Delegates[method].Signature, + method.FunctionType.ToString(), vTableMethodDelegateName); NewLine(); @@ -2490,7 +2490,7 @@ namespace CppSharp.Generators.CSharp var delegateId = Generator.GeneratedIdentifier(@delegate); WriteLine("var {0} = ({1}) Marshal.GetDelegateForFunctionPointer(new IntPtr({2}), typeof({1}));", - delegateId, Context.Delegates[method].Signature, + delegateId, method.FunctionType.ToString(), Helpers.SlotIdentifier); return delegateId; diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index 13a3683e..9298fa23 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -657,9 +657,6 @@ namespace CppSharp.Generators.CSharp typeBuilder.Append(printedType); var type = typeBuilder.ToString(); - if (Context.Delegates.ContainsKey(param)) - return $"{Context.Delegates[param].Signature} {param.Name}"; - if (ContextKind == TypePrinterContextKind.Native) return $"{type} {param.Name}"; diff --git a/src/Generator/Passes/DelegatesPass.cs b/src/Generator/Passes/DelegatesPass.cs index 0a7dd949..77683148 100644 --- a/src/Generator/Passes/DelegatesPass.cs +++ b/src/Generator/Passes/DelegatesPass.cs @@ -3,32 +3,15 @@ using System.Linq; using System.Text; using CppSharp.AST; using CppSharp.AST.Extensions; -using CppSharp.Generators; using CppSharp.Generators.CSharp; namespace CppSharp.Passes { public class DelegatesPass : TranslationUnitPass { - public const string DelegatesNamespace = "Delegates"; - - public class DelegateDefinition - { - public DelegateDefinition(string @namespace, string signature) - { - Namespace = @namespace; - Signature = signature; - } - - public string Namespace { get; } - - public string Signature { get; } - } - public DelegatesPass() { VisitOptions.VisitClassBases = false; - VisitOptions.VisitFunctionParameters = false; VisitOptions.VisitFunctionReturnType = false; VisitOptions.VisitNamespaceEnums = false; VisitOptions.VisitNamespaceTemplates = false; @@ -37,177 +20,194 @@ namespace CppSharp.Passes public override bool VisitASTContext(ASTContext context) { - foreach (var module in Options.Modules) - libsDelegates[module] = new Dictionary(); + bool result = base.VisitASTContext(context); + + foreach (var @delegate in delegates) + @delegate.Namespace.Declarations.Add(@delegate); + delegates.Clear(); - var unit = context.TranslationUnits.GetGenerated().LastOrDefault(); + if (!Options.IsCSharpGenerator) + return result; + + var generatedUnits = context.TranslationUnits.GetGenerated(); + var unit = generatedUnits.LastOrDefault(); if (unit == null) return false; - var result = base.VisitASTContext(context); - - foreach (var module in Options.Modules.Where(m => namespacesDelegates.ContainsKey(m))) - namespacesDelegates[module].Namespace.Declarations.Add(namespacesDelegates[module]); + foreach (var module in Options.Modules.Where(namespacesDelegates.ContainsKey)) + { + var @namespace = namespacesDelegates[module]; + @namespace.Namespace.Declarations.Add(@namespace); + } return result; } - private void AddDelegatesToDictionary(Declaration decl, Module module) + public override bool VisitMethodDecl(Method method) { - CallingConvention callingConvention; - bool isDependent = false; - QualifiedType returnType; - List @params; - if (decl is Method) - { - var method = (Method) decl; - @params = method.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi, true).ToList(); - callingConvention = method.CallingConvention; - isDependent = method.IsDependent; - returnType = method.ReturnType; - } - else - { - var param = (Parameter) decl; - var funcTypeParam = param.Type.Desugar().GetFinalPointee().Desugar() as FunctionType; - @params = funcTypeParam.Parameters; - callingConvention = funcTypeParam.CallingConvention; - isDependent = funcTypeParam.IsDependent; - returnType = funcTypeParam.ReturnType; - } + if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore) + return false; - var delegateName = GenerateDelegateSignature(@params, returnType); - Namespace namespaceDelegates; + method.FunctionType = CheckForDelegate(method.FunctionType, method); - if (namespacesDelegates.ContainsKey(module)) - { - namespaceDelegates = namespacesDelegates[module]; - } - else - { - Namespace parent = null; - if (string.IsNullOrEmpty(module.OutputNamespace)) - { - var group = module.Units.SelectMany(u => u.Declarations).OfType( - ).GroupBy(d => d.Name).Where(g => g.Any(d => d.HasDeclarations)).ToList(); - if (group.Count == 1) - parent = group.Last().Last(); - } - if (parent == null) - parent = module.Units.Last(); - namespaceDelegates = new Namespace - { - Name = DelegatesNamespace, - Namespace = parent - }; - namespacesDelegates.Add(module, namespaceDelegates); - } + return true; + } - var functionType = new FunctionType - { - CallingConvention = callingConvention, - IsDependent = isDependent, - ReturnType = returnType - }; - functionType.Parameters.AddRange(@params); - var @delegate = new TypedefDecl - { - Name = delegateName, - QualifiedType = new QualifiedType( - new PointerType(new QualifiedType(functionType))), - Namespace = namespaceDelegates, - IsSynthetized = true, - Access = decl is Method ? AccessSpecifier.Private : AccessSpecifier.Public - }; + public override bool VisitFunctionDecl(Function function) + { + if (!base.VisitFunctionDecl(function) || function.Ignore) + return false; - var delegateString = @delegate.Visit(TypePrinter).Type; - var existingDelegate = GetExistingDelegate( - module, delegateString); + function.ReturnType = CheckForDelegate(function.ReturnType, function); + return true; + } - if (existingDelegate != null) - { - Context.Delegates.Add(decl, existingDelegate); - return; - } + public override bool VisitParameterDecl(Parameter parameter) + { + if (!base.VisitParameterDecl(parameter) || parameter.Namespace == null || + parameter.Namespace.Ignore) + return false; + + parameter.QualifiedType = CheckForDelegate(parameter.QualifiedType, parameter); + + return true; + } + + private QualifiedType CheckForDelegate(QualifiedType type, ITypedDecl decl) + { + if (type.Type is TypedefType) + return type; + + var desugared = type.Type.Desugar(); + if (desugared.IsDependent) + return type; - existingDelegate = new DelegateDefinition(module.OutputNamespace, delegateString); - Context.Delegates.Add(decl, existingDelegate); + Type pointee = desugared.GetPointee() ?? desugared; + if (pointee is TypedefType) + return type; - libsDelegates[module].Add(delegateString, existingDelegate); + var functionType = pointee.Desugar() as FunctionType; + if (functionType == null) + return type; - namespaceDelegates.Declarations.Add(@delegate); + TypedefDecl @delegate = GetDelegate(type, decl); + return new QualifiedType(new TypedefType { Declaration = @delegate }); } - private void VisitFunctionTypeParameters(Function function) + private TypedefDecl GetDelegate(QualifiedType type, ITypedDecl decl) { - foreach (var param in from param in function.Parameters - where !(param.Type is TypedefType) - let paramType = param.Type.Desugar() - where paramType.IsAddress() && - paramType.GetPointee() is FunctionType - select param) + FunctionType newFunctionType = GetNewFunctionType(decl, type); + + var delegateName = GetDelegateName(newFunctionType); + var access = decl is Method ? AccessSpecifier.Private : AccessSpecifier.Public; + var existingDelegate = delegates.SingleOrDefault(t => t.Name == delegateName); + if (existingDelegate != null) { - var module = function.TranslationUnit.Module; - AddDelegatesToDictionary(param, module); + // Ensure a delegate used for a virtual method and a type is public + if (existingDelegate.Access == AccessSpecifier.Private && + access == AccessSpecifier.Public) + existingDelegate.Access = access; + + // Check if there is an existing delegate with a different calling convention + if (((FunctionType) existingDelegate.Type.GetPointee()).CallingConvention == + newFunctionType.CallingConvention) + return existingDelegate; + + // Add a new delegate with the calling convention appended to its name + delegateName += newFunctionType.CallingConvention; } + + var namespaceDelegates = GetDeclContextForDelegates(((Declaration) decl).Namespace); + var delegateType = new QualifiedType(new PointerType(new QualifiedType(newFunctionType))); + existingDelegate = new TypedefDecl + { + Access = access, + Name = delegateName, + Namespace = namespaceDelegates, + QualifiedType = delegateType, + IsSynthetized = true + }; + delegates.Add(existingDelegate); + + return existingDelegate; } - public override bool VisitFunctionDecl(Function function) + private FunctionType GetNewFunctionType(ITypedDecl decl, QualifiedType type) { - if (!base.VisitFunctionDecl(function) || function.Ignore) - return false; + var functionType = new FunctionType(); + var method = decl as Method; + if (method != null && method.FunctionType == type) + { + functionType.Parameters.AddRange( + method.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi, true)); + functionType.CallingConvention = method.CallingConvention; + functionType.IsDependent = method.IsDependent; + functionType.ReturnType = method.ReturnType; + } + else + { + var funcTypeParam = (FunctionType) decl.Type.Desugar().GetFinalPointee().Desugar(); + functionType = new FunctionType(funcTypeParam); + } - // HACK : We should shift this call to VisitFunctionTypeParameters in VisitParameter. We can't do it now - // because we need to use the module and a since a parameter's namespace is null, we can't reach the - // translation unit and thus the module - VisitFunctionTypeParameters(function); + for (int i = 0; i < functionType.Parameters.Count; i++) + functionType.Parameters[i].Name = $"_{i}"; - return true; + return functionType; } - public override bool VisitMethodDecl(Method method) + private DeclarationContext GetDeclContextForDelegates(DeclarationContext @namespace) { - if (!base.VisitMethodDecl(method) || !method.IsVirtual || method.Ignore) - return false; - - var module = method.TranslationUnit.Module; - AddDelegatesToDictionary(method, module); + if (Options.IsCLIGenerator) + return @namespace is Function ? @namespace.Namespace : @namespace; - return true; - } - - private DelegateDefinition GetExistingDelegate(Module module, string delegateString) - { - if (module.Libraries.Count == 0) - return Context.Delegates.Values.FirstOrDefault(t => t.Signature == delegateString); + var module = @namespace.TranslationUnit.Module; + if (namespacesDelegates.ContainsKey(module)) + return namespacesDelegates[module]; - DelegateDefinition @delegate = null; - if (new[] { module }.Union(module.Dependencies).Any( - m => libsDelegates.ContainsKey(m) && libsDelegates[m].TryGetValue( - delegateString, out @delegate))) - return @delegate; + Namespace parent = null; + if (string.IsNullOrEmpty(module.OutputNamespace)) + { + var groups = module.Units.SelectMany(u => u.Declarations).OfType( + ).GroupBy(d => d.Name).Where(g => g.Any(d => d.HasDeclarations)).ToList(); + if (groups.Count == 1) + parent = groups.Last().Last(); + } + + if (parent == null) + parent = module.Units.Last(); - return null; + var namespaceDelegates = new Namespace + { + Name = "Delegates", + Namespace = parent + }; + namespacesDelegates.Add(module, namespaceDelegates); + + return namespaceDelegates; } - private string GenerateDelegateSignature(IEnumerable @params, QualifiedType returnType) + private string GetDelegateName(FunctionType functionType) { var typesBuilder = new StringBuilder(); - if (!returnType.Type.IsPrimitiveType(PrimitiveType.Void)) + if (!functionType.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) { - typesBuilder.Insert(0, returnType.Visit(TypePrinter)); + typesBuilder.Insert(0, functionType.ReturnType.Visit(TypePrinter)); typesBuilder.Append('_'); } - foreach (var parameter in @params) + + foreach (var parameter in functionType.Parameters) { typesBuilder.Append(parameter.Visit(TypePrinter)); typesBuilder.Append('_'); } + if (typesBuilder.Length > 0) typesBuilder.Remove(typesBuilder.Length - 1, 1); + var delegateName = FormatTypesStringForIdentifier(typesBuilder); - if (returnType.Type.IsPrimitiveType(PrimitiveType.Void)) + if (functionType.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) delegateName.Insert(0, "Action_"); else delegateName.Insert(0, "Func_"); @@ -239,9 +239,13 @@ namespace CppSharp.Passes } } - private Dictionary namespacesDelegates = new Dictionary(); + private Dictionary namespacesDelegates = new Dictionary(); private CSharpTypePrinter typePrinter; - private static readonly Dictionary> libsDelegates = - new Dictionary>(); + + /// + /// The generated typedefs. The tree can't be modified while + /// iterating over it, so we collect all the typedefs and add them at the end. + /// + private readonly List delegates = new List(); } } diff --git a/src/Generator/Passes/GenerateAnonymousDelegatesPass.cs b/src/Generator/Passes/GenerateAnonymousDelegatesPass.cs deleted file mode 100644 index cff31d2a..00000000 --- a/src/Generator/Passes/GenerateAnonymousDelegatesPass.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using CppSharp.AST; -using CppSharp.AST.Extensions; - -namespace CppSharp.Passes -{ - /// - /// C++ function pointers are converted to delegates. If the function pointer is typedef'd then a delegate is - /// generated with that name, otherwise the generic Action or Func delegates are used. The delegates are marhsalled - /// using the GetDelegateForFunctionPointer and GetFunctionPointerForDelegate methods; unfortunately, these methods - /// don't support generic types, so marshalling fails when function pointers are used without typedefs. This pass - /// generates explicit delegates for these function pointers when used as function arguments or return types. - /// - public class GenerateAnonymousDelegatesPass : TranslationUnitPass - { - private struct Typedef - { - public DeclarationContext Context; - public TypedefDecl Declaration; - } - - /// - /// The generated typedefs keyed by the qualified declaration context name. The tree can't be modified while - /// iterating over it, so we collect all the typedefs and add them at the end. - /// - private readonly Dictionary> allTypedefs = new Dictionary>(); - - public override bool VisitASTContext(ASTContext context) - { - bool result = base.VisitASTContext(context); - - foreach (var typedef in allTypedefs) - { - foreach (var foo in typedef.Value) - { - foo.Context.Declarations.Add(foo.Declaration); - } - } - allTypedefs.Clear(); - - return result; - } - - public override bool VisitFunctionDecl(Function function) - { - if (!base.VisitFunctionDecl(function) || function.Ignore) - return false; - - function.ReturnType = CheckType(function.Namespace, function.ReturnType); - foreach (var parameter in function.Parameters) - { - parameter.QualifiedType = CheckType(function.Namespace, parameter.QualifiedType); - } - return true; - } - - /// - /// Generates a new typedef for the given type if necessary and returns the new type. - /// - /// The namespace the typedef will be added to. - /// The type to check. - /// The new type. - private QualifiedType CheckType(DeclarationContext @namespace, QualifiedType type) - { - if (type.Type.IsDependent) - return type; - - var pointerType = type.Type as PointerType; - if (pointerType == null) - return type; - - var functionType = pointerType.Pointee as FunctionType; - if (functionType == null) - return type; - - List typedefs; - if (!allTypedefs.TryGetValue(@namespace.QualifiedName, out typedefs)) - { - typedefs = new List(); - allTypedefs.Add(@namespace.QualifiedName, typedefs); - } - - var typedef = FindMatchingTypedef(typedefs, functionType); - if (typedef == null) - { - for (int i = 0; i < functionType.Parameters.Count; i++) - { - functionType.Parameters[i].Name = string.Format("_{0}", i); - } - - typedef = new TypedefDecl - { - Access = AccessSpecifier.Public, - Name = string.Format("__AnonymousDelegate{0}", typedefs.Count), - Namespace = @namespace, - QualifiedType = type, - IsSynthetized = true - }; - typedefs.Add(new Typedef - { - Context = @namespace, - Declaration = typedef - }); - } - - var typedefType = new TypedefType - { - Declaration = typedef - }; - return new QualifiedType(typedefType); - } - - /// - /// Finds a typedef with the same return type and parameter types. - /// - /// The typedef list to search. - /// The function to match. - /// The matching typedef, or null if not found. - private static TypedefDecl FindMatchingTypedef(IEnumerable typedefs, FunctionType functionType) - { - return (from typedef in typedefs - let type = (FunctionType)typedef.Declaration.Type.GetPointee() - where type.ReturnType == functionType.ReturnType && - type.Parameters.SequenceEqual(functionType.Parameters, ParameterTypeComparer.Instance) - select typedef.Declaration).SingleOrDefault(); - } - } -} diff --git a/tests/CSharp/CSharp.cpp b/tests/CSharp/CSharp.cpp index 416c9088..89e3df73 100644 --- a/tests/CSharp/CSharp.cpp +++ b/tests/CSharp/CSharp.cpp @@ -1382,6 +1382,12 @@ int funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr* func) return func(a, b); } +typedefedFuncPtr* TestDuplicateDelegate::testDuplicateDelegate(int a) +{ + typedefedFuncPtr* func; + return func; +} + void InlineNamespace::FunctionInsideInlineNamespace() { } diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h index d3e89c0b..b7230864 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/CSharp/CSharp.h @@ -1225,6 +1225,12 @@ void useStdStringJustAsParameter(std::string s); typedef int (typedefedFuncPtr)(Foo* a, Bar b); int DLL_API funcWithTypedefedFuncPtrAsParam(typedefedFuncPtr* func); +class DLL_API TestDuplicateDelegate +{ +public: + virtual typedefedFuncPtr* testDuplicateDelegate(int a); +}; + inline namespace InlineNamespace { diff --git a/tests/Common/Common.Tests.cs b/tests/Common/Common.Tests.cs index 9a8ee54f..33acdc5f 100644 --- a/tests/Common/Common.Tests.cs +++ b/tests/Common/Common.Tests.cs @@ -556,7 +556,7 @@ public class CommonTests : GeneratorTestFixture new TestDelegates().MarshalUnattributedDelegate(i => i); } - [Test, Platform(Exclude = "Win", Reason = "This test crashes our Windows build, possibly a problem with the NUnit runner there.")] + [Test] public void TestPassAnonymousDelegate() { var testDelegates = new TestDelegates();