void CodeGen::runSplitCodeGen(const SmallString<128> &BCFilename) { const std::string &TripleStr = M->getTargetTriple(); Triple TheTriple(TripleStr); SubtargetFeatures Features = getFeatures(TheTriple); TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); CodeGenOpt::Level CGOptLevel = getCGOptLevel(); SmallString<128> Filename; // Note that openOutputFile will append a unique ID for each task if (!options::obj_path.empty()) Filename = options::obj_path; else if (options::TheOutputType == options::OT_SAVE_TEMPS) Filename = output_name + ".o"; // Note that the default parallelism is 1 instead of the // hardware_concurrency, as there are behavioral differences between // parallelism levels (e.g. symbol ordering will be different, and some uses // of inline asm currently have issues with parallelism >1). unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1; std::vector<SmallString<128>> Filenames(MaxThreads); std::vector<SmallString<128>> BCFilenames(MaxThreads); bool TempOutFile = Filename.empty(); { // Open a file descriptor for each backend task. This is done in a block // so that the output file descriptors are closed before gold opens them. std::list<llvm::raw_fd_ostream> OSs; std::vector<llvm::raw_pwrite_stream *> OSPtrs(MaxThreads); for (unsigned I = 0; I != MaxThreads; ++I) { int FD = openOutputFile(Filename, TempOutFile, Filenames[I], // Only append ID if there are multiple tasks. MaxThreads > 1 ? I : -1); OSs.emplace_back(FD, true); OSPtrs[I] = &OSs.back(); } std::list<llvm::raw_fd_ostream> BCOSs; std::vector<llvm::raw_pwrite_stream *> BCOSPtrs; if (!BCFilename.empty() && MaxThreads > 1) { for (unsigned I = 0; I != MaxThreads; ++I) { int FD = openOutputFile(BCFilename, false, BCFilenames[I], I); BCOSs.emplace_back(FD, true); BCOSPtrs.push_back(&BCOSs.back()); } } // Run backend tasks. splitCodeGen(std::move(M), OSPtrs, BCOSPtrs, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel); } for (auto &Filename : Filenames) recordFile(Filename.c_str(), TempOutFile); }
std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) { SmallString<128> StringStorage; if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) { StringRef KeyStr = SN->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage KeyStr = StringStorage.str().copy(StringAllocator); } return llvm::make_unique<ScalarHNode>(N, KeyStr); } else if (BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(N)) { StringRef ValueCopy = BSN->getValue().copy(StringAllocator); return llvm::make_unique<ScalarHNode>(N, ValueCopy); } else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) { auto SQHNode = llvm::make_unique<SequenceHNode>(N); for (Node &SN : *SQ) { auto Entry = createHNodes(&SN); if (EC) break; SQHNode->Entries.push_back(std::move(Entry)); } return std::move(SQHNode); } else if (MappingNode *Map = dyn_cast<MappingNode>(N)) { auto mapHNode = llvm::make_unique<MapHNode>(N); for (KeyValueNode &KVN : *Map) { Node *KeyNode = KVN.getKey(); ScalarNode *Key = dyn_cast<ScalarNode>(KeyNode); Node *Value = KVN.getValue(); if (!Key || !Value) { if (!Key) setError(KeyNode, "Map key must be a scalar"); if (!Value) setError(KeyNode, "Map value must not be empty"); break; } StringStorage.clear(); StringRef KeyStr = Key->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage KeyStr = StringStorage.str().copy(StringAllocator); } auto ValueHNode = createHNodes(Value); if (EC) break; mapHNode->Mapping[KeyStr] = std::move(ValueHNode); } return std::move(mapHNode); } else if (isa<NullNode>(N)) { return llvm::make_unique<EmptyHNode>(N); } else { setError(N, "unknown node kind"); return nullptr; } }
Input::HNode *Input::createHNodes(Node *N) { SmallString<128> StringStorage; if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) { StringRef KeyStr = SN->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage unsigned Len = StringStorage.size(); char *Buf = StringAllocator.Allocate<char>(Len); memcpy(Buf, &StringStorage[0], Len); KeyStr = StringRef(Buf, Len); } return new ScalarHNode(N, KeyStr); } else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) { SequenceHNode *SQHNode = new SequenceHNode(N); for (Node &SN : *SQ) { HNode *Entry = this->createHNodes(&SN); if (EC) break; SQHNode->Entries.push_back(Entry); } return SQHNode; } else if (MappingNode *Map = dyn_cast<MappingNode>(N)) { MapHNode *mapHNode = new MapHNode(N); for (KeyValueNode &KVN : *Map) { Node *KeyNode = KVN.getKey(); ScalarNode *KeyScalar = dyn_cast<ScalarNode>(KeyNode); if (!KeyScalar) { setError(KeyNode, "Map key must be a scalar"); break; } StringStorage.clear(); StringRef KeyStr = KeyScalar->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage unsigned Len = StringStorage.size(); char *Buf = StringAllocator.Allocate<char>(Len); memcpy(Buf, &StringStorage[0], Len); KeyStr = StringRef(Buf, Len); } HNode *ValueHNode = this->createHNodes(KVN.getValue()); if (EC) break; mapHNode->Mapping[KeyStr] = ValueHNode; } return mapHNode; } else if (isa<NullNode>(N)) { return new EmptyHNode(N); } else { setError(N, "unknown node kind"); return nullptr; } }
Input::HNode *Input::createHNodes(Node *N) { SmallString<128> StringStorage; if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) { StringRef KeyStr = SN->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage unsigned Len = StringStorage.size(); char *Buf = StringAllocator.Allocate<char>(Len); memcpy(Buf, &StringStorage[0], Len); KeyStr = StringRef(Buf, Len); } return new ScalarHNode(N, KeyStr); } else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) { SequenceHNode *SQHNode = new SequenceHNode(N); for (SequenceNode::iterator i = SQ->begin(), End = SQ->end(); i != End; ++i) { HNode *Entry = this->createHNodes(i); if (EC) break; SQHNode->Entries.push_back(Entry); } return SQHNode; } else if (MappingNode *Map = dyn_cast<MappingNode>(N)) { MapHNode *mapHNode = new MapHNode(N); for (MappingNode::iterator i = Map->begin(), End = Map->end(); i != End; ++i) { ScalarNode *KeyScalar = dyn_cast<ScalarNode>(i->getKey()); StringStorage.clear(); StringRef KeyStr = KeyScalar->getValue(StringStorage); if (!StringStorage.empty()) { // Copy string to permanent storage unsigned Len = StringStorage.size(); char *Buf = StringAllocator.Allocate<char>(Len); memcpy(Buf, &StringStorage[0], Len); KeyStr = StringRef(Buf, Len); } HNode *ValueHNode = this->createHNodes(i->getValue()); if (EC) break; mapHNode->Mapping[KeyStr] = ValueHNode; } return mapHNode; } else if (isa<NullNode>(N)) { return new EmptyHNode(N); } else { setError(N, "unknown node kind"); return NULL; } }
// Convert a path into the canonical form. // Canonical form is either "/", or "/segment" * N: // C:\foo\bar --> /c:/foo/bar // /foo/ --> /foo // a/b/c --> /a/b/c static SmallString<128> canonicalize(StringRef Path) { SmallString<128> Result = Path.rtrim('/'); native(Result, sys::path::Style::posix); if (Result.empty() || Result.front() != '/') Result.insert(Result.begin(), '/'); return Result; }
/// CrashHandler - This callback is run if a fatal signal is delivered to the /// process, it prints the pretty stack trace. static void CrashHandler(void *) { #ifndef __APPLE__ // On non-apple systems, just emit the crash stack trace to stderr. PrintCurStackTrace(errs()); #else // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also // put it into __crashreporter_info__. SmallString<2048> TmpStr; { raw_svector_ostream Stream(TmpStr); PrintCurStackTrace(Stream); } if (!TmpStr.empty()) { #ifdef HAVE_CRASHREPORTERCLIENT_H // Cast to void to avoid warning. (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); #elif HAVE_CRASHREPORTER_INFO __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); #endif errs() << TmpStr.str(); } #endif }
const MCSection * X86WindowsTargetObjectFile::getSectionForConstant(SectionKind Kind, const Constant *C) const { if (Kind.isReadOnly()) { if (C) { Type *Ty = C->getType(); SmallString<32> COMDATSymName; if (Ty->isFloatTy() || Ty->isDoubleTy()) { COMDATSymName = "__real@"; COMDATSymName += scalarConstantToHexString(C); } else if (const auto *VTy = dyn_cast<VectorType>(Ty)) { uint64_t NumBits = VTy->getBitWidth(); if (NumBits == 128 || NumBits == 256) { COMDATSymName = NumBits == 128 ? "__xmm@" : "__ymm@"; for (int I = VTy->getNumElements() - 1, E = -1; I != E; --I) COMDATSymName += scalarConstantToHexString(C->getAggregateElement(I)); } } if (!COMDATSymName.empty()) { unsigned Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_LNK_COMDAT; return getContext().getCOFFSection(".rdata", Characteristics, Kind, COMDATSymName, COFF::IMAGE_COMDAT_SELECT_ANY); } } } return TargetLoweringObjectFile::getSectionForConstant(Kind, C); }
/// Launch each module's backend pipeline in a separate task in a thread pool. static void thinLTOBackends(raw_fd_ostream *ApiFile, const ModuleSummaryIndex &CombinedIndex) { unsigned TaskCount = 0; std::vector<ThinLTOTaskInfo> Tasks; Tasks.reserve(Modules.size()); unsigned int MaxThreads = options::Parallelism ? options::Parallelism : thread::hardware_concurrency(); // Create ThreadPool in nested scope so that threads will be joined // on destruction. { ThreadPool ThinLTOThreadPool(MaxThreads); for (claimed_file &F : Modules) { // Do all the gold callbacks in the main thread, since gold is not thread // safe by default. PluginInputFile InputFile(F.handle); const void *View = getSymbolsAndView(F); if (!View) continue; SmallString<128> Filename; if (!options::obj_path.empty()) // Note that openOutputFile will append a unique ID for each task Filename = options::obj_path; else if (options::TheOutputType == options::OT_SAVE_TEMPS) { // Use the input file name so that we get a unique and identifiable // output file for each ThinLTO backend task. Filename = InputFile.file().name; Filename += ".thinlto.o"; } bool TempOutFile = Filename.empty(); SmallString<128> NewFilename; int FD = openOutputFile(Filename, TempOutFile, NewFilename, // Only append the TaskID if we will use the // non-unique obj_path. !options::obj_path.empty() ? TaskCount : -1); TaskCount++; std::unique_ptr<raw_fd_ostream> OS = llvm::make_unique<raw_fd_ostream>(FD, true); // Enqueue the task ThinLTOThreadPool.async(thinLTOBackendTask, std::ref(F), View, std::ref(InputFile.file()), ApiFile, std::ref(CombinedIndex), OS.get(), TaskCount); // Record the information needed by the task or during its cleanup // to a ThinLTOTaskInfo instance. For information needed by the task // the unique_ptr ownership is transferred to the ThinLTOTaskInfo. Tasks.emplace_back(std::move(InputFile), std::move(OS), NewFilename.c_str(), TempOutFile); } } for (auto &Task : Tasks) Task.cleanup(); }
void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { const DataLayout &DL = M.getDataLayout(); SmallString<128> Str; raw_svector_ostream OS(Str); for (const Function &F : M) if (F.isDeclarationForLinker()) { assert(F.hasName() && "imported functions must have a name"); if (F.isIntrinsic()) continue; if (Str.empty()) OS << "\t.imports\n"; OS << "\t.import " << toSymbol(F.getName()) << " \"\" \"" << F.getName() << "\""; const WebAssemblyTargetLowering &TLI = *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering(); // If we need to legalize the return type, it'll get converted into // passing a pointer. bool SawParam = false; SmallVector<MVT, 4> ResultVTs; ComputeLegalValueVTs(M.getContext(), TLI, DL, F.getReturnType(), ResultVTs); if (ResultVTs.size() > 1) { ResultVTs.clear(); OS << " (param " << toString(TLI.getPointerTy(DL)); SawParam = true; } for (const Argument &A : F.args()) { SmallVector<MVT, 4> ParamVTs; ComputeLegalValueVTs(M.getContext(), TLI, DL, A.getType(), ParamVTs); for (EVT VT : ParamVTs) { if (!SawParam) { OS << " (param"; SawParam = true; } OS << ' ' << toString(VT.getSimpleVT()); } } if (SawParam) OS << ')'; for (EVT VT : ResultVTs) OS << " (result " << toString(VT.getSimpleVT()) << ')'; OS << '\n'; } StringRef Text = OS.str(); if (!Text.empty()) OutStreamer->EmitRawText(Text.substr(0, Text.size() - 1)); }
/// \brief Simple utility function that appends a \p New string to the given /// \p Old string, using the \p Buffer for storage. /// /// \param Old The string to which we are appending. This parameter will be /// updated to reflect the complete string. /// /// /// \param New The string to append to \p Old. /// /// \param Buffer A buffer that stores the actual, concatenated string. It will /// be used if the old string is already-non-empty. static void AppendToString(StringRef &Old, StringRef New, SmallString<256> &Buffer) { if (Old.empty()) { Old = New; return; } if (Buffer.empty()) Buffer.append(Old.begin(), Old.end()); Buffer.append(New.begin(), New.end()); Old = Buffer.str(); }
/// \brief Find the end of the word starting at the given offset /// within a string. /// /// \returns the index pointing one character past the end of the /// word. static unsigned findEndOfWord(unsigned Start, StringRef Str, unsigned Length, unsigned Column, unsigned Columns) { assert(Start < Str.size() && "Invalid start position!"); unsigned End = Start + 1; // If we are already at the end of the string, take that as the word. if (End == Str.size()) return End; // Determine if the start of the string is actually opening // punctuation, e.g., a quote or parentheses. char EndPunct = findMatchingPunctuation(Str[Start]); if (!EndPunct) { // This is a normal word. Just find the first space character. while (End < Length && !isspace(Str[End])) ++End; return End; } // We have the start of a balanced punctuation sequence (quotes, // parentheses, etc.). Determine the full sequence is. SmallString<16> PunctuationEndStack; PunctuationEndStack.push_back(EndPunct); while (End < Length && !PunctuationEndStack.empty()) { if (Str[End] == PunctuationEndStack.back()) PunctuationEndStack.pop_back(); else if (char SubEndPunct = findMatchingPunctuation(Str[End])) PunctuationEndStack.push_back(SubEndPunct); ++End; } // Find the first space character after the punctuation ended. while (End < Length && !isspace(Str[End])) ++End; unsigned PunctWordLength = End - Start; if (// If the word fits on this line Column + PunctWordLength <= Columns || // ... or the word is "short enough" to take up the next line // without too much ugly white space PunctWordLength < Columns/3) return End; // Take the whole thing as a single "word". // The whole quoted/parenthesized string is too long to print as a // single "word". Instead, find the "word" that starts just after // the punctuation and use that end-point instead. This will recurse // until it finds something small enough to consider a word. return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns); }
bool ASTUnit::serialize(llvm::raw_ostream &OS) { if (getDiagnostics().hasErrorOccurred()) return true; SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); Writer.WriteAST(getSema(), 0, std::string(), 0); // Write the generated bitstream to "Out". if (!Buffer.empty()) OS.write((char *)&Buffer.front(), Buffer.size()); return false; }
// If we haven't already, emit metadata describing this thread. void captureThreadMetadata() { uint64_t TID = get_threadid(); std::lock_guard<std::mutex> Lock(Mu); if (ThreadsWithMD.insert(TID).second) { SmallString<32> Name; get_thread_name(Name); if (!Name.empty()) { rawEvent("M", json::obj{ {"tid", TID}, {"name", "thread_name"}, {"args", json::obj{{"name", Name}}}, }); } } }
void CVTypeDumperImpl::visitPointer(TypeLeafKind Leaf, PointerRecord &Ptr) { printTypeIndex("PointeeType", Ptr.getReferentType()); W.printHex("PointerAttributes", uint32_t(Ptr.getOptions())); W.printEnum("PtrType", unsigned(Ptr.getPointerKind()), makeArrayRef(PtrKindNames)); W.printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); W.printNumber("IsFlat", Ptr.isFlat()); W.printNumber("IsConst", Ptr.isConst()); W.printNumber("IsVolatile", Ptr.isVolatile()); W.printNumber("IsUnaligned", Ptr.isUnaligned()); if (Ptr.isPointerToMember()) { const MemberPointerInfo &MI = Ptr.getMemberInfo(); printTypeIndex("ClassType", MI.getContainingType()); W.printEnum("Representation", uint16_t(MI.getRepresentation()), makeArrayRef(PtrMemberRepNames)); StringRef PointeeName = getTypeName(Ptr.getReferentType()); StringRef ClassName = getTypeName(MI.getContainingType()); SmallString<256> TypeName(PointeeName); TypeName.push_back(' '); TypeName.append(ClassName); TypeName.append("::*"); Name = CVTD.saveName(TypeName); } else { SmallString<256> TypeName; if (Ptr.isConst()) TypeName.append("const "); if (Ptr.isVolatile()) TypeName.append("volatile "); if (Ptr.isUnaligned()) TypeName.append("__unaligned "); TypeName.append(getTypeName(Ptr.getReferentType())); if (Ptr.getMode() == PointerMode::LValueReference) TypeName.append("&"); else if (Ptr.getMode() == PointerMode::RValueReference) TypeName.append("&&"); else if (Ptr.getMode() == PointerMode::Pointer) TypeName.append("*"); if (!TypeName.empty()) Name = CVTD.saveName(TypeName); } }
std::string TypeChecker::gatherGenericParamBindingsText( ArrayRef<Type> types, TypeArrayView<GenericTypeParamType> genericParams, TypeSubstitutionFn substitutions) { llvm::SmallPtrSet<GenericTypeParamType *, 2> knownGenericParams; for (auto type : types) { if (type.isNull()) continue; type.visit([&](Type type) { if (auto gp = type->getAs<GenericTypeParamType>()) { knownGenericParams.insert( gp->getCanonicalType()->castTo<GenericTypeParamType>()); } }); } if (knownGenericParams.empty()) return ""; SmallString<128> result; for (auto gp : genericParams) { auto canonGP = gp->getCanonicalType()->castTo<GenericTypeParamType>(); if (!knownGenericParams.count(canonGP)) continue; if (result.empty()) result += " [with "; else result += ", "; result += gp->getName().str(); result += " = "; auto type = substitutions(canonGP); if (!type) return ""; result += type.getString(); } result += "]"; return result.str().str(); }
ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) { SmallString<256> Path; Path_.toVector(Path); // Handle relative paths if (error_code EC = sys::fs::make_absolute(Path)) return EC; if (Path.empty()) return error_code(errc::invalid_argument, system_category()); sys::path::const_iterator Start = sys::path::begin(Path); sys::path::const_iterator End = sys::path::end(Path); for (std::vector<Entry *>::iterator I = Roots.begin(), E = Roots.end(); I != E; ++I) { ErrorOr<Entry *> Result = lookupPath(Start, End, *I); if (Result || Result.getError() != errc::no_such_file_or_directory) return Result; } return error_code(errc::no_such_file_or_directory, system_category()); }
/// Create a text string that describes the bindings of generic parameters that /// are relevant to the given set of types, e.g., "[with T = Bar, U = Wibble]". /// /// \param types The types that will be scanned for generic type parameters, /// which will be used in the resulting type. /// /// \param genericSig The actual generic parameters, whose names will be used /// in the resulting text. /// /// \param substitutions The generic parameter -> generic argument substitutions /// that will have been applied to these types. These are used to produce the /// "parameter = argument" bindings in the test. static std::string gatherGenericParamBindingsText( ArrayRef<Type> types, GenericSignature *genericSig, const TypeSubstitutionMap &substitutions) { llvm::SmallPtrSet<GenericTypeParamType *, 2> knownGenericParams; for (auto type : types) { type.visit([&](Type type) { if (auto gp = type->getAs<GenericTypeParamType>()) { knownGenericParams.insert(gp->getCanonicalType() ->castTo<GenericTypeParamType>()); } }); } if (knownGenericParams.empty()) return ""; SmallString<128> result; for (auto gp : genericSig->getGenericParams()) { auto canonGP = gp->getCanonicalType()->castTo<GenericTypeParamType>(); if (!knownGenericParams.count(canonGP)) continue; if (result.empty()) result += " [with "; else result += ", "; result += gp->getName().str(); result += " = "; auto found = substitutions.find(canonGP); if (found == substitutions.end()) return ""; result += found->second.getString(); } result += "]"; return result.str().str(); }
void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { SmallString<128> Str; raw_svector_ostream OS(Str); for (const Function &F : M) if (F.isDeclarationForLinker()) { assert(F.hasName() && "imported functions must have a name"); if (F.getName().startswith("llvm.")) continue; if (Str.empty()) OS << "\t.imports\n"; Type *Rt = F.getReturnType(); OS << "\t.import " << toSymbol(F.getName()) << " \"\" \"" << F.getName() << "\" (param"; for (const Argument &A : F.args()) OS << ' ' << toString(A.getType()); OS << ')'; if (!Rt->isVoidTy()) OS << " (result " << toString(Rt) << ')'; OS << '\n'; } OutStreamer->EmitRawText(OS.str()); }
void BuildSystemFrontendDelegate::commandStarted(Command* command) { // Don't report status if opted out by the command. if (!command->shouldShowStatus()) { return; } // Log the command. // // FIXME: Design the logging and status output APIs. SmallString<64> description; if (getFrontend().getInvocation().showVerboseStatus) { command->getVerboseDescription(description); } else { command->getShortDescription(description); // If the short description is empty, always show the verbose one. if (description.empty()) { command->getVerboseDescription(description); } } fprintf(stdout, "%s\n", description.c_str()); fflush(stdout); }
static void prepareLinkingPaths(SmallString<32> invocationPath) { // First search the directory of the binary for the library, in case it is // all bundled together. sys::path::remove_filename(invocationPath); if (!invocationPath.empty()) { libPaths.push_back(invocationPath.str()); } // If the builder doesn't plan on installing it, we still need to get to the // runtime library somehow, so just build in the path to the temporary one. #ifdef CMAKE_INSTALL_PREFIX libPaths.push_back(CMAKE_INSTALL_PREFIX "/lib"); #elif defined(CMAKE_TEMP_LIBRARY_PATH) libPaths.push_back(CMAKE_TEMP_LIBRARY_PATH); #elif defined(TEMP_LIBRARY_PATH) // This is a bit of a hack libPaths.push_back(TEMP_LIBRARY_PATH "/Debug+Asserts/lib/"); libPaths.push_back(TEMP_LIBRARY_PATH "/Release+Asserts/lib/"); libPaths.push_back(TEMP_LIBRARY_PATH "/Debug/lib/"); libPaths.push_back(TEMP_LIBRARY_PATH "/Release/lib/"); #endif libraries.push_back(RUNTIME_LIB); libraries.push_back("rt"); }
/// Create a text string that describes the bindings of generic parameters that /// are relevant to the given set of types, e.g., "[with T = Bar, U = Wibble]". /// /// \param types The types that will be scanned for generic type parameters, /// which will be used in the resulting type. /// /// \param genericParams The actual generic parameters, whose names will be used /// in the resulting text. /// /// \param substitutions The generic parameter -> generic argument substitutions /// that will have been applied to these types. These are used to produce the /// "parameter = argument" bindings in the test. static std::string gatherGenericParamBindingsText( ArrayRef<Type> types, ArrayRef<GenericTypeParamType *> genericParams, TypeSubstitutionMap &substitutions) { llvm::SmallPtrSet<GenericTypeParamType *, 2> knownGenericParams; for (auto type : types) { type.findIf([&](Type type) -> bool { if (auto gp = type->getAs<GenericTypeParamType>()) { knownGenericParams.insert(gp->getCanonicalType() ->castTo<GenericTypeParamType>()); } return false; }); } if (knownGenericParams.empty()) return ""; SmallString<128> result; for (auto gp : genericParams) { auto canonGP = gp->getCanonicalType()->castTo<GenericTypeParamType>(); if (!knownGenericParams.count(canonGP)) continue; if (result.empty()) result += " [with "; else result += ", "; result += gp->getName().str(); result += " = "; result += substitutions[canonGP].getString(); } result += "]"; return result.str().str(); }
/// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. static void compileModule(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, Module *Module, StringRef ModuleFileName) { llvm::LockFileManager Locked(ModuleFileName); switch (Locked) { case llvm::LockFileManager::LFS_Error: return; case llvm::LockFileManager::LFS_Owned: // We're responsible for building the module ourselves. Do so below. break; case llvm::LockFileManager::LFS_Shared: // Someone else is responsible for building the module. Wait for them to // finish. Locked.waitForUnlock(); return; } ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); // Construct a compiler invocation for creating this module. IntrusiveRefCntPtr<CompilerInvocation> Invocation (new CompilerInvocation(ImportingInstance.getInvocation())); PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); // For any options that aren't intended to affect how a module is built, // reset them to their default values. Invocation->getLangOpts()->resetNonModularOptions(); PPOpts.resetNonModularOptions(); // Note the name of the module we're building. Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName(); // Make sure that the failed-module structure has been allocated in // the importing instance, and propagate the pointer to the newly-created // instance. PreprocessorOptions &ImportingPPOpts = ImportingInstance.getInvocation().getPreprocessorOpts(); if (!ImportingPPOpts.FailedModules) ImportingPPOpts.FailedModules = new PreprocessorOptions::FailedModulesSet; PPOpts.FailedModules = ImportingPPOpts.FailedModules; // If there is a module map file, build the module using the module map. // Set up the inputs/outputs so that we build the module from its umbrella // header. FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); FrontendOpts.OutputFile = ModuleFileName.str(); FrontendOpts.DisableFree = false; FrontendOpts.Inputs.clear(); InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts()); // Get or create the module map that we'll use to build this module. SmallString<128> TempModuleMapFileName; if (const FileEntry *ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { // Use the module map where this module resides. FrontendOpts.Inputs.push_back(FrontendInputFile(ModuleMapFile->getName(), IK)); } else { // Create a temporary module map file. TempModuleMapFileName = Module->Name; TempModuleMapFileName += "-%%%%%%%%.map"; int FD; if (llvm::sys::fs::unique_file(TempModuleMapFileName.str(), FD, TempModuleMapFileName, /*makeAbsolute=*/true) != llvm::errc::success) { ImportingInstance.getDiagnostics().Report(diag::err_module_map_temp_file) << TempModuleMapFileName; return; } // Print the module map to this file. llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true); Module->print(OS); FrontendOpts.Inputs.push_back( FrontendInputFile(TempModuleMapFileName.str().str(), IK)); } // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; assert(ImportingInstance.getInvocation().getModuleHash() == Invocation->getModuleHash() && "Module hash mismatch!"); // Construct a compiler instance that will be used to actually create the // module. CompilerInstance Instance; Instance.setInvocation(&*Invocation); Instance.createDiagnostics(/*argc=*/0, /*argv=*/0, &ImportingInstance.getDiagnosticClient(), /*ShouldOwnClient=*/true, /*ShouldCloneClient=*/true); // Note that this module is part of the module build stack, so that we // can detect cycles in the module graph. Instance.createFileManager(); // FIXME: Adopt file manager from importer? Instance.createSourceManager(Instance.getFileManager()); SourceManager &SourceMgr = Instance.getSourceManager(); SourceMgr.setModuleBuildStack( ImportingInstance.getSourceManager().getModuleBuildStack()); SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(), FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); // Construct a module-generating action. GenerateModuleAction CreateModuleAction; // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. const unsigned ThreadStackSize = 8 << 20; llvm::CrashRecoveryContext CRC; CompileModuleMapData Data = { Instance, CreateModuleAction }; CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize); // Delete the temporary module map file. // FIXME: Even though we're executing under crash protection, it would still // be nice to do this with RemoveFileOnSignal when we can. However, that // doesn't make sense for all clients, so clean this up manually. Instance.clearOutputFiles(/*EraseFiles=*/true); if (!TempModuleMapFileName.empty()) llvm::sys::Path(TempModuleMapFileName).eraseFromDisk(); }
static void codegen(std::unique_ptr<Module> M) { const std::string &TripleStr = M->getTargetTriple(); Triple TheTriple(TripleStr); std::string ErrMsg; const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); if (!TheTarget) message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str()); if (unsigned NumOpts = options::extra.size()) cl::ParseCommandLineOptions(NumOpts, &options::extra[0]); SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(TheTriple); for (const std::string &A : MAttrs) Features.AddFeature(A); TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); CodeGenOpt::Level CGOptLevel; switch (options::OptLevel) { case 0: CGOptLevel = CodeGenOpt::None; break; case 1: CGOptLevel = CodeGenOpt::Less; break; case 2: CGOptLevel = CodeGenOpt::Default; break; case 3: CGOptLevel = CodeGenOpt::Aggressive; break; } std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine( TripleStr, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel)); runLTOPasses(*M, *TM); if (options::TheOutputType == options::OT_SAVE_TEMPS) saveBCFile(output_name + ".opt.bc", *M); SmallString<128> Filename; if (!options::obj_path.empty()) Filename = options::obj_path; else if (options::TheOutputType == options::OT_SAVE_TEMPS) Filename = output_name + ".o"; std::vector<SmallString<128>> Filenames(options::Parallelism); bool TempOutFile = Filename.empty(); { // Open a file descriptor for each backend thread. This is done in a block // so that the output file descriptors are closed before gold opens them. std::list<llvm::raw_fd_ostream> OSs; std::vector<llvm::raw_pwrite_stream *> OSPtrs(options::Parallelism); for (unsigned I = 0; I != options::Parallelism; ++I) { int FD; if (TempOutFile) { std::error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filenames[I]); if (EC) message(LDPL_FATAL, "Could not create temporary file: %s", EC.message().c_str()); } else { Filenames[I] = Filename; if (options::Parallelism != 1) Filenames[I] += utostr(I); std::error_code EC = sys::fs::openFileForWrite(Filenames[I], FD, sys::fs::F_None); if (EC) message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str()); } OSs.emplace_back(FD, true); OSPtrs[I] = &OSs.back(); } // Run backend threads. splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(), Options, RelocationModel, CodeModel::Default, CGOptLevel); } for (auto &Filename : Filenames) { if (add_input_file(Filename.c_str()) != LDPS_OK) message(LDPL_FATAL, "Unable to add .o file to the link. File left behind in: %s", Filename.c_str()); if (TempOutFile) Cleanup.push_back(Filename.c_str()); } }
void CodeGenModule::EmitCXXGlobalInitFunc() { while (!CXXGlobalInits.empty() && !CXXGlobalInits.back()) CXXGlobalInits.pop_back(); if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty()) return; llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction(); // Create our global initialization function. if (!PrioritizedCXXGlobalInits.empty()) { SmallVector<llvm::Function *, 8> LocalCXXGlobalInits; llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(), PrioritizedCXXGlobalInits.end()); // Iterate over "chunks" of ctors with same priority and emit each chunk // into separate function. Note - everything is sorted first by priority, // second - by lex order, so we emit ctor functions in proper order. for (SmallVectorImpl<GlobalInitData >::iterator I = PrioritizedCXXGlobalInits.begin(), E = PrioritizedCXXGlobalInits.end(); I != E; ) { SmallVectorImpl<GlobalInitData >::iterator PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp()); LocalCXXGlobalInits.clear(); unsigned Priority = I->first.priority; // Compute the function suffix from priority. Prepend with zeroes to make // sure the function names are also ordered as priorities. std::string PrioritySuffix = llvm::utostr(Priority); // Priority is always <= 65535 (enforced by sema). PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix; llvm::Function *Fn = CreateGlobalInitOrDestructFunction( FTy, "_GLOBAL__I_" + PrioritySuffix, FI); for (; I < PrioE; ++I) LocalCXXGlobalInits.push_back(I->second); CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, LocalCXXGlobalInits); AddGlobalCtor(Fn, Priority); } PrioritizedCXXGlobalInits.clear(); } // Include the filename in the symbol name. Including "sub_" matches gcc and // makes sure these symbols appear lexicographically behind the symbols with // priority emitted above. SmallString<128> FileName = llvm::sys::path::filename(getModule().getName()); if (FileName.empty()) FileName = "<null>"; for (size_t i = 0; i < FileName.size(); ++i) { // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens // to be the set of C preprocessing numbers. if (!isPreprocessingNumberBody(FileName[i])) FileName[i] = '_'; } llvm::Function *Fn = CreateGlobalInitOrDestructFunction( FTy, llvm::Twine("_GLOBAL__sub_I_", FileName), FI); CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits); AddGlobalCtor(Fn); CXXGlobalInits.clear(); }
void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { FullCommentParts Parts(C, Traits); const DeclInfo *DI = C->getDeclInfo(); StringRef RootEndTag; if (DI) { switch (DI->getKind()) { case DeclInfo::OtherKind: RootEndTag = "</Other>"; Result << "<Other"; break; case DeclInfo::FunctionKind: RootEndTag = "</Function>"; Result << "<Function"; switch (DI->TemplateKind) { case DeclInfo::NotTemplate: break; case DeclInfo::Template: Result << " templateKind=\"template\""; break; case DeclInfo::TemplateSpecialization: Result << " templateKind=\"specialization\""; break; case DeclInfo::TemplatePartialSpecialization: llvm_unreachable("partial specializations of functions " "are not allowed in C++"); } if (DI->IsInstanceMethod) Result << " isInstanceMethod=\"1\""; if (DI->IsClassMethod) Result << " isClassMethod=\"1\""; break; case DeclInfo::ClassKind: RootEndTag = "</Class>"; Result << "<Class"; switch (DI->TemplateKind) { case DeclInfo::NotTemplate: break; case DeclInfo::Template: Result << " templateKind=\"template\""; break; case DeclInfo::TemplateSpecialization: Result << " templateKind=\"specialization\""; break; case DeclInfo::TemplatePartialSpecialization: Result << " templateKind=\"partialSpecialization\""; break; } break; case DeclInfo::VariableKind: RootEndTag = "</Variable>"; Result << "<Variable"; break; case DeclInfo::NamespaceKind: RootEndTag = "</Namespace>"; Result << "<Namespace"; break; case DeclInfo::TypedefKind: RootEndTag = "</Typedef>"; Result << "<Typedef"; break; case DeclInfo::EnumKind: RootEndTag = "</Enum>"; Result << "<Enum"; break; } { // Print line and column number. SourceLocation Loc = DI->CurrentDecl->getLocation(); std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; if (FID.isValid()) { if (const FileEntry *FE = SM.getFileEntryForID(FID)) { Result << " file=\""; appendToResultWithXMLEscaping(FE->getName()); Result << "\""; } Result << " line=\"" << SM.getLineNumber(FID, FileOffset) << "\" column=\"" << SM.getColumnNumber(FID, FileOffset) << "\""; } } // Finish the root tag. Result << ">"; bool FoundName = false; if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) { if (DeclarationName DeclName = ND->getDeclName()) { Result << "<Name>"; std::string Name = DeclName.getAsString(); appendToResultWithXMLEscaping(Name); FoundName = true; Result << "</Name>"; } } if (!FoundName) Result << "<Name><anonymous></Name>"; { // Print USR. SmallString<128> USR; generateUSRForDecl(DI->CommentDecl, USR); if (!USR.empty()) { Result << "<USR>"; appendToResultWithXMLEscaping(USR); Result << "</USR>"; } } } else { // No DeclInfo -- just emit some root tag and name tag. RootEndTag = "</Other>"; Result << "<Other><Name>unknown</Name>"; } if (Parts.Headerfile) { Result << "<Headerfile>"; visit(Parts.Headerfile); Result << "</Headerfile>"; } { // Pretty-print the declaration. Result << "<Declaration>"; SmallString<128> Declaration; getSourceTextOfDeclaration(DI, Declaration); formatTextOfDeclaration(DI, Declaration); appendToResultWithXMLEscaping(Declaration); Result << "</Declaration>"; } bool FirstParagraphIsBrief = false; if (Parts.Brief) { Result << "<Abstract>"; visit(Parts.Brief); Result << "</Abstract>"; } else if (Parts.FirstParagraph) { Result << "<Abstract>"; visit(Parts.FirstParagraph); Result << "</Abstract>"; FirstParagraphIsBrief = true; } if (Parts.TParams.size() != 0) { Result << "<TemplateParameters>"; for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) visit(Parts.TParams[i]); Result << "</TemplateParameters>"; } if (Parts.Params.size() != 0) { Result << "<Parameters>"; for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) visit(Parts.Params[i]); Result << "</Parameters>"; } if (Parts.Exceptions.size() != 0) { Result << "<Exceptions>"; for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i) visit(Parts.Exceptions[i]); Result << "</Exceptions>"; } if (Parts.Returns.size() != 0) { Result << "<ResultDiscussion>"; for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) visit(Parts.Returns[i]); Result << "</ResultDiscussion>"; } if (DI->CommentDecl->hasAttrs()) { const AttrVec &Attrs = DI->CommentDecl->getAttrs(); for (unsigned i = 0, e = Attrs.size(); i != e; i++) { const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]); if (!AA) { if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) { if (DA->getMessage().empty()) Result << "<Deprecated/>"; else { Result << "<Deprecated>"; appendToResultWithXMLEscaping(DA->getMessage()); Result << "</Deprecated>"; } } else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) { if (UA->getMessage().empty()) Result << "<Unavailable/>"; else { Result << "<Unavailable>"; appendToResultWithXMLEscaping(UA->getMessage()); Result << "</Unavailable>"; } } continue; } // 'availability' attribute. Result << "<Availability"; StringRef Distribution; if (AA->getPlatform()) { Distribution = AvailabilityAttr::getPrettyPlatformName( AA->getPlatform()->getName()); if (Distribution.empty()) Distribution = AA->getPlatform()->getName(); } Result << " distribution=\"" << Distribution << "\">"; VersionTuple IntroducedInVersion = AA->getIntroduced(); if (!IntroducedInVersion.empty()) { Result << "<IntroducedInVersion>" << IntroducedInVersion.getAsString() << "</IntroducedInVersion>"; } VersionTuple DeprecatedInVersion = AA->getDeprecated(); if (!DeprecatedInVersion.empty()) { Result << "<DeprecatedInVersion>" << DeprecatedInVersion.getAsString() << "</DeprecatedInVersion>"; } VersionTuple RemovedAfterVersion = AA->getObsoleted(); if (!RemovedAfterVersion.empty()) { Result << "<RemovedAfterVersion>" << RemovedAfterVersion.getAsString() << "</RemovedAfterVersion>"; } StringRef DeprecationSummary = AA->getMessage(); if (!DeprecationSummary.empty()) { Result << "<DeprecationSummary>"; appendToResultWithXMLEscaping(DeprecationSummary); Result << "</DeprecationSummary>"; } if (AA->getUnavailable()) Result << "<Unavailable/>"; Result << "</Availability>"; } } { bool StartTagEmitted = false; for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { const Comment *C = Parts.MiscBlocks[i]; if (FirstParagraphIsBrief && C == Parts.FirstParagraph) continue; if (!StartTagEmitted) { Result << "<Discussion>"; StartTagEmitted = true; } visit(C); } if (StartTagEmitted) Result << "</Discussion>"; } Result << RootEndTag; }
void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { FullCommentParts Parts(C); const DeclInfo *DI = C->getDeclInfo(); StringRef RootEndTag; if (DI) { switch (DI->getKind()) { case DeclInfo::OtherKind: RootEndTag = "</Other>"; Result << "<Other"; break; case DeclInfo::FunctionKind: RootEndTag = "</Function>"; Result << "<Function"; switch (DI->TemplateKind) { case DeclInfo::NotTemplate: break; case DeclInfo::Template: Result << " templateKind=\"template\""; break; case DeclInfo::TemplateSpecialization: Result << " templateKind=\"specialization\""; break; case DeclInfo::TemplatePartialSpecialization: llvm_unreachable("partial specializations of functions " "are not allowed in C++"); } if (DI->IsInstanceMethod) Result << " isInstanceMethod=\"1\""; if (DI->IsClassMethod) Result << " isClassMethod=\"1\""; break; case DeclInfo::ClassKind: RootEndTag = "</Class>"; Result << "<Class"; switch (DI->TemplateKind) { case DeclInfo::NotTemplate: break; case DeclInfo::Template: Result << " templateKind=\"template\""; break; case DeclInfo::TemplateSpecialization: Result << " templateKind=\"specialization\""; break; case DeclInfo::TemplatePartialSpecialization: Result << " templateKind=\"partialSpecialization\""; break; } break; case DeclInfo::VariableKind: RootEndTag = "</Variable>"; Result << "<Variable"; break; case DeclInfo::NamespaceKind: RootEndTag = "</Namespace>"; Result << "<Namespace"; break; case DeclInfo::TypedefKind: RootEndTag = "</Typedef>"; Result << "<Typedef"; break; case DeclInfo::EnumKind: RootEndTag = "</Enum>"; Result << "<Enum"; break; } { // Print line and column number. SourceLocation Loc = DI->ThisDecl->getLocation(); std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; if (!FID.isInvalid()) { if (const FileEntry *FE = SM.getFileEntryForID(FID)) { Result << " file=\""; appendToResultWithXMLEscaping(FE->getName()); Result << "\""; } Result << " line=\"" << SM.getLineNumber(FID, FileOffset) << "\" column=\"" << SM.getColumnNumber(FID, FileOffset) << "\""; } } // Finish the root tag. Result << ">"; bool FoundName = false; if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->ThisDecl)) { if (DeclarationName DeclName = ND->getDeclName()) { Result << "<Name>"; std::string Name = DeclName.getAsString(); appendToResultWithXMLEscaping(Name); FoundName = true; Result << "</Name>"; } } if (!FoundName) Result << "<Name><anonymous></Name>"; { // Print USR. SmallString<128> USR; cxcursor::getDeclCursorUSR(DI->ThisDecl, USR); if (!USR.empty()) { Result << "<USR>"; appendToResultWithXMLEscaping(USR); Result << "</USR>"; } } } else { // No DeclInfo -- just emit some root tag and name tag. RootEndTag = "</Other>"; Result << "<Other><Name>unknown</Name>"; } bool FirstParagraphIsBrief = false; if (Parts.Brief) { Result << "<Abstract>"; visit(Parts.Brief); Result << "</Abstract>"; } else if (Parts.FirstParagraph) { Result << "<Abstract>"; visit(Parts.FirstParagraph); Result << "</Abstract>"; FirstParagraphIsBrief = true; } if (Parts.TParams.size() != 0) { Result << "<TemplateParameters>"; for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) visit(Parts.TParams[i]); Result << "</TemplateParameters>"; } if (Parts.Params.size() != 0) { Result << "<Parameters>"; for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) visit(Parts.Params[i]); Result << "</Parameters>"; } if (Parts.Returns) { Result << "<ResultDiscussion>"; visit(Parts.Returns); Result << "</ResultDiscussion>"; } { bool StartTagEmitted = false; for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { const Comment *C = Parts.MiscBlocks[i]; if (FirstParagraphIsBrief && C == Parts.FirstParagraph) continue; if (!StartTagEmitted) { Result << "<Discussion>"; StartTagEmitted = true; } visit(C); } if (StartTagEmitted) Result << "</Discussion>"; } Result << RootEndTag; Result.flush(); }
/// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. const FileEntry *DirectoryLookup::DoFrameworkLookup( StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework) const { FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. size_t SlashPos = Filename.find('/'); if (SlashPos == StringRef::npos) return nullptr; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answers are yes/no and unknown. HeaderSearch::FrameworkCacheEntry &CacheEntry = HS.LookupFrameworkCache(Filename.substr(0, SlashPos)); // If it is known and in some other directory, fail. if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir()) return nullptr; // Otherwise, construct the path to this framework dir. // FrameworkName = "/System/Library/Frameworks/" SmallString<1024> FrameworkName; FrameworkName += getFrameworkDir()->getName(); if (FrameworkName.empty() || FrameworkName.back() != '/') FrameworkName.push_back('/'); // FrameworkName = "/System/Library/Frameworks/Cocoa" StringRef ModuleName(Filename.begin(), SlashPos); FrameworkName += ModuleName; // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" FrameworkName += ".framework/"; // If the cache entry was unresolved, populate it now. if (!CacheEntry.Directory) { HS.IncrementFrameworkLookupCount(); // If the framework dir doesn't exist, we fail. const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str()); if (!Dir) return nullptr; // Otherwise, if it does, remember that this is the right direntry for this // framework. CacheEntry.Directory = getFrameworkDir(); // If this is a user search directory, check if the framework has been // user-specified as a system framework. if (getDirCharacteristic() == SrcMgr::C_User) { SmallString<1024> SystemFrameworkMarker(FrameworkName); SystemFrameworkMarker += ".system_framework"; if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) { CacheEntry.IsUserSpecifiedSystemFramework = true; } } } // Set the 'user-specified system framework' flag. InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework; if (RelativePath) { RelativePath->clear(); RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); } // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" unsigned OrigSize = FrameworkName.size(); FrameworkName += "Headers/"; if (SearchPath) { SearchPath->clear(); // Without trailing '/'. SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); } FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule); if (!FE) { // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" const char *Private = "Private"; FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, Private+strlen(Private)); if (SearchPath) SearchPath->insert(SearchPath->begin()+OrigSize, Private, Private+strlen(Private)); FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule); } // If we found the header and are allowed to suggest a module, do so now. if (FE && SuggestedModule) { // Find the framework in which this header occurs. StringRef FrameworkPath = FE->getDir()->getName(); bool FoundFramework = false; do { // Determine whether this directory exists. const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath); if (!Dir) break; // If this is a framework directory, then we're a subframework of this // framework. if (llvm::sys::path::extension(FrameworkPath) == ".framework") { FoundFramework = true; break; } // Get the parent directory name. FrameworkPath = llvm::sys::path::parent_path(FrameworkPath); if (FrameworkPath.empty()) break; } while (true); if (FoundFramework) { // Find the top-level framework based on this framework. SmallVector<std::string, 4> SubmodulePath; const DirectoryEntry *TopFrameworkDir = ::getTopFrameworkDir(FileMgr, FrameworkPath, SubmodulePath); // Determine the name of the top-level framework. StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName()); // Load this framework module. If that succeeds, find the suggested module // for this header, if any. bool IsSystem = getDirCharacteristic() != SrcMgr::C_User; if (HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) { *SuggestedModule = HS.findModuleForHeader(FE); } } else { *SuggestedModule = HS.findModuleForHeader(FE); } } return FE; }
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C, bool IsBind) const { // Generate an error node. ExplodedNode *N = C.generateSink(State); if (!N) return; // We know that 'location' cannot be non-null. This is what // we call an "explicit" null dereference. if (!BT_null) BT_null.reset(new BuiltinBug("Dereference of null pointer")); SmallString<100> buf; SmallVector<SourceRange, 2> Ranges; // Walk through lvalue casts to get the original expression // that syntactically caused the load. if (const Expr *expr = dyn_cast<Expr>(S)) S = expr->IgnoreParenLValueCasts(); const MemRegion *sourceR = 0; if (IsBind) { if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) { if (BO->isAssignmentOp()) S = BO->getRHS(); } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { assert(DS->isSingleDecl() && "We process decls one by one"); if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) if (const Expr *Init = VD->getAnyInitializer()) S = Init; } } switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { llvm::raw_svector_ostream os(buf); os << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), State.getPtr(), N->getLocationContext()); os << " results in a null pointer dereference"; break; } case Stmt::UnaryOperatorClass: { llvm::raw_svector_ostream os(buf); os << "Dereference of null pointer"; const UnaryOperator *U = cast<UnaryOperator>(S); sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), State.getPtr(), N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast<MemberExpr>(S); if (M->isArrow()) { llvm::raw_svector_ostream os(buf); os << "Access to field '" << M->getMemberNameInfo() << "' results in a dereference of a null pointer"; sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), State.getPtr(), N->getLocationContext(), true); } break; } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { llvm::raw_svector_ostream os(buf); os << "Instance variable access (via '" << VD->getName() << "') results in a null pointer dereference"; } } Ranges.push_back(IV->getSourceRange()); break; } default: break; } BugReport *report = new BugReport(*BT_null, buf.empty() ? BT_null->getDescription() : buf.str(), N); bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N), report); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) report->addRange(*I); if (sourceR) { report->markInteresting(sourceR); report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR))); } C.EmitReport(report); }
/// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPolicy &Policy) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); // Check the type specifier components first. // If decltype(auto) is used, no other type specifiers are permitted. if (TypeSpecType == TST_decltype_auto && (TypeSpecWidth != TSW_unspecified || TypeSpecComplex != TSC_unspecified || TypeSpecSign != TSS_unspecified || TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || TypeQualifiers)) { const unsigned NumLocs = 8; SourceLocation ExtraLocs[NumLocs] = { TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc }; FixItHint Hints[NumLocs]; SourceLocation FirstLoc; for (unsigned I = 0; I != NumLocs; ++I) { if (!ExtraLocs[I].isInvalid()) { if (FirstLoc.isInvalid() || PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I], FirstLoc)) FirstLoc = ExtraLocs[I]; Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]); } } TypeSpecWidth = TSW_unspecified; TypeSpecComplex = TSC_unspecified; TypeSpecSign = TSS_unspecified; TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false; TypeQualifiers = 0; Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined) << Hints[0] << Hints[1] << Hints[2] << Hints[3] << Hints[4] << Hints[5] << Hints[6] << Hints[7]; } // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType, Policy)); } // Only 'short' and 'long long' are valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) && (TypeSpecWidth != TSW_longlong)) Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // vector bool long long requires VSX support. if ((TypeSpecWidth == TSW_longlong) && (!PP.getTargetInfo().hasFeature("vsx")) && (!PP.getTargetInfo().hasFeature("power8-vector"))) Diag(D, TSTLoc, diag::err_invalid_vector_long_long_decl_spec); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } else if (TypeSpecType == TST_double) { // vector long double and vector long long double are never allowed. // vector double is OK for Power7 and later. if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong) Diag(D, TSWLoc, diag::err_invalid_vector_long_double_decl_spec); else if (!PP.getTargetInfo().hasFeature("vsx")) Diag(D, TSTLoc, diag::err_invalid_vector_double_decl_spec); } else if (TypeSpecWidth == TSW_long) { Diag(D, TSWLoc, diag::warn_vector_long_decl_spec_combination) << getSpecifierName((TST)TypeSpecType, Policy); } if (TypeAltiVecPixel) { //TODO: perform validation TypeSpecType = TST_int; TypeSpecSign = TSS_unsigned; TypeSpecWidth = TSW_short; TypeSpecOwned = false; } } // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType, Policy); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. if (!PP.getLangOpts().CPlusPlus) Diag(D, TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecComplex = TSC_unspecified; } } // C11 6.7.1/3, C++11 [dcl.stc]p1, GNU TLS: __thread, thread_local and // _Thread_local can only appear with the 'static' and 'extern' storage class // specifiers. We also allow __private_extern__ as an extension. if (ThreadStorageClassSpec != TSCS_unspecified) { switch (StorageClassSpec) { case SCS_unspecified: case SCS_extern: case SCS_private_extern: case SCS_static: break; default: if (PP.getSourceManager().isBeforeInTranslationUnit( getThreadStorageClassSpecLoc(), getStorageClassSpecLoc())) Diag(D, getStorageClassSpecLoc(), diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getThreadStorageClassSpec()) << SourceRange(getThreadStorageClassSpecLoc()); else Diag(D, getThreadStorageClassSpecLoc(), diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getStorageClassSpec()) << SourceRange(getStorageClassSpecLoc()); // Discard the thread storage class specifier to recover. ThreadStorageClassSpec = TSCS_unspecified; ThreadStorageClassSpecLoc = SourceLocation(); } } // If no type specifier was provided and we're parsing a language where // the type specifier is not optional, but we got 'auto' as a storage // class specifier, then assume this is an attempt to use C++0x's 'auto' // type specifier. if (PP.getLangOpts().CPlusPlus && TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { TypeSpecType = TST_auto; StorageClassSpec = SCS_unspecified; TSTLoc = TSTNameLoc = StorageClassSpecLoc; StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class // specifier in a pre-C++11 dialect of C++. if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) Diag(D, TSTLoc, diag::ext_auto_type_specifier); if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) << FixItHint::CreateRemoval(StorageClassSpecLoc); if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32) Diag(D, TSTLoc, diag::warn_cxx98_compat_unicode_type) << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t"); if (Constexpr_specified) Diag(D, ConstexprLoc, diag::warn_cxx98_compat_constexpr); // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && (getStorageClassSpec() || getThreadStorageClassSpec())) { SmallString<32> SpecName; SourceLocation SCLoc; FixItHint StorageHint, ThreadHint; if (DeclSpec::SCS SC = getStorageClassSpec()) { SpecName = getSpecifierName(SC); SCLoc = getStorageClassSpecLoc(); StorageHint = FixItHint::CreateRemoval(SCLoc); } if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) { if (!SpecName.empty()) SpecName += " "; SpecName += getSpecifierName(TSC); SCLoc = getThreadStorageClassSpecLoc(); ThreadHint = FixItHint::CreateRemoval(SCLoc); } Diag(D, SCLoc, diag::err_friend_decl_spec) << SpecName << StorageHint << ThreadHint; ClearStorageClassSpecs(); } // C++11 [dcl.fct.spec]p5: // The virtual specifier shall be used only in the initial // declaration of a non-static class member function; // C++11 [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of // a constructor or conversion function within its class // definition; if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) { StringRef Keyword; SourceLocation SCLoc; if (isVirtualSpecified()) { Keyword = "virtual"; SCLoc = getVirtualSpecLoc(); } else { Keyword = "explicit"; SCLoc = getExplicitSpecLoc(); } FixItHint Hint = FixItHint::CreateRemoval(SCLoc); Diag(D, SCLoc, diag::err_friend_decl_spec) << Keyword << Hint; FS_virtual_specified = FS_explicit_specified = false; FS_virtualLoc = FS_explicitLoc = SourceLocation(); } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }
void init() { sys::fs::createTemporaryFile("temp", "history", HistPath); ASSERT_FALSE(HistPath.empty()); LE = new LineEditor("test", HistPath); }