Skip to content

Commit abad2fa

Browse files
committed
Make the optional feature StrictMemorySafety migratable
This feature is essentially self-migrating, but fit it into the migration flow by marking it as migratable, adding `-strict-memory-safety:migrate`, and introducing a test.
1 parent a32782b commit abad2fa

14 files changed

+58
-12
lines changed

include/swift/Basic/Features.def

Lines changed: 7 additions & 1 deletion
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)
@@ -290,7 +295,7 @@ MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
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

@@ -521,6 +526,7 @@ EXPERIMENTAL_FEATURE(ModuleSelector, false)
521526
#undef UPCOMING_FEATURE
522527
#undef MIGRATABLE_UPCOMING_FEATURE
523528
#undef MIGRATABLE_EXPERIMENTAL_FEATURE
529+
#undef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE
524530
#undef BASELINE_LANGUAGE_FEATURE
525531
#undef OPTIONAL_LANGUAGE_FEATURE
526532
#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/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/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
@@ -2257,7 +2257,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
22572257
diagnoseOverrideForAvailability(override, base);
22582258
}
22592259

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

lib/Sema/TypeCheckDeclPrimary.cpp

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

24142414
// If strict memory safety checking is enabled, check the storage
24152415
// of the nominal type.
2416-
if (Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety) &&
2416+
if (Ctx.LangOpts.hasFeature(
2417+
Feature::StrictMemorySafety, /*allowMigration=*/true) &&
24172418
!isa<ProtocolDecl>(nominal)) {
24182419
checkUnsafeStorage(nominal);
24192420
}

lib/Sema/TypeCheckEffects.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4554,7 +4554,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
45544554
if (classification.hasUnsafe()) {
45554555
// If there is no such effect, complain.
45564556
if (S->getUnsafeLoc().isInvalid() &&
4557-
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
4557+
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety,
4558+
/*allowMigration=*/true)) {
45584559
auto insertionLoc = S->getPattern()->getStartLoc();
45594560
Ctx.Diags.diagnose(S->getForLoc(), diag::for_unsafe_without_unsafe)
45604561
.fixItInsert(insertionLoc, "unsafe ");
@@ -4801,7 +4802,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
48014802

48024803
void diagnoseUncoveredUnsafeSite(
48034804
const Expr *anchor, ArrayRef<UnsafeUse> unsafeUses) {
4804-
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
4805+
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
48054806
return;
48064807

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

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2646,7 +2646,8 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
26462646
// If we're enforcing strict memory safety and this conformance hasn't
26472647
// opted out, look for safe/unsafe witness mismatches.
26482648
if (conformance->getExplicitSafety() == ExplicitSafety::Unspecified &&
2649-
Context.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
2649+
Context.LangOpts.hasFeature(Feature::StrictMemorySafety,
2650+
/*allowMigration=*/true)) {
26502651
// Collect all of the unsafe uses for this conformance.
26512652
SmallVector<UnsafeUse, 2> unsafeUses;
26522653
for (auto requirement: Proto->getMembers()) {

test/Unsafe/migrate.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -swift-version 6 -strict-memory-safety:migrate %s
2+
3+
// REQUIRES: concurrency
4+
5+
@preconcurrency import _Concurrency
6+
7+
@unsafe func f() { }
8+
9+
func g() {
10+
f() // expected-warning{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{3-3=unsafe }}
11+
// expected-note@-1{{reference to unsafe global function 'f()'}}
12+
}
13+
14+
protocol P {
15+
func f()
16+
}
17+
18+
struct Conforming: P {
19+
// expected-warning@-1{{conformance of 'Conforming' to protocol 'P' involves unsafe code; use '@unsafe' to indicate that the conformance is not memory-safe}}{{20-20=@unsafe }}
20+
@unsafe func f() { } // expected-note{{unsafe instance method 'f()' cannot satisfy safe requirement}}
21+
}

0 commit comments

Comments
 (0)