Skip to content

Commit 553758a

Browse files
beccadaxtshortli
authored andcommitted
Add resilience boundary around top-level code
Previously, the availability checker has assumed that no code in a module is available on less than the minimum deployment target. In modules using library evolution, this is not actually true--certain function bodies can be inlined into modules with lower minimum deployment targets, where they can run against versions of the library that had lower minimum deployment targets. By failing to check for availability violations in these function bodies that relate to versions below the minimum deployment target, we can end up allowing inlinable code that doesn't compile with the correct runtime linkage or has other serious problems. This commit lowers the root type refinement context's avialability to the value of the -target-min-inlining-version option (if provided) and then raises it again inside the bodies of functions whose implementations are not exposed to clients. This introduces some incorrect typechecking of declaration signatures, but we'll fix that in another commit.
1 parent df74841 commit 553758a

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,12 +569,19 @@ class TypeRefinementContextBuilder : private ASTWalker {
569569
if (auto afd = dyn_cast<AbstractFunctionDecl>(D))
570570
return bodyIsResilienceBoundary(afd);
571571

572-
return false;
572+
// The only other case we care about is top-level code.
573+
return isa<TopLevelCodeDecl>(D);
573574
}
574575

575576
TypeRefinementContext *buildBodyRefinementContext(Decl *D) {
576-
auto afd = cast<AbstractFunctionDecl>(D);
577-
SourceRange range = afd->getBodySourceRange();
577+
SourceRange range;
578+
if (auto tlcd = dyn_cast<TopLevelCodeDecl>(D)) {
579+
range = tlcd->getSourceRange();
580+
} else if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
581+
range = afd->getBodySourceRange();
582+
} else {
583+
llvm_unreachable("unknown decl");
584+
}
578585

579586
AvailabilityContext DeploymentTargetInfo =
580587
AvailabilityContext::forDeploymentTarget(Context);

test/attr/attr_inlinable_available.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,3 +466,20 @@ internal struct InternalStruct { // expected-note 3 {{add @available attribute}}
466466
var fInternal: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in}}
467467
}
468468

469+
// Top-level code, if somehow present in a resilient module, is treated like
470+
// a non-inlinable function.
471+
defer {
472+
_ = AtDeploymentTarget()
473+
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
474+
}
475+
_ = NoAvailable()
476+
_ = BeforeInliningTarget()
477+
_ = AtInliningTarget()
478+
_ = BetweenTargets()
479+
_ = AtDeploymentTarget()
480+
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
481+
482+
if #available(macOS 11, iOS 14, tvOS 14, watchOS 7, *) {
483+
_ = AfterDeploymentTarget()
484+
}
485+

0 commit comments

Comments
 (0)