diff --git a/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs b/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs
index e1e74632ef382..3c845a63b0060 100644
--- a/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs
+++ b/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs
@@ -4,6 +4,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.UseAutoProperty;
@@ -2999,4 +3000,62 @@ class Class
readonly ref int P => ref i;
}
""");
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77011")]
+ public Task TestRemoveThisIfPreferredCodeStyle()
+ => TestInRegularAndScriptAsync(
+ """
+ class C
+ {
+ [|private readonly string a;|]
+
+ public C(string a)
+ {
+ this.a = a;
+ }
+
+ public string A => a;
+ }
+ """,
+ """
+ class C
+ {
+ public C(string a)
+ {
+ A = a;
+ }
+
+ public string A { get; }
+ }
+ """,
+ options: Option(CodeStyleOptions2.QualifyPropertyAccess, false, NotificationOption2.Error));
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/77011")]
+ public Task TestKeepThisIfPreferredCodeStyle()
+ => TestInRegularAndScriptAsync(
+ """
+ class C
+ {
+ [|private readonly string a;|]
+
+ public C(string a)
+ {
+ this.a = a;
+ }
+
+ public string A => a;
+ }
+ """,
+ """
+ class C
+ {
+ public C(string a)
+ {
+ this.A = a;
+ }
+
+ public string A { get; }
+ }
+ """,
+ options: Option(CodeStyleOptions2.QualifyPropertyAccess, true, NotificationOption2.Error));
}
diff --git a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator_RefSafety.cs b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator_RefSafety.cs
new file mode 100644
index 0000000000000..07ea26d9bc8f0
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator_RefSafety.cs
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis.CSharp.Symbols;
+
+namespace Microsoft.CodeAnalysis.CSharp.CodeGen;
+
+internal partial class CodeGenerator
+{
+ ///
+ private static bool MightEscapeTemporaryRefs(BoundCall node, bool used)
+ {
+ return MightEscapeTemporaryRefs(
+ used: used,
+ returnType: node.Type,
+ returnRefKind: node.Method.RefKind,
+ thisParameterSymbol: node.Method.TryGetThisParameter(out var thisParameter) ? thisParameter : null,
+ parameters: node.Method.Parameters);
+ }
+
+ ///
+ private static bool MightEscapeTemporaryRefs(BoundObjectCreationExpression node, bool used)
+ {
+ return MightEscapeTemporaryRefs(
+ used: used,
+ returnType: node.Type,
+ returnRefKind: RefKind.None,
+ thisParameterSymbol: null,
+ parameters: node.Constructor.Parameters);
+ }
+
+ ///
+ private static bool MightEscapeTemporaryRefs(BoundFunctionPointerInvocation node, bool used)
+ {
+ FunctionPointerMethodSymbol method = node.FunctionPointer.Signature;
+ return MightEscapeTemporaryRefs(
+ used: used,
+ returnType: node.Type,
+ returnRefKind: method.RefKind,
+ thisParameterSymbol: null,
+ parameters: method.Parameters);
+ }
+
+ ///
+ /// Determines whether a 'ref' can be captured by the call (considering only its signature).
+ ///
+ ///
+ ///
+ /// The emit layer consults this to avoid reusing temporaries that are passed by ref to such methods.
+ ///
+ ///
+ /// This is a heuristic which might have false positives, i.e.,
+ /// it might not recognize that a call cannot capture a 'ref'
+ /// even if the binding-time ref safety analysis would recognize that.
+ /// That is fine, the IL will be correct, albeit less optimal (it might use more temps).
+ /// But we still want some heuristic to avoid regressing IL of common safe cases.
+ ///
+ ///
+ private static bool MightEscapeTemporaryRefs(
+ bool used,
+ TypeSymbol returnType,
+ RefKind returnRefKind,
+ ParameterSymbol? thisParameterSymbol,
+ ImmutableArray parameters)
+ {
+ // whether we have any outputs that can capture `ref`s
+ bool anyRefTargets = false;
+ // whether we have any inputs that can contain `ref`s
+ bool anyRefSources = false;
+
+ if (used && (returnRefKind != RefKind.None || returnType.IsRefLikeOrAllowsRefLikeType()))
+ {
+ // If returning by ref or returning a ref struct, the result might capture `ref`s.
+ anyRefTargets = true;
+ }
+
+ if (thisParameterSymbol is not null && processParameter(thisParameterSymbol, anyRefSources: ref anyRefSources, anyRefTargets: ref anyRefTargets))
+ {
+ return true;
+ }
+
+ foreach (var parameter in parameters)
+ {
+ if (processParameter(parameter, anyRefSources: ref anyRefSources, anyRefTargets: ref anyRefTargets))
+ {
+ return true;
+ }
+ }
+
+ return false;
+
+ // Returns true if we can return 'true' early.
+ static bool processParameter(ParameterSymbol parameter, ref bool anyRefSources, ref bool anyRefTargets)
+ {
+ if (parameter.Type.IsRefLikeOrAllowsRefLikeType() && parameter.EffectiveScope != ScopedKind.ScopedValue)
+ {
+ anyRefSources = true;
+ if (parameter.RefKind.IsWritableReference())
+ {
+ anyRefTargets = true;
+ }
+ }
+ else if (parameter.RefKind != RefKind.None && parameter.EffectiveScope == ScopedKind.None)
+ {
+ anyRefSources = true;
+ }
+
+ // If there is at least one output and at least one input, a `ref` can be captured.
+ return anyRefTargets && anyRefSources;
+ }
+ }
+}
diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
index 86b3e463535e1..127509552c312 100644
--- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
+++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
@@ -1660,7 +1660,13 @@ private void EmitStaticCallExpression(BoundCall call, UseKind useKind)
Debug.Assert(method.IsStatic);
+ var countBefore = _builder.LocalSlotManager.StartScopeOfTrackingAddressedLocals();
+
EmitArguments(arguments, method.Parameters, call.ArgumentRefKindsOpt);
+
+ _builder.LocalSlotManager.EndScopeOfTrackingAddressedLocals(countBefore,
+ MightEscapeTemporaryRefs(call, used: useKind != UseKind.Unused));
+
int stackBehavior = GetCallStackBehavior(method, arguments);
if (method.IsAbstract || method.IsVirtual)
@@ -1690,6 +1696,8 @@ private void EmitInstanceCallExpression(BoundCall call, UseKind useKind)
bool box;
LocalDefinition tempOpt;
+ var countBefore = _builder.LocalSlotManager.StartScopeOfTrackingAddressedLocals();
+
if (receiverIsInstanceCall(call, out BoundCall nested))
{
var calls = ArrayBuilder.GetInstance();
@@ -1755,6 +1763,11 @@ private void EmitInstanceCallExpression(BoundCall call, UseKind useKind)
}
emitArgumentsAndCallEpilogue(call, callKind, receiverUseKind);
+
+ _builder.LocalSlotManager.EndScopeOfTrackingAddressedLocals(countBefore, MightEscapeTemporaryRefs(call, used: true));
+
+ countBefore = _builder.LocalSlotManager.StartScopeOfTrackingAddressedLocals();
+
FreeOptTemp(tempOpt);
tempOpt = null;
@@ -1815,6 +1828,9 @@ private void EmitInstanceCallExpression(BoundCall call, UseKind useKind)
}
emitArgumentsAndCallEpilogue(call, callKind, useKind);
+
+ _builder.LocalSlotManager.EndScopeOfTrackingAddressedLocals(countBefore, MightEscapeTemporaryRefs(call, used: useKind != UseKind.Unused));
+
FreeOptTemp(tempOpt);
return;
@@ -2446,8 +2462,14 @@ private void EmitObjectCreationExpression(BoundObjectCreationExpression expressi
}
// none of the above cases, so just create an instance
+
+ var countBefore = _builder.LocalSlotManager.StartScopeOfTrackingAddressedLocals();
+
EmitArguments(expression.Arguments, constructor.Parameters, expression.ArgumentRefKindsOpt);
+ _builder.LocalSlotManager.EndScopeOfTrackingAddressedLocals(countBefore,
+ MightEscapeTemporaryRefs(expression, used));
+
var stackAdjustment = GetObjCreationStackBehavior(expression);
_builder.EmitOpCode(ILOpCode.Newobj, stackAdjustment);
@@ -2572,8 +2594,7 @@ private void EmitAssignmentExpression(BoundAssignmentOperator assignmentOperator
private bool TryEmitAssignmentInPlace(BoundAssignmentOperator assignmentOperator, bool used)
{
// If the left hand is itself a ref, then we can't use in-place assignment
- // because we need to spill the creation. This code can't be written in C#, but
- // can be produced by lowering.
+ // because we need to spill the creation.
if (assignmentOperator.IsRef)
{
return false;
@@ -2704,7 +2725,14 @@ private bool TryInPlaceCtorCall(BoundExpression target, BoundObjectCreationExpre
Debug.Assert(temp == null, "in-place ctor target should not create temps");
var constructor = objCreation.Constructor;
+
+ var countBefore = _builder.LocalSlotManager.StartScopeOfTrackingAddressedLocals();
+
EmitArguments(objCreation.Arguments, constructor.Parameters, objCreation.ArgumentRefKindsOpt);
+
+ _builder.LocalSlotManager.EndScopeOfTrackingAddressedLocals(countBefore,
+ MightEscapeTemporaryRefs(objCreation, used));
+
// -2 to adjust for consumed target address and not produced value.
var stackAdjustment = GetObjCreationStackBehavior(objCreation) - 2;
_builder.EmitOpCode(ILOpCode.Call, stackAdjustment);
@@ -4026,7 +4054,14 @@ private void EmitCalli(BoundFunctionPointerInvocation ptrInvocation, UseKind use
}
FunctionPointerMethodSymbol method = ptrInvocation.FunctionPointer.Signature;
+
+ var countBefore = _builder.LocalSlotManager.StartScopeOfTrackingAddressedLocals();
+
EmitArguments(ptrInvocation.Arguments, method.Parameters, ptrInvocation.ArgumentRefKindsOpt);
+
+ _builder.LocalSlotManager.EndScopeOfTrackingAddressedLocals(countBefore,
+ MightEscapeTemporaryRefs(ptrInvocation, used: useKind != UseKind.Unused));
+
var stackBehavior = GetCallStackBehavior(ptrInvocation.FunctionPointer.Signature, ptrInvocation.Arguments);
if (temp is object)
diff --git a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
index 365cd44a08702..b3af222698d72 100644
--- a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
+++ b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
@@ -991,13 +991,23 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
// Special Case: If the RHS is a pointer conversion, then the assignment functions as
// a conversion (because the RHS will actually be typed as a native u/int in IL), so
// we should not optimize away the local (i.e. schedule it on the stack).
- if (CanScheduleToStack(localSymbol) &&
+ else if (CanScheduleToStack(localSymbol) &&
assignmentLocal.Type.IsPointerOrFunctionPointer() && right.Kind == BoundKind.Conversion &&
((BoundConversion)right).ConversionKind.IsPointerConversion())
{
ShouldNotSchedule(localSymbol);
}
+ // If this is a pointer-to-ref assignment, keep the local so GC knows to re-track it.
+ // We don't need to do this for implicitly synthesized locals because working with pointers in an unsafe context does not guarantee any GC tracking,
+ // but when a pointer is converted to a user-defined ref local, it becomes a use of a "safe" feature where we should guarantee the ref is tracked by GC.
+ else if (localSymbol.RefKind != RefKind.None &&
+ localSymbol.SynthesizedKind == SynthesizedLocalKind.UserDefined &&
+ right.Kind == BoundKind.PointerIndirectionOperator)
+ {
+ ShouldNotSchedule(localSymbol);
+ }
+
RecordVarWrite(localSymbol);
assignmentLocal = null;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs
index b3359712b498d..87cd14d63032f 100644
--- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs
@@ -368,6 +368,20 @@ public override ImmutableArray Parameters
}
}
+ internal override bool TryGetThisParameter(out ParameterSymbol? thisParameter)
+ {
+ if (UnderlyingMethod.TryGetThisParameter(out ParameterSymbol? underlyingThisParameter))
+ {
+ thisParameter = underlyingThisParameter != null
+ ? new ThisParameterSymbol(this, _container)
+ : null;
+ return true;
+ }
+
+ thisParameter = null;
+ return false;
+ }
+
public override ImmutableArray ExplicitInterfaceImplementations => ImmutableArray.Empty;
public override ImmutableArray RefCustomModifiers => UnderlyingMethod.RefCustomModifiers;
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs
index 1f87e26e45231..b34b097c130ad 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs
@@ -861,7 +861,8 @@ static ref readonly int M(in int x)
// Code size 72 (0x48)
.maxstack 3
.locals init (int V_0,
- int V_1)
+ int V_1,
+ int V_2)
IL_0000: ldc.i4.s 42
IL_0002: stloc.0
IL_0003: ldloca.s V_0
@@ -870,22 +871,22 @@ .locals init (int V_0,
IL_000b: call ""void System.Console.WriteLine(int)""
IL_0010: newobj ""Program..ctor()""
IL_0015: ldc.i4.5
- IL_0016: stloc.0
- IL_0017: ldloca.s V_0
+ IL_0016: stloc.1
+ IL_0017: ldloca.s V_1
IL_0019: ldc.i4.6
- IL_001a: stloc.1
- IL_001b: ldloca.s V_1
+ IL_001a: stloc.2
+ IL_001b: ldloca.s V_2
IL_001d: call ""int Program.this[in int, in int].get""
IL_0022: call ""void System.Console.WriteLine(int)""
IL_0027: ldc.i4.s 42
- IL_0029: stloc.0
- IL_002a: ldloca.s V_0
+ IL_0029: stloc.1
+ IL_002a: ldloca.s V_1
IL_002c: call ""ref readonly int Program.M(in int)""
IL_0031: ldind.i4
IL_0032: call ""void System.Console.WriteLine(int)""
IL_0037: ldc.i4.s 42
- IL_0039: stloc.0
- IL_003a: ldloca.s V_0
+ IL_0039: stloc.2
+ IL_003a: ldloca.s V_2
IL_003c: call ""ref readonly int Program.M(in int)""
IL_0041: ldind.i4
IL_0042: call ""void System.Console.WriteLine(int)""
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs
index 5e6809f136b60..989fda6428452 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs
@@ -95,31 +95,40 @@ unsafe static void Main()
11");
verifier.VerifyIL("C.Main", @"
{
- // Code size 34 (0x22)
+ // Code size 43 (0x2b)
.maxstack 2
.locals init (int V_0, //x
int V_1, //y
- pinned int& V_2)
+ int& V_2, //rx
+ pinned int& V_3)
IL_0000: ldc.i4.5
IL_0001: stloc.0
IL_0002: ldc.i4.s 11
IL_0004: stloc.1
- IL_0005: ldloca.s V_1
+ IL_0005: ldloca.s V_0
IL_0007: stloc.2
- IL_0008: ldloc.2
- IL_0009: conv.u
+ IL_0008: ldloca.s V_1
IL_000a: dup
- IL_000b: ldind.i4
- IL_000c: call ""void System.Console.WriteLine(int)""
- IL_0011: dup
- IL_0012: ldind.i4
- IL_0013: call ""void System.Console.WriteLine(int)""
- IL_0018: ldind.i4
- IL_0019: call ""void System.Console.WriteLine(int)""
- IL_001e: ldc.i4.0
- IL_001f: conv.u
- IL_0020: stloc.2
- IL_0021: ret
+ IL_000b: stloc.2
+ IL_000c: stloc.3
+ IL_000d: ldloc.3
+ IL_000e: conv.u
+ IL_000f: dup
+ IL_0010: ldind.i4
+ IL_0011: call ""void System.Console.WriteLine(int)""
+ IL_0016: dup
+ IL_0017: stloc.2
+ IL_0018: ldloc.2
+ IL_0019: ldind.i4
+ IL_001a: call ""void System.Console.WriteLine(int)""
+ IL_001f: stloc.2
+ IL_0020: ldloc.2
+ IL_0021: ldind.i4
+ IL_0022: call ""void System.Console.WriteLine(int)""
+ IL_0027: ldc.i4.0
+ IL_0028: conv.u
+ IL_0029: stloc.3
+ IL_002a: ret
}");
}
@@ -4204,13 +4213,14 @@ public void TestRefOnPointerIndirection_01()
}
";
- verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
+ verify(TestOptions.UnsafeReleaseExe, Verification.Fails, @"
{
// Code size 14 (0xe)
.maxstack 1
+ .locals init (int& V_0) //x
IL_0000: ldc.i4.0
IL_0001: conv.i
- IL_0002: pop
+ IL_0002: stloc.0
IL_0003: ldstr ""run""
IL_0008: call ""void System.Console.WriteLine(string)""
IL_000d: ret
@@ -4275,14 +4285,17 @@ .maxstack 1
verify(TestOptions.UnsafeReleaseExe, @"
{
- // Code size 14 (0xe)
+ // Code size 16 (0x10)
.maxstack 1
+ .locals init (int& V_0) //x
IL_0000: ldc.i4.0
IL_0001: conv.i
- IL_0002: call ""void* Unsafe.AsPointer(ref int)""
- IL_0007: conv.i4
- IL_0008: call ""void System.Console.WriteLine(int)""
- IL_000d: ret
+ IL_0002: stloc.0
+ IL_0003: ldloc.0
+ IL_0004: call ""void* Unsafe.AsPointer(ref int)""
+ IL_0009: conv.i4
+ IL_000a: call ""void System.Console.WriteLine(int)""
+ IL_000f: ret
}
");
@@ -4329,19 +4342,22 @@ public void TestRefOnPointerIndirection_03()
}
";
- verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
+ verify(TestOptions.UnsafeReleaseExe, Verification.Fails, @"
{
- // Code size 16 (0x10)
+ // Code size 19 (0x13)
.maxstack 1
- .locals init (int V_0) //i1
+ .locals init (int V_0, //i1
+ int& V_1) //i2
IL_0000: ldc.i4.0
IL_0001: stloc.0
- IL_0002: ldc.i4.0
- IL_0003: conv.i
- IL_0004: pop
- IL_0005: ldstr ""run""
- IL_000a: call ""void System.Console.WriteLine(string)""
- IL_000f: ret
+ IL_0002: ldloca.s V_0
+ IL_0004: stloc.1
+ IL_0005: ldc.i4.0
+ IL_0006: conv.i
+ IL_0007: stloc.1
+ IL_0008: ldstr ""run""
+ IL_000d: call ""void System.Console.WriteLine(string)""
+ IL_0012: ret
}
");
@@ -4392,13 +4408,14 @@ public void TestRefOnPointerArrayAccess_01()
}
";
- verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
+ verify(TestOptions.UnsafeReleaseExe, Verification.Fails, @"
{
// Code size 14 (0xe)
.maxstack 1
+ .locals init (int& V_0) //x
IL_0000: ldc.i4.0
IL_0001: conv.i
- IL_0002: pop
+ IL_0002: stloc.0
IL_0003: ldstr ""run""
IL_0008: call ""void System.Console.WriteLine(string)""
IL_000d: ret
@@ -4444,15 +4461,16 @@ public void TestRefOnPointerArrayAccess_02()
}
";
- verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
+ verify(TestOptions.UnsafeReleaseExe, Verification.Fails, @"
{
// Code size 16 (0x10)
.maxstack 2
+ .locals init (int& V_0) //x
IL_0000: ldc.i4.0
IL_0001: conv.i
IL_0002: ldc.i4.4
IL_0003: add
- IL_0004: pop
+ IL_0004: stloc.0
IL_0005: ldstr ""run""
IL_000a: call ""void System.Console.WriteLine(string)""
IL_000f: ret
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs
index 6f709ef6d664d..a6896e2bf31c9 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs
@@ -176,9 +176,10 @@ unsafe static void Main()
CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "12", verify: Verification.Passes)
.VerifyIL("Program.Main", @"
{
- // Code size 52 (0x34)
+ // Code size 54 (0x36)
.maxstack 2
- .locals init (S1 V_0) //c
+ .locals init (S1 V_0, //c
+ int& V_1) //i
IL_0000: ldloca.s V_0
IL_0002: initobj ""S1""
IL_0008: ldloca.s V_0
@@ -191,9 +192,11 @@ .locals init (S1 V_0) //c
IL_001e: ldflda ""S S1.field""
IL_0023: ldflda ""int* S.x""
IL_0028: ldflda ""int S.e__FixedBuffer.FixedElementField""
- IL_002d: ldind.i4
- IL_002e: call ""void System.Console.WriteLine(int)""
- IL_0033: ret
+ IL_002d: stloc.1
+ IL_002e: ldloc.1
+ IL_002f: ldind.i4
+ IL_0030: call ""void System.Console.WriteLine(int)""
+ IL_0035: ret
}");
}
@@ -227,8 +230,9 @@ unsafe static void Main()
CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "12", verify: Verification.Passes)
.VerifyIL("Program.Main", @"
{
- // Code size 46 (0x2e)
+ // Code size 48 (0x30)
.maxstack 3
+ .locals init (int& V_0) //i
IL_0000: newobj ""C1..ctor()""
IL_0005: dup
IL_0006: ldflda ""S C1.field""
@@ -239,9 +243,11 @@ .maxstack 3
IL_0018: ldflda ""S C1.field""
IL_001d: ldflda ""int* S.x""
IL_0022: ldflda ""int S.e__FixedBuffer.FixedElementField""
- IL_0027: ldind.i4
- IL_0028: call ""void System.Console.WriteLine(int)""
- IL_002d: ret
+ IL_0027: stloc.0
+ IL_0028: ldloc.0
+ IL_0029: ldind.i4
+ IL_002a: call ""void System.Console.WriteLine(int)""
+ IL_002f: ret
}");
}
@@ -278,8 +284,9 @@ unsafe static void Main()
CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "12", verify: Verification.Passes)
.VerifyIL("Program.Main", @"
{
- // Code size 58 (0x3a)
+ // Code size 60 (0x3c)
.maxstack 3
+ .locals init (int& V_0) //i
IL_0000: newobj ""C1..ctor()""
IL_0005: dup
IL_0006: ldflda ""S C1.field""
@@ -293,9 +300,11 @@ .maxstack 3
IL_0024: ldflda ""S C1.field""
IL_0029: ldflda ""int* S.x""
IL_002e: ldflda ""int S.e__FixedBuffer.FixedElementField""
- IL_0033: ldind.i4
- IL_0034: call ""void System.Console.WriteLine(int)""
- IL_0039: ret
+ IL_0033: stloc.0
+ IL_0034: ldloc.0
+ IL_0035: ldind.i4
+ IL_0036: call ""void System.Console.WriteLine(int)""
+ IL_003b: ret
}");
}
@@ -439,16 +448,17 @@ unsafe static void Main()
CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "12", verify: Verification.Fails)
.VerifyIL("Program.Main", @"
{
- // Code size 62 (0x3e)
+ // Code size 64 (0x40)
.maxstack 4
- .locals init (pinned int& V_0)
+ .locals init (int& V_0, //i
+ pinned int& V_1)
IL_0000: newobj ""S1..ctor()""
IL_0005: dup
IL_0006: ldflda ""S S1.field""
IL_000b: ldflda ""int* S.x""
IL_0010: ldflda ""int S.e__FixedBuffer.FixedElementField""
- IL_0015: stloc.0
- IL_0016: ldloc.0
+ IL_0015: stloc.1
+ IL_0016: ldloc.1
IL_0017: conv.u
IL_0018: ldc.i4.3
IL_0019: conv.i
@@ -459,7 +469,7 @@ .locals init (pinned int& V_0)
IL_001f: stind.i4
IL_0020: ldc.i4.0
IL_0021: conv.u
- IL_0022: stloc.0
+ IL_0022: stloc.1
IL_0023: ldflda ""S S1.field""
IL_0028: ldflda ""int* S.x""
IL_002d: ldflda ""int S.e__FixedBuffer.FixedElementField""
@@ -468,9 +478,11 @@ .locals init (pinned int& V_0)
IL_0034: ldc.i4.4
IL_0035: mul
IL_0036: add
- IL_0037: ldind.i4
- IL_0038: call ""void System.Console.WriteLine(int)""
- IL_003d: ret
+ IL_0037: stloc.0
+ IL_0038: ldloc.0
+ IL_0039: ldind.i4
+ IL_003a: call ""void System.Console.WriteLine(int)""
+ IL_003f: ret
}");
}
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs
index d36e398902681..ac044fc67d7a4 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs
@@ -668,6 +668,282 @@ .locals init (S V_0) //s
");
}
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79051")]
+ public void Retrack_PointerToRefLocal()
+ {
+ // When converting from a pointer to a ref, we must avoid eliding the ref local in IL, so the GC knows to track the ref.
+ var source = """
+ class C
+ {
+ unsafe void M(byte* p)
+ {
+ ref byte b = ref *p;
+ b.ToString();
+ }
+ }
+ """;
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeDebugDll).VerifyIL("C.M", """
+ {
+ // Code size 11 (0xb)
+ .maxstack 1
+ .locals init (byte& V_0) //b
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: stloc.0
+ IL_0003: ldloc.0
+ IL_0004: call "string byte.ToString()"
+ IL_0009: pop
+ IL_000a: ret
+ }
+ """);
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.M", """
+ {
+ // Code size 10 (0xa)
+ .maxstack 1
+ .locals init (byte& V_0) //b
+ IL_0000: ldarg.1
+ IL_0001: stloc.0
+ IL_0002: ldloc.0
+ IL_0003: call "string byte.ToString()"
+ IL_0008: pop
+ IL_0009: ret
+ }
+ """);
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79051")]
+ public void Retrack_PointerToRefLocal_Nested()
+ {
+ var source = """
+ class C
+ {
+ unsafe void M(ref byte b1, byte* p)
+ {
+ ref byte local = ref b1;
+ {
+ ref byte b2 = ref *p;
+ local = ref b2;
+ }
+ local.ToString();
+ }
+ }
+ """;
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeDebugDll).VerifyIL("C.M", """
+ {
+ // Code size 17 (0x11)
+ .maxstack 1
+ .locals init (byte& V_0, //local
+ byte& V_1) //b2
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: stloc.0
+ IL_0003: nop
+ IL_0004: ldarg.2
+ IL_0005: stloc.1
+ IL_0006: ldloc.1
+ IL_0007: stloc.0
+ IL_0008: nop
+ IL_0009: ldloc.0
+ IL_000a: call "string byte.ToString()"
+ IL_000f: pop
+ IL_0010: ret
+ }
+ """);
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.M", """
+ {
+ // Code size 10 (0xa)
+ .maxstack 1
+ .locals init (byte& V_0) //b2
+ IL_0000: ldarg.2
+ IL_0001: stloc.0
+ IL_0002: ldloc.0
+ IL_0003: call "string byte.ToString()"
+ IL_0008: pop
+ IL_0009: ret
+ }
+ """);
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79051")]
+ public void Retrack_PointerToRefLocal_Arg()
+ {
+ var source = """
+ class C
+ {
+ unsafe void M1(byte* p)
+ {
+ ref byte b = ref M2(ref *p);
+ b.ToString();
+ }
+ ref byte M2(ref byte b) => ref b;
+ }
+ """;
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeDebugDll).VerifyIL("C.M1", """
+ {
+ // Code size 17 (0x11)
+ .maxstack 2
+ .locals init (byte& V_0) //b
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: ldarg.1
+ IL_0003: call "ref byte C.M2(ref byte)"
+ IL_0008: stloc.0
+ IL_0009: ldloc.0
+ IL_000a: call "string byte.ToString()"
+ IL_000f: pop
+ IL_0010: ret
+ }
+ """);
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.M1", """
+ {
+ // Code size 14 (0xe)
+ .maxstack 2
+ IL_0000: ldarg.0
+ IL_0001: ldarg.1
+ IL_0002: call "ref byte C.M2(ref byte)"
+ IL_0007: call "string byte.ToString()"
+ IL_000c: pop
+ IL_000d: ret
+ }
+ """);
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79051")]
+ public void Retrack_PointerToRefLocal_Arg_EvaluationOrder()
+ {
+ // Perhaps the pointer-to-ref conversion should be preserved in the IL (via a ref local)
+ // so GC can re-track it before evaulating other arguments (which can have side effects),
+ // but there is no ref local in the C# source, so the current behavior might be expected.
+ var source = """
+ class C
+ {
+ unsafe void M1(byte* p)
+ {
+ ref byte b = ref M2(ref *p, M3());
+ b.ToString();
+ }
+ ref byte M2(ref byte b, int i) => ref b;
+ int M3() => 42;
+ }
+ """;
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeDebugDll).VerifyIL("C.M1", """
+ {
+ // Code size 23 (0x17)
+ .maxstack 3
+ .locals init (byte& V_0) //b
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: ldarg.1
+ IL_0003: ldarg.0
+ IL_0004: call "int C.M3()"
+ IL_0009: call "ref byte C.M2(ref byte, int)"
+ IL_000e: stloc.0
+ IL_000f: ldloc.0
+ IL_0010: call "string byte.ToString()"
+ IL_0015: pop
+ IL_0016: ret
+ }
+ """);
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.M1", """
+ {
+ // Code size 20 (0x14)
+ .maxstack 3
+ IL_0000: ldarg.0
+ IL_0001: ldarg.1
+ IL_0002: ldarg.0
+ IL_0003: call "int C.M3()"
+ IL_0008: call "ref byte C.M2(ref byte, int)"
+ IL_000d: call "string byte.ToString()"
+ IL_0012: pop
+ IL_0013: ret
+ }
+ """);
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79051")]
+ public void Retrack_PointerToRefLocal_Synthesized()
+ {
+ // Implicit (synthesized) ref locals can be elided.
+ var source = """
+ class C
+ {
+ unsafe void M(byte* p)
+ {
+ (*p)++;
+ }
+ }
+ """;
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeDebugDll).VerifyIL("C.M", """
+ {
+ // Code size 9 (0x9)
+ .maxstack 3
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: dup
+ IL_0003: ldind.u1
+ IL_0004: ldc.i4.1
+ IL_0005: add
+ IL_0006: conv.u1
+ IL_0007: stind.i1
+ IL_0008: ret
+ }
+ """);
+ CompileAndVerify(source, verify: Verification.Fails, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.M", """
+ {
+ // Code size 8 (0x8)
+ .maxstack 3
+ IL_0000: ldarg.1
+ IL_0001: dup
+ IL_0002: ldind.u1
+ IL_0003: ldc.i4.1
+ IL_0004: add
+ IL_0005: conv.u1
+ IL_0006: stind.i1
+ IL_0007: ret
+ }
+ """);
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79051")]
+ public void Retrack_RefLocalToRefLocal()
+ {
+ // There is no pointer-to-ref conversion, so the ref local b2 can be elided in Release mode.
+ var source = """
+ class C
+ {
+ void M(ref byte b1)
+ {
+ ref byte b2 = ref b1;
+ b2.ToString();
+ }
+ }
+ """;
+ CompileAndVerify(source, options: TestOptions.DebugDll).VerifyIL("C.M", """
+ {
+ // Code size 11 (0xb)
+ .maxstack 1
+ .locals init (byte& V_0) //b2
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: stloc.0
+ IL_0003: ldloc.0
+ IL_0004: call "string byte.ToString()"
+ IL_0009: pop
+ IL_000a: ret
+ }
+ """);
+ CompileAndVerify(source, options: TestOptions.ReleaseDll).VerifyIL("C.M", """
+ {
+ // Code size 8 (0x8)
+ .maxstack 1
+ IL_0000: ldarg.1
+ IL_0001: call "string byte.ToString()"
+ IL_0006: pop
+ IL_0007: ret
+ }
+ """);
+ }
+
#endregion Dereference tests
#region Pointer member access tests
diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs
index 292b8336a9ee2..41b3ab5677a5b 100644
--- a/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs
+++ b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs
@@ -9525,7 +9525,8 @@ .locals init (System.ReadOnlySpan V_0, //y
System.ReadOnlySpan V_3,
int V_4,
int[] V_5,
- System.Span V_6)
+ System.Span V_6,
+ System.Span V_7)
IL_0000: ldtoken ".__StaticArrayInitTypeSize=8_Align=4 .34FB5C825DE7CA4AEA6E712F19D439C1DA0C92C37B423936C5F618545CA4FA1F4"
IL_0005: call "System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"
IL_000a: stloc.0
@@ -9561,8 +9562,8 @@ .locals init (System.ReadOnlySpan V_0, //y
IL_0056: ldloca.s V_3
IL_0058: ldloc.s V_5
IL_005a: newobj "System.Span..ctor(int[])"
- IL_005f: stloc.s V_6
- IL_0061: ldloca.s V_6
+ IL_005f: stloc.s V_7
+ IL_0061: ldloca.s V_7
IL_0063: ldloc.s V_4
IL_0065: ldloca.s V_3
IL_0067: call "int System.ReadOnlySpan.Length.get"
@@ -11541,7 +11542,8 @@ .locals init (System.Collections.Generic.List V_0,
T[] V_2,
System.Span V_3,
System.Span V_4,
- System.Span V_5)
+ System.Span V_5,
+ System.Span V_6)
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stloc.0
@@ -11577,8 +11579,8 @@ .locals init (System.Collections.Generic.List V_0,
IL_004e: ldloca.s V_4
IL_0050: ldloc.2
IL_0051: newobj "System.Span..ctor(T[])"
- IL_0056: stloc.s V_5
- IL_0058: ldloca.s V_5
+ IL_0056: stloc.s V_6
+ IL_0058: ldloca.s V_6
IL_005a: ldloc.1
IL_005b: ldloca.s V_4
IL_005d: call "int System.Span.Length.get"
@@ -11645,7 +11647,8 @@ .locals init (int[] V_0,
int V_10,
int V_11,
int V_12,
- int V_13)
+ int V_13,
+ System.Span V_14)
IL_0000: ldstr "A"
IL_0005: ldc.i4.2
IL_0006: newarr "int"
@@ -11762,8 +11765,8 @@ .locals init (int[] V_0,
IL_0105: ldloca.s V_6
IL_0107: ldloc.s V_4
IL_0109: newobj "System.Span..ctor(int[])"
- IL_010e: stloc.s V_7
- IL_0110: ldloca.s V_7
+ IL_010e: stloc.s V_14
+ IL_0110: ldloca.s V_14
IL_0112: ldloc.3
IL_0113: ldloca.s V_6
IL_0115: call "int System.Span.Length.get"
@@ -33712,7 +33715,8 @@ .locals init (System.ReadOnlySpan V_0, //li1
System.ReadOnlySpan V_3,
int V_4,
int[] V_5,
- System.Span V_6)
+ System.Span V_6,
+ System.Span V_7)
IL_0000: ldtoken ".__StaticArrayInitTypeSize=12_Align=4 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4"
IL_0005: call "System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"
IL_000a: stloc.0
@@ -33754,8 +33758,8 @@ .locals init (System.ReadOnlySpan V_0, //li1
IL_006d: ldloca.s V_3
IL_006f: ldloc.s V_5
IL_0071: newobj "System.Span..ctor(int[])"
- IL_0076: stloc.s V_6
- IL_0078: ldloca.s V_6
+ IL_0076: stloc.s V_7
+ IL_0078: ldloca.s V_7
IL_007a: ldloc.s V_4
IL_007c: ldloca.s V_3
IL_007e: call "int System.ReadOnlySpan.Length.get"
@@ -33811,7 +33815,8 @@ .locals init (System.ReadOnlySpan V_0, //li1
C[] V_6,
System.ReadOnlySpan.Enumerator V_7,
D V_8,
- System.ReadOnlySpan V_9)
+ System.ReadOnlySpan.Enumerator V_9,
+ System.ReadOnlySpan V_10)
IL_0000: newobj "D..ctor()"
IL_0005: stloc.1
IL_0006: ldloca.s V_1
@@ -33854,9 +33859,9 @@ .locals init (System.ReadOnlySpan V_0, //li1
IL_0061: brtrue.s IL_0043
IL_0063: ldloca.s V_4
IL_0065: call "System.ReadOnlySpan.Enumerator System.ReadOnlySpan.GetEnumerator()"
- IL_006a: stloc.s V_7
+ IL_006a: stloc.s V_9
IL_006c: br.s IL_0085
- IL_006e: ldloca.s V_7
+ IL_006e: ldloca.s V_9
IL_0070: call "ref readonly D System.ReadOnlySpan.Enumerator.Current.get"
IL_0075: ldind.ref
IL_0076: stloc.s V_8
@@ -33868,13 +33873,13 @@ .locals init (System.ReadOnlySpan V_0, //li1
IL_0081: ldc.i4.1
IL_0082: add
IL_0083: stloc.s V_5
- IL_0085: ldloca.s V_7
+ IL_0085: ldloca.s V_9
IL_0087: call "bool System.ReadOnlySpan.Enumerator.MoveNext()"
IL_008c: brtrue.s IL_006e
IL_008e: ldloc.s V_6
IL_0090: call "System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(C[])"
- IL_0095: stloc.s V_9
- IL_0097: ldloca.s V_9
+ IL_0095: stloc.s V_10
+ IL_0097: ldloca.s V_10
IL_0099: call "void CollectionExtensions.Report(in System.ReadOnlySpan)"
IL_009e: ret
}
@@ -34231,7 +34236,8 @@ .locals init (Base[] V_0,
int V_3,
Base[] V_4,
System.ReadOnlySpan V_5,
- System.Span V_6)
+ System.Span V_6,
+ System.Span V_7)
IL_0000: ldc.i4.1
IL_0001: newarr "Derived"
IL_0006: dup
@@ -34283,8 +34289,8 @@ .locals init (Base[] V_0,
IL_006a: ldloca.s V_5
IL_006c: ldloc.s V_4
IL_006e: newobj "System.Span..ctor(Base[])"
- IL_0073: stloc.s V_6
- IL_0075: ldloca.s V_6
+ IL_0073: stloc.s V_7
+ IL_0075: ldloca.s V_7
IL_0077: ldloc.3
IL_0078: ldloca.s V_5
IL_007a: call "int System.ReadOnlySpan.Length.get"
@@ -35283,7 +35289,8 @@ .locals init (int[] V_0,
int[] V_3,
System.ReadOnlySpan V_4,
System.ReadOnlySpan V_5,
- System.Span V_6)
+ System.Span V_6,
+ System.Span V_7)
IL_0000: ldc.i4.2
IL_0001: newarr "int"
IL_0006: dup
@@ -35335,8 +35342,8 @@ .locals init (int[] V_0,
IL_005f: ldloca.s V_5
IL_0061: ldloc.3
IL_0062: newobj "System.Span..ctor(int[])"
- IL_0067: stloc.s V_6
- IL_0069: ldloca.s V_6
+ IL_0067: stloc.s V_7
+ IL_0069: ldloca.s V_7
IL_006b: ldloc.2
IL_006c: ldloca.s V_5
IL_006e: call "int System.ReadOnlySpan.Length.get"
@@ -35564,7 +35571,8 @@ .locals init (int V_0,
System.ReadOnlySpan V_6,
System.Runtime.CompilerServices.TaskAwaiter V_7,
System.Span V_8,
- System.Exception V_9)
+ System.Span V_9,
+ System.Exception V_10)
IL_0000: ldarg.0
IL_0001: ldfld "int C.d__0.<>1__state"
IL_0006: stloc.0
@@ -35659,8 +35667,8 @@ .locals init (int V_0,
IL_00ea: ldarg.0
IL_00eb: ldfld "int[] C.d__0.<>7__wrap4"
IL_00f0: newobj "System.Span..ctor(int[])"
- IL_00f5: stloc.s V_8
- IL_00f7: ldloca.s V_8
+ IL_00f5: stloc.s V_9
+ IL_00f7: ldloca.s V_9
IL_00f9: ldloc.s V_4
IL_00fb: ldloca.s V_6
IL_00fd: call "int System.ReadOnlySpan.Length.get"
@@ -35739,13 +35747,13 @@ .locals init (int V_0,
}
catch System.Exception
{
- IL_01c5: stloc.s V_9
+ IL_01c5: stloc.s V_10
IL_01c7: ldarg.0
IL_01c8: ldc.i4.s -2
IL_01ca: stfld "int C.d__0.<>1__state"
IL_01cf: ldarg.0
IL_01d0: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"
- IL_01d5: ldloc.s V_9
+ IL_01d5: ldloc.s V_10
IL_01d7: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
IL_01dc: leave.s IL_01f1
}
@@ -35872,13 +35880,14 @@ static void Main()
verifier.VerifyDiagnostics();
verifier.VerifyIL("C.Main", """
{
- // Code size 146 (0x92)
+ // Code size 147 (0x93)
.maxstack 4
.locals init (int V_0,
System.Span V_1,
int V_2,
System.Collections.Generic.List V_3,
- System.Span V_4)
+ System.Span V_4,
+ System.Span V_5)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: ldloc.0
@@ -35928,27 +35937,27 @@ .locals init (int V_0,
IL_0055: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)"
IL_005a: ldloc.3
IL_005b: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)"
- IL_0060: stloc.1
- IL_0061: ldc.i4.0
- IL_0062: stloc.0
- IL_0063: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)"
- IL_0068: stloc.s V_4
- IL_006a: ldloca.s V_4
- IL_006c: ldloca.s V_1
- IL_006e: ldloc.0
- IL_006f: ldloca.s V_4
- IL_0071: call "int System.Span.Length.get"
- IL_0076: call "System.Span System.Span.Slice(int, int)"
- IL_007b: call "void System.Span.CopyTo(System.Span)"
- IL_0080: ldloc.0
- IL_0081: ldloca.s V_4
- IL_0083: call "int System.Span.Length.get"
- IL_0088: add
- IL_0089: stloc.0
- IL_008a: ldloc.3
- IL_008b: ldc.i4.0
- IL_008c: call "void CollectionExtensions.Report(object, bool)"
- IL_0091: ret
+ IL_0060: stloc.s V_4
+ IL_0062: ldc.i4.0
+ IL_0063: stloc.0
+ IL_0064: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)"
+ IL_0069: stloc.s V_5
+ IL_006b: ldloca.s V_5
+ IL_006d: ldloca.s V_4
+ IL_006f: ldloc.0
+ IL_0070: ldloca.s V_5
+ IL_0072: call "int System.Span.Length.get"
+ IL_0077: call "System.Span System.Span.Slice(int, int)"
+ IL_007c: call "void System.Span.CopyTo(System.Span)"
+ IL_0081: ldloc.0
+ IL_0082: ldloca.s V_5
+ IL_0084: call "int System.Span.Length.get"
+ IL_0089: add
+ IL_008a: stloc.0
+ IL_008b: ldloc.3
+ IL_008c: ldc.i4.0
+ IL_008d: call "void CollectionExtensions.Report(object, bool)"
+ IL_0092: ret
}
""");
}
@@ -37859,15 +37868,16 @@ static void Main()
// Ideally we'd like to be able to use *both* something like AddRange, *and* AsSpan/CopyTo/etc. while building the same target collection
verifier.VerifyIL("C.Main", """
{
- // Code size 181 (0xb5)
+ // Code size 182 (0xb6)
.maxstack 3
.locals init (int V_0,
System.Span V_1,
int V_2,
System.Collections.Generic.ICollection V_3,
System.Collections.Generic.List V_4,
- System.Collections.Generic.IEnumerator V_5,
- int V_6)
+ System.Span V_5,
+ System.Collections.Generic.IEnumerator V_6,
+ int V_7)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: ldloc.0
@@ -37920,49 +37930,49 @@ .locals init (int V_0,
IL_005a: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)"
IL_005f: ldloc.s V_4
IL_0061: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)"
- IL_0066: stloc.1
- IL_0067: ldc.i4.0
- IL_0068: stloc.0
- IL_0069: ldloc.3
- IL_006a: callvirt "System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()"
- IL_006f: stloc.s V_5
+ IL_0066: stloc.s V_5
+ IL_0068: ldc.i4.0
+ IL_0069: stloc.0
+ IL_006a: ldloc.3
+ IL_006b: callvirt "System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()"
+ IL_0070: stloc.s V_6
.try
{
- IL_0071: br.s IL_008b
- IL_0073: ldloc.s V_5
- IL_0075: callvirt "int System.Collections.Generic.IEnumerator.Current.get"
- IL_007a: stloc.s V_6
- IL_007c: ldloca.s V_1
- IL_007e: ldloc.0
- IL_007f: call "ref int System.Span.this[int].get"
- IL_0084: ldloc.s V_6
- IL_0086: stind.i4
- IL_0087: ldloc.0
- IL_0088: ldc.i4.1
- IL_0089: add
- IL_008a: stloc.0
- IL_008b: ldloc.s V_5
- IL_008d: callvirt "bool System.Collections.IEnumerator.MoveNext()"
- IL_0092: brtrue.s IL_0073
- IL_0094: leave.s IL_00a2
+ IL_0072: br.s IL_008c
+ IL_0074: ldloc.s V_6
+ IL_0076: callvirt "int System.Collections.Generic.IEnumerator.Current.get"
+ IL_007b: stloc.s V_7
+ IL_007d: ldloca.s V_5
+ IL_007f: ldloc.0
+ IL_0080: call "ref int System.Span.this[int].get"
+ IL_0085: ldloc.s V_7
+ IL_0087: stind.i4
+ IL_0088: ldloc.0
+ IL_0089: ldc.i4.1
+ IL_008a: add
+ IL_008b: stloc.0
+ IL_008c: ldloc.s V_6
+ IL_008e: callvirt "bool System.Collections.IEnumerator.MoveNext()"
+ IL_0093: brtrue.s IL_0074
+ IL_0095: leave.s IL_00a3
}
finally
{
- IL_0096: ldloc.s V_5
- IL_0098: brfalse.s IL_00a1
- IL_009a: ldloc.s V_5
- IL_009c: callvirt "void System.IDisposable.Dispose()"
- IL_00a1: endfinally
+ IL_0097: ldloc.s V_6
+ IL_0099: brfalse.s IL_00a2
+ IL_009b: ldloc.s V_6
+ IL_009d: callvirt "void System.IDisposable.Dispose()"
+ IL_00a2: endfinally
}
- IL_00a2: ldloca.s V_1
- IL_00a4: ldloc.0
- IL_00a5: call "ref int System.Span.this[int].get"
- IL_00aa: ldc.i4.4
- IL_00ab: stind.i4
- IL_00ac: ldloc.s V_4
- IL_00ae: ldc.i4.0
- IL_00af: call "void CollectionExtensions.Report(object, bool)"
- IL_00b4: ret
+ IL_00a3: ldloca.s V_5
+ IL_00a5: ldloc.0
+ IL_00a6: call "ref int System.Span.this[int].get"
+ IL_00ab: ldc.i4.4
+ IL_00ac: stind.i4
+ IL_00ad: ldloc.s V_4
+ IL_00af: ldc.i4.0
+ IL_00b0: call "void CollectionExtensions.Report(object, bool)"
+ IL_00b5: ret
}
""");
}
diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/InlineArrayTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/InlineArrayTests.cs
index 027e23174b049..a9621b5999619 100644
--- a/src/Compilers/CSharp/Test/Emit3/Semantics/InlineArrayTests.cs
+++ b/src/Compilers/CSharp/Test/Emit3/Semantics/InlineArrayTests.cs
@@ -7339,13 +7339,14 @@ static async Task FromResult(T r)
verifier.VerifyIL("Program.d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext",
@"
{
- // Code size 208 (0xd0)
+ // Code size 209 (0xd1)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter V_2,
System.Span V_3,
- System.Exception V_4)
+ System.Span V_4,
+ System.Exception V_5)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.d__2.<>1__state""
IL_0006: stloc.0
@@ -7377,7 +7378,7 @@ .locals init (int V_0,
IL_0041: ldloca.s V_2
IL_0043: ldarg.0
IL_0044: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.d__2>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__2)""
- IL_0049: leave IL_00cf
+ IL_0049: leave IL_00d0
IL_004e: ldarg.0
IL_004f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.d__2.<>u__1""
IL_0054: stloc.2
@@ -7402,36 +7403,36 @@ .locals init (int V_0,
IL_0087: ldc.i4.0
IL_0088: ldloc.1
IL_0089: call ""System.Span System.Span.Slice(int, int)""
- IL_008e: stloc.3
- IL_008f: ldloca.s V_3
- IL_0091: ldc.i4.0
- IL_0092: call ""ref int System.Span.this[int].get""
- IL_0097: ldc.i4.s 111
- IL_0099: stind.i4
- IL_009a: ldarg.0
- IL_009b: ldnull
- IL_009c: stfld ""C Program.d__2.<>7__wrap1""
- IL_00a1: leave.s IL_00bc
+ IL_008e: stloc.s V_4
+ IL_0090: ldloca.s V_4
+ IL_0092: ldc.i4.0
+ IL_0093: call ""ref int System.Span.this[int].get""
+ IL_0098: ldc.i4.s 111
+ IL_009a: stind.i4
+ IL_009b: ldarg.0
+ IL_009c: ldnull
+ IL_009d: stfld ""C Program.d__2.<>7__wrap1""
+ IL_00a2: leave.s IL_00bd
}
catch System.Exception
{
- IL_00a3: stloc.s V_4
- IL_00a5: ldarg.0
- IL_00a6: ldc.i4.s -2
- IL_00a8: stfld ""int Program.d__2.<>1__state""
- IL_00ad: ldarg.0
- IL_00ae: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
- IL_00b3: ldloc.s V_4
- IL_00b5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
- IL_00ba: leave.s IL_00cf
+ IL_00a4: stloc.s V_5
+ IL_00a6: ldarg.0
+ IL_00a7: ldc.i4.s -2
+ IL_00a9: stfld ""int Program.d__2.<>1__state""
+ IL_00ae: ldarg.0
+ IL_00af: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
+ IL_00b4: ldloc.s V_5
+ IL_00b6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
+ IL_00bb: leave.s IL_00d0
}
- IL_00bc: ldarg.0
- IL_00bd: ldc.i4.s -2
- IL_00bf: stfld ""int Program.d__2.<>1__state""
- IL_00c4: ldarg.0
- IL_00c5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
- IL_00ca: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
- IL_00cf: ret
+ IL_00bd: ldarg.0
+ IL_00be: ldc.i4.s -2
+ IL_00c0: stfld ""int Program.d__2.<>1__state""
+ IL_00c5: ldarg.0
+ IL_00c6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
+ IL_00cb: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
+ IL_00d0: ret
}
");
}
@@ -7482,7 +7483,8 @@ .locals init (int V_0,
int V_2,
System.Runtime.CompilerServices.TaskAwaiter V_3,
System.Span V_4,
- System.Exception V_5)
+ System.Span V_5,
+ System.Exception V_6)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.d__2.<>1__state""
IL_0006: stloc.0
@@ -7547,8 +7549,8 @@ .locals init (int V_0,
IL_0098: ldloc.2
IL_0099: sub
IL_009a: call ""System.Span System.Span.Slice(int, int)""
- IL_009f: stloc.s V_4
- IL_00a1: ldloca.s V_4
+ IL_009f: stloc.s V_5
+ IL_00a1: ldloca.s V_5
IL_00a3: ldc.i4.0
IL_00a4: call ""ref int System.Span.this[int].get""
IL_00a9: ldc.i4.s 111
@@ -7560,13 +7562,13 @@ .locals init (int V_0,
}
catch System.Exception
{
- IL_00b5: stloc.s V_5
+ IL_00b5: stloc.s V_6
IL_00b7: ldarg.0
IL_00b8: ldc.i4.s -2
IL_00ba: stfld ""int Program.d__2.<>1__state""
IL_00bf: ldarg.0
IL_00c0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
- IL_00c5: ldloc.s V_5
+ IL_00c5: ldloc.s V_6
IL_00c7: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00cc: leave.s IL_00e1
}
@@ -7630,7 +7632,8 @@ .locals init (int V_0,
System.Runtime.CompilerServices.TaskAwaiter V_5,
System.Index V_6,
System.Span V_7,
- System.Exception V_8)
+ System.Span V_8,
+ System.Exception V_9)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.d__2.<>1__state""
IL_0006: stloc.0
@@ -7711,8 +7714,8 @@ .locals init (int V_0,
IL_00cc: ldloc.3
IL_00cd: ldloc.s V_4
IL_00cf: call ""System.Span System.Span.Slice(int, int)""
- IL_00d4: stloc.s V_7
- IL_00d6: ldloca.s V_7
+ IL_00d4: stloc.s V_8
+ IL_00d6: ldloca.s V_8
IL_00d8: ldc.i4.0
IL_00d9: call ""ref int System.Span.this[int].get""
IL_00de: ldc.i4.s 111
@@ -7724,13 +7727,13 @@ .locals init (int V_0,
}
catch System.Exception
{
- IL_00ea: stloc.s V_8
+ IL_00ea: stloc.s V_9
IL_00ec: ldarg.0
IL_00ed: ldc.i4.s -2
IL_00ef: stfld ""int Program.d__2.<>1__state""
IL_00f4: ldarg.0
IL_00f5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
- IL_00fa: ldloc.s V_8
+ IL_00fa: ldloc.s V_9
IL_00fc: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_0101: leave.s IL_0116
}
@@ -7795,7 +7798,8 @@ .locals init (int V_0,
int V_2,
System.Runtime.CompilerServices.TaskAwaiter V_3,
System.Span V_4,
- System.Exception V_5)
+ System.Span V_5,
+ System.Exception V_6)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.d__2.<>1__state""
IL_0006: stloc.0
@@ -7872,8 +7876,8 @@ .locals init (int V_0,
IL_00c5: ldarg.0
IL_00c6: ldfld ""int Program.d__2.<>7__wrap2""
IL_00cb: call ""System.Span System.Span.Slice(int, int)""
- IL_00d0: stloc.s V_4
- IL_00d2: ldloca.s V_4
+ IL_00d0: stloc.s V_5
+ IL_00d2: ldloca.s V_5
IL_00d4: ldarg.0
IL_00d5: ldfld ""int Program.d__2.<>7__wrap3""
IL_00da: call ""ref int System.Span.this[int].get""
@@ -7886,13 +7890,13 @@ .locals init (int V_0,
}
catch System.Exception
{
- IL_00ea: stloc.s V_5
+ IL_00ea: stloc.s V_6
IL_00ec: ldarg.0
IL_00ed: ldc.i4.s -2
IL_00ef: stfld ""int Program.d__2.<>1__state""
IL_00f4: ldarg.0
IL_00f5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__2.<>t__builder""
- IL_00fa: ldloc.s V_5
+ IL_00fa: ldloc.s V_6
IL_00fc: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_0101: leave.s IL_0116
}
@@ -7961,7 +7965,8 @@ .locals init (int V_0,
System.Index V_6,
System.Runtime.CompilerServices.TaskAwaiter V_7,
System.ReadOnlySpan V_8,
- System.Exception V_9)
+ System.ReadOnlySpan V_9,
+ System.Exception V_10)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.d__1.<>1__state""
IL_0006: stloc.0
@@ -8051,8 +8056,8 @@ .locals init (int V_0,
IL_00ee: ldarg.0
IL_00ef: ldfld ""int Program.d__1.<>7__wrap2""
IL_00f4: call ""System.ReadOnlySpan System.ReadOnlySpan.Slice(int, int)""
- IL_00f9: stloc.s V_8
- IL_00fb: ldloca.s V_8
+ IL_00f9: stloc.s V_9
+ IL_00fb: ldloca.s V_9
IL_00fd: ldloc.s V_5
IL_00ff: call ""ref readonly int System.ReadOnlySpan.this[int].get""
IL_0104: ldind.i4
@@ -8061,13 +8066,13 @@ .locals init (int V_0,
}
catch System.Exception
{
- IL_0108: stloc.s V_9
+ IL_0108: stloc.s V_10
IL_010a: ldarg.0
IL_010b: ldc.i4.s -2
IL_010d: stfld ""int Program.d__1.<>1__state""
IL_0112: ldarg.0
IL_0113: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.d__1.<>t__builder""
- IL_0118: ldloc.s V_9
+ IL_0118: ldloc.s V_10
IL_011a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_011f: leave.s IL_0135
}
@@ -8813,7 +8818,8 @@ static int M4(in int x, Buffer10 y)
// Code size 32 (0x20)
.maxstack 2
.locals init (Buffer10 V_0,
- int V_1)
+ int V_1,
+ Buffer10 V_2)
IL_0000: call ""Buffer10 Program.M3()""
IL_0005: stloc.0
IL_0006: ldloca.s V_0
@@ -8821,9 +8827,9 @@ .locals init (Buffer10 V_0,
IL_000d: ldind.i4
IL_000e: stloc.1
IL_000f: ldloca.s V_1
- IL_0011: ldloca.s V_0
+ IL_0011: ldloca.s V_2
IL_0013: initobj ""Buffer10""
- IL_0019: ldloc.0
+ IL_0019: ldloc.2
IL_001a: call ""int Program.M4(in int, Buffer10)""
IL_001f: ret
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs
index 1c2864d66eac5..7ae0f73ffafb3 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs
@@ -3822,7 +3822,8 @@ public void NestedInterpolatedStrings_02(string expression)
.maxstack 4
.locals init (int V_0, //i1
int V_1, //i2
- System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2,
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.2
@@ -3836,14 +3837,14 @@ .locals init (int V_0, //i1
IL_0010: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
IL_0015: ldloca.s V_2
IL_0017: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
- IL_001c: ldloca.s V_2
+ IL_001c: ldloca.s V_3
IL_001e: ldc.i4.0
IL_001f: ldc.i4.1
IL_0020: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
- IL_0025: ldloca.s V_2
+ IL_0025: ldloca.s V_3
IL_0027: ldloc.1
IL_0028: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
- IL_002d: ldloca.s V_2
+ IL_002d: ldloca.s V_3
IL_002f: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0034: call ""string string.Concat(string, string)""
IL_0039: call ""void System.Console.WriteLine(string)""
@@ -10151,14 +10152,15 @@ Creating DummyHandler from StructLogger#2
verifier.VerifyIL("", @"
{
- // Code size 175 (0xaf)
+ // Code size 177 (0xb1)
.maxstack 4
.locals init (int V_0, //i
StructLogger V_1, //s
StructLogger V_2,
DummyHandler V_3,
bool V_4,
- StructLogger& V_5)
+ StructLogger& V_5,
+ DummyHandler V_6)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_2
@@ -10207,32 +10209,32 @@ .locals init (int V_0, //i
IL_0064: ldobj ""StructLogger""
IL_0069: ldloca.s V_4
IL_006b: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)""
- IL_0070: stloc.3
- IL_0071: ldloc.s V_4
- IL_0073: brfalse.s IL_008f
- IL_0075: ldloca.s V_3
- IL_0077: ldstr ""log:""
- IL_007c: call ""void DummyHandler.AppendLiteral(string)""
- IL_0081: nop
- IL_0082: ldloca.s V_3
- IL_0084: ldloc.0
- IL_0085: dup
- IL_0086: ldc.i4.1
- IL_0087: add
- IL_0088: stloc.0
- IL_0089: call ""void DummyHandler.AppendFormatted(int)""
- IL_008e: nop
- IL_008f: ldloc.s V_5
- IL_0091: ldloc.3
- IL_0092: call ""void StructLogger.Log(DummyHandler)""
- IL_0097: nop
- IL_0098: ldstr ""(2) i={0}""
- IL_009d: ldloc.0
- IL_009e: box ""int""
- IL_00a3: call ""string string.Format(string, object)""
- IL_00a8: call ""void System.Console.WriteLine(string)""
- IL_00ad: nop
- IL_00ae: ret
+ IL_0070: stloc.s V_6
+ IL_0072: ldloc.s V_4
+ IL_0074: brfalse.s IL_0090
+ IL_0076: ldloca.s V_6
+ IL_0078: ldstr ""log:""
+ IL_007d: call ""void DummyHandler.AppendLiteral(string)""
+ IL_0082: nop
+ IL_0083: ldloca.s V_6
+ IL_0085: ldloc.0
+ IL_0086: dup
+ IL_0087: ldc.i4.1
+ IL_0088: add
+ IL_0089: stloc.0
+ IL_008a: call ""void DummyHandler.AppendFormatted(int)""
+ IL_008f: nop
+ IL_0090: ldloc.s V_5
+ IL_0092: ldloc.s V_6
+ IL_0094: call ""void StructLogger.Log(DummyHandler)""
+ IL_0099: nop
+ IL_009a: ldstr ""(2) i={0}""
+ IL_009f: ldloc.0
+ IL_00a0: box ""int""
+ IL_00a5: call ""string string.Format(string, object)""
+ IL_00aa: call ""void System.Console.WriteLine(string)""
+ IL_00af: nop
+ IL_00b0: ret
}
");
}
@@ -16800,13 +16802,14 @@ public void ParenthesizedAdditiveExpression_04()
verifier.VerifyIL("Program.<$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
- // Code size 244 (0xf4)
+ // Code size 245 (0xf5)
.maxstack 4
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter V_2,
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3,
- System.Exception V_4)
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4,
+ System.Exception V_5)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<$>d__0.<>1__state""
IL_0006: stloc.0
@@ -16839,7 +16842,7 @@ .locals init (int V_0,
IL_0042: ldloca.s V_2
IL_0044: ldarg.0
IL_0045: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<$>d__0)""
- IL_004a: leave IL_00f3
+ IL_004a: leave IL_00f4
IL_004f: ldarg.0
IL_0050: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<$>d__0.<>u__1""
IL_0055: stloc.2
@@ -16871,36 +16874,36 @@ .locals init (int V_0,
IL_009f: ldc.i4.0
IL_00a0: ldc.i4.1
IL_00a1: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
- IL_00a6: stloc.3
- IL_00a7: ldloca.s V_3
- IL_00a9: ldarg.0
- IL_00aa: ldfld ""int Program.<$>d__0.5__3""
- IL_00af: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
- IL_00b4: ldloca.s V_3
- IL_00b6: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
- IL_00bb: call ""string string.Concat(string, string, string)""
- IL_00c0: call ""void System.Console.WriteLine(string)""
- IL_00c5: leave.s IL_00e0
+ IL_00a6: stloc.s V_4
+ IL_00a8: ldloca.s V_4
+ IL_00aa: ldarg.0
+ IL_00ab: ldfld ""int Program.<$>d__0.5__3""
+ IL_00b0: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
+ IL_00b5: ldloca.s V_4
+ IL_00b7: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
+ IL_00bc: call ""string string.Concat(string, string, string)""
+ IL_00c1: call ""void System.Console.WriteLine(string)""
+ IL_00c6: leave.s IL_00e1
}
catch System.Exception
{
- IL_00c7: stloc.s V_4
- IL_00c9: ldarg.0
- IL_00ca: ldc.i4.s -2
- IL_00cc: stfld ""int Program.<$>d__0.<>1__state""
- IL_00d1: ldarg.0
- IL_00d2: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<$>d__0.<>t__builder""
- IL_00d7: ldloc.s V_4
- IL_00d9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
- IL_00de: leave.s IL_00f3
+ IL_00c8: stloc.s V_5
+ IL_00ca: ldarg.0
+ IL_00cb: ldc.i4.s -2
+ IL_00cd: stfld ""int Program.<$>d__0.<>1__state""
+ IL_00d2: ldarg.0
+ IL_00d3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<$>d__0.<>t__builder""
+ IL_00d8: ldloc.s V_5
+ IL_00da: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
+ IL_00df: leave.s IL_00f4
}
- IL_00e0: ldarg.0
- IL_00e1: ldc.i4.s -2
- IL_00e3: stfld ""int Program.<$>d__0.<>1__state""
- IL_00e8: ldarg.0
- IL_00e9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<$>d__0.<>t__builder""
- IL_00ee: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
- IL_00f3: ret
+ IL_00e1: ldarg.0
+ IL_00e2: ldc.i4.s -2
+ IL_00e4: stfld ""int Program.<$>d__0.<>1__state""
+ IL_00e9: ldarg.0
+ IL_00ea: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<$>d__0.<>t__builder""
+ IL_00ef: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
+ IL_00f4: ret
}");
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs
index 9770e5eb3930b..81c060e72a02b 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs
@@ -2223,7 +2223,8 @@ public void NestedInterpolatedStrings_02(string expression)
.maxstack 4
.locals init (int V_0, //i1
int V_1, //i2
- System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2,
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.2
@@ -2237,14 +2238,14 @@ .locals init (int V_0, //i1
IL_0010: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
IL_0015: ldloca.s V_2
IL_0017: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
- IL_001c: ldloca.s V_2
+ IL_001c: ldloca.s V_3
IL_001e: ldc.i4.0
IL_001f: ldc.i4.1
IL_0020: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
- IL_0025: ldloca.s V_2
+ IL_0025: ldloca.s V_3
IL_0027: ldloc.1
IL_0028: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
- IL_002d: ldloca.s V_2
+ IL_002d: ldloca.s V_3
IL_002f: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0034: call ""string string.Concat(string, string)""
IL_0039: call ""void System.Console.WriteLine(string)""
@@ -12228,13 +12229,14 @@ public void ParenthesizedAdditiveExpression_04()
verifier.VerifyIL("Program.<$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
- // Code size 244 (0xf4)
+ // Code size 245 (0xf5)
.maxstack 4
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter V_2,
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3,
- System.Exception V_4)
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4,
+ System.Exception V_5)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<$>d__0.<>1__state""
IL_0006: stloc.0
@@ -12267,7 +12269,7 @@ .locals init (int V_0,
IL_0042: ldloca.s V_2
IL_0044: ldarg.0
IL_0045: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<$>d__0)""
- IL_004a: leave IL_00f3
+ IL_004a: leave IL_00f4
IL_004f: ldarg.0
IL_0050: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<$>d__0.<>u__1""
IL_0055: stloc.2
@@ -12299,36 +12301,36 @@ .locals init (int V_0,
IL_009f: ldc.i4.0
IL_00a0: ldc.i4.1
IL_00a1: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
- IL_00a6: stloc.3
- IL_00a7: ldloca.s V_3
- IL_00a9: ldarg.0
- IL_00aa: ldfld ""int Program.<$>d__0.5__3""
- IL_00af: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
- IL_00b4: ldloca.s V_3
- IL_00b6: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
- IL_00bb: call ""string string.Concat(string, string, string)""
- IL_00c0: call ""void System.Console.WriteLine(string)""
- IL_00c5: leave.s IL_00e0
+ IL_00a6: stloc.s V_4
+ IL_00a8: ldloca.s V_4
+ IL_00aa: ldarg.0
+ IL_00ab: ldfld ""int Program.<$>d__0.5__3""
+ IL_00b0: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
+ IL_00b5: ldloca.s V_4
+ IL_00b7: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
+ IL_00bc: call ""string string.Concat(string, string, string)""
+ IL_00c1: call ""void System.Console.WriteLine(string)""
+ IL_00c6: leave.s IL_00e1
}
catch System.Exception
{
- IL_00c7: stloc.s V_4
- IL_00c9: ldarg.0
- IL_00ca: ldc.i4.s -2
- IL_00cc: stfld ""int Program.<$>d__0.<>1__state""
- IL_00d1: ldarg.0
- IL_00d2: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<$>d__0.<>t__builder""
- IL_00d7: ldloc.s V_4
- IL_00d9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
- IL_00de: leave.s IL_00f3
+ IL_00c8: stloc.s V_5
+ IL_00ca: ldarg.0
+ IL_00cb: ldc.i4.s -2
+ IL_00cd: stfld ""int Program.<$>d__0.<>1__state""
+ IL_00d2: ldarg.0
+ IL_00d3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<$>d__0.<>t__builder""
+ IL_00d8: ldloc.s V_5
+ IL_00da: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
+ IL_00df: leave.s IL_00f4
}
- IL_00e0: ldarg.0
- IL_00e1: ldc.i4.s -2
- IL_00e3: stfld ""int Program.<