16
16
17
17
#include " TypeCheckAvailability.h"
18
18
#include " TypeCheckConcurrency.h"
19
+ #include " TypeCheckInvertible.h"
19
20
#include " TypeCheckType.h"
20
21
#include " TypeCheckUnsafe.h"
21
22
@@ -121,6 +122,7 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use) {
121
122
}
122
123
123
124
case UnsafeUse::ReferenceToUnsafe:
125
+ case UnsafeUse::ReferenceToUnsafeStorage:
124
126
case UnsafeUse::CallToUnsafe: {
125
127
bool isCall = use.getKind () == UnsafeUse::CallToUnsafe;
126
128
auto decl = cast_or_null<ValueDecl>(use.getDecl ());
@@ -133,7 +135,8 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use) {
133
135
[&](Type specificType) {
134
136
ctx.Diags .diagnose (
135
137
loc,
136
- diag::note_reference_to_unsafe_typed_decl,
138
+ use.getKind () == UnsafeUse::ReferenceToUnsafeStorage ? diag::note_unsafe_storage
139
+ : diag::note_reference_to_unsafe_typed_decl,
137
140
isCall, decl, specificType);
138
141
});
139
142
} else if (type) {
@@ -376,3 +379,61 @@ void swift::diagnoseUnsafeType(ASTContext &ctx, SourceLoc loc, Type type,
376
379
377
380
diagnose (specificType ? specificType : type);
378
381
}
382
+
383
+ void swift::checkUnsafeStorage (NominalTypeDecl *nominal) {
384
+ // If the type is marked explicitly with @safe or @unsafe, there's nothing
385
+ // to check.
386
+ switch (nominal->getExplicitSafety ()) {
387
+ case ExplicitSafety::Safe:
388
+ case ExplicitSafety::Unsafe:
389
+ return ;
390
+
391
+ case ExplicitSafety::Unspecified:
392
+ break ;
393
+ }
394
+
395
+ // Visitor that finds unsafe storage.
396
+ class UnsafeStorageVisitor : public StorageVisitor {
397
+ ASTContext &ctx;
398
+ SmallVectorImpl<UnsafeUse> &unsafeUses;
399
+
400
+ public:
401
+ UnsafeStorageVisitor (ASTContext &ctx, SmallVectorImpl<UnsafeUse> &unsafeUses)
402
+ : ctx(ctx), unsafeUses(unsafeUses) { }
403
+
404
+ bool operator ()(VarDecl *property, Type propertyType) override {
405
+ diagnoseUnsafeType (ctx, property->getLoc (), propertyType, [&](Type type) {
406
+ unsafeUses.push_back (
407
+ UnsafeUse::forReferenceToUnsafeStorage (
408
+ property, propertyType, property->getLoc ()));
409
+ });
410
+ return false ;
411
+ }
412
+
413
+ bool operator ()(EnumElementDecl *element, Type elementType) override {
414
+ diagnoseUnsafeType (ctx, element->getLoc (), elementType, [&](Type type) {
415
+ unsafeUses.push_back (
416
+ UnsafeUse::forReferenceToUnsafeStorage (
417
+ element, elementType, element->getLoc ()));
418
+ });
419
+ return false ;
420
+ }
421
+ };
422
+
423
+ // Look for any unsafe storage in this nominal type.
424
+ ASTContext &ctx = nominal->getASTContext ();
425
+ SmallVector<UnsafeUse, 4 > unsafeUses;
426
+ UnsafeStorageVisitor (ctx, unsafeUses).visit (nominal, nominal->getDeclContext ());
427
+
428
+ // If we didn't find any unsafe storage, there's nothing to do.
429
+ if (unsafeUses.empty ())
430
+ return ;
431
+
432
+ // Complain about this type needing @safe or @unsafe.
433
+ nominal->diagnose (diag::decl_unsafe_storage, nominal);
434
+ nominal->diagnose (diag::decl_storage_mark_unsafe)
435
+ .fixItInsert (nominal->getAttributeInsertionLoc (false ), " @unsafe " );
436
+ nominal->diagnose (diag::decl_storage_mark_safe)
437
+ .fixItInsert (nominal->getAttributeInsertionLoc (false ), " @safe " );
438
+ std::for_each (unsafeUses.begin (), unsafeUses.end (), diagnoseUnsafeUse);
439
+ }
0 commit comments