Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion src/coreclr/tools/ILVerification.Tests/ILTests/PrefixTests.il
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>() 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<T>() 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
}

Expand Down
37 changes: 29 additions & 8 deletions src/coreclr/tools/ILVerification/ILImporter.Verify.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/tools/ILVerification/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@
<data name="ConstrainedCallWithNonByRefThis" xml:space="preserve">
<value>The 'this' argument to a constrained call must have ByRef type.</value>
</data>
<data name="ConstrainedTypeNoInterfaceImpl" xml:space="preserve">
<value>The type operand of the constrained prefix must implement the interface declaring the static virtual method.</value>
</data>
<data name="CtorExpected" xml:space="preserve">
<value>.ctor expected.</value>
</data>
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/ILVerification/VerifierError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
}
Loading