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 +}