diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 07ac4365ee72..c47435188906 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -1292,6 +1292,8 @@ internal protected virtual TypeDefinition MarkTypeVisibleToReflection (TypeRefer // could be incorrect) or IsAssignableFrom (where assignability of unconstructed types might change). Annotations.MarkRelevantToVariantCasting (reference.Resolve ()); + MarkImplicitlyUsedFields (reference.Resolve ()); + return MarkType (reference, reason, sourceLocationMember); } @@ -1380,10 +1382,6 @@ internal protected virtual TypeDefinition MarkType (TypeReference reference, Dep MarkGenericParameterProvider (type, sourceLocationMember); - // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit - if (type.IsValueType || !type.IsAutoLayout) - MarkFields (type, includeStatic: type.IsEnum, reason: new DependencyInfo (DependencyKind.MemberOfType, type)); - // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type // However, for some other types there is no benefit to deferring @@ -2341,6 +2339,16 @@ protected virtual void DoAdditionalMethodProcessing (MethodDefinition method) { } + void MarkImplicitlyUsedFields (TypeDefinition type) + { + if (type?.HasFields != true) + return; + + // keep fields for types with explicit layout and for enums + if (!type.IsAutoLayout || type.IsEnum) + MarkFields (type, includeStatic: type.IsEnum, reason: new DependencyInfo (DependencyKind.MemberOfType, type)); + } + protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type) { if (Annotations.IsInstantiated (type)) @@ -2353,6 +2361,8 @@ protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type foreach (var method in GetRequiredMethodsForInstantiatedType (type)) MarkMethod (method, new DependencyInfo (DependencyKind.MethodForInstantiatedType, type), type); + MarkImplicitlyUsedFields (type); + DoAdditionalInstantiatedTypeProcessing (type); } diff --git a/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/ExplicitClass.cs b/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/ExplicitClass.cs index b9d5c960f1ab..20116e22308c 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/ExplicitClass.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/ExplicitClass.cs @@ -19,12 +19,36 @@ class ExplicitClassData public int never_ever_used; } + [StructLayout (LayoutKind.Explicit)] + [Kept] + class UnallocatedExplicitClassData + { + [FieldOffset (0)] + public int never_used; + } + + [StructLayout (LayoutKind.Explicit)] + [Kept] + class UnallocatedButReferencedWithReflectionExplicitClassData + { + [Kept] + [FieldOffset (0)] + public int never_used; + } + public class ExplicitClass { + [Kept] + static UnallocatedExplicitClassData _myField; + public static void Main () { var c = new ExplicitClassData (); c.used = 1; + + _myField = null; + + typeof (UnallocatedButReferencedWithReflectionExplicitClassData).ToString (); } } } diff --git a/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/SequentialClass.cs b/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/SequentialClass.cs index dd8a8b65920c..fd92a3b6b7ac 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/SequentialClass.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes.StructLayout/SequentialClass.cs @@ -14,14 +14,36 @@ class SequentialClassData public int used; } + [Kept] + [StructLayout (LayoutKind.Sequential)] + class UnallocatedSequentialClassData + { + public int never_used; + } + + [Kept] + [StructLayout (LayoutKind.Sequential)] + class UnallocatedButReferencedWithReflectionSequentialClassData + { + [Kept] + public int never_used; + } + public class SequentialClass { + [Kept] + static UnallocatedSequentialClassData _field; + public static void Main () { var c = new SequentialClassData (); c.used = 1; if (Marshal.SizeOf (c) != 8) throw new ApplicationException (); + + _field = null; + + typeof (UnallocatedButReferencedWithReflectionSequentialClassData).ToString (); } } }