Skip to content

Commit 4cdac3f

Browse files
committed
Don't add variables declared in 'guard let' to a SourceFile's Decls.
These variables really are local variables -- they have have a TopLevelCodeDecl as their DeclContext rather than the SourceFile. Treating them as global variables caused crashes in serialization. We need an overhaul of top-level variables in script files anyway (see rdar://problem/20992489&21628526), but this fixes the immediate issue. rdar://problem/21928533 Swift SVN r30519
1 parent 9bedabe commit 4cdac3f

File tree

5 files changed

+58
-11
lines changed

5 files changed

+58
-11
lines changed

lib/AST/NameLookup.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ struct FindLocalVal : public StmtVisitor<FindLocalVal> {
344344
void checkSourceFile(const SourceFile &SF) {
345345
for (Decl *D : SF.Decls) {
346346
if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(D))
347-
visit(TLCD->getBody());
347+
visitBraceStmt(TLCD->getBody(), /*isTopLevel=*/true);
348348
}
349349
}
350350

@@ -364,6 +364,17 @@ struct FindLocalVal : public StmtVisitor<FindLocalVal> {
364364
visit(S->getElseStmt());
365365
}
366366
void visitGuardStmt(GuardStmt *S) {
367+
if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
368+
return;
369+
370+
// Names in the guard aren't visible until after the pattern.
371+
if (!IntersectsRange(S->getBody()->getSourceRange())) {
372+
for (const StmtConditionElement &condition : S->getCond()) {
373+
if (auto *pattern = condition.getPatternOrNull())
374+
checkPattern(pattern, DeclVisibilityKind::LocalVariable);
375+
}
376+
}
377+
367378
visit(S->getBody());
368379
}
369380
void visitIfConfigStmt(IfConfigStmt *S) {
@@ -413,9 +424,15 @@ struct FindLocalVal : public StmtVisitor<FindLocalVal> {
413424
visit(S->getBody());
414425
checkPattern(S->getPattern(), DeclVisibilityKind::LocalVariable);
415426
}
416-
void visitBraceStmt(BraceStmt *S) {
417-
if (!IntersectsRange(S->getSourceRange()))
418-
return;
427+
void visitBraceStmt(BraceStmt *S, bool isTopLevelCode = false) {
428+
if (isTopLevelCode) {
429+
if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
430+
return;
431+
} else {
432+
if (!IntersectsRange(S->getSourceRange()))
433+
return;
434+
}
435+
419436
for (auto elem : S->getElements()) {
420437
if (Stmt *S = elem.dyn_cast<Stmt*>())
421438
visit(S);

lib/Parse/ParseStmt.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,16 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
370370

371371
// If the parsed stmt was a GuardStmt, push the VarDecls into the
372372
// Entries list, so that they can be found by unqual name lookup later.
373-
if (auto guard = dyn_cast_or_null<GuardStmt>(Result.dyn_cast<Stmt*>())){
374-
for (const auto &elt : guard->getCond()) {
375-
if (!elt.getPatternOrNull()) continue;
376-
377-
elt.getPattern()->forEachVariable([&](VarDecl *VD) {
378-
Entries.push_back(VD);
379-
});
373+
if (!IsTopLevel) {
374+
auto resultStmt = Result.dyn_cast<Stmt*>();
375+
if (auto guard = dyn_cast_or_null<GuardStmt>(resultStmt)) {
376+
for (const auto &elt : guard->getCond()) {
377+
if (!elt.getPatternOrNull()) continue;
378+
379+
elt.getPattern()->forEachVariable([&](VarDecl *VD) {
380+
Entries.push_back(VD);
381+
});
382+
}
380383
}
381384
}
382385
}

test/Parse/guard-top-level.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
let a: Int? = 1
4+
guard let b = a else {
5+
}
6+
7+
func foo() {} // to interrupt the TopLevelCodeDecl
8+
9+
let c = b
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
func use(x: Int) {}
2+
func test() {
3+
use(a!)
4+
use(b) // expected-error {{use of unresolved identifier 'b'}}
5+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: rm -rf %t && mkdir %t
2+
// RUN: %target-swift-frontend -emit-module -o %t %s -module-name Test
3+
// RUN: llvm-bcanalyzer %t/Test.swiftmodule | FileCheck %s
4+
5+
// RUN: cp %s %t/main.swift
6+
// RUN: %target-swift-frontend -parse -verify %t/main.swift -primary-file %S/Inputs/top-level-code-other.swift
7+
8+
// CHECK-NOT: UnknownCode
9+
10+
let a: Int? = 1
11+
guard let b = a else {
12+
fatalError()
13+
}

0 commit comments

Comments
 (0)