Skip to content

Commit eb29166

Browse files
Extend RunClassConstructor intrinsic handling to accept NonPublicConstructors (#103947)
This should not generate a warning since the static constructor will be kept.
1 parent d6581f8 commit eb29166

File tree

5 files changed

+73
-6
lines changed

5 files changed

+73
-6
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,6 @@ public static void PrepareDelegate(Delegate d)
266266
{
267267
}
268268

269-
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2059:UnrecognizedReflectionPattern",
270-
Justification = "We keep class constructors of all types with an MethodTable")]
271269
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:UnrecognizedReflectionPattern",
272270
Justification = "Constructed MethodTable of a Nullable forces a constructed MethodTable of the element type")]
273271
public static unsafe object GetUninitializedObject(

src/tools/illink/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ RuntimeTypeHandleValue typeHandle
133133
=> new SystemTypeValue (typeHandle.RepresentedType),
134134
RuntimeTypeHandleForGenericParameterValue genericParam
135135
=> _annotations.GetGenericParameterValue (genericParam.GenericParameter),
136+
RuntimeTypeHandleForValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
137+
=> valueWithDynamicallyAccessedMembers.UnderlyingTypeValue,
136138
_ => annotatedMethodReturnValue
137139
});
138140
}
@@ -157,6 +159,8 @@ SystemTypeValue typeHandle
157159
=> new RuntimeTypeHandleValue (typeHandle.RepresentedType),
158160
GenericParameterValue genericParam
159161
=> new RuntimeTypeHandleForGenericParameterValue (genericParam.GenericParameter),
162+
ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
163+
=> new RuntimeTypeHandleForValueWithDynamicallyAccessedMembers(valueWithDynamicallyAccessedMembers),
160164
_ => annotatedMethodReturnValue
161165
});
162166
else
@@ -286,6 +290,9 @@ GenericParameterValue genericParam
286290
foreach (var typeHandleValue in argumentValues[0].AsEnumerable ()) {
287291
if (typeHandleValue is RuntimeTypeHandleValue runtimeTypeHandleValue) {
288292
MarkStaticConstructor (runtimeTypeHandleValue.RepresentedType);
293+
} else if (typeHandleValue is RuntimeTypeHandleForValueWithDynamicallyAccessedMembers damAnnotatedHandle
294+
&& (damAnnotatedHandle.UnderlyingTypeValue.DynamicallyAccessedMemberTypes & DynamicallyAccessedMemberTypes.NonPublicConstructors) != 0) {
295+
// No action needed, NonPublicConstructors keeps the static constructor on the type
289296
} else {
290297
_diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedTypeInRuntimeHelpersRunClassConstructor, calledMethod.GetDisplayName ());
291298
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Diagnostics;
5+
using ILLink.Shared.DataFlow;
6+
using ILLink.Shared.TypeSystemProxy;
7+
8+
// This is needed due to NativeAOT which doesn't enable nullable globally yet
9+
#nullable enable
10+
11+
namespace ILLink.Shared.TrimAnalysis
12+
{
13+
/// <summary>
14+
/// This represents a type handle obtained from a Type with DynamicallyAccessedMembers annotations.
15+
/// </summary>
16+
internal sealed record RuntimeTypeHandleForValueWithDynamicallyAccessedMembers : SingleValue
17+
{
18+
public RuntimeTypeHandleForValueWithDynamicallyAccessedMembers (in ValueWithDynamicallyAccessedMembers underlyingTypeValue)
19+
{
20+
UnderlyingTypeValue = underlyingTypeValue;
21+
}
22+
23+
public readonly ValueWithDynamicallyAccessedMembers UnderlyingTypeValue;
24+
25+
public override SingleValue DeepCopy () => this; // This value is immutable
26+
27+
public override string ToString () => this.ValueToString (UnderlyingTypeValue);
28+
}
29+
}

src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/TypeHandleDataFlow.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public static void Main ()
1818
TestTypeOfFromGeneric<TestType> ();
1919
TestGetTypeHandle ();
2020
TestGetTypeHandleFromGeneric<TestType> ();
21-
TestUnsupportedPatterns (typeof (TestType));
21+
TestFlowThroughGetTypeHandleGetTypeFromHandle (typeof (TestType));
2222
TestNull ();
2323
TestNoValue ();
2424
}
@@ -58,8 +58,7 @@ static void TestGetTypeHandle ()
5858
Type.GetTypeFromHandle (typeof (T).TypeHandle).RequiresPublicFields ();
5959
}
6060

61-
[ExpectedWarning ("IL2072", nameof (Type.GetTypeFromHandle), nameof (DataFlowTypeExtensions.RequiresPublicMethods))]
62-
static void TestUnsupportedPatterns ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeWithMethods)
61+
static void TestFlowThroughGetTypeHandleGetTypeFromHandle ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeWithMethods)
6362
{
6463
Type.GetTypeFromHandle (typeWithMethods.TypeHandle).RequiresPublicMethods ();
6564
}

src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Runtime.CompilerServices;
34
using Mono.Linker.Tests.Cases.Expectations.Assertions;
45
using Mono.Linker.Tests.Cases.Expectations.Metadata;
@@ -16,6 +17,8 @@ public static void Main ()
1617
TestNull ();
1718
TestNoValue ();
1819
TestDataFlowType ();
20+
TestNonPublicConstructorDataFlowType ();
21+
TestPublicConstructorDataFlowType ();
1922
TestIfElseUsingRuntimeTypeHandle (1);
2023
TestIfElseUsingType (1);
2124
}
@@ -62,6 +65,37 @@ static void TestDataFlowType ()
6265
RuntimeHelpers.RunClassConstructor (type.TypeHandle);
6366
}
6467

68+
[Kept]
69+
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
70+
[return: KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
71+
static Type FindTypeWithNonPublicConstructors ()
72+
{
73+
return null;
74+
}
75+
76+
[Kept]
77+
static void TestNonPublicConstructorDataFlowType ()
78+
{
79+
Type type = FindTypeWithNonPublicConstructors ();
80+
RuntimeHelpers.RunClassConstructor (type.TypeHandle);
81+
}
82+
83+
[Kept]
84+
[return: KeptAttributeAttribute(typeof (DynamicallyAccessedMembersAttribute))]
85+
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
86+
static Type FindTypeWithPublicConstructors ()
87+
{
88+
return null;
89+
}
90+
91+
[Kept]
92+
[ExpectedWarning ("IL2059", nameof (RuntimeHelpers) + "." + nameof (RuntimeHelpers.RunClassConstructor))]
93+
static void TestPublicConstructorDataFlowType ()
94+
{
95+
Type type = FindTypeWithPublicConstructors ();
96+
RuntimeHelpers.RunClassConstructor (type.TypeHandle);
97+
}
98+
6599
[Kept]
66100
[ExpectedWarning ("IL2059", nameof (RuntimeHelpers) + "." + nameof (RuntimeHelpers.RunClassConstructor))]
67101
static void TestIfElseUsingRuntimeTypeHandle (int i)
@@ -147,4 +181,4 @@ public ElseClass2 (int foo)
147181
{ }
148182
}
149183
}
150-
}
184+
}

0 commit comments

Comments
 (0)