Skip to content

Commit a657f97

Browse files
committed
[Parse] Avoid skipping bodies with #sourceLocation
`#sourceLocation` requires setting and restoring state in the parser, so we cannot skip any bodies containing `#sourceLocation` tokens. Member skipping was already doing this, extend it to function body skipping too.
1 parent 1bd2a9b commit a657f97

File tree

3 files changed

+76
-11
lines changed

3 files changed

+76
-11
lines changed

lib/Parse/ParseDecl.cpp

+22-8
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,
@@ -7085,16 +7090,22 @@ bool Parser::canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
70857090
// we can't lazily parse.
70867091
CancellableBacktrackingScope BackTrack(*this);
70877092
bool HasPoundDirective;
7093+
bool HasPoundSourceLocation;
70887094
bool HasNestedTypeDeclarations;
70897095
bool HasPotentialRegexLiteral;
70907096
skipUntilMatchingRBrace(*this,
70917097
HasPoundDirective,
7098+
HasPoundSourceLocation,
70927099
HasOperatorDeclarations,
70937100
HasNestedClassDeclarations,
70947101
HasNestedTypeDeclarations,
70957102
HasPotentialRegexLiteral);
7096-
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);
70977107
BackTrack.cancelBacktrack();
7108+
}
70987109
return !BackTrack.willBacktrack();
70997110
}
71007111

@@ -7690,17 +7701,20 @@ bool Parser::canDelayFunctionBodyParsing(bool &HasNestedTypeDeclarations) {
76907701
return false;
76917702

76927703
// Skip until the matching right curly bracket; If it has a potential regex
7693-
// 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.
76947707
CancellableBacktrackingScope BackTrack(*this);
76957708
consumeToken(tok::l_brace);
76967709
bool HasPoundDirectives;
7710+
bool HasPoundSourceLocation;
76977711
bool HasOperatorDeclarations;
76987712
bool HasNestedClassDeclarations;
76997713
bool HasPotentialRegexLiteral;
7700-
skipUntilMatchingRBrace(*this, HasPoundDirectives, HasOperatorDeclarations,
7701-
HasNestedClassDeclarations, HasNestedTypeDeclarations,
7702-
HasPotentialRegexLiteral);
7703-
if (HasPotentialRegexLiteral)
7714+
skipUntilMatchingRBrace(*this, HasPoundDirectives, HasPoundSourceLocation,
7715+
HasOperatorDeclarations, HasNestedClassDeclarations,
7716+
HasNestedTypeDeclarations, HasPotentialRegexLiteral);
7717+
if (HasPoundSourceLocation || HasPotentialRegexLiteral)
77047718
return false;
77057719

77067720
BackTrack.cancelBacktrack();
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

+1-3
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)