Skip to content
Closed
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
16 changes: 16 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4055,6 +4055,14 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres
case BoundKind.BinaryOperator:
var binary = (BoundBinaryOperator)expr;

#if DEBUG
// Nested binary operators on the left-hand side are not visited by BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator.
if (binary.Left is BoundBinaryOperator)
{
_visited.Add(binary.Left);
}
#endif

if (binary.Method is { } binaryMethod)
{
return GetInvocationEscapeScope(
Expand Down Expand Up @@ -4734,6 +4742,14 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF
return true;
}

#if DEBUG
// Nested binary operators on the left-hand side are not visited by BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator.
if (binary.Left is BoundBinaryOperator)
{
_visited.Add(binary.Left);
}
#endif

if (binary.Method is { } binaryMethod)
{
return CheckInvocationEscape(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ private void AssertVisited(BoundExpression expr)
}
else if (_visited is { } && _visited.Count <= MaxTrackVisited)
{
Debug.Assert(_visited.Contains(expr));
Debug.Assert(_visited.Contains(expr), $"Expected {expr} `{expr.Syntax}` to be visited.");
}
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7871,6 +7871,37 @@ ref struct S
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(47, 16));
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")]
public void UserDefinedBinaryOperator_RefStruct_Nested()
{
var source = """
class C
{
S M()
{
S s;
s = default(S) + 100 + 200;
return s;
}
}

ref struct S
{
public static S operator+(S y, in int x) => throw null;
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (6,13): error CS8347: Cannot use a result of 'S.operator +(S, in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// s = default(S) + 100 + 200;
Diagnostic(ErrorCode.ERR_EscapeCall, "default(S) + 100").WithArguments("S.operator +(S, in int)", "x").WithLocation(6, 13),
// (6,13): error CS8347: Cannot use a result of 'S.operator +(S, in int)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// s = default(S) + 100 + 200;
Diagnostic(ErrorCode.ERR_EscapeCall, "default(S) + 100 + 200").WithArguments("S.operator +(S, in int)", "y").WithLocation(6, 13),
// (6,26): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// s = default(S) + 100 + 200;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "100").WithLocation(6, 26));
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")]
public void UserDefinedBinaryOperator_RefStruct_Scoped_Left()
{
Expand Down Expand Up @@ -8531,5 +8562,16 @@ static R F2()
// return new R(1) | new R(2);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "1").WithLocation(18, 22));
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72873")]
public void Utf8Addition()
{
var code = """
using System;
ReadOnlySpan<byte> x = "Hello"u8 + " "u8 + "World!"u8;
Console.WriteLine(x.Length);
""";
CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyDiagnostics();
}
}
}