diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index bd3846195daa1..967875391b206 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2691,10 +2691,28 @@ checkIndividualConformance(NormalProtocolConformance *conformance) { } if (!unsafeUses.empty()) { - Context.Diags.diagnose( + // Primary diagnostic along with a Fix-It to add @unsafe in the appropriate + // place. + { + auto diag = Context.Diags.diagnose( conformance->getLoc(), diag::conformance_involves_unsafe, - conformance->getType(), Proto) - .fixItInsert(conformance->getProtocolNameLoc(), "@unsafe "); + conformance->getType(), Proto); + + // Find the original explicit conformance, where we can add the Fix-It. + auto explicitConformance = conformance; + while (explicitConformance->getSourceKind() == + ConformanceEntryKind::Implied) { + explicitConformance = + explicitConformance->ProtocolConformance::getImplyingConformance(); + } + + if (explicitConformance->getSourceKind() == + ConformanceEntryKind::Explicit) { + diag.fixItInsert(explicitConformance->getProtocolNameLoc(), + "@unsafe "); + } + } + for (const auto& unsafeUse : unsafeUses) diagnoseUnsafeUse(unsafeUse); } diff --git a/test/Unsafe/safe.swift b/test/Unsafe/safe.swift index 25b0249c4df5f..c2648c9bed2e0 100644 --- a/test/Unsafe/safe.swift +++ b/test/Unsafe/safe.swift @@ -359,3 +359,17 @@ func testSwitch(se: SomeEnum) { if case unsafe someEnumValue = unsafe se { } } + +@unsafe class SomeClass {} +@unsafe class SomeClassWrapper { } + +protocol Associated { + associatedtype Associated +} + +protocol CustomAssociated: Associated { } + +// expected-warning@+1{{conformance of 'SomeClass' to protocol 'Associated' involves unsafe code}}{{22-22=@unsafe }} +extension SomeClass: CustomAssociated { + typealias Associated = SomeClassWrapper // expected-note{{unsafe type 'SomeClass.Associated' (aka 'SomeClassWrapper') cannot satisfy safe associated type 'Associated'}} +}