Skip to content

Commit d8b00b9

Browse files
UnsafeAccessor - ambiguous name and signature match (#120011)
Handle the case where there is an ambiguous name and signature match, but one is generic and the other isn't.
1 parent dd8b194 commit d8b00b9

File tree

3 files changed

+99
-26
lines changed

3 files changed

+99
-26
lines changed

src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,12 @@ private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationConte
318318
return false;
319319
}
320320

321+
// Validate generic parameter.
322+
if (declSig.GenericParameterCount != maybeSig.GenericParameterCount)
323+
{
324+
return false;
325+
}
326+
321327
// Validate argument count and return type
322328
if (context.Kind == UnsafeAccessorKind.Constructor)
323329
{

src/coreclr/vm/prestub.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,14 +1190,26 @@ namespace
11901190
return false;
11911191
}
11921192

1193-
// Handle generic param count
1194-
DWORD declGenericCount = 0;
1195-
DWORD methodGenericCount = 0;
1193+
// Handle generic signature
11961194
if (callConvDecl & IMAGE_CEE_CS_CALLCONV_GENERIC)
1195+
{
1196+
if (!(callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC))
1197+
return false;
1198+
1199+
DWORD declGenericCount = 0;
1200+
DWORD methodGenericCount = 0;
11971201
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declGenericCount));
1198-
if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)
11991202
IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &methodGenericCount));
12001203

1204+
if (declGenericCount != methodGenericCount)
1205+
return false;
1206+
}
1207+
else if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)
1208+
{
1209+
// Method is generic but declaration is not
1210+
return false;
1211+
}
1212+
12011213
DWORD declArgCount;
12021214
DWORD methodArgCount;
12031215
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declArgCount));
@@ -3541,7 +3553,7 @@ static PCODE getHelperForStaticBase(Module * pModule, CORCOMPILE_FIXUP_BLOB_KIND
35413553
bool threadStatic = (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER);
35423554

35433555
CorInfoHelpFunc helper;
3544-
3556+
35453557
if (threadStatic)
35463558
{
35473559
if (GCStatic)

src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -181,21 +181,76 @@ public static void Verify_Generic_AccessFieldClass()
181181
}
182182
}
183183

184+
class AmbiguousMethodName
185+
{
186+
private void M() { }
187+
private void M<T>() { }
188+
private void N() { }
189+
190+
private static void SM() { }
191+
private static void SM<U>() { }
192+
private static void SN() { }
193+
}
194+
195+
static class AccessorsAmbiguousMethodName
196+
{
197+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
198+
public extern static void CallM(AmbiguousMethodName a);
199+
200+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
201+
public extern static void CallM<T>(AmbiguousMethodName a);
202+
203+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "N")]
204+
public extern static void CallN_MissingMethod<T>(AmbiguousMethodName a);
205+
206+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")]
207+
public extern static void CallSM(AmbiguousMethodName a);
208+
209+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")]
210+
public extern static void CallSM<U>(AmbiguousMethodName a);
211+
212+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SN")]
213+
public extern static void CallSN_MissingMethod<T>(AmbiguousMethodName a);
214+
}
215+
216+
[Fact]
217+
public static void Verify_Generic_AmbiguousMethodName()
218+
{
219+
Console.WriteLine($"Running {nameof(Verify_Generic_AmbiguousMethodName)}");
220+
221+
{
222+
AmbiguousMethodName a = new();
223+
AccessorsAmbiguousMethodName.CallM(a);
224+
AccessorsAmbiguousMethodName.CallM<int>(a);
225+
AccessorsAmbiguousMethodName.CallM<string>(a);
226+
AccessorsAmbiguousMethodName.CallM<Guid>(a);
227+
Assert.Throws<MissingMethodException>(() => AccessorsAmbiguousMethodName.CallN_MissingMethod<int>(a));
228+
}
229+
230+
{
231+
AccessorsAmbiguousMethodName.CallSM(null);
232+
AccessorsAmbiguousMethodName.CallSM<int>(null);
233+
AccessorsAmbiguousMethodName.CallSM<string>(null);
234+
AccessorsAmbiguousMethodName.CallSM<Guid>(null);
235+
Assert.Throws<MissingMethodException>(() => AccessorsAmbiguousMethodName.CallSN_MissingMethod<int>(null));
236+
}
237+
}
238+
184239
class Base
185240
{
186-
protected virtual string CreateMessageGeneric<T>(T t) => $"{nameof(Base)}:{t}";
241+
protected virtual string CreateMessage<T>(T t) => $"{nameof(Base)}<>:{t}";
187242
}
188243

189-
class GenericBase<T> : Base
244+
class GenericBase<U> : Base
190245
{
191-
protected virtual string CreateMessage(T t) => $"{nameof(GenericBase<T>)}:{t}";
192-
protected override string CreateMessageGeneric<U>(U u) => $"{nameof(GenericBase<T>)}:{u}";
246+
protected virtual string CreateMessage(U u) => $"{nameof(GenericBase<U>)}:{u}";
247+
protected override string CreateMessage<V>(V v) => $"{nameof(GenericBase<U>)}<>:{v}";
193248
}
194249

195250
sealed class Derived1 : GenericBase<string>
196251
{
197252
protected override string CreateMessage(string u) => $"{nameof(Derived1)}:{u}";
198-
protected override string CreateMessageGeneric<U>(U t) => $"{nameof(Derived1)}:{t}";
253+
protected override string CreateMessage<W>(W w) => $"{nameof(Derived1)}<>:{w}";
199254
}
200255

201256
sealed class Derived2 : GenericBase<string>
@@ -209,33 +264,33 @@ public static void Verify_Generic_InheritanceMethodResolution()
209264
Console.WriteLine($"Running {nameof(Verify_Generic_InheritanceMethodResolution)}");
210265
{
211266
Base a = new();
212-
Assert.Equal($"{nameof(Base)}:1", CreateMessage<int>(a, 1));
213-
Assert.Equal($"{nameof(Base)}:{expect}", CreateMessage<string>(a, expect));
214-
Assert.Equal($"{nameof(Base)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
267+
Assert.Equal($"{nameof(Base)}<>:1", CreateMessage<int>(a, 1));
268+
Assert.Equal($"{nameof(Base)}<>:{expect}", CreateMessage<string>(a, expect));
269+
Assert.Equal($"{nameof(Base)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
215270
}
216271
{
217272
GenericBase<int> a = new();
218-
Assert.Equal($"{nameof(GenericBase<int>)}:1", CreateMessage<int>(a, 1));
219-
Assert.Equal($"{nameof(GenericBase<int>)}:{expect}", CreateMessage<string>(a, expect));
220-
Assert.Equal($"{nameof(GenericBase<int>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
273+
Assert.Equal($"{nameof(GenericBase<int>)}<>:1", CreateMessage<int>(a, 1));
274+
Assert.Equal($"{nameof(GenericBase<int>)}<>:{expect}", CreateMessage<string>(a, expect));
275+
Assert.Equal($"{nameof(GenericBase<int>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
221276
}
222277
{
223278
GenericBase<string> a = new();
224-
Assert.Equal($"{nameof(GenericBase<string>)}:1", CreateMessage<int>(a, 1));
225-
Assert.Equal($"{nameof(GenericBase<string>)}:{expect}", CreateMessage<string>(a, expect));
226-
Assert.Equal($"{nameof(GenericBase<string>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
279+
Assert.Equal($"{nameof(GenericBase<string>)}<>:1", CreateMessage<int>(a, 1));
280+
Assert.Equal($"{nameof(GenericBase<string>)}<>:{expect}", CreateMessage<string>(a, expect));
281+
Assert.Equal($"{nameof(GenericBase<string>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
227282
}
228283
{
229284
GenericBase<Struct> a = new();
230-
Assert.Equal($"{nameof(GenericBase<Struct>)}:1", CreateMessage<int>(a, 1));
231-
Assert.Equal($"{nameof(GenericBase<Struct>)}:{expect}", CreateMessage<string>(a, expect));
232-
Assert.Equal($"{nameof(GenericBase<Struct>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
285+
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:1", CreateMessage<int>(a, 1));
286+
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:{expect}", CreateMessage<string>(a, expect));
287+
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
233288
}
234289
{
235290
Derived1 a = new();
236-
Assert.Equal($"{nameof(Derived1)}:1", CreateMessage<int>(a, 1));
237-
Assert.Equal($"{nameof(Derived1)}:{expect}", CreateMessage<string>(a, expect));
238-
Assert.Equal($"{nameof(Derived1)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
291+
Assert.Equal($"{nameof(Derived1)}<>:1", CreateMessage<int>(a, 1));
292+
Assert.Equal($"{nameof(Derived1)}<>:{expect}", CreateMessage<string>(a, expect));
293+
Assert.Equal($"{nameof(Derived1)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
239294
}
240295
{
241296
// Verify resolution of generic override logic.
@@ -245,7 +300,7 @@ public static void Verify_Generic_InheritanceMethodResolution()
245300
Assert.Equal($"{nameof(GenericBase<string>)}:{expect}", Accessors<string>.CreateMessage(a2, expect));
246301
}
247302

248-
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessageGeneric")]
303+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessage")]
249304
extern static string CreateMessage<W>(Base b, W w);
250305
}
251306

0 commit comments

Comments
 (0)