@@ -219,6 +219,40 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc,
219219 return true ;
220220}
221221
222+ // / Returns true if access to \p D should be diagnosed during exportability
223+ // / checking. These diagnostics would typically be handled by the access
224+ // / checker, and therefore should be suppressed to avoid duplicate diagnostics.
225+ // / However, extensions are special because they do not have an intrinsic access
226+ // / level and therefore the access checker does not currently handle them.
227+ // / Instead, diagnostics for decls referenced in extension signatures are
228+ // / deferred to exportability checking. An exportable extension is effectively a
229+ // / public extension.
230+ static bool shouldDiagnoseDeclAccess (const ValueDecl *D,
231+ const ExportContext &where) {
232+ auto reason = where.getExportabilityReason ();
233+ auto DC = where.getDeclContext ();
234+
235+ switch (*reason) {
236+ case ExportabilityReason::ExtensionWithPublicMembers:
237+ case ExportabilityReason::ExtensionWithConditionalConformances:
238+ return true ;
239+ case ExportabilityReason::Inheritance:
240+ return isa<ProtocolDecl>(D);
241+ case ExportabilityReason::AvailableAttribute:
242+ // If the context is an extension and that extension has an explicit
243+ // access level then availability domains access has already been
244+ // diagnosed.
245+ if (auto *ED = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl ()))
246+ return !ED->getAttrs ().getAttribute <AccessControlAttr>();
247+ return false ;
248+
249+ case ExportabilityReason::General:
250+ case ExportabilityReason::ResultBuilder:
251+ case ExportabilityReason::PropertyWrapper:
252+ return false ;
253+ }
254+ }
255+
222256static bool diagnoseValueDeclRefExportability (SourceLoc loc, const ValueDecl *D,
223257 const ExportContext &where) {
224258 assert (where.mustOnlyReferenceExportedDecls ());
@@ -247,41 +281,35 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
247281 }
248282 });
249283
250- // Access levels from imports are reported with the others access levels.
251- // Except for extensions and protocol conformances, we report them here.
252- if (originKind == DisallowedOriginKind::NonPublicImport) {
253- bool reportHere = [&] {
254- switch (*reason) {
255- case ExportabilityReason::ExtensionWithPublicMembers:
256- case ExportabilityReason::ExtensionWithConditionalConformances:
257- return true ;
258- case ExportabilityReason::Inheritance:
259- return isa<ProtocolDecl>(D);
260- case ExportabilityReason::AvailableAttribute:
261- // If the context is an extension and that extension has an explicit
262- // access level, then access has already been diagnosed for the
263- // @available attribute.
264- if (auto *ED = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl ()))
265- return !ED->getAttrs ().getAttribute <AccessControlAttr>();
266- return false ;
267- default :
268- return false ;
269- }
270- }();
271- if (!reportHere)
272- return false ;
273- }
274-
275- if (originKind == DisallowedOriginKind::None)
284+ switch (originKind) {
285+ case DisallowedOriginKind::None:
286+ // The decl does not come from a source that needs to be checked for
287+ // exportability.
276288 return false ;
277289
278- // Some diagnostics emitted with the `MemberImportVisibility` feature enabled
279- // subsume these diagnostics.
280- if (originKind == DisallowedOriginKind::MissingImport &&
281- ctx.LangOpts .hasFeature (Feature::MemberImportVisibility,
282- /* allowMigration=*/ true ) &&
283- SF)
284- return false ;
290+ case DisallowedOriginKind::NonPublicImport:
291+ // With a few exceptions, access levels from imports are diagnosed during
292+ // access checking and should be skipped here.
293+ if (!shouldDiagnoseDeclAccess (D, where))
294+ return false ;
295+ break ;
296+
297+ case DisallowedOriginKind::MissingImport:
298+ // Some diagnostics emitted with the `MemberImportVisibility` feature
299+ // enabled subsume these diagnostics.
300+ if (ctx.LangOpts .hasFeature (Feature::MemberImportVisibility,
301+ /* allowMigration=*/ true ) &&
302+ SF)
303+ return false ;
304+ break ;
305+
306+ case DisallowedOriginKind::SPIOnly:
307+ case DisallowedOriginKind::ImplementationOnly:
308+ case DisallowedOriginKind::SPIImported:
309+ case DisallowedOriginKind::SPILocal:
310+ case DisallowedOriginKind::FragileCxxAPI:
311+ break ;
312+ }
285313
286314 if (auto accessor = dyn_cast<AccessorDecl>(D)) {
287315 // Only diagnose accessors if their disallowed origin kind differs from
0 commit comments