Skip to content

Commit d9e1755

Browse files
committed
[BitwiseCopyable] Don't derive on @unchecked field
Allow for a type to conform to BitwiseCopyable but not in such a way that aggregates containing an instance will derive conformance automatically. Useful for types which don't involve reference counting but nonetheless can't simply be copied bit-by-bit.
1 parent e43fac5 commit d9e1755

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

lib/Sema/TypeCheckBitwise.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class BitwiseCopyableStorageVisitor : public StorageVisitor {
106106

107107
bool visitMemberDecl(ValueDecl *storage, Type ty);
108108
bool visitMemberType(Type type, SourceLoc loc);
109+
bool isUnchecked(ProtocolConformanceRef conformance);
109110
bool visitNonconformingMemberType(Type type, SourceLoc loc);
110111
void emitNonconformingMemberTypeDiagnostic(Type ty, SourceLoc loc);
111112
};
@@ -136,6 +137,13 @@ bool BitwiseCopyableStorageVisitor::visitMemberType(Type ty, SourceLoc loc) {
136137
return visitNonconformingMemberType(ty, loc);
137138
}
138139

140+
if (isImplicit(check) && isUnchecked(conformance)) {
141+
// Do not automatically derive conformance if one of the field's
142+
// conformance is @unchecked.
143+
invalid = true;
144+
return true;
145+
}
146+
139147
// Walk the conformance, diagnosing any missing BitwiseCopyable conformances.
140148
bool anyMissing = false;
141149
conformance.forEachMissingConformance(
@@ -150,6 +158,20 @@ bool BitwiseCopyableStorageVisitor::visitMemberType(Type ty, SourceLoc loc) {
150158
return anyMissing;
151159
}
152160

161+
bool BitwiseCopyableStorageVisitor::isUnchecked(
162+
ProtocolConformanceRef conformance) {
163+
if (!conformance.isConcrete())
164+
return false;
165+
auto concrete = conformance.getConcrete();
166+
assert(concrete);
167+
auto *root = concrete->getRootConformance();
168+
assert(root);
169+
auto *normal = dyn_cast<NormalProtocolConformance>(root);
170+
if (!normal)
171+
return false;
172+
return normal->isUnchecked();
173+
}
174+
153175
bool BitwiseCopyableStorageVisitor::visitNonconformingMemberType(
154176
Type ty, SourceLoc loc) {
155177
if (ty->hasError())

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2165,7 +2165,8 @@ static void diagnoseConformanceImpliedByConditionalConformance(
21652165
/// to the given protocol. This should return true when @unchecked can be
21662166
/// used to disable those semantic checks.
21672167
static bool hasAdditionalSemanticChecks(ProtocolDecl *proto) {
2168-
return proto->isSpecificProtocol(KnownProtocolKind::Sendable);
2168+
return proto->isSpecificProtocol(KnownProtocolKind::Sendable) ||
2169+
proto->isSpecificProtocol(KnownProtocolKind::BitwiseCopyable);
21692170
}
21702171

21712172
/// Determine whether the type \c T conforms to the protocol \c Proto,

test/Sema/bitwise_copyable.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ struct S_Explicit_With_Metatype_Optional_AnyObject : _BitwiseCopyable {
9494
var ty: Optional<AnyObject>.Type
9595
}
9696

97+
struct S_Unchecked : @unchecked _BitwiseCopyable {}
98+
99+
struct S_Implicit_With_S_Unchecked {
100+
var s: S_Unchecked
101+
}
102+
103+
func passS_Implicit_With_S_Unchecked(_ s: S_Implicit_With_S_Unchecked) {
104+
take1(s) // expected-error{{type_does_not_conform_decl_owner}}
105+
// expected-note@-92 {{where_requirement_failure_one_subst}}
106+
}
107+
108+
struct S_Explicit_With_S_Unchecked : _BitwiseCopyable {
109+
var s: S_Unchecked
110+
}
111+
97112
//==============================================================================
98113
//===========================DEPENDENCY-FREE TESTS=(END)======================}}
99114
//==============================================================================

0 commit comments

Comments
 (0)