Suppress interface generic dataflow warnings under RUC - #131911
Conversation
Warnings for generic instantiations in the interface list originate from the type declaration itself, so they are not suppressed by RequiresUnreferencedCode on the type. The base type case was fixed in dotnet#119419 by moving the check to the (implicit) constructor, but the interface list is still analyzed at the type level in the analyzer, ILLink and ILCompiler. Cover the interface analogues of the existing base type test cases: - new() constraint with a RUC generic argument, with and without RUC on the implementing type (dotnet#108507) - DynamicallyAccessedMembers mismatch with RUC on the implementing type (dotnet#108523) The unsuppressed warnings are marked with UnexpectedWarning so the tests document the current behavior and will need updating once fixed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28 Assisted-by: GitHub Copilot CLI:claude-opus-5
The generic instantiations in a type's interface list are only reachable through the members of that type. When the type is annotated with RequiresUnreferencedCode, all of those members are in the Requires scope, so the attribute should silence the warnings, the same way it already does for the base type instantiation (dotnet#119419). This warns at the type declaration rather than at the point where the type becomes castable to the interface, so it is scoped narrowly to the three interface-list call sites instead of being added to the shared Requires suppression helpers. Attributes on the type and DynamicallyAccessedMembers type hierarchy warnings are deliberately not affected, since those are reachable from reflection outside of any Requires scope. The data flow still runs in ILLink and ILCompiler so that the members required by the instantiation (for example the parameterless constructor implied by a new() constraint) keep being marked; only the diagnostics are suppressed. Fixes dotnet#108507 for interfaces. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28 Assisted-by: GitHub Copilot CLI:claude-opus-5
Type-level RequiresUnreferencedCode should suppress the trimming warnings produced while analyzing a generic interface instantiation, but it does not suppress RequiresAssemblyFiles or RequiresDynamicCode warnings. Narrow NativeAOT's warning gate to the trimming axis so IL3002 and IL3050 remain reported. Add regression coverage for those capability warnings and for the requirement that suppressed interface dataflow still preserves the members requested by DynamicallyAccessedMembers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28 Assisted-by: GitHub Copilot CLI:gpt-5.6-sol
There was a problem hiding this comment.
Pull request overview
This PR adjusts trimming/dataflow diagnostics so that generic instantiations in a type’s interface list no longer produce IL2026/IL2091 warnings when the implementing type is directly annotated with RequiresUnreferencedCode, while still running dataflow to preserve members required by the instantiation and maintaining cross-tool consistency (linker, analyzer, NativeAOT).
Changes:
- Suppress interface-list generic-argument dataflow warnings under type-level RUC while keeping marking/dataflow active (ILLink + NativeAOT).
- Align Roslyn analyzer behavior to skip interface-list generic instantiation warnings for RUC-annotated types while leaving DAM hierarchy/attribute analysis intact.
- Extend test coverage to validate warning suppression behavior and that required members are still kept/marked.
Show a summary per file
| File | Description |
|---|---|
| src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | Adds localized suppression state around interface implementation generic-argument dataflow to silence warnings while still marking required members. |
| src/tools/illink/src/linker/Linker.Dataflow/GenericArgumentDataFlow.cs | Adds a suppression parameter to control whether generic-argument diagnostics are emitted during processing. |
| src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs | Skips interface-list generic instantiation analysis for types with RequiresUnreferencedCode, while still applying DAM type-hierarchy analysis. |
| src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataflowAnalyzedTypeDefinitionNode.cs | Suppresses interface-list trimming diagnostics under type-level RUC while still executing dataflow to mark required members. |
| src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs | Introduces an option to suppress trim-analysis warnings while keeping other capability warnings (e.g., AOT/single-file) reportable. |
| src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs | Threads suppression through generic argument dataflow to match the updated interface-list behavior. |
| src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs | Adds test cases covering interface-list generic warnings under RUC and ensures other capability warnings remain for NativeAOT where appropriate. |
| src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlowMarking.cs | Adds a kept-member regression ensuring interface instantiation still marks required members under RUC suppression. |
| src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs | Updates expected warnings to reflect the new suppression behavior for interface generic analysis under RUC. |
Copilot's findings
- Files reviewed: 9/9 changed files
- Comments generated: 1
Keep interface-list suppression limited to trimming diagnostics while preserving the origin's independent AOT and single-file suppression scopes. Name the ReflectionMarker suppression argument to clarify which diagnostic axis it controls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28 Assisted-by: GitHub Copilot CLI:gpt-5.6-sol
There was a problem hiding this comment.
Copilot's findings
Suppressed comments (2)
src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs:1503
- If you add the non-RUC baseline interface implementation (
ClassImplementingInterfaceWithWarning), it needs to be referenced/instantiated so the interface list is processed and the IL2091 expectation is exercised.
var m = new GenericAnnotatedWithWarningWithRequires<int>();
var n = new ClassImplementingInterfaceWithWarningOnGenericArgumentConstructor();
var o = new ClassImplementingInterfaceWithWarningOnGenericArgumentConstructorWithRequires();
var p = new ClassImplementingInterfaceWithWarningWithRequires();
var q = new ClassImplementingInterfaceWithOtherCapabilityWarningsWithRequires();
src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs:1457
- The new coverage for interface-list generic dataflow under type-level RUC doesn't include a non-RUC baseline for the IL2091 interface generic-argument mismatch. Adding one here would ensure the change suppresses IL2091 only under
[RequiresUnreferencedCode]and doesn't accidentally suppress it unconditionally.
This issue also appears on line 1499 of the same file.
[RequiresUnreferencedCode("--ClassImplementingInterfaceWithWarningWithRequires--")]
public class ClassImplementingInterfaceWithWarningWithRequires : IRequiresAll<T>
{
}
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
# Conflicts: # src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs
There was a problem hiding this comment.
Copilot's findings
Suppressed comments (1)
src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs:158
- This change stops analyzing generic instantiations in base types entirely (the previous behavior analyzed both base types and interfaces). That would suppress IL2091 (and related) diagnostics for base-type generic instantiations even when the implementing type is not annotated with RequiresUnreferencedCode.
If the goal is to suppress only interface-list diagnostics under type-level RUC, the base-type analysis should remain (and, if needed, be suppressed separately based on the desired behavior).
// Examine generic instantiations in the interface list
context.RegisterSymbolAction(context =>
{
var type = (INamedTypeSymbol)context.Symbol;
var location = GetPrimaryLocation(type.Locations);
var typeNameResolver = new TypeNameResolver(context.Compilation);
// The generic instantiations in the interface list are only reachable through the
// members of the type, which are all in the Requires scope of a type-level
// RequiresUnreferencedCode, so the attribute silences these warnings.
// This is not the case for the DynamicallyAccessedMembers hierarchy below, or for
// attributes on the type, which may be accessed via reflection from code which is
// not in a Requires scope.
if (!type.HasAttribute(RequiresUnreferencedCodeAnalyzer.RequiresUnreferencedCodeAttribute))
{
var genericArgumentDataFlow = new GenericArgumentDataFlow(dataFlowAnalyzerContext.TrimAnalyzer, FeatureContext.None, typeNameResolver, type, location, context.ReportDiagnostic);
foreach (var interfaceType in type.Interfaces)
genericArgumentDataFlow.ProcessGenericArgumentDataFlow(interfaceType);
}
- Files reviewed: 9/9 changed files
- Comments generated: 1
jtschuster
left a comment
There was a problem hiding this comment.
I don't love MarkStep._suppressWarningsForInterfaceImplementationDataFlow, but I'm okay if we can't find a cleaner solution right now.
Assisted-by: GitHub Copilot:gpt-5.6-sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28
Assisted-by: GitHub Copilot:gpt-5.6-sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28
Assisted-by: GitHub Copilot:gpt-5.6-sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28
Assisted-by: GitHub Copilot:gpt-5.6-sol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89d21a2e-26e9-4e1c-b670-5ec5336c5e28
There was a problem hiding this comment.
Review details
Suppressed comments (2)
src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs:152
- The
HasAttributehelper only compares the attribute type's simple name (not its namespace), so a user-definedRequiresUnreferencedCodeAttributecould accidentally suppress these interface-list diagnostics. Use a fully-qualified attribute check to avoid false suppression.
if (!type.HasAttribute(RequiresUnreferencedCodeAnalyzer.RequiresUnreferencedCodeAttribute))
src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs:1539
- These assignments exist only to keep the interface types rooted. Using a temporary local that is never read is unnecessary and can generate compiler warnings; use discard assignments (as this file already does) to keep the types referenced.
Type interfaceType;
interfaceType = typeof(IRequiresNew<>);
interfaceType = typeof(IRequiresAll<>);
- Files reviewed: 10/10 changed files
- Comments generated: 0 new
- Review effort level: Lite
Summary
RequiresUnreferencedCodeThis follows the existing base-type behavior while keeping the suppression local to interface-list analysis. Warnings from attributes and
DynamicallyAccessedMemberstype-hierarchy analysis remain unaffected because those can be reached through reflection outside the type'sRequiresUnreferencedCodescope.Fixes #108507
Fixes #108523
Testing
ILLink.RoslynAnalyzer.TestsILCompiler.Trimming.TestsMono.Linker.TestsNote
This content was created with assistance from AI.