Skip to content

Commit db0d658

Browse files
authored
Merge pull request #79645 from DougGregor/enable-se-0458-by-default
[SE-0458] Enable unsafe expressions / attributes / for..in effects by default
2 parents 3806913 + 7977e46 commit db0d658

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+493
-143
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,31 @@
33
> [!NOTE]
44
> This is in reverse chronological order, so newer entries are added to the top.
55
6+
## Swift 6.2
7+
8+
* [SE-0458][]:
9+
Introduced an opt-in mode for strict checking of memory safety, which can be
10+
enabled with the compiler flag `-strict-memory-safety`. In this mode,
11+
the Swift compiler will produce warnings for uses of memory-unsafe constructs
12+
and APIs. For example,
13+
14+
```swift
15+
func evilMalloc(size: Int) -> Int {
16+
// warning: call to global function 'malloc' involves unsafe type 'UnsafeMutableRawPointer'
17+
return Int(bitPattern: malloc(size))
18+
}
19+
```
20+
21+
These warnings are in their own diagnostic group (`Unsafe`) and can
22+
be suppressed by ackwnowledging the memory-unsafe behavior, for
23+
example with an `unsafe` expression:
24+
25+
```swift
26+
func evilMalloc(size: Int) -> Int {
27+
return unsafe Int(bitPattern: malloc(size)) // no warning
28+
}
29+
```
30+
631
## Swift 6.1
732

833
* Previous versions of Swift would incorrectly allow Objective-C `-init...`
@@ -10676,6 +10701,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig
1067610701
[SE-0431]: https://github.com/apple/swift-evolution/blob/main/proposals/0431-isolated-any-functions.md
1067710702
[SE-0442]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0442-allow-taskgroup-childtaskresult-type-to-be-inferred.md
1067810703
[SE-0444]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md
10704+
[SE-0458]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md
1067910705
[#64927]: <https://github.com/apple/swift/issues/64927>
1068010706
[#42697]: <https://github.com/apple/swift/issues/42697>
1068110707
[#42728]: <https://github.com/apple/swift/issues/42728>

include/swift/AST/ConformanceAttributes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct ConformanceAttributes {
2727

2828
/// The location of the "unsafe" attribute if present.
2929
SourceLoc unsafeLoc;
30+
31+
/// The location of the "@isolated" attribute if present.
32+
SourceLoc isolatedLoc;
3033

3134
/// Merge other conformance attributes into this set.
3235
ConformanceAttributes &
@@ -37,6 +40,8 @@ struct ConformanceAttributes {
3740
preconcurrencyLoc = other.preconcurrencyLoc;
3841
if (other.unsafeLoc.isValid())
3942
unsafeLoc = other.unsafeLoc;
43+
if (other.isolatedLoc.isValid())
44+
isolatedLoc = other.isolatedLoc;
4045
return *this;
4146
}
4247
};

include/swift/AST/Decl.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,12 +1836,13 @@ struct InheritedEntry : public TypeLoc {
18361836
bool isPreconcurrency() const {
18371837
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
18381838
}
1839+
bool isIsolated() const {
1840+
return getOptions().contains(ProtocolConformanceFlags::Isolated);
1841+
}
18391842

18401843
ExplicitSafety getExplicitSafety() const {
18411844
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
18421845
return ExplicitSafety::Unsafe;
1843-
if (getOptions().contains(ProtocolConformanceFlags::Safe))
1844-
return ExplicitSafety::Safe;
18451846
return ExplicitSafety::Unspecified;
18461847
}
18471848

@@ -1852,13 +1853,10 @@ struct InheritedEntry : public TypeLoc {
18521853
}
18531854

18541855
void setOption(ExplicitSafety safety) {
1855-
RawOptions = (getOptions() - ProtocolConformanceFlags::Unsafe
1856-
- ProtocolConformanceFlags::Safe).toRaw();
1856+
RawOptions = (getOptions() - ProtocolConformanceFlags::Unsafe).toRaw();
18571857
switch (safety) {
18581858
case ExplicitSafety::Unspecified:
1859-
break;
18601859
case ExplicitSafety::Safe:
1861-
RawOptions = (getOptions() | ProtocolConformanceFlags::Safe).toRaw();
18621860
break;
18631861
case ExplicitSafety::Unsafe:
18641862
RawOptions = (getOptions() | ProtocolConformanceFlags::Unsafe).toRaw();

include/swift/AST/DiagnosticsSema.def

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,8 +2722,23 @@ WARNING(add_predates_concurrency_import,none,
27222722
GROUPED_WARNING(remove_predates_concurrency_import,PreconcurrencyImport,
27232723
DefaultIgnore,
27242724
"'@preconcurrency' attribute on module %0 has no effect", (Identifier))
2725+
NOTE(add_isolated_to_conformance,none,
2726+
"add 'isolated' to the %0 conformance to restrict it to %1 code",
2727+
(DeclName, ActorIsolation))
27252728
NOTE(add_preconcurrency_to_conformance,none,
27262729
"add '@preconcurrency' to the %0 conformance to defer isolation checking to run time", (DeclName))
2730+
ERROR(isolated_conformance_not_global_actor_isolated,none,
2731+
"isolated conformance is only permitted on global-actor-isolated types",
2732+
())
2733+
ERROR(isolated_conformance_experimental_feature,none,
2734+
"isolated conformances require experimental feature "
2735+
" 'IsolatedConformances'", ())
2736+
ERROR(nonisolated_conformance_depends_on_isolated_conformance,none,
2737+
"conformance of %0 to %1 depends on %2 conformance of %3 to %4; mark it as 'isolated'",
2738+
(Type, DeclName, ActorIsolation, Type, DeclName))
2739+
ERROR(isolated_conformance_mismatch_with_associated_isolation,none,
2740+
"%0 conformance of %1 to %2 cannot depend on %3 conformance of %4 to %5",
2741+
(ActorIsolation, Type, DeclName, ActorIsolation, Type, DeclName))
27272742
WARNING(remove_public_import,none,
27282743
"public import of %0 was not used in public declarations or inlinable code",
27292744
(Identifier))
@@ -8149,9 +8164,6 @@ NOTE(sending_function_result_with_sending_param_note, none,
81498164
//------------------------------------------------------------------------------
81508165
// MARK: Strict Safety Diagnostics
81518166
//------------------------------------------------------------------------------
8152-
ERROR(unsafe_attr_disabled,none,
8153-
"attribute requires '-enable-experimental-feature AllowUnsafeAttribute'", ())
8154-
81558167
NOTE(note_reference_to_unsafe_decl,none,
81568168
"%select{reference|call}0 to unsafe %kind1",
81578169
(bool, const ValueDecl *))

include/swift/AST/ProtocolConformance.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,11 @@ class NormalProtocolConformance : public RootProtocolConformance,
669669
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
670670
}
671671

672+
/// Whether this is an isolated conformance.
673+
bool isIsolated() const {
674+
return getOptions().contains(ProtocolConformanceFlags::Isolated);
675+
}
676+
672677
/// Retrieve the location of `@preconcurrency`, if there is one and it is
673678
/// known.
674679
SourceLoc getPreconcurrencyLoc() const { return PreconcurrencyLoc; }
@@ -678,8 +683,6 @@ class NormalProtocolConformance : public RootProtocolConformance,
678683
ExplicitSafety getExplicitSafety() const {
679684
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
680685
return ExplicitSafety::Unsafe;
681-
if (getOptions().contains(ProtocolConformanceFlags::Safe))
682-
return ExplicitSafety::Safe;
683686
return ExplicitSafety::Unspecified;
684687
}
685688

include/swift/AST/ProtocolConformanceOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ enum class ProtocolConformanceFlags {
3434
/// @retroactive conformance
3535
Retroactive = 0x08,
3636

37-
/// @safe conformance
38-
Safe = 0x10,
37+
/// @isolated conformance
38+
Isolated = 0x10,
3939

4040
// Note: whenever you add a bit here, update
4141
// NumProtocolConformanceOptions below.

include/swift/Basic/Features.def

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
// for features that can be assumed to be available in any Swift compiler that
4949
// will be used to process the textual interface files produced by this
5050
// Swift compiler.
51+
//
52+
// OPTIONAL_LANGUAGE_FEATURE is the same as LANGUAGE_FEATURE, but describes
53+
// accepted features that can be enabled independently of language version and
54+
// are not scheduled to be enabled in some specific language version. Examples
55+
// of optional language features include strict memory safety checking (SE-0458)
56+
// and Embedded Swift.
5157
//===----------------------------------------------------------------------===//
5258

5359
#ifndef LANGUAGE_FEATURE
@@ -89,6 +95,11 @@
8995
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
9096
#endif
9197

98+
#ifndef OPTIONAL_LANGUAGE_FEATURE
99+
# define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
100+
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
101+
#endif
102+
92103
// A feature that's both conditionally-suppressible and experimental.
93104
// Delegates to whichever the includer defines.
94105
#ifndef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
@@ -203,6 +214,7 @@ LANGUAGE_FEATURE(IsolatedAny2, 431, "@isolated(any) function types")
203214
LANGUAGE_FEATURE(ObjCImplementation, 436, "@objc @implementation extensions")
204215
LANGUAGE_FEATURE(NonescapableTypes, 446, "Nonescapable types")
205216
LANGUAGE_FEATURE(BuiltinEmplaceTypedThrows, 0, "Builtin.emplace typed throws")
217+
SUPPRESSIBLE_LANGUAGE_FEATURE(MemorySafetyAttributes, 458, "@unsafe attribute")
206218

207219
// Swift 6
208220
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
@@ -226,6 +238,14 @@ UPCOMING_FEATURE(ExistentialAny, 335, 7)
226238
UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
227239
UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
228240

241+
// Optional language features / modes
242+
243+
/// Diagnose uses of language constructs and APIs that can violate memory
244+
/// safety.
245+
OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety")
246+
247+
// Experimental features
248+
229249
EXPERIMENTAL_FEATURE(StaticAssert, false)
230250
EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false)
231251
EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false)
@@ -396,12 +416,6 @@ EXPERIMENTAL_FEATURE(Extern, true)
396416
// Enable trailing comma for comma-separated lists.
397417
EXPERIMENTAL_FEATURE(TrailingComma, false)
398418

399-
/// Allow the @unsafe attribute.
400-
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(AllowUnsafeAttribute, true)
401-
402-
/// Warn on use of unsafe constructs.
403-
EXPERIMENTAL_FEATURE(WarnUnsafe, true)
404-
405419
// Import bounds safety and lifetime attributes from interop headers to
406420
// generate Swift wrappers with safe pointer types.
407421
EXPERIMENTAL_FEATURE(SafeInteropWrappers, false)
@@ -450,15 +464,20 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(CustomAvailability, true)
450464
/// Be strict about the Sendable conformance of metatypes.
451465
EXPERIMENTAL_FEATURE(StrictSendableMetatypes, true)
452466

467+
453468
/// Allow public enumerations to be extensible by default
454469
/// regardless of whether the module they are declared in
455470
/// is resilient or not.
456471
EXPERIMENTAL_FEATURE(ExtensibleEnums, true)
457472

473+
/// Allow isolated conformances.
474+
EXPERIMENTAL_FEATURE(IsolatedConformances, true)
475+
458476
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
459477
#undef EXPERIMENTAL_FEATURE
460478
#undef UPCOMING_FEATURE
461479
#undef BASELINE_LANGUAGE_FEATURE
480+
#undef OPTIONAL_LANGUAGE_FEATURE
462481
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
463482
#undef CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE
464483
#undef SUPPRESSIBLE_EXPERIMENTAL_FEATURE

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,11 @@ def disable_upcoming_feature : Separate<["-"], "disable-upcoming-feature">,
10051005
HelpText<"Disable a feature that will be introduced in an upcoming language "
10061006
"version">;
10071007

1008+
def strict_memory_safety : Flag<["-"], "strict-memory-safety">,
1009+
Flags<[FrontendOption, ModuleInterfaceOptionIgnorable,
1010+
SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>,
1011+
HelpText<"Enable strict memory safety checking">;
1012+
10081013
def Rpass_EQ : Joined<["-"], "Rpass=">,
10091014
Flags<[FrontendOption]>,
10101015
HelpText<"Report performed transformations by optimization passes whose "

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3214,9 +3214,10 @@ struct ExcludeAttrRAII {
32143214
}
32153215

32163216
static void
3217-
suppressingFeatureAllowUnsafeAttribute(PrintOptions &options,
3217+
suppressingFeatureMemorySafetyAttributes(PrintOptions &options,
32183218
llvm::function_ref<void()> action) {
32193219
ExcludeAttrRAII scope(options.ExcludeAttrList, DeclAttrKind::Unsafe);
3220+
ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::Safe);
32203221
action();
32213222
}
32223223

lib/AST/ConformanceLookupTable.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
154154
options |= ProtocolConformanceFlags::Preconcurrency;
155155
if (getUnsafeLoc().isValid())
156156
options |= ProtocolConformanceFlags::Unsafe;
157+
if (getIsolatedLoc().isValid())
158+
options |= ProtocolConformanceFlags::Isolated;
157159
return options;
158160
}
159161

@@ -209,6 +211,11 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
209211
return attributes.unsafeLoc;
210212
}
211213

214+
/// The location of the @isolated attribute, if any.
215+
SourceLoc getIsolatedLoc() const {
216+
return attributes.isolatedLoc;
217+
}
218+
212219
/// For an inherited conformance, retrieve the class declaration
213220
/// for the inheriting class.
214221
ClassDecl *getInheritingClass() const {

lib/AST/Decl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,8 @@ InheritedEntry::InheritedEntry(const TypeLoc &typeLoc)
17801780
setOption(ProtocolConformanceFlags::Unsafe);
17811781
if (typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency).isValid())
17821782
setOption(ProtocolConformanceFlags::Preconcurrency);
1783+
if (typeRepr->findAttrLoc(TypeAttrKind::Isolated).isValid())
1784+
setOption(ProtocolConformanceFlags::Isolated);
17831785
}
17841786
}
17851787

lib/AST/FeatureSet.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,6 @@ UNINTERESTING_FEATURE(ReinitializeConsumeInMultiBlockDefer)
330330
UNINTERESTING_FEATURE(SE427NoInferenceOnExtension)
331331
UNINTERESTING_FEATURE(TrailingComma)
332332

333-
static bool usesFeatureAllowUnsafeAttribute(Decl *decl) {
334-
return decl->getAttrs().hasAttribute<UnsafeAttr>();
335-
}
336-
337333
static ABIAttr *getABIAttr(Decl *decl) {
338334
if (auto pbd = dyn_cast<PatternBindingDecl>(decl))
339335
for (auto i : range(pbd->getNumPatternEntries()))
@@ -348,7 +344,17 @@ static bool usesFeatureABIAttribute(Decl *decl) {
348344
return getABIAttr(decl) != nullptr;
349345
}
350346

351-
UNINTERESTING_FEATURE(WarnUnsafe)
347+
static bool usesFeatureIsolatedConformances(Decl *decl) {
348+
// FIXME: Check conformances associated with this decl?
349+
return false;
350+
}
351+
352+
static bool usesFeatureMemorySafetyAttributes(Decl *decl) {
353+
return decl->getAttrs().hasAttribute<SafeAttr>() ||
354+
decl->getAttrs().hasAttribute<UnsafeAttr>();
355+
}
356+
357+
UNINTERESTING_FEATURE(StrictMemorySafety)
352358
UNINTERESTING_FEATURE(SafeInteropWrappers)
353359
UNINTERESTING_FEATURE(AssumeResilientCxxTypes)
354360
UNINTERESTING_FEATURE(CoroutineAccessorsUnwindOnCallerError)

lib/AST/NameLookup.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3144,6 +3144,12 @@ directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx,
31443144
attributed->getTypeRepr(), dc, options);
31453145
}
31463146

3147+
case TypeReprKind::Isolated: {
3148+
auto isolated = cast<IsolatedTypeRepr>(typeRepr);
3149+
return directReferencesForTypeRepr(evaluator, ctx,
3150+
isolated->getBase(), dc, options);
3151+
}
3152+
31473153
case TypeReprKind::Composition: {
31483154
auto composition = cast<CompositionTypeRepr>(typeRepr);
31493155
for (auto component : composition->getTypes()) {
@@ -3217,7 +3223,6 @@ directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx,
32173223
case TypeReprKind::Error:
32183224
case TypeReprKind::Function:
32193225
case TypeReprKind::Ownership:
3220-
case TypeReprKind::Isolated:
32213226
case TypeReprKind::CompileTimeConst:
32223227
case TypeReprKind::Metatype:
32233228
case TypeReprKind::Protocol:
@@ -3933,6 +3938,21 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
39333938
return nullptr;
39343939
}
39353940

3941+
/// Find the location of 'isolated' within this type representation.
3942+
static SourceLoc findIsolatedLoc(TypeRepr *typeRepr) {
3943+
do {
3944+
if (auto isolatedTypeRepr = dyn_cast<IsolatedTypeRepr>(typeRepr))
3945+
return isolatedTypeRepr->getLoc();
3946+
3947+
if (auto attrTypeRepr = dyn_cast<AttributedTypeRepr>(typeRepr)) {
3948+
typeRepr = attrTypeRepr->getTypeRepr();
3949+
continue;
3950+
}
3951+
3952+
return SourceLoc();
3953+
} while (true);
3954+
}
3955+
39363956
/// Decompose the ith inheritance clause entry to a list of type declarations,
39373957
/// inverses, and optional AnyObject member.
39383958
void swift::getDirectlyInheritedNominalTypeDecls(
@@ -3971,6 +3991,9 @@ void swift::getDirectlyInheritedNominalTypeDecls(
39713991
attributes.uncheckedLoc = typeRepr->findAttrLoc(TypeAttrKind::Unchecked);
39723992
attributes.preconcurrencyLoc = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency);
39733993
attributes.unsafeLoc = typeRepr->findAttrLoc(TypeAttrKind::Unsafe);
3994+
3995+
// Look for an IsolatedTypeRepr.
3996+
attributes.isolatedLoc = findIsolatedLoc(typeRepr);
39743997
}
39753998

39763999
// Form the result.

lib/ASTGen/Sources/ASTGen/SourceFile.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ extension Parser.ExperimentalFeatures {
7777
mapFeature(.CoroutineAccessors, to: .coroutineAccessors)
7878
mapFeature(.ValueGenerics, to: .valueGenerics)
7979
mapFeature(.ABIAttribute, to: .abiAttribute)
80-
mapFeature(.WarnUnsafe, to: .unsafeExpression)
8180
}
8281
}
8382

0 commit comments

Comments
 (0)