Skip to content

Commit e25b822

Browse files
authored
Merge pull request #41673 from tshortli/inlining-availability-checking
Add -target-min-inlining-version to aid type checking for inlinable functions in resilient libraries
2 parents 62575ed + eccc086 commit e25b822

17 files changed

+953
-132
lines changed

include/swift/AST/Availability.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ class AvailabilityContext {
220220
/// deployment target.
221221
static AvailabilityContext forDeploymentTarget(ASTContext &Ctx);
222222

223+
/// Creates a context that imposes the constraints of the ASTContext's
224+
/// inlining target (i.e. minimum inlining version).
225+
static AvailabilityContext forInliningTarget(ASTContext &Ctx);
226+
223227
/// Creates a context that imposes no constraints.
224228
///
225229
/// \see isAlwaysAvailable

include/swift/AST/TypeRefinementContext.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
5858
/// function declaration or the contents of a class declaration).
5959
Decl,
6060

61+
/// The context was introduced by a resilience boundary; that is, we are in
62+
/// a module with library evolution enabled and the parent context's
63+
/// contents can be visible to the module's clients, but this context's
64+
/// contents are not.
65+
ResilienceBoundary,
66+
6167
/// The context was introduced for the Then branch of an IfStmt.
6268
IfStmtThenBranch,
6369

@@ -102,7 +108,10 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
102108

103109
public:
104110
IntroNode(SourceFile *SF) : IntroReason(Reason::Root), SF(SF) {}
105-
IntroNode(Decl *D) : IntroReason(Reason::Decl), D(D) {}
111+
IntroNode(Decl *D, Reason introReason = Reason::Decl)
112+
: IntroReason(introReason), D(D) {
113+
(void)getAsDecl(); // check that assertion succeeds
114+
}
106115
IntroNode(IfStmt *IS, bool IsThen) :
107116
IntroReason(IsThen ? Reason::IfStmtThenBranch : Reason::IfStmtElseBranch),
108117
IS(IS) {}
@@ -122,7 +131,8 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
122131
}
123132

124133
Decl *getAsDecl() const {
125-
assert(IntroReason == Reason::Decl);
134+
assert(IntroReason == Reason::Decl ||
135+
IntroReason == Reason::ResilienceBoundary);
126136
return D;
127137
}
128138

@@ -182,7 +192,14 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
182192
const AvailabilityContext &Info,
183193
const AvailabilityContext &ExplicitInfo,
184194
SourceRange SrcRange);
185-
195+
196+
/// Create a refinement context for the given declaration.
197+
static TypeRefinementContext *
198+
createForResilienceBoundary(ASTContext &Ctx, Decl *D,
199+
TypeRefinementContext *Parent,
200+
const AvailabilityContext &Info,
201+
SourceRange SrcRange);
202+
186203
/// Create a refinement context for the Then branch of the given IfStmt.
187204
static TypeRefinementContext *
188205
createForIfStmtThen(ASTContext &Ctx, IfStmt *S, TypeRefinementContext *Parent,

include/swift/Basic/LangOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ namespace swift {
134134
/// The SDK canonical name, if known.
135135
std::string SDKName;
136136

137+
/// The lowest target OS version that code in this module may be inlined
138+
/// into. In resilient modules, this should match the minimum
139+
/// deployment target of the *first* resilient version of the module, since
140+
/// clients may need to interoperate with versions as far back as that
141+
/// deployment target.
142+
llvm::VersionTuple MinimumInliningTargetVersion;
143+
137144
/// The alternate name to use for the entry point instead of main.
138145
std::string entryPointFunctionName = "main";
139146

include/swift/Basic/Platform.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ namespace swift {
5555
bool triplesAreValidForZippering(const llvm::Triple &target,
5656
const llvm::Triple &targetVariant);
5757

58+
const Optional<llvm::VersionTuple>
59+
minimumABIStableOSVersionForTriple(const llvm::Triple &triple);
60+
5861
/// Returns true if the given triple represents an OS that has all the
5962
/// "built-in" ABI-stable libraries (stdlib and _Concurrency)
6063
/// (eg. in /usr/lib/swift).

include/swift/Frontend/DiagnosticVerifier.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class DiagnosticVerifier : public DiagnosticConsumer {
132132
/// unexpected ones.
133133
Result verifyFile(unsigned BufferID);
134134

135-
bool checkForFixIt(const ExpectedFixIt &Expected,
135+
bool checkForFixIt(const std::vector<ExpectedFixIt> &ExpectedAlts,
136136
const CapturedDiagnosticInfo &D, unsigned BufferID) const;
137137

138138
// Render the verifier syntax for a given set of fix-its.

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,11 @@ def disable_clang_target : Flag<["-"], "disable-clang-target">,
11561156
Flags<[NewDriverOnlyOption]>,
11571157
HelpText<"Disable a separately specified target triple for Clang instance to use">;
11581158

1159+
def min_inlining_target_version : Separate<["-"], "target-min-inlining-version">,
1160+
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable]>,
1161+
HelpText<"Require inlinable code with no '@available' attribute to back-deploy "
1162+
"to this version of the '-target' OS">;
1163+
11591164
def profile_generate : Flag<["-"], "profile-generate">,
11601165
Flags<[FrontendOption, NoInteractiveOption]>,
11611166
HelpText<"Generate instrumented code to collect execution counts">;

lib/AST/Availability.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ AvailabilityContext AvailabilityContext::forDeploymentTarget(ASTContext &Ctx) {
3030
VersionRange::allGTE(Ctx.LangOpts.getMinPlatformVersion()));
3131
}
3232

33+
AvailabilityContext AvailabilityContext::forInliningTarget(ASTContext &Ctx) {
34+
return AvailabilityContext(
35+
VersionRange::allGTE(Ctx.LangOpts.MinimumInliningTargetVersion));
36+
}
37+
3338
namespace {
3439

3540
/// The inferred availability required to access a group of declarations

lib/AST/TypeRefinementContext.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@ TypeRefinementContext::createForDecl(ASTContext &Ctx, Decl *D,
6464
TypeRefinementContext(Ctx, D, Parent, SrcRange, Info, ExplicitInfo);
6565
}
6666

67+
TypeRefinementContext *
68+
TypeRefinementContext::createForResilienceBoundary(ASTContext &Ctx, Decl *D,
69+
TypeRefinementContext *Parent,
70+
const AvailabilityContext &Info,
71+
SourceRange SrcRange) {
72+
assert(D);
73+
assert(Parent);
74+
return new (Ctx)
75+
TypeRefinementContext(Ctx, IntroNode(D, Reason::ResilienceBoundary),
76+
Parent, SrcRange, Info,
77+
AvailabilityContext::alwaysAvailable());
78+
79+
}
80+
6781
TypeRefinementContext *
6882
TypeRefinementContext::createForIfStmtThen(ASTContext &Ctx, IfStmt *S,
6983
TypeRefinementContext *Parent,
@@ -170,6 +184,7 @@ void TypeRefinementContext::dump(raw_ostream &OS, SourceManager &SrcMgr) const {
170184
SourceLoc TypeRefinementContext::getIntroductionLoc() const {
171185
switch (getReason()) {
172186
case Reason::Decl:
187+
case Reason::ResilienceBoundary:
173188
return Node.getAsDecl()->getLoc();
174189

175190
case Reason::IfStmtThenBranch:
@@ -283,6 +298,7 @@ TypeRefinementContext::getAvailabilityConditionVersionSourceRange(
283298
Node.getAsWhileStmt()->getCond(), Platform, Version);
284299

285300
case Reason::Root:
301+
case Reason::ResilienceBoundary:
286302
return SourceRange();
287303
}
288304

@@ -296,13 +312,16 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
296312

297313
OS << " versions=" << AvailabilityInfo.getOSVersion().getAsString();
298314

299-
if (getReason() == Reason::Decl) {
315+
if (getReason() == Reason::Decl
316+
|| getReason() == Reason::ResilienceBoundary) {
300317
Decl *D = Node.getAsDecl();
301318
OS << " decl=";
302319
if (auto VD = dyn_cast<ValueDecl>(D)) {
303320
OS << VD->getName();
304321
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
305322
OS << "extension." << ED->getExtendedType().getString();
323+
} else if (isa<TopLevelCodeDecl>(D)) {
324+
OS << "<top-level-code>";
306325
}
307326
}
308327

@@ -312,6 +331,10 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
312331
R.print(OS, SrcMgr, /*PrintText=*/false);
313332
}
314333

334+
if (!ExplicitAvailabilityInfo.isAlwaysAvailable())
335+
OS << " explicit_versions="
336+
<< ExplicitAvailabilityInfo.getOSVersion().getAsString();
337+
315338
for (TypeRefinementContext *Child : Children) {
316339
OS << '\n';
317340
Child->print(OS, SrcMgr, Indent + 2);
@@ -332,6 +355,9 @@ StringRef TypeRefinementContext::getReasonName(Reason R) {
332355
case Reason::Decl:
333356
return "decl";
334357

358+
case Reason::ResilienceBoundary:
359+
return "resilience_boundary";
360+
335361
case Reason::IfStmtThenBranch:
336362
return "if_then";
337363

lib/Basic/Platform.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ bool swift::triplesAreValidForZippering(const llvm::Triple &target,
7979
return false;
8080
}
8181

82+
const Optional<llvm::VersionTuple>
83+
swift::minimumABIStableOSVersionForTriple(const llvm::Triple &triple) {
84+
if (triple.isMacOSX())
85+
return llvm::VersionTuple(10, 14, 4);
86+
87+
if (triple.isiOS() /* including tvOS */)
88+
return llvm::VersionTuple(12, 2);
89+
90+
if (triple.isWatchOS())
91+
return llvm::VersionTuple(5, 2);
92+
93+
return None;
94+
}
95+
8296
bool swift::tripleRequiresRPathForSwiftLibrariesInOS(
8397
const llvm::Triple &triple) {
8498
if (triple.isMacOSX()) {

lib/Frontend/CompilerInvocation.cpp

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -800,29 +800,63 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
800800
Diags.diagnose(SourceLoc(), diag::error_unsupported_target_os, TargetArgOS);
801801
}
802802

803-
// Parse the SDK version.
804-
if (Arg *A = Args.getLastArg(options::OPT_target_sdk_version)) {
805-
auto vers = version::Version::parseVersionString(
806-
A->getValue(), SourceLoc(), &Diags);
807-
if (vers.hasValue()) {
808-
Opts.SDKVersion = *vers;
809-
} else {
810-
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
811-
A->getAsString(Args), A->getValue());
812-
}
813-
}
803+
// First, set up default minimum inlining target versions.
804+
auto getDefaultMinimumInliningTargetVersion =
805+
[&](const llvm::Triple &triple) -> llvm::VersionTuple {
806+
#if SWIFT_DEFAULT_TARGET_MIN_INLINING_VERSION_TO_ABI
807+
// In ABI-stable modules, default to the version where the target's ABI
808+
// was first frozen; older versions will use that one's backwards
809+
// compatibility libraries.
810+
if (FrontendOpts.EnableLibraryEvolution)
811+
if (auto abiStability = minimumABIStableOSVersionForTriple(triple))
812+
// FIXME: Should we raise it to the minimum supported OS version for
813+
// architectures which were born ABI-stable?
814+
return *abiStability;
815+
#endif
816+
817+
// In ABI-unstable modules, we will never have to interoperate with
818+
// older versions of the module, so we should default to the minimum
819+
// deployment target.
820+
unsigned major, minor, patch;
821+
if (triple.isMacOSX())
822+
triple.getMacOSXVersion(major, minor, patch);
823+
else
824+
triple.getOSVersion(major, minor, patch);
825+
return llvm::VersionTuple(major, minor, patch);
826+
};
814827

815-
// Parse the target variant SDK version.
816-
if (Arg *A = Args.getLastArg(options::OPT_target_variant_sdk_version)) {
817-
auto vers = version::Version::parseVersionString(
818-
A->getValue(), SourceLoc(), &Diags);
819-
if (vers.hasValue()) {
820-
Opts.VariantSDKVersion = *vers;
821-
} else {
822-
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
823-
A->getAsString(Args), A->getValue());
824-
}
825-
}
828+
Opts.MinimumInliningTargetVersion =
829+
getDefaultMinimumInliningTargetVersion(Opts.Target);
830+
831+
// Parse OS version number arguments.
832+
auto parseVersionArg = [&](OptSpecifier opt) -> Optional<llvm::VersionTuple> {
833+
Arg *A = Args.getLastArg(opt);
834+
if (!A)
835+
return None;
836+
837+
if (StringRef(A->getValue()) == "target")
838+
return Opts.getMinPlatformVersion();
839+
if (StringRef(A->getValue()) == "abi")
840+
return minimumABIStableOSVersionForTriple(Opts.Target);
841+
842+
if (auto vers = version::Version::parseVersionString(A->getValue(),
843+
SourceLoc(), &Diags))
844+
return (llvm::VersionTuple)*vers;
845+
846+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
847+
A->getAsString(Args), A->getValue());
848+
return None;
849+
};
850+
851+
if (auto vers = parseVersionArg(OPT_min_inlining_target_version))
852+
// FIXME: Should we diagnose if it's below the default?
853+
Opts.MinimumInliningTargetVersion = *vers;
854+
855+
if (auto vers = parseVersionArg(OPT_target_sdk_version))
856+
Opts.SDKVersion = *vers;
857+
858+
if (auto vers = parseVersionArg(OPT_target_variant_sdk_version))
859+
Opts.VariantSDKVersion = *vers;
826860

827861
// Get the SDK name.
828862
if (Arg *A = Args.getLastArg(options::OPT_target_sdk_name)) {

0 commit comments

Comments
 (0)