Skip to content

Commit 01a3263

Browse files
committed
Sema: Ensure that use of availability macros in closures in fragile functions is diagnosed.
Type checking of closure bodies does not invoke `TypeChecker::typeCheckStmtConditionElement()` so use of availability macros inside closure bodies written in fragile (inlinable) functions was undiagnosed. Move the diagnostic logic to `MiscDiagnostics.cpp` which implements diagnostics that are emitted regardless of the typechecking model used. Additionally, remove the `DC->getAsDecl() != nullptr` check from `diagnoseHasSymbolCondition()` which was preventing similar fragile function diagnostics for `if #_hasSymbol` from being emitted when a closure was involved. Resolves rdar://100581013
1 parent 4205446 commit 01a3263

File tree

4 files changed

+64
-39
lines changed

4 files changed

+64
-39
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4390,6 +4390,32 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
43904390
}
43914391
}
43924392

4393+
/// Diagnoses a `if #available(...)` condition. Returns true if a diagnostic
4394+
/// was emitted.
4395+
static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info,
4396+
DeclContext *DC) {
4397+
// Reject inlinable code using availability macros. In order to lift this
4398+
// restriction, macros would need to either be expanded when printed in
4399+
// swiftinterfaces or be parsable as macros by module clients.
4400+
auto fragileKind = DC->getFragileFunctionKind();
4401+
if (fragileKind.kind != FragileFunctionKind::None) {
4402+
for (auto queries : info->getQueries()) {
4403+
if (auto availSpec =
4404+
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(queries)) {
4405+
if (availSpec->getMacroLoc().isValid()) {
4406+
DC->getASTContext().Diags.diagnose(
4407+
availSpec->getMacroLoc(),
4408+
swift::diag::availability_macro_in_inlinable,
4409+
fragileKind.getSelector());
4410+
return true;
4411+
}
4412+
}
4413+
}
4414+
}
4415+
4416+
return false;
4417+
}
4418+
43934419
/// Diagnoses a `if #_hasSymbol(...)` condition. Returns true if a diagnostic
43944420
/// was emitted.
43954421
static bool diagnoseHasSymbolCondition(PoundHasSymbolInfo *info,
@@ -4416,21 +4442,19 @@ static bool diagnoseHasSymbolCondition(PoundHasSymbolInfo *info,
44164442
return true;
44174443
}
44184444

4419-
if (DC->getAsDecl()) {
4420-
auto fragileKind = DC->getFragileFunctionKind();
4421-
if (fragileKind.kind != FragileFunctionKind::None) {
4422-
// #_hasSymbol cannot be used in inlinable code because of limitations of
4423-
// the current implementation strategy. It relies on recording the
4424-
// referenced ValueDecl, mangling a helper function name using that
4425-
// ValueDecl, and then passing the responsibility of generating the
4426-
// definition for that helper function to IRGen. In order to lift this
4427-
// restriction, we will need teach SIL to encode the ValueDecl, or take
4428-
// another approach entirely.
4429-
ctx.Diags.diagnose(info->getStartLoc(),
4430-
diag::has_symbol_condition_in_inlinable,
4431-
fragileKind.getSelector());
4432-
return true;
4433-
}
4445+
auto fragileKind = DC->getFragileFunctionKind();
4446+
if (fragileKind.kind != FragileFunctionKind::None) {
4447+
// #_hasSymbol cannot be used in inlinable code because of limitations of
4448+
// the current implementation strategy. It relies on recording the
4449+
// referenced ValueDecl, mangling a helper function name using that
4450+
// ValueDecl, and then passing the responsibility of generating the
4451+
// definition for that helper function to IRGen. In order to lift this
4452+
// restriction, we will need teach SIL to encode the ValueDecl, or take
4453+
// another approach entirely.
4454+
ctx.Diags.diagnose(info->getStartLoc(),
4455+
diag::has_symbol_condition_in_inlinable,
4456+
fragileKind.getSelector());
4457+
return true;
44344458
}
44354459

44364460
auto decl = info->getReferencedDecl().getDecl();
@@ -4465,9 +4489,12 @@ static void checkLabeledStmtConditions(ASTContext &ctx,
44654489
switch (elt.getKind()) {
44664490
case StmtConditionElement::CK_Boolean:
44674491
case StmtConditionElement::CK_PatternBinding:
4468-
case StmtConditionElement::CK_Availability:
44694492
break;
4470-
4493+
case StmtConditionElement::CK_Availability: {
4494+
auto info = elt.getAvailability();
4495+
(void)diagnoseAvailabilityCondition(info, DC);
4496+
break;
4497+
}
44714498
case StmtConditionElement::CK_HasSymbol: {
44724499
auto info = elt.getHasSymbolInfo();
44734500
if (diagnoseHasSymbolCondition(info, DC))

lib/Sema/TypeCheckStmt.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -471,24 +471,6 @@ bool TypeChecker::typeCheckStmtConditionElement(StmtConditionElement &elt,
471471
// Typecheck a #available or #unavailable condition.
472472
if (elt.getKind() == StmtConditionElement::CK_Availability) {
473473
isFalsable = true;
474-
475-
// Reject inlinable code using availability macros.
476-
PoundAvailableInfo *info = elt.getAvailability();
477-
if (auto *decl = dc->getAsDecl()) {
478-
auto fragileKind = dc->getFragileFunctionKind();
479-
if (fragileKind.kind != FragileFunctionKind::None)
480-
for (auto queries : info->getQueries())
481-
if (auto availSpec =
482-
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(queries))
483-
if (availSpec->getMacroLoc().isValid()) {
484-
Context.Diags.diagnose(
485-
availSpec->getMacroLoc(),
486-
swift::diag::availability_macro_in_inlinable,
487-
fragileKind.getSelector());
488-
break;
489-
}
490-
}
491-
492474
return false;
493475
}
494476

test/Sema/availability_define.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func client() {
6666
if #available(_unknownMacro, *) { } // expected-error {{expected version number}}
6767
}
6868

69+
public func doIt(_ closure: () -> ()) {
70+
closure()
71+
}
72+
6973
@inlinable
7074
public func forbidMacrosInInlinableCode() {
7175
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
@@ -74,6 +78,9 @@ public func forbidMacrosInInlinableCode() {
7478
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
7579
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
7680
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
81+
doIt {
82+
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
83+
}
7784
}
7885

7986
@_alwaysEmitIntoClient
@@ -84,6 +91,9 @@ public func forbidMacrosInInlinableCode1() {
8491
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
8592
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
8693
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
94+
doIt {
95+
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
96+
}
8797
}
8898

8999
@available(_iOS8Aligned, *)
@@ -95,4 +105,7 @@ public func forbidMacrosInInlinableCode2() {
95105
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
96106
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
97107
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
108+
doIt {
109+
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
110+
}
98111
}

test/Sema/has_symbol.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,23 @@ func testWhile() {
115115
while #_hasSymbol(localFunc) { break } // expected-warning {{global function 'localFunc()' is not a weakly linked declaration}}
116116
}
117117

118+
func doIt(_ closure: () -> ()) {
119+
closure()
120+
}
121+
118122
@inlinable
119123
func testInlinable() {
120124
if #_hasSymbol(noArgFunc) {} // expected-error {{'#_hasSymbol' cannot be used in an '@inlinable' function}}
125+
doIt {
126+
if #_hasSymbol(noArgFunc) {} // expected-error {{'#_hasSymbol' cannot be used in an '@inlinable' function}}
127+
}
121128
}
122129

123130
@_alwaysEmitIntoClient
124131
func testAEIC() {
125132
if #_hasSymbol(noArgFunc) {} // expected-error {{'#_hasSymbol' cannot be used in an '@_alwaysEmitIntoClient' function}}
126133
}
127134

128-
func doIt(_ closure: () -> ()) {
129-
closure()
130-
}
131-
132135
func testClosure() {
133136
doIt { if #_hasSymbol(global) {} }
134137
doIt { if #_hasSymbol(noArgFunc) {} }

0 commit comments

Comments
 (0)