-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compound Assignment when ref temps are required crashes the compiler #36443
Comments
Compiling this sort of scenario seems to work fine from the command-line, With both the native compiler and Roslyn, the write to the field involves an additional dereference after the await completes (ie. we couldn't save a ref to the field). // produced by native compiler, 4.7.3190.0
private void MoveNext()
{
try
{
bool flag = true;
object item;
int num;
TaskAwaiter<int> awaiter;
if (<>1__state != 0)
{
item = <>4__this;
num = ((C)item).field;
awaiter = <>4__this.M2().GetAwaiter();
if (!awaiter.IsCompleted)
{
Tuple<C, int> tuple = (Tuple<C, int>)(<>t__stack = new Tuple<C, int>((C)item, num));
<>1__state = 0;
<>u__$awaiter1 = awaiter;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
flag = false;
return;
}
}
else
{
Tuple<C, int> tuple = (Tuple<C, int>)<>t__stack;
item = tuple.Item1;
num = tuple.Item2;
<>t__stack = null;
awaiter = <>u__$awaiter1;
<>u__$awaiter1 = default(TaskAwaiter<int>);
<>1__state = -1;
}
int result = awaiter.GetResult();
awaiter = default(TaskAwaiter<int>);
((C)item).field = num + result; // assign to the field
Console.Write(<>4__this.field);
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult();
} // produced by 3.2 compiler
private void MoveNext()
{
int num = <>1__state;
try
{
TaskAwaiter<int> awaiter;
if (num != 0)
{
<>s__1 = <>4__this.field;
awaiter = <>4__this.M2().GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<M>d__1 stateMachine = this;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(TaskAwaiter<int>);
num = (<>1__state = -1);
}
<>s__2 = awaiter.GetResult();
<>4__this.field = <>s__1 + <>s__2; // assign to the field
Console.Write(<>4__this.field);
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult();
} // original source
class C
{
int field = 1;
async System.Threading.Tasks.Task M()
{
this.field += await M2();
System.Console.Write(this.field);
}
async System.Threading.Tasks.Task<int> M2()
{
await System.Threading.Tasks.Task.Yield();
return 42;
}
} |
The code sample in OP doesn't crash the latest compiler (tested in command-line, unittest and sharplab). Let's confirm and narrow down the repro scenario. Correction: it does crash in unittest with Update: repros with
if (compilation.Options.OptimizationLevel != OptimizationLevel.Release)
{
Debug.Assert(variablesToHoist.Count == 0);
// In debug build we hoist all locals and parameters:
foreach (var v in allVariables)
{
var symbol = v.Symbol;
if ((object)symbol != null && HoistInDebugBuild(symbol))
{
variablesToHoist.Add(symbol);
}
}
} |
The analysis fails to determine that the local |
This code crashes the compiler with the following stack:
The issue here is that
TransformCompoundAssignmentLHS
can return aref
local for the following case:roslyn/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
Lines 490 to 493 in d5b8d64
The fix is likely to simply issue an understandable error here, instead of throwing an UnreachableCode exception. FYI @jcouv @agocke.
The text was updated successfully, but these errors were encountered: