Skip to content

Commit ddca4b7

Browse files
committed
Sema: Refactor diagnoseValueDeclRefExportability().
This is meant to make it clearer how exceptions for each `DisallowedOriginKind` are handled.
1 parent a5a49aa commit ddca4b7

File tree

1 file changed

+61
-33
lines changed

1 file changed

+61
-33
lines changed

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
222256
static 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

Comments
 (0)