Skip to content

Commit 5a5f00a

Browse files
authored
Merge pull request #58864 from hamishknight/irregular-grammar-5.7-04182022
2 parents 56ccc6d + 7009be5 commit 5a5f00a

File tree

4 files changed

+48
-0
lines changed

4 files changed

+48
-0
lines changed

include/swift/Basic/SourceManager.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/Basic/FileSystem.h"
1717
#include "swift/Basic/SourceLoc.h"
1818
#include "clang/Basic/FileManager.h"
19+
#include "llvm/ADT/DenseSet.h"
1920
#include "llvm/ADT/Optional.h"
2021
#include "llvm/Support/SourceMgr.h"
2122
#include <map>
@@ -55,6 +56,10 @@ class SourceManager {
5556
/// reusing compilation.
5657
llvm::DenseMap<SourceRange, SourceRange> ReplacedRanges;
5758

59+
/// The starting source locations of regex literals written in source. This
60+
/// is an unfortunate hack needed to allow for correct re-lexing.
61+
llvm::DenseSet<SourceLoc> RegexLiteralStartLocs;
62+
5863
std::map<const char *, VirtualFile> VirtualFiles;
5964
mutable std::pair<const char *, const VirtualFile*> CachedVFile = {nullptr, nullptr};
6065

@@ -107,6 +112,17 @@ class SourceManager {
107112
ReplacedRanges[Orig] = New;
108113
}
109114

115+
/// Record the starting source location of a regex literal.
116+
void recordRegexLiteralStartLoc(SourceLoc loc) {
117+
RegexLiteralStartLocs.insert(loc);
118+
}
119+
120+
/// Checks whether a given source location is for the start of a regex
121+
/// literal.
122+
bool isRegexLiteralStart(SourceLoc loc) const {
123+
return RegexLiteralStartLocs.contains(loc);
124+
}
125+
110126
/// Returns true if \c LHS is before \c RHS in the source buffer.
111127
bool isBeforeInBuffer(SourceLoc LHS, SourceLoc RHS) const {
112128
return LHS.Value.getPointer() < RHS.Value.getPointer();

lib/Parse/Lexer.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2685,6 +2685,16 @@ Token Lexer::getTokenAtLocation(const SourceManager &SM, SourceLoc Loc,
26852685
// we need to lex just the comment token.
26862686
Lexer L(FakeLangOpts, SM, BufferID, nullptr, LexerMode::Swift,
26872687
HashbangMode::Allowed, CRM);
2688+
2689+
if (SM.isRegexLiteralStart(Loc)) {
2690+
// HACK: If this was previously lexed as a regex literal, make sure we
2691+
// re-lex with forward slash regex literals enabled to make sure we get an
2692+
// accurate length. We can force EnableExperimentalStringProcessing on, as
2693+
// we know it must have been enabled to parse the regex in the first place.
2694+
FakeLangOpts.EnableExperimentalStringProcessing = true;
2695+
L.ForwardSlashRegexMode = LexerForwardSlashRegexMode::Always;
2696+
}
2697+
26882698
L.restoreState(State(Loc));
26892699
return L.peekNextToken();
26902700
}

lib/Parse/ParseRegex.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ ParserResult<Expr> Parser::parseExprRegexLiteral() {
5252
/*captureStructureOut*/ capturesBuf.data(),
5353
/*captureStructureSize*/ capturesBuf.size());
5454
auto loc = consumeToken();
55+
SourceMgr.recordRegexLiteralStartLoc(loc);
56+
5557
if (errorStr) {
5658
diagnose(loc, diag::regex_literal_parsing_error, errorStr);
5759
return makeParserResult(new (Context) ErrorExpr(loc));
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-typecheck-verify-swift -enable-bare-slash-regex -disable-availability-checking
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
postfix operator ^^
6+
postfix func ^^ <T> (_ x: T) -> T { x }
7+
8+
prefix operator !!
9+
prefix func !! <T> (_ x: T) -> T { x }
10+
11+
// rdar://92469692 - Make sure we get a correct fix-it location here.
12+
func foo<T>(_ x: T, y: Int) {} // expected-note 3{{'foo(_:y:)' declared here}}
13+
foo(/a/) // expected-error {{missing argument for parameter 'y' in call}} {{8-8=, y: <#Int#>}}
14+
foo(/, /) // expected-error {{missing argument for parameter 'y' in call}} {{9-9=, y: <#Int#>}}
15+
foo(/a/^^) // expected-error {{missing argument for parameter 'y' in call}} {{10-10=, y: <#Int#>}}
16+
17+
func bar<T>(x: Int, _ y: T) {} // expected-note 3{{'bar(x:_:)' declared here}}
18+
bar(/a/) // expected-error {{missing argument for parameter 'x' in call}} {{5-5=x: <#Int#>, }}
19+
bar(/, /) // expected-error {{missing argument for parameter 'x' in call}} {{5-5=x: <#Int#>, }}
20+
bar(!!/a/) // expected-error {{missing argument for parameter 'x' in call}} {{5-5=x: <#Int#>, }}

0 commit comments

Comments
 (0)