void IndexSwiftASTWalker::collectRecursiveModuleImports( Module &TopMod, llvm::SmallPtrSet<Module *, 16> &Visited) { bool IsNew = Visited.insert(&TopMod).second; if (!IsNew) return; // Pure Clang modules are tied to their dependencies, no need to look into its // imports. // FIXME: What happens if the clang module imports a swift module ? So far // the assumption is that the path to the swift module will be fixed, so no // need to hash the clang module. // FIXME: This is a bit of a hack. if (TopMod.getFiles().size() == 1) if (TopMod.getFiles().front()->getKind() == FileUnitKind::ClangModule) return; auto It = ImportsMap.find(&TopMod); if (It != ImportsMap.end()) { Visited.insert(It->second.begin(), It->second.end()); return; } SmallVector<Module::ImportedModule, 8> Imports; TopMod.getImportedModules(Imports, Module::ImportFilter::All); for (auto Import : Imports) { collectRecursiveModuleImports(*Import.second, Visited); } }
/// Add the requirements for the given potential archetype and its nested /// potential archetypes to the set of requirements. static void addRequirements( Module &mod, Type type, ArchetypeBuilder::PotentialArchetype *pa, llvm::SmallPtrSet<ArchetypeBuilder::PotentialArchetype *, 16> &knownPAs, SmallVectorImpl<Requirement> &requirements) { // If the potential archetype has been bound away to a concrete type, // it needs no requirements. if (pa->isConcreteType()) return; // Add a value witness marker. requirements.push_back(Requirement(RequirementKind::WitnessMarker, type, Type())); // Add superclass requirement, if needed. if (auto superclass = pa->getSuperclass()) { // FIXME: Distinguish superclass from conformance? // FIXME: What if the superclass type involves a type parameter? requirements.push_back(Requirement(RequirementKind::Conformance, type, superclass)); } // Add conformance requirements. SmallVector<ProtocolDecl *, 4> protocols; for (const auto &conforms : pa->getConformsTo()) { protocols.push_back(conforms.first); } ProtocolType::canonicalizeProtocols(protocols); for (auto proto : protocols) { requirements.push_back(Requirement(RequirementKind::Conformance, type, proto->getDeclaredType())); } }
/// Collect the visible conversions of a base class. /// /// \param Base a base class of the class we're considering /// \param InVirtual whether this base class is a virtual base (or a base /// of a virtual base) /// \param Access the access along the inheritance path to this base /// \param ParentHiddenTypes the conversions provided by the inheritors /// of this base /// \param Output the set to which to add conversions from non-virtual bases /// \param VOutput the set to which to add conversions from virtual bases /// \param HiddenVBaseCs the set of conversions which were hidden in a /// virtual base along some inheritance path static void CollectVisibleConversions(ASTContext &Context, CXXRecordDecl *Record, bool InVirtual, AccessSpecifier Access, const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, UnresolvedSetImpl &Output, UnresolvedSetImpl &VOutput, llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) { // The set of types which have conversions in this class or its // subclasses. As an optimization, we don't copy the derived set // unless it might change. const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes; llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer; // Collect the direct conversions and figure out which conversions // will be hidden in the subclasses. UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); if (!Cs.empty()) { HiddenTypesBuffer = ParentHiddenTypes; HiddenTypes = &HiddenTypesBuffer; for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) { bool Hidden = !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl())); // If this conversion is hidden and we're in a virtual base, // remember that it's hidden along some inheritance path. if (Hidden && InVirtual) HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())); // If this conversion isn't hidden, add it to the appropriate output. else if (!Hidden) { AccessSpecifier IAccess = CXXRecordDecl::MergeAccess(Access, I.getAccess()); if (InVirtual) VOutput.addDecl(I.getDecl(), IAccess); else Output.addDecl(I.getDecl(), IAccess); } } } // Collect information recursively from any base classes. for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { const RecordType *RT = I->getType()->getAs<RecordType>(); if (!RT) continue; AccessSpecifier BaseAccess = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier()); bool BaseInVirtual = InVirtual || I->isVirtual(); CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } }
/// Add a stack slot that was take-assigned to the inout from an exit BB /// to the analysis. If we already have seen a store on this BB, or if the /// slot does not match the entry slot, the analysis fails. void addExitSlot(AllocStackInst *slot, SILBasicBlock *exitBB) { if (Failed) return; if (TheSlot && slot != TheSlot) return setFailed("inout is loaded and stored into different slots"); if (!ExitBBs.erase(exitBB)) return setFailed("inout is stored multiple times from same exit BB"); DEBUG(llvm::dbgs() << " found load from stack slot on exit " << exitBB << '\n'); TheSlot = slot; }
StackSlotState(SILFunction *F) : Failed(false), HaveEntrySlot(false) { // We need to see a store back to the inout on every exit path. for (auto &bb : *F) { auto term = bb.getTerminator(); if (isa<ReturnInst>(term) || isa<ThrowInst>(term)) { DEBUG(llvm::dbgs() << " need load from stack slot on exit " << &bb << '\n'); ExitBBs.insert(&bb); } } }
/// Get the single stack slot we can deshadow, or null if no such slot was /// found. AllocStackInst *getDeshadowableSlot() { if (Failed) return nullptr; // We must have seen both a store to and a load from the slot to deshadow // on every exit BB. if (!HaveEntrySlot) { DEBUG(llvm::dbgs() << "*** Rejecting deshadow: no store to stack slot\n"); return nullptr; } if (!ExitBBs.empty()) { DEBUG(llvm::dbgs() << "*** Rejecting deshadow: no load from stack slot " "on some paths\n"); return nullptr; } return TheSlot; }
void CXXRecordDecl::collectConversionFunctions( llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const { const UnresolvedSetImpl *Cs = getConversionFunctions(); for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { NamedDecl *TopConv = *I; CanQualType TConvType; if (FunctionTemplateDecl *TConversionTemplate = dyn_cast<FunctionTemplateDecl>(TopConv)) TConvType = getASTContext().getCanonicalType( TConversionTemplate->getTemplatedDecl()->getResultType()); else TConvType = getASTContext().getCanonicalType( cast<CXXConversionDecl>(TopConv)->getConversionType()); ConversionsTypeSet.insert(TConvType); } }
/// isSafeToConvert - Return true if it is safe to convert the specified record /// decl to IR and lay it out, false if doing so would cause us to get into a /// recursive compilation mess. static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT, llvm::SmallPtrSet<const RecordDecl*, 16> &AlreadyChecked) { // If we have already checked this type (maybe the same type is used by-value // multiple times in multiple structure fields, don't check again. if (!AlreadyChecked.insert(RD)) return true; const Type *Key = CGT.getContext().getTagDeclType(RD).getTypePtr(); // If this type is already laid out, converting it is a noop. if (CGT.isRecordLayoutComplete(Key)) return true; // If this type is currently being laid out, we can't recursively compile it. if (CGT.isRecordBeingLaidOut(Key)) return false; // If this type would require laying out bases that are currently being laid // out, don't do it. This includes virtual base classes which get laid out // when a class is translated, even though they aren't embedded by-value into // the class. if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { for (CXXRecordDecl::base_class_const_iterator I = CRD->bases_begin(), E = CRD->bases_end(); I != E; ++I) if (!isSafeToConvert(I->getType()->getAs<RecordType>()->getDecl(), CGT, AlreadyChecked)) return false; } // If this type would require laying out members that are currently being laid // out, don't do it. for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) if (!isSafeToConvert(I->getType(), CGT, AlreadyChecked)) return false; // If there are no problems, lets do it. return true; }
/// \brief Perform a depth-first visit of the current module. static bool visitDepthFirst(Module &M, bool (*Visitor)(Module &M, bool Preorder, void *UserData), void *UserData, llvm::SmallPtrSet<Module *, 4> &Visited) { // Preorder visitation if (Visitor(M, /*Preorder=*/true, UserData)) return true; // Visit children for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(), IMEnd = M.Imports.end(); IM != IMEnd; ++IM) { if (!Visited.insert(*IM)) continue; if (visitDepthFirst(**IM, Visitor, UserData, Visited)) return true; } // Postorder visitation return Visitor(M, /*Preorder=*/false, UserData); }
bool IndexSwiftASTWalker::visitImports(SourceFileOrModule TopMod, llvm::SmallPtrSet<Module *, 16> &Visited) { // Dependencies of the stdlib module (like SwiftShims module) are // implementation details. if (TopMod.getModule().isStdlibModule()) return true; bool IsNew = Visited.insert(&TopMod.getModule()).second; if (!IsNew) return true; SmallVector<Module::ImportedModule, 8> Imports; TopMod.getImportedModules(Imports); llvm::SmallPtrSet<Module *, 8> Reported; for (auto Import : Imports) { Module *Mod = Import.second; bool NewReport = Reported.insert(Mod).second; if (!NewReport) continue; // FIXME: Handle modules with multiple source files; these will fail on // getModuleFilename() (by returning an empty path). Note that such modules // may be heterogeneous. StringRef Path = Mod->getModuleFilename(); if (Path.empty() || Path == TopMod.getFilename()) continue; // this is a submodule. UIdent ImportKind; for (auto File : Mod->getFiles()) { switch (File->getKind()) { case FileUnitKind::Source: assert(ImportKind.isInvalid() && "cannot handle multi-file modules"); ImportKind = KindImportSourceFile; break; case FileUnitKind::Builtin: case FileUnitKind::Derived: break; case FileUnitKind::SerializedAST: assert(ImportKind.isInvalid() && "cannot handle multi-file modules"); ImportKind = KindImportModuleSwift; break; case FileUnitKind::ClangModule: assert(ImportKind.isInvalid() && "cannot handle multi-file modules"); ImportKind = KindImportModuleClang; break; } } if (ImportKind.isInvalid()) continue; StringRef Hash; SmallString<32> HashBuf; if (ImportKind != KindImportModuleClang) { llvm::raw_svector_ostream HashOS(HashBuf); getModuleHash(*Mod, HashOS); Hash = HashOS.str(); } if (!IdxConsumer.startDependency(ImportKind, Mod->getName().str(), Path, Mod->isSystemModule(), Hash)) return false; if (ImportKind != KindImportModuleClang) if (!visitImports(*Mod, Visited)) return false; if (!IdxConsumer.finishDependency(ImportKind)) return false; } return true; }
bool VisitDeclRefExpr(clang::DeclRefExpr* dref) { uses.insert(dref); return true; }
bool swift::immediate::IRGenImportedModules( CompilerInstance &CI, llvm::Module &Module, llvm::SmallPtrSet<swift::Module *, 8> &ImportedModules, SmallVectorImpl<llvm::Function*> &InitFns, IRGenOptions &IRGenOpts, const SILOptions &SILOpts) { swift::Module *M = CI.getMainModule(); // Perform autolinking. SmallVector<LinkLibrary, 4> AllLinkLibraries(IRGenOpts.LinkLibraries); auto addLinkLibrary = [&](LinkLibrary linkLib) { AllLinkLibraries.push_back(linkLib); }; M->forAllVisibleModules({}, /*includePrivateTopLevel=*/true, [&](Module::ImportedModule import) { import.second->collectLinkLibraries(addLinkLibrary); }); // Hack to handle thunks eagerly synthesized by the Clang importer. swift::Module *prev = nullptr; for (auto external : CI.getASTContext().ExternalDefinitions) { swift::Module *next = external->getModuleContext(); if (next == prev) continue; next->collectLinkLibraries(addLinkLibrary); prev = next; } tryLoadLibraries(AllLinkLibraries, CI.getASTContext().SearchPathOpts, CI.getDiags()); ImportedModules.insert(M); if (!CI.hasSourceImport()) return false; // IRGen the modules this module depends on. This is only really necessary // for imported source, but that's a very convenient thing to do in -i mode. // FIXME: Crawling all loaded modules is a hack. // FIXME: And re-doing SILGen, SIL-linking, SIL diagnostics, and IRGen is // expensive, because it's not properly being limited to new things right now. bool hadError = false; for (auto &entry : CI.getASTContext().LoadedModules) { swift::Module *import = entry.second; if (!ImportedModules.insert(import).second) continue; std::unique_ptr<SILModule> SILMod = performSILGeneration(import, CI.getSILOptions()); performSILLinking(SILMod.get()); if (runSILDiagnosticPasses(*SILMod)) { hadError = true; break; } // FIXME: We shouldn't need to use the global context here, but // something is persisting across calls to performIRGeneration. auto SubModule = performIRGeneration(IRGenOpts, import, SILMod.get(), import->getName().str(), llvm::getGlobalContext()); if (CI.getASTContext().hadError()) { hadError = true; break; } if (!linkLLVMModules(&Module, std::move(SubModule) // TODO: reactivate the linker mode if it is // supported in llvm again. Otherwise remove the // commented code completely. /*, llvm::Linker::DestroySource */)) { hadError = true; break; } // FIXME: This is an ugly hack; need to figure out how this should // actually work. SmallVector<char, 20> NameBuf; StringRef InitFnName = (import->getName().str() + ".init").toStringRef(NameBuf); llvm::Function *InitFn = Module.getFunction(InitFnName); if (InitFn) InitFns.push_back(InitFn); } return hadError; }
/// getNestedVisibleConversionFunctions - imports unique conversion /// functions from base classes into the visible conversion function /// list of the class 'RD'. This is a private helper method. /// TopConversionsTypeSet is the set of conversion functions of the class /// we are interested in. HiddenConversionTypes is set of conversion functions /// of the immediate derived class which hides the conversion functions found /// in current class. void CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes) { bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs<RecordType>()) { const UnresolvedSetImpl *Cs = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { NamedDecl *Conv = *I; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. CanQualType ConvType; if (FunctionTemplateDecl *ConversionTemplate = dyn_cast<FunctionTemplateDecl>(Conv)) ConvType = getASTContext().getCanonicalType( ConversionTemplate->getTemplatedDecl()->getResultType()); else ConvType = getASTContext().getCanonicalType( cast<CXXConversionDecl>(Conv)->getConversionType()); // We only add conversion functions found in the base class if they // are not hidden by those found in HiddenConversionTypes which are // the conversion functions in its derived class. if (inTopClass || (!TopConversionsTypeSet.count(ConvType) && !HiddenConversionTypes.count(ConvType)) ) { if (FunctionTemplateDecl *ConversionTemplate = dyn_cast<FunctionTemplateDecl>(Conv)) RD->addVisibleConversionFunction(ConversionTemplate); else RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv)); } } } if (getNumBases() == 0 && getNumVBases() == 0) return; llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; if (!inTopClass) collectConversionFunctions(ConversionFunctions); for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), E = vbases_end(); VBase != E; ++VBase) { if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) { CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); VBaseClassDecl->getNestedVisibleConversionFunctions(RD, TopConversionsTypeSet, (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); } } for (CXXRecordDecl::base_class_iterator Base = bases_begin(), E = bases_end(); Base != E; ++Base) { if (Base->isVirtual()) continue; if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); BaseClassDecl->getNestedVisibleConversionFunctions(RD, TopConversionsTypeSet, (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); } } }