mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Piggybacks some resilience diagnostics onto the availability checking code. Public and versioned functions with inlineable bodies can only reference other public and internal entities, since the SIL code for the function body is serialized and stored as part of the module. This includes @_transparent functions, @_inlineable functions, accessors for @_inlineable storage, @inline(__always) functions, and in Swift 4 mode, default argument expressions. The new checks are a source-breaking change, however we don't guarantee source compatibility for underscored attributes. The new ABI and tests for the default argument model will come in subsequent commits.
99 lines
3.6 KiB
C++
99 lines
3.6 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 @inlineable.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TypeChecker.h"
|
|
#include "swift/AST/Attr.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/DeclContext.h"
|
|
using namespace swift;
|
|
|
|
enum FragileFunctionKind : unsigned {
|
|
Transparent,
|
|
InlineAlways,
|
|
Inlineable,
|
|
DefaultArgument
|
|
};
|
|
|
|
FragileFunctionKind getFragileFunctionKind(const DeclContext *DC) {
|
|
for (; DC->isLocalContext(); DC = DC->getParent()) {
|
|
if (auto *DAI = dyn_cast<DefaultArgumentInitializer>(DC))
|
|
if (DAI->getResilienceExpansion() == ResilienceExpansion::Minimal)
|
|
return FragileFunctionKind::DefaultArgument;
|
|
|
|
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
|
|
// If the function is a nested function, we will serialize its body if
|
|
// we serialize the parent's body.
|
|
if (AFD->getDeclContext()->isLocalContext())
|
|
continue;
|
|
|
|
// Bodies of public transparent and always-inline functions are
|
|
// serialized, so use conservative access patterns.
|
|
if (AFD->isTransparent())
|
|
return FragileFunctionKind::Transparent;
|
|
|
|
if (AFD->getAttrs().hasAttribute<InlineableAttr>())
|
|
return FragileFunctionKind::Inlineable;
|
|
|
|
if (auto attr = AFD->getAttrs().getAttribute<InlineAttr>())
|
|
if (attr->getKind() == InlineKind::Always)
|
|
return FragileFunctionKind::InlineAlways;
|
|
|
|
// If a property or subscript is @_inlineable, the accessors are
|
|
// @_inlineable also.
|
|
if (auto FD = dyn_cast<FuncDecl>(AFD))
|
|
if (auto *ASD = FD->getAccessorStorageDecl())
|
|
if (ASD->getAttrs().getAttribute<InlineableAttr>())
|
|
return FragileFunctionKind::Inlineable;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Context is not nested inside a fragile function");
|
|
}
|
|
|
|
void TypeChecker::diagnoseInlineableLocalType(const NominalTypeDecl *NTD) {
|
|
auto *DC = NTD->getDeclContext();
|
|
auto expansion = DC->getResilienceExpansion();
|
|
if (expansion == ResilienceExpansion::Minimal) {
|
|
diagnose(NTD, diag::local_type_in_inlineable_function,
|
|
NTD->getFullName(), getFragileFunctionKind(DC));
|
|
}
|
|
}
|
|
|
|
bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
|
|
const ValueDecl *D,
|
|
const DeclContext *DC) {
|
|
auto expansion = DC->getResilienceExpansion();
|
|
if (expansion == ResilienceExpansion::Minimal) {
|
|
if (!isa<GenericTypeParamDecl>(D) &&
|
|
// FIXME: Figure out what to do with typealiases
|
|
!isa<TypeAliasDecl>(D) &&
|
|
!D->getDeclContext()->isLocalContext() &&
|
|
D->hasAccessibility()) {
|
|
if (D->getEffectiveAccess() < Accessibility::Public) {
|
|
diagnose(loc, diag::resilience_decl_unavailable,
|
|
D->getDescriptiveKind(), D->getFullName(),
|
|
D->getFormalAccess(), getFragileFunctionKind(DC));
|
|
diagnose(D, diag::resilience_decl_declared_here,
|
|
D->getDescriptiveKind(), D->getFullName());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|