Description
Background and motivation
Context: dotnet/roslyn#73920
In short, we need a way to indicate that the compiler should flow attributes from C# code to compiler-generated symbols, to aid downstream IL-based analysis tools. This behavior will be opt-in per attribute type, when the attribute type is annotated with CompilerLoweringPreserveAttribute
.
API Proposal
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CompilerLoweringPreserveAttribute : Attribute
{
public CompilerLoweringPreserveAttribute() { }
}
API Usage
CompilerLoweringPreserveAttribute
shall be placed on an attribute definition to indicate that this attribute should flow to compiler-generated symbols:
[CompilerLoweringPreserve]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter)]
public class MyAttribute { }
For example, when the compiler generates fields for primary constructor parameters, attributes flow from source parameters to compiler-generated fields.
Original:
class C([My] int v)
{
// ...
}
Generated IL (pseudo-C#)
class C(int v)
{
[My] // Attribute flows to generated field
[CompilerGenerated]
int <v>P;
public C([My] v)
{
<v>P = v;
base..ctor();
}
// ...
}
(Note this does not specify whether the compiler generates a field - just that if it does, the attribute flows as long as it has compatible AttributeTargets. See discussion in dotnet/roslyn#73920).
CompilerLoweringPreserveAttribute
will be applied to DynamicallyAccessedMembersAttribute
, to allow primary constructors, and other constructs that lower to compiler-generated types/members, to be annotated for trimming without requiring ILLink to do as much reverse-engineering of the compiler-generated constructs.
Alternative Designs
- Don't flow attributes, and require downstream tools to reverse-engineer the compiler-generated code. This results in a more fragile dependency on the compiler-generated code.
- Flow all attributes (don't make it conditional on
CompilerLoweringPreserveAttribute
) with compatible AttributeTargets. This would lead to metadata bloat and possible unexpected semantics for attributes that have different meanings for different AttributeTargets.
Risks
There is some risk that this will lead to more downstream tools taking a dependency on the compiler-generated code. We should make it clear that this is not a guarantee of any particular rewrite strategy from C# to IL. Any tooling which looks for CompilerLoweringPreserveAttribute
-annotated attributes should not rely on the lowering strategy and may need to be adjusted in response to compiler changes.