Skip to content

Commit c3c7fe0

Browse files
authored
Merge pull request #41811 from tshortli/forbid-availability-macros-in-back-deploy-funcs
Sema: Diagnose use of availability macros in conditional statements in @_backDeploy functions
2 parents 4f3373a + 5f5cc9f commit c3c7fe0

File tree

7 files changed

+65
-32
lines changed

7 files changed

+65
-32
lines changed

include/swift/AST/DeclContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ struct FragileFunctionKind {
212212
return (lhs.kind == rhs.kind &&
213213
lhs.allowUsableFromInline == rhs.allowUsableFromInline);
214214
}
215+
216+
/// Casts to `unsigned` for diagnostic %selects.
217+
unsigned getSelector() { return static_cast<unsigned>(kind); }
215218
};
216219

217220
/// A DeclContext is an AST object which acts as a semantic container

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5631,10 +5631,6 @@ WARNING(public_decl_needs_availability, none,
56315631
"public declarations should have an availability attribute when building "
56325632
"with -require-explicit-availability", ())
56335633

5634-
ERROR(availability_macro_in_inlinable, none,
5635-
"availability macro cannot be used in inlinable %0",
5636-
(DescriptiveDeclKind))
5637-
56385634
ERROR(attr_requires_decl_availability_for_platform,none,
56395635
"'%0' requires that %1 have explicit availability for %2",
56405636
(DeclAttribute, DeclName, StringRef))
@@ -5731,7 +5727,8 @@ ERROR(usable_from_inline_attr_in_protocol,none,
57315727
"an '@inlinable' function|" \
57325728
"an '@_alwaysEmitIntoClient' function|" \
57335729
"a default argument value|" \
5734-
"a property initializer in a '@frozen' type}"
5730+
"a property initializer in a '@frozen' type|" \
5731+
"a '@_backDeploy' function'}"
57355732

57365733
#define DECL_OR_ACCESSOR "%select{%0|%0 for}"
57375734

@@ -5756,6 +5753,10 @@ ERROR(inlinable_decl_ref_from_hidden_module,
57565753
"it is SPI}4",
57575754
(DescriptiveDeclKind, DeclName, unsigned, Identifier, unsigned))
57585755

5756+
ERROR(availability_macro_in_inlinable, none,
5757+
"availability macro cannot be used in " FRAGILE_FUNC_KIND "0",
5758+
(unsigned))
5759+
57595760
#undef FRAGILE_FUNC_KIND
57605761

57615762
NOTE(resilience_decl_declared_here_public,

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
//
13-
// This file implements diagnostics for @inlinable.
13+
// This file implements diagnostics for fragile functions, like those with
14+
// @inlinable, @_alwaysEmitIntoClient, or @_backDeploy.
1415
//
1516
//===----------------------------------------------------------------------===//
1617

@@ -91,12 +92,9 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
9192
if (downgradeToWarning == DowngradeToWarning::Yes)
9293
diagID = diag::resilience_decl_unavailable_warn;
9394

94-
Context.Diags.diagnose(
95-
loc, diagID,
96-
D->getDescriptiveKind(), diagName,
97-
D->getFormalAccessScope().accessLevelForDiagnostics(),
98-
static_cast<unsigned>(fragileKind.kind),
99-
isAccessor);
95+
Context.Diags.diagnose(loc, diagID, D->getDescriptiveKind(), diagName,
96+
D->getFormalAccessScope().accessLevelForDiagnostics(),
97+
fragileKind.getSelector(), isAccessor);
10098

10199
if (fragileKind.allowUsableFromInline) {
102100
Context.Diags.diagnose(D, diag::resilience_decl_declared_here,
@@ -150,8 +148,7 @@ TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
150148
} else {
151149
ctx.Diags.diagnose(loc, diag::inlinable_decl_ref_from_hidden_module,
152150
D->getDescriptiveKind(), D->getName(),
153-
static_cast<unsigned>(fragileKind.kind),
154-
definingModule->getName(),
151+
fragileKind.getSelector(), definingModule->getName(),
155152
static_cast<unsigned>(originKind));
156153
}
157154
return true;

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2268,7 +2268,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22682268
auto kind = DC->getFragileFunctionKind();
22692269
if (kind.kind != FragileFunctionKind::None) {
22702270
NTD->diagnose(diag::local_type_in_inlinable_function, NTD->getName(),
2271-
static_cast<unsigned>(kind.kind));
2271+
kind.getSelector());
22722272
}
22732273

22742274
// We don't support protocols outside the top level of a file.

lib/Sema/TypeCheckStmt.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -429,16 +429,16 @@ bool TypeChecker::typeCheckStmtConditionElement(StmtConditionElement &elt,
429429
// Reject inlinable code using availability macros.
430430
PoundAvailableInfo *info = elt.getAvailability();
431431
if (auto *decl = dc->getAsDecl()) {
432-
if (decl->getAttrs().hasAttribute<InlinableAttr>() ||
433-
decl->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
432+
auto fragileKind = dc->getFragileFunctionKind();
433+
if (fragileKind.kind != FragileFunctionKind::None)
434434
for (auto queries : info->getQueries())
435435
if (auto availSpec =
436436
dyn_cast<PlatformVersionConstraintAvailabilitySpec>(queries))
437437
if (availSpec->getMacroLoc().isValid()) {
438438
Context.Diags.diagnose(
439439
availSpec->getMacroLoc(),
440440
swift::diag::availability_macro_in_inlinable,
441-
decl->getDescriptiveKind());
441+
fragileKind.getSelector());
442442
break;
443443
}
444444
}
@@ -1754,8 +1754,7 @@ static void checkClassConstructorBody(ClassDecl *classDecl,
17541754
auto kind = ctor->getFragileFunctionKind();
17551755
if (kind.kind != FragileFunctionKind::None) {
17561756
ctor->diagnose(diag::class_designated_init_inlinable_resilient,
1757-
classDecl->getDeclaredInterfaceType(),
1758-
static_cast<unsigned>(kind.kind));
1757+
classDecl->getDeclaredInterfaceType(), kind.getSelector());
17591758
}
17601759
}
17611760

test/Sema/availability_define.swift

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,31 @@ func client() {
6868

6969
@inlinable
7070
public func forbidMacrosInInlinableCode() {
71-
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in inlinable global function}}
72-
if #available(_iOS9, _macOS10_11, *) { } // expected-error {{availability macro cannot be used in inlinable global function}}
73-
if #available(iOS 9.0, _macOS10_11, tvOS 9.0, *) { } // expected-error {{availability macro cannot be used in inlinable global function}}
74-
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in inlinable global function}}
75-
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in inlinable global function}}
76-
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in inlinable global function}}
71+
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
72+
if #available(_iOS9, _macOS10_11, *) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
73+
if #available(iOS 9.0, _macOS10_11, tvOS 9.0, *) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
74+
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
75+
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
76+
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in an '@inlinable' function}}
7777
}
7878

7979
@_alwaysEmitIntoClient
8080
public func forbidMacrosInInlinableCode1() {
81-
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in inlinable global function}}
82-
if #available(_iOS9, _macOS10_11, *) { } // expected-error {{availability macro cannot be used in inlinable global function}}
83-
if #available(iOS 9.0, _macOS10_11, tvOS 9.0, *) { } // expected-error {{availability macro cannot be used in inlinable global function}}
84-
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in inlinable global function}}
85-
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in inlinable global function}}
86-
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in inlinable global function}}
81+
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
82+
if #available(_iOS9, _macOS10_11, *) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
83+
if #available(iOS 9.0, _macOS10_11, tvOS 9.0, *) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
84+
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
85+
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
86+
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in an '@_alwaysEmitIntoClient' function}}
87+
}
88+
89+
@available(_iOS8Aligned, *)
90+
@_backDeploy(_iOS9Aligned)
91+
public func forbidMacrosInInlinableCode2() {
92+
if #available(_iOS9Aligned, *) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
93+
if #available(_iOS9, _macOS10_11, *) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
94+
if #available(iOS 9.0, _macOS10_11, tvOS 9.0, *) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
95+
if #unavailable(_iOS9Aligned) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
96+
if #unavailable(_iOS9, _macOS10_11) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
97+
if #unavailable(iOS 9.0, _macOS10_11, tvOS 9.0) { } // expected-error {{availability macro cannot be used in a '@_backDeploy' function}}
8798
}

test/attr/attr_backDeploy.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,28 @@ public struct CannotBackDeployCoroutines {
159159
}
160160
}
161161

162+
// MARK: - Function body diagnostics
163+
164+
public struct FunctionBodyDiagnostics {
165+
public func publicFunc() {}
166+
@usableFromInline func usableFromInlineFunc() {}
167+
func internalFunc() {} // expected-note {{instance method 'internalFunc()' is not '@usableFromInline' or public}}
168+
fileprivate func fileprivateFunc() {} // expected-note {{instance method 'fileprivateFunc()' is not '@usableFromInline' or public}}
169+
private func privateFunc() {} // expected-note {{instance method 'privateFunc()' is not '@usableFromInline' or public}}
170+
171+
@available(macOS 11.0, *)
172+
@_backDeploy(macOS 12.0)
173+
public func backDeployedMethod() {
174+
struct Nested {} // expected-error {{type 'Nested' cannot be nested inside a '@_backDeploy' function}}
175+
176+
publicFunc()
177+
usableFromInlineFunc()
178+
internalFunc() // expected-error {{instance method 'internalFunc()' is internal and cannot be referenced from a '@_backDeploy' function}}
179+
fileprivateFunc() // expected-error {{instance method 'fileprivateFunc()' is fileprivate and cannot be referenced from a '@_backDeploy' function}}
180+
privateFunc() // expected-error {{instance method 'privateFunc()' is private and cannot be referenced from a '@_backDeploy' function}}
181+
}
182+
}
183+
162184
// MARK: - Incompatible declarations
163185

164186
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' may not be used on fileprivate declarations}}

0 commit comments

Comments
 (0)