Skip to content

Commit 7b0d845

Browse files
committed
[ast][silgen] Wire up the case body var decls and use them in SILGenPattern emission to fix the evil fallthrough bug.
rdar://47467128
1 parent ed94b13 commit 7b0d845

File tree

11 files changed

+385
-123
lines changed

11 files changed

+385
-123
lines changed

include/swift/Parse/Parser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,11 +689,11 @@ class Parser {
689689
swift::ScopeInfo &getScopeInfo() { return State->getScopeInfo(); }
690690

691691
/// Add the given Decl to the current scope.
692-
void addToScope(ValueDecl *D) {
692+
void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true) {
693693
if (Context.LangOpts.EnableASTScopeLookup)
694694
return;
695695

696-
getScopeInfo().addToScope(D, *this);
696+
getScopeInfo().addToScope(D, *this, diagnoseRedefinitions);
697697
}
698698

699699
ValueDecl *lookupInScope(DeclName Name) {

include/swift/Parse/Scope.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class ScopeInfo {
5252

5353
/// addToScope - Register the specified decl as being in the current lexical
5454
/// scope.
55-
void addToScope(ValueDecl *D, Parser &TheParser);
55+
void addToScope(ValueDecl *D, Parser &TheParser,
56+
bool diagnoseRedefinitions = true);
5657

5758
bool isInactiveConfigBlock() const;
5859

lib/AST/ASTVerifier.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,20 @@ class Verifier : public ASTWalker {
25002500
}
25012501
}
25022502

2503+
if (auto *caseStmt =
2504+
dyn_cast_or_null<CaseStmt>(var->getRecursiveParentPatternStmt())) {
2505+
// In a type checked AST, a case stmt that is a recursive parent pattern
2506+
// stmt of a var decl, must have bound decls. This is because we
2507+
// guarantee that all case label items bind corresponding patterns and
2508+
// the case body var decls of a case stmt are created from the var decls
2509+
// of the first case label items.
2510+
if (!caseStmt->hasBoundDecls()) {
2511+
Out << "parent CaseStmt of VarDecl does not have any case body "
2512+
"decls?!\n";
2513+
abort();
2514+
}
2515+
}
2516+
25032517
verifyCheckedBase(var);
25042518
}
25052519

lib/AST/Decl.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,14 +1294,6 @@ VarDecl *PatternBindingInitializer::getInitializedLazyVar() const {
12941294
return nullptr;
12951295
}
12961296

1297-
static bool patternContainsVarDeclBinding(const Pattern *P, const VarDecl *VD) {
1298-
bool Result = false;
1299-
P->forEachVariable([&](VarDecl *FoundVD) {
1300-
Result |= FoundVD == VD;
1301-
});
1302-
return Result;
1303-
}
1304-
13051297
unsigned PatternBindingDecl::getPatternEntryIndexForVarDecl(const VarDecl *VD) const {
13061298
assert(VD && "Cannot find a null VarDecl");
13071299

lib/AST/NameLookup.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,8 +2347,14 @@ void FindLocalVal::visitCaseStmt(CaseStmt *S) {
23472347
}
23482348
}
23492349
}
2350-
if (!inPatterns && !items.empty())
2351-
checkPattern(items[0].getPattern(), DeclVisibilityKind::LocalVariable);
2350+
2351+
if (!inPatterns && !items.empty()) {
2352+
if (auto caseBodyVars = S->getCaseBodyVariables()) {
2353+
for (auto *vd : *caseBodyVars) {
2354+
checkValueDecl(vd, DeclVisibilityKind::LocalVariable);
2355+
}
2356+
}
2357+
}
23522358
visit(S->getBody());
23532359
}
23542360

lib/Parse/ParseStmt.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,20 @@ ParserResult<CaseStmt> Parser::parseStmtCase(bool IsActive) {
24762476

24772477
assert(!CaseLabelItems.empty() && "did not parse any labels?!");
24782478

2479+
// Add a scope so that the parser can find our body bound decls if it emits
2480+
// optimized accesses.
2481+
Optional<Scope> BodyScope;
2482+
if (CaseBodyDecls) {
2483+
BodyScope.emplace(this, ScopeKind::CaseVars);
2484+
for (auto *v : *CaseBodyDecls) {
2485+
setLocalDiscriminator(v);
2486+
// If we had any bad redefinitions, we already diagnosed them against the
2487+
// first case label item.
2488+
if (v->hasName())
2489+
addToScope(v, false /*diagnoseRedefinitions*/);
2490+
}
2491+
}
2492+
24792493
SmallVector<ASTNode, 8> BodyItems;
24802494

24812495
SourceLoc StartOfBody = Tok.getLoc();

lib/Parse/Scope.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ static bool checkValidOverload(const ValueDecl *D1, const ValueDecl *D2,
104104

105105
/// addToScope - Register the specified decl as being in the current lexical
106106
/// scope.
107-
void ScopeInfo::addToScope(ValueDecl *D, Parser &TheParser) {
107+
void ScopeInfo::addToScope(ValueDecl *D, Parser &TheParser,
108+
bool diagnoseRedefinitions) {
108109
if (!CurScope->isResolvable())
109110
return;
110111

@@ -121,9 +122,13 @@ void ScopeInfo::addToScope(ValueDecl *D, Parser &TheParser) {
121122

122123
// If this is in a resolvable scope, diagnose redefinitions. Later
123124
// phases will handle scopes like module-scope, etc.
124-
if (CurScope->getDepth() >= ResolvableDepth)
125-
return TheParser.diagnoseRedefinition(PrevDecl, D);
126-
125+
if (CurScope->getDepth() >= ResolvableDepth) {
126+
if (diagnoseRedefinitions) {
127+
return TheParser.diagnoseRedefinition(PrevDecl, D);
128+
}
129+
return;
130+
}
131+
127132
// If this is at top-level scope, validate that the members of the overload
128133
// set all agree.
129134

lib/SILGen/SILGenPattern.cpp

Lines changed: 77 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,12 @@ class PatternMatchEmission {
445445

446446
void emitCaseBody(CaseStmt *caseBlock);
447447

448+
SILValue getAddressOnlyTemporary(VarDecl *decl) {
449+
auto found = Temporaries.find(decl);
450+
assert(found != Temporaries.end());
451+
return found->second;
452+
}
453+
448454
private:
449455
void emitWildcardDispatch(ClauseMatrix &matrix, ArgArray args, unsigned row,
450456
const FailureHandler &failure);
@@ -2326,16 +2332,12 @@ void PatternMatchEmission::initSharedCaseBlockDest(CaseStmt *caseBlock,
23262332
auto *block = SGF.createBasicBlock();
23272333
result.first->second.first = block;
23282334

2329-
// If we do not have any bound decls, we do not need to setup any phi
2330-
// arguments for the shared case block. Just bail early.
2331-
if (!caseBlock->hasBoundDecls()) {
2335+
// Add args for any pattern variables
2336+
auto caseBodyVars = caseBlock->getCaseBodyVariables();
2337+
if (!caseBodyVars)
23322338
return;
2333-
}
23342339

2335-
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2336-
SmallVector<VarDecl *, 4> patternVarDecls;
2337-
pattern->collectVariables(patternVarDecls);
2338-
for (auto *vd : patternVarDecls) {
2340+
for (auto *vd : *caseBodyVars) {
23392341
if (!vd->hasName())
23402342
continue;
23412343

@@ -2363,39 +2365,18 @@ void PatternMatchEmission::emitAddressOnlyAllocations() {
23632365
for (auto &entry : SharedCases) {
23642366
CaseStmt *caseBlock = entry.first;
23652367

2366-
// If we do not have any bound decls, we can bail early.
2367-
if (!caseBlock->hasBoundDecls()) {
2368+
auto caseBodyVars = caseBlock->getCaseBodyVariables();
2369+
if (!caseBodyVars)
23682370
continue;
2369-
}
23702371

2371-
// If we have a shared case with bound decls, then the 0th pattern has the
2372-
// order of variables that are the incoming BB arguments. Setup the VarLocs
2373-
// to point to the incoming args and setup initialization so any args needing
2374-
// cleanup will get that as well.
2375-
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2376-
SmallVector<VarDecl *, 4> patternVarDecls;
2377-
pattern->collectVariables(patternVarDecls);
2378-
for (auto *vd : patternVarDecls) {
2372+
// If we have a shared case with bound decls, setup the arguments for the
2373+
// shared block by emitting the temporary allocation used for the arguments
2374+
// of the shared block.
2375+
for (auto *vd : *caseBodyVars) {
23792376
if (!vd->hasName())
23802377
continue;
23812378

23822379
SILType ty = SGF.getLoweredType(vd->getType());
2383-
if (ty.isNull()) {
2384-
// If we're making the shared block on behalf of a previous case's
2385-
// fallthrough, caseBlock's VarDecl's won't be in the SGF yet, so
2386-
// determine phi types by using current vars of the same name.
2387-
for (auto var : SGF.VarLocs) {
2388-
auto varDecl = dyn_cast<VarDecl>(var.getFirst());
2389-
if (!varDecl || !varDecl->hasName() ||
2390-
varDecl->getName() != vd->getName())
2391-
continue;
2392-
ty = var.getSecond().value->getType();
2393-
if (var.getSecond().box) {
2394-
ty = ty.getObjectType();
2395-
}
2396-
}
2397-
}
2398-
23992380
if (!ty.isAddressOnly(SGF.F.getModule()))
24002381
continue;
24012382
assert(!Temporaries[vd]);
@@ -2455,23 +2436,19 @@ void PatternMatchEmission::emitSharedCaseBlocks() {
24552436
assert(SGF.getCleanupsDepth() == PatternMatchStmtDepth);
24562437
SWIFT_DEFER { assert(SGF.getCleanupsDepth() == PatternMatchStmtDepth); };
24572438

2458-
// If we do not have any bound decls, just emit the case body since we do
2459-
// not need to setup any var locs.
2460-
if (!caseBlock->hasBoundDecls()) {
2439+
auto caseBodyVars = caseBlock->getCaseBodyVariables();
2440+
if (!caseBodyVars) {
24612441
emitCaseBody(caseBlock);
24622442
continue;
24632443
}
24642444

2465-
// If we have a shared case with bound decls, then the 0th pattern has the
2466-
// order of variables that are the incoming BB arguments. Setup the VarLocs
2467-
// to point to the incoming args and setup initialization so any args
2468-
// needing cleanup will get that as well.
2445+
// If we have a shared case with bound decls, then the case stmt pattern has
2446+
// the order of variables that are the incoming BB arguments. Setup the
2447+
// VarLocs to point to the incoming args and setup initialization so any
2448+
// args needing Cleanup will get that as well.
24692449
Scope scope(SGF.Cleanups, CleanupLocation(caseBlock));
2470-
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2471-
SmallVector<VarDecl *, 4> patternVarDecls;
2472-
pattern->collectVariables(patternVarDecls);
24732450
unsigned argIndex = 0;
2474-
for (auto *vd : patternVarDecls) {
2451+
for (auto *vd : *caseBodyVars) {
24752452
if (!vd->hasName())
24762453
continue;
24772454

@@ -2622,10 +2599,33 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
26222599

26232600
// Certain case statements can be entered along multiple paths, either because
26242601
// they have multiple labels or because of fallthrough. When we need multiple
2625-
// entrance path, we factor the paths with a shared block. If we don't have a
2626-
// fallthrough or a multi-pattern 'case', we can just emit the body inline and
2627-
// save some dead blocks. Emit the statement here and bail early.
2602+
// entrance path, we factor the paths with a shared block.
2603+
//
2604+
// If we don't have a fallthrough or a multi-pattern 'case', we can emit the
2605+
// body inline. Emit the statement here and bail early.
26282606
if (!row.hasFallthroughTo() && caseBlock->getCaseLabelItems().size() == 1) {
2607+
// If we have case body vars, set them up to point at the matching var
2608+
// decls.
2609+
if (auto caseBodyVars = caseBlock->getCaseBodyVariables()) {
2610+
// Since we know that we only have one case label item, grab its pattern
2611+
// vars and use that to update expected with the right SILValue.
2612+
//
2613+
// TODO: Do we need a copy here?
2614+
SmallVector<VarDecl *, 4> patternVars;
2615+
row.getCasePattern()->collectVariables(patternVars);
2616+
for (auto *expected : *caseBodyVars) {
2617+
if (!expected->hasName())
2618+
continue;
2619+
for (auto *vd : patternVars) {
2620+
if (!vd->hasName() || vd->getName() != expected->getName()) {
2621+
continue;
2622+
}
2623+
2624+
// Ok, we found a match. Update the VarLocs for the case block.
2625+
SGF.VarLocs[expected] = SGF.VarLocs[vd];
2626+
}
2627+
}
2628+
}
26292629
emission.emitCaseBody(caseBlock);
26302630
return;
26312631
}
@@ -2639,7 +2639,10 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
26392639

26402640
// If we do not have any bound decls, we do not need to setup any
26412641
// variables. Just jump to the shared destination.
2642-
if (!caseBlock->hasBoundDecls()) {
2642+
auto caseBodyVars = caseBlock->getCaseBodyVariables();
2643+
if (!caseBodyVars) {
2644+
// Don't emit anything yet, we emit it at the cleanup level of the switch
2645+
// statement.
26432646
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock);
26442647
SGF.Cleanups.emitBranchAndCleanups(sharedDest, caseBlock);
26452648
return;
@@ -2650,18 +2653,14 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
26502653
// +1 along to the shared case block dest. (The cleanups still happen, as they
26512654
// are threaded through here messily, but the explicit retains here counteract
26522655
// them, and then the retain/release pair gets optimized out.)
2653-
ArrayRef<CaseLabelItem> labelItems = caseBlock->getCaseLabelItems();
26542656
SmallVector<SILValue, 4> args;
2655-
SmallVector<VarDecl *, 4> expectedVarOrder;
2656-
SmallVector<VarDecl *, 4> vars;
2657-
labelItems[0].getPattern()->collectVariables(expectedVarOrder);
2658-
row.getCasePattern()->collectVariables(vars);
2659-
26602657
SILModule &M = SGF.F.getModule();
2661-
for (auto expected : expectedVarOrder) {
2658+
SmallVector<VarDecl *, 4> patternVars;
2659+
row.getCasePattern()->collectVariables(patternVars);
2660+
for (auto *expected : *caseBodyVars) {
26622661
if (!expected->hasName())
26632662
continue;
2664-
for (auto *var : vars) {
2663+
for (auto *var : patternVars) {
26652664
if (!var->hasName() || var->getName() != expected->getName())
26662665
continue;
26672666

@@ -2690,6 +2689,7 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
26902689
}
26912690
}
26922691

2692+
// Now that we have initialized our arguments, branch to the shared dest.
26932693
SGF.Cleanups.emitBranchAndCleanups(sharedDest, caseBlock, args);
26942694
}
26952695

@@ -2837,45 +2837,46 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
28372837
void SILGenFunction::emitSwitchFallthrough(FallthroughStmt *S) {
28382838
assert(!SwitchStack.empty() && "fallthrough outside of switch?!");
28392839
PatternMatchContext *context = SwitchStack.back();
2840-
2840+
28412841
// Get the destination block.
2842-
CaseStmt *caseStmt = S->getFallthroughDest();
2843-
JumpDest sharedDest =
2844-
context->Emission.getSharedCaseBlockDest(caseStmt);
2842+
CaseStmt *destCaseStmt = S->getFallthroughDest();
2843+
JumpDest sharedDest = context->Emission.getSharedCaseBlockDest(destCaseStmt);
28452844

2846-
if (!caseStmt->hasBoundDecls()) {
2845+
// If our destination case doesn't have any bound decls, there is no rebinding
2846+
// to do. Just jump to the shared dest.
2847+
auto destCaseBodyVars = destCaseStmt->getCaseBodyVariables();
2848+
if (!destCaseBodyVars) {
28472849
Cleanups.emitBranchAndCleanups(sharedDest, S);
28482850
return;
28492851
}
28502852

28512853
// Generate branch args to pass along current vars to fallthrough case.
28522854
SILModule &M = F.getModule();
2853-
ArrayRef<CaseLabelItem> labelItems = caseStmt->getCaseLabelItems();
28542855
SmallVector<SILValue, 4> args;
2855-
SmallVector<VarDecl *, 4> expectedVarOrder;
2856-
labelItems[0].getPattern()->collectVariables(expectedVarOrder);
2856+
CaseStmt *fallthroughSourceStmt = S->getFallthroughSource();
28572857

2858-
for (auto *expected : expectedVarOrder) {
2858+
for (auto *expected : *destCaseBodyVars) {
28592859
if (!expected->hasName())
28602860
continue;
2861-
for (auto var : VarLocs) {
2862-
auto varDecl = dyn_cast<VarDecl>(var.getFirst());
2863-
if (!varDecl || !varDecl->hasName() ||
2864-
varDecl->getName() != expected->getName()) {
2861+
2862+
// The type checker enforces that if our destination case has variables then
2863+
// our fallthrough source must as well.
2864+
for (auto *var : *fallthroughSourceStmt->getCaseBodyVariables()) {
2865+
if (!var->hasName() || var->getName() != expected->getName()) {
28652866
continue;
28662867
}
28672868

2868-
SILValue value = var.getSecond().value;
2869+
auto varLoc = VarLocs[var];
2870+
SILValue value = varLoc.value;
28692871

28702872
if (value->getType().isAddressOnly(M)) {
28712873
context->Emission.emitAddressOnlyInitialization(expected, value);
28722874
break;
28732875
}
28742876

2875-
if (var.getSecond().box) {
2876-
auto &lowering = getTypeLowering(value->getType());
2877-
auto argValue = lowering.emitLoad(B, CurrentSILLoc, value,
2878-
LoadOwnershipQualifier::Copy);
2877+
if (varLoc.box) {
2878+
SILValue argValue = B.emitLoadValueOperation(
2879+
CurrentSILLoc, value, LoadOwnershipQualifier::Copy);
28792880
args.push_back(argValue);
28802881
break;
28812882
}

0 commit comments

Comments
 (0)