@@ -219,6 +219,42 @@ 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+ if (!reason)
235+ return false ;
236+
237+ switch (*reason) {
238+ case ExportabilityReason::ExtensionWithPublicMembers:
239+ case ExportabilityReason::ExtensionWithConditionalConformances:
240+ return true ;
241+ case ExportabilityReason::Inheritance:
242+ return isa<ProtocolDecl>(D);
243+ case ExportabilityReason::AvailableAttribute:
244+ // If the context is an extension and that extension has an explicit
245+ // access level then availability domains access has already been
246+ // diagnosed.
247+ if (auto *ED = dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl ()))
248+ return !ED->getAttrs ().getAttribute <AccessControlAttr>();
249+ return false ;
250+
251+ case ExportabilityReason::General:
252+ case ExportabilityReason::ResultBuilder:
253+ case ExportabilityReason::PropertyWrapper:
254+ return false ;
255+ }
256+ }
257+
222258static bool diagnoseValueDeclRefExportability (SourceLoc loc, const ValueDecl *D,
223259 const ExportContext &where) {
224260 assert (where.mustOnlyReferenceExportedDecls ());
@@ -247,41 +283,44 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
247283 }
248284 });
249285
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)
286+ switch (originKind) {
287+ case DisallowedOriginKind::None:
288+ // The decl does not come from a source that needs to be checked for
289+ // exportability.
276290 return false ;
277291
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 ;
292+ case DisallowedOriginKind::NonPublicImport:
293+ // With a few exceptions, access levels from imports are diagnosed during
294+ // access checking and should be skipped here.
295+ if (!shouldDiagnoseDeclAccess (D, where))
296+ return false ;
297+ break ;
298+
299+ case DisallowedOriginKind::MissingImport:
300+ // Some diagnostics emitted with the `MemberImportVisibility` feature
301+ // enabled subsume these diagnostics.
302+ if (ctx.LangOpts .hasFeature (Feature::MemberImportVisibility,
303+ /* allowMigration=*/ true ) &&
304+ SF)
305+ return false ;
306+ break ;
307+
308+ case DisallowedOriginKind::SPIOnly:
309+ // Availability attributes referring to availability domains from modules
310+ // that are imported @_spiOnly in a -library-level=api will not be printed
311+ // in the public swiftinterface of the module and should therefore not be
312+ // diagnosed for exportability.
313+ if (reason && reason == ExportabilityReason::AvailableAttribute &&
314+ ctx.LangOpts .LibraryLevel == LibraryLevel::API)
315+ return false ;
316+ break ;
317+
318+ case DisallowedOriginKind::ImplementationOnly:
319+ case DisallowedOriginKind::SPIImported:
320+ case DisallowedOriginKind::SPILocal:
321+ case DisallowedOriginKind::FragileCxxAPI:
322+ break ;
323+ }
285324
286325 if (auto accessor = dyn_cast<AccessorDecl>(D)) {
287326 // Only diagnose accessors if their disallowed origin kind differs from
0 commit comments