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 analyzersuntriagedNew issue has not been triaged by the area owner

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions