diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index b3d2d580cdf652..c1c492d1501106 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -710,7 +710,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbb, W("EnableRiscV64 #endif // Runtime-async -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_RuntimeAsync, W("RuntimeAsync"), 0, "Enables runtime async method support") +RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_RuntimeAsync, W("RuntimeAsync"), 1, "Enables runtime async method support") /// /// Uncategorized diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 2b8643e922cb49..50a5d17043642c 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -3301,6 +3301,23 @@ MethodTableBuilder::EnumerateClassMethods() } } + // Vararg methods are not allowed to be marked MethodImpl.Async + // and even when they return Tasks they are still treated as NormalMethod. + if (returnKind != MethodReturnKind::NormalMethod) + { + if (MetaSig::IsVarArg(Signature(pMemberSignature, cMemberSignature))) + { + if (IsMiAsync(dwImplFlags)) + { + BuildMethodTableThrowException(IDS_EE_VARARG_NOT_SUPPORTED); + } + else + { + returnKind = MethodReturnKind::NormalMethod; + } + } + } + // // Create a new bmtMDMethod representing this method and add it to the // declared method list. diff --git a/src/tests/async/Directory.Build.targets b/src/tests/async/Directory.Build.targets index 6804180057690e..f2d39cb6d975ff 100644 --- a/src/tests/async/Directory.Build.targets +++ b/src/tests/async/Directory.Build.targets @@ -9,10 +9,5 @@ true - - - true - - diff --git a/src/tests/async/varargs/varargs.cs b/src/tests/async/varargs/varargs.cs new file mode 100644 index 00000000000000..4301dc92709099 --- /dev/null +++ b/src/tests/async/varargs/varargs.cs @@ -0,0 +1,80 @@ +// 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.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +public class Async2Varargs +{ + [Fact] + public static void TestTaskDirectCall() + { + TaskWithArglist(42, __arglist(100, 200)).Wait(); + } + + [Fact] + public static void TestTaskAwait() + { + TestTaskAwaitAsync().Wait(); + } + + private static async Task TestTaskAwaitAsync() + { + await TaskWithArglist(42, __arglist(100, 200)); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Task TaskWithArglist(int fixedArg, __arglist) + { + Assert.Equal(42, fixedArg); + + ArgIterator args = new ArgIterator(__arglist); + Assert.Equal(2, args.GetRemainingCount()); + + int arg1 = __refvalue(args.GetNextArg(), int); + int arg2 = __refvalue(args.GetNextArg(), int); + + Assert.Equal(100, arg1); + Assert.Equal(200, arg2); + + return Task.CompletedTask; + } + + [Fact] + public static void TestValueTaskDirectCall() + { + int result = ValueTaskWithArglist(42, __arglist(100, 200)).Result; + Assert.Equal(342, result); + } + + [Fact] + public static void TestValueTaskAwait() + { + TestValueTaskAwaitAsync().Wait(); + } + + private static async Task TestValueTaskAwaitAsync() + { + int result = await ValueTaskWithArglist(42, __arglist(100, 200)); + Assert.Equal(342, result); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static ValueTask ValueTaskWithArglist(int fixedArg, __arglist) + { + Assert.Equal(42, fixedArg); + + ArgIterator args = new ArgIterator(__arglist); + Assert.Equal(2, args.GetRemainingCount()); + + int arg1 = __refvalue(args.GetNextArg(), int); + int arg2 = __refvalue(args.GetNextArg(), int); + + Assert.Equal(100, arg1); + Assert.Equal(200, arg2); + + return new ValueTask(fixedArg + arg1 + arg2); + } +} diff --git a/src/tests/async/varargs/varargs.csproj b/src/tests/async/varargs/varargs.csproj new file mode 100644 index 00000000000000..197767e2c4e249 --- /dev/null +++ b/src/tests/async/varargs/varargs.csproj @@ -0,0 +1,5 @@ + + + + +