Skip to content

Commit ba23f36

Browse files
committed
Diagnose the use of a typealias that involves unsafe types
As we do when referencing other kinds of declarations, if a typealias isn't `@unsafe`, but it involves unsafe types, diagnose the non-safety at the point of reference. Fixes swiftlang#78220
1 parent 419c477 commit ba23f36

File tree

6 files changed

+68
-1
lines changed

6 files changed

+68
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8085,6 +8085,9 @@ NOTE(note_reference_to_unsafe_decl,none,
80858085
NOTE(note_reference_to_unsafe_typed_decl,none,
80868086
"%select{reference|call}0 to %kind1 involves unsafe type %2",
80878087
(bool, const ValueDecl *, Type))
8088+
NOTE(note_reference_to_unsafe_through_typealias,none,
8089+
"reference to %kind0 whose underlying type involves unsafe type %1",
8090+
(const ValueDecl *, Type))
80888091
NOTE(note_reference_to_nonisolated_unsafe,none,
80898092
"reference to nonisolated(unsafe) %kind0 is unsafe in concurrently-executing code",
80908093
(const ValueDecl *))
@@ -8120,6 +8123,9 @@ GROUPED_WARNING(reference_to_unsafe_decl,Unsafe,none,
81208123
GROUPED_WARNING(reference_to_unsafe_typed_decl,Unsafe,none,
81218124
"%select{reference|call}0 to %kindbase1 involves unsafe type %2",
81228125
(bool, const ValueDecl *, Type))
8126+
GROUPED_WARNING(reference_to_unsafe_through_typealias,Unsafe,none,
8127+
"reference to %kind0 whose underlying type involves unsafe type %1",
8128+
(const ValueDecl *, Type))
81238129
GROUPED_WARNING(preconcurrency_import_unsafe,Unsafe,none,
81248130
"@preconcurrency import is not memory-safe because it can silently "
81258131
"introduce data races; use '@safe(unchecked)' to assert that the "

include/swift/AST/UnsafeUse.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class UnsafeUse {
4343
NonisolatedUnsafe,
4444
/// A reference to an unsafe declaration.
4545
ReferenceToUnsafe,
46+
/// A reference to a typealias that is not itself unsafe, but has
47+
/// an unsafe underlying type.
48+
ReferenceToUnsafeThroughTypealias,
4649
/// A call to an unsafe declaration.
4750
CallToUnsafe,
4851
/// A @preconcurrency import.
@@ -110,6 +113,7 @@ class UnsafeUse {
110113
assert(kind == UnownedUnsafe ||
111114
kind == NonisolatedUnsafe ||
112115
kind == ReferenceToUnsafe ||
116+
kind == ReferenceToUnsafeThroughTypealias ||
113117
kind == CallToUnsafe);
114118

115119
UnsafeUse result(kind);
@@ -177,6 +181,14 @@ class UnsafeUse {
177181
decl, type, location);
178182
}
179183

184+
static UnsafeUse forReferenceToUnsafeThroughTypealias(const Decl *decl,
185+
DeclContext *dc,
186+
Type type,
187+
SourceLoc location) {
188+
return forReference(ReferenceToUnsafeThroughTypealias, dc,
189+
decl, type, location);
190+
}
191+
180192
static UnsafeUse forPreconcurrencyImport(const ImportDecl *importDecl) {
181193
UnsafeUse result(PreconcurrencyImport);
182194
result.storage.importDecl = importDecl;
@@ -205,6 +217,7 @@ class UnsafeUse {
205217
case UnownedUnsafe:
206218
case NonisolatedUnsafe:
207219
case ReferenceToUnsafe:
220+
case ReferenceToUnsafeThroughTypealias:
208221
case CallToUnsafe:
209222
return SourceLoc(
210223
llvm::SMLoc::getFromPointer((const char *)storage.entity.location));
@@ -227,6 +240,7 @@ class UnsafeUse {
227240
case UnownedUnsafe:
228241
case NonisolatedUnsafe:
229242
case ReferenceToUnsafe:
243+
case ReferenceToUnsafeThroughTypealias:
230244
case CallToUnsafe:
231245
return storage.entity.decl;
232246

@@ -250,6 +264,7 @@ class UnsafeUse {
250264
case UnownedUnsafe:
251265
case NonisolatedUnsafe:
252266
case ReferenceToUnsafe:
267+
case ReferenceToUnsafeThroughTypealias:
253268
case CallToUnsafe:
254269
return storage.entity.declContext;
255270

@@ -281,6 +296,7 @@ class UnsafeUse {
281296
case UnownedUnsafe:
282297
case NonisolatedUnsafe:
283298
case ReferenceToUnsafe:
299+
case ReferenceToUnsafeThroughTypealias:
284300
case CallToUnsafe:
285301
case UnsafeConformance:
286302
case PreconcurrencyImport:
@@ -305,6 +321,7 @@ class UnsafeUse {
305321
case UnownedUnsafe:
306322
case NonisolatedUnsafe:
307323
case ReferenceToUnsafe:
324+
case ReferenceToUnsafeThroughTypealias:
308325
case CallToUnsafe:
309326
return storage.entity.type;
310327
}
@@ -327,6 +344,7 @@ class UnsafeUse {
327344
case UnownedUnsafe:
328345
case NonisolatedUnsafe:
329346
case ReferenceToUnsafe:
347+
case ReferenceToUnsafeThroughTypealias:
330348
case CallToUnsafe:
331349
case PreconcurrencyImport:
332350
return ProtocolConformanceRef::forInvalid();

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4221,6 +4221,19 @@ diagnoseDeclUnsafe(const ValueDecl *D, SourceRange R,
42214221
}
42224222

42234223
if (auto valueDecl = dyn_cast<ValueDecl>(D)) {
4224+
// A typealias that is not itself @unsafe but references an unsafe type
4225+
// is diagnosed separately.
4226+
if (auto typealias = dyn_cast<TypeAliasDecl>(valueDecl)) {
4227+
if (Type underlying = typealias->getUnderlyingType()) {
4228+
if (underlying->isUnsafe()) {
4229+
diagnoseUnsafeUse(
4230+
UnsafeUse::forReferenceToUnsafeThroughTypealias(
4231+
D, Where.getDeclContext(), underlying, diagLoc));
4232+
return;
4233+
}
4234+
}
4235+
}
4236+
42244237
// Use of a nonisolated(unsafe) declaration is unsafe, but is only
42254238
// diagnosed as such under strict concurrency.
42264239
if (ctx.LangOpts.StrictConcurrencyLevel == StrictConcurrency::Complete &&

lib/Sema/TypeCheckUnsafe.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static bool isUnsafeUseInDefinition(const UnsafeUse &use) {
4444
return false;
4545

4646
case UnsafeUse::ReferenceToUnsafe:
47+
case UnsafeUse::ReferenceToUnsafeThroughTypealias:
4748
case UnsafeUse::CallToUnsafe:
4849
case UnsafeUse::NonisolatedUnsafe:
4950
case UnsafeUse::UnownedUnsafe:
@@ -91,6 +92,7 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use, bool asNote) {
9192
// It will be diagnosed later, along with all other unsafe uses within this
9293
// same declaration.
9394
if (use.getKind() == UnsafeUse::ReferenceToUnsafe ||
95+
use.getKind() == UnsafeUse::ReferenceToUnsafeThroughTypealias ||
9496
use.getKind() == UnsafeUse::CallToUnsafe ||
9597
use.getKind() == UnsafeUse::NonisolatedUnsafe ||
9698
use.getKind() == UnsafeUse::UnownedUnsafe ||
@@ -190,6 +192,21 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use, bool asNote) {
190192
}
191193
return;
192194
}
195+
case UnsafeUse::ReferenceToUnsafeThroughTypealias: {
196+
auto typealias = cast<TypeAliasDecl>(use.getDecl());
197+
ASTContext &ctx = typealias->getASTContext();
198+
diagnoseUnsafeType(
199+
ctx, use.getLocation(), use.getType(),
200+
use.getDeclContext(),
201+
[&](Type specificType) {
202+
ctx.Diags.diagnose(
203+
use.getLocation(),
204+
asNote ? diag::note_reference_to_unsafe_through_typealias
205+
: diag::reference_to_unsafe_through_typealias,
206+
typealias, specificType);
207+
});
208+
return;
209+
}
193210

194211
case UnsafeUse::ReferenceToUnsafe:
195212
case UnsafeUse::CallToUnsafe: {

test/Unsafe/Inputs/unsafe_swift_decls.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
@unsafe public struct PointerType { } // expected-note{{'PointerType' declared here}}
22

3+
public typealias UnsafeTypeAlias = PointerType
4+
35
public func getPointers() -> [PointerType] { [] }
46

57
public struct HasAPointerType {

test/Unsafe/unsafe_imports.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
// RUN: %target-typecheck-verify-swift -enable-experimental-feature AllowUnsafeAttribute -enable-experimental-feature WarnUnsafe -I %S/Inputs
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module-path %t/unsafe_swift_decls.swiftmodule %S/Inputs/unsafe_swift_decls.swift -enable-experimental-feature AllowUnsafeAttribute
3+
4+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature AllowUnsafeAttribute -enable-experimental-feature WarnUnsafe -I %S/Inputs -I %t
25

36
// REQUIRES: swift_feature_AllowUnsafeAttribute
47
// REQUIRES: swift_feature_WarnUnsafe
58

69
import unsafe_decls
10+
import unsafe_swift_decls
711

812
// expected-warning@+1{{global function 'testUnsafe' involves unsafe code; use '@unsafe' to indicate that its use is not memory-safe}}{{1-1=@unsafe }}
913
func testUnsafe(_ ut: UnsafeType) { // expected-note{{reference to unsafe struct 'UnsafeType'}}
@@ -13,3 +17,10 @@ func testUnsafe(_ ut: UnsafeType) { // expected-note{{reference to unsafe struct
1317
print_ints(&array, CInt(array.count))
1418
// expected-note@-1{{call to global function 'print_ints' involves unsafe type 'UnsafeMutablePointer<Int32>'}}
1519
}
20+
21+
// Reference a typealias that isn't itself @unsafe, but refers to an unsafe
22+
// type.
23+
24+
// expected-warning@+1{{global function 'testUnsafeThroughAlias' involves unsafe code; use '@unsafe' to indicate that its use is not memory-safe}}
25+
func testUnsafeThroughAlias(_ ut: UnsafeTypeAlias) { // expected-note{{reference to type alias 'UnsafeTypeAlias' whose underlying type involves unsafe type 'PointerType'}}
26+
}

0 commit comments

Comments
 (0)