@@ -219,6 +219,40 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc,
219
219
return true ;
220
220
}
221
221
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
+
222
256
static bool diagnoseValueDeclRefExportability (SourceLoc loc, const ValueDecl *D,
223
257
const ExportContext &where) {
224
258
assert (where.mustOnlyReferenceExportedDecls ());
@@ -247,41 +281,35 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
247
281
}
248
282
});
249
283
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.
276
288
return false ;
277
289
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
+ }
285
313
286
314
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
287
315
// Only diagnose accessors if their disallowed origin kind differs from
0 commit comments