Fix custom-attribute generic argument dataflow in the trimmer#128776
Fix custom-attribute generic argument dataflow in the trimmer#128776Copilot wants to merge 9 commits into
Conversation
Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
…new()-constrained ctor Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
|
Tagging subscribers to this area: @agocke, @dotnet/illink |
There was a problem hiding this comment.
Pull request overview
This PR updates ILLink’s marking behavior for custom attributes so generic instantiations on attribute types participate in generic argument dataflow, ensuring requirements like new() constraints (and related annotations) are honored when attributes are materialized via reflection.
Changes:
- Run
GenericArgumentDataFlow.ProcessGenericArgumentDataFlowfor the attribute constructor’s declaring type duringMarkStep.MarkCustomAttribute. - Add a regression test that reflects over a type with a
new()-constrained generic attribute and asserts the generic argument’s public parameterless constructor is preserved.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | Invokes generic-argument dataflow for attribute type instantiations when marking custom attributes. |
| src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/NewConstrainedGenericAttributeArgumentConstructorIsKept.cs | Adds a linker test covering new()-constrained generic attribute arguments accessed via reflection. |
|
|
||
| [Kept] | ||
| [KeptBaseType(typeof(Attribute))] | ||
| class MyAttribute<[KeptGenericParamAttributes(GenericParameterAttributes.DefaultConstructorConstraint)] T> : Attribute where T : new() |
There was a problem hiding this comment.
@copilot Can we move this to the existing GenericAttributes tests? And could we add a test for a generic attribute where the generic parameter has DynamicallyAccessedMembers?
There was a problem hiding this comment.
@copilot please move this test case to GenericAttributes tests and add a similar test case where the generic parameter has DynamicallyAccessedMembers. It should warn when the T passed in is unannotated, and not warn when it is annotated. It should look similar to below.
typeof(GenericClass<int, string>.InnerClass).GetCustomAttributes();
typeof(GenericClass<int, string>.InnerClass2).GetCustomAttributes();
class MyAnnotatedAttribute<[DynamicallyAccessedMembers(DAMT.Methods)] T>
{
}
class GenericClass<TUnnotated, [DynamicallyAccessedMembers(DAMT.Methods)]TAnnotated>
{
[MyAnnotated<TUnannotated>] // Warns
public class InnerClass { }
[MyAnnotated<TAnnotated>] // no warning
public class InnerClass2 { }
}| TypeReference constructor_type = ca.Constructor.DeclaringType; | ||
| GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in origin, this, Context, constructor_type); | ||
|
|
Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
…ric-attribute case Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com>
A generic attribute carrying a
new()constraint failed to keep the parameterless constructor of its generic argument, and the trimmer could NRE while emitting IL2091 for generic-argument dataflow on custom attributes.Description
ProcessGenericArgumentDataFlowwithRequiresGenericArgumentDataFlowso generic-argument analysis only runs when the argument actually carries requirements.GetGenericParameterDeclaringMemberDisplayName,GetNamespaceDisplayName) so emitting IL2091 for an orphan generic parameter — a custom-attribute generic argument with no resolvable declaring type/method — no longer throws.NewConstrainedGenericAttributeArgumentConstructorIsKeptintoGenericAttributes, and drop a bogus[KeptMember(".ctor()")]onWithNewConstrainedGenericAttribute(its ctor is correctly trimmed since the attribute is read viaGetCustomAttributes, never constructed).GenericAttributesDataFlow.il) for the generic-attribute DAM dataflow scenario, which cannot be expressed in C# (CS8968: a type parameter cannot be used as a generic attribute argument). The test asserts the unannotated argument warns IL2091 without crashing, matched viaLogContainsbecause the warning originates in the dependency assembly rather than the test assembly.Known limitation
The reviewer-requested "no warning when the argument is annotated" half is not currently achievable. A custom-attribute generic argument is encoded as an orphan positional generic parameter (
!0, withDeclaringType/DeclaringMethod/Ownerall null), soFlowAnnotations.GetGenericParameterAnnotationreturnsNoneand annotated/unannotated arguments warn identically. Suppressing the annotated case would require resolving positional generic parameters against the attribute's target type — out of scope for this fix and flagged for reviewer decision.