Skip to content

Commit 2967b80

Browse files
committed
AST: Ignore availability attrs for app extension platforms in some queries.
When determining whether a declaration should be considered unavailable at runtime, ignore `@available` attributes for application extension platforms but continue searching for other `@available` attributes that might still make the declaration unavailable. This ensures corner cases like these are handled: ``` // Dubious, but allowed @available(macOS, unavailable) @available(macOSApplicationExtension, unavailable) public func doublyUnavailableOnMacOSFunc() {} // Expresses an uncommon, but valid constraint @available(macCatalyst, unavailable) @available(iOSApplicationExtension, unavailable) public func confusingDiamondAvailabilityInheritanceFunc() {} ```
1 parent 7b50414 commit 2967b80

File tree

6 files changed

+47
-24
lines changed

6 files changed

+47
-24
lines changed

include/swift/AST/Attr.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,7 +2655,8 @@ class DeclAttributes {
26552655
/// Finds the most-specific platform-specific attribute that is
26562656
/// active for the current platform.
26572657
const AvailableAttr *
2658-
findMostSpecificActivePlatform(const ASTContext &ctx) const;
2658+
findMostSpecificActivePlatform(const ASTContext &ctx,
2659+
bool ignoreAppExtensions = false) const;
26592660

26602661
/// Returns the first @available attribute that indicates
26612662
/// a declaration is unavailable, or the first one that indicates it's
@@ -2664,7 +2665,8 @@ class DeclAttributes {
26642665

26652666
/// Returns the first @available attribute that indicates
26662667
/// a declaration is unavailable, or null otherwise.
2667-
const AvailableAttr *getUnavailable(const ASTContext &ctx) const;
2668+
const AvailableAttr *getUnavailable(const ASTContext &ctx,
2669+
bool ignoreAppExtensions = false) const;
26682670

26692671
/// Returns the first @available attribute that indicates
26702672
/// a declaration is deprecated on all deployment targets, or null otherwise.

include/swift/AST/Decl.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
12861286
getSemanticAvailableRangeAttr() const;
12871287

12881288
/// Retrieve the @available attribute that makes this declaration unavailable,
1289-
/// if any.
1289+
/// if any. If \p ignoreAppExtensions is true then attributes for app
1290+
/// extension platforms are ignored.
12901291
///
12911292
/// This attribute may come from an enclosing decl since availability is
12921293
/// inherited. The second member of the returned pair is the decl that owns
@@ -1295,7 +1296,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
12951296
/// Note that this notion of unavailability is broader than that which is
12961297
/// checked by \c AvailableAttr::isUnavailable.
12971298
llvm::Optional<std::pair<const AvailableAttr *, const Decl *>>
1298-
getSemanticUnavailableAttr() const;
1299+
getSemanticUnavailableAttr(bool ignoreAppExtensions = false) const;
12991300

13001301
/// Returns true if this declaration should be considered available during
13011302
/// SIL/IR lowering. A declaration would not be available during lowering if,

include/swift/AST/TypeCheckRequests.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3985,16 +3985,18 @@ class SemanticAvailableRangeAttrRequest
39853985

39863986
class SemanticUnavailableAttrRequest
39873987
: public SimpleRequest<SemanticUnavailableAttrRequest,
3988-
llvm::Optional<AvailableAttrDeclPair>(const Decl *),
3988+
llvm::Optional<AvailableAttrDeclPair>(
3989+
const Decl *decl, bool ignoreAppExtensions),
39893990
RequestFlags::Cached> {
39903991
public:
39913992
using SimpleRequest::SimpleRequest;
39923993

39933994
private:
39943995
friend SimpleRequest;
39953996

3996-
llvm::Optional<AvailableAttrDeclPair> evaluate(Evaluator &evaluator,
3997-
const Decl *decl) const;
3997+
llvm::Optional<AvailableAttrDeclPair>
3998+
evaluate(Evaluator &evaluator, const Decl *decl,
3999+
bool ignoreAppExtensions) const;
39984000

39994001
public:
40004002
bool isCached() const { return true; }

lib/AST/Attr.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ DeclAttributes::isUnavailableInSwiftVersion(
337337
}
338338

339339
const AvailableAttr *
340-
DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx) const{
340+
DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx,
341+
bool ignoreAppExtensions) const {
341342
const AvailableAttr *bestAttr = nullptr;
342343

343344
for (auto attr : *this) {
@@ -354,6 +355,9 @@ DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx) const{
354355
if (!avAttr->isActivePlatform(ctx))
355356
continue;
356357

358+
if (ignoreAppExtensions && isApplicationExtensionPlatform(avAttr->Platform))
359+
continue;
360+
357361
// We have an attribute that is active for the platform, but
358362
// is it more specific than our current best?
359363
if (!bestAttr || inheritsAvailabilityFromPlatform(avAttr->Platform,
@@ -407,10 +411,12 @@ DeclAttributes::getPotentiallyUnavailable(const ASTContext &ctx) const {
407411
return potential;
408412
}
409413

410-
const AvailableAttr *DeclAttributes::getUnavailable(
411-
const ASTContext &ctx) const {
414+
const AvailableAttr *
415+
DeclAttributes::getUnavailable(const ASTContext &ctx,
416+
bool ignoreAppExtensions) const {
412417
const AvailableAttr *conditional = nullptr;
413-
const AvailableAttr *bestActive = findMostSpecificActivePlatform(ctx);
418+
const AvailableAttr *bestActive =
419+
findMostSpecificActivePlatform(ctx, ignoreAppExtensions);
414420

415421
for (auto Attr : *this)
416422
if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) {
@@ -429,6 +435,10 @@ const AvailableAttr *DeclAttributes::getUnavailable(
429435
!AvAttr->isPackageDescriptionVersionSpecific())
430436
continue;
431437

438+
if (ignoreAppExtensions &&
439+
isApplicationExtensionPlatform(AvAttr->Platform))
440+
continue;
441+
432442
// Unconditional unavailable.
433443
if (AvAttr->isUnconditionallyUnavailable())
434444
return AvAttr;

lib/AST/Availability.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -302,31 +302,35 @@ bool Decl::isAvailableAsSPI() const {
302302
}
303303

304304
llvm::Optional<AvailableAttrDeclPair>
305-
SemanticUnavailableAttrRequest::evaluate(Evaluator &evaluator,
306-
const Decl *decl) const {
305+
SemanticUnavailableAttrRequest::evaluate(Evaluator &evaluator, const Decl *decl,
306+
bool ignoreAppExtensions) const {
307307
// Directly marked unavailable.
308-
if (auto attr = decl->getAttrs().getUnavailable(decl->getASTContext()))
308+
if (auto attr = decl->getAttrs().getUnavailable(decl->getASTContext(),
309+
ignoreAppExtensions))
309310
return std::make_pair(attr, decl);
310311

311312
if (auto *parent =
312313
AvailabilityInference::parentDeclForInferredAvailability(decl))
313-
return parent->getSemanticUnavailableAttr();
314+
return parent->getSemanticUnavailableAttr(ignoreAppExtensions);
314315

315316
return llvm::None;
316317
}
317318

318-
llvm::Optional<AvailableAttrDeclPair> Decl::getSemanticUnavailableAttr() const {
319+
llvm::Optional<AvailableAttrDeclPair>
320+
Decl::getSemanticUnavailableAttr(bool ignoreAppExtensions) const {
319321
auto &eval = getASTContext().evaluator;
320-
return evaluateOrDefault(eval, SemanticUnavailableAttrRequest{this},
321-
llvm::None);
322+
return evaluateOrDefault(
323+
eval, SemanticUnavailableAttrRequest{this, ignoreAppExtensions},
324+
llvm::None);
322325
}
323326

324327
static bool shouldStubOrSkipUnavailableDecl(const Decl *D) {
325328
// Don't trust unavailability on declarations from clang modules.
326329
if (isa<ClangModuleUnit>(D->getDeclContext()->getModuleScopeContext()))
327330
return false;
328331

329-
auto unavailableAttrAndDecl = D->getSemanticUnavailableAttr();
332+
auto unavailableAttrAndDecl =
333+
D->getSemanticUnavailableAttr(/*ignoreAppExtensions=*/true);
330334
if (!unavailableAttrAndDecl)
331335
return false;
332336

@@ -338,11 +342,6 @@ static bool shouldStubOrSkipUnavailableDecl(const Decl *D) {
338342
if (!unavailableAttr->isUnconditionallyUnavailable())
339343
return false;
340344

341-
// If the decl is only unavailable to app extensions it still may need to be
342-
// present at runtime for non-extension processes.
343-
if (isApplicationExtensionPlatform(unavailableAttr->Platform))
344-
return false;
345-
346345
return true;
347346
}
348347

test/SILGen/unavailable_decl_optimization_stub_macos.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ public func unavailableOnMacOSFunc() {}
3535
@available(macOSApplicationExtension, unavailable)
3636
public func unavailableOnMacOSExtensionFunc() {}
3737

38+
// CHECK-LABEL: sil{{.*}}@$s4Test021unavailableOnMacOSAndD15OSExtensionFuncyyF
39+
// CHECK-SWIFT5_8: [[FNREF:%.*]] = function_ref @$ss36_diagnoseUnavailableCodeReached_aeics5NeverOyF : $@convention(thin) () -> Never
40+
// CHECK-SWIFT5_9: [[FNREF:%.*]] = function_ref @$ss31_diagnoseUnavailableCodeReacheds5NeverOyF : $@convention(thin) () -> Never
41+
// CHECK-NEXT: [[APPLY:%.*]] = apply [[FNREF]]()
42+
// CHECK: } // end sil function '$s4Test021unavailableOnMacOSAndD15OSExtensionFuncyyF'
43+
@available(macOS, unavailable)
44+
@available(macOSApplicationExtension, unavailable) // FIXME: Seems like this should be diagnosed as redundant
45+
public func unavailableOnMacOSAndMacOSExtensionFunc() {}
46+
3847
// CHECK-LABEL: sil{{.*}}@$s4Test20unavailableOniOSFuncyyF
3948
// CHECK-NOT: function_ref @$ss36_diagnoseUnavailableCodeReached{{.*}} : $@convention(thin) () -> Never
4049
// CHECK: } // end sil function '$s4Test20unavailableOniOSFuncyyF'

0 commit comments

Comments
 (0)