From ec0bb49776bd03330356556de88bb8456b4f667c Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 29 Mar 2021 21:12:29 -0500 Subject: [PATCH] Annotate CreateInstanceForAnotherGenericParameter as PublicParameterlessConstructor (#50390) This allows private constructors on the Types to be trimmed. Fix #50353 --- .../src/System/RuntimeHandles.cs | 15 +++++++++++++-- .../src/System/Collections/Generic/Comparer.cs | 2 +- .../Collections/Generic/EqualityComparer.cs | 2 +- .../src/System/RuntimeType.Mono.cs | 8 ++++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index f5eb863c158e1..6e99db321a05d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -209,8 +209,13 @@ internal static bool HasElementType(RuntimeType type) return outHandles; } - internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] RuntimeType type, RuntimeType genericParameter) + internal static object CreateInstanceForAnotherGenericParameter( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type, + RuntimeType genericParameter) { + Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic, + $"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors."); + object? instantiatedObject = null; IntPtr typeHandle = genericParameter.GetTypeHandleInternal().Value; @@ -224,8 +229,14 @@ internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAcce return instantiatedObject!; } - internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] RuntimeType type, RuntimeType genericParameter1, RuntimeType genericParameter2) + internal static object CreateInstanceForAnotherGenericParameter( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type, + RuntimeType genericParameter1, + RuntimeType genericParameter2) { + Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic, + $"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors."); + object? instantiatedObject = null; IntPtr* pTypeHandles = stackalloc IntPtr[] diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs index c21928a7381fd..cdfc29a7a3e43 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs @@ -120,7 +120,7 @@ public override int GetHashCode() => [Serializable] internal sealed partial class EnumComparer : Comparer, ISerializable where T : struct, Enum { - internal EnumComparer() { } + public EnumComparer() { } // Used by the serialization engine. private EnumComparer(SerializationInfo info, StreamingContext context) { } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs index 0af18e7f7dd1a..e7f23a80ab5fa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs @@ -180,7 +180,7 @@ public override int GetHashCode() => // Needs to be public to support binary serialization compatibility public sealed partial class EnumEqualityComparer : EqualityComparer, ISerializable where T : struct, Enum { - internal EnumEqualityComparer() { } + public EnumEqualityComparer() { } // This is used by the serialization engine. private EnumEqualityComparer(SerializationInfo information, StreamingContext context) { } diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index 7e54e26fe9949..f58b2d5bd4cce 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -1835,11 +1835,15 @@ public override Type[] GetGenericParameterConstraints() return constraints ?? Type.EmptyTypes; } - internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type genericType, RuntimeType genericArgument) + internal static object CreateInstanceForAnotherGenericParameter( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type genericType, + RuntimeType genericArgument) { var gt = (RuntimeType)MakeGenericType(genericType, new Type[] { genericArgument }); RuntimeConstructorInfo? ctor = gt.GetDefaultConstructor(); - if (ctor is null) + + // CreateInstanceForAnotherGenericParameter requires type to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors. + if (ctor is null || !ctor.IsPublic) throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, gt)); return ctor.InternalInvoke(null, null, wrapExceptions: true)!;