//===--- 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(DC)) if (DAI->getResilienceExpansion() == ResilienceExpansion::Minimal) return FragileFunctionKind::DefaultArgument; if (auto *AFD = dyn_cast(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()) return FragileFunctionKind::Inlineable; if (auto attr = AFD->getAttrs().getAttribute()) 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(AFD)) if (auto *ASD = FD->getAccessorStorageDecl()) if (ASD->getAttrs().getAttribute()) 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(); // Internal declarations referenced from non-inlineable contexts are OK. if (expansion == ResilienceExpansion::Maximal) return false; // Local declarations are OK. if (D->getDeclContext()->isLocalContext()) return false; // Type parameters are OK. if (isa(D)) return false; // Public declarations are OK. if (D->getEffectiveAccess() >= Accessibility::Public) return false; // Enum cases are handled as part of their containing enum. if (isa(D)) return false; // Protocol requirements are not versioned because there's no // global entry point. if (isa(D->getDeclContext()) && D->isProtocolRequirement()) return false; // FIXME: Figure out what to do with typealiases if (isa(D)) return false; 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; } void TypeChecker::diagnoseResilientConstructor(ConstructorDecl *ctor) { auto nominalDecl = ctor->getDeclContext() ->getAsNominalTypeOrNominalTypeExtensionContext(); // These restrictions only apply to concrete types, and not protocol // extensions. if (isa(nominalDecl)) return; bool isDelegating = (ctor->getDelegatingOrChainedInitKind(&Diags) == ConstructorDecl::BodyInitKind::Delegating); if (!isDelegating && !nominalDecl->hasFixedLayout(ctor->getParentModule(), ctor->getResilienceExpansion())) { if (ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) { // An @_inlineable designated initializer defined in a resilient type // cannot initialize stored properties directly, and must chain to // another initializer. diagnose(ctor->getLoc(), isa(nominalDecl) ? diag::class_designated_init_inlineable_resilient : diag::designated_init_inlineable_resilient, nominalDecl->getDeclaredInterfaceType(), getFragileFunctionKind(ctor)); } else { // A designated initializer defined on an extension of a resilient // type from a different resilience domain cannot initialize stored // properties directly, and must chain to another initializer. diagnose(ctor->getLoc(), diag::designated_init_in_extension_resilient, nominalDecl->getDeclaredInterfaceType()); } } }