diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs index 9c5927a7532c03..6f67e769dd3a1d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs @@ -90,15 +90,24 @@ private partial bool TryHandleIntrinsic( } } } - else if (typeInstantiated.Instantiation.IsConstrainedToBeReferenceTypes()) - { - // This will always succeed thanks to the runtime type loader - } else { - triggersWarning = true; - } + if (typeInstantiated.Instantiation.IsConstrainedToBeReferenceTypes()) + { + // This will always succeed thanks to the runtime type loader + } + else + { + triggersWarning = true; + } + // This should technically be in the IsConstrainedToBeReferenceTypes branch above + // but we have trim warning suppressions in dotnet/runtime and elsewhere that rely on the implementation + // detail that reference type instantiations will work, even if the generic is not + // constrained to be a reference type. + // MarkType will try to come up with a reference type type loader template. + _reflectionMarker.MarkType(_diagnosticContext.Origin, typeInstantiated, "MakeGenericType"); + } } else if (value == NullValue.Instance) { diff --git a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs index a0ee00a5e7ac21..10a21b4d59e236 100644 --- a/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs +++ b/src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs @@ -76,6 +76,8 @@ private static int Main() Test105034Regression.Run(); TestMethodsNeededFromNativeLayout.Run(); TestFieldAndParamMetadata.Run(); + TestActivationWithoutConstructor.Run(); + TestNestedMakeGeneric.Run(); // // Mostly functionality tests @@ -859,6 +861,60 @@ public static void Run() } } + class TestActivationWithoutConstructor + { + public static void Run() + { + { + object o = Activator.CreateInstance(typeof(StructForCreateInstanceDirect<>).MakeGenericType(GetTheType())); + if (!o.ToString().Contains(nameof(StructForCreateInstanceDirect<>))) + throw new Exception(); + } + + { + object o = CreateInstance(typeof(StructForCreateInstanceIndirect<>).MakeGenericType(GetTheType())); + if (!o.ToString().Contains(nameof(StructForCreateInstanceIndirect<>))) + throw new Exception(); + + static object CreateInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type t) + => Activator.CreateInstance(t); + } + + { + object o = RuntimeHelpers.GetUninitializedObject(typeof(StructForGetUninitializedObject<>).MakeGenericType(GetTheType())); + if (!o.ToString().Contains(nameof(StructForGetUninitializedObject<>))) + throw new Exception(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Type GetTheType() => typeof(Atom); + } + + class Atom; + + struct StructForCreateInstanceDirect where T : class; + struct StructForCreateInstanceIndirect where T : class; + struct StructForGetUninitializedObject where T : class; + } + + class TestNestedMakeGeneric + { + class Outie where T : class; + class Innie where T : class; + class Atom; + + public static void Run() + { + Type inner = typeof(Innie<>).MakeGenericType(GetAtom()); + Type outer = typeof(Outie<>).MakeGenericType(inner); + + Console.WriteLine(Activator.CreateInstance(outer)); + + [MethodImpl(MethodImplOptions.NoInlining)] + static Type GetAtom() => typeof(Atom); + } + } + class TestCreateDelegate { internal class Greeter