Skip to content

Commit 1c6298a

Browse files
committed
Add resilience boundary around non-exported decls
1 parent 553758a commit 1c6298a

File tree

2 files changed

+87
-22
lines changed

2 files changed

+87
-22
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
455455
if (declarationIntroducesNewContext(D)) {
456456
return buildDeclarationRefinementContext(D);
457457
}
458-
458+
459459
return nullptr;
460460
}
461461

@@ -468,7 +468,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
468468
// probably to gin up a source range for the declaration when synthesizing
469469
// it.
470470
assert(D->getSourceRange().isValid());
471-
471+
472472
// The potential versions in the declaration are constrained by both
473473
// the declared availability of the declaration and the potential versions
474474
// of its lexical context.
@@ -477,45 +477,69 @@ class TypeRefinementContextBuilder : private ASTWalker {
477477
AvailabilityContext DeclInfo = ExplicitDeclInfo;
478478
DeclInfo.intersectWith(getCurrentTRC()->getAvailabilityInfo());
479479

480-
TypeRefinementContext *NewTRC =
481-
TypeRefinementContext::createForDecl(Context, D, getCurrentTRC(),
482-
DeclInfo,
483-
ExplicitDeclInfo,
484-
refinementSourceRangeForDecl(D));
485-
480+
// If the entire declaration is surrounded by a resilience boundary, it is
481+
// also constrained by the deployment target.
482+
if (signatureIsResilienceBoundary(D))
483+
DeclInfo.intersectWith(AvailabilityContext::forDeploymentTarget(Context));
484+
485+
SourceRange Range = refinementSourceRangeForDecl(D);
486+
TypeRefinementContext *NewTRC;
487+
if (hasActiveAvailableAttribute(D, Context))
488+
NewTRC = TypeRefinementContext::createForDecl(Context, D, getCurrentTRC(),
489+
DeclInfo, ExplicitDeclInfo,
490+
Range);
491+
else
492+
NewTRC =
493+
TypeRefinementContext::createForResilienceBoundary(Context, D,
494+
getCurrentTRC(),
495+
DeclInfo, Range);
486496

487497
// Possibly use this as an effective parent context later.
488498
recordEffectiveParentContext(D, NewTRC);
489499

490500
return NewTRC;
491501
}
492-
502+
493503
/// Returns true if the declaration should introduce a new refinement context.
494504
bool declarationIntroducesNewContext(Decl *D) {
495505
if (!isa<ValueDecl>(D) && !isa<ExtensionDecl>(D)) {
496506
return false;
497507
}
498-
508+
509+
// Ignore implicit declarations. This mainly skips over the functions in
510+
// `DeferStmt`s.
511+
if (D->isImplicit()) {
512+
return false;
513+
}
514+
499515
// No need to introduce a context if the declaration does not have an
500-
// availability attribute.
501-
if (!hasActiveAvailableAttribute(D, Context)) {
516+
// availability attribute and the signature is not a resilience boundary.
517+
if (!hasActiveAvailableAttribute(D, Context) &&
518+
!signatureIsResilienceBoundary(D)) {
502519
return false;
503520
}
504-
521+
505522
// Only introduce for an AbstractStorageDecl if it is not local.
506523
// We introduce for the non-local case because these may
507524
// have getters and setters (and these may be synthesized, so they might
508525
// not even exist yet).
509526
if (auto *storageDecl = dyn_cast<AbstractStorageDecl>(D)) {
510527
if (storageDecl->getDeclContext()->isLocalContext()) {
511-
// No need to
512528
return false;
513529
}
514530
}
515-
531+
516532
return true;
517533
}
518534

535+
/// A declaration's signature is a resilience boundary if the entire
536+
/// declaration--not just the body--is not ABI-public and it's in a context
537+
/// where ABI-public declarations would be available below the minimum
538+
/// deployment target.
539+
bool signatureIsResilienceBoundary(Decl *D) {
540+
return !isCurrentTRCContainedByDeploymentTarget() && !::isExported(D);
541+
}
542+
519543
/// Returns the source range which should be refined by declaration. This
520544
/// provides a convenient place to specify the refined range when it is
521545
/// different than the declaration's source range.

test/attr/attr_inlinable_available.swift

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ public func deployedUseAfterDeploymentTarget(
296296
_ = NoAvailable()
297297
_ = BeforeInliningTarget()
298298
_ = AtInliningTarget()
299-
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} {{18-25=10.14.5}} || {{31-35=12.3}} || {{42-46=12.3}} || {{56-59=5.3}}
299+
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} FIXME: should have {{18-25=10.14.5}} || {{31-35=12.3}} || {{42-46=12.3}} || {{56-59=5.3}}
300300
_ = AtDeploymentTarget() // expected-error {{'AtDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
301301
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
302302

@@ -438,7 +438,7 @@ public func defaultArgsUseNoAvailable( // expected-note 3 {{add @available attri
438438
_: Any = AfterDeploymentTarget.self // expected-error {{'AfterDeploymentTarget' is only available in}}
439439
) {}
440440

441-
public struct PublicStruct { // expected-note 6 {{add @available attribute}}
441+
public struct PublicStruct { // expected-note 7 {{add @available attribute}}
442442
// Public declarations act like @inlinable.
443443
public var aPublic: NoAvailable
444444
public var bPublic: BeforeInliningTarget
@@ -451,18 +451,59 @@ public struct PublicStruct { // expected-note 6 {{add @available attribute}}
451451
var aInternal: NoAvailable
452452
var bInternal: BeforeInliningTarget
453453
var cInternal: AtInliningTarget
454-
var dInternal: BetweenTargets // FIXME: expected-error {{'BetweenTargets' is only available in}}
455-
var eInternal: AtDeploymentTarget // FIXME: expected-error {{'AtDeploymentTarget' is only available in}}
454+
var dInternal: BetweenTargets
455+
var eInternal: AtDeploymentTarget
456+
var fInternal: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in}}
457+
458+
@available(macOS 10.14.5, iOS 12.3, tvOS 12.3, watchOS 5.3, *)
459+
public internal(set) var internalSetter: Void {
460+
@inlinable get {
461+
// Public inlinable getter acts like @inlinable
462+
_ = NoAvailable()
463+
_ = BeforeInliningTarget()
464+
_ = AtInliningTarget()
465+
_ = BetweenTargets()
466+
_ = AtDeploymentTarget() // expected-error {{'AtDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
467+
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
468+
469+
}
470+
set {
471+
// Private setter acts like non-inlinable
472+
_ = NoAvailable()
473+
_ = BeforeInliningTarget()
474+
_ = AtInliningTarget()
475+
_ = BetweenTargets()
476+
_ = AtDeploymentTarget()
477+
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
478+
}
479+
}
480+
}
481+
482+
@frozen public struct FrozenPublicStruct { // expected-note 6 {{add @available attribute}}
483+
// Public declarations act like @inlinable.
484+
public var aPublic: NoAvailable
485+
public var bPublic: BeforeInliningTarget
486+
public var cPublic: AtInliningTarget
487+
public var dPublic: BetweenTargets // expected-error {{'BetweenTargets' is only available in}}
488+
public var ePublic: AtDeploymentTarget // expected-error {{'AtDeploymentTarget' is only available in}}
489+
public var fPublic: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in}}
490+
491+
// Internal declarations act like @inlinable in a frozen struct.
492+
var aInternal: NoAvailable
493+
var bInternal: BeforeInliningTarget
494+
var cInternal: AtInliningTarget
495+
var dInternal: BetweenTargets // expected-error {{'BetweenTargets' is only available in}}
496+
var eInternal: AtDeploymentTarget // expected-error {{'AtDeploymentTarget' is only available in}}
456497
var fInternal: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in}}
457498
}
458499

459-
internal struct InternalStruct { // expected-note 3 {{add @available attribute}}
500+
internal struct InternalStruct { // expected-note {{add @available attribute}}
460501
// Internal declarations act like non-inlinable.
461502
var aInternal: NoAvailable
462503
var bInternal: BeforeInliningTarget
463504
var cInternal: AtInliningTarget
464-
var dInternal: BetweenTargets // FIXME: expected-error {{'BetweenTargets' is only available in}}
465-
var eInternal: AtDeploymentTarget // FIXME: expected-error {{'AtDeploymentTarget' is only available in}}
505+
var dInternal: BetweenTargets
506+
var eInternal: AtDeploymentTarget
466507
var fInternal: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in}}
467508
}
468509

0 commit comments

Comments
 (0)