Skip to content

Commit 8e6dc39

Browse files
committed
Parse: Keep track of top-level declarations that follow a 'guard' statement
1 parent 04bf432 commit 8e6dc39

File tree

4 files changed

+53
-6
lines changed

4 files changed

+53
-6
lines changed

include/swift/AST/Decl.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ class alignas(1 << DeclAlignInBits) Decl {
399399
HasSingleExpressionBody : 1
400400
);
401401

402-
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2,
402+
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1,
403403
/// Whether we've computed the 'static' flag yet.
404404
IsStaticComputed : 1,
405405

@@ -416,7 +416,12 @@ class alignas(1 << DeclAlignInBits) Decl {
416416
SelfAccessComputed : 1,
417417

418418
/// Backing bits for 'self' access kind.
419-
SelfAccess : 2
419+
SelfAccess : 2,
420+
421+
/// Whether this is a top-level function which should be treated
422+
/// as if it were in local context for the purposes of capture
423+
/// analysis.
424+
HasTopLevelLocalContextCaptures : 1
420425
);
421426

422427
SWIFT_INLINE_BITFIELD(AccessorDecl, FuncDecl, 4+1+1,
@@ -6078,6 +6083,7 @@ class FuncDecl : public AbstractFunctionDecl {
60786083
Bits.FuncDecl.SelfAccessComputed = false;
60796084
Bits.FuncDecl.IsStaticComputed = false;
60806085
Bits.FuncDecl.IsStatic = false;
6086+
Bits.FuncDecl.HasTopLevelLocalContextCaptures = false;
60816087
}
60826088

60836089
private:
@@ -6235,6 +6241,12 @@ class FuncDecl : public AbstractFunctionDecl {
62356241
/// Perform basic checking to determine whether the @IBAction or
62366242
/// @IBSegueAction attribute can be applied to this function.
62376243
bool isPotentialIBActionTarget() const;
6244+
6245+
bool hasTopLevelLocalContextCaptures() const {
6246+
return Bits.FuncDecl.HasTopLevelLocalContextCaptures;
6247+
}
6248+
6249+
void setHasTopLevelLocalContextCaptures(bool hasCaptures=true);
62386250
};
62396251

62406252
/// This represents an accessor function, such as a getter or setter.

include/swift/Parse/Parser.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,11 +856,19 @@ class Parser {
856856
void consumeTopLevelDecl(ParserPosition BeginParserPosition,
857857
TopLevelCodeDecl *TLCD);
858858

859+
ParserStatus parseBraceItems(SmallVectorImpl<ASTNode> &Decls,
860+
BraceItemListKind Kind,
861+
BraceItemListKind ConditionalBlockKind,
862+
bool &IsFollowingGuard);
859863
ParserStatus parseBraceItems(SmallVectorImpl<ASTNode> &Decls,
860864
BraceItemListKind Kind =
861865
BraceItemListKind::Brace,
862866
BraceItemListKind ConditionalBlockKind =
863-
BraceItemListKind::Brace);
867+
BraceItemListKind::Brace) {
868+
bool IsFollowingGuard = false;
869+
return parseBraceItems(Decls, Kind, ConditionalBlockKind,
870+
IsFollowingGuard);
871+
}
864872
ParserResult<BraceStmt> parseBraceItemList(Diag<> ID);
865873

866874
//===--------------------------------------------------------------------===//

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7669,6 +7669,12 @@ bool FuncDecl::isPotentialIBActionTarget() const {
76697669
!isa<AccessorDecl>(this);
76707670
}
76717671

7672+
void FuncDecl::setHasTopLevelLocalContextCaptures(bool hasCaptures) {
7673+
assert(!hasCaptures || isa<SourceFile>(getDeclContext()));
7674+
7675+
Bits.FuncDecl.HasTopLevelLocalContextCaptures = hasCaptures;
7676+
}
7677+
76727678
Type TypeBase::getSwiftNewtypeUnderlyingType() {
76737679
auto structDecl = getStructOrBoundGenericStruct();
76747680
if (!structDecl)

lib/Parse/ParseStmt.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ void Parser::consumeTopLevelDecl(ParserPosition BeginParserPosition,
271271
/// expr '=' expr
272272
ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
273273
BraceItemListKind Kind,
274-
BraceItemListKind ConditionalBlockKind) {
274+
BraceItemListKind ConditionalBlockKind,
275+
bool &IsFollowingGuard) {
275276
bool isRootCtx = SyntaxContext->isRoot();
276277
SyntaxParsingContext ItemListContext(SyntaxContext,
277278
SyntaxKind::CodeBlockItemList);
@@ -364,7 +365,8 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
364365
[&](SmallVectorImpl<ASTNode> &Elements, bool IsActive) {
365366
parseBraceItems(Elements, Kind, IsActive
366367
? BraceItemListKind::ActiveConditionalBlock
367-
: BraceItemListKind::InactiveConditionalBlock);
368+
: BraceItemListKind::InactiveConditionalBlock,
369+
IsFollowingGuard);
368370
});
369371
if (IfConfigResult.hasCodeCompletion() && isCodeCompletionFirstPass()) {
370372
consumeDecl(BeginParserPosition, None, IsTopLevel);
@@ -401,7 +403,18 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
401403
ParserResult<Decl> DeclResult =
402404
parseDecl(IsTopLevel ? PD_AllowTopLevel : PD_Default,
403405
IsAtStartOfLineOrPreviousHadSemi,
404-
[&](Decl *D) {TmpDecls.push_back(D);});
406+
[&](Decl *D) {
407+
TmpDecls.push_back(D);
408+
409+
// Any function after a 'guard' statement is marked as
410+
// possibly having local captures. This allows SILGen
411+
// to correctly determine its capture list, since
412+
// otherwise it would be skipped because it is not
413+
// defined inside a local context.
414+
if (IsFollowingGuard)
415+
if (auto *FD = dyn_cast<FuncDecl>(D))
416+
FD->setHasTopLevelLocalContextCaptures();
417+
});
405418
BraceItemsStatus |= DeclResult;
406419
if (DeclResult.isParseError()) {
407420
NeedParseErrorRecovery = true;
@@ -451,6 +464,14 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
451464
Result, Result.getEndLoc());
452465
TLCD->setBody(Brace);
453466
Entries.push_back(TLCD);
467+
468+
// A top-level 'guard' statement can introduce local bindings, so we
469+
// must mark all functions following one. This makes them behave
470+
// as if they were in local context for the purposes of capture
471+
// emission in SILGen.
472+
if (auto *stmt = Result.dyn_cast<Stmt *>())
473+
if (isa<GuardStmt>(stmt))
474+
IsFollowingGuard = true;
454475
}
455476
} else if (Tok.is(tok::kw_init) && isa<ConstructorDecl>(CurDeclContext)) {
456477
SourceLoc StartLoc = Tok.getLoc();

0 commit comments

Comments
 (0)