mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -155,6 +155,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE
|
||||
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name) \
|
||||
OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, #Name)
|
||||
#endif
|
||||
|
||||
#ifndef UPCOMING_FEATURE
|
||||
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
|
||||
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
|
||||
@@ -290,7 +295,7 @@ MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
|
||||
|
||||
/// Diagnose uses of language constructs and APIs that can violate memory
|
||||
/// safety.
|
||||
OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety")
|
||||
MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety")
|
||||
|
||||
// Experimental features
|
||||
|
||||
@@ -521,6 +526,7 @@ EXPERIMENTAL_FEATURE(ModuleSelector, false)
|
||||
#undef UPCOMING_FEATURE
|
||||
#undef MIGRATABLE_UPCOMING_FEATURE
|
||||
#undef MIGRATABLE_EXPERIMENTAL_FEATURE
|
||||
#undef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE
|
||||
#undef BASELINE_LANGUAGE_FEATURE
|
||||
#undef OPTIONAL_LANGUAGE_FEATURE
|
||||
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
|
||||
|
||||
@@ -872,7 +872,9 @@ namespace swift {
|
||||
FeatureState getFeatureState(Feature feature) const;
|
||||
|
||||
/// Returns whether the given feature is enabled.
|
||||
bool hasFeature(Feature feature) const;
|
||||
///
|
||||
/// If allowMigration is set, also returns true when the feature has been enabled for migration.
|
||||
bool hasFeature(Feature feature, bool allowMigration = false) const;
|
||||
|
||||
/// Returns whether a feature with the given name is enabled. Returns
|
||||
/// `false` if a feature by this name is not known.
|
||||
|
||||
@@ -1018,6 +1018,10 @@ def strict_memory_safety : Flag<["-"], "strict-memory-safety">,
|
||||
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable,
|
||||
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
|
||||
HelpText<"Enable strict memory safety checking">;
|
||||
def strict_memory_safety_migrate : Flag<["-"], "strict-memory-safety:migrate">,
|
||||
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable,
|
||||
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
|
||||
HelpText<"Enable migration to strict memory safety checking">;
|
||||
|
||||
def Rpass_EQ : Joined<["-"], "Rpass=">,
|
||||
Flags<[FrontendOption]>,
|
||||
|
||||
@@ -73,6 +73,7 @@ bool Feature::isMigratable() const {
|
||||
switch (kind) {
|
||||
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
|
||||
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
|
||||
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name)
|
||||
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
|
||||
case Feature::FeatureName:
|
||||
#include "swift/Basic/Features.def"
|
||||
@@ -82,6 +83,8 @@ bool Feature::isMigratable() const {
|
||||
case Feature::FeatureName:
|
||||
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
|
||||
case Feature::FeatureName:
|
||||
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name) \
|
||||
case Feature::FeatureName:
|
||||
#include "swift/Basic/Features.def"
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -335,13 +335,17 @@ LangOptions::FeatureState LangOptions::getFeatureState(Feature feature) const {
|
||||
return state;
|
||||
}
|
||||
|
||||
bool LangOptions::hasFeature(Feature feature) const {
|
||||
if (featureStates.getState(feature).isEnabled())
|
||||
bool LangOptions::hasFeature(Feature feature, bool allowMigration) const {
|
||||
auto state = featureStates.getState(feature);
|
||||
if (state.isEnabled())
|
||||
return true;
|
||||
|
||||
if (auto version = feature.getLanguageVersion())
|
||||
return isSwiftVersionAtLeast(*version);
|
||||
|
||||
if (allowMigration && state.isEnabledForMigration())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -284,7 +284,8 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
|
||||
options::OPT_disable_experimental_feature,
|
||||
options::OPT_enable_upcoming_feature,
|
||||
options::OPT_disable_upcoming_feature});
|
||||
inputArgs.AddLastArg(arguments, options::OPT_strict_memory_safety);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_strict_memory_safety,
|
||||
options::OPT_strict_memory_safety_migrate);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);
|
||||
|
||||
@@ -996,6 +996,8 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
|
||||
|
||||
if (Args.hasArg(OPT_strict_memory_safety))
|
||||
Opts.enableFeature(Feature::StrictMemorySafety);
|
||||
else if (Args.hasArg(OPT_strict_memory_safety_migrate))
|
||||
Opts.enableFeature(Feature::StrictMemorySafety, /*forMigration=*/true);
|
||||
|
||||
return HadError;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ deriveBodyDistributed_doInvokeOnReturn(AbstractFunctionDecl *afd, void *arg) {
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(returnTypeParam),
|
||||
dloc, implicit))}));
|
||||
|
||||
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety))
|
||||
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
|
||||
resultLoadCall = new (C) UnsafeExpr(sloc, resultLoadCall, Type(), true);
|
||||
|
||||
auto resultPattern = NamedPattern::createImplicit(C, resultVar);
|
||||
|
||||
@@ -106,7 +106,7 @@ deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl, void *) {
|
||||
auto *argList = ArgumentList::forImplicitCallTo(functionRef->getName(),
|
||||
{selfRef, typeExpr}, C);
|
||||
Expr *call = CallExpr::createImplicit(C, functionRef, argList);
|
||||
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety))
|
||||
if (C.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
|
||||
call = UnsafeExpr::createImplicit(C, SourceLoc(), call);
|
||||
auto *returnStmt = ReturnStmt::createImplicit(C, call);
|
||||
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
|
||||
|
||||
@@ -2257,7 +2257,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
|
||||
diagnoseOverrideForAvailability(override, base);
|
||||
}
|
||||
|
||||
if (ctx.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
|
||||
if (ctx.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true)) {
|
||||
// If the override is unsafe but the base declaration is not, then the
|
||||
// inheritance itself is unsafe.
|
||||
auto subs = SubstitutionMap::getOverrideSubstitutions(base, override);
|
||||
|
||||
@@ -2413,7 +2413,8 @@ public:
|
||||
|
||||
// If strict memory safety checking is enabled, check the storage
|
||||
// of the nominal type.
|
||||
if (Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety) &&
|
||||
if (Ctx.LangOpts.hasFeature(
|
||||
Feature::StrictMemorySafety, /*allowMigration=*/true) &&
|
||||
!isa<ProtocolDecl>(nominal)) {
|
||||
checkUnsafeStorage(nominal);
|
||||
}
|
||||
|
||||
@@ -4554,7 +4554,8 @@ private:
|
||||
if (classification.hasUnsafe()) {
|
||||
// If there is no such effect, complain.
|
||||
if (S->getUnsafeLoc().isInvalid() &&
|
||||
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
|
||||
Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety,
|
||||
/*allowMigration=*/true)) {
|
||||
auto insertionLoc = S->getPattern()->getStartLoc();
|
||||
Ctx.Diags.diagnose(S->getForLoc(), diag::for_unsafe_without_unsafe)
|
||||
.fixItInsert(insertionLoc, "unsafe ");
|
||||
@@ -4801,7 +4802,7 @@ private:
|
||||
|
||||
void diagnoseUncoveredUnsafeSite(
|
||||
const Expr *anchor, ArrayRef<UnsafeUse> unsafeUses) {
|
||||
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
|
||||
if (!Ctx.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true))
|
||||
return;
|
||||
|
||||
const auto &[loc, insertText] = getFixItForUncoveredSite(anchor, "unsafe");
|
||||
|
||||
@@ -2646,7 +2646,8 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
|
||||
// If we're enforcing strict memory safety and this conformance hasn't
|
||||
// opted out, look for safe/unsafe witness mismatches.
|
||||
if (conformance->getExplicitSafety() == ExplicitSafety::Unspecified &&
|
||||
Context.LangOpts.hasFeature(Feature::StrictMemorySafety)) {
|
||||
Context.LangOpts.hasFeature(Feature::StrictMemorySafety,
|
||||
/*allowMigration=*/true)) {
|
||||
// Collect all of the unsafe uses for this conformance.
|
||||
SmallVector<UnsafeUse, 2> unsafeUses;
|
||||
for (auto requirement: Proto->getMembers()) {
|
||||
|
||||
21
test/Unsafe/migrate.swift
Normal file
21
test/Unsafe/migrate.swift
Normal file
@@ -0,0 +1,21 @@
|
||||
// RUN: %target-swift-frontend -typecheck -verify -swift-version 6 -strict-memory-safety:migrate %s
|
||||
|
||||
// REQUIRES: concurrency
|
||||
|
||||
@preconcurrency import _Concurrency
|
||||
|
||||
@unsafe func f() { }
|
||||
|
||||
func g() {
|
||||
f() // expected-warning{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{3-3=unsafe }}
|
||||
// expected-note@-1{{reference to unsafe global function 'f()'}}
|
||||
}
|
||||
|
||||
protocol P {
|
||||
func f()
|
||||
}
|
||||
|
||||
struct Conforming: P {
|
||||
// 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 }}
|
||||
@unsafe func f() { } // expected-note{{unsafe instance method 'f()' cannot satisfy safe requirement}}
|
||||
}
|
||||
Reference in New Issue
Block a user