Skip to content

Strict safety improvements toolchain workaround #78340

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

Closed
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
4 changes: 2 additions & 2 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/AST/Evaluator.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Import.h"
#include "swift/AST/ProtocolConformanceOptions.h"
#include "swift/AST/SILOptions.h"
#include "swift/AST/SearchPathOptions.h"
#include "swift/AST/Type.h"
Expand Down Expand Up @@ -1299,8 +1300,7 @@ class ASTContext final {
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state,
bool isUnchecked,
bool isPreconcurrency,
ProtocolConformanceOptions options,
SourceLoc preconcurrencyLoc = SourceLoc());

/// Produce a self-conformance for the given protocol.
Expand Down
46 changes: 31 additions & 15 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "swift/AST/Initializer.h"
#include "swift/AST/LayoutConstraint.h"
#include "swift/AST/LifetimeAnnotation.h"
#include "swift/AST/ProtocolConformanceOptions.h"
#include "swift/AST/ReferenceCounting.h"
#include "swift/AST/RequirementSignature.h"
#include "swift/AST/StorageImpl.h"
Expand Down Expand Up @@ -1782,14 +1783,8 @@ class ImportDecl final : public Decl,
/// An entry in the "inherited" list of a type or extension.
struct InheritedEntry : public TypeLoc {
private:
/// Whether there was an @unchecked attribute.
bool IsUnchecked : 1;

/// Whether there was an @retroactive attribute.
bool IsRetroactive : 1;

/// Whether there was an @preconcurrency attribute.
bool IsPreconcurrency : 1;
/// Options on a protocol conformance that are expressed as attributes.
unsigned RawOptions: 8;

/// Whether there was a ~ indicating suppression.
///
Expand All @@ -1799,17 +1794,38 @@ struct InheritedEntry : public TypeLoc {
public:
InheritedEntry(const TypeLoc &typeLoc);

InheritedEntry(const TypeLoc &typeLoc, bool isUnchecked, bool isRetroactive,
bool isPreconcurrency, bool isSuppressed = false)
: TypeLoc(typeLoc), IsUnchecked(isUnchecked),
IsRetroactive(isRetroactive), IsPreconcurrency(isPreconcurrency),
InheritedEntry(const TypeLoc &typeLoc, ProtocolConformanceOptions options,
bool isSuppressed = false)
: TypeLoc(typeLoc), RawOptions(options.toRaw()),
IsSuppressed(isSuppressed) {}

bool isUnchecked() const { return IsUnchecked; }
bool isRetroactive() const { return IsRetroactive; }
bool isPreconcurrency() const { return IsPreconcurrency; }
ProtocolConformanceOptions getOptions() const {
return ProtocolConformanceOptions(RawOptions);
}

bool isUnchecked() const {
return getOptions().contains(ProtocolConformanceFlags::Unchecked);
}
bool isRetroactive() const {
return getOptions().contains(ProtocolConformanceFlags::Retroactive);
}
bool isPreconcurrency() const {
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
}
bool isUnsafe() const {
return getOptions().contains(ProtocolConformanceFlags::Unsafe);
}

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

bool isSuppressed() const { return IsSuppressed; }

void setOption(ProtocolConformanceFlags flag) {
RawOptions = (getOptions() | flag).toRaw();
}

void setSuppressed() {
assert(!IsSuppressed && "setting suppressed again!?");
IsSuppressed = true;
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ SIMPLE_DECL_ATTR(_addressableSelf, AddressableSelf,

DECL_ATTR(safe, Safe,
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
OnExtension | OnTypeAlias | UserInaccessible |
OnExtension | OnTypeAlias | OnImport | UserInaccessible |
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
163)

Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -589,5 +589,9 @@ ERROR(experimental_not_supported_in_production,none,
"experimental feature '%0' cannot be enabled in production compiler",
(StringRef))

GROUPED_WARNING(Ounchecked_with_strict_safety,Unsafe,none,
"'-Ounchecked' is not memory-safe and should not be combined with "
"strict memory safety checking", ())

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
57 changes: 30 additions & 27 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -5792,22 +5792,19 @@ ERROR(non_sendable_type,none,
ERROR(sendable_raw_storage,none,
"struct %0 with @_rawLayout does not conform to the 'Sendable' protocol", (DeclName))

ERROR(typeattr_not_inheritance_clause,none,
"'%0' attribute only applies in inheritance clauses", (StringRef))
ERROR(typeattr_not_existential,none,
"'%0' attribute cannot apply to non-protocol type %1", (StringRef, Type))

WARNING(unchecked_conformance_not_special,none,
"@unchecked conformance to %0 has no meaning", (Type))
WARNING(restate_unchecked_sendable,none,
"class %0 must restate inherited '@unchecked Sendable' conformance",
(DeclName))
ERROR(unchecked_not_inheritance_clause,none,
"'unchecked' attribute only applies in inheritance clauses", ())
ERROR(unchecked_not_existential,none,
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))

WARNING(preconcurrency_conformance_not_used,none,
"@preconcurrency attribute on conformance to %0 has no effect", (Type))
ERROR(preconcurrency_not_inheritance_clause,none,
"'preconcurrency' attribute only applies in inheritance clauses", ())
ERROR(preconcurrency_not_existential,none,
"'preconcurrency' attribute cannot apply to non-protocol type %0", (Type))

ERROR(redundant_any_in_existential,none,
"redundant 'any' in type %0",
Expand Down Expand Up @@ -7570,17 +7567,13 @@ ERROR(cannot_convert_default_value_type_to_argument_type, none,
// MARK: Back deployment
//------------------------------------------------------------------------------

ERROR(attr_incompatible_with_back_deployed,none,
"'%0' cannot be applied to a back deployed %kind1",
(DeclAttribute, const Decl *))

WARNING(back_deployed_opaque_result_not_supported,none,
"'%0' cannot be applied to %kind1 because it has a 'some' return type",
(DeclAttribute, const ValueDecl *))
ERROR(attr_incompatible_with_back_deploy,none,
"'%0' cannot be applied to a back deployed %1",
(DeclAttribute, DescriptiveDeclKind))

ERROR(back_deployed_requires_body,none,
"'%0' requires that %kind1 have a body",
(DeclAttribute, const ValueDecl *))
WARNING(backdeployed_opaque_result_not_supported,none,
"'%0' is unsupported on a %1 with a 'some' return type",
(DeclAttribute, DescriptiveDeclKind))

//------------------------------------------------------------------------------
// MARK: Implicit opening of existential types
Expand Down Expand Up @@ -8093,17 +8086,25 @@ NOTE(note_reference_to_nonisolated_unsafe,none,
(const ValueDecl *))
NOTE(note_reference_unowned_unsafe,none,
"reference to unowned(unsafe) %kind0 is unsafe", (const ValueDecl *))

GROUPED_WARNING(override_safe_withunsafe,Unsafe,none,
"override of safe %0 with unsafe %0", (DescriptiveDeclKind))
GROUPED_WARNING(witness_unsafe,Unsafe,none,
NOTE(note_use_of_unsafe_conformance_is_unsafe,none,
"@unsafe conformance of %0 to %kind1 involves unsafe code",
(Type, const ValueDecl *))
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",
(Type, const ValueDecl *))
NOTE(note_witness_unsafe,none,
"unsafe %0 %1 cannot satisfy safe requirement",
(DescriptiveDeclKind, DeclName))
GROUPED_WARNING(type_witness_unsafe,Unsafe,none,
NOTE(note_type_witness_unsafe,none,
"unsafe type %0 cannot satisfy safe associated type %1",
(Type, DeclName))
GROUPED_WARNING(unchecked_conformance_is_unsafe,Unsafe,none,
"@unchecked conformance involves unsafe code", ())

GROUPED_WARNING(override_safe_withunsafe,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_to_nonisolated_unsafe,Unsafe,none,
Expand All @@ -8115,8 +8116,10 @@ GROUPED_WARNING(reference_to_unsafe_decl,Unsafe,none,
GROUPED_WARNING(reference_to_unsafe_typed_decl,Unsafe,none,
"%select{reference|call}0 to %kindbase1 involves unsafe type %2",
(bool, const ValueDecl *, Type))
NOTE(unsafe_decl_here,none,
"unsafe %kindbase0 declared here", (const ValueDecl *))
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 *))
Expand Down
10 changes: 9 additions & 1 deletion include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,16 +609,24 @@ struct InheritedNominalEntry : Located<NominalTypeDecl *> {
/// The location of the "preconcurrency" attribute if present.
SourceLoc preconcurrencyLoc;

/// 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)
: Located(item, loc), uncheckedLoc(uncheckedLoc),
preconcurrencyLoc(preconcurrencyLoc), isSuppressed(isSuppressed) {}
preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc),
safeRange(safeRange), isSuppressed(isSuppressed) {}
};

/// Retrieve the set of nominal type declarations that are directly
Expand Down
47 changes: 32 additions & 15 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ProtocolConformanceOptions.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/AST/TypeAlignments.h"
Expand Down Expand Up @@ -146,20 +147,21 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance
SWIFT_INLINE_BITFIELD_EMPTY(RootProtocolConformance, ProtocolConformance);

SWIFT_INLINE_BITFIELD_FULL(NormalProtocolConformance, RootProtocolConformance,
1+1+1+1+bitmax(NumProtocolConformanceStateBits,8)+
1+1+
bitmax(NumProtocolConformanceOptions,8)+
bitmax(NumProtocolConformanceStateBits,8)+
bitmax(NumConformanceEntryKindBits,8),
/// Indicates whether the conformance is invalid.
IsInvalid : 1,
/// The conformance was labeled with @unchecked.
IsUnchecked : 1,
/// The conformance was labeled with @preconcurrency.
IsPreconcurrency : 1,
/// We have allocated the AssociatedConformances array (but not necessarily
/// populated any of its elements).
HasComputedAssociatedConformances : 1,

: NumPadBits,

/// Options.
Options : bitmax(NumProtocolConformanceOptions, 8),

/// The current state of the conformance.
State : bitmax(NumProtocolConformanceStateBits, 8),
/// The reason that this conformance exists.
Expand Down Expand Up @@ -567,8 +569,8 @@ class NormalProtocolConformance : public RootProtocolConformance,
public:
NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol,
SourceLoc loc, DeclContext *dc,
ProtocolConformanceState state, bool isUnchecked,
bool isPreconcurrency,
ProtocolConformanceState state,
ProtocolConformanceOptions options,
SourceLoc preconcurrencyLoc)
: RootProtocolConformance(ProtocolConformanceKind::Normal,
conformingType),
Expand All @@ -577,12 +579,12 @@ class NormalProtocolConformance : public RootProtocolConformance,
Context(dc) {
assert(!conformingType->hasArchetype() &&
"ProtocolConformances should store interface types");
assert((preconcurrencyLoc.isInvalid() || isPreconcurrency) &&
assert((preconcurrencyLoc.isInvalid() ||
options.contains(ProtocolConformanceFlags::Preconcurrency)) &&
"Cannot have a @preconcurrency location without isPreconcurrency");
setState(state);
Bits.NormalProtocolConformance.IsInvalid = false;
Bits.NormalProtocolConformance.IsUnchecked = isUnchecked;
Bits.NormalProtocolConformance.IsPreconcurrency = isPreconcurrency;
Bits.NormalProtocolConformance.Options = options.toRaw();
Bits.NormalProtocolConformance.HasComputedAssociatedConformances = false;
Bits.NormalProtocolConformance.SourceKind =
unsigned(ConformanceEntryKind::Explicit);
Expand Down Expand Up @@ -626,27 +628,42 @@ class NormalProtocolConformance : public RootProtocolConformance,
/// Mark this conformance as invalid.
void setInvalid() { Bits.NormalProtocolConformance.IsInvalid = true; }

ProtocolConformanceOptions getOptions() const {
return ProtocolConformanceOptions(Bits.NormalProtocolConformance.Options);
}

/// Whether this is an "unchecked" conformance.
bool isUnchecked() const {
return Bits.NormalProtocolConformance.IsUnchecked;
return getOptions().contains(ProtocolConformanceFlags::Unchecked);
}

/// Mark the conformance as unchecked (equivalent to the @unchecked
/// conformance attribute).
void setUnchecked() {
// OK to mutate because the flags are not part of the folding set node ID.
Bits.NormalProtocolConformance.IsUnchecked = true;
Bits.NormalProtocolConformance.Options =
(getOptions() | ProtocolConformanceFlags::Unchecked).toRaw();
}

/// Whether this is an preconcurrency conformance.
bool isPreconcurrency() const {
return Bits.NormalProtocolConformance.IsPreconcurrency;
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
}

/// Retrieve the location of `@preconcurrency`, if there is one and it is
/// known.
SourceLoc getPreconcurrencyLoc() const { return PreconcurrencyLoc; }

/// Whether this is an "unsafe" conformance.
bool isUnsafe() const {
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 Expand Up @@ -684,8 +701,8 @@ class NormalProtocolConformance : public RootProtocolConformance,
if (auto implying = implyingConformance) {
ImplyingConformance = implying;
PreconcurrencyLoc = implying->getPreconcurrencyLoc();
Bits.NormalProtocolConformance.IsPreconcurrency =
implying->isPreconcurrency();
Bits.NormalProtocolConformance.Options =
implyingConformance->getOptions().toRaw();
}
}

Expand Down
Loading