Skip to content

Implement an unsafe expression to cover uses of unsafe constructs #78554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -1505,6 +1505,11 @@ BridgedUnresolvedSpecializeExpr BridgedUnresolvedSpecializeExpr_createParsed(
BridgedSourceLoc cLAngleLoc, BridgedArrayRef cArguments,
BridgedSourceLoc cRAngleLoc);

SWIFT_NAME("BridgedUnsafeExpr.createParsed(_:unsafeLoc:subExpr:)")
BridgedUnsafeExpr BridgedUnsafeExpr_createParsed(BridgedASTContext cContext,
BridgedSourceLoc cUnsafeLoc,
BridgedExpr cSubExpr);

SWIFT_NAME("BridgedInOutExpr.createParsed(_:loc:subExpr:)")
BridgedInOutExpr BridgedInOutExpr_createParsed(BridgedASTContext cContext,
BridgedSourceLoc cLoc,
Expand Down
20 changes: 0 additions & 20 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2830,26 +2830,6 @@ class RawLayoutAttr final : public DeclAttribute {
UNIMPLEMENTED_CLONE(RawLayoutAttr)
};

class SafeAttr final : public DeclAttribute {
public:
/// The optional message.
const StringRef message;

SafeAttr(SourceLoc atLoc, SourceRange range, StringRef message,
bool isImplicit = false)
: DeclAttribute(DeclAttrKind::Safe, atLoc, range, isImplicit),
message(message) { }

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DeclAttrKind::Safe;
}

/// Create a copy of this attribute.
SafeAttr *clone(ASTContext &ctx) const {
return new (ctx) SafeAttr(AtLoc, Range, message, isImplicit());
}
};

class LifetimeAttr final : public DeclAttribute {
LifetimeEntry *entry;

Expand Down
7 changes: 0 additions & 7 deletions include/swift/AST/AvailabilityContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ class AvailabilityContext {
/// Returns true if this context is `@_unavailableInEmbedded`.
bool isUnavailableInEmbedded() const;

/// Returns true if this context allows the use of unsafe constructs inside
/// it.
bool allowsUnsafe() const;

/// Constrain with another `AvailabilityContext`.
void constrainWithContext(const AvailabilityContext &other, ASTContext &ctx);

Expand All @@ -107,9 +103,6 @@ class AvailabilityContext {
constrainWithDeclAndPlatformRange(const Decl *decl,
const AvailabilityRange &platformRange);

/// Constrain to allow unsafe code.
void constrainWithAllowsUnsafe(ASTContext &ctx);

/// Returns true if `other` is as available or is more available.
bool isContainedIn(const AvailabilityContext other) const;

Expand Down
5 changes: 0 additions & 5 deletions include/swift/AST/AvailabilityContextStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ struct AvailabilityContext::PlatformInfo {
/// platform.
unsigned IsDeprecated : 1;

/// Whether or not the context allows unsafe code within it, e.g., via the
/// `@unsafe` attribute.
unsigned AllowsUnsafe: 1;

/// Sets each field to the value of the corresponding field in `other` if the
/// other is more restrictive. Returns true if any field changed as a result
/// of adding this constraint.
Expand All @@ -67,7 +63,6 @@ struct AvailabilityContext::PlatformInfo {
ID.AddBoolean(IsUnavailableInEmbedded);
ID.AddInteger(static_cast<uint8_t>(UnavailablePlatform));
ID.AddBoolean(IsDeprecated);
ID.AddBoolean(AllowsUnsafe);
}
};

Expand Down
10 changes: 0 additions & 10 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1207,10 +1207,6 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
/// used in a "safe" dialect.
bool isUnsafe() const;

/// Whether this declaration explicitly states that it is allowed to contain
/// unsafe code.
bool allowsUnsafe() const;

private:
bool isUnsafeComputed() const {
return Bits.Decl.IsUnsafeComputed;
Expand Down Expand Up @@ -1824,10 +1820,6 @@ struct InheritedEntry : public TypeLoc {
return getOptions().contains(ProtocolConformanceFlags::Unsafe);
}

bool isSafe() const {
return getOptions().contains(ProtocolConformanceFlags::Safe);
}

bool isSuppressed() const { return IsSuppressed; }

void setOption(ProtocolConformanceFlags flag) {
Expand Down Expand Up @@ -1957,7 +1949,6 @@ class ExtensionDecl final : public GenericContext, public Decl,
friend class Decl;
public:
using Decl::getASTContext;
using Decl::allowsUnsafe;

/// Create a new extension declaration.
static ExtensionDecl *create(ASTContext &ctx, SourceLoc extensionLoc,
Expand Down Expand Up @@ -3435,7 +3426,6 @@ class GenericTypeDecl : public GenericContext, public TypeDecl {
using DeclContext::operator new;
using DeclContext::operator delete;
using TypeDecl::getDeclaredInterfaceType;
using Decl::allowsUnsafe;

static bool classof(const DeclContext *C) {
if (auto D = C->getAsDecl())
Expand Down
6 changes: 1 addition & 5 deletions include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -531,11 +531,7 @@ SIMPLE_DECL_ATTR(_addressableForDependencies, AddressableForDependencies,
OnNominalType | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UserInaccessible,
163)

DECL_ATTR(safe, Safe,
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
OnExtension | OnTypeAlias | OnImport | UserInaccessible |
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
164)
// 164 was the never-shipped @safe attribute and can be reused

DECL_ATTR(abi, ABI,
OnAbstractFunction | OnVar /* will eventually add types */ | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
Expand Down
4 changes: 0 additions & 4 deletions include/swift/AST/DeclContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -718,10 +718,6 @@ class alignas(1 << DeclContextAlignInBits) DeclContext
/// target. Used for conformance lookup disambiguation.
bool isAlwaysAvailableConformanceContext() const;

/// Determines whether this context is explicitly allowed to use unsafe
/// constructs.
bool allowsUnsafe() const;

/// \returns true if traversal was aborted, false otherwise.
bool walkContext(ASTWalker &Walker);

Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/DiagnosticEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace swift {

enum class CXXStdlibKind : uint8_t;
enum class DescriptivePatternKind : uint8_t;
enum class DiagGroupID : uint16_t;
enum class SelfAccessKind : uint8_t;
enum class ReferenceOwnership : uint8_t;
enum class StaticSpellingKind : uint8_t;
Expand Down
5 changes: 2 additions & 3 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,8 @@ ERROR(expected_expr_after_ternary_colon,none,
"expected expression after '? ... :' in ternary expression", ())
ERROR(expected_expr_after_await, none,
"expected expression after 'await'", ())
ERROR(expected_expr_after_unsafe, none,
"expected expression after 'unsafe'", ())
ERROR(expected_expr_after_move, none,
"expected expression after 'consume'", ())
ERROR(expected_expr_after_copy, none,
Expand Down Expand Up @@ -2109,9 +2111,6 @@ ERROR(parser_new_parser_errors,none,
"new Swift parser generated errors for code that C++ parser accepted",
())

ERROR(safe_attr_unchecked,none,
"'@safe' attribute must be written as '@safe(unchecked)'", ())

// MARK: Reference Binding Diagnostics
ERROR(sil_markuncheckedreferencebinding_requires_attribute,none,
"mark_unchecked_reference_binding requires an attribute like [inout]", ())
Expand Down
52 changes: 14 additions & 38 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4522,7 +4522,7 @@ WARNING(nan_comparison_both_nan, none,
(StringRef, bool))

// If you change this, also change enum TryKindForDiagnostics.
#define TRY_KIND_SELECT(SUB) "%select{try|try!|try?|await}" #SUB
#define TRY_KIND_SELECT(SUB) "%select{try|try!|try?|await|unsafe}" #SUB

ERROR(try_rhs,none,
"'" TRY_KIND_SELECT(0) "' cannot appear to the right of a "
Expand Down Expand Up @@ -8078,11 +8078,6 @@ NOTE(sending_function_result_with_sending_param_note, none,
ERROR(unsafe_attr_disabled,none,
"attribute requires '-enable-experimental-feature AllowUnsafeAttribute'", ())

GROUPED_WARNING(decl_involves_unsafe,Unsafe,none,
"%kindbase0 involves unsafe code; "
"use %select{'@unsafe' to indicate that its use is not memory-safe|"
"'@safe(unchecked)' to assert that the code is memory-safe}1",
(const Decl *, bool))
NOTE(note_reference_to_unsafe_decl,none,
"%select{reference|call}0 to unsafe %kind1",
(bool, const ValueDecl *))
Expand All @@ -8102,6 +8097,12 @@ NOTE(note_reference_exclusivity_unchecked,none,
NOTE(note_use_of_unsafe_conformance_is_unsafe,none,
"@unsafe conformance of %0 to %kind1 involves unsafe code",
(Type, const ValueDecl *))

GROUPED_WARNING(decl_signature_involves_unsafe,Unsafe,none,
"%kindbase0 has an interface that is not memory-safe; "
"use '@unsafe' to indicate that its use is unsafe",
(const Decl *))

GROUPED_WARNING(conformance_involves_unsafe,Unsafe,none,
"conformance of %0 to %kind1 involves unsafe code; use '@unsafe' to "
"indicate that the conformance is not memory-safe",
Expand All @@ -8113,44 +8114,19 @@ NOTE(note_type_witness_unsafe,none,
"unsafe type %0 cannot satisfy safe associated type %1",
(Type, DeclName))

GROUPED_WARNING(override_safe_withunsafe,Unsafe,none,
GROUPED_WARNING(override_safe_with_unsafe,Unsafe,none,
"override of safe %0 with unsafe %0", (DescriptiveDeclKind))
GROUPED_WARNING(use_of_unsafe_conformance_is_unsafe,Unsafe,none,
"@unsafe conformance of %0 to %kind1 involves unsafe code",
(Type, const ValueDecl *))
GROUPED_WARNING(reference_unowned_unsafe,Unsafe,none,
"reference to unowned(unsafe) %kind0 is unsafe", (const ValueDecl *))
GROUPED_WARNING(reference_exclusivity_unchecked,Unsafe,none,
"reference to @exclusivity(unchecked) %kind0 is unsafe", (const ValueDecl *))

GROUPED_WARNING(reference_to_nonisolated_unsafe,Unsafe,none,
"reference to nonisolated(unsafe) %kind0 is unsafe in concurrently-executing code",
(const ValueDecl *))
GROUPED_WARNING(reference_to_unsafe_decl,Unsafe,none,
"%select{reference|call}0 to unsafe %kindbase1",
(bool, const ValueDecl *))
GROUPED_WARNING(reference_to_unsafe_typed_decl,Unsafe,none,
"%select{reference|call}0 to %kindbase1 involves unsafe type %2",
(bool, const ValueDecl *, Type))
GROUPED_WARNING(reference_to_unsafe_through_typealias,Unsafe,none,
"reference to %kind0 whose underlying type involves unsafe type %1",
(const ValueDecl *, Type))

GROUPED_WARNING(preconcurrency_import_unsafe,Unsafe,none,
"@preconcurrency import is not memory-safe because it can silently "
"introduce data races; use '@safe(unchecked)' to assert that the "
"code is memory-safe", ())
NOTE(encapsulate_unsafe_in_enclosing_context,none,
"make %kindbase0 @safe(unchecked) to allow it to use unsafe constructs in its definition",
(const Decl *))
NOTE(make_enclosing_context_unsafe,none,
"make %kindbase0 @unsafe to indicate that its use is not memory-safe",
(const Decl *))
"introduce data races", ())
GROUPED_WARNING(unsafe_without_unsafe,Unsafe,none,
"expression uses unsafe constructs but is not marked with 'unsafe'", ())
WARNING(no_unsafe_in_unsafe,none,
"no unsafe operations occur within 'unsafe' expression", ())
NOTE(make_subclass_unsafe,none,
"make class %0 @unsafe to allow unsafe overrides of safe superclass methods",
(DeclName))
NOTE(make_conforming_context_unsafe,none,
"make the enclosing %0 @unsafe to allow unsafe conformance to protocol %1",
(DescriptiveDeclKind, DeclName))

//===----------------------------------------------------------------------===//
// MARK: Value Generics
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/Effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class ProtocolDecl;

enum class EffectKind : uint8_t {
Throws = 1 << 0,
Async = 1 << 1
Async = 1 << 1,
Unsafe = 1 << 2,
};
using PossibleEffects = OptionSet<EffectKind>;

Expand Down
30 changes: 30 additions & 0 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,36 @@ class AwaitExpr final : public IdentityExpr {
}
};

/// UnsafeExpr - An 'unsafe' surrounding an expression, marking that the
/// expression contains uses of unsafe declarations.
///
/// getSemanticsProvidingExpr() looks through this because it doesn't
/// provide the value and only very specific clients care where the
/// 'unsafe' was written.
class UnsafeExpr final : public IdentityExpr {
SourceLoc UnsafeLoc;
public:
UnsafeExpr(SourceLoc unsafeLoc, Expr *sub, Type type = Type(),
bool implicit = false)
: IdentityExpr(ExprKind::Unsafe, sub, type, implicit),
UnsafeLoc(unsafeLoc) {
}

static UnsafeExpr *createImplicit(ASTContext &ctx, SourceLoc unsafeLoc, Expr *sub, Type type = Type()) {
return new (ctx) UnsafeExpr(unsafeLoc, sub, type, /*implicit=*/true);
}

SourceLoc getLoc() const { return UnsafeLoc; }

SourceLoc getUnsafeLoc() const { return UnsafeLoc; }
SourceLoc getStartLoc() const { return UnsafeLoc; }
SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

static bool classof(const Expr *e) {
return e->getKind() == ExprKind::Unsafe;
}
};

/// ConsumeExpr - A 'consume' surrounding an lvalue expression marking the
/// lvalue as needing to be moved.
class ConsumeExpr final : public Expr {
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ExprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ ABSTRACT_EXPR(Identity, Expr)
EXPR(Paren, IdentityExpr)
EXPR(DotSelf, IdentityExpr)
EXPR(Await, IdentityExpr)
EXPR(Unsafe, IdentityExpr)
EXPR(Borrow, IdentityExpr)
EXPR(UnresolvedMemberChainResult, IdentityExpr)
EXPR_RANGE(Identity, Paren, UnresolvedMemberChainResult)
Expand Down
8 changes: 2 additions & 6 deletions include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -612,21 +612,17 @@ struct InheritedNominalEntry : Located<NominalTypeDecl *> {
/// The location of the "unsafe" attribute if present.
SourceLoc unsafeLoc;

/// The range of the "safe(unchecked)" attribute if present.
SourceRange safeRange;

/// Whether this inherited entry was suppressed via "~".
bool isSuppressed;

InheritedNominalEntry() { }

InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc,
SourceLoc uncheckedLoc, SourceLoc preconcurrencyLoc,
SourceLoc unsafeLoc, SourceRange safeRange,
bool isSuppressed)
SourceLoc unsafeLoc, bool isSuppressed)
: Located(item, loc), uncheckedLoc(uncheckedLoc),
preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc),
safeRange(safeRange), isSuppressed(isSuppressed) {}
isSuppressed(isSuppressed) {}
};

/// Retrieve the set of nominal type declarations that are directly
Expand Down
5 changes: 0 additions & 5 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -659,11 +659,6 @@ class NormalProtocolConformance : public RootProtocolConformance,
return getOptions().contains(ProtocolConformanceFlags::Unsafe);
}

/// Whether this is an "safe(unchecked)" conformance.
bool isSafe() const {
return getOptions().contains(ProtocolConformanceFlags::Safe);
}

/// Determine whether we've lazily computed the associated conformance array
/// already.
bool hasComputedAssociatedConformances() const {
Expand Down
7 changes: 2 additions & 5 deletions include/swift/AST/ProtocolConformanceOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,8 @@ enum class ProtocolConformanceFlags {
/// @unsafe conformance
Unsafe = 0x04,

/// @safe(unchecked) conformance
Safe = 0x08,

/// @retroactive conformance
Retroactive = 0x10,
Retroactive = 0x08,

// Note: whenever you add a bit here, update
// NumProtocolConformanceOptions below.
Expand All @@ -52,7 +49,7 @@ inline ProtocolConformanceOptions operator|(
}

enum : unsigned {
NumProtocolConformanceOptions = 5
NumProtocolConformanceOptions = 4
};

} // end namespace swift
Expand Down
6 changes: 0 additions & 6 deletions include/swift/AST/SourceFileExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#ifndef SWIFT_AST_SOURCEFILEEXTRAS_H
#define SWIFT_AST_SOURCEFILEEXTRAS_H

#include "swift/AST/UnsafeUse.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>

Expand All @@ -24,11 +23,6 @@ class Decl;
/// Extra information associated with a source file that is lazily created and
/// stored in a separately-allocated side structure.
struct SourceFileExtras {
/// Captures all of the unsafe uses associated with a given declaration.
///
/// The declaration is the entity that can be annotated (e.g., with @unsafe)
/// to suppress all of the unsafe-related diagnostics listed here.
llvm::DenseMap<const Decl *, std::vector<UnsafeUse>> unsafeUses;
};

}
Expand Down
1 change: 0 additions & 1 deletion include/swift/AST/TypeAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ SIMPLE_TYPE_ATTR(retroactive, Retroactive)
SIMPLE_TYPE_ATTR(unchecked, Unchecked)
SIMPLE_TYPE_ATTR(preconcurrency, Preconcurrency)
SIMPLE_TYPE_ATTR(unsafe, Unsafe)
SIMPLE_TYPE_ATTR(safe, Safe)
SIMPLE_TYPE_ATTR(_local, Local)
SIMPLE_TYPE_ATTR(_noMetadata, NoMetadata)
TYPE_ATTR(_opaqueReturnTypeOf, OpaqueReturnTypeOf)
Expand Down
Loading