diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 002b0a25e6cb1..98844f4c0150a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -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( @@ -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( diff --git a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs index 2029d8d5aa669..8d4310758fc17 100644 --- a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs +++ b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs @@ -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 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index 6da08b9784005..0cd3ee133280d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -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() { @@ -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 x = "Hello"u8 + " "u8 + "World!"u8; + Console.WriteLine(x.Length); + """; + CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } } }