1616
1717#include " TypeCheckAvailability.h"
1818#include " TypeCheckConcurrency.h"
19+ #include " TypeCheckInvertible.h"
1920#include " TypeCheckType.h"
2021#include " TypeCheckUnsafe.h"
2122
@@ -121,6 +122,7 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use) {
121122 }
122123
123124 case UnsafeUse::ReferenceToUnsafe:
125+ case UnsafeUse::ReferenceToUnsafeStorage:
124126 case UnsafeUse::CallToUnsafe: {
125127 bool isCall = use.getKind () == UnsafeUse::CallToUnsafe;
126128 auto decl = cast_or_null<ValueDecl>(use.getDecl ());
@@ -133,7 +135,8 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use) {
133135 [&](Type specificType) {
134136 ctx.Diags .diagnose (
135137 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,
137140 isCall, decl, specificType);
138141 });
139142 } else if (type) {
@@ -376,3 +379,61 @@ void swift::diagnoseUnsafeType(ASTContext &ctx, SourceLoc loc, Type type,
376379
377380 diagnose (specificType ? specificType : type);
378381}
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