From 83df0ab9b9dfd74dd3440d5d27d544c88a7bc205 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 21 Nov 2025 19:08:09 -0800 Subject: [PATCH] Handle multiple calling conventions at once --- .../TestCases/Pretty/FunctionPointers.cs | 26 +++++++++++++ .../CSharp/ExpressionBuilder.cs | 2 +- .../TypeSystem/FunctionPointerType.cs | 39 +++++++++++-------- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs index 9ebcc0524..5379e4948 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs @@ -129,6 +129,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public unsafe delegate* unmanaged[Cdecl, Fastcall] AddressOfLocalFunction_CDeclAndFastcall() + { + return &LocalFunction; + + [UnmanagedCallersOnly(CallConvs = new Type[] { + typeof(CallConvCdecl), + typeof(CallConvFastcall) + })] + static void LocalFunction() + { + } + } + + public unsafe delegate* unmanaged[Fastcall, Cdecl] AddressOfLocalFunction_FastcallAndCDecl() + { + return &LocalFunction; + + [UnmanagedCallersOnly(CallConvs = new Type[] { + typeof(CallConvFastcall), + typeof(CallConvCdecl) + })] + static void LocalFunction() + { + } + } + #if NET60 public unsafe delegate* unmanaged[Cdecl, SuppressGCTransition] AddressOfLocalFunction_CDeclAndSuppressGCTransition() { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index d4990a944..0e79d9b5d 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -4611,7 +4611,7 @@ namespace ICSharpCode.Decompiler.CSharp var builder = ImmutableArray.CreateBuilder(array.Length); foreach (var type in array.Select(a => a.Value).OfType()) { - SignatureCallingConvention? foundCallingConvention = type.Namespace is not "System.Runtime.CompilerServices" ? null : type.Name switch { + SignatureCallingConvention? foundCallingConvention = type.Namespace is not "System.Runtime.CompilerServices" || callingConvention != SignatureCallingConvention.Unmanaged ? null : type.Name switch { "CallConvCdecl" => SignatureCallingConvention.CDecl, "CallConvFastcall" => SignatureCallingConvention.FastCall, "CallConvStdcall" => SignatureCallingConvention.StdCall, diff --git a/ICSharpCode.Decompiler/TypeSystem/FunctionPointerType.cs b/ICSharpCode.Decompiler/TypeSystem/FunctionPointerType.cs index 79abcd92c..75fe0fd75 100644 --- a/ICSharpCode.Decompiler/TypeSystem/FunctionPointerType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/FunctionPointerType.cs @@ -46,23 +46,30 @@ namespace ICSharpCode.Decompiler.TypeSystem && modReturn.Modifier.Namespace == "System.Runtime.CompilerServices") { returnType = modReturn.ElementType; - switch (modReturn.Modifier.Name) + if (callingConvention == SignatureCallingConvention.Unmanaged) { - case "CallConvCdecl": - callingConvention = SignatureCallingConvention.CDecl; - break; - case "CallConvFastcall": - callingConvention = SignatureCallingConvention.FastCall; - break; - case "CallConvStdcall": - callingConvention = SignatureCallingConvention.StdCall; - break; - case "CallConvThiscall": - callingConvention = SignatureCallingConvention.ThisCall; - break; - default: - customCallConvs.Add(modReturn.Modifier); - break; + switch (modReturn.Modifier.Name) + { + case "CallConvCdecl": + callingConvention = SignatureCallingConvention.CDecl; + break; + case "CallConvFastcall": + callingConvention = SignatureCallingConvention.FastCall; + break; + case "CallConvStdcall": + callingConvention = SignatureCallingConvention.StdCall; + break; + case "CallConvThiscall": + callingConvention = SignatureCallingConvention.ThisCall; + break; + default: + customCallConvs.Add(modReturn.Modifier); + break; + } + } + else + { + customCallConvs.Add(modReturn.Modifier); } } else