/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/CSharp15/LabeledBreakContinueBindingTests.cs
2 344 строки
69 KB
Fred Silberberg
Add C# 15 language version (#84799)
11 авг 2026, 23:51
Не верифицирован
11 авг 2026, 23:51
1284a4a
Код
Авторство
О чём код?
// 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.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics; public sealed class LabeledBreakContinueBindingTests : CSharpTestBase { private static readonly CSharpParseOptions s_optionsCSharp14 = TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp14); #region Valid: all loop types [Fact] public void Continue_LabeledForEachDeconstruction() { var source = """ class C { void M((int, int)[] items) { outer: foreach (var (x, y) in items) { foreach (var z in items) continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Valid: switch [Fact] public void Break_LabeledSwitch() { var source = """ class C { void M(int x) { outer: switch (x) { default: while (true) break outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Valid: nested labels [Fact] public void Break_StackedLabels() { var source = """ class C { void M() { a: b: c: while (true) { break b; } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,9): warning CS0164: This label has not been referenced // a: b: c: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "a").WithLocation(5, 9), // (5,15): warning CS0164: This label has not been referenced // a: b: c: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "c").WithLocation(5, 15), // (7,19): error CS9393: No enclosing loop or switch statement with the label 'b' out of which to break // break b; Diagnostic(ErrorCode.ERR_NoBreakId, "b").WithArguments("b").WithLocation(7, 19)); } [Fact] public void Break_DeeplyNested_LoopSwitchLoop() { var source = """ class C { void M(int a, int b) { L0: while (a-- > 0) { L1: switch (b) { default: L2: while (true) { if (a == 0) break L0; if (b == 0) break L1; continue L2; } break; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (16,21): warning CS0162: Unreachable code detected // break; Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(16, 21)); } #endregion #region Valid: interaction with other constructs [Fact] public void Break_InsideTryCatch() { var source = """ class C { void M() { outer: while (true) { try { break outer; } catch { } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_InsideChecked() { var source = """ class C { void M() { outer: for (int i = 0; i < 10; i++) { checked { break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,40): warning CS0162: Unreachable code detected // outer: for (int i = 0; i < 10; i++) Diagnostic(ErrorCode.WRN_UnreachableCode, "i").WithLocation(5, 40)); } [Fact] public void Break_InsideLockUsing() { var source = """ class C { void M() { outer: while (true) { lock (this) { using var d = default(System.IDisposable); break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_PatternSwitchWithWhen() { var source = """ class C { void M(object o) { outer: while (true) { switch (o) { case int x when x > 0: break outer; default: break; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_AsyncMethod() { var source = """ using System.Threading.Tasks; class C { async Task M() { outer: for (int i = 0; i < 1; i++) { for (int j = 0; j < 1; j++) { await Task.Yield(); continue outer; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,36): warning CS0162: Unreachable code detected // for (int j = 0; j < 1; j++) Diagnostic(ErrorCode.WRN_UnreachableCode, "j").WithLocation(8, 36)); } [Fact] public void Break_Iterator() { var source = """ using System.Collections.Generic; class C { IEnumerable<int> M() { outer: while (true) { yield return 1; break outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_GotoAndLabeledBreak_SameLabel() { var source = """ class C { void M() { L: while (true) { goto L; break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): warning CS0162: Unreachable code detected // break L; Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 13)); } [Fact] public void Continue_SwitchInsideLabeledFor() { var source = """ class C { void M(int x) { L: for (;;) switch (x) { default: continue L; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_UnicodeEscapedLabel() { var source = """ class C { void M() { \u006Futer: while (true) { break outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_UnreachableLabeledBreak_StillSuppressesWarning() { var source = """ class C { void M() { outer: while (true) { break; break outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): warning CS0162: Unreachable code detected // break outer; Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 13)); } [Fact] public void Continue_UnreachableLabeledContinue_StillSuppressesWarning() { var source = """ class C { void M() { outer: while (true) { break; continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): warning CS0162: Unreachable code detected // continue outer; Diagnostic(ErrorCode.WRN_UnreachableCode, "continue").WithLocation(8, 13)); } [Fact] public void Break_StackedLabels_OnlyValidLabelReferenced() { var source = """ class C { void M() { a: b: c: while (true) { break c; } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,9): warning CS0164: This label has not been referenced // a: b: c: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "a").WithLocation(5, 9), // (5,12): warning CS0164: This label has not been referenced // a: b: c: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "b").WithLocation(5, 12)); } [Fact] public void Break_MultipleLabeledBreaksToSameLabel() { var source = """ class C { void M(bool x) { outer: while (true) { if (x) break outer; else break outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_MultipleLabeledContinuesToSameLabel() { var source = """ class C { void M(bool x) { outer: for (int i = 0; i < 10; i++) { if (x) continue outer; else continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_MixedUnlabeledAndLabeledExits() { var source = """ class C { void M(bool cond) { outer: while (true) { while (cond) break; break outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_LabeledBreakFirst_GotoUnreachable() { var source = """ class C { void M() { L: while (true) { break L; goto L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): warning CS0162: Unreachable code detected // goto L; Diagnostic(ErrorCode.WRN_UnreachableCode, "goto").WithLocation(8, 13)); } [Fact] public void Break_InCatch_WithFinally_TargetsOuterLoop() { var source = """ class C { void M() { outer: while (true) { try { throw new System.Exception(); } catch { break outer; } finally { } } } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Invalid: label not found [Fact] public void Break_LabelNotFound() { var source = """ class C { void M() { while (true) break missing; } } """; CreateCompilation(source).VerifyDiagnostics( // (6,19): error CS9393: No enclosing loop or switch statement with the label 'missing' out of which to break // break missing; Diagnostic(ErrorCode.ERR_NoBreakId, "missing").WithArguments("missing").WithLocation(6, 19)); } [Fact] public void Break_LabelInSiblingBlock() { var source = """ class C { void M() { { L: while (true) { } } { break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,11): warning CS0164: This label has not been referenced // { L: while (true) { } } Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L").WithLocation(5, 11), // (6,11): warning CS0162: Unreachable code detected // { break L; } Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(6, 11), // (6,17): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // { break L; } Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(6, 17)); } #endregion #region Invalid: label not on loop/switch [Fact] public void Break_LabelOnBlock() { var source = """ class C { void M() { L: { break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,20): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // L: { break L; } Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(5, 20)); } [Fact] public void Break_LabelOnIf() { var source = """ class C { void M() { L: if (true) break L; } } """; CreateCompilation(source).VerifyDiagnostics( // (6,19): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(6, 19)); } [Fact] public void Break_LabelOnEmptyStatement() { var source = """ class C { void M() { L: ; while (true) break L; } } """; CreateCompilation(source).VerifyDiagnostics( // (6,28): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // while (true) break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(6, 28)); } [Fact] public void Break_LabelOnExpressionStatement() { var source = """ class C { void M() { L: System.Console.WriteLine(); if (true) break L; } } """; CreateCompilation(source).VerifyDiagnostics( // (6,25): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // if (true) break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(6, 25)); } [Fact] public void Break_LabelOnLocalDeclaration_SwitchExpression() { var source = """ class C { void M(int x) { L: var y = x switch { _ => 1 }; while (true) break L; } } """; CreateCompilation(source).VerifyDiagnostics( // (6,28): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // while (true) break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(6, 28)); } [Fact] public void Break_LabelOnLock() { var source = """ class C { void M(object o) { L: lock (o) { break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,29): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // L: lock (o) { break L; } Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(5, 29)); } #endregion #region Invalid: continue targeting switch [Fact] public void Continue_TargetIsSwitch() { var source = """ class C { void M(int x) { outer: switch (x) { default: continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,31): error CS9394: No enclosing loop with the label 'outer' out of which to continue // default: continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(7, 31)); } #endregion #region Invalid: label not containing [Fact] public void Break_LabelOnSiblingLoop() { var source = """ class C { void M() { outer: while (false) { } while (true) { break outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (6,30): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // while (true) { break outer; } Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(6, 30)); } [Fact] public void Continue_LabelOnFollowingLoop() { var source = """ class C { void M() { while (true) { continue outer; } outer: while (false) { } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,33): error CS9394: No enclosing loop with the label 'outer' out of which to continue // while (true) { continue outer; } Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(5, 33)); } [Fact] public void Break_LabelAfterBreak() { var source = """ class C { void M() { foreach (var x in new int[0]) { break outer; outer: foreach (var y in new int[0]) { } } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,19): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // break outer; Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(7, 19)); } [Fact] public void Continue_LabelOnInnerLoop_NotContaining() { var source = """ class C { void M() { foreach (var x in new int[0]) { continue outer; outer: foreach (var y in new int[0]) { } } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,22): error CS9394: No enclosing loop with the label 'outer' out of which to continue // continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(7, 22)); } [Fact] public void Continue_LabelOnDeeperNestedLoop() { var source = """ class C { void M() { foreach (var x in new int[0]) { continue outer; { outer: foreach (var y in new int[0]) { } } } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,22): error CS9394: No enclosing loop with the label 'outer' out of which to continue // continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(7, 22), // (8,15): warning CS0164: This label has not been referenced // { outer: foreach (var y in new int[0]) { } } Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(8, 15)); } [Fact] public void Break_LabelOnDeeperNestedLoop() { var source = """ class C { void M() { foreach (var x in new int[0]) { break outer; { outer: foreach (var y in new int[0]) { } } } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,19): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // break outer; Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(7, 19), // (8,15): warning CS0164: This label has not been referenced // { outer: foreach (var y in new int[0]) { } } Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(8, 15)); } #endregion #region Invalid: label various illegal positions [Fact] public void Continue_LabelExistsAfterLoop() { var source = """ class C { void M() { foreach (var x in new int[0]) { continue outer; } outer: ; } } """; CreateCompilation(source).VerifyDiagnostics( // (7,22): error CS9394: No enclosing loop with the label 'outer' out of which to continue // continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(7, 22)); } [Fact] public void Continue_LabelBeforeLoop() { var source = """ class C { void M() { outer: ; foreach (var x in new int[0]) { continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,22): error CS9394: No enclosing loop with the label 'outer' out of which to continue // continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(8, 22)); } #endregion #region Lambda and local function boundaries [Fact] public void Break_InsideLambda_LabelOutside() { var source = """ using System; class C { void M() { outer: while (true) { Action a = () => { break outer; }; } } } """; CreateCompilation(source).VerifyDiagnostics( // (6,9): warning CS0164: This label has not been referenced // outer: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(6, 9), // (8,32): error CS1632: Control cannot leave the body of an anonymous method or lambda expression // Action a = () => { break outer; }; Diagnostic(ErrorCode.ERR_BadDelegateLeave, "break").WithLocation(8, 32)); } [Fact] public void Break_InsideLocalFunction_LabelOutside() { var source = """ class C { void M() { outer: while (true) { void F() { break outer; } F(); } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,30): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // void F() { break outer; } Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(7, 30)); } [Fact] public void Break_LabelInsideLambda_BreakOutside() { var source = """ using System; class C { void M() { Action a = () => { outer: while (true) { } }; break outer; } } """; CreateCompilation(source).VerifyDiagnostics( // (6,28): warning CS0164: This label has not been referenced // Action a = () => { outer: while (true) { } }; Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(6, 28), // (7,15): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // break outer; Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(7, 15)); } [Fact] public void Break_InsideLambda_TargetsLoopInsideLambda() { var source = """ using System; class C { void M() { Action a = () => { outer: while (true) { while (true) break outer; } }; } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_InsideLambda_TargetsLoopInsideLambda() { var source = """ using System; class C { void M() { Action a = () => { outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) continue outer; } }; } } """; CreateCompilation(source).VerifyDiagnostics( // (10,41): warning CS0162: Unreachable code detected // for (int j = 0; j < 10; j++) Diagnostic(ErrorCode.WRN_UnreachableCode, "j").WithLocation(10, 41)); } [Fact] public void Break_InsideLocalFunction_TargetsLoopInsideLocalFunction() { var source = """ class C { void M() { void F() { outer: while (true) { while (true) break outer; } } F(); } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_InsideLocalFunction_TargetsLoopInsideLocalFunction() { var source = """ class C { void M() { void F() { outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) continue outer; } } F(); } } """; CreateCompilation(source).VerifyDiagnostics( // (9,41): warning CS0162: Unreachable code detected // for (int j = 0; j < 10; j++) Diagnostic(ErrorCode.WRN_UnreachableCode, "j").WithLocation(9, 41)); } #endregion #region Finally blocks [Fact] public void Break_InFinally_TargetsOuterLoop() { var source = """ class C { void M() { outer: for (int i = 0; i < 10; i++) { try { } finally { break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,40): warning CS0162: Unreachable code detected // outer: for (int i = 0; i < 10; i++) Diagnostic(ErrorCode.WRN_UnreachableCode, "i").WithLocation(5, 40), // (8,23): error CS0157: Control cannot leave the body of a finally clause // finally { break outer; } Diagnostic(ErrorCode.ERR_BadFinallyLeave, "break").WithLocation(8, 23)); } [Fact] public void Continue_InFinally_TargetsOuterLoop() { var source = """ class C { void M() { outer: for (int i = 0; i < 10; i++) { try { } finally { continue outer; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,23): error CS0157: Control cannot leave the body of a finally clause // finally { continue outer; } Diagnostic(ErrorCode.ERR_BadFinallyLeave, "continue").WithLocation(8, 23)); } [Fact] public void Break_InFinally_TargetsLoopInsideFinally() { var source = """ class C { void M() { try { } finally { outer: while (true) { while (true) break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_InFinally_TargetsLoopInsideFinally() { var source = """ class C { void M() { try { } finally { outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) continue outer; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (10,41): warning CS0162: Unreachable code detected // for (int j = 0; j < 10; j++) Diagnostic(ErrorCode.WRN_UnreachableCode, "j").WithLocation(10, 41)); } [Fact] public void Break_InTryWithFinally_Valid() { var source = """ class C { void M() { outer: while (true) { try { break outer; } finally { } } } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Using statements [Fact] public void LabeledBreakInUsingStatement() { var source = """ outer: while (true) { using var x = GetResource(); break outer; } System.IDisposable GetResource() => null; """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void LabeledContinueInUsingStatement() { var source = """ outer: while (true) { using var x = GetResource(); continue outer; } System.IDisposable GetResource() => null; """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Language version gating [Fact] public void Break_CSharp14_FeatureNotAvailable() { var source = """ class C { void M() { outer: while (true) break outer; } } """; CreateCompilation(source, parseOptions: s_optionsCSharp14).VerifyDiagnostics( // (6,19): error CS9327: Feature 'labeled break and continue' is not available in C# 14.0. Please use language version 15.0 or greater. // break outer; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "outer").WithArguments("labeled break and continue", "15.0").WithLocation(6, 19)); } [Fact] public void Continue_CSharp14_FeatureNotAvailable() { var source = """ class C { void M() { outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) continue outer; } } } """; CreateCompilation(source, parseOptions: s_optionsCSharp14).VerifyDiagnostics( // (7,37): warning CS0162: Unreachable code detected // for (int j = 0; j < 10; j++) Diagnostic(ErrorCode.WRN_UnreachableCode, "j").WithLocation(7, 37), // (8,26): error CS9327: Feature 'labeled break and continue' is not available in C# 14.0. Please use language version 15.0 or greater. // continue outer; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "outer").WithArguments("labeled break and continue", "15.0").WithLocation(8, 26)); } #endregion #region Reachability and definite assignment [Fact] public void StatementAfterLabeledBreak_Unreachable() { var source = """ class C { void M() { outer: while (true) { break outer; System.Console.WriteLine("dead"); } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): warning CS0162: Unreachable code detected // System.Console.WriteLine("dead"); Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(8, 13)); } [Fact] public void StatementAfterLabeledContinue_Unreachable() { var source = """ class C { void M() { outer: while (true) { continue outer; System.Console.WriteLine("dead"); } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): warning CS0162: Unreachable code detected // System.Console.WriteLine("dead"); Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(8, 13)); } [Fact] public void LabeledBreak_DefinitelyAssignedAfterLoop() { var source = """ class C { int M() { int x; outer: while (true) { while (true) { x = 1; break outer; } } return x; } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void LabeledBreak_NotDefinitelyAssigned_ReportsCS0165() { var source = """ class C { int M(bool b) { int x; outer: while (true) { if (b) { x = 1; break outer; } break outer; } return x; } } """; CreateCompilation(source).VerifyDiagnostics( // (15,16): error CS0165: Use of unassigned local variable 'x' // return x; Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(15, 16)); } [Fact] public void LabeledContinue_PreventsFallthrough_NoDefiniteAssignmentError() { var source = """ class C { void M(int[] items, bool b) { outer: foreach (var item in items) { int x; if (b) { x = 1; } else { continue outer; } System.Console.WriteLine(x); } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void IntReturningMethod_WithLabeledBreak_NotAllPathsReturn_ReportsCS0161() { var source = """ class C { int M() { outer: while (true) { break outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (3,9): error CS0161: 'C.M()': not all code paths return a value // int M() Diagnostic(ErrorCode.ERR_ReturnExpected, "M").WithArguments("C.M()").WithLocation(3, 9)); } [Fact] public void IntReturningMethod_InfiniteLoopNoLabeledBreak_NoError() { var source = """ class C { int M() { outer: while (true) { continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void LabeledBreak_ExitsTryFinally_CodeAfterLoop_Reachable() { var source = """ class C { int M() { int x; outer: while (true) { try { x = 1; break outer; } finally { System.Console.WriteLine("cleanup"); } } return x; } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Scope transparency (unchecked / unsafe / fixed) [Fact] public void Break_Unchecked_TargetIsOuterLoop() { var source = """ class C { void M() { outer: while (true) { unchecked { break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_Unchecked_TargetIsOuterLoop() { var source = """ class C { void M() { outer: while (true) { unchecked { continue outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Break_Unsafe_TargetIsOuterLoop() { var source = """ class C { unsafe void M() { outer: while (true) { unsafe { break outer; } } } } """; CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] public void Continue_Unsafe_TargetIsOuterLoop() { var source = """ class C { unsafe void M() { outer: while (true) { unsafe { continue outer; } } } } """; CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] public void Break_Fixed_TargetIsOuterLoop() { var source = """ class C { unsafe void M(int[] a) { outer: while (true) { fixed (int* p = a) { break outer; } } } } """; CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } #endregion #region Label shadowing [Fact] public void LabelShadowing_LocalFunctionInsideLabeledLoop_ReportsShadowing() { var source = """ class C { void M() { L: while (true) { void Inner() { L: while (true) { break L; } } break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,18): warning CS8321: The local function 'Inner' is declared but never used // void Inner() Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Inner").WithArguments("Inner").WithLocation(7, 18), // (9,17): error CS0158: The label 'L' shadows another label by the same name in a contained scope // L: while (true) Diagnostic(ErrorCode.ERR_LabelShadow, "L").WithArguments("L").WithLocation(9, 17)); } [Fact] public void LabelShadowing_LambdaInsideLabeledLoop_ReportsShadowing() { var source = """ using System; class C { void M() { L: while (true) { Action a = () => { L: while (true) { break L; } }; break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (10,17): error CS0158: The label 'L' shadows another label by the same name in a contained scope // L: while (true) Diagnostic(ErrorCode.ERR_LabelShadow, "L").WithArguments("L").WithLocation(10, 17)); } [Fact] public void LabelShadowing_DistinctLabelsInNestedLocalFunction_NoError() { var source = """ class C { void M() { outer: while (true) { void Inner() { inner: while (true) { break inner; } } Inner(); break outer; } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void LabelShadowing_MethodLevelDuplicate_ReportsError() { var source = """ class C { void M() { L: while (true) { break L; } L: while (true) { } } } """; CreateCompilation(source).VerifyDiagnostics( // (6,9): error CS0140: The label 'L' is a duplicate // L: while (true) { } Diagnostic(ErrorCode.ERR_DuplicateLabel, "L").WithArguments("L").WithLocation(6, 9)); } #endregion #region Top-level statements: error cases [Fact] public void Break_TopLevelStatements_UnknownLabel() { var source = """ outer: while (true) { break missing; } """; CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (1,1): warning CS0164: This label has not been referenced // outer: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(1, 1), // (3,11): error CS9393: No enclosing loop or switch statement with the label 'missing' out of which to breake // break missing; Diagnostic(ErrorCode.ERR_NoBreakId, "missing").WithArguments("missing").WithLocation(3, 11)); } [Fact] public void Continue_TopLevelStatements_UnknownLabel() { var source = """ outer: while (true) { continue missing; } """; CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (1,1): warning CS0164: This label has not been referenced // outer: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(1, 1), // (3,14): error CS9394: No enclosing loop with the label 'missing' out of which to continue // continue missing; Diagnostic(ErrorCode.ERR_NoContinueId, "missing").WithArguments("missing").WithLocation(3, 14)); } [Fact] public void Break_TopLevelStatements_LabeledJumpOutsideAnyLoop() { var source = """ L: ; break L; """; CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (2,7): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(2, 7)); } #endregion #region Ref foreach [Fact] public void Break_RefForeach_Labeled() { var source = """ using System; class C { void M(Span<int> items) { outer: foreach (ref int x in items) { foreach (ref int y in items) { if (y == 0) break outer; } } } } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(); } [Fact] public void Continue_RefForeach_Labeled() { var source = """ using System; class C { void M(Span<int> items) { outer: foreach (ref int x in items) { foreach (ref int y in items) { if (y == 0) continue outer; } } } } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(); } #endregion #region Out-var in loop condition [Fact] public void Break_OutVarInCondition_Labeled() { var source = """ class C { bool Filter(out int i) { i = 0; return true; } void M() { outer: while (Filter(out var i)) { while (Filter(out var j)) { if (i + j > 10) break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Continue_OutVarInCondition_Labeled() { var source = """ class C { bool Filter(out int i) { i = 0; return true; } void M() { outer: while (Filter(out var i)) { while (Filter(out var j)) { if (i + j > 10) continue outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Labeled break/continue in if without enclosing loop [Fact] public void Break_IfWithoutEnclosingLoop_Labeled() { var source = """ class C { void M(bool b) { if (b) break outer; } } """; CreateCompilation(source).VerifyDiagnostics( // (5,22): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // if (b) break outer; Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(5, 22)); } [Fact] public void Continue_IfWithoutEnclosingLoop_Labeled() { var source = """ class C { void M(bool b) { if (b) continue outer; } } """; CreateCompilation(source).VerifyDiagnostics( // (5,25): error CS9394: No enclosing loop with the label 'outer' out of which to continue // if (b) continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(5, 25)); } #endregion #region Primary constructor parameter capture [Fact] public void LabeledBreakContinue_DoesNotCapturePrimaryConstructorParameter() { // The label identifiers in `break p1;` / `continue p2;` are label references, // not value references to the same-named primary-constructor parameters, so // the parameters should be reported as unread (no capture). var source = """ class C(int p1, int p2) { void M() { p1: while (true) { break p1; } p2: foreach (var x in new[] { 1 }) { continue p2; } } } """; CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyEmitDiagnostics( // (1,13): warning CS9113: Parameter 'p1' is unread. // class C(int p1, int p2) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p1").WithArguments("p1").WithLocation(1, 13), // (1,21): warning CS9113: Parameter 'p2' is unread. // class C(int p1, int p2) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p2").WithArguments("p2").WithLocation(1, 21)); } #endregion #region Definite assignment [Fact] public void DefiniteAssignment_BreakOuter_CarriesAssignmentOutOfLoop() { var source = """ class C { int M(bool b) { int x; outer: while (true) { while (true) { x = 1; break outer; } } return x; } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void DefiniteAssignment_BreakOuter_NotAssignedOnJumpPath_ReportsCS0165() { var source = """ class C { int M(bool b) { int x; outer: while (true) { while (true) { if (b) break outer; x = 1; } } return x; } } """; CreateCompilation(source).VerifyDiagnostics( // (16,16): error CS0165: Use of unassigned local variable 'x' // return x; Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(16, 16)); } [Fact] public void DefiniteAssignment_ContinueOuter_SkipsOuterAssignment_ReportsCS0165() { var source = """ class C { void M(bool b) { outer: while (b) { int x; while (b) { continue outer; } x = 1; System.Console.WriteLine(x); } } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void DefiniteAssignment_OutParameter_AssignedOnlyViaBreakOuter() { var source = """ class C { void M(bool b, out int x) { outer: while (true) { while (true) { x = 1; break outer; } } } } """; CreateCompilation(source).VerifyDiagnostics(); } #endregion #region Nullable reference type flow [Fact] public void Nullable_BreakOuter_NarrowedStateFlowsPastLoop() { var source = """ #nullable enable class C { void M(string? s) { outer: while (true) { while (true) { if (s != null) break outer; } } s.ToString(); } } """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void Nullable_BreakOuter_MaybeNullStateFlowsPastLoop_ReportsCS8602() { var source = """ #nullable enable class C { void M(string? s, bool b) { outer: while (true) { while (true) { if (b) break outer; } } s.ToString(); } } """; CreateCompilation(source).VerifyDiagnostics( // (15,9): warning CS8602: Dereference of a possibly null reference. // s.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(15, 9)); } [Fact] public void Nullable_ContinueOuter_BackEdgeMergesState() { var source = """ #nullable enable class C { void M(bool b) { string? s = "start"; outer: while (b) { s.ToString(); s = null; while (b) { s = "inner"; continue outer; } } } } """; CreateCompilation(source).VerifyDiagnostics( // (9,13): warning CS8602: Dereference of a possibly null reference. // s.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(9, 13)); } #endregion #region Interactions: stackalloc/Span and expression trees [Fact] public void Span_StackallocInLoop_BreakOuter_NoRefSafetyError() { var source = """ using System; class C { void M(bool b) { outer: while (b) { Span<int> s = stackalloc int[4]; s[0] = 1; while (b) { if (b) break outer; } } } } """; CreateCompilationWithMscorlibAndSpan(source).VerifyDiagnostics(); } [Fact] public void ExpressionTree_StatementLambdaWithLabeledBreak_ReportsStatementBodyError() { var source = """ using System; using System.Linq.Expressions; class C { void M() { Expression<Action> e = () => { outer: while (true) { break outer; } }; } } """; CreateCompilation(source).VerifyDiagnostics( // (7,32): error CS0834: A lambda expression with a statement body cannot be converted to an expression tree // Expression<Action> e = () => Diagnostic(ErrorCode.ERR_StatementLambdaToExpressionTree, """ () => { outer: while (true) { break outer; } } """).WithLocation(7, 32)); } #endregion #region Resolved-label-as-target side effects // These tests document the diagnostics when a labeled break/continue's label resolves but isn't a valid // target (lambda/iterator/finally/switch-section/etc.). [Fact] public void Break_InsideLambda_LabelOutside_LeaksBadDelegateLeave() { var source = """ using System; class C { void M() { outer: while (true) { Action a = () => { break outer; }; } } } """; CreateCompilation(source).VerifyDiagnostics( // (6,9): warning CS0164: This label has not been referenced // outer: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(6, 9), // (8,32): error CS1632: Control cannot leave the body of an anonymous method or lambda expression // Action a = () => { break outer; }; Diagnostic(ErrorCode.ERR_BadDelegateLeave, "break").WithLocation(8, 32)); } [Fact] public void Continue_InsideAsyncLambda_LabelOutside_LeaksBadDelegateLeave() { var source = """ using System; using System.Threading.Tasks; class C { void M() { outer: while (true) { Func<Task> a = async () => { await Task.Yield(); continue outer; }; } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,9): warning CS0164: This label has not been referenced // outer: while (true) Diagnostic(ErrorCode.WRN_UnreferencedLabel, "outer").WithLocation(7, 9), // (9,62): error CS1632: Control cannot leave the body of an anonymous method or lambda expression // Func<Task> a = async () => { await Task.Yield(); continue outer; }; Diagnostic(ErrorCode.ERR_BadDelegateLeave, "continue").WithLocation(9, 62)); } [Fact] public void Break_InsideIterator_LabelOutside_StillReportsUnreachableCode() { var source = """ using System.Collections.Generic; class C { IEnumerable<int> M() { outer: while (true) { yield return 1; } while (true) break outer; } } """; CreateCompilation(source).VerifyDiagnostics( // (10,9): warning CS0162: Unreachable code detected // while (true) break outer; Diagnostic(ErrorCode.WRN_UnreachableCode, "while").WithLocation(10, 9), // (10,28): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // while (true) break outer; Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(10, 28)); } [Fact] public void Break_InsideFinally_LabelOnOuterBlock_LeaksControlCannotLeaveFinally() { var source = """ class C { void M() { L: try { } finally { break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (8,13): error CS0157: Control cannot leave the body of a finally clause // break L; Diagnostic(ErrorCode.ERR_BadFinallyLeave, "break").WithLocation(8, 13), // (8,19): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(8, 19)); } [Fact] public void Break_InSwitchSection_LabelInDifferentSection_LabelTreatedAsReferenced() { var source = """ class C { void M(int x) { switch (x) { case 0: L: break; case 1: break L; } } } """; CreateCompilation(source).VerifyDiagnostics( // (10,23): error CS9393: No enclosing loop or switch statement with the label 'L' out of which to break // break L; Diagnostic(ErrorCode.ERR_NoBreakId, "L").WithArguments("L").WithLocation(10, 23)); } [Fact] public void Continue_TargetOnSwitch_SuppressesSwitchFallOutAndUnreferencedLabel() { var source = """ class C { void M(int x) { outer: switch (x) { default: continue outer; } } } """; CreateCompilation(source).VerifyDiagnostics( // (7,31): error CS9394: No enclosing loop with the label 'outer' out of which to continue // default: continue outer; Diagnostic(ErrorCode.ERR_NoContinueId, "outer").WithArguments("outer").WithLocation(7, 31)); } [Fact] public void Break_LabelOnFollowingLoop_SuppressesUnreachableCodeAndUnreferencedLabel() { var source = """ class C { void M() { while (true) { break outer; } outer: while (false) { } } } """; CreateCompilation(source).VerifyDiagnostics( // (5,30): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // while (true) { break outer; } Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(5, 30)); } [Fact] public void GetSymbolInfo_BreakWithBadTarget_SemanticModelStillResolvesIdentifier() { var source = """ class C { void M() { outer: while (true) { void F() { break outer; } F(); } } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,30): error CS9393: No enclosing loop or switch statement with the label 'outer' out of which to break // void F() { break outer; } Diagnostic(ErrorCode.ERR_NoBreakId, "outer").WithArguments("outer").WithLocation(7, 30)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var labelDecl = tree.GetRoot().DescendantNodes().OfType<LabeledStatementSyntax>().Single(); var declaredSymbol = model.GetDeclaredSymbol(labelDecl); var breakSyntax = tree.GetRoot().DescendantNodes().OfType<BreakStatementSyntax>().Single(b => b.Name is not null); Assert.Same(declaredSymbol, model.GetSymbolInfo(breakSyntax.Name!).Symbol); } #endregion }