diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 885f0039928ec7..89f3e7fc6d91fc 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3362,6 +3362,9 @@ void ProcessInteropMethod (MethodDefinition method, MessageOrigin origin) } } + if (method.AssemblyHasDisableRuntimeMarshalling ()) + return; + TypeDefinition? returnTypeDefinition = Context.TryResolve (method.ReturnType); const bool includeStaticFields = false; diff --git a/src/tools/illink/src/linker/Linker/MethodDefinitionExtensions.cs b/src/tools/illink/src/linker/Linker/MethodDefinitionExtensions.cs index 0555fbf3cd8450..8fe373f5682bdb 100644 --- a/src/tools/illink/src/linker/Linker/MethodDefinitionExtensions.cs +++ b/src/tools/illink/src/linker/Linker/MethodDefinitionExtensions.cs @@ -35,6 +35,21 @@ public static bool IsIntrinsic (this MethodDefinition method) return false; } + public static bool AssemblyHasDisableRuntimeMarshalling (this MethodDefinition method) + { + var assembly = method.Module.Assembly; + if (!assembly.HasCustomAttributes) + return false; + + foreach (var ca in assembly.CustomAttributes) { + var caType = ca.AttributeType; + if (caType.Name == "DisableRuntimeMarshallingAttribute" && caType.Namespace == "System.Runtime.CompilerServices") + return true; + } + + return false; + } + public static bool IsPropertyMethod (this MethodDefinition md) { return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 || diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs index 04f63629f6d93f..3d2b9cd163a78f 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs @@ -46,5 +46,11 @@ public Task UnusedPInvoke () { return RunTest (); } + + [Fact] + public Task RespectsDisableRuntimeMarshalling () + { + return RunTest (); + } } } \ No newline at end of file diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Dependencies/AssemblyWithoutDisableRuntimeMarshalling.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Dependencies/AssemblyWithoutDisableRuntimeMarshalling.cs new file mode 100644 index 00000000000000..493563df454f92 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Dependencies/AssemblyWithoutDisableRuntimeMarshalling.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; + +namespace Mono.Linker.Tests.Cases.Interop.PInvoke.Dependencies; + +public class AssemblyWithoutDisableRuntimeMarshalling +{ + [DllImport ("Unused")] + public static extern B SomeMethod (); + + public class B; +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Interop/PInvoke/RespectsDisableRuntimeMarshalling.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Interop/PInvoke/RespectsDisableRuntimeMarshalling.cs new file mode 100644 index 00000000000000..d1bf402767c1bf --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Interop/PInvoke/RespectsDisableRuntimeMarshalling.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.Interop.PInvoke.Dependencies; + +#if INCLUDE_DISABLE_RUNTIME_MARSHALLING_ATTRIBUTE +[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling] +#endif + +[assembly: KeptAttributeAttribute(typeof(DisableRuntimeMarshallingAttribute))] + +namespace Mono.Linker.Tests.Cases.Interop.PInvoke; + +[SetupCompileBefore ("WithoutDisable.dll", new [] { typeof(AssemblyWithoutDisableRuntimeMarshalling) })] +[Define ("INCLUDE_DISABLE_RUNTIME_MARSHALLING_ATTRIBUTE")] +[KeptModuleReference ("Unused")] +[KeptMemberInAssembly ("WithoutDisable.dll", typeof (AssemblyWithoutDisableRuntimeMarshalling.B), ".ctor()")] +public class RespectsDisableRuntimeMarshalling +{ + public static void Main () + { + var a = SomeMethod (); + var b = AssemblyWithoutDisableRuntimeMarshalling.SomeMethod (); + } + + // The .ctor() will not be marked due to DisableRuntimeMarshalling + [Kept] + class A; + + [Kept] + [DllImport ("Unused")] + static extern A SomeMethod (); +}