Skip to content

Commit ae711a7

Browse files
committed
Fix a Family of Crashers in Availability Checking
NIO exposed an issue in the new availability walkers where an implicit check was not being performed. They were able to get this to crash by using a defer statement - the body of which contains implicit declarations that got run through the walker. This exposed a wider hole in availability checking of defer statements. Namely, that it wasn't happening. Let's dilute the meaning of `isImplicit` in the availability walkers to account for this desugaring. rdar://74484150
1 parent 997f410 commit ae711a7

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ static void computeExportContextBits(ASTContext &Ctx, Decl *D,
147147
if (D->isSPI())
148148
*spi = true;
149149

150-
if (D->isImplicit())
150+
// Defer bodies are desugared to an implicit closure expression. We need to
151+
// dilute the meaning of "implicit" to make sure we're still checking
152+
// availability inside of defer statements.
153+
const auto isDeferBody = isa<FuncDecl>(D) && cast<FuncDecl>(D)->isDeferBody();
154+
if (D->isImplicit() && !isDeferBody)
151155
*implicit = true;
152156

153157
if (D->getAttrs().getDeprecated(Ctx))

test/Sema/availability.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,32 @@ struct VarToFunc {
195195
}
196196
}
197197

198+
struct DeferBody {
199+
func foo() {
200+
enum No: Error {
201+
case no
202+
}
203+
204+
defer {
205+
do {
206+
throw No.no
207+
} catch No.no {
208+
} catch {
209+
}
210+
}
211+
_ = ()
212+
}
213+
214+
func bar() {
215+
@available(*, unavailable)
216+
enum No: Error { // expected-note 2 {{'No' has been explicitly marked unavailable here}}
217+
case no
218+
}
219+
do {
220+
throw No.no
221+
// expected-error@-1 {{'No' is unavailable}}
222+
} catch No.no {} catch _ {}
223+
// expected-error@-1 {{'No' is unavailable}}
224+
}
225+
}
226+

test/attr/attr_inlinable.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,12 @@ public struct PrivateInlinableCrash {
357357
// expected-error@-2 {{initializer 'init()' is private and cannot be referenced from an '@inlinable' function}}
358358
}
359359
}
360+
361+
// Just make sure we don't crash.
362+
private func deferBodyTestCall() {} // expected-note {{global function 'deferBodyTestCall()' is not '@usableFromInline' or public}}
363+
@inlinable public func deferBodyTest() {
364+
defer {
365+
deferBodyTestCall() // expected-error {{global function 'deferBodyTestCall()' is private and cannot be referenced from an '@inlinable' function}}
366+
}
367+
_ = ()
368+
}

0 commit comments

Comments
 (0)