Пример #1
0
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);
  }
}
Пример #2
0
/// 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()));
  }
}
Пример #3
0
/// 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);
  }
}
Пример #4
0
 /// 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;
 }
Пример #5
0
 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);
     }
   }
 }
Пример #6
0
 /// 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);
  }  
}
Пример #8
0
/// 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;
}
Пример #9
0
/// \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);
}
Пример #10
0
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;
}
Пример #11
0
 bool VisitDeclRefExpr(clang::DeclRefExpr* dref) {
   uses.insert(dref);
   return true;
 }
Пример #12
0
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));
    }
  }
}