Skip to content

Commit 5d92f79

Browse files
Merge pull request #79792 from AnthonyLatsis/danaus-plexippus-2
Introduce adoption mode for Swift features (take 2)
2 parents 38c8cc8 + 5c373a5 commit 5d92f79

26 files changed

+1427
-105
lines changed

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@
269269
/unittests/AST/ @hborla @slavapestov @xedin
270270
/unittests/AST/*Evaluator* @CodaFi @slavapestov
271271
/unittests/DependencyScan/ @artemcm @cachemeifyoucan
272-
/unittests/FrontendTool/ @artemcm @tshortli
272+
/unittests/Frontend*/ @artemcm @tshortli
273273
/unittests/Parse/ @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro
274274
/unittests/Reflection/ @slavapestov
275275
/unittests/SIL/ @jckarter

include/swift/AST/DiagnosticsFrontend.def

+15-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -50,6 +50,20 @@ GROUPED_WARNING(feature_not_experimental, StrictLanguageFeatures, DefaultIgnore,
5050
"use -%select{disable|enable}1-upcoming-feature instead",
5151
(StringRef, bool))
5252

53+
GROUPED_WARNING(invalid_feature_mode, StrictLanguageFeatures, none,
54+
"'%0' is not a recognized mode for feature '%1'"
55+
"%select{|; did you mean '%2'?}3",
56+
(StringRef, StringRef, StringRef, bool))
57+
58+
GROUPED_WARNING(cannot_disable_feature_with_mode, StrictLanguageFeatures, none,
59+
"'%0' argument '%1' cannot specify a mode",
60+
(StringRef, StringRef))
61+
62+
GROUPED_WARNING(feature_does_not_support_adoption_mode, StrictLanguageFeatures,
63+
none,
64+
"feature '%0' does not support adoption mode",
65+
(StringRef))
66+
5367
ERROR(error_unknown_library_level, none,
5468
"unknown library level '%0', "
5569
"expected one of 'api', 'spi', 'ipi', or 'other'", (StringRef))

include/swift/Basic/BasicBridging.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2022 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2022 - 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -214,7 +214,8 @@ void BridgedData_free(BridgedData data);
214214
//===----------------------------------------------------------------------===//
215215

216216
enum ENUM_EXTENSIBILITY_ATTR(open) BridgedFeature {
217-
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
217+
#define LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description) \
218+
FeatureName,
218219
#include "swift/Basic/Features.def"
219220
};
220221

include/swift/Basic/Feature.h

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -21,14 +21,16 @@ namespace swift {
2121
class LangOptions;
2222

2323
/// Enumeration describing all of the named features.
24-
enum class Feature {
25-
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
24+
enum class Feature : uint16_t {
25+
#define LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description) \
26+
FeatureName,
2627
#include "swift/Basic/Features.def"
2728
};
2829

2930
constexpr unsigned numFeatures() {
3031
enum Features {
31-
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName,
32+
#define LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description) \
33+
FeatureName,
3234
#include "swift/Basic/Features.def"
3335
NumFeatures
3436
};
@@ -61,6 +63,9 @@ std::optional<Feature> getExperimentalFeature(llvm::StringRef name);
6163
/// \c None if it does not have such a version.
6264
std::optional<unsigned> getFeatureLanguageVersion(Feature feature);
6365

66+
/// Determine whether the given feature supports adoption mode.
67+
bool isFeatureAdoptable(Feature feature);
68+
6469
/// Determine whether this feature should be included in the
6570
/// module interface
6671
bool includeInModuleInterface(Feature feature);

include/swift/Basic/Features.def

+56-20
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,28 @@
1414
// features.
1515
//
1616
//
17-
// LANGUAGE_FEATURE(FeatureName, SENumber, Description)
17+
// LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description)
1818
//
1919
// The LANGUAGE_FEATURE macro describes each named feature that is
2020
// introduced in Swift. It allows Swift code to check for a particular
2121
// feature with "#if $FeatureName" in source code.
2222
//
2323
// FeatureName: The name given to this feature to be used in source code,
2424
// e.g., AsyncAwait.
25+
// IsAdoptable: Whether the feature implements adoption mode.
26+
//
27+
// If the feature is upcoming (source-breaking) and provides for a
28+
// mechanical code migration, it should implement adoption mode.
29+
//
30+
// Adoption mode is a feature-oriented code migration mechanism: a mode
31+
// of operation that should produce compiler warnings with attached
32+
// fix-its that can be applied to preserve the behavior of the code once
33+
// the upcoming feature is enacted.
34+
// These warnings must belong to a diagnostic group named after the
35+
// feature. Adoption mode itself *and* the fix-its it produces must be
36+
// source and binary compatible with how the code is compiled when the
37+
// feature is disabled.
38+
//
2539
// SENumber: The number assigned to this feature in the Swift Evolution
2640
// process, or 0 if there isn't one.
2741
// Description: A string literal describing the feature.
@@ -91,13 +105,14 @@
91105
#endif
92106

93107
#ifndef SUPPRESSIBLE_LANGUAGE_FEATURE
94-
# define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
95-
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
108+
#define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
109+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/false, SENumber, \
110+
Description)
96111
#endif
97112

98113
#ifndef OPTIONAL_LANGUAGE_FEATURE
99-
# define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
100-
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
114+
#define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
115+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/false, SENumber, Description)
101116
#endif
102117

103118
// A feature that's both conditionally-suppressible and experimental.
@@ -116,20 +131,35 @@
116131
#endif
117132

118133
#ifndef CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE
119-
# define CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
120-
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
134+
#define CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, \
135+
Description) \
136+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/false, SENumber, \
137+
Description)
138+
#endif
139+
140+
// An upcoming feature that supports adoption mode.
141+
#ifndef ADOPTABLE_UPCOMING_FEATURE
142+
#if defined(UPCOMING_FEATURE)
143+
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
144+
UPCOMING_FEATURE(FeatureName, SENumber, Version)
145+
#else
146+
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
147+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/true, SENumber, \
148+
#FeatureName)
149+
#endif
121150
#endif
122151

123152
#ifndef UPCOMING_FEATURE
124-
# define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
125-
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
153+
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
154+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/false, SENumber, \
155+
#FeatureName)
126156
#endif
127157

128158
#ifndef EXPERIMENTAL_FEATURE
129-
// Warning: setting `AvailableInProd` to `true` on a feature means that the flag
130-
// cannot be dropped in the future.
131-
# define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
132-
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName)
159+
// Warning: setting `AvailableInProd` to `true` on a feature means that the
160+
// flag cannot be dropped in the future.
161+
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
162+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/false, 0, #FeatureName)
133163
#endif
134164

135165
#ifndef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
@@ -138,8 +168,9 @@
138168
#endif
139169

140170
#ifndef BASELINE_LANGUAGE_FEATURE
141-
# define BASELINE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
142-
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
171+
#define BASELINE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
172+
LANGUAGE_FEATURE(FeatureName, /*IsAdoptable=*/false, SENumber, \
173+
Description)
143174
#endif
144175

145176
BASELINE_LANGUAGE_FEATURE(AsyncAwait, 296, "async/await")
@@ -210,10 +241,14 @@ BASELINE_LANGUAGE_FEATURE(BodyMacros, 415, "Function body macros")
210241
SUPPRESSIBLE_LANGUAGE_FEATURE(SendingArgsAndResults, 430, "Sending arg and results")
211242
BASELINE_LANGUAGE_FEATURE(BorrowingSwitch, 432, "Noncopyable type pattern matching")
212243
CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(IsolatedAny, 431, "@isolated(any) function types")
213-
LANGUAGE_FEATURE(IsolatedAny2, 431, "@isolated(any) function types")
214-
LANGUAGE_FEATURE(ObjCImplementation, 436, "@objc @implementation extensions")
215-
LANGUAGE_FEATURE(NonescapableTypes, 446, "Nonescapable types")
216-
LANGUAGE_FEATURE(BuiltinEmplaceTypedThrows, 0, "Builtin.emplace typed throws")
244+
LANGUAGE_FEATURE(IsolatedAny2, /*IsAdoptable=*/false, 431,
245+
"@isolated(any) function types")
246+
LANGUAGE_FEATURE(ObjCImplementation, /*IsAdoptable=*/false, 436,
247+
"@objc @implementation extensions")
248+
LANGUAGE_FEATURE(NonescapableTypes, /*IsAdoptable=*/false, 446,
249+
"Nonescapable types")
250+
LANGUAGE_FEATURE(BuiltinEmplaceTypedThrows, /*IsAdoptable=*/false, 0,
251+
"Builtin.emplace typed throws")
217252
SUPPRESSIBLE_LANGUAGE_FEATURE(MemorySafetyAttributes, 458, "@unsafe attribute")
218253

219254
// Swift 6
@@ -234,7 +269,7 @@ UPCOMING_FEATURE(NonfrozenEnumExhaustivity, 192, 6)
234269
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)
235270

236271
// Swift 7
237-
UPCOMING_FEATURE(ExistentialAny, 335, 7)
272+
ADOPTABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7)
238273
UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
239274
UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
240275

@@ -485,6 +520,7 @@ EXPERIMENTAL_FEATURE(CompileTimeValues, true)
485520
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
486521
#undef EXPERIMENTAL_FEATURE
487522
#undef UPCOMING_FEATURE
523+
#undef ADOPTABLE_UPCOMING_FEATURE
488524
#undef BASELINE_LANGUAGE_FEATURE
489525
#undef OPTIONAL_LANGUAGE_FEATURE
490526
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE

include/swift/Basic/LangOptions.h

+63-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -20,7 +20,6 @@
2020

2121
#include "swift/Basic/CXXStdlibKind.h"
2222
#include "swift/Basic/Feature.h"
23-
#include "swift/Basic/FixedBitSet.h"
2423
#include "swift/Basic/FunctionBodySkipping.h"
2524
#include "swift/Basic/LLVM.h"
2625
#include "swift/Basic/PlaygroundOption.h"
@@ -725,19 +724,6 @@ namespace swift {
725724
return cxxInteropCompatVersion.isVersionAtLeast(major, minor);
726725
}
727726

728-
/// Determine whether the given feature is enabled.
729-
bool hasFeature(Feature feature) const;
730-
731-
/// Determine whether the given feature is enabled, looking up the feature
732-
/// by name.
733-
bool hasFeature(llvm::StringRef featureName) const;
734-
735-
/// Enable the given feature.
736-
void enableFeature(Feature feature) { Features.insert(feature); }
737-
738-
/// Disable the given feature.
739-
void disableFeature(Feature feature) { Features.remove(feature); }
740-
741727
/// Sets the "_hasAtomicBitWidth" conditional.
742728
void setHasAtomicBitWidth(llvm::Triple triple);
743729

@@ -822,10 +808,68 @@ namespace swift {
822808
PlatformConditionValues;
823809
llvm::SmallVector<std::string, 2> CustomConditionalCompilationFlags;
824810

825-
/// The set of features that have been enabled. Doesn't include upcoming
826-
/// features, which are checked against the language version in
827-
/// `hasFeature`.
828-
FixedBitSet<numFeatures(), Feature> Features;
811+
public:
812+
// MARK: Features
813+
// =========================================================================
814+
815+
/// A wrapper around the feature state enumeration.
816+
struct FeatureState {
817+
enum Kind : uint8_t { Off, EnabledForAdoption, Enabled };
818+
819+
private:
820+
Feature feature;
821+
Kind state;
822+
823+
public:
824+
FeatureState(Feature feature, Kind state)
825+
: feature(feature), state(state) {}
826+
827+
/// Returns whether the feature is enabled.
828+
bool isEnabled() const;
829+
830+
/// Returns whether the feature is enabled in adoption mode. Should only
831+
/// be called if the feature is known to support this mode.
832+
bool isEnabledForAdoption() const;
833+
834+
operator Kind() const { return state; }
835+
};
836+
837+
private:
838+
class FeatureStateStorage {
839+
std::vector<FeatureState::Kind> states;
840+
841+
public:
842+
FeatureStateStorage();
843+
844+
/// Sets the given state for the given feature.
845+
void setState(Feature feature, FeatureState::Kind state);
846+
847+
/// Retrieves the state of the given feature.
848+
FeatureState getState(Feature feature) const;
849+
};
850+
851+
/// The states of language features.
852+
FeatureStateStorage featureStates;
853+
854+
public:
855+
/// Retrieve the state of the given feature.
856+
FeatureState getFeatureState(Feature feature) const;
857+
858+
/// Returns whether the given feature is enabled.
859+
bool hasFeature(Feature feature) const;
860+
861+
/// Returns whether a feature with the given name is enabled. Returns
862+
/// `false` if a feature by this name is not known.
863+
bool hasFeature(llvm::StringRef featureName) const;
864+
865+
/// Enables the given feature (enables in adoption mode if `forAdoption` is
866+
/// `true`).
867+
void enableFeature(Feature feature, bool forAdoption = false);
868+
869+
/// Disables the given feature.
870+
void disableFeature(Feature feature);
871+
872+
// =========================================================================
829873
};
830874

831875
class TypeCheckerOptions final {

lib/AST/ASTPrinter.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// This source file is part of the Swift.org open source project
33
//
4-
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
4+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
55
// Licensed under Apache License v2.0 with Runtime Library Exception
66
//
77
// See https://swift.org/LICENSE.txt for license information
@@ -3267,7 +3267,7 @@ suppressingFeatureExecutionAttribute(PrintOptions &options,
32673267
static void suppressingFeature(PrintOptions &options, Feature feature,
32683268
llvm::function_ref<void()> action) {
32693269
switch (feature) {
3270-
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
3270+
#define LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description) \
32713271
case Feature::FeatureName: \
32723272
llvm_unreachable("not a suppressible feature");
32733273
#define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \

lib/AST/FeatureSet.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2024 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2024 - 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -45,7 +45,7 @@ static bool usesTypeMatching(Decl *decl, llvm::function_ref<bool(Type)> fn) {
4545

4646
#define BASELINE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
4747
static bool usesFeature##FeatureName(Decl *decl) { return false; }
48-
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
48+
#define LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description)
4949
#include "swift/Basic/Features.def"
5050

5151
#define UNINTERESTING_FEATURE(FeatureName) \
@@ -551,7 +551,7 @@ void FeatureSet::collectFeaturesUsed(Decl *decl, InsertOrRemove operation) {
551551

552552
// Go through each of the features, checking whether the
553553
// declaration uses that feature.
554-
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
554+
#define LANGUAGE_FEATURE(FeatureName, IsAdoptable, SENumber, Description) \
555555
if (CHECK(usesFeature##FeatureName)) \
556556
collectRequiredFeature(Feature::FeatureName, operation);
557557
#define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \

0 commit comments

Comments
 (0)