Skip to content

Commit f4b4db6

Browse files
authored
Merge pull request #74041 from jckarter/diagnose-unimplemented-shared-noncopyable-case-patterns
SILGen: Diagnose unsupported shared case blocks for noncopyable switch subjects.
2 parents 847e959 + 44483be commit f4b4db6

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,5 +1038,8 @@ NOTE(lifetime_outside_scope_use, none,
10381038
NOTE(lifetime_outside_scope_escape, none,
10391039
"this use causes the lifetime-dependent value to escape", ())
10401040

1041+
ERROR(noncopyable_shared_case_block_unimplemented, none,
1042+
"matching a non-'Copyable' value using a case label that has multiple patterns is not implemented", ())
1043+
10411044
#define UNDEFINE_DIAGNOSTIC_MACROS
10421045
#include "DefineDiagnosticMacros.h"

lib/SILGen/SILGenPattern.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,8 @@ class PatternMatchEmission {
457457
void emitDestructiveCaseBlocks();
458458

459459
JumpDest getSharedCaseBlockDest(CaseStmt *caseStmt);
460-
void emitSharedCaseBlocks(llvm::function_ref<void(CaseStmt *)> bodyEmitter);
460+
void emitSharedCaseBlocks(ValueOwnership ownership,
461+
llvm::function_ref<void(CaseStmt *)> bodyEmitter);
461462

462463
void emitCaseBody(CaseStmt *caseBlock);
463464

@@ -2790,8 +2791,13 @@ void PatternMatchEmission::emitDestructiveCaseBlocks() {
27902791
// TODO: handle fallthroughs and multiple cases bindings
27912792
// In those cases we'd need to forward bindings through the shared case
27922793
// destination blocks.
2793-
assert(!stmt->hasFallthroughDest()
2794-
&& stmt->getCaseLabelItems().size() == 1);
2794+
if (stmt->hasFallthroughDest()
2795+
|| stmt->getCaseLabelItems().size() != 1) {
2796+
// This should already have been diagnosed as unsupported, so just emit
2797+
// an unreachable here.
2798+
SGF.B.createUnreachable(stmt);
2799+
continue;
2800+
}
27952801

27962802
// Bind variables from the pattern.
27972803
if (stmt->hasCaseBodyVariables()) {
@@ -2899,7 +2905,21 @@ emitAddressOnlyInitialization(VarDecl *dest, SILValue value) {
28992905

29002906
/// Emit all the shared case statements.
29012907
void PatternMatchEmission::emitSharedCaseBlocks(
2908+
ValueOwnership ownership,
29022909
llvm::function_ref<void(CaseStmt *)> bodyEmitter) {
2910+
if (ownership >= ValueOwnership::Shared
2911+
&& !SharedCases.empty()) {
2912+
SGF.SGM.diagnose(SharedCases.front().first,
2913+
diag::noncopyable_shared_case_block_unimplemented);
2914+
2915+
for (auto &entry : SharedCases) {
2916+
SILBasicBlock *caseBB = entry.second.first;
2917+
SGF.B.setInsertionPoint(caseBB);
2918+
SGF.B.createUnreachable(entry.first);
2919+
}
2920+
2921+
return;
2922+
}
29032923
for (auto &entry : SharedCases) {
29042924
CaseStmt *caseBlock = entry.first;
29052925
SILBasicBlock *caseBB = entry.second.first;
@@ -3742,7 +3762,7 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
37423762
}
37433763

37443764
// Then emit the case blocks shared by multiple pattern cases.
3745-
emission.emitSharedCaseBlocks(
3765+
emission.emitSharedCaseBlocks(ownership,
37463766
[&](CaseStmt *caseStmt) { emission.emitCaseBody(caseStmt); });
37473767

37483768
// Bookkeeping.
@@ -4015,7 +4035,8 @@ void SILGenFunction::emitCatchDispatch(DoCatchStmt *S, ManagedValue exn,
40154035
stmtScope.pop();
40164036

40174037
// Then emit the case blocks shared by multiple pattern cases.
4018-
emission.emitSharedCaseBlocks([&](CaseStmt *caseStmt) {
4038+
emission.emitSharedCaseBlocks(ValueOwnership::Default,
4039+
[&](CaseStmt *caseStmt) {
40194040
emitStmt(caseStmt->getBody());
40204041

40214042
// If we fell out of the catch clause, branch to the fallthrough dest.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %target-swift-emit-silgen -verify %s
2+
3+
struct Inner: ~Copyable {}
4+
enum Outer: ~Copyable { case value(Inner, Int) }
5+
6+
func borrow(_: borrowing Inner) {}
7+
func consume(_: consuming Inner) {}
8+
9+
func foo(x: borrowing Outer) {
10+
switch x {
11+
case .value(let y, 0), // expected-error{{not implemented}}
12+
.value(let y, _):
13+
borrow(y)
14+
}
15+
16+
}
17+
18+
func bar(x: borrowing Outer) {
19+
switch x {
20+
case .value(let y, 0):
21+
borrow(y)
22+
fallthrough
23+
24+
case .value(let y, _): // expected-error{{not implemented}}
25+
borrow(y)
26+
}
27+
28+
}
29+
30+
func zim(x: consuming Outer) {
31+
switch consume x {
32+
case .value(let y, 0), // expected-error{{not implemented}}
33+
.value(let y, _):
34+
consume(y)
35+
}
36+
37+
}
38+
39+
func zang(x: consuming Outer) {
40+
switch consume x {
41+
case .value(let y, 0):
42+
// should eventually test that this gets diagnosed as a double-consume
43+
//consume(y)
44+
fallthrough
45+
46+
case .value(let y, _): // expected-error{{not implemented}}
47+
consume(y)
48+
}
49+
50+
}

0 commit comments

Comments
 (0)