Skip to content

Trim analyzer: Doesn't produce warnings due to annotated generic parameter in various situations #95121

@vitek-karas

Description

@vitek-karas
Method<string>();

Type Method<TUnknown>()
{
    // Should WARN - TUnknown does have All annotation
    return typeof(TRequires<TUnknown>);
}

class TRequires<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>
{
}

The able produces IL2091 in the trimmer, but doesn't produce it in the analyzer. The bug seems to be that we don't process generic parameter annotations in a typeof.

Also happens for a declaration of a local variable:

void Method<TUnknown>()
{
    // Trimmer produces IL2091 here, analyzer doesn't
    TRequires<TUnknown> a;
}

Note that for local variables NativeAOT doesn't produce the warning either - see the comment here for why:

// NativeAOT differences in behavior:
//
// Validation of generic parameters only matters if the instantiation can be used to run code with the substituted type.
// So for generic methods the validation has to happen basically always (since any access to the method can lead to the code
// of the method executing eventually).
// For generic types though the situation is different. Code on the type can only run if the type is instantiated (new)
// or if static members are accessed on it (method calls, or fields accesses both can lead to static .cctor execution).
// Others usages of the type cannot themselves lead to code execution in the type, and thus don't need to be validated.
// Currently linker and analyzer both validate every time there's a type occurrence in the code.
// NativeAOT on the other hand only validates the cases which can lead to code execution (this is partially because the compiler
// doesn't care about the type in other situations really).
// So for example local variables of a given type, or method parameters of that type alone will not cause code execution
// inside that type and thus won't be validated by NativeAOT compiler.
//
// Below this explanation/fact is referred to as "NativeAOT_StorageSpaceType"
// Storage space - declaring a storage space as having a specific type doesn't in itself do anything with that type as per
// the above description.

We should figure out if analyzer needs to produce the warning or not.

Another situation is a static field access:

    TRequires<TUnknown>.Field;  // Should warn

Yet another situation - expression trees:

Expression<Func<string>> a = () => TRequires<TUnknown>.Field

And then type checks (NativeAOT doesn't warn here, see the link above):

if (value is TRequires<TUnknown>) {}

var a = value as TRequires<TUnknown>;

Catch and filter expressions (NativeAOT doesn't warn):

try {}
catch (TRequires<TUnknown>) {}
catch (Exception ex) when (ex is TRequires<TUnknown>) {}

Nested generic for methods:

GenericMethod<Generic1<Generic2<TRequires<TUnknown>>>();

Similarly nested generics don't cause DAM marking and thus diagnostics:

GenericMethod<Generic1<Generic2<TRequires<TypeWIthRUCMethod>>>(); // Should produce IL2026

Metadata

Metadata

Assignees

Labels

area-Tools-ILLink.NET linker development as well as trimming analyzers

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions