Skip to content

Commit 0ed5cff

Browse files
authored
Merge pull request #81744 from DougGregor/more-migratable-features-6.2
[6.2] Make `InferIsolatedConformances` and `StrictMemorySafety` migratable features
2 parents 17d8955 + 60024c3 commit 0ed5cff

24 files changed

+188
-40
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8545,6 +8545,9 @@ GROUPED_ERROR(isolated_conformance_with_sendable_simple,IsolatedConformances,
85458545
GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none,
85468546
"%0 conformance of %1 to %2 cannot be used in %3 context",
85478547
(ActorIsolation, Type, DeclName, ActorIsolation))
8548+
GROUPED_WARNING(isolated_conformance_will_become_nonisolated,IsolatedConformances,none,
8549+
"conformance of %0 to %1 should be marked 'nonisolated' to retain its behavior with upcoming feature 'InferIsolatedConformances'",
8550+
(const ValueDecl *, const ValueDecl *))
85488551
85498552
//===----------------------------------------------------------------------===//
85508553
// MARK: @_inheritActorContext

include/swift/Basic/Features.def

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@
155155
#endif
156156
#endif
157157

158+
#ifndef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE
159+
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name) \
160+
OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, #Name)
161+
#endif
162+
158163
#ifndef UPCOMING_FEATURE
159164
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
160165
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
@@ -283,14 +288,14 @@ UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)
283288
MIGRATABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7)
284289
UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
285290
UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
286-
UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
291+
MIGRATABLE_UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
287292
MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
288293

289294
// Optional language features / modes
290295

291296
/// Diagnose uses of language constructs and APIs that can violate memory
292297
/// safety.
293-
OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety")
298+
MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety")
294299

295300
// Experimental features
296301

@@ -522,6 +527,7 @@ EXPERIMENTAL_FEATURE(CopyBlockOptimization, true)
522527
#undef UPCOMING_FEATURE
523528
#undef MIGRATABLE_UPCOMING_FEATURE
524529
#undef MIGRATABLE_EXPERIMENTAL_FEATURE
530+
#undef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE
525531
#undef BASELINE_LANGUAGE_FEATURE
526532
#undef OPTIONAL_LANGUAGE_FEATURE
527533
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,9 @@ namespace swift {
872872
FeatureState getFeatureState(Feature feature) const;
873873

874874
/// Returns whether the given feature is enabled.
875-
bool hasFeature(Feature feature) const;
875+
///
876+
/// If allowMigration is set, also returns true when the feature has been enabled for migration.
877+
bool hasFeature(Feature feature, bool allowMigration = false) const;
876878

877879
/// Returns whether a feature with the given name is enabled. Returns
878880
/// `false` if a feature by this name is not known.

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,10 @@ def strict_memory_safety : Flag<["-"], "strict-memory-safety">,
10181018
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable,
10191019
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
10201020
HelpText<"Enable strict memory safety checking">;
1021+
def strict_memory_safety_migrate : Flag<["-"], "strict-memory-safety:migrate">,
1022+
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable,
1023+
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
1024+
HelpText<"Enable migration to strict memory safety checking">;
10211025

10221026
def Rpass_EQ : Joined<["-"], "Rpass=">,
10231027
Flags<[FrontendOption]>,

lib/Basic/Feature.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ bool Feature::isMigratable() const {
7373
switch (kind) {
7474
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
7575
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
76+
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name)
7677
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
7778
case Feature::FeatureName:
7879
#include "swift/Basic/Features.def"
@@ -82,6 +83,8 @@ bool Feature::isMigratable() const {
8283
case Feature::FeatureName:
8384
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
8485
case Feature::FeatureName:
86+
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name) \
87+
case Feature::FeatureName:
8588
#include "swift/Basic/Features.def"
8689
return true;
8790
}

lib/Basic/LangOptions.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,17 @@ LangOptions::FeatureState LangOptions::getFeatureState(Feature feature) const {
335335
return state;
336336
}
337337

338-
bool LangOptions::hasFeature(Feature feature) const {
339-
if (featureStates.getState(feature).isEnabled())
338+
bool LangOptions::hasFeature(Feature feature, bool allowMigration) const {
339+
auto state = featureStates.getState(feature);
340+
if (state.isEnabled())
340341
return true;
341342

342343
if (auto version = feature.getLanguageVersion())
343344
return isSwiftVersionAtLeast(*version);
344345

346+
if (allowMigration && state.isEnabledForMigration())
347+
return true;
348+
345349
return false;
346350
}
347351

lib/Basic/SupportedFeatures.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <array>
1414
#include <vector>
1515

16+
#include "swift/AST/DiagnosticGroups.h"
1617
#include "swift/Basic/Feature.h"
1718
#include "swift/Frontend/Frontend.h"
1819

@@ -22,6 +23,33 @@ using namespace swift;
2223

2324
namespace swift {
2425
namespace features {
26+
27+
/// The subset of diagnostic groups (called categories by the diagnostic machinery) whose diagnostics should be
28+
/// considered to be part of the migration for this feature.
29+
///
30+
/// When making a feature migratable, ensure that all of the warnings that are used to drive the migration are
31+
/// part of a diagnostic group, and put that diagnostic group into the list for that feature here.
32+
static std::vector<DiagGroupID> migratableCategories(Feature feature) {
33+
switch (feature) {
34+
case Feature::InnerKind::ExistentialAny:
35+
return { DiagGroupID::ExistentialAny };
36+
case Feature::InnerKind::InferIsolatedConformances:
37+
return { DiagGroupID::IsolatedConformances };
38+
case Feature::InnerKind::NonisolatedNonsendingByDefault:
39+
return { DiagGroupID::NonisolatedNonsendingByDefault };
40+
case Feature::InnerKind::StrictMemorySafety:
41+
return { DiagGroupID::StrictMemorySafety };
42+
43+
// Provide unreachable cases for all of the non-migratable features.
44+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) case Feature::FeatureName:
45+
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
46+
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
47+
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name)
48+
#include "swift/Basic/Features.def"
49+
llvm_unreachable("Not a migratable feature");
50+
}
51+
}
52+
2553
/// Print information about what features upcoming/experimental are
2654
/// supported by the compiler.
2755
/// The information includes whether a feature is adoptable and for
@@ -50,9 +78,18 @@ void printSupportedFeatures(llvm::raw_ostream &out) {
5078
out << "{ \"name\": \"" << feature.getName() << "\"";
5179
if (feature.isMigratable()) {
5280
out << ", \"migratable\": true";
81+
82+
auto categories = migratableCategories(feature);
83+
out << ", \"categories\": [";
84+
llvm::interleave(categories, [&out](DiagGroupID diagGroupID) {
85+
out << "\"" << getDiagGroupInfoByID(diagGroupID).name << "\"";
86+
}, [&out] {
87+
out << ", ";
88+
});
89+
out << "]";
5390
}
5491
if (auto version = feature.getLanguageVersion()) {
55-
out << ", \"enabled_in\": " << *version;
92+
out << ", \"enabled_in\": \"" << *version << "\"";
5693
}
5794
out << " }";
5895
};
@@ -71,4 +108,4 @@ void printSupportedFeatures(llvm::raw_ostream &out) {
71108
}
72109

73110
} // end namespace features
74-
} // end namespace swift
111+
} // end namespace swift

lib/Driver/ToolChains.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
284284
options::OPT_disable_experimental_feature,
285285
options::OPT_enable_upcoming_feature,
286286
options::OPT_disable_upcoming_feature});
287-
inputArgs.AddLastArg(arguments, options::OPT_strict_memory_safety);
287+
inputArgs.AddLastArg(arguments, options::OPT_strict_memory_safety,
288+
options::OPT_strict_memory_safety_migrate);
288289
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
289290
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
290291
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,8 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
996996

997997
if (Args.hasArg(OPT_strict_memory_safety))
998998
Opts.enableFeature(Feature::StrictMemorySafety);
999+
else if (Args.hasArg(OPT_strict_memory_safety_migrate))
1000+
Opts.enableFeature(Feature::StrictMemorySafety, /*forMigration=*/true);
9991001

10001002
return HadError;
10011003
}

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8172,7 +8172,7 @@ Expr *ExprRewriter::convertLiteralInPlace(
81728172
Diag<> brokenProtocolDiag, Diag<> brokenBuiltinProtocolDiag) {
81738173
// If coercing a literal to an unresolved type, we don't try to look up the
81748174
// witness members, just do it.
8175-
if (type->is<UnresolvedType>()) {
8175+
if (type->is<UnresolvedType>() || type->is<ErrorType>()) {
81768176
cs.setType(literal, type);
81778177
return literal;
81788178
}

lib/Sema/DerivedConformance/DerivedConformanceDistributedActor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ deriveBodyDistributed_doInvokeOnReturn(AbstractFunctionDecl *afd, void *arg) {
171171
new (C) DeclRefExpr(ConcreteDeclRef(returnTypeParam),
172172
dloc, implicit))}));
173173

174-
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety))
174+
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
175175
resultLoadCall = new (C) UnsafeExpr(sloc, resultLoadCall, Type(), true);
176176

177177
auto resultPattern = NamedPattern::createImplicit(C, resultVar);

lib/Sema/DerivedConformance/DerivedConformanceRawRepresentable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl, void *) {
106106
auto *argList = ArgumentList::forImplicitCallTo(functionRef->getName(),
107107
{selfRef, typeExpr}, C);
108108
Expr *call = CallExpr::createImplicit(C, functionRef, argList);
109-
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety))
109+
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
110110
call = UnsafeExpr::createImplicit(C, SourceLoc(), call);
111111
auto *returnStmt = ReturnStmt::createImplicit(C, call);
112112
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2262,7 +2262,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
22622262
diagnoseOverrideForAvailability(override, base);
22632263
}
22642264

2265-
if (ctx.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
2265+
if (ctx.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true)) {
22662266
// If the override is unsafe but the base declaration is not, then the
22672267
// inheritance itself is unsafe.
22682268
auto subs = SubstitutionMap::getOverrideSubstitutions(base, override);

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2430,7 +2430,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24302430

24312431
// If strict memory safety checking is enabled, check the storage
24322432
// of the nominal type.
2433-
if (Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety) &&
2433+
if (Ctx.LangOpts.hasFeature(
2434+
Feature::StrictMemorySafety, /*allowMigration=*/true) &&
24342435
!isa<ProtocolDecl>(nominal)) {
24352436
checkUnsafeStorage(nominal);
24362437
}

lib/Sema/TypeCheckEffects.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,8 +1187,7 @@ class Classification {
11871187
Classification result;
11881188
bool considerAsync = !onlyEffect || *onlyEffect == EffectKind::Async;
11891189
bool considerThrows = !onlyEffect || *onlyEffect == EffectKind::Throws;
1190-
bool considerUnsafe = (!onlyEffect || *onlyEffect == EffectKind::Unsafe) &&
1191-
ctx.LangOpts.hasFeature(Feature::StrictMemorySafety);
1190+
bool considerUnsafe = (!onlyEffect || *onlyEffect == EffectKind::Unsafe);
11921191

11931192
// If we're tracking "unsafe" effects, compute them here.
11941193
if (considerUnsafe) {
@@ -1710,8 +1709,7 @@ class ApplyClassifier {
17101709
!fnType->isAsync() &&
17111710
!E->isImplicitlyAsync() &&
17121711
!hasAnyConformances &&
1713-
(fnRef.getExplicitSafety() == ExplicitSafety::Safe ||
1714-
!ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))) {
1712+
fnRef.getExplicitSafety() == ExplicitSafety::Safe) {
17151713
return Classification();
17161714
}
17171715

@@ -1932,7 +1930,6 @@ class ApplyClassifier {
19321930
// If the safety of the callee is unspecified, check the safety of the
19331931
// arguments specifically.
19341932
if (hasUnspecifiedSafety &&
1935-
ctx.LangOpts.hasFeature(Feature::StrictMemorySafety) &&
19361933
!(assumedSafeArguments && assumedSafeArguments->contains(E))) {
19371934
classifyApplyEffect(EffectKind::Unsafe);
19381935
}
@@ -4553,13 +4550,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
45534550
if (classification.hasUnsafe()) {
45544551
// If there is no such effect, complain.
45554552
if (S->getUnsafeLoc().isInvalid() &&
4556-
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
4553+
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety,
4554+
/*allowMigration=*/true)) {
45574555
auto insertionLoc = S->getPattern()->getStartLoc();
45584556
Ctx.Diags.diagnose(S->getForLoc(), diag::for_unsafe_without_unsafe)
45594557
.fixItInsert(insertionLoc, "unsafe ");
45604558
}
4561-
} else if (S->getUnsafeLoc().isValid() &&
4562-
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
4559+
} else if (S->getUnsafeLoc().isValid()) {
45634560
// Extraneous "unsafe" on the sequence.
45644561
Ctx.Diags.diagnose(S->getUnsafeLoc(), diag::no_unsafe_in_unsafe_for)
45654562
.fixItRemove(S->getUnsafeLoc());
@@ -4604,9 +4601,6 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
46044601
}
46054602

46064603
void diagnoseRedundantUnsafe(UnsafeExpr *E) const {
4607-
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
4608-
return;
4609-
46104604
// Silence this warning in the expansion of the _SwiftifyImport macro.
46114605
// This is a hack because it's tricky to determine when to insert "unsafe".
46124606
unsigned bufferID =
@@ -4880,7 +4874,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
48804874

48814875
void diagnoseUncoveredUnsafeSite(
48824876
const Expr *anchor, ArrayRef<UnsafeUse> unsafeUses) {
4883-
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
4877+
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
48844878
return;
48854879

48864880
const auto &[loc, insertText] = getFixItForUncoveredSite(anchor, "unsafe");

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2650,7 +2650,8 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
26502650
// If we're enforcing strict memory safety and this conformance hasn't
26512651
// opted out, look for safe/unsafe witness mismatches.
26522652
if (conformance->getExplicitSafety() == ExplicitSafety::Unspecified &&
2653-
Context.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
2653+
Context.LangOpts.hasFeature(Feature::StrictMemorySafety,
2654+
/*allowMigration=*/true)) {
26542655
// Collect all of the unsafe uses for this conformance.
26552656
SmallVector<UnsafeUse, 2> unsafeUses;
26562657
for (auto requirement: Proto->getMembers()) {
@@ -6668,6 +6669,49 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
66686669
}
66696670
}
66706671

6672+
// If we are migrating to InferIsolatedConformances, and the
6673+
// nominal type is global-actor-isolated, look for conformances
6674+
// that are nonisolated but were not explicitly marked as such.
6675+
// These conformances will need to be marked 'nonisolated' to
6676+
// retain their current behavior.
6677+
if (Context.LangOpts
6678+
.getFeatureState(Feature::InferIsolatedConformances)
6679+
.isEnabledForMigration() &&
6680+
getActorIsolation(const_cast<NominalTypeDecl *>(nominal))
6681+
.isGlobalActor()) {
6682+
for (auto conformance : conformances) {
6683+
auto normal = dyn_cast<NormalProtocolConformance>(conformance);
6684+
if (!normal)
6685+
continue;
6686+
6687+
// Explicit nonisolated and @preconcurrency suppress this.
6688+
auto options = normal->getOptions();
6689+
if (options.contains(ProtocolConformanceFlags::Nonisolated) ||
6690+
options.contains(ProtocolConformanceFlags::Preconcurrency))
6691+
continue;
6692+
6693+
// Only consider conformances that were explicitly written in the source.
6694+
if (normal->getSourceKind() != ConformanceEntryKind::Explicit)
6695+
continue;
6696+
6697+
// Only consider conformances to non-marker, nonisolated protocols.
6698+
auto proto = normal->getProtocol();
6699+
if (proto->isMarkerProtocol() || getActorIsolation(proto).isActorIsolated())
6700+
continue;
6701+
6702+
// Only nonisolated conformances can be affected.
6703+
if (!conformance->getIsolation().isNonisolated())
6704+
continue;
6705+
6706+
auto nameLoc = normal->getProtocolNameLoc();
6707+
if (nameLoc.isValid()) {
6708+
Context.Diags.diagnose(
6709+
nameLoc, diag::isolated_conformance_will_become_nonisolated, nominal, proto)
6710+
.fixItInsert(nameLoc, "nonisolated ");
6711+
}
6712+
}
6713+
}
6714+
66716715
if (Context.TypeCheckerOpts.DebugGenericSignatures &&
66726716
!conformances.empty()) {
66736717
// Now that they're filled out, print out information about the conformances

lib/Sema/TypeCheckUnsafe.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,6 @@ bool swift::enumerateUnsafeUses(ArrayRef<ProtocolConformanceRef> conformances,
341341
if (conformance.isInvalid())
342342
continue;
343343

344-
ASTContext &ctx = conformance.getProtocol()->getASTContext();
345-
if (!ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
346-
return false;
347-
348344
if (!conformance.hasEffect(EffectKind::Unsafe))
349345
continue;
350346

@@ -413,9 +409,6 @@ bool swift::isUnsafeInConformance(const ValueDecl *requirement,
413409

414410
void swift::diagnoseUnsafeType(ASTContext &ctx, SourceLoc loc, Type type,
415411
llvm::function_ref<void(Type)> diagnose) {
416-
if (!ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
417-
return;
418-
419412
if (!type->isUnsafe())
420413
return;
421414

0 commit comments

Comments
 (0)