This issue is a follow-up to #19043
When building apps with NativeAOT, the ILC prints an AOT analysis warning IL3050: ..cctor(): Using member 'System.Enum.GetValues(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling.
The problem is caused by the [DynamicDependency] attributes we generate in the ApplyPreserveAttributeBase custom linker step when we're transforming [Preserve(AllMembers = true)]. There are two cases in which we get this warning:
- the
[Preserve(AllMembers = true)] is applied to an enum
- the class with the attribute contains a nested enum
We transform the attribute by generating a [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(T))] attribute on the module cctor. This will pull all members of T, but also all members of its base types. In the case of enums, this unfortunately includes the GetValues(Type) static method which is annotated with RequiresDynamicCode.
I see some potential solutions, each of them has a different trade-off:
- Do not preserve nested types
- We change the
DynamicDependency attribute from All to All ^ PublicNestedTypes ^ NonPublicNestedTypes for classes and to PublicFields for enums. This doesn't seem to be a problem in the xamarin-macios codebase (all tests are passing locally with this change), but it will be a breaking change.
- Deprecate
[Preserve]
- We remove all nested enums that cause this problem (
NSObject_Disposer -> NSObject -> Flags, XamarinGCHandleFlags) and make [Preserve] attribute obsolete. We would still keep the custom linker steps that transform Preserve into DynamicDependency, but customers won't get this warning unless they have nested enums in their classes. On our end, we would need to remove all uses of [Preserve] especially in tests (~1200 uses) and in MAUI. The Preserve attributes are baked into bgen-generated binding libraries which could be a problem.
- Suppress the warning
- I think it can be argued that nobody expects
Enum.GetValues(Type) method to be preserved when the [Preserve] attribute is applied to an enum. We might want to simply suppress IL3050 on the module initializer that we generate. I'm not a fan of this solution since we can't suppress just the warning for GetValues and we could miss some other warning with the same ID.
What other solutions should we consider?
/cc @rolfbjarne @ivanpovazan @vitek-karas
Steps to Reproduce
- Build the MySingleView test app with NativeAOT:
dotnet publish -f net8.0-ios -r ios-arm64 \
-p:PublishAot=true -p:PublishAotUsingRuntimepack=true \
-p:EnableTrimAnalyzer=true -p:TrimmerSingleWarn=false \
tests/dotnet/MySingleView/
- Inspect warnings
Expected Behavior
There are no build warnings.
Actual Behavior
ILC prints this warning:
ILC : AOT analysis warning IL3050: <Module>..cctor(): Using member 'System.Enum.GetValues(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload or the GetValuesAsUnderlyingType method instead. [/.../xamarin-macios/tests/dotnet/MySingleView/MySingleView.csproj]
This issue is a follow-up to #19043
When building apps with NativeAOT, the ILC prints an AOT analysis warning IL3050: ..cctor(): Using member 'System.Enum.GetValues(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling.
The problem is caused by the
[DynamicDependency]attributes we generate in theApplyPreserveAttributeBasecustom linker step when we're transforming[Preserve(AllMembers = true)]. There are two cases in which we get this warning:[Preserve(AllMembers = true)]is applied to an enumWe transform the attribute by generating a
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(T))]attribute on the module cctor. This will pull all members ofT, but also all members of its base types. In the case of enums, this unfortunately includes theGetValues(Type)static method which is annotated withRequiresDynamicCode.I see some potential solutions, each of them has a different trade-off:
DynamicDependencyattribute fromAlltoAll ^ PublicNestedTypes ^ NonPublicNestedTypesfor classes and toPublicFieldsfor enums. This doesn't seem to be a problem in the xamarin-macios codebase (all tests are passing locally with this change), but it will be a breaking change.[Preserve]NSObject_Disposer -> NSObject -> Flags, XamarinGCHandleFlags) and make[Preserve]attribute obsolete. We would still keep the custom linker steps that transform Preserve into DynamicDependency, but customers won't get this warning unless they have nested enums in their classes. On our end, we would need to remove all uses of[Preserve]especially in tests (~1200 uses) and in MAUI. The Preserve attributes are baked into bgen-generated binding libraries which could be a problem.Enum.GetValues(Type)method to be preserved when the[Preserve]attribute is applied to an enum. We might want to simply suppressIL3050on the module initializer that we generate. I'm not a fan of this solution since we can't suppress just the warning forGetValuesand we could miss some other warning with the same ID.What other solutions should we consider?
/cc @rolfbjarne @ivanpovazan @vitek-karas
Steps to Reproduce
Expected Behavior
There are no build warnings.
Actual Behavior
ILC prints this warning: