Skip to content

Commit a9f26ab

Browse files
committed
Don't crash when using @unknown default with a non-enum type.
Also improve the error message when using it with a very large space. https://bugs.swift.org/browse/SR-7408
1 parent 15a04fc commit a9f26ab

File tree

5 files changed

+76
-3
lines changed

5 files changed

+76
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3925,6 +3925,9 @@ NOTE(missing_several_cases,none,
39253925
NOTE(missing_unknown_case,none,
39263926
"handle unknown values using \"@unknown default\"", ())
39273927

3928+
NOTE(non_exhaustive_switch_drop_unknown,none,
3929+
"remove '@unknown' to handle remaining values", ())
3930+
39283931
NOTE(missing_particular_case,none,
39293932
"add missing case: '%0'", (StringRef))
39303933
WARNING(redundant_particular_case,none,

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,10 +1342,25 @@ namespace {
13421342

13431343
// Decide whether we want an error or a warning.
13441344
auto mainDiagType = diag::non_exhaustive_switch;
1345-
if (!uncovered.isEmpty() && unknownCase) {
1346-
assert(defaultReason == RequiresDefault::No);
1347-
mainDiagType = diag::non_exhaustive_switch_warn;
1345+
if (unknownCase) {
1346+
switch (defaultReason) {
1347+
case RequiresDefault::EmptySwitchBody:
1348+
llvm_unreachable("there's an @unknown case; the body can't be empty");
1349+
case RequiresDefault::No:
1350+
if (!uncovered.isEmpty())
1351+
mainDiagType = diag::non_exhaustive_switch_warn;
1352+
break;
1353+
case RequiresDefault::UncoveredSwitch:
1354+
case RequiresDefault::SpaceTooLarge:
1355+
TC.diagnose(startLoc, diag::non_exhaustive_switch);
1356+
TC.diagnose(unknownCase->getLoc(),
1357+
diag::non_exhaustive_switch_drop_unknown)
1358+
.fixItRemoveChars(unknownCase->getStartLoc(),
1359+
unknownCase->getLoc());
1360+
return;
1361+
}
13481362
}
1363+
13491364
switch (uncovered.checkDowngradeToWarning()) {
13501365
case DowngradeToWarning::No:
13511366
break;

test/Compatibility/exhaustive_switch.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,21 @@ func quiteBigEnough() -> Bool {
473473
case (.case10, _): return true
474474
}
475475

476+
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) { // expected-error {{switch must be exhaustive}}
477+
case (.case0, _): return true
478+
case (.case1, _): return true
479+
case (.case2, _): return true
480+
case (.case3, _): return true
481+
case (.case4, _): return true
482+
case (.case5, _): return true
483+
case (.case6, _): return true
484+
case (.case7, _): return true
485+
case (.case8, _): return true
486+
case (.case9, _): return true
487+
case (.case10, _): return true
488+
@unknown default: return false // expected-note {{remove '@unknown' to handle remaining values}} {{3-12=}}
489+
}
490+
476491

477492
// No diagnostic
478493
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) {
@@ -526,6 +541,10 @@ func quiteBigEnough() -> Bool {
526541
case .two: return true
527542
case .three: return true
528543
}
544+
545+
// Make sure we haven't just stopped emitting diagnostics.
546+
switch OverlyLargeSpaceEnum.case1 { // expected-error {{switch must be exhaustive}} expected-note 12 {{add missing case}} expected-note {{handle unknown values}}
547+
}
529548
}
530549

531550
indirect enum InfinitelySized {

test/Parse/switch.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,3 +522,20 @@ switch Whatever.Thing { // expected-warning {{switch must be exhaustive}} expect
522522
case _:
523523
break
524524
}
525+
526+
switch x { // expected-error {{switch must be exhaustive}}
527+
case 1:
528+
break
529+
@unknown case _: // expected-note {{remove '@unknown' to handle remaining values}} {{1-10=}}
530+
break
531+
}
532+
533+
switch x { // expected-error {{switch must be exhaustive}}
534+
@unknown case _: // expected-note {{remove '@unknown' to handle remaining values}} {{1-10=}}
535+
break
536+
}
537+
538+
switch x { // expected-error {{switch must be exhaustive}}
539+
@unknown default: // expected-note {{remove '@unknown' to handle remaining values}} {{1-10=}}
540+
break
541+
}

test/Sema/exhaustive_switch.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,21 @@ func quiteBigEnough() -> Bool {
472472
case (.case10, _): return true
473473
}
474474

475+
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) { // expected-error {{switch must be exhaustive}}
476+
case (.case0, _): return true
477+
case (.case1, _): return true
478+
case (.case2, _): return true
479+
case (.case3, _): return true
480+
case (.case4, _): return true
481+
case (.case5, _): return true
482+
case (.case6, _): return true
483+
case (.case7, _): return true
484+
case (.case8, _): return true
485+
case (.case9, _): return true
486+
case (.case10, _): return true
487+
@unknown default: return false // expected-note {{remove '@unknown' to handle remaining values}} {{3-12=}}
488+
}
489+
475490

476491
// No diagnostic
477492
switch (OverlyLargeSpaceEnum.case1, OverlyLargeSpaceEnum.case2) {
@@ -525,6 +540,10 @@ func quiteBigEnough() -> Bool {
525540
case .two: return true
526541
case .three: return true
527542
}
543+
544+
// Make sure we haven't just stopped emitting diagnostics.
545+
switch OverlyLargeSpaceEnum.case1 { // expected-error {{switch must be exhaustive}} expected-note 12 {{add missing case}} expected-note {{handle unknown values}}
546+
}
528547
}
529548

530549
indirect enum InfinitelySized {

0 commit comments

Comments
 (0)