diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidator.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidator.cs index d347b6d0f4af74..3ead6a529d148d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidator.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/TypeLoader/ConstraintValidator.cs @@ -38,7 +38,7 @@ private static bool SatisfiesConstraints(this Type genericVariable, SigTypeConte if ((attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0) { - if (!typeArg.HasExplicitOrImplicitPublicDefaultConstructor()) + if (!typeArg.HasExplicitOrImplicitPublicDefaultConstructor() || typeArg.IsAbstract) return false; } diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index ac7dea00ec2907..1d2ac6960da308 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -1455,7 +1455,7 @@ BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstra if ((specialConstraints & gpDefaultConstructorConstraint) != 0) { - if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor())) + if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor() || thArg.IsAbstract())) return FALSE; } diff --git a/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs b/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs index 31560a94bfe5d8..4c244f139fa905 100644 --- a/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs +++ b/src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs @@ -178,7 +178,7 @@ public static bool CanSpecialize(Type type, GenericParameterAttributes attribute if ((attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0) { // value types always have default constructors - if (!type.IsValueType && (type.GetConstructor(Type.EmptyTypes) == null)) + if (!type.IsValueType && ((type.GetConstructor(Type.EmptyTypes) == null) || type.IsAbstract)) { return false; } diff --git a/src/mono/mono/metadata/verify.c b/src/mono/mono/metadata/verify.c index 134a63a3bf2d5e..1a6742acd718c1 100644 --- a/src/mono/mono/metadata/verify.c +++ b/src/mono/mono/metadata/verify.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -99,7 +100,7 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && m_class_is_valuetype (paramClass)) return FALSE; - if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && !mono_class_has_default_constructor (paramClass, TRUE)) + if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && (!mono_class_has_default_constructor (paramClass, TRUE) || mono_class_is_abstract (paramClass))) return FALSE; if (!param_info->constraints) diff --git a/src/tests/reflection/DisallowAbstractConstructors/DisallowAbstractConstructors.cs b/src/tests/reflection/DisallowAbstractConstructors/DisallowAbstractConstructors.cs new file mode 100644 index 00000000000000..038f004a2cd5e4 --- /dev/null +++ b/src/tests/reflection/DisallowAbstractConstructors/DisallowAbstractConstructors.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Reflection; +using Xunit; + +public class X +{ + public abstract class AbstractClassWithConstructor + { + public AbstractClassWithConstructor() + { + } + } + + public static T TestConstructorMethod() where T : new() + { + return new T(); + } + + public interface IItemCreator + { + public object CreateItem(); + } + + public sealed class ItemCreator : IItemCreator where T : new() + { + public object CreateItem() + { + return new T(); + } + } + + [Fact] + public static int TestEntryPoint() + { + var ok = true; + + Type type = null; + try + { + type = typeof(ItemCreator<>).MakeGenericType(typeof(AbstractClassWithConstructor)); + } + catch + { + //Could check if it is the proper type of exception + } + if (type == null) { + Console.WriteLine("Wasn't able to load type as expected"); + } + else + { + Console.WriteLine("Was able to make type which wasn't expected"); + ok = false; + } + + MethodInfo baseMethod = typeof(X).GetMethod(nameof(TestConstructorMethod), BindingFlags.Static | BindingFlags.Public); + if (baseMethod == null) + { + Console.WriteLine("baseMethod was null which wasn't expected"); + ok = false; + } + MethodInfo method = null; + try + { + method = baseMethod.MakeGenericMethod(typeof(AbstractClassWithConstructor)); + } + catch + { + //Could check if it is the proper method of exception + } + if (method == null) + { + Console.WriteLine("Wasn't able to load method as expected"); + } + else + { + Console.WriteLine("Was able to make method which wasn't expected"); + ok = false; + } + + Console.WriteLine(ok ? "PASS" : "FAIL"); + return ok ? 100 : -1; + } +} + + diff --git a/src/tests/reflection/DisallowAbstractConstructors/DisallowAbstractConstructors.csproj b/src/tests/reflection/DisallowAbstractConstructors/DisallowAbstractConstructors.csproj new file mode 100644 index 00000000000000..0705040d10f5cd --- /dev/null +++ b/src/tests/reflection/DisallowAbstractConstructors/DisallowAbstractConstructors.csproj @@ -0,0 +1,5 @@ + + + + +