Skip to content

Commit 7d1da2a

Browse files
authored
Merge pull request #5243 from milseman/escaping
[3.0 compat] Don't diagnose @escaping var-arg closures.
2 parents 4e83034 + 12fb0ba commit 7d1da2a

File tree

7 files changed

+36
-2
lines changed

7 files changed

+36
-2
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,9 @@ class ASTContext {
784784
clang::ObjCInterfaceDecl *classDecl,
785785
bool forInstance);
786786

787+
/// Whether our effective Swift version is in the Swift 3 family
788+
bool isSwiftVersion3() const { return LangOpts.isSwiftVersion3(); }
789+
787790
private:
788791
friend class Decl;
789792
Optional<RawComment> getRawComment(const Decl *D);

include/swift/Basic/LangOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@ namespace swift {
227227
return CustomConditionalCompilationFlags;
228228
}
229229

230+
/// Whether our effective Swift version is in the Swift 3 family
231+
bool isSwiftVersion3() const {
232+
return EffectiveLanguageVersion.isVersion3();
233+
}
234+
230235
/// Returns true if the 'os' platform condition argument represents
231236
/// a supported target operating system.
232237
///

include/swift/Basic/Version.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ class Version {
9595
/// are attempting to maintain backward-compatibility support for.
9696
bool isValidEffectiveLanguageVersion() const;
9797

98+
/// Whether this version is in the Swift 3 family
99+
bool isVersion3() const { return !empty() && Components[0] == 3; }
100+
98101
/// Parse a version in the form used by the _compiler_version \#if condition.
99102
static Version parseCompilerVersionString(StringRef VersionString,
100103
SourceLoc Loc,

lib/Basic/Version.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,13 @@ Version::isValidEffectiveLanguageVersion() const
291291
// Whitelist of backward-compatibility versions that we permit passing as
292292
// -swift-version <vers>
293293
char const *whitelist[] = {
294+
// Swift 3 family
294295
"3",
295296
"3.0",
297+
298+
// Swift 4 family
299+
"4",
300+
"4.0",
296301
};
297302
for (auto const i : whitelist) {
298303
auto v = parseVersionString(i, SourceLoc(), nullptr);

lib/Sema/TypeCheckType.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2032,8 +2032,14 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
20322032
// Handle @escaping
20332033
if (hasFunctionAttr && ty->is<FunctionType>()) {
20342034
if (attrs.has(TAK_escaping)) {
2035+
// For compatibility with 3.0, we don't emit an error if it appears on a
2036+
// variadic argument list.
2037+
bool skipDiagnostic =
2038+
isVariadicFunctionParam && Context.isSwiftVersion3();
2039+
20352040
// The attribute is meaningless except on parameter types.
2036-
if (!isFunctionParam) {
2041+
bool shouldDiagnose = !isFunctionParam && !skipDiagnostic;
2042+
if (shouldDiagnose) {
20372043
auto &SM = TC.Context.SourceMgr;
20382044
auto loc = attrs.getLoc(TAK_escaping);
20392045
auto attrRange = SourceRange(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
// This is allowed, in order to keep source compat with Swift version 3.0.
4+
func takesVarargsOfFunctionsExplicitEscaping(_ fns: @escaping () -> ()...) {}
5+
6+
func takesVarargsOfFunctions(_ fn: () -> (), _ fns: () -> ()...) {
7+
// expected-note@-1{{parameter 'fn' is implicitly non-escaping}}
8+
takesVarargsOfFunctionsExplicitEscaping(fns[0], fns[1]) // ok
9+
takesVarargsOfFunctionsExplicitEscaping(fn) // expected-error{{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
10+
}

test/attr/attr_escaping.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-parse-verify-swift
1+
// RUN: %target-parse-verify-swift -swift-version 4
22

33
@escaping var fn : () -> Int = { 4 } // expected-error {{attribute can only be applied to types, not declarations}}
44
func paramDeclEscaping(@escaping fn: (Int) -> Void) {} // expected-error {{attribute can only be applied to types, not declarations}}
@@ -140,6 +140,8 @@ func takesVarargsOfFunctions(fns: () -> ()...) {
140140
}
141141
}
142142

143+
func takesVarargsOfFunctionsExplicitEscaping(fns: @escaping () -> ()...) {} // expected-error{{@escaping attribute may only be used in function parameter position}}
144+
143145
func takesNoEscapeFunction(fn: () -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}}
144146
takesVarargsOfFunctions(fns: fn) // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
145147
}

0 commit comments

Comments
 (0)