diff --git a/src/coreclr/tools/ILVerification.Tests/ILTests/PrefixTests.il b/src/coreclr/tools/ILVerification.Tests/ILTests/PrefixTests.il index 46e4738dd39efb..ad4dc32c49e399 100644 --- a/src/coreclr/tools/ILVerification.Tests/ILTests/PrefixTests.il +++ b/src/coreclr/tools/ILVerification.Tests/ILTests/PrefixTests.il @@ -9,11 +9,114 @@ { } +.class interface public auto ansi abstract IStaticInterface +{ + .method public hidebysig newslot abstract virtual static void StaticAbstractMethod() cil managed + { + } +} + +.class public sequential ansi sealed beforefieldinit ImplStruct + extends [System.Runtime]System.ValueType + implements IStaticInterface +{ + .pack 0 + .size 1 + + .method public hidebysig static void StaticAbstractMethod() cil managed + { + .override method void IStaticInterface::StaticAbstractMethod() + ret + } +} + +.class public sequential ansi sealed beforefieldinit NonImplStruct + extends [System.Runtime]System.ValueType +{ + .pack 0 + .size 1 +} + .class public auto ansi beforefieldinit PrefixTestsType extends [System.Runtime]System.Object { - .method static public hidebysig void StaticMethod() cil managed + .method static public hidebysig void StaticMethod() cil managed + { + ret + } + + .method static public hidebysig void ConstrainedCall.StaticAbstractOnConstrainedTypeParam_Valid<(IStaticInterface) T>() cil managed + { + constrained. !!T + call void IStaticInterface::StaticAbstractMethod() + ret + } + + .method static public hidebysig void ConstrainedCall.StaticAbstractOnImplStruct_Valid() cil managed + { + constrained. ImplStruct + call void IStaticInterface::StaticAbstractMethod() + ret + } + + .method static public hidebysig void ConstrainedCall.UnconstrainedTypeParam_Invalid_ConstrainedTypeNoInterfaceImpl() cil managed + { + constrained. !!T + call void IStaticInterface::StaticAbstractMethod() + ret + } + + .method static public hidebysig void ConstrainedCall.NonImplStruct_Invalid_ConstrainedTypeNoInterfaceImpl() cil managed + { + constrained. NonImplStruct + call void IStaticInterface::StaticAbstractMethod() + ret + } + + .method static public hidebysig void ConstrainedCall.NonVirtualStaticMethod_Invalid_Constrained<(IStaticInterface) T>() cil managed + { + constrained. !!T + call void PrefixTestsType::StaticMethod() + ret + } + + .method static public hidebysig void ConstrainedLdftn.StaticAbstractOnConstrainedTypeParam_Valid<(IStaticInterface) T>() cil managed + { + constrained. !!T + ldftn void IStaticInterface::StaticAbstractMethod() + pop + ret + } + + .method static public hidebysig void ConstrainedLdftn.StaticAbstractOnImplStruct_Valid() cil managed + { + constrained. ImplStruct + ldftn void IStaticInterface::StaticAbstractMethod() + pop + ret + } + + .method static public hidebysig void ConstrainedLdftn.UnconstrainedTypeParam_Invalid_ConstrainedTypeNoInterfaceImpl() cil managed { + constrained. !!T + ldftn void IStaticInterface::StaticAbstractMethod() + pop + ret + } + + .method static public hidebysig void ConstrainedLdftn.NonImplStruct_Invalid_ConstrainedTypeNoInterfaceImpl() cil managed + { + constrained. NonImplStruct + ldftn void IStaticInterface::StaticAbstractMethod() + pop + ret + } + + .method static public hidebysig void ConstrainedLdftn.NonVirtualStaticMethod_Invalid_Constrained<(IStaticInterface) T>() cil managed + { + constrained. !!T + ldftn void PrefixTestsType::StaticMethod() + pop ret } diff --git a/src/coreclr/tools/ILVerification/ILImporter.Verify.cs b/src/coreclr/tools/ILVerification/ILImporter.Verify.cs index 963f470e8ea7bf..e87be8d0be02e0 100644 --- a/src/coreclr/tools/ILVerification/ILImporter.Verify.cs +++ b/src/coreclr/tools/ILVerification/ILImporter.Verify.cs @@ -1553,12 +1553,27 @@ void ImportCall(ILOpcode opcode, int token) TypeDesc constrained = null; bool tailCall = false; + MethodDesc method = ResolveMethodToken(token); + MethodSignature sig = method.Signature; + if (opcode != ILOpcode.newobj) { - if (HasPendingPrefix(Prefix.Constrained) && opcode == ILOpcode.callvirt) + if (HasPendingPrefix(Prefix.Constrained)) { - ClearPendingPrefix(Prefix.Constrained); - constrained = _constrained; + if (opcode == ILOpcode.callvirt) + { + ClearPendingPrefix(Prefix.Constrained); + constrained = _constrained; + } + else if (opcode == ILOpcode.call && method.IsVirtual && sig.IsStatic && method.OwningType.IsInterface) + { + ClearPendingPrefix(Prefix.Constrained); + constrained = _constrained; + + // The constrained type must implement the interface declaring the static virtual method + if (!constrained.CanCastTo(method.OwningType)) + VerificationError(VerifierError.ConstrainedTypeNoInterfaceImpl, constrained, method.OwningType); + } } if (HasPendingPrefix(Prefix.Tail)) @@ -1572,10 +1587,6 @@ void ImportCall(ILOpcode opcode, int token) // if (sig.isVarArg()) // eeGetCallSiteSig(memberRef, getCurrentModuleHandle(), getCurrentContext(), &sig, false); - MethodDesc method = ResolveMethodToken(token); - - MethodSignature sig = method.Signature; - TypeDesc methodType = sig.IsStatic ? null : method.OwningType; if (opcode == ILOpcode.callvirt) @@ -1587,7 +1598,9 @@ void ImportCall(ILOpcode opcode, int token) { EcmaMethod ecmaMethod = method.GetTypicalMethodDefinition() as EcmaMethod; if (ecmaMethod != null) - Check(!ecmaMethod.IsAbstract, VerifierError.CallAbstract); + { + Check(!ecmaMethod.IsAbstract || (method.OwningType.IsInterface && constrained != null), VerifierError.CallAbstract); + } } if (opcode == ILOpcode.newobj && methodType.IsDelegate) @@ -1820,6 +1833,14 @@ void ImportLdFtn(int token, ILOpcode opCode) _delegateCreateStart = _currentInstructionOffset; instance = null; + + if (HasPendingPrefix(Prefix.Constrained) && method.IsVirtual && + method.Signature.IsStatic && method.OwningType.IsInterface) + { + ClearPendingPrefix(Prefix.Constrained); + if (!_constrained.CanCastTo(method.OwningType)) + VerificationError(VerifierError.ConstrainedTypeNoInterfaceImpl, _constrained, method.OwningType); + } } else if (opCode == ILOpcode.ldvirtftn) { diff --git a/src/coreclr/tools/ILVerification/Strings.resx b/src/coreclr/tools/ILVerification/Strings.resx index f89e854992af17..f8da49bb2b5c5c 100644 --- a/src/coreclr/tools/ILVerification/Strings.resx +++ b/src/coreclr/tools/ILVerification/Strings.resx @@ -183,6 +183,9 @@ The 'this' argument to a constrained call must have ByRef type. + + The type operand of the constrained prefix must implement the interface declaring the static virtual method. + .ctor expected. diff --git a/src/coreclr/tools/ILVerification/VerifierError.cs b/src/coreclr/tools/ILVerification/VerifierError.cs index 4a4103febacb97..6bff88641aae2a 100644 --- a/src/coreclr/tools/ILVerification/VerifierError.cs +++ b/src/coreclr/tools/ILVerification/VerifierError.cs @@ -192,5 +192,6 @@ public enum VerifierError LocallocStackNotEmpty, // localloc requires that stack must be empty, except for 'size' argument InvalidBaseType, // Type has an invalid base type. BadTypeSpec, // Invalid TypeSpec metadata. + ConstrainedTypeNoInterfaceImpl, // The type operand of the constrained prefix must implement the interface declaring the static virtual method. } }