Skip to content

Commit f14baef

Browse files
committed
Ensure that we record the @unsafe for conformances introduced via extensions
1 parent aea6b38 commit f14baef

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

lib/AST/ConformanceLookupTable.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,17 @@ namespace {
166166
/// The location of the "preconcurrency" attribute if present.
167167
const SourceLoc preconcurrencyLoc;
168168

169+
/// The location of the "unsafe" attribute if present.
170+
const SourceLoc unsafeLoc;
171+
169172
ConformanceConstructionInfo() { }
170173

171174
ConformanceConstructionInfo(ProtocolDecl *item, SourceLoc loc,
172175
SourceLoc uncheckedLoc,
173-
SourceLoc preconcurrencyLoc)
176+
SourceLoc preconcurrencyLoc,
177+
SourceLoc unsafeLoc)
174178
: Located(item, loc), uncheckedLoc(uncheckedLoc),
175-
preconcurrencyLoc(preconcurrencyLoc) {}
179+
preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc) {}
176180
};
177181
}
178182

@@ -228,7 +232,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
228232
registerProtocolConformances(next, conformances);
229233
for (auto conf : conformances) {
230234
protocols.push_back(
231-
{conf->getProtocol(), SourceLoc(), SourceLoc(), SourceLoc()});
235+
{conf->getProtocol(), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc()});
232236
}
233237
} else if (next->getParentSourceFile() ||
234238
next->getParentModule()->isBuiltinModule()) {
@@ -238,7 +242,8 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
238242
getDirectlyInheritedNominalTypeDecls(next, inverses, anyObject)) {
239243
if (auto proto = dyn_cast<ProtocolDecl>(found.Item))
240244
protocols.push_back(
241-
{proto, found.Loc, found.uncheckedLoc, found.preconcurrencyLoc});
245+
{proto, found.Loc, found.uncheckedLoc,
246+
found.preconcurrencyLoc, found.unsafeLoc});
242247
}
243248
}
244249

@@ -343,7 +348,8 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
343348
addProtocol(
344349
locAndProto.Item, locAndProto.Loc,
345350
source.withUncheckedLoc(locAndProto.uncheckedLoc)
346-
.withPreconcurrencyLoc(locAndProto.preconcurrencyLoc));
351+
.withPreconcurrencyLoc(locAndProto.preconcurrencyLoc)
352+
.withUnsafeLoc(locAndProto.unsafeLoc));
347353
});
348354
break;
349355

test/Unsafe/safe.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ struct HasProperties {
6060
}()
6161
}
6262

63+
protocol P { }
64+
65+
extension Int: @unsafe P { }
66+
67+
func acceptP(_: some P) { }
68+
69+
func testConformance(i: Int) {
70+
// expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}}
71+
acceptP(i) // expected-note{{@unsafe conformance of 'Int' to protocol 'P' involves unsafe code}}
72+
}
73+
74+
6375
// Parsing of `unsafe` expressions.
6476
func testUnsafePositionError() -> Int {
6577
return 3 + unsafe unsafeInt() // expected-error{{'unsafe' cannot appear to the right of a non-assignment operator}}

0 commit comments

Comments
 (0)