Skip to content

Commit 9753d7c

Browse files
authored
Merge pull request swiftlang#75540 from hamishknight/skip-loc
[Parse] Avoid skipping bodies with `#sourceLocation`
2 parents 5819c31 + a657f97 commit 9753d7c

File tree

4 files changed

+82
-15
lines changed

4 files changed

+82
-15
lines changed

include/swift/Parse/Parser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,13 @@ class Parser {
156156
/// Whether this context has an async attribute.
157157
bool InPatternWithAsyncAttribute = false;
158158

159+
/// Whether a '#sourceLocation' is currently active.
160+
/// NOTE: Do not use this outside of `parseLineDirective`, it doesn't have
161+
/// its state restored when parsing delayed bodies (we avoid skipping bodies
162+
/// if we see a `#sourceLocation` in them though). Instead, query the
163+
/// SourceManager.
159164
bool InPoundLineEnvironment = false;
165+
160166
bool InPoundIfEnvironment = false;
161167
/// ASTScopes are not created in inactive clauses and lookups to decls will fail.
162168
bool InInactiveClauseEnvironment = false;

lib/Parse/ParseDecl.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5620,11 +5620,13 @@ static void diagnoseOperatorFixityAttributes(Parser &P,
56205620

56215621
static unsigned skipUntilMatchingRBrace(Parser &P,
56225622
bool &HasPoundDirective,
5623+
bool &HasPoundSourceLocation,
56235624
bool &HasOperatorDeclarations,
56245625
bool &HasNestedClassDeclarations,
56255626
bool &HasNestedTypeDeclarations,
56265627
bool &HasPotentialRegexLiteral) {
56275628
HasPoundDirective = false;
5629+
HasPoundSourceLocation = false;
56285630
HasOperatorDeclarations = false;
56295631
HasNestedClassDeclarations = false;
56305632
HasNestedTypeDeclarations = false;
@@ -5646,8 +5648,11 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
56465648

56475649
HasNestedClassDeclarations |= P.Tok.is(tok::kw_class);
56485650

5649-
HasPoundDirective |= P.Tok.isAny(tok::pound_sourceLocation, tok::pound_line,
5650-
tok::pound_if, tok::pound_else, tok::pound_endif, tok::pound_elseif);
5651+
HasPoundSourceLocation |= P.Tok.isAny(tok::pound_sourceLocation,
5652+
tok::pound_line);
5653+
HasPoundDirective |= HasPoundSourceLocation;
5654+
HasPoundDirective |= P.Tok.isAny(tok::pound_if, tok::pound_else,
5655+
tok::pound_endif, tok::pound_elseif);
56515656

56525657
HasNestedTypeDeclarations |= P.Tok.isAny(tok::kw_class, tok::kw_struct,
56535658
tok::kw_enum, tok::kw_typealias,
@@ -7080,25 +7085,27 @@ bool Parser::canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
70807085
// If explicitly disabled, respect the flag.
70817086
if (!isDelayedParsingEnabled())
70827087
return false;
7083-
// Recovering parser status later for #sourceLocation is not-trivial and
7084-
// it may not worth it.
7085-
if (InPoundLineEnvironment)
7086-
return false;
70877088

70887089
// Skip until the matching right curly bracket; if we find a pound directive,
70897090
// we can't lazily parse.
70907091
CancellableBacktrackingScope BackTrack(*this);
70917092
bool HasPoundDirective;
7093+
bool HasPoundSourceLocation;
70927094
bool HasNestedTypeDeclarations;
70937095
bool HasPotentialRegexLiteral;
70947096
skipUntilMatchingRBrace(*this,
70957097
HasPoundDirective,
7098+
HasPoundSourceLocation,
70967099
HasOperatorDeclarations,
70977100
HasNestedClassDeclarations,
70987101
HasNestedTypeDeclarations,
70997102
HasPotentialRegexLiteral);
7100-
if (!HasPoundDirective && !HasPotentialRegexLiteral)
7103+
if (!HasPoundDirective && !HasPotentialRegexLiteral) {
7104+
// If we didn't see any pound directive, we must not have seen
7105+
// #sourceLocation either.
7106+
ASSERT(!HasPoundSourceLocation);
71017107
BackTrack.cancelBacktrack();
7108+
}
71027109
return !BackTrack.willBacktrack();
71037110
}
71047111

@@ -7694,17 +7701,20 @@ bool Parser::canDelayFunctionBodyParsing(bool &HasNestedTypeDeclarations) {
76947701
return false;
76957702

76967703
// Skip until the matching right curly bracket; If it has a potential regex
7697-
// literal, we can't skip. We don't care others, so just ignore them;
7704+
// literal, we can't skip. If there's a `#sourceLocation`, we also can't skip
7705+
// since we rely on setting and restoring state in the parser. Other cases we
7706+
// can handle.
76987707
CancellableBacktrackingScope BackTrack(*this);
76997708
consumeToken(tok::l_brace);
77007709
bool HasPoundDirectives;
7710+
bool HasPoundSourceLocation;
77017711
bool HasOperatorDeclarations;
77027712
bool HasNestedClassDeclarations;
77037713
bool HasPotentialRegexLiteral;
7704-
skipUntilMatchingRBrace(*this, HasPoundDirectives, HasOperatorDeclarations,
7705-
HasNestedClassDeclarations, HasNestedTypeDeclarations,
7706-
HasPotentialRegexLiteral);
7707-
if (HasPotentialRegexLiteral)
7714+
skipUntilMatchingRBrace(*this, HasPoundDirectives, HasPoundSourceLocation,
7715+
HasOperatorDeclarations, HasNestedClassDeclarations,
7716+
HasNestedTypeDeclarations, HasPotentialRegexLiteral);
7717+
if (HasPoundSourceLocation || HasPotentialRegexLiteral)
77087718
return false;
77097719

77107720
BackTrack.cancelBacktrack();
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Note we use '--implicit-check-not' to ensure we exhaustively match errors.
2+
// RUN: not %target-swift-frontend -parse -experimental-skip-all-function-bodies -diagnostic-style=llvm %s 2>&1 | %FileCheck --implicit-check-not='error:' %s
3+
4+
// We cannot skip function bodies with #sourceLocation.
5+
func foo() {
6+
// CHECK: [[@LINE+1]]:4: error: expected expression
7+
[;
8+
#sourceLocation(file: "A", line: 1)
9+
[;
10+
// CHECK: A:1:4: error: expected expression
11+
}
12+
13+
func bar() {
14+
// CHECK: A:7:4: error: expected expression
15+
[;
16+
#sourceLocation()
17+
[;
18+
// CHECK: [[@LINE-1]]:4: error: expected expression
19+
}
20+
21+
// This function body is skipped.
22+
func baz() {
23+
[;
24+
}
25+
26+
// This member list and function are not skipped.
27+
struct S {
28+
func qux() {
29+
// CHECK: [[@LINE+1]]:6: error: expected expression
30+
[;
31+
#sourceLocation(file: "B", line: 1)
32+
[;
33+
// CHECK: B:1:6: error: expected expression
34+
}
35+
func ;
36+
// CHECK: B:4:8: error: expected identifier
37+
}
38+
39+
// This member list is also not skipped.
40+
struct R {
41+
// CHECK: B:11:8: error: expected identifier
42+
func ;
43+
44+
#sourceLocation()
45+
46+
func ;
47+
// CHECK: [[@LINE-1]]:8: error: expected identifier
48+
}
49+
50+
// This member list is skipped.
51+
struct Q {
52+
[;
53+
}

test/Parse/issue-74561.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
// Make sure we can parse with and without skipping.
44
// RUN: %target-typecheck-verify-swift
5-
// RUN: not %target-swift-frontend -emit-module -experimental-skip-non-inlinable-function-bodies -module-name Mod -emit-module-path %t/Mod.swiftmodule -diagnostic-style=llvm %s 2>&1 | %FileCheck %s
5+
// RUN: %target-swift-frontend -verify -emit-module -experimental-skip-non-inlinable-function-bodies -module-name Mod -emit-module-path %t/Mod.swiftmodule %s
66

77
// https://github.com/swiftlang/swift/issues/74561
88
// Make sure we can parse this.
@@ -11,10 +11,8 @@ public func foo(_ param: Int) {
1111
#sourceLocation()
1212
}
1313

14-
// FIXME: This should parse correctly.
1514
#sourceLocation(file: "B", line: 3)
1615
@inlinable
1716
public func bar(_ param: Int) {
1817
#sourceLocation()
1918
}
20-
// CHECK: B:6:1: error: parameterless closing #sourceLocation() directive without prior opening #sourceLocation(file:,line:) directive

0 commit comments

Comments
 (0)