From c0cb74c716a155f0be28099828b143f157005be1 Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Mon, 3 Aug 2020 12:47:17 +0000
Subject: [PATCH 1/6] Update dependencies from
https://github.com/dotnet/runtime build 20200802.3 (#1401)
[master] Update dependencies from dotnet/runtime
- Updates:
- Microsoft.NET.Sdk.IL: from 5.0.0-rc.1.20371.13 to 5.0.0-rc.1.20402.3
---
eng/Version.Details.xml | 4 ++--
eng/Versions.props | 2 +-
global.json | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index b5dff8aeb74f..327e6f2289c5 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -11,9 +11,9 @@
https://github.com/dotnet/arcade
ff5d4b6c8dbdaeacb6e6159d3f8185118dffd915
-
+
https://github.com/dotnet/runtime
- d8cf13e0ba9b369a15a83472b6b97463c6d07fe2
+ ca70fc9903e68d36ee16f7d10a9a491251ea8f20
diff --git a/eng/Versions.props b/eng/Versions.props
index d7ce4af8f280..a15a87e1e282 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -13,7 +13,7 @@
true
- 5.0.0-rc.1.20371.13
+ 5.0.0-rc.1.20402.3
$(MicrosoftNETSdkILPackageVersion)
diff --git a/global.json b/global.json
index ad19e99f7dea..d3ec12a809a0 100644
--- a/global.json
+++ b/global.json
@@ -9,6 +9,6 @@
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20364.3",
- "Microsoft.NET.Sdk.IL": "5.0.0-rc.1.20371.13"
+ "Microsoft.NET.Sdk.IL": "5.0.0-rc.1.20402.3"
}
}
From ec94b763eb370d72611bd0d8b7ff97a7b104e9b2 Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Mon, 3 Aug 2020 13:36:48 +0000
Subject: [PATCH 2/6] Update dependencies from https://github.com/dotnet/arcade
build 20200724.1 (#1400)
[master] Update dependencies from dotnet/arcade
- Updates:
- Microsoft.DotNet.Arcade.Sdk: from 5.0.0-beta.20364.3 to 5.0.0-beta.20374.1
- Microsoft.DotNet.ApiCompat: from 5.0.0-beta.20364.3 to 5.0.0-beta.20374.1
- Merge branch 'master' into darc-master-c01627a2-32af-48c1-b5af-553d5bb41b7f
---
eng/Version.Details.xml | 8 +++----
eng/Versions.props | 2 +-
eng/common/cross/toolchain.cmake | 41 ++++++++++++++++++++------------
global.json | 2 +-
4 files changed, 32 insertions(+), 21 deletions(-)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 327e6f2289c5..0b482e132aa1 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -3,13 +3,13 @@
-
+
https://github.com/dotnet/arcade
- ff5d4b6c8dbdaeacb6e6159d3f8185118dffd915
+ f6192d1e284a08ac05041d05fa6e60dec74b24f5
-
+
https://github.com/dotnet/arcade
- ff5d4b6c8dbdaeacb6e6159d3f8185118dffd915
+ f6192d1e284a08ac05041d05fa6e60dec74b24f5
https://github.com/dotnet/runtime
diff --git a/eng/Versions.props b/eng/Versions.props
index a15a87e1e282..0c1c8da814ef 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -20,7 +20,7 @@
1.5.0
15.4.8
15.4.8
- 5.0.0-beta.20364.3
+ 5.0.0-beta.20374.1
0.11.2
diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake
index 88a758afb19c..b9fe796f0da7 100644
--- a/eng/common/cross/toolchain.cmake
+++ b/eng/common/cross/toolchain.cmake
@@ -127,29 +127,40 @@ endif()
# Specify link flags
+function(add_toolchain_linker_flag Flag)
+ set(Config "${ARGV1}")
+ set(CONFIG_SUFFIX "")
+ if (NOT Config STREQUAL "")
+ set(CONFIG_SUFFIX "_${Config}")
+ endif()
+ set("CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE)
+ set("CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE)
+endfunction()
+
+
if(TARGET_ARCH_NAME STREQUAL "armel")
if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only
- add_link_options("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
- add_link_options("-L${CROSS_ROOTFS}/lib")
- add_link_options("-L${CROSS_ROOTFS}/usr/lib")
- add_link_options("-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
endif()
elseif(TARGET_ARCH_NAME STREQUAL "arm64")
if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only
- add_link_options("-B${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
- add_link_options("-L${CROSS_ROOTFS}/lib64")
- add_link_options("-L${CROSS_ROOTFS}/usr/lib64")
- add_link_options("-L${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
-
- add_link_options("-Wl,--rpath-link=${CROSS_ROOTFS}/lib64")
- add_link_options("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64")
- add_link_options("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/lib64")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
endif()
elseif(TARGET_ARCH_NAME STREQUAL "x86")
- add_link_options(-m32)
+ add_toolchain_linker_flag(-m32)
elseif(ILLUMOS)
- add_link_options("-L${CROSS_ROOTFS}/lib/amd64")
- add_link_options("-L${CROSS_ROOTFS}/usr/amd64/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib/amd64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/amd64/lib")
endif()
# Specify compile options
diff --git a/global.json b/global.json
index d3ec12a809a0..1326251f8c68 100644
--- a/global.json
+++ b/global.json
@@ -8,7 +8,7 @@
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20364.3",
+ "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20374.1",
"Microsoft.NET.Sdk.IL": "5.0.0-rc.1.20402.3"
}
}
From edaf18961fe80083245822bd2dec205db5df64f4 Mon Sep 17 00:00:00 2001
From: Mateo Torres-Ruiz
Date: Mon, 3 Aug 2020 10:50:26 -0700
Subject: [PATCH 3/6] Add suppressions before checking for ca removal instances
(#1395)
---
src/linker/Linker.Steps/MarkStep.cs | 5 ++--
.../AddSuppressionsBeforeAttributeRemoval.cs | 27 +++++++++++++++++++
.../AddSuppressionsBeforeAttributeRemoval.xml | 8 ++++++
3 files changed, 38 insertions(+), 2 deletions(-)
create mode 100644 test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs
create mode 100644 test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 4b812e92b4c9..383520ef5582 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -558,6 +558,9 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo
continue;
}
+ if (UnconditionalSuppressMessageAttributeState.TypeRefHasUnconditionalSuppressions (ca.Constructor.DeclaringType))
+ _context.Suppressions.AddSuppression (ca, provider);
+
if (_context.Annotations.HasLinkerAttribute (ca.AttributeType.Resolve ()) && providerInLinkedAssembly)
continue;
@@ -1590,8 +1593,6 @@ bool MarkSpecialCustomAttributeDependencies (CustomAttribute ca, ICustomAttribut
provider,
sourceLocationMember);
return true;
- } else if (UnconditionalSuppressMessageAttributeState.TypeRefHasUnconditionalSuppressions (dt)) {
- _context.Suppressions.AddSuppression (ca, provider);
}
return false;
diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs
new file mode 100644
index 000000000000..681a36075b13
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq.Expressions;
+using System.Text;
+
+namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression
+{
+ [SkipKeptItemsValidation]
+ [SetupLinkAttributesFile ("AddSuppressionsBeforeAttributeRemoval.xml")]
+ [LogDoesNotContain ("IL2006: Mono.Linker.Tests.Cases.Warnings.WarningSuppression.AddSuppressionsBeforeAttributeRemoval.Main()")]
+ public class AddSuppressionsBeforeAttributeRemoval
+ {
+ public static Type TriggerUnrecognizedPattern ()
+ {
+ return typeof (AddedPseudoAttributeAttribute);
+ }
+
+ [UnconditionalSuppressMessage ("ILLinker", "IL2006")]
+ public static void Main ()
+ {
+ Expression.Call (TriggerUnrecognizedPattern (), "", Type.EmptyTypes);
+ }
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml
new file mode 100644
index 000000000000..bd79f27926cf
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
From a3d706af86403f5e9556d0bcdd7e62bd9d051a33 Mon Sep 17 00:00:00 2001
From: Mateo Torres-Ruiz
Date: Mon, 3 Aug 2020 17:02:37 -0700
Subject: [PATCH 4/6] Warn by default (#1372)
* Always log warnings and errors
---
src/linker/Linker.Steps/BlacklistStep.cs | 4 ++--
src/linker/Linker/LinkContext.cs | 12 +++++-------
.../CommandLine/AddCustomStep.cs | 3 ++-
.../CommandLine/CustomStepData.cs | 4 ++--
test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs | 2 +-
.../TestCasesRunner/TestCaseMetadaProvider.cs | 8 --------
6 files changed, 12 insertions(+), 21 deletions(-)
diff --git a/src/linker/Linker.Steps/BlacklistStep.cs b/src/linker/Linker.Steps/BlacklistStep.cs
index 0db345190e12..87cd8f7545c5 100644
--- a/src/linker/Linker.Steps/BlacklistStep.cs
+++ b/src/linker/Linker.Steps/BlacklistStep.cs
@@ -91,10 +91,10 @@ protected override void Process ()
.Where (res => res.Name.Equals ("ILLink.LinkAttributes.xml", StringComparison.OrdinalIgnoreCase))
.Cast ()) {
try {
- Context.LogMessage (MessageContainer.CreateInfoMessage ($"Processing embedded {rsc.Name} from {asm.Name}"));
+ Context.LogMessage ($"Processing embedded {rsc.Name} from {asm.Name}");
steps_to_add.Push (GetExternalLinkAttributesStep (rsc, asm));
} catch (XmlException ex) {
- Context.LogMessage (MessageContainer.CreateErrorMessage ($"Error processing {rsc.Name} from {asm.Name}: {ex}", 1003));
+ Context.LogError ($"Error processing {rsc.Name} from {asm.Name}: {ex}", 1003);
}
}
}
diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs
index a0514d87e4f6..60629e53b5b1 100644
--- a/src/linker/Linker/LinkContext.cs
+++ b/src/linker/Linker/LinkContext.cs
@@ -496,7 +496,11 @@ public bool IsOptimizationEnabled (CodeOptimizations optimization, AssemblyDefin
public void LogMessage (MessageContainer message)
{
- if (!LogMessages || message == MessageContainer.Empty)
+ if (message == MessageContainer.Empty)
+ return;
+
+ if ((message.Category == MessageCategory.Diagnostic ||
+ message.Category == MessageCategory.Info) && !LogMessages)
return;
if (message.Category == MessageCategory.Warning &&
@@ -549,9 +553,6 @@ public void LogDiagnostic (string message)
/// New MessageContainer of 'Warning' category
public void LogWarning (string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None)
{
- if (!LogMessages)
- return;
-
var version = GetWarningVersion (code);
if ((GeneralWarnAsError && (!WarnAsError.TryGetValue ((uint) code, out var warnAsError) || warnAsError)) ||
@@ -606,9 +607,6 @@ public void LogWarning (string text, int code, string origin, string subcategory
/// New MessageContainer of 'Error' category
public void LogError (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null, bool isWarnAsError = false, WarnVersion? version = null)
{
- if (!LogMessages)
- return;
-
var error = MessageContainer.CreateErrorMessage (text, code, subcategory, origin, isWarnAsError, version);
LogMessage (error);
}
diff --git a/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs b/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs
index 9dde4df354dc..b31040d8029d 100644
--- a/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs
+++ b/test/Mono.Linker.Tests.Cases/CommandLine/AddCustomStep.cs
@@ -7,11 +7,12 @@ namespace Mono.Linker.Tests.Cases.CommandLine
#if !NETCOREAPP
[IgnoreTestCase ("Can be enabled once MonoBuild produces a dll from which we can grab the types in the Mono.Linker namespace.")]
#else
- [SetupCompileBefore ("CustomStep.dll", new [] { "Dependencies/CustomStepDummy.cs" }, new [] { "illink.dll" })]
+ [SetupCompileBefore ("CustomStep.dll", new[] { "Dependencies/CustomStepDummy.cs" }, new[] { "illink.dll" })]
#endif
[SetupLinkerArgument ("--custom-step", "CustomStep.CustomStepDummy,CustomStep.dll")]
[SetupLinkerArgument ("--custom-step", "-CleanStep:CustomStep.CustomStepDummy,CustomStep.dll")]
[SetupLinkerArgument ("--custom-step", "+CleanStep:CustomStep.CustomStepDummy,CustomStep.dll")]
+ [SetupLinkerArgument ("--verbose")]
[LogContains ("Custom step added")]
public class AddCustomStep
{
diff --git a/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs b/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs
index 383127a493aa..c6ef3633af99 100644
--- a/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs
+++ b/test/Mono.Linker.Tests.Cases/CommandLine/CustomStepData.cs
@@ -7,11 +7,11 @@ namespace Mono.Linker.Tests.Cases.CommandLine
#if !NETCOREAPP
[IgnoreTestCase ("Can be enabled once MonoBuild produces a dll from which we can grab the types in the Mono.Linker namespace.")]
#else
- [SetupCompileBefore ("CustomStep.dll", new [] { "Dependencies/CustomStepUser.cs" }, new [] { "illink.dll" })]
+ [SetupCompileBefore ("CustomStep.dll", new[] { "Dependencies/CustomStepUser.cs" }, new[] { "illink.dll" })]
#endif
[SetupLinkerArgument ("--custom-step", "CustomStep.CustomStepUser,CustomStep.dll")]
[SetupLinkerArgument ("--custom-data", "NewKey=UserValue")]
-
+ [SetupLinkerArgument ("--verbose")]
[LogContains ("Custom step added with custom data of UserValue")]
public class CustomStepData
{
diff --git a/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs b/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs
index 87082fbd1978..9d863952cf68 100644
--- a/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs
+++ b/test/Mono.Linker.Tests.Cases/Logging/CommonLogs.cs
@@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Logging
[SetupCompileBefore ("LogStep.dll", new[] { "Dependencies/LogStep.cs" }, new[] { "illink.dll" })]
#endif
[SetupLinkerArgument ("--custom-step", "Log.LogStep,LogStep.dll")]
-
+ [SetupLinkerArgument ("--verbose")]
[LogContains ("ILLink: error IL1004: Error")]
[LogContains ("logtest(1,1): warning IL2001: Warning")]
[LogContains ("ILLink: Info")]
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs
index 43d6f3415012..bfc113392abb 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs
@@ -84,14 +84,6 @@ public virtual TestCaseLinkerOptions GetLinkerOptions (NPath inputPath)
tclo.AdditionalArguments.Add (new KeyValuePair ((string) ca[0].Value, values));
}
- foreach (var testType in _fullTestCaseAssemblyDefinition.AllDefinedTypes ()) {
- if (testType.CustomAttributes.Concat (testType.AllMembers ().SelectMany (m => m.CustomAttributes)).Any (attr =>
- attr.AttributeType.Name == nameof (LogContainsAttribute) || attr.AttributeType.Name == nameof (LogDoesNotContainAttribute))) {
- tclo.AdditionalArguments.Add (new KeyValuePair ("--verbose", new string[] { }));
- break;
- }
- }
-
return tclo;
}
From 8f32ed57a05eeb0bae3790c4db75b316c3da76c7 Mon Sep 17 00:00:00 2001
From: Mateo Torres-Ruiz
Date: Mon, 3 Aug 2020 17:51:23 -0700
Subject: [PATCH 5/6] Add support for property tag on CA annotations (#1397)
* Add support for property tag on CA annotations
---
docs/error-codes.md | 22 +-
.../Linker.Steps/BodySubstituterStep.cs | 101 ---------
src/linker/Linker.Steps/LinkAttributesStep.cs | 200 +++++++++++-------
.../Linker.Steps/ProcessLinkerXmlStepBase.cs | 121 +++++++++++
.../DataFlow/XmlAnnotations.cs | 4 +-
.../DataFlow/XmlAnnotations.xml | 10 +-
.../LinkAttributes/LinkerAttributeRemoval.cs | 2 +-
7 files changed, 271 insertions(+), 189 deletions(-)
diff --git a/docs/error-codes.md b/docs/error-codes.md
index 4f76adc145bf..85dc1efc8c84 100644
--- a/docs/error-codes.md
+++ b/docs/error-codes.md
@@ -252,7 +252,7 @@ the error code. For example:
- CustomAttribute 'type' is being referenced in the code but the 'type' has been removed using the "remove" attribute tag on a type inside the LinkAttributes xml
-#### `IL2046`: Presence of RequiresUnreferencedCodeAttribute on method '' doesn't match overridden method 'base method'. All overridden methods must have RequiresUnreferencedCodeAttribute.
+#### `IL2046`: Presence of RequiresUnreferencedCodeAttribute on method 'method' doesn't match overridden method 'base method'. All overridden methods must have RequiresUnreferencedCodeAttribute.
- All overrides of a virtual method including the base method must either have or not have the RequiresUnreferencedCodeAttribute.
@@ -260,9 +260,9 @@ the error code. For example:
- All overrides of a virtual method including the base method must have the same DynamicallyAccessedMemberAttribute usage on all it's components (return value, parameters and generic parameters).
-#### `IL2048`: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'member type' 'member'
+#### `IL2048`: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'member'
-- Internal attribute 'RemoveAttributeInstances' is a special attribute that should only be used on custom attribute types and is being used on'member type' 'member'.
+- Internal attribute 'RemoveAttributeInstances' is a special attribute that should only be used on custom attribute types and is being used on 'member'.
#### `IL2049`: Unrecognized internal attribute 'attribute'
@@ -271,3 +271,19 @@ the error code. For example:
#### `IL2050`: Correctness of COM interop cannot be guaranteed
- P/invoke method 'method' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.
+
+#### `IL2051`: Property element does not contain attribute 'name'
+
+- An attribute element declares a property but this does not specify its name or is empty.
+
+#### `IL2052`: Property 'propertyName' could not be found
+
+- An attribute element has property 'propertyName' but this could not be found.
+
+#### `IL2053`: Invalid value 'propertyValue' for property 'propertyName'
+
+- The value 'propertyValue' used in a custom attribute annotation does not match the type of the attribute's property 'propertyName'.
+
+#### `IL2054`: Invalid argument value 'argumentValue' for attribute 'attribute'
+
+- The value 'argumentValue' used in a custom attribute annotation does not match the type of one of the attribute's constructor arguments. The arguments used for a custom attribute annotation should be declared in the same order the constructor uses.
\ No newline at end of file
diff --git a/src/linker/Linker.Steps/BodySubstituterStep.cs b/src/linker/Linker.Steps/BodySubstituterStep.cs
index 9d7360e58f5b..ff3f191a3f76 100644
--- a/src/linker/Linker.Steps/BodySubstituterStep.cs
+++ b/src/linker/Linker.Steps/BodySubstituterStep.cs
@@ -167,107 +167,6 @@ void ProcessResources (AssemblyDefinition assembly, XPathNodeIterator iterator)
}
}
- static bool TryConvertValue (string value, TypeReference target, out object result)
- {
- switch (target.MetadataType) {
- case MetadataType.Boolean:
- if (bool.TryParse (value, out bool bvalue)) {
- result = bvalue ? 1 : 0;
- return true;
- }
-
- goto case MetadataType.Int32;
-
- case MetadataType.Byte:
- if (!byte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult))
- break;
-
- result = (int) byteresult;
- return true;
-
- case MetadataType.SByte:
- if (!sbyte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult))
- break;
-
- result = (int) sbyteresult;
- return true;
-
- case MetadataType.Int16:
- if (!short.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult))
- break;
-
- result = (int) shortresult;
- return true;
-
- case MetadataType.UInt16:
- if (!ushort.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult))
- break;
-
- result = (int) ushortresult;
- return true;
-
- case MetadataType.Int32:
- if (!int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult))
- break;
-
- result = iresult;
- return true;
-
- case MetadataType.UInt32:
- if (!uint.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult))
- break;
-
- result = (int) uresult;
- return true;
-
- case MetadataType.Double:
- if (!double.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult))
- break;
-
- result = dresult;
- return true;
-
- case MetadataType.Single:
- if (!float.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult))
- break;
-
- result = fresult;
- return true;
-
- case MetadataType.Int64:
- if (!long.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult))
- break;
-
- result = lresult;
- return true;
-
- case MetadataType.UInt64:
- if (!ulong.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult))
- break;
-
- result = (long) ulresult;
- return true;
-
- case MetadataType.Char:
- if (!char.TryParse (value, out char chresult))
- break;
-
- result = (int) chresult;
- return true;
-
- case MetadataType.String:
- if (value is string || value == null) {
- result = value;
- return true;
- }
-
- break;
- }
-
- result = null;
- return false;
- }
-
static MethodDefinition FindMethod (TypeDefinition type, string signature)
{
if (!type.HasMethods)
diff --git a/src/linker/Linker.Steps/LinkAttributesStep.cs b/src/linker/Linker.Steps/LinkAttributesStep.cs
index af8b21b345a1..d30fc60fe41f 100644
--- a/src/linker/Linker.Steps/LinkAttributesStep.cs
+++ b/src/linker/Linker.Steps/LinkAttributesStep.cs
@@ -32,103 +32,143 @@ IEnumerable ProcessAttributes (XPathNavigator nav, ICustomAttri
if (!ShouldProcessElement (iterator.Current))
continue;
- AssemblyDefinition assembly;
- TypeDefinition attributeType;
-
string internalAttribute = GetAttribute (iterator.Current, "internal");
- if (internalAttribute != String.Empty) {
- if (internalAttribute == "RemoveAttributeInstances") {
- if (provider.MetadataToken.TokenType == TokenType.TypeDef) {
- if (!Annotations.IsMarked (provider)) {
- IEnumerable removeAttributeInstance = new List { new RemoveAttributeInstancesAttribute () };
- Context.CustomAttributes.AddInternalAttributes (provider, removeAttributeInstance);
- }
- continue;
- } else {
- Context.LogWarning ($"Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on '{nav.Name}' '{provider}'", 2048, _xmlDocumentLocation);
- continue;
- }
- } else {
- Context.LogWarning ($"Unrecognized internal attribute '{internalAttribute}'", 2049, _xmlDocumentLocation);
- continue;
- }
+ if (!string.IsNullOrEmpty (internalAttribute)) {
+ ProcessInternalAttribute (provider, internalAttribute);
+ continue;
}
string attributeFullName = GetFullName (iterator.Current);
- if (attributeFullName == String.Empty) {
+ if (attributeFullName == string.Empty) {
Context.LogWarning ($"Attribute element does not contain attribute 'fullname'", 2029, _xmlDocumentLocation);
continue;
}
- string assemblyName = GetAttribute (iterator.Current, "assembly");
- if (assemblyName == String.Empty)
- attributeType = Context.GetType (attributeFullName);
- else {
- try {
- assembly = GetAssembly (Context, AssemblyNameReference.Parse (assemblyName));
- } catch (Exception) {
- Context.LogWarning ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in the '{_xmlDocumentLocation}'", 2030, _xmlDocumentLocation);
- continue;
- }
- attributeType = assembly.FindType (attributeFullName);
- }
- if (attributeType == null) {
- Context.LogWarning ($"Attribute type '{attributeFullName}' could not be found", 2031, _xmlDocumentLocation);
+
+ if (!GetAttributeType (iterator, attributeFullName, out TypeDefinition attributeType))
+ continue;
+
+ CustomAttribute customAttribute = CreateCustomAttribute (iterator, attributeType);
+ if (customAttribute != null)
+ attributes.Add (customAttribute);
+ }
+
+ return attributes;
+ }
+
+ CustomAttribute CreateCustomAttribute (XPathNodeIterator iterator, TypeDefinition attributeType)
+ {
+ string[] attributeArguments = (GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty))).ToArray ();
+ MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == attributeArguments.Length);
+ if (constructor == null) {
+ Context.LogWarning ($"Could not find a constructor for type '{attributeType}' that receives '{attributeArguments.Length}' arguments as parameter", 2022, _xmlDocumentLocation);
+ return null;
+ }
+
+ CustomAttribute customAttribute = new CustomAttribute (constructor);
+ var arguments = ProcessAttributeArguments (constructor, attributeArguments);
+ if (arguments != null)
+ foreach (var argument in arguments)
+ customAttribute.ConstructorArguments.Add (argument);
+
+ var properties = ProcessAttributeProperties (iterator.Current.SelectChildren ("property", string.Empty), attributeType);
+ if (properties != null)
+ foreach (var property in properties)
+ customAttribute.Properties.Add (property);
+
+ return customAttribute;
+ }
+
+ List ProcessAttributeProperties (XPathNodeIterator iterator, TypeDefinition attributeType)
+ {
+ List attributeProperties = new List ();
+ while (iterator.MoveNext ()) {
+ string propertyName = GetName (iterator.Current);
+ if (propertyName == string.Empty) {
+ Context.LogWarning ($"Property element does not contain attribute 'name'", 2051, _xmlDocumentLocation);
continue;
}
- ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty));
- MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == arguments.Count);
- if (constructor == null) {
- Context.LogWarning ($"Could not find a constructor for type '{attributeType}' that receives '{arguments.Count}' arguments as parameter", 2022, _xmlDocumentLocation);
+ PropertyDefinition property = attributeType.Properties.Where (prop => prop.Name == propertyName).FirstOrDefault ();
+ if (property == null) {
+ Context.LogWarning ($"Property '{propertyName}' could not be found", 2052, _xmlDocumentLocation);
continue;
}
- string[] xmlArguments = arguments.ToArray ();
- bool recognizedArgument = true;
- CustomAttribute attribute = new CustomAttribute (constructor);
- if (xmlArguments == null) {
- attributes.Add (attribute);
+ var propertyValue = iterator.Current.Value;
+ if (!TryConvertValue (propertyValue, property.PropertyType, out object value)) {
+ Context.LogWarning ($"Invalid value '{propertyValue}' for property '{propertyName}'", 2053, _xmlDocumentLocation);
continue;
}
- for (int i = 0; i < xmlArguments.Length; i++) {
- object argumentValue = null;
-
- if (constructor.Parameters[i].ParameterType.Resolve ().IsEnum) {
- foreach (var field in constructor.Parameters[i].ParameterType.Resolve ().Fields) {
- if (field.IsStatic && field.Name == xmlArguments[i]) {
- argumentValue = Convert.ToInt32 (field.Constant);
- break;
- }
- }
- if (argumentValue == null) {
- Context.LogWarning ($"Could not parse argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' as a {constructor.Parameters[i].ParameterType.FullName}", 2021, _xmlDocumentLocation);
- recognizedArgument = false;
- }
- } else {
- switch (constructor.Parameters[i].ParameterType.MetadataType) {
- case MetadataType.String:
- argumentValue = xmlArguments[i];
- break;
- case MetadataType.Int32:
- int result;
- if (int.TryParse (xmlArguments[i], out result))
- argumentValue = result;
- else {
- Context.LogWarning ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to the constructor parameter type", 2032, _xmlDocumentLocation);
- }
- break;
- default:
- Context.LogWarning ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' is of unsupported type '{constructor.Parameters[i].ParameterType}'", 2020, _xmlDocumentLocation);
- recognizedArgument = false;
- break;
- }
- }
- attribute.ConstructorArguments.Add (new CustomAttributeArgument (constructor.Parameters[i].ParameterType, argumentValue));
+
+ attributeProperties.Add (new CustomAttributeNamedArgument (property.Name,
+ new CustomAttributeArgument (property.PropertyType, value)));
+ }
+
+ return attributeProperties;
+ }
+
+ List ProcessAttributeArguments (MethodDefinition attributeConstructor, string[] arguments)
+ {
+ if (arguments == null)
+ return null;
+
+ List attributeArguments = new List ();
+ for (int i = 0; i < arguments.Length; i++) {
+ object argValue;
+ TypeDefinition parameterType = attributeConstructor.Parameters[i].ParameterType.Resolve ();
+ if (!TryConvertValue (arguments[i], parameterType, out argValue)) {
+ Context.LogWarning ($"Invalid argument value '{arguments[i]}' for attribute '{attributeConstructor.DeclaringType.GetDisplayName ()}'", 2054, _xmlDocumentLocation);
+ return null;
}
- if (recognizedArgument)
- attributes.Add (attribute);
+
+ attributeArguments.Add (new CustomAttributeArgument (parameterType, argValue));
}
- return attributes;
+
+ return attributeArguments;
+ }
+
+ void ProcessInternalAttribute (ICustomAttributeProvider provider, string internalAttribute)
+ {
+ if (internalAttribute != "RemoveAttributeInstances") {
+ Context.LogWarning ($"Unrecognized internal attribute '{internalAttribute}'", 2049, _xmlDocumentLocation);
+ return;
+ }
+
+ if (provider.MetadataToken.TokenType != TokenType.TypeDef) {
+ Context.LogWarning ($"Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on '{provider}'", 2048, _xmlDocumentLocation);
+ return;
+ }
+
+ if (!Annotations.IsMarked (provider)) {
+ IEnumerable removeAttributeInstance = new List { new RemoveAttributeInstancesAttribute () };
+ Context.CustomAttributes.AddInternalAttributes (provider, removeAttributeInstance);
+ }
+ }
+
+ bool GetAttributeType (XPathNodeIterator iterator, string attributeFullName, out TypeDefinition attributeType)
+ {
+ string assemblyName = GetAttribute (iterator.Current, "assembly");
+ if (string.IsNullOrEmpty (assemblyName)) {
+ attributeType = Context.GetType (attributeFullName);
+ } else {
+ AssemblyDefinition assembly;
+ try {
+ assembly = GetAssembly (Context, AssemblyNameReference.Parse (assemblyName));
+ } catch (Exception) {
+ Context.LogWarning ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in '{_xmlDocumentLocation}'", 2030, _xmlDocumentLocation);
+ attributeType = default;
+ return false;
+ }
+
+ attributeType = assembly.FindType (attributeFullName);
+ }
+
+ if (attributeType == null) {
+ Context.LogWarning ($"Attribute type '{attributeFullName}' could not be found", 2031, _xmlDocumentLocation);
+ return false;
+ }
+
+ return true;
}
ArrayBuilder GetAttributeChildren (XPathNodeIterator iterator)
diff --git a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs
index 0d270c31ca3d..d6e25b60c518 100644
--- a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs
+++ b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs
@@ -1,4 +1,6 @@
using System;
+using System.Globalization;
+using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.XPath;
using Mono.Cecil;
@@ -424,6 +426,11 @@ protected static string GetFullName (XPathNavigator nav)
return GetAttribute (nav, FullNameAttributeName);
}
+ protected static string GetName (XPathNavigator nav)
+ {
+ return GetAttribute (nav, NameAttributeName);
+ }
+
protected static string GetSignature (XPathNavigator nav)
{
return GetAttribute (nav, SignatureAttributeName);
@@ -435,5 +442,119 @@ protected static string GetAttribute (XPathNavigator nav, string attribute)
}
public override string ToString () => GetType ().Name + ": " + _xmlDocumentLocation;
+
+ public static bool TryConvertValue (string value, TypeReference target, out object result)
+ {
+ switch (target.MetadataType) {
+ case MetadataType.Boolean:
+ if (bool.TryParse (value, out bool bvalue)) {
+ result = bvalue ? 1 : 0;
+ return true;
+ }
+
+ goto case MetadataType.Int32;
+
+ case MetadataType.Byte:
+ if (!byte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult))
+ break;
+
+ result = (int) byteresult;
+ return true;
+
+ case MetadataType.SByte:
+ if (!sbyte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult))
+ break;
+
+ result = (int) sbyteresult;
+ return true;
+
+ case MetadataType.Int16:
+ if (!short.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult))
+ break;
+
+ result = (int) shortresult;
+ return true;
+
+ case MetadataType.UInt16:
+ if (!ushort.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult))
+ break;
+
+ result = (int) ushortresult;
+ return true;
+
+ case MetadataType.Int32:
+ if (!int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult))
+ break;
+
+ result = iresult;
+ return true;
+
+ case MetadataType.UInt32:
+ if (!uint.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult))
+ break;
+
+ result = (int) uresult;
+ return true;
+
+ case MetadataType.Double:
+ if (!double.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult))
+ break;
+
+ result = dresult;
+ return true;
+
+ case MetadataType.Single:
+ if (!float.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult))
+ break;
+
+ result = fresult;
+ return true;
+
+ case MetadataType.Int64:
+ if (!long.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult))
+ break;
+
+ result = lresult;
+ return true;
+
+ case MetadataType.UInt64:
+ if (!ulong.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult))
+ break;
+
+ result = (long) ulresult;
+ return true;
+
+ case MetadataType.Char:
+ if (!char.TryParse (value, out char chresult))
+ break;
+
+ result = (int) chresult;
+ return true;
+
+ case MetadataType.String:
+ if (value is string || value == null) {
+ result = value;
+ return true;
+ }
+
+ break;
+
+ case MetadataType.ValueType:
+ if (value is string &&
+ target.Resolve () is var typeDefinition &&
+ typeDefinition.IsEnum) {
+ var enumField = typeDefinition.Fields.Where (f => f.IsStatic && f.Name == value).FirstOrDefault ();
+ if (enumField != null) {
+ result = Convert.ToInt32 (enumField.Constant);
+ return true;
+ }
+ }
+
+ break;
+ }
+
+ result = null;
+ return false;
+ }
}
}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs
index ce7721a8f47d..ac6e536f740b 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs
@@ -13,8 +13,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
[SkipKeptItemsValidation]
[SetupLinkAttributesFile ("XmlAnnotations.xml")]
- [LogContains ("XmlAnnotations.xml: warning IL2031: Attribute type 'System.DoesNotExistattribute' could not be found")]
- [LogContains ("XmlAnnotations.xml: warning IL2021: Could not parse argument 'NonValidArgument' specified in *", true)]
+ [LogContains ("XmlAnnotations.xml: warning IL2031: Attribute type 'System.DoesNotExistAttribute' could not be found")]
+ [LogDoesNotContain ("IL2006: Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField():*", true)]
class XmlAnnotations
{
public static void Main ()
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml
index 38810e96e43f..2747c62634e8 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml
@@ -1,9 +1,15 @@
-
+
+ ILLink
+ IL2006
+ member
+ M:Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField
+
+
-
+
0
diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs
index 3d1ea8c0579f..1454637b9e51 100644
--- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs
+++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs
@@ -49,7 +49,7 @@ namespace Mono.Linker.Tests.Cases.LinkAttributes
[LogDoesNotContain ("IL2045")] // No other 2045 messages should be logged
- [LogContains ("IL2048: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'method' 'System.String Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval::methodWithCustomAttribute(System.String)'")]
+ [LogContains ("IL2048: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'System.String Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval::methodWithCustomAttribute(System.String)'")]
[LogContains ("IL2049: Unrecognized internal attribute 'InvalidInternal'")]
[KeptMember (".ctor()")]
From 4b98de3ee714bf737d35ee30761244611f234a64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?=
Date: Wed, 5 Aug 2020 12:58:55 +0200
Subject: [PATCH 6/6] Do not call MarkInterfaceImplementation if already marked
(#1396)
Fixes #1394.
The problem was that marking the interface implementation marks the custom attributes on the InterfaceImpl record which enqueues the attribute constructor. The constructor is already processed, but enqueuing a new method causes the main processing loop to run again. This will rerun the virtual method logic and cause the attribute constructor to be re-added, forever.
Normally, linker protects itself from things like this by having a "processed" state along with "marked" state for various entities. InterfaceImpls don't have a "processed" state and calling Mark will cause the same logic to run. Alternative fix would be to add a "processed" state.
---
src/linker/Linker.Steps/MarkStep.cs | 3 ++
.../InterfaceWithAttributeOnImpl.il | 40 +++++++++++++++++++
.../InterfaceWithAttributeOnImplementation.cs | 22 ++++++++++
3 files changed, 65 insertions(+)
create mode 100644 test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il
create mode 100644 test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index 383520ef5582..cbe86ba75897 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -2898,6 +2898,9 @@ protected virtual bool ShouldMarkInterfaceImplementation (TypeDefinition type, I
protected virtual void MarkInterfaceImplementation (InterfaceImplementation iface, TypeDefinition type)
{
+ if (Annotations.IsMarked (iface))
+ return;
+
// Blame the type that has the interfaceimpl, expecting the type itself to get marked for other reasons.
MarkCustomAttributes (iface, new DependencyInfo (DependencyKind.CustomAttribute, iface), type);
// Blame the interface type on the interfaceimpl itself.
diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il
new file mode 100644
index 000000000000..6615e890fd8a
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/InterfaceWithAttributeOnImpl.il
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class interface public auto ansi abstract IMyInterface
+{
+ .method public hidebysig newslot virtual
+ instance void Frob () cil managed
+ {
+ ret
+ }
+}
+
+.class public auto ansi MyClass
+ extends [mscorlib]System.Object
+ implements IMyInterface
+{
+ .interfaceimpl type IMyInterface
+ .custom instance void MyAttribute::.ctor() = ( 01 00 00 00 )
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor () cil managed
+ {
+ ret
+ }
+}
+
+.class private auto ansi sealed beforefieldinit MyAttribute
+ extends [mscorlib]System.Attribute
+{
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor () cil managed
+ {
+ ret
+ }
+}
diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs
new file mode 100644
index 000000000000..9be72541cb88
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/InterfaceWithAttributeOnImplementation.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods
+{
+#if NETCOREAPP
+ [Define ("IL_ASSEMBLY_AVAILABLE")]
+ [SetupCompileBefore ("library.dll", new[] { "Dependencies/InterfaceWithAttributeOnImpl.il" })]
+ class InterfaceWithAttributeOnImplementation
+ {
+ static void Main ()
+ {
+#if IL_ASSEMBLY_AVAILABLE
+ ((IMyInterface)new MyClass ()).Frob ();
+#endif
+ }
+ }
+#endif
+}