Files
swift-mirror/lib/Sema/ResilienceDiagnostics.cpp
Alexis Laferrière 9127f90d8d [Sema] Report uses of implicitly imported decls in inlinable code
Implicitly imported decls may end up in inlinable code and break the
module API. This have been known to lead to deserialization crash and
could in theory break the generated swiftinterfaces files. Let's
explicitly check for such a case, keeping it to a warning until Swift 6
where we can make it an error.

rdar://95816286
2022-06-29 16:09:42 -07:00

197 lines
7.4 KiB
C++

//===--- ResilienceDiagnostics.cpp - Resilience Inlineability Diagnostics -===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements diagnostics for fragile functions, like those with
// @inlinable, @_alwaysEmitIntoClient, or @_backDeploy.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "TypeCheckAvailability.h"
#include "TypeCheckAccess.h"
#include "swift/AST/Attr.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeDeclFinder.h"
using namespace swift;
bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
const ValueDecl *D,
const ExportContext &where) {
auto fragileKind = where.getFragileFunctionKind();
if (fragileKind.kind == FragileFunctionKind::None)
return false;
// Local declarations are OK.
if (D->getDeclContext()->isLocalContext())
return false;
auto *DC = where.getDeclContext();
// Public declarations are OK, even if they're SPI or came from an
// implementation-only import. We'll diagnose exportability violations
// from diagnoseDeclRefExportability().
if (D->getFormalAccessScope(/*useDC=*/nullptr,
fragileKind.allowUsableFromInline).isPublic())
return false;
auto &Context = DC->getASTContext();
// Dynamic declarations were mistakenly not checked in Swift 4.2.
// Do enforce the restriction even in pre-Swift-5 modes if the module we're
// building is resilient, though.
if (D->shouldUseObjCDispatch() && !Context.isSwiftVersionAtLeast(5) &&
!DC->getParentModule()->isResilient()) {
return false;
}
DowngradeToWarning downgradeToWarning = DowngradeToWarning::No;
// Swift 4.2 did not perform any checks for type aliases.
if (isa<TypeAliasDecl>(D)) {
if (!Context.isSwiftVersionAtLeast(4, 2))
return false;
if (!Context.isSwiftVersionAtLeast(5))
downgradeToWarning = DowngradeToWarning::Yes;
}
auto diagName = D->getName();
bool isAccessor = false;
// Swift 4.2 did not check accessor accessibility.
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
isAccessor = true;
if (!Context.isSwiftVersionAtLeast(5))
downgradeToWarning = DowngradeToWarning::Yes;
// For accessors, diagnose with the name of the storage instead of the
// implicit '_'.
diagName = accessor->getStorage()->getName();
}
// Swift 5.0 did not check the underlying types of local typealiases.
// FIXME: Conditionalize this once we have a new language mode.
if (isa<TypeAliasDecl>(DC))
downgradeToWarning = DowngradeToWarning::Yes;
auto diagID = diag::resilience_decl_unavailable;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::resilience_decl_unavailable_warn;
Context.Diags.diagnose(loc, diagID, D->getDescriptiveKind(), diagName,
D->getFormalAccessScope().accessLevelForDiagnostics(),
fragileKind.getSelector(), isAccessor);
if (fragileKind.allowUsableFromInline) {
Context.Diags.diagnose(D, diag::resilience_decl_declared_here,
D->getDescriptiveKind(), diagName, isAccessor);
} else {
Context.Diags.diagnose(D, diag::resilience_decl_declared_here_public,
D->getDescriptiveKind(), diagName, isAccessor);
}
return (downgradeToWarning == DowngradeToWarning::No);
}
bool
TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
const ValueDecl *D,
const ExportContext &where) {
// Accessors cannot have exportability that's different than the storage,
// so skip them for now.
if (isa<AccessorDecl>(D))
return false;
if (!where.mustOnlyReferenceExportedDecls())
return false;
auto definingModule = D->getModuleContext();
auto downgradeToWarning = DowngradeToWarning::No;
auto originKind = getDisallowedOriginKind(
D, where, downgradeToWarning);
if (originKind == DisallowedOriginKind::None)
return false;
ASTContext &ctx = definingModule->getASTContext();
auto fragileKind = where.getFragileFunctionKind();
auto reason = where.getExportabilityReason();
if (fragileKind.kind == FragileFunctionKind::None) {
auto errorOrWarning = downgradeToWarning == DowngradeToWarning::Yes?
diag::decl_from_hidden_module_warn:
diag::decl_from_hidden_module;
ctx.Diags.diagnose(loc, errorOrWarning,
D->getDescriptiveKind(),
D->getName(),
static_cast<unsigned>(*reason),
definingModule->getName(),
static_cast<unsigned>(originKind));
D->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
} else {
// Only implicitly imported decls should be reported as a warning,
// and only for language versions below Swift 6.
assert(downgradeToWarning == DowngradeToWarning::No ||
originKind == DisallowedOriginKind::ImplicitlyImported &&
"Only implicitly imported decls should be reported as a warning.");
auto errorOrWarning = downgradeToWarning == DowngradeToWarning::Yes?
diag::inlinable_decl_ref_from_hidden_module_warn:
diag::inlinable_decl_ref_from_hidden_module;
ctx.Diags.diagnose(loc, errorOrWarning,
D->getDescriptiveKind(), D->getName(),
fragileKind.getSelector(), definingModule->getName(),
static_cast<unsigned>(originKind));
}
return true;
}
bool
TypeChecker::diagnoseConformanceExportability(SourceLoc loc,
const RootProtocolConformance *rootConf,
const ExtensionDecl *ext,
const ExportContext &where,
bool useConformanceAvailabilityErrorsOption) {
if (!where.mustOnlyReferenceExportedDecls())
return false;
auto originKind = getDisallowedOriginKind(ext, where);
if (originKind == DisallowedOriginKind::None)
return false;
ModuleDecl *M = ext->getParentModule();
ASTContext &ctx = M->getASTContext();
auto reason = where.getExportabilityReason();
if (!reason.hasValue())
reason = ExportabilityReason::General;
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module,
rootConf->getType(),
rootConf->getProtocol()->getName(),
static_cast<unsigned>(*reason),
M->getName(),
static_cast<unsigned>(originKind))
.warnUntilSwiftVersionIf(useConformanceAvailabilityErrorsOption &&
!ctx.LangOpts.EnableConformanceAvailabilityErrors,
6);
return true;
}