//===--- SILSymbolVisitor.cpp ---------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 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 liker symbol enumeration for SILSymbolVisitor. // //===----------------------------------------------------------------------===// #include "swift/SIL/SILSymbolVisitor.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/FileUnit.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/SynthesizedFileUnit.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Defer.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILLinkage.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILVTableVisitor.h" #include "swift/SIL/SILWitnessTable.h" #include "swift/SIL/SILWitnessVisitor.h" using namespace swift; static bool requiresLinkerDirective(Decl *D) { for (auto *attr : D->getAttrs()) { if (auto *ODA = dyn_cast(attr)) { auto Active = ODA->isActivePlatform(D->getASTContext()); if (Active.has_value()) return true; } } return false; } static bool isGlobalOrStaticVar(VarDecl *VD) { return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); } using DynamicKind = SILSymbolVisitor::DynamicKind; static std::optional getDynamicKind(ValueDecl *VD) { if (VD->shouldUseNativeMethodReplacement()) return DynamicKind::Replaceable; if (VD->getDynamicallyReplacedDecl()) return DynamicKind::Replacement; return std::nullopt; } class SILSymbolVisitorImpl : public ASTVisitor { SILSymbolVisitor &Visitor; const SILSymbolVisitorContext &Ctx; llvm::SmallVector DeclStack; /// A set of original function and derivative configuration pairs for which /// derivative symbols have been emitted. /// /// Used to deduplicate derivative symbol emission for `@differentiable` and /// `@derivative` attributes. llvm::DenseSet> AddedDerivatives; void addMainIfNecessary(FileUnit *file) { // Make sure to only add the main symbol for the module that we're emitting // TBD for, and not for any statically linked libraries. if (!file->hasEntryPoint() || file->getParentModule() != Ctx.getModule()) return; auto entryPointSymbol = file->getParentModule()->getASTContext().getEntryPointFunctionName(); if (auto *decl = file->getMainDecl()) { addFunction(SILDeclRef::getMainDeclEntryPoint(decl), /*ignoreLinkage=*/true); return; } auto declRef = SILDeclRef::getMainFileEntryPoint(file); Visitor.addFunction(entryPointSymbol, declRef); } /// Emits the given `SILDeclRef` to the downstream visitor as long as the /// entity has the required linkage. /// /// FIXME: The need for an ignoreLinkage flag here possibly indicates that /// there is something broken about the linkage computation below. void addFunction(SILDeclRef declRef, bool ignoreLinkage = false) { if (!ignoreLinkage) { auto linkage = effectiveLinkageForClassMember( declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); if (shouldSkipVisit(linkage)) return; } Visitor.addFunction(declRef); } bool shouldSkipVisit(SILLinkage linkage) { return Ctx.getOpts().PublicOrPackageSymbolsOnly && !(linkage == SILLinkage::Public || linkage == SILLinkage::Package); } bool shouldSkipVisit(SILDeclRef declRef) { return Ctx.getOpts().PublicOrPackageSymbolsOnly && !declRef.isSerialized(); } bool shouldSkipVisit(FormalLinkage formalLinkage) { return Ctx.getOpts().PublicOrPackageSymbolsOnly && !(formalLinkage == FormalLinkage::PublicUnique || formalLinkage == FormalLinkage::PackageUnique); } void addAsyncFunctionPointer(SILDeclRef declRef) { auto silLinkage = effectiveLinkageForClassMember( declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); if (shouldSkipVisit(silLinkage)) return; Visitor.addAsyncFunctionPointer(declRef); } void addCoroFunctionPointer(SILDeclRef declRef) { auto silLinkage = effectiveLinkageForClassMember( declRef.getLinkage(ForDefinition), declRef.getSubclassScope()); if (shouldSkipVisit(silLinkage)) return; Visitor.addCoroFunctionPointer(declRef); } void addAutoDiffLinearMapFunction(AbstractFunctionDecl *original, const AutoDiffConfig &config, AutoDiffLinearMapKind kind) { auto &ctx = original->getASTContext(); auto declRef = SILDeclRef(original).asForeign(requiresForeignEntryPoint(original)); // Linear maps are public only when the original function is serialized. So // if we're only including public symbols and it's not serialized, bail. if (shouldSkipVisit(declRef)) return; // Differential functions are emitted only when forward-mode is enabled. if (kind == AutoDiffLinearMapKind::Differential && !ctx.LangOpts.hasFeature(Feature::ForwardModeDifferentiation)) return; auto *loweredParamIndices = autodiff::getLoweredParameterIndices( config.parameterIndices, original->getInterfaceType()->castTo()); Mangle::ASTMangler mangler(original->getASTContext()); AutoDiffConfig silConfig{ loweredParamIndices, config.resultIndices, autodiff::getDifferentiabilityWitnessGenericSignature( original->getGenericSignature(), config.derivativeGenericSignature)}; std::string linearMapName = mangler.mangleAutoDiffLinearMap(original, kind, silConfig); // TODO: Can we encode a linear map function in a SILDeclRef instead of // doing a bespoke mangling here? Visitor.addFunction(linearMapName, declRef); } void addAutoDiffDerivativeFunction(AbstractFunctionDecl *original, IndexSubset *parameterIndices, GenericSignature derivativeGenericSignature, AutoDiffDerivativeFunctionKind kind) { auto *assocFnId = AutoDiffDerivativeFunctionIdentifier::get( kind, parameterIndices, autodiff::getDifferentiabilityWitnessGenericSignature( original->getGenericSignature(), derivativeGenericSignature), original->getASTContext()); auto declRef = SILDeclRef(original).asForeign(requiresForeignEntryPoint(original)); addFunction(declRef.asAutoDiffDerivativeFunction(assocFnId)); } void addDifferentiabilityWitness( AbstractFunctionDecl *original, DifferentiabilityKind kind, IndexSubset *astParameterIndices, IndexSubset *resultIndices, GenericSignature derivativeGenericSignature) { bool foreign = requiresForeignEntryPoint(original); auto declRef = SILDeclRef(original).asForeign(foreign); // Skip symbol emission for original functions that do not have public // linkage. Exclude original functions that require a foreign entry point // with `public_external` linkage. auto originalLinkage = declRef.getLinkage(ForDefinition); if (foreign) originalLinkage = stripExternalFromLinkage(originalLinkage); if (shouldSkipVisit(originalLinkage)) return; auto *silParamIndices = autodiff::getLoweredParameterIndices( astParameterIndices, original->getInterfaceType()->castTo()); auto originalMangledName = declRef.mangle(); AutoDiffConfig config{ silParamIndices, resultIndices, autodiff::getDifferentiabilityWitnessGenericSignature( original->getGenericSignature(), derivativeGenericSignature)}; Mangle::ASTMangler mangler(original->getASTContext()); auto mangledName = mangler.mangleSILDifferentiabilityWitness( originalMangledName, kind, config); // TODO: Can we encode a differentiability witness function in a SILDeclRef // instead of doing a bespoke mangling here? Visitor.addFunction(mangledName, declRef); } void addDerivativeConfiguration(DifferentiabilityKind diffKind, AbstractFunctionDecl *original, const AutoDiffConfig &config) { auto inserted = AddedDerivatives.insert({original, config}); if (!inserted.second) return; addAutoDiffLinearMapFunction(original, config, AutoDiffLinearMapKind::Differential); addAutoDiffLinearMapFunction(original, config, AutoDiffLinearMapKind::Pullback); addAutoDiffDerivativeFunction(original, config.parameterIndices, config.derivativeGenericSignature, AutoDiffDerivativeFunctionKind::JVP); addAutoDiffDerivativeFunction(original, config.parameterIndices, config.derivativeGenericSignature, AutoDiffDerivativeFunctionKind::VJP); addDifferentiabilityWitness(original, diffKind, config.parameterIndices, config.resultIndices, config.derivativeGenericSignature); } void addOpaqueResultIfNecessary(ValueDecl *VD) { if (auto opaqueResult = VD->getOpaqueResultTypeDecl()) { Visitor.addOpaqueTypeDescriptor(opaqueResult); assert(opaqueResult->getNamingDecl() == VD); if (auto dynKind = getDynamicKind(VD)) { Visitor.addOpaqueTypeDescriptorAccessor(opaqueResult, *dynKind); } } } void addConformances(const IterableDeclContext *IDC) { for (auto conformance : IDC->getLocalConformances(ConformanceLookupKind::NonInherited)) { auto protocol = conformance->getProtocol(); if (canSkipNominal(protocol)) continue; auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable(protocol); if (!needsWTable) continue; // Only root conformances get symbols; the others get any public symbols // from their parent conformances. auto rootConformance = dyn_cast(conformance); if (!rootConformance) { continue; } // We cannot emit the witness table symbol if the protocol is imported // from another module and it's resilient, because initialization of that // protocol is necessary in this case if (Ctx.getOpts().FragileResilientProtocols || !rootConformance->getProtocol()->isResilient( IDC->getAsGenericContext()->getParentModule(), ResilienceExpansion::Maximal)) Visitor.addProtocolWitnessTable(rootConformance); Visitor.addProtocolConformanceDescriptor(rootConformance); // FIXME: the logic around visibility in extensions is confusing, and // sometimes witness thunks need to be manually made public. auto conformanceSeializedKind = SILWitnessTable::conformanceSerializedKind(rootConformance); auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl, ValueDecl *witnessDecl) { auto witnessRef = SILDeclRef(witnessDecl); if (Ctx.getOpts().PublicOrPackageSymbolsOnly) { if (conformanceSeializedKind == IsNotSerialized) return; if (!isa(rootConformance) && !fixmeWitnessHasLinkageThatNeedsToBePublic( witnessRef, witnessRef.getASTContext().SILOpts.EnableSerializePackage)) { return; } } Visitor.addProtocolWitnessThunk(rootConformance, requirementDecl); }; rootConformance->forEachValueWitness([&](ValueDecl *valueReq, Witness witness) { auto witnessDecl = witness.getDecl(); if (!witnessDecl) return; if (isa(valueReq)) { addSymbolIfNecessary(valueReq, witnessDecl); } else if (auto *storage = dyn_cast(valueReq)) { if (auto witnessStorage = dyn_cast(witnessDecl)) { storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) { auto witnessAccessor = witnessStorage->getSynthesizedAccessor( reqtAccessor->getAccessorKind()); addSymbolIfNecessary(reqtAccessor, witnessAccessor); }); } else if (isa(witnessDecl)) { auto getter = storage->getSynthesizedAccessor(AccessorKind::Get); addSymbolIfNecessary(getter, witnessDecl); } } }, /*useResolver=*/true); } } bool addClassMetadata(ClassDecl *CD) { if (canSkipNominal(CD)) return false; auto &ctxt = CD->getASTContext(); auto isGeneric = CD->isGenericContext(); auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric; auto isObjC = objCCompatible && CD->isObjC(); // Metaclasses and ObjC classes (duh) are an ObjC thing, and so are not // needed in build artifacts/for classes which can't touch ObjC. if (objCCompatible) { if (isObjC) Visitor.addObjCInterface(CD); else if (CD->getMetaclassKind() == ClassDecl::MetaclassKind::ObjC) // If an ObjCInterface was not added, an external ObjC Metaclass can // still be needed for subclassing. Visitor.addObjCMetaclass(CD); else Visitor.addSwiftMetaclassStub(CD); } // Some members of classes get extra handling, beyond members of // struct/enums, so let's walk over them manually. if (Ctx.getOpts().VisitMembers) for (auto *var : CD->getStoredProperties()) Visitor.addFieldOffset(var); visitNominalTypeDecl(CD); bool resilientAncestry = CD->checkAncestry(AncestryFlags::ResilientOther); // Types with resilient superclasses have some extra symbols. if (resilientAncestry || CD->hasResilientMetadata()) Visitor.addClassMetadataBaseOffset(CD); auto &Ctx = CD->getASTContext(); if (Ctx.LangOpts.EnableObjCInterop && resilientAncestry) Visitor.addObjCResilientClassStub(CD); return true; } void addMethodIfNecessary(FuncDecl *FD) { auto CD = dyn_cast(FD->getDeclContext()); if (!CD) return; // If we're already visiting the parent ClassDecl then this was handled by // its vtable visitor. if (llvm::find(DeclStack, CD) != DeclStack.end()) return; SILDeclRef method = SILDeclRef(FD); if (Ctx.getOpts().VirtualFunctionElimination || CD->hasResilientMetadata()) { Visitor.addDispatchThunk(method); } Visitor.addMethodDescriptor(method); } /// Returns `true` if the neither the nominal nor its members have any symbols /// that need to be visited because it has non-public linkage. bool canSkipNominal(const NominalTypeDecl *NTD) { if (!Ctx.getOpts().PublicOrPackageSymbolsOnly) return false; // Don't skip nominals from clang modules; they have PublicNonUnique // linkage. if (isa(NTD->getDeclContext()->getModuleScopeContext())) return false; return !(getDeclLinkage(NTD) == FormalLinkage::PublicUnique || getDeclLinkage(NTD) == FormalLinkage::PackageUnique); } public: SILSymbolVisitorImpl(SILSymbolVisitor &Visitor, const SILSymbolVisitorContext &Ctx) : Visitor{Visitor}, Ctx{Ctx} {} void visit(Decl *D) { DeclStack.push_back(D); SWIFT_DEFER { DeclStack.pop_back(); }; if (!Visitor.willVisitDecl(D)) return; ASTVisitor::visit(D); Visitor.didVisitDecl(D); } void visit(FileUnit *file) { auto visitFile = [this](FileUnit *file) { SmallVector decls; file->getTopLevelDeclsWithAuxiliaryDecls(decls); addMainIfNecessary(file); for (auto D : decls) { if (Ctx.getOpts().LinkerDirectivesOnly && !requiresLinkerDirective(D)) continue; visit(D); } }; visitFile(file); // Visit synthesized file, if it exists. if (auto *synthesizedFile = file->getSynthesizedFile()) visitFile(synthesizedFile); } void visitDefaultArguments(ValueDecl *VD, ParameterList *PL) { auto moduleDecl = VD->getModuleContext(); // Check if symbols should be more visible than their declared access level. // In case of `package` access level, the symbol should be visible by an // external module in the same package, thus the default argument should be // generated and its linkage emitted. auto shouldGenerateDefaultArgs = moduleDecl->isTestingEnabled() || moduleDecl->arePrivateImportsEnabled() || VD->getFormalAccess() >= AccessLevel::Package; if (Ctx.getOpts().PublicOrPackageSymbolsOnly && !shouldGenerateDefaultArgs) return; // In Swift 3 (or under -enable-testing), default arguments (of public // functions) are public symbols, as the default values are computed at the // call site. auto index = 0; for (auto *param : *PL) { if (param->isDefaultArgument()) addFunction(SILDeclRef::getDefaultArgGenerator(VD, index)); ++index; } } void visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) { // Add exported prespecialized symbols. for (auto *attr : AFD->getAttrs().getAttributes()) { if (!attr->isExported()) continue; auto specializedSignature = attr->getSpecializedSignature(AFD); auto erasedSignature = SILSpecializeAttr::buildTypeErasedSignature(specializedSignature, attr->getTypeErasedParams()); if (auto *targetFun = attr->getTargetFunctionDecl(AFD)) { addFunction(SILDeclRef(targetFun, erasedSignature), /*ignoreLinkage=*/true); } else { addFunction(SILDeclRef(AFD, erasedSignature), /*ignoreLinkage=*/true); } } addFunction(SILDeclRef(AFD)); ASSERT(ABIRoleInfo(AFD).providesAPI() && "SILSymbolVisitorImpl visiting ABI-only decl?"); if (auto dynKind = getDynamicKind(AFD)) { // Add the global function pointer for a dynamically replaceable function. Visitor.addDynamicFunction(AFD, *dynKind); } if (AFD->getAttrs().hasAttribute()) { // A @_cdecl("...") function has an extra symbol, with the name from the // attribute. addFunction(SILDeclRef(AFD).asForeign()); } if (auto distributedThunk = AFD->getDistributedThunk()) { auto thunk = SILDeclRef(distributedThunk).asDistributed(); addFunction(thunk); addAsyncFunctionPointer(thunk); } // Add derivative function symbols. for (const auto *differentiableAttr : AFD->getAttrs().getAttributes()) { auto *resultIndices = autodiff::getFunctionSemanticResultIndices( AFD, differentiableAttr->getParameterIndices()); addDerivativeConfiguration( differentiableAttr->getDifferentiabilityKind(), AFD, AutoDiffConfig(differentiableAttr->getParameterIndices(), resultIndices, differentiableAttr->getDerivativeGenericSignature())); } for (const auto *derivativeAttr : AFD->getAttrs().getAttributes()) { auto *resultIndices = autodiff::getFunctionSemanticResultIndices( derivativeAttr->getOriginalFunction(AFD->getASTContext()), derivativeAttr->getParameterIndices()); addDerivativeConfiguration( DifferentiabilityKind::Reverse, derivativeAttr->getOriginalFunction(AFD->getASTContext()), AutoDiffConfig(derivativeAttr->getParameterIndices(), resultIndices, AFD->getGenericSignature())); } visitDefaultArguments(AFD, AFD->getParameters()); if (AFD->hasAsync()) { addAsyncFunctionPointer(SILDeclRef(AFD)); } auto *accessor = dyn_cast(AFD); if (accessor && requiresFeatureCoroutineAccessors(accessor->getAccessorKind())) { addCoroFunctionPointer(SILDeclRef(accessor)); } // Skip non objc compatible methods or non-public methods. if (isa(AFD) || !AFD->isObjC() || AFD->getFormalAccess() != AccessLevel::Public) return; Visitor.addObjCMethod(AFD); } void visitFuncDecl(FuncDecl *FD) { // If there's an opaque return type, its descriptor is exported. addOpaqueResultIfNecessary(FD); visitAbstractFunctionDecl(FD); addMethodIfNecessary(FD); } void visitAccessorDecl(AccessorDecl *AD) { llvm_unreachable("should not see an accessor here"); } void visitAbstractStorageDecl(AbstractStorageDecl *ASD) { // Add the property descriptor if the decl needs it. if (ASD->getPropertyDescriptorGenericSignature()) { Visitor.addPropertyDescriptor(ASD); } // ...and the opaque result decl if it has one. addOpaqueResultIfNecessary(ASD); // Explicitly look at each accessor here: see visitAccessorDecl. ASD->visitEmittedAccessors([&](AccessorDecl *accessor) { visitFuncDecl(accessor); }); // Add derivative function symbols. for (const auto *differentiableAttr : ASD->getAttrs().getAttributes()) { // FIXME: handle other accessors auto accessorDecl = ASD->getOpaqueAccessor(AccessorKind::Get); addDerivativeConfiguration( differentiableAttr->getDifferentiabilityKind(), accessorDecl, AutoDiffConfig(differentiableAttr->getParameterIndices(), autodiff::getFunctionSemanticResultIndices(accessorDecl, differentiableAttr->getParameterIndices()), differentiableAttr->getDerivativeGenericSignature())); } } void visitVarDecl(VarDecl *VD) { // Variables inside non-resilient modules have some additional symbols. if (!VD->isStrictlyResilient()) { // Non-global variables might have an explicit initializer symbol in // non-resilient modules. if (VD->getAttrs().hasAttribute() && !isGlobalOrStaticVar(VD)) { auto declRef = SILDeclRef(VD, SILDeclRef::Kind::StoredPropertyInitializer); // Stored property initializers for public properties are public. addFunction(declRef); } // Statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { if (!shouldSkipVisit(getDeclLinkage(VD))) { Visitor.addGlobalVar(VD); } if (VD->isLazilyInitializedGlobal()) addFunction(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } // Wrapped non-static member properties may have a backing initializer. auto initInfo = VD->getPropertyWrapperInitializerInfo(); if (initInfo.hasInitFromWrappedValue() && !VD->isStatic()) { addFunction(SILDeclRef( VD, SILDeclRef::Kind::PropertyWrapperBackingInitializer)); } } visitAbstractStorageDecl(VD); } void visitSubscriptDecl(SubscriptDecl *SD) { visitDefaultArguments(SD, SD->getIndices()); visitAbstractStorageDecl(SD); } template void visitMembers(NominalOrExtension *D) { if (!Ctx.getOpts().VisitMembers) return; for (auto member : D->getABIMembers()) visit(member); } void visitNominalTypeDecl(NominalTypeDecl *NTD) { if (canSkipNominal(NTD)) return; if (NTD->getASTContext().LangOpts.hasFeature(Feature::Embedded)) return; auto declaredType = NTD->getDeclaredType()->getCanonicalType(); if (!NTD->getObjCImplementationDecl()) { Visitor.addNominalTypeDescriptor(NTD); // Generic types do not get metadata directly, only through the function. if (!NTD->isGenericContext()) { Visitor.addTypeMetadataAddress(declaredType); } } Visitor.addTypeMetadataAccessFunction(declaredType); // There are symbols associated with any protocols this type conforms to. addConformances(NTD); visitMembers(NTD); } void visitClassDecl(ClassDecl *CD) { if (!addClassMetadata(CD)) return; // Emit dispatch thunks for every new vtable entry. struct VTableVisitor : public SILVTableVisitor { SILSymbolVisitor &Visitor; ClassDecl *CD; bool FirstTime = true; bool VirtualFunctionElimination; public: VTableVisitor(SILSymbolVisitorImpl &V, ClassDecl *CD) : Visitor{V.Visitor}, CD{CD}, VirtualFunctionElimination{ V.Ctx.getOpts().VirtualFunctionElimination} {} void addMethod(SILDeclRef method) { assert(method.getDecl()->getDeclContext() == CD); // If the class is itself resilient and has at least one vtable // entry, it has a method lookup function. bool hasLookupFunc = VirtualFunctionElimination || CD->hasResilientMetadata(); if (FirstTime) { FirstTime = false; if (hasLookupFunc) Visitor.addMethodLookupFunction(CD); } if (!Visitor.willVisitDecl(method.getDecl())) return; if (hasLookupFunc) Visitor.addDispatchThunk(method); Visitor.addMethodDescriptor(method); Visitor.didVisitDecl(method.getDecl()); } void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {} void addPlaceholder(MissingMemberDecl *) {} void doIt() { addVTableEntries(CD); } }; if (Ctx.getOpts().VisitMembers) VTableVisitor(*this, CD).doIt(); } void visitConstructorDecl(ConstructorDecl *CD) { if (CD->getParent()->getSelfClassDecl()) { // Class constructors come in two forms, allocating and non-allocating. // The default ValueDecl handling gives the allocating one, so we have to // manually include the non-allocating one. addFunction(SILDeclRef(CD, SILDeclRef::Kind::Initializer)); if (CD->hasAsync()) { addAsyncFunctionPointer(SILDeclRef(CD, SILDeclRef::Kind::Initializer)); } } visitAbstractFunctionDecl(CD); } void visitDestructorDecl(DestructorDecl *DD) { // Destructors come in three forms (non-deallocating, deallocating, isolated // deallocating) Classes use all three but move only non-class nominal types // only use the deallocating one. This is the deallocating one: visitAbstractFunctionDecl(DD); if (auto parentClass = DD->getParent()->getSelfClassDecl()) { // But the non-deallocating one doesn't apply to some @objc classes. if (!Lowering::usesObjCAllocator(parentClass)) { addFunction(SILDeclRef(DD, SILDeclRef::Kind::Destroyer)); } } // And isolated also does not always exist if (Lowering::needsIsolatingDestructor(DD)) { addFunction(SILDeclRef(DD, SILDeclRef::Kind::IsolatedDeallocator)); } } void visitExtensionDecl(ExtensionDecl *ED) { auto nominal = ED->getExtendedNominal(); if (!nominal) return; if (canSkipNominal(nominal)) return; if (auto CD = dyn_cast_or_null(ED->getImplementedObjCDecl())) { // @_objcImplementation extensions generate the class metadata symbols. (void)addClassMetadata(CD); } if (!isa(nominal)) { addConformances(ED); } visitMembers(ED); } #ifndef NDEBUG static bool isExpectedProtocolMember(const Decl *D) { switch (D->getKind()) { case DeclKind::TypeAlias: case DeclKind::AssociatedType: case DeclKind::Var: case DeclKind::Subscript: case DeclKind::PatternBinding: case DeclKind::Func: case DeclKind::Accessor: case DeclKind::Constructor: case DeclKind::Destructor: return true; case DeclKind::OpaqueType: case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: case DeclKind::Protocol: case DeclKind::GenericTypeParam: case DeclKind::Module: case DeclKind::Param: case DeclKind::EnumElement: case DeclKind::Extension: case DeclKind::TopLevelCode: case DeclKind::Import: case DeclKind::PrecedenceGroup: case DeclKind::MissingMember: case DeclKind::EnumCase: case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: case DeclKind::Macro: case DeclKind::MacroExpansion: return false; case DeclKind::Missing: llvm_unreachable("missing decl should not show up here"); case DeclKind::BuiltinTuple: llvm_unreachable("BuiltinTupleDecl should not show up here"); } llvm_unreachable("covered switch"); } #endif void visitProtocolDecl(ProtocolDecl *PD) { if (canSkipNominal(PD)) return; if (!PD->isObjC() && !PD->isMarkerProtocol()) { Visitor.addProtocolDescriptor(PD); struct WitnessVisitor : public SILWitnessVisitor { SILSymbolVisitor &Visitor; ProtocolDecl *PD; bool Resilient; bool WitnessMethodElimination; public: WitnessVisitor(SILSymbolVisitorImpl &V, ProtocolDecl *PD) : Visitor{V.Visitor}, PD{PD}, Resilient{PD->getParentModule()->isResilient()}, WitnessMethodElimination{ V.Ctx.getOpts().WitnessMethodElimination} {} void addMethod(SILDeclRef declRef) { if (Resilient || WitnessMethodElimination) { Visitor.addDispatchThunk(declRef); Visitor.addMethodDescriptor(declRef); } auto *decl = llvm::dyn_cast_or_null(declRef.getDecl()); if (decl && decl->hasBody()) { Visitor.addFunction(declRef); auto *accessor = dyn_cast(decl); if (accessor && requiresFeatureCoroutineAccessors( accessor->getAccessorKind())) { Visitor.addCoroFunctionPointer(SILDeclRef(accessor)); } } } void addAssociatedType(AssociatedTypeDecl *assocType) { Visitor.addAssociatedTypeDescriptor(assocType); } void addProtocolConformanceDescriptor() { Visitor.addProtocolRequirementsBaseDescriptor(PD); } void addOutOfLineBaseProtocol(ProtocolDecl *proto) { Visitor.addBaseConformanceDescriptor(BaseConformance(PD, proto)); } void addAssociatedConformance(AssociatedConformance associatedConf) { Visitor.addAssociatedConformanceDescriptor(associatedConf); } void addPlaceholder(MissingMemberDecl *decl) {} void doIt() { visitProtocolDecl(PD); } }; WitnessVisitor(*this, PD).doIt(); // Include the self-conformance. addConformances(PD); } #ifndef NDEBUG // There are currently no symbols associated with the members of a protocol; // each conforming type has to handle them individually. // Let's assert this fact: for (auto *member : PD->getMembers()) { assert(isExpectedProtocolMember(member) && "unexpected member of protocol during TBD generation"); } #endif } void visitEnumDecl(EnumDecl *ED) { visitNominalTypeDecl(ED); } void visitEnumElementDecl(EnumElementDecl *EED) { if (EED->getParentEnum()->isResilient()) Visitor.addEnumCase(EED); if (auto *PL = EED->getParameterList()) visitDefaultArguments(EED, PL); } #define UNINTERESTING_DECL(CLASS) \ void visit##CLASS##Decl(CLASS##Decl *) {} UNINTERESTING_DECL(EnumCase) UNINTERESTING_DECL(Import) UNINTERESTING_DECL(MacroExpansion) UNINTERESTING_DECL(Missing) UNINTERESTING_DECL(MissingMember) UNINTERESTING_DECL(Operator) UNINTERESTING_DECL(PatternBinding) UNINTERESTING_DECL(PrecedenceGroup) UNINTERESTING_DECL(TopLevelCode) UNINTERESTING_DECL(Value) #undef UNINTERESTING_DECL }; void SILSymbolVisitor::visitDecl(Decl *D, const SILSymbolVisitorContext &ctx) { SILSymbolVisitorImpl(*this, ctx).visit(D); } void SILSymbolVisitor::visitFile(FileUnit *file, const SILSymbolVisitorContext &ctx) { SILSymbolVisitorImpl(*this, ctx).visit(file); } void SILSymbolVisitor::visitModules(llvm::SmallVector &modules, const SILSymbolVisitorContext &ctx) { auto impl = SILSymbolVisitorImpl(*this, ctx); for (auto *M : modules) { for (auto *file : M->getFiles()) { impl.visit(file); } } }