/// ApplyQAOverride - Apply a list of edits to the input argument lists. /// /// The input string is a space separate list of edits to perform, /// they are applied in order to the input argument lists. Edits /// should be one of the following forms: /// /// '#': Silence information about the changes to the command line arguments. /// /// '^': Add FOO as a new argument at the beginning of the command line. /// /// '+': Add FOO as a new argument at the end of the command line. /// /// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command /// line. /// /// 'xOPTION': Removes all instances of the literal argument OPTION. /// /// 'XOPTION': Removes all instances of the literal argument OPTION, /// and the following argument. /// /// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox' /// at the end of the command line. /// /// \param OS - The stream to write edit information to. /// \param Args - The vector of command line arguments. /// \param Edit - The override command to perform. /// \param SavedStrings - Set to use for storing string representations. static void ApplyOneQAOverride(raw_ostream &OS, SmallVectorImpl<const char*> &Args, StringRef Edit, std::set<std::string> &SavedStrings) { // This does not need to be efficient. if (Edit[0] == '^') { const char *Str = SaveStringInSet(SavedStrings, Edit.substr(1)); OS << "### Adding argument " << Str << " at beginning\n"; Args.insert(Args.begin() + 1, Str); } else if (Edit[0] == '+') { const char *Str = SaveStringInSet(SavedStrings, Edit.substr(1)); OS << "### Adding argument " << Str << " at end\n"; Args.push_back(Str); } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") && Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) { StringRef MatchPattern = Edit.substr(2).split('/').first; StringRef ReplPattern = Edit.substr(2).split('/').second; ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1); for (unsigned i = 1, e = Args.size(); i != e; ++i) { std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]); if (Repl != Args[i]) { OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n"; Args[i] = SaveStringInSet(SavedStrings, Repl); } } } else if (Edit[0] == 'x' || Edit[0] == 'X') { std::string Option = Edit.substr(1, std::string::npos); for (unsigned i = 1; i < Args.size();) { if (Option == Args[i]) { OS << "### Deleting argument " << Args[i] << '\n'; Args.erase(Args.begin() + i); if (Edit[0] == 'X') { if (i < Args.size()) { OS << "### Deleting argument " << Args[i] << '\n'; Args.erase(Args.begin() + i); } else OS << "### Invalid X edit, end of command line!\n"; } } else ++i; } } else if (Edit[0] == 'O') { for (unsigned i = 1; i < Args.size();) { const char *A = Args[i]; if (A[0] == '-' && A[1] == 'O' && (A[2] == '\0' || (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' || ('0' <= A[2] && A[2] <= '9'))))) { OS << "### Deleting argument " << Args[i] << '\n'; Args.erase(Args.begin() + i); } else ++i; } OS << "### Adding argument " << Edit << " at end\n"; Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit.str())); } else { OS << "### Unrecognized edit: " << Edit << "\n"; } }
static void dumpCXXData(const ObjectFile *Obj) { struct CompleteObjectLocator { StringRef Symbols[2]; ArrayRef<little32_t> Data; }; struct ClassHierarchyDescriptor { StringRef Symbols[1]; ArrayRef<little32_t> Data; }; struct BaseClassDescriptor { StringRef Symbols[2]; ArrayRef<little32_t> Data; }; struct TypeDescriptor { StringRef Symbols[1]; uint64_t AlwaysZero; StringRef MangledName; }; struct ThrowInfo { uint32_t Flags; }; struct CatchableTypeArray { uint32_t NumEntries; }; struct CatchableType { uint32_t Flags; uint32_t NonVirtualBaseAdjustmentOffset; int32_t VirtualBasePointerOffset; uint32_t VirtualBaseAdjustmentOffset; uint32_t Size; StringRef Symbols[2]; }; std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries; std::map<std::pair<StringRef, uint64_t>, StringRef> TIEntries; std::map<std::pair<StringRef, uint64_t>, StringRef> CTAEntries; std::map<StringRef, ArrayRef<little32_t>> VBTables; std::map<StringRef, CompleteObjectLocator> COLs; std::map<StringRef, ClassHierarchyDescriptor> CHDs; std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries; std::map<StringRef, BaseClassDescriptor> BCDs; std::map<StringRef, TypeDescriptor> TDs; std::map<StringRef, ThrowInfo> TIs; std::map<StringRef, CatchableTypeArray> CTAs; std::map<StringRef, CatchableType> CTs; std::map<std::pair<StringRef, uint64_t>, StringRef> VTableSymEntries; std::map<std::pair<StringRef, uint64_t>, int64_t> VTableDataEntries; std::map<std::pair<StringRef, uint64_t>, StringRef> VTTEntries; std::map<StringRef, StringRef> TINames; SectionRelocMap.clear(); for (const SectionRef &Section : Obj->sections()) { section_iterator Sec2 = Section.getRelocatedSection(); if (Sec2 != Obj->section_end()) SectionRelocMap[*Sec2].push_back(Section); } uint8_t BytesInAddress = Obj->getBytesInAddress(); std::vector<std::pair<SymbolRef, uint64_t>> SymAddr = object::computeSymbolSizes(*Obj); for (auto &P : SymAddr) { object::SymbolRef Sym = P.first; uint64_t SymSize = P.second; ErrorOr<StringRef> SymNameOrErr = Sym.getName(); error(SymNameOrErr.getError()); StringRef SymName = *SymNameOrErr; ErrorOr<object::section_iterator> SecIOrErr = Sym.getSection(); error(SecIOrErr.getError()); object::section_iterator SecI = *SecIOrErr; // Skip external symbols. if (SecI == Obj->section_end()) continue; const SectionRef &Sec = *SecI; // Skip virtual or BSS sections. if (Sec.isBSS() || Sec.isVirtual()) continue; StringRef SecContents; error(Sec.getContents(SecContents)); ErrorOr<uint64_t> SymAddressOrErr = Sym.getAddress(); error(SymAddressOrErr.getError()); uint64_t SymAddress = *SymAddressOrErr; uint64_t SecAddress = Sec.getAddress(); uint64_t SecSize = Sec.getSize(); uint64_t SymOffset = SymAddress - SecAddress; StringRef SymContents = SecContents.substr(SymOffset, SymSize); // VFTables in the MS-ABI start with '??_7' and are contained within their // own COMDAT section. We then determine the contents of the VFTable by // looking at each relocation in the section. if (SymName.startswith("??_7")) { // Each relocation either names a virtual method or a thunk. We note the // offset into the section and the symbol used for the relocation. collectRelocationOffsets(Obj, Sec, SecAddress, SecAddress, SecSize, SymName, VFTableEntries); } // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit // offsets of virtual bases. else if (SymName.startswith("??_8")) { ArrayRef<little32_t> VBTableData( reinterpret_cast<const little32_t *>(SymContents.data()), SymContents.size() / sizeof(little32_t)); VBTables[SymName] = VBTableData; } // Complete object locators in the MS-ABI start with '??_R4' else if (SymName.startswith("??_R4")) { CompleteObjectLocator COL; COL.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()), 3); StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); COLs[SymName] = COL; } // Class hierarchy descriptors in the MS-ABI start with '??_R3' else if (SymName.startswith("??_R3")) { ClassHierarchyDescriptor CHD; CHD.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()), 3); StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); CHDs[SymName] = CHD; } // Class hierarchy descriptors in the MS-ABI start with '??_R2' else if (SymName.startswith("??_R2")) { // Each relocation names a base class descriptor. We note the offset into // the section and the symbol used for the relocation. collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, BCAEntries); } // Base class descriptors in the MS-ABI start with '??_R1' else if (SymName.startswith("??_R1")) { BaseClassDescriptor BCD; BCD.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5); StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); BCDs[SymName] = BCD; } // Type descriptors in the MS-ABI start with '??_R0' else if (SymName.startswith("??_R0")) { const char *DataPtr = SymContents.drop_front(BytesInAddress).data(); TypeDescriptor TD; if (BytesInAddress == 8) TD.AlwaysZero = *reinterpret_cast<const little64_t *>(DataPtr); else TD.AlwaysZero = *reinterpret_cast<const little32_t *>(DataPtr); TD.MangledName = SymContents.drop_front(BytesInAddress * 2); StringRef *I = std::begin(TD.Symbols), *E = std::end(TD.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); TDs[SymName] = TD; } // Throw descriptors in the MS-ABI start with '_TI' else if (SymName.startswith("_TI") || SymName.startswith("__TI")) { ThrowInfo TI; TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data()); collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, TIEntries); TIs[SymName] = TI; } // Catchable type arrays in the MS-ABI start with _CTA or __CTA. else if (SymName.startswith("_CTA") || SymName.startswith("__CTA")) { CatchableTypeArray CTA; CTA.NumEntries = *reinterpret_cast<const little32_t *>(SymContents.data()); collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, CTAEntries); CTAs[SymName] = CTA; } // Catchable types in the MS-ABI start with _CT or __CT. else if (SymName.startswith("_CT") || SymName.startswith("__CT")) { const little32_t *DataPtr = reinterpret_cast<const little32_t *>(SymContents.data()); CatchableType CT; CT.Flags = DataPtr[0]; CT.NonVirtualBaseAdjustmentOffset = DataPtr[2]; CT.VirtualBasePointerOffset = DataPtr[3]; CT.VirtualBaseAdjustmentOffset = DataPtr[4]; CT.Size = DataPtr[5]; StringRef *I = std::begin(CT.Symbols), *E = std::end(CT.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); CTs[SymName] = CT; } // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'. else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) { collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, VTTEntries); } // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'. else if (SymName.startswith("_ZTS") || SymName.startswith("__ZTS")) { TINames[SymName] = SymContents.slice(0, SymContents.find('\0')); } // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'. else if (SymName.startswith("_ZTV") || SymName.startswith("__ZTV")) { collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, VTableSymEntries); for (uint64_t SymOffI = 0; SymOffI < SymSize; SymOffI += BytesInAddress) { auto Key = std::make_pair(SymName, SymOffI); if (VTableSymEntries.count(Key)) continue; const char *DataPtr = SymContents.substr(SymOffI, BytesInAddress).data(); int64_t VData; if (BytesInAddress == 8) VData = *reinterpret_cast<const little64_t *>(DataPtr); else VData = *reinterpret_cast<const little32_t *>(DataPtr); VTableDataEntries[Key] = VData; } } // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'. else if (SymName.startswith("_ZTI") || SymName.startswith("__ZTI")) { // FIXME: Do something with these! } } for (const auto &VFTableEntry : VFTableEntries) { StringRef VFTableName = VFTableEntry.first.first; uint64_t Offset = VFTableEntry.first.second; StringRef SymName = VFTableEntry.second; outs() << VFTableName << '[' << Offset << "]: " << SymName << '\n'; } for (const auto &VBTable : VBTables) { StringRef VBTableName = VBTable.first; uint32_t Idx = 0; for (little32_t Offset : VBTable.second) { outs() << VBTableName << '[' << Idx << "]: " << Offset << '\n'; Idx += sizeof(Offset); } } for (const auto &COLPair : COLs) { StringRef COLName = COLPair.first; const CompleteObjectLocator &COL = COLPair.second; outs() << COLName << "[IsImageRelative]: " << COL.Data[0] << '\n'; outs() << COLName << "[OffsetToTop]: " << COL.Data[1] << '\n'; outs() << COLName << "[VFPtrOffset]: " << COL.Data[2] << '\n'; outs() << COLName << "[TypeDescriptor]: " << COL.Symbols[0] << '\n'; outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1] << '\n'; } for (const auto &CHDPair : CHDs) { StringRef CHDName = CHDPair.first; const ClassHierarchyDescriptor &CHD = CHDPair.second; outs() << CHDName << "[AlwaysZero]: " << CHD.Data[0] << '\n'; outs() << CHDName << "[Flags]: " << CHD.Data[1] << '\n'; outs() << CHDName << "[NumClasses]: " << CHD.Data[2] << '\n'; outs() << CHDName << "[BaseClassArray]: " << CHD.Symbols[0] << '\n'; } for (const auto &BCAEntry : BCAEntries) { StringRef BCAName = BCAEntry.first.first; uint64_t Offset = BCAEntry.first.second; StringRef SymName = BCAEntry.second; outs() << BCAName << '[' << Offset << "]: " << SymName << '\n'; } for (const auto &BCDPair : BCDs) { StringRef BCDName = BCDPair.first; const BaseClassDescriptor &BCD = BCDPair.second; outs() << BCDName << "[TypeDescriptor]: " << BCD.Symbols[0] << '\n'; outs() << BCDName << "[NumBases]: " << BCD.Data[0] << '\n'; outs() << BCDName << "[OffsetInVBase]: " << BCD.Data[1] << '\n'; outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n'; outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n'; outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n'; outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] << '\n'; } for (const auto &TDPair : TDs) { StringRef TDName = TDPair.first; const TypeDescriptor &TD = TDPair.second; outs() << TDName << "[VFPtr]: " << TD.Symbols[0] << '\n'; outs() << TDName << "[AlwaysZero]: " << TD.AlwaysZero << '\n'; outs() << TDName << "[MangledName]: "; outs().write_escaped(TD.MangledName.rtrim(StringRef("\0", 1)), /*UseHexEscapes=*/true) << '\n'; } for (const auto &TIPair : TIs) { StringRef TIName = TIPair.first; const ThrowInfo &TI = TIPair.second; auto dumpThrowInfoFlag = [&](const char *Name, uint32_t Flag) { outs() << TIName << "[Flags." << Name << "]: " << (TI.Flags & Flag ? "true" : "false") << '\n'; }; auto dumpThrowInfoSymbol = [&](const char *Name, int Offset) { outs() << TIName << '[' << Name << "]: "; auto Entry = TIEntries.find(std::make_pair(TIName, Offset)); outs() << (Entry == TIEntries.end() ? "null" : Entry->second) << '\n'; }; outs() << TIName << "[Flags]: " << TI.Flags << '\n'; dumpThrowInfoFlag("Const", 1); dumpThrowInfoFlag("Volatile", 2); dumpThrowInfoSymbol("CleanupFn", 4); dumpThrowInfoSymbol("ForwardCompat", 8); dumpThrowInfoSymbol("CatchableTypeArray", 12); } for (const auto &CTAPair : CTAs) { StringRef CTAName = CTAPair.first; const CatchableTypeArray &CTA = CTAPair.second; outs() << CTAName << "[NumEntries]: " << CTA.NumEntries << '\n'; unsigned Idx = 0; for (auto I = CTAEntries.lower_bound(std::make_pair(CTAName, 0)), E = CTAEntries.upper_bound(std::make_pair(CTAName, UINT64_MAX)); I != E; ++I) outs() << CTAName << '[' << Idx++ << "]: " << I->second << '\n'; } for (const auto &CTPair : CTs) { StringRef CTName = CTPair.first; const CatchableType &CT = CTPair.second; auto dumpCatchableTypeFlag = [&](const char *Name, uint32_t Flag) { outs() << CTName << "[Flags." << Name << "]: " << (CT.Flags & Flag ? "true" : "false") << '\n'; }; outs() << CTName << "[Flags]: " << CT.Flags << '\n'; dumpCatchableTypeFlag("ScalarType", 1); dumpCatchableTypeFlag("VirtualInheritance", 4); outs() << CTName << "[TypeDescriptor]: " << CT.Symbols[0] << '\n'; outs() << CTName << "[NonVirtualBaseAdjustmentOffset]: " << CT.NonVirtualBaseAdjustmentOffset << '\n'; outs() << CTName << "[VirtualBasePointerOffset]: " << CT.VirtualBasePointerOffset << '\n'; outs() << CTName << "[VirtualBaseAdjustmentOffset]: " << CT.VirtualBaseAdjustmentOffset << '\n'; outs() << CTName << "[Size]: " << CT.Size << '\n'; outs() << CTName << "[CopyCtor]: " << (CT.Symbols[1].empty() ? "null" : CT.Symbols[1]) << '\n'; } for (const auto &VTTPair : VTTEntries) { StringRef VTTName = VTTPair.first.first; uint64_t VTTOffset = VTTPair.first.second; StringRef VTTEntry = VTTPair.second; outs() << VTTName << '[' << VTTOffset << "]: " << VTTEntry << '\n'; } for (const auto &TIPair : TINames) { StringRef TIName = TIPair.first; outs() << TIName << ": " << TIPair.second << '\n'; } auto VTableSymI = VTableSymEntries.begin(); auto VTableSymE = VTableSymEntries.end(); auto VTableDataI = VTableDataEntries.begin(); auto VTableDataE = VTableDataEntries.end(); for (;;) { bool SymDone = VTableSymI == VTableSymE; bool DataDone = VTableDataI == VTableDataE; if (SymDone && DataDone) break; if (!SymDone && (DataDone || VTableSymI->first < VTableDataI->first)) { StringRef VTableName = VTableSymI->first.first; uint64_t Offset = VTableSymI->first.second; StringRef VTableEntry = VTableSymI->second; outs() << VTableName << '[' << Offset << "]: "; outs() << VTableEntry; outs() << '\n'; ++VTableSymI; continue; } if (!DataDone && (SymDone || VTableDataI->first < VTableSymI->first)) { StringRef VTableName = VTableDataI->first.first; uint64_t Offset = VTableDataI->first.second; int64_t VTableEntry = VTableDataI->second; outs() << VTableName << '[' << Offset << "]: "; outs() << VTableEntry; outs() << '\n'; ++VTableDataI; continue; } } }
int main(int argc, char **argv) { std::vector<StringRef> Components; bool PrintLibs = false, PrintLibNames = false, PrintLibFiles = false; bool HasAnyOption = false; // llvm-config is designed to support being run both from a development tree // and from an installed path. We try and auto-detect which case we are in so // that we can report the correct information when run from a development // tree. bool IsInDevelopmentTree, DevelopmentTreeLayoutIsCMakeStyle; llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0]).str()); std::string CurrentExecPrefix; std::string ActiveObjRoot; // Create an absolute path, and pop up one directory (we expect to be inside a // bin dir). sys::fs::make_absolute(CurrentPath); CurrentExecPrefix = sys::path::parent_path( sys::path::parent_path(CurrentPath)).str(); // Check to see if we are inside a development tree by comparing to possible // locations (prefix style or CMake style). This could be wrong in the face of // symbolic links, but is good enough. if (CurrentExecPrefix == std::string(LLVM_OBJ_ROOT) + "/" + LLVM_BUILDMODE) { IsInDevelopmentTree = true; DevelopmentTreeLayoutIsCMakeStyle = false; // If we are in a development tree, then check if we are in a BuildTools // directory. This indicates we are built for the build triple, but we // always want to provide information for the host triple. if (sys::path::filename(LLVM_OBJ_ROOT) == "BuildTools") { ActiveObjRoot = sys::path::parent_path(LLVM_OBJ_ROOT); } else { ActiveObjRoot = LLVM_OBJ_ROOT; } } else if (CurrentExecPrefix == std::string(LLVM_OBJ_ROOT) + "/bin") { IsInDevelopmentTree = true; DevelopmentTreeLayoutIsCMakeStyle = true; ActiveObjRoot = LLVM_OBJ_ROOT; } else { IsInDevelopmentTree = false; } // Compute various directory locations based on the derived location // information. std::string ActivePrefix, ActiveBinDir, ActiveIncludeDir, ActiveLibDir; std::string ActiveIncludeOption; if (IsInDevelopmentTree) { ActivePrefix = CurrentExecPrefix; // CMake organizes the products differently than a normal prefix style // layout. if (DevelopmentTreeLayoutIsCMakeStyle) { ActiveIncludeDir = ActiveObjRoot + "/include"; ActiveBinDir = ActiveObjRoot + "/bin/" + LLVM_BUILDMODE; ActiveLibDir = ActiveObjRoot + "/lib/" + LLVM_BUILDMODE; } else { ActiveIncludeDir = ActiveObjRoot + "/include"; ActiveBinDir = ActiveObjRoot + "/" + LLVM_BUILDMODE + "/bin"; ActiveLibDir = ActiveObjRoot + "/" + LLVM_BUILDMODE + "/lib"; } // We need to include files from both the source and object trees. ActiveIncludeOption = ("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include"); } else { ActivePrefix = CurrentExecPrefix; ActiveIncludeDir = ActivePrefix + "/include"; ActiveBinDir = ActivePrefix + "/bin"; ActiveLibDir = ActivePrefix + "/lib"; ActiveIncludeOption = "-I" + ActiveIncludeDir; } raw_ostream &OS = outs(); for (int i = 1; i != argc; ++i) { StringRef Arg = argv[i]; if (Arg.startswith("-")) { HasAnyOption = true; if (Arg == "--version") { OS << PACKAGE_VERSION << '\n'; } else if (Arg == "--prefix") { OS << ActivePrefix << '\n'; } else if (Arg == "--bindir") { OS << ActiveBinDir << '\n'; } else if (Arg == "--includedir") { OS << ActiveIncludeDir << '\n'; } else if (Arg == "--libdir") { OS << ActiveLibDir << '\n'; } else if (Arg == "--cppflags") { OS << ActiveIncludeOption << ' ' << LLVM_CPPFLAGS << '\n'; } else if (Arg == "--cflags") { OS << ActiveIncludeOption << ' ' << LLVM_CFLAGS << '\n'; } else if (Arg == "--cxxflags") { OS << ActiveIncludeOption << ' ' << LLVM_CXXFLAGS << '\n'; } else if (Arg == "--ldflags") { OS << "-L" << ActiveLibDir << ' ' << LLVM_LDFLAGS << ' ' << LLVM_SYSTEM_LIBS << '\n'; } else if (Arg == "--libs") { PrintLibs = true; } else if (Arg == "--libnames") { PrintLibNames = true; } else if (Arg == "--libfiles") { PrintLibFiles = true; } else if (Arg == "--components") { for (unsigned j = 0; j != array_lengthof(AvailableComponents); ++j) { OS << ' '; OS << AvailableComponents[j].Name; } OS << '\n'; } else if (Arg == "--targets-built") { bool First = true; for (TargetRegistry::iterator I = TargetRegistry::begin(), E = TargetRegistry::end(); I != E; First = false, ++I) { if (!First) OS << ' '; OS << I->getName(); } OS << '\n'; } else if (Arg == "--host-target") { OS << LLVM_DEFAULT_TARGET_TRIPLE << '\n'; } else if (Arg == "--build-mode") { OS << LLVM_BUILDMODE << '\n'; } else if (Arg == "--obj-root") { OS << LLVM_OBJ_ROOT << '\n'; } else if (Arg == "--src-root") { OS << LLVM_SRC_ROOT << '\n'; } else { usage(); } } else { Components.push_back(Arg); } } if (!HasAnyOption) usage(); if (PrintLibs || PrintLibNames || PrintLibFiles) { // Construct the list of all the required libraries. std::vector<StringRef> RequiredLibs; ComputeLibsForComponents(Components, RequiredLibs); for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { StringRef Lib = RequiredLibs[i]; if (i) OS << ' '; if (PrintLibNames) { OS << Lib; } else if (PrintLibFiles) { OS << ActiveLibDir << '/' << Lib; } else if (PrintLibs) { // If this is a typical library name, include it using -l. if (Lib.startswith("lib") && Lib.endswith(".a")) { OS << "-l" << Lib.slice(3, Lib.size()-2); continue; } // Otherwise, print the full path. OS << ActiveLibDir << '/' << Lib; } } OS << '\n'; } else if (!Components.empty()) { errs() << "llvm-config: error: components given, but unused\n\n"; usage(); } return 0; }
llvm::StringRef swift::ide::getTrimmedTextForLine(unsigned LineIndex, StringRef Text) { size_t LineOffset = getOffsetOfTrimmedLine(LineIndex, Text); size_t LineEnd = Text.find_first_of("\r\n", LineOffset); return Text.slice(LineOffset, LineEnd); }
bool X86ATTAsmParser:: ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl<MCParsedAsmOperand*> &Operands) { StringRef PatchedName = Name; // FIXME: Hack to recognize setneb as setne. if (PatchedName.startswith("set") && PatchedName.endswith("b") && PatchedName != "setb" && PatchedName != "setnb") PatchedName = PatchedName.substr(0, Name.size()-1); // FIXME: Hack to recognize cmp<comparison code>{ss,sd,ps,pd}. const MCExpr *ExtraImmOp = 0; if ((PatchedName.startswith("cmp") || PatchedName.startswith("vcmp")) && (PatchedName.endswith("ss") || PatchedName.endswith("sd") || PatchedName.endswith("ps") || PatchedName.endswith("pd"))) { bool IsVCMP = PatchedName.startswith("vcmp"); unsigned SSECCIdx = IsVCMP ? 4 : 3; unsigned SSEComparisonCode = StringSwitch<unsigned>( PatchedName.slice(SSECCIdx, PatchedName.size() - 2)) .Case("eq", 0) .Case("lt", 1) .Case("le", 2) .Case("unord", 3) .Case("neq", 4) .Case("nlt", 5) .Case("nle", 6) .Case("ord", 7) .Case("eq_uq", 8) .Case("nge", 9) .Case("ngt", 0x0A) .Case("false", 0x0B) .Case("neq_oq", 0x0C) .Case("ge", 0x0D) .Case("gt", 0x0E) .Case("true", 0x0F) .Case("eq_os", 0x10) .Case("lt_oq", 0x11) .Case("le_oq", 0x12) .Case("unord_s", 0x13) .Case("neq_us", 0x14) .Case("nlt_uq", 0x15) .Case("nle_uq", 0x16) .Case("ord_s", 0x17) .Case("eq_us", 0x18) .Case("nge_uq", 0x19) .Case("ngt_uq", 0x1A) .Case("false_os", 0x1B) .Case("neq_os", 0x1C) .Case("ge_oq", 0x1D) .Case("gt_oq", 0x1E) .Case("true_us", 0x1F) .Default(~0U); if (SSEComparisonCode != ~0U) { ExtraImmOp = MCConstantExpr::Create(SSEComparisonCode, getParser().getContext()); if (PatchedName.endswith("ss")) { PatchedName = IsVCMP ? "vcmpss" : "cmpss"; } else if (PatchedName.endswith("sd")) { PatchedName = IsVCMP ? "vcmpsd" : "cmpsd"; } else if (PatchedName.endswith("ps")) { PatchedName = IsVCMP ? "vcmpps" : "cmpps"; } else { assert(PatchedName.endswith("pd") && "Unexpected mnemonic!"); PatchedName = IsVCMP ? "vcmppd" : "cmppd"; } } } // FIXME: Hack to recognize vpclmul<src1_quadword, src2_quadword>dq if (PatchedName.startswith("vpclmul")) { unsigned CLMULQuadWordSelect = StringSwitch<unsigned>( PatchedName.slice(7, PatchedName.size() - 2)) .Case("lqlq", 0x00) // src1[63:0], src2[63:0] .Case("hqlq", 0x01) // src1[127:64], src2[63:0] .Case("lqhq", 0x10) // src1[63:0], src2[127:64] .Case("hqhq", 0x11) // src1[127:64], src2[127:64] .Default(~0U); if (CLMULQuadWordSelect != ~0U) { ExtraImmOp = MCConstantExpr::Create(CLMULQuadWordSelect, getParser().getContext()); assert(PatchedName.endswith("dq") && "Unexpected mnemonic!"); PatchedName = "vpclmulqdq"; } } Operands.push_back(X86Operand::CreateToken(PatchedName, NameLoc)); if (ExtraImmOp) Operands.push_back(X86Operand::CreateImm(ExtraImmOp, NameLoc, NameLoc)); // Determine whether this is an instruction prefix. bool isPrefix = Name == "lock" || Name == "rep" || Name == "repe" || Name == "repz" || Name == "repne" || Name == "repnz" || Name == "rex64" || Name == "data16"; // This does the actual operand parsing. Don't parse any more if we have a // prefix juxtaposed with an operation like "lock incl 4(%rax)", because we // just want to parse the "lock" as the first instruction and the "incl" as // the next one. if (getLexer().isNot(AsmToken::EndOfStatement) && !isPrefix) { // Parse '*' modifier. if (getLexer().is(AsmToken::Star)) { SMLoc Loc = Parser.getTok().getLoc(); Operands.push_back(X86Operand::CreateToken("*", Loc)); Parser.Lex(); // Eat the star. } // Read the first operand. if (X86Operand *Op = ParseOperand()) Operands.push_back(Op); else { Parser.EatToEndOfStatement(); return true; } while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. // Parse and remember the operand. if (X86Operand *Op = ParseOperand()) Operands.push_back(Op); else { Parser.EatToEndOfStatement(); return true; } } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); Parser.EatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } } if (getLexer().is(AsmToken::EndOfStatement)) Parser.Lex(); // Consume the EndOfStatement else if (isPrefix && getLexer().is(AsmToken::Slash)) Parser.Lex(); // Consume the prefix separator Slash // This is a terrible hack to handle "out[bwl]? %al, (%dx)" -> // "outb %al, %dx". Out doesn't take a memory form, but this is a widely // documented form in various unofficial manuals, so a lot of code uses it. if ((Name == "outb" || Name == "outw" || Name == "outl" || Name == "out") && Operands.size() == 3) { X86Operand &Op = *(X86Operand*)Operands.back(); if (Op.isMem() && Op.Mem.SegReg == 0 && isa<MCConstantExpr>(Op.Mem.Disp) && cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 && Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) { SMLoc Loc = Op.getEndLoc(); Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc); delete &Op; } } // FIXME: Hack to handle recognize s{hr,ar,hl} $1, <op>. Canonicalize to // "shift <op>". if ((Name.startswith("shr") || Name.startswith("sar") || Name.startswith("shl") || Name.startswith("sal") || Name.startswith("rcl") || Name.startswith("rcr") || Name.startswith("rol") || Name.startswith("ror")) && Operands.size() == 3) { X86Operand *Op1 = static_cast<X86Operand*>(Operands[1]); if (Op1->isImm() && isa<MCConstantExpr>(Op1->getImm()) && cast<MCConstantExpr>(Op1->getImm())->getValue() == 1) { delete Operands[1]; Operands.erase(Operands.begin() + 1); } } return false; }
std::string Regex::sub(StringRef Repl, StringRef String, std::string *Error) { SmallVector<StringRef, 8> Matches; // Reset error, if given. if (Error && !Error->empty()) *Error = ""; // Return the input if there was no match. if (!match(String, &Matches)) return String; // Otherwise splice in the replacement string, starting with the prefix before // the match. std::string Res(String.begin(), Matches[0].begin()); // Then the replacement string, honoring possible substitutions. while (!Repl.empty()) { // Skip to the next escape. std::pair<StringRef, StringRef> Split = Repl.split('\\'); // Add the skipped substring. Res += Split.first; // Check for terminimation and trailing backslash. if (Split.second.empty()) { if (Repl.size() != Split.first.size() && Error && Error->empty()) *Error = "replacement string contained trailing backslash"; break; } // Otherwise update the replacement string and interpret escapes. Repl = Split.second; // FIXME: We should have a StringExtras function for mapping C99 escapes. switch (Repl[0]) { // Treat all unrecognized characters as self-quoting. default: Res += Repl[0]; Repl = Repl.substr(1); break; // Single character escapes. case 't': Res += '\t'; Repl = Repl.substr(1); break; case 'n': Res += '\n'; Repl = Repl.substr(1); break; // Decimal escapes are backreferences. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { // Extract the backreference number. StringRef Ref = Repl.slice(0, Repl.find_first_not_of("0123456789")); Repl = Repl.substr(Ref.size()); unsigned RefValue; if (!Ref.getAsInteger(10, RefValue) && RefValue < Matches.size()) Res += Matches[RefValue]; else if (Error && Error->empty()) *Error = ("invalid backreference string '" + Twine(Ref) + "'").str(); break; } } } // And finally the suffix. Res += StringRef(Matches[0].end(), String.end() - Matches[0].end()); return Res; }
bool Punycode::decodePunycode(StringRef InputPunycode, std::vector<uint32_t> &OutCodePoints) { OutCodePoints.clear(); OutCodePoints.reserve(InputPunycode.size()); // -- Build the decoded string as UTF32 first because we need random access. uint32_t n = initial_n; int i = 0; int bias = initial_bias; /// let output = an empty string indexed from 0 // consume all code points before the last delimiter (if there is one) // and copy them to output, size_t lastDelimiter = InputPunycode.find_last_of(delimiter); if (lastDelimiter != StringRef::npos) { for (char c : InputPunycode.slice(0, lastDelimiter)) { // fail on any non-basic code point if (static_cast<unsigned char>(c) > 0x7f) return true; OutCodePoints.push_back(c); } // if more than zero code points were consumed then consume one more // (which will be the last delimiter) InputPunycode = InputPunycode.slice(lastDelimiter + 1, InputPunycode.size()); } while (!InputPunycode.empty()) { int oldi = i; int w = 1; for (int k = base; ; k += base) { // consume a code point, or fail if there was none to consume if (InputPunycode.empty()) return true; char codePoint = InputPunycode.front(); InputPunycode = InputPunycode.slice(1, InputPunycode.size()); // let digit = the code point's digit-value, fail if it has none int digit = digit_index(codePoint); if (digit < 0) return true; i = i + digit * w; int t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; if (digit < t) break; w = w * (base - t); } bias = adapt(i - oldi, OutCodePoints.size() + 1, oldi == 0); n = n + i / (OutCodePoints.size() + 1); i = i % (OutCodePoints.size() + 1); // if n is a basic code point then fail if (n < 0x80) return true; // insert n into output at position i OutCodePoints.insert(OutCodePoints.begin() + i, n); i++; } return true; }
std::string Triple::normalize(StringRef Str) { // Parse into components. SmallVector<StringRef, 4> Components; for (size_t First = 0, Last = 0; Last != StringRef::npos; First = Last + 1) { Last = Str.find('-', First); Components.push_back(Str.slice(First, Last)); } // If the first component corresponds to a known architecture, preferentially // use it for the architecture. If the second component corresponds to a // known vendor, preferentially use it for the vendor, etc. This avoids silly // component movement when a component parses as (eg) both a valid arch and a // valid os. ArchType Arch = UnknownArch; if (Components.size() > 0) Arch = ParseArch(Components[0]); VendorType Vendor = UnknownVendor; if (Components.size() > 1) Vendor = ParseVendor(Components[1]); OSType OS = UnknownOS; if (Components.size() > 2) OS = ParseOS(Components[2]); EnvironmentType Environment = UnknownEnvironment; if (Components.size() > 3) Environment = ParseEnvironment(Components[3]); // Note which components are already in their final position. These will not // be moved. bool Found[4]; Found[0] = Arch != UnknownArch; Found[1] = Vendor != UnknownVendor; Found[2] = OS != UnknownOS; Found[3] = Environment != UnknownEnvironment; // If they are not there already, permute the components into their canonical // positions by seeing if they parse as a valid architecture, and if so moving // the component to the architecture position etc. for (unsigned Pos = 0; Pos != array_lengthof(Found); ++Pos) { if (Found[Pos]) continue; // Already in the canonical position. for (unsigned Idx = 0; Idx != Components.size(); ++Idx) { // Do not reparse any components that already matched. if (Idx < array_lengthof(Found) && Found[Idx]) continue; // Does this component parse as valid for the target position? bool Valid = false; StringRef Comp = Components[Idx]; switch (Pos) { default: assert(false && "unexpected component type!"); case 0: Arch = ParseArch(Comp); Valid = Arch != UnknownArch; break; case 1: Vendor = ParseVendor(Comp); Valid = Vendor != UnknownVendor; break; case 2: OS = ParseOS(Comp); Valid = OS != UnknownOS; break; case 3: Environment = ParseEnvironment(Comp); Valid = Environment != UnknownEnvironment; break; } if (!Valid) continue; // Nope, try the next component. // Move the component to the target position, pushing any non-fixed // components that are in the way to the right. This tends to give // good results in the common cases of a forgotten vendor component // or a wrongly positioned environment. if (Pos < Idx) { // Insert left, pushing the existing components to the right. For // example, a-b-i386 -> i386-a-b when moving i386 to the front. StringRef CurrentComponent(""); // The empty component. // Replace the component we are moving with an empty component. std::swap(CurrentComponent, Components[Idx]); // Insert the component being moved at Pos, displacing any existing // components to the right. for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { // Skip over any fixed components. while (i < array_lengthof(Found) && Found[i]) ++i; // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); } } else if (Pos > Idx) { // Push right by inserting empty components until the component at Idx // reaches the target position Pos. For example, pc-a -> -pc-a when // moving pc to the second position. do { // Insert one empty component at Idx. StringRef CurrentComponent(""); // The empty component. for (unsigned i = Idx; i < Components.size();) { // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); // If it was placed on top of an empty component then we are done. if (CurrentComponent.empty()) break; // Advance to the next component, skipping any fixed components. while (++i < array_lengthof(Found) && Found[i]) ; } // The last component was pushed off the end - append it. if (!CurrentComponent.empty()) Components.push_back(CurrentComponent); // Advance Idx to the component's new position. while (++Idx < array_lengthof(Found) && Found[Idx]) {} } while (Idx < Pos); // Add more until the final position is reached. } assert(Pos < Components.size() && Components[Pos] == Comp && "Component moved wrong!"); Found[Pos] = true; break; } } // Special case logic goes here. At this point Arch, Vendor and OS have the // correct values for the computed components. // Stick the corrected components back together to form the normalized string. std::string Normalized; for (unsigned i = 0, e = Components.size(); i != e; ++i) { if (i) Normalized += '-'; Normalized += Components[i]; } return Normalized; }
CudaInstallationDetector::CudaInstallationDetector( const Driver &D, const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args) : D(D) { struct Candidate { std::string Path; bool StrictChecking; Candidate(std::string Path, bool StrictChecking = false) : Path(Path), StrictChecking(StrictChecking) {} }; SmallVector<Candidate, 4> Candidates; // In decreasing order so we prefer newer versions to older versions. std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) { Candidates.emplace_back( Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ).str()); } else if (HostTriple.isOSWindows()) { for (const char *Ver : Versions) Candidates.emplace_back( D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + Ver); } else { if (!Args.hasArg(clang::driver::options::OPT_cuda_path_ignore_env)) { // Try to find ptxas binary. If the executable is located in a directory // called 'bin/', its parent directory might be a good guess for a valid // CUDA installation. // However, some distributions might installs 'ptxas' to /usr/bin. In that // case the candidate would be '/usr' which passes the following checks // because '/usr/include' exists as well. To avoid this case, we always // check for the directory potentially containing files for libdevice, // even if the user passes -nocudalib. if (llvm::ErrorOr<std::string> ptxas = llvm::sys::findProgramByName("ptxas")) { SmallString<256> ptxasAbsolutePath; llvm::sys::fs::real_path(*ptxas, ptxasAbsolutePath); StringRef ptxasDir = llvm::sys::path::parent_path(ptxasAbsolutePath); if (llvm::sys::path::filename(ptxasDir) == "bin") Candidates.emplace_back(llvm::sys::path::parent_path(ptxasDir), /*StrictChecking=*/true); } } Candidates.emplace_back(D.SysRoot + "/usr/local/cuda"); for (const char *Ver : Versions) Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver); if (Distro(D.getVFS()).IsDebian()) // Special case for Debian to have nvidia-cuda-toolkit work // out of the box. More info on http://bugs.debian.org/882505 Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda"); } bool NoCudaLib = Args.hasArg(options::OPT_nocudalib); for (const auto &Candidate : Candidates) { InstallPath = Candidate.Path; if (InstallPath.empty() || !D.getVFS().exists(InstallPath)) continue; BinPath = InstallPath + "/bin"; IncludePath = InstallPath + "/include"; LibDevicePath = InstallPath + "/nvvm/libdevice"; auto &FS = D.getVFS(); if (!(FS.exists(IncludePath) && FS.exists(BinPath))) continue; bool CheckLibDevice = (!NoCudaLib || Candidate.StrictChecking); if (CheckLibDevice && !FS.exists(LibDevicePath)) continue; // On Linux, we have both lib and lib64 directories, and we need to choose // based on our triple. On MacOS, we have only a lib directory. // // It's sufficient for our purposes to be flexible: If both lib and lib64 // exist, we choose whichever one matches our triple. Otherwise, if only // lib exists, we use it. if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) LibPath = InstallPath + "/lib64"; else if (FS.exists(InstallPath + "/lib")) LibPath = InstallPath + "/lib"; else continue; llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = FS.getBufferForFile(InstallPath + "/version.txt"); if (!VersionFile) { // CUDA 7.0 doesn't have a version.txt, so guess that's our version if // version.txt isn't present. Version = CudaVersion::CUDA_70; } else { Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); } if (Version >= CudaVersion::CUDA_90) { // CUDA-9+ uses single libdevice file for all GPU variants. std::string FilePath = LibDevicePath + "/libdevice.10.bc"; if (FS.exists(FilePath)) { for (const char *GpuArchName : {"sm_30", "sm_32", "sm_35", "sm_37", "sm_50", "sm_52", "sm_53", "sm_60", "sm_61", "sm_62", "sm_70", "sm_72"}) { const CudaArch GpuArch = StringToCudaArch(GpuArchName); if (Version >= MinVersionForCudaArch(GpuArch) && Version <= MaxVersionForCudaArch(GpuArch)) LibDeviceMap[GpuArchName] = FilePath; } } } else { std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); // Process all bitcode filenames that look like // libdevice.compute_XX.YY.bc const StringRef LibDeviceName = "libdevice."; if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) continue; StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); LibDeviceMap[GpuArch] = FilePath.str(); // Insert map entries for specific devices with this compute // capability. NVCC's choice of the libdevice library version is // rather peculiar and depends on the CUDA version. if (GpuArch == "compute_20") { LibDeviceMap["sm_20"] = FilePath; LibDeviceMap["sm_21"] = FilePath; LibDeviceMap["sm_32"] = FilePath; } else if (GpuArch == "compute_30") { LibDeviceMap["sm_30"] = FilePath; if (Version < CudaVersion::CUDA_80) { LibDeviceMap["sm_50"] = FilePath; LibDeviceMap["sm_52"] = FilePath; LibDeviceMap["sm_53"] = FilePath; } LibDeviceMap["sm_60"] = FilePath; LibDeviceMap["sm_61"] = FilePath; LibDeviceMap["sm_62"] = FilePath; } else if (GpuArch == "compute_35") { LibDeviceMap["sm_35"] = FilePath; LibDeviceMap["sm_37"] = FilePath; } else if (GpuArch == "compute_50") { if (Version >= CudaVersion::CUDA_80) { LibDeviceMap["sm_50"] = FilePath; LibDeviceMap["sm_52"] = FilePath; LibDeviceMap["sm_53"] = FilePath; } } } } // Check that we have found at least one libdevice that we can link in if // -nocudalib hasn't been specified. if (LibDeviceMap.empty() && !NoCudaLib) continue; IsValid = true; break; } }
/// Determine the prefix to be stripped from the names of the enum constants /// within the given enum. void EnumInfo::determineConstantNamePrefix(ASTContext &ctx, const clang::EnumDecl *decl) { switch (getKind()) { case EnumKind::Enum: case EnumKind::Options: // Enums are mapped to Swift enums, Options to Swift option sets, both // of which attempt prefix-stripping. break; case EnumKind::Constants: case EnumKind::Unknown: // Nothing to do. return; } // If there are no enumers, there is no prefix to compute. auto ec = decl->enumerator_begin(), ecEnd = decl->enumerator_end(); if (ec == ecEnd) return; // Determine whether the given enumerator is non-deprecated and has no // specifically-provided name. auto isNonDeprecatedWithoutCustomName = []( const clang::EnumConstantDecl *elem) -> bool { if (elem->hasAttr<clang::SwiftNameAttr>()) return false; clang::VersionTuple maxVersion{~0U, ~0U, ~0U}; switch (elem->getAvailability(nullptr, maxVersion)) { case clang::AR_Available: case clang::AR_NotYetIntroduced: for (auto attr : elem->attrs()) { if (auto annotate = dyn_cast<clang::AnnotateAttr>(attr)) { if (annotate->getAnnotation() == "swift1_unavailable") return false; } if (auto avail = dyn_cast<clang::AvailabilityAttr>(attr)) { if (avail->getPlatform()->getName() == "swift") return false; } } return true; case clang::AR_Deprecated: case clang::AR_Unavailable: return false; } }; // Move to the first non-deprecated enumerator, or non-swift_name'd // enumerator, if present. auto firstNonDeprecated = std::find_if(ec, ecEnd, isNonDeprecatedWithoutCustomName); bool hasNonDeprecated = (firstNonDeprecated != ecEnd); if (hasNonDeprecated) { ec = firstNonDeprecated; } else { // Advance to the first case without a custom name, deprecated or not. while (ec != ecEnd && (*ec)->hasAttr<clang::SwiftNameAttr>()) ++ec; if (ec == ecEnd) { return; } } // Compute the common prefix. StringRef commonPrefix = (*ec)->getName(); bool followedByNonIdentifier = false; for (++ec; ec != ecEnd; ++ec) { // Skip deprecated or swift_name'd enumerators. const clang::EnumConstantDecl *elem = *ec; if (hasNonDeprecated) { if (!isNonDeprecatedWithoutCustomName(elem)) continue; } else { if (elem->hasAttr<clang::SwiftNameAttr>()) continue; } commonPrefix = getCommonWordPrefix(commonPrefix, elem->getName(), followedByNonIdentifier); if (commonPrefix.empty()) break; } if (!commonPrefix.empty()) { StringRef checkPrefix = commonPrefix; // Account for the 'kConstant' naming convention on enumerators. if (checkPrefix[0] == 'k') { bool canDropK; if (checkPrefix.size() >= 2) canDropK = clang::isUppercase(checkPrefix[1]); else canDropK = !followedByNonIdentifier; if (canDropK) checkPrefix = checkPrefix.drop_front(); } // Don't use importFullName() here, we want to ignore the swift_name // and swift_private attributes. StringRef enumNameStr = decl->getName(); StringRef commonWithEnum = getCommonPluralPrefix(checkPrefix, enumNameStr); size_t delta = commonPrefix.size() - checkPrefix.size(); // Account for the 'EnumName_Constant' convention on enumerators. if (commonWithEnum.size() < checkPrefix.size() && checkPrefix[commonWithEnum.size()] == '_' && !followedByNonIdentifier) { delta += 1; } commonPrefix = commonPrefix.slice(0, commonWithEnum.size() + delta); } constantNamePrefix = ctx.AllocateCopy(commonPrefix); }
int main(int argc, char **argv) { std::vector<StringRef> Components; bool PrintLibs = false, PrintLibNames = false, PrintLibFiles = false; bool PrintSystemLibs = false; bool HasAnyOption = false; // llvm-config is designed to support being run both from a development tree // and from an installed path. We try and auto-detect which case we are in so // that we can report the correct information when run from a development // tree. bool IsInDevelopmentTree; enum { MakefileStyle, CMakeStyle, CMakeBuildModeStyle } DevelopmentTreeLayout; llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0])); std::string CurrentExecPrefix; std::string ActiveObjRoot; // If CMAKE_CFG_INTDIR is given, honor it as build mode. char const *build_mode = LLVM_BUILDMODE; #if defined(CMAKE_CFG_INTDIR) if (!(CMAKE_CFG_INTDIR[0] == '.' && CMAKE_CFG_INTDIR[1] == '\0')) build_mode = CMAKE_CFG_INTDIR; #endif // Create an absolute path, and pop up one directory (we expect to be inside a // bin dir). sys::fs::make_absolute(CurrentPath); CurrentExecPrefix = sys::path::parent_path( sys::path::parent_path(CurrentPath)).str(); // Check to see if we are inside a development tree by comparing to possible // locations (prefix style or CMake style). if (sys::fs::equivalent(CurrentExecPrefix, Twine(LLVM_OBJ_ROOT) + "/" + build_mode)) { IsInDevelopmentTree = true; DevelopmentTreeLayout = MakefileStyle; // If we are in a development tree, then check if we are in a BuildTools // directory. This indicates we are built for the build triple, but we // always want to provide information for the host triple. if (sys::path::filename(LLVM_OBJ_ROOT) == "BuildTools") { ActiveObjRoot = sys::path::parent_path(LLVM_OBJ_ROOT); } else { ActiveObjRoot = LLVM_OBJ_ROOT; } } else if (sys::fs::equivalent(CurrentExecPrefix, LLVM_OBJ_ROOT)) { IsInDevelopmentTree = true; DevelopmentTreeLayout = CMakeStyle; ActiveObjRoot = LLVM_OBJ_ROOT; } else if (sys::fs::equivalent(CurrentExecPrefix, Twine(LLVM_OBJ_ROOT) + "/bin")) { IsInDevelopmentTree = true; DevelopmentTreeLayout = CMakeBuildModeStyle; ActiveObjRoot = LLVM_OBJ_ROOT; } else { IsInDevelopmentTree = false; DevelopmentTreeLayout = MakefileStyle; // Initialized to avoid warnings. } // Compute various directory locations based on the derived location // information. std::string ActivePrefix, ActiveBinDir, ActiveIncludeDir, ActiveLibDir; std::string ActiveIncludeOption; if (IsInDevelopmentTree) { ActiveIncludeDir = std::string(LLVM_SRC_ROOT) + "/include"; ActivePrefix = CurrentExecPrefix; // CMake organizes the products differently than a normal prefix style // layout. switch (DevelopmentTreeLayout) { case MakefileStyle: ActivePrefix = ActiveObjRoot; ActiveBinDir = ActiveObjRoot + "/" + build_mode + "/bin"; ActiveLibDir = ActiveObjRoot + "/" + build_mode + "/lib" + LLVM_LIBDIR_SUFFIX; break; case CMakeStyle: ActiveBinDir = ActiveObjRoot + "/bin"; ActiveLibDir = ActiveObjRoot + "/lib" + LLVM_LIBDIR_SUFFIX; break; case CMakeBuildModeStyle: ActivePrefix = ActiveObjRoot; ActiveBinDir = ActiveObjRoot + "/bin/" + build_mode; ActiveLibDir = ActiveObjRoot + "/lib" + LLVM_LIBDIR_SUFFIX + "/" + build_mode; break; } // We need to include files from both the source and object trees. ActiveIncludeOption = ("-I" + ActiveIncludeDir + " " + "-I" + ActiveObjRoot + "/include"); } else { ActivePrefix = CurrentExecPrefix; ActiveIncludeDir = ActivePrefix + "/include"; ActiveBinDir = ActivePrefix + "/bin"; ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX; ActiveIncludeOption = "-I" + ActiveIncludeDir; } raw_ostream &OS = outs(); for (int i = 1; i != argc; ++i) { StringRef Arg = argv[i]; if (Arg.startswith("-")) { HasAnyOption = true; if (Arg == "--version") { OS << PACKAGE_VERSION << '\n'; } else if (Arg == "--prefix") { OS << ActivePrefix << '\n'; } else if (Arg == "--bindir") { OS << ActiveBinDir << '\n'; } else if (Arg == "--includedir") { OS << ActiveIncludeDir << '\n'; } else if (Arg == "--libdir") { OS << ActiveLibDir << '\n'; } else if (Arg == "--cppflags") { OS << ActiveIncludeOption << ' ' << LLVM_CPPFLAGS << '\n'; } else if (Arg == "--cflags") { OS << ActiveIncludeOption << ' ' << LLVM_CFLAGS << '\n'; } else if (Arg == "--cxxflags") { OS << ActiveIncludeOption << ' ' << LLVM_CXXFLAGS << '\n'; } else if (Arg == "--ldflags") { OS << "-L" << ActiveLibDir << ' ' << LLVM_LDFLAGS << '\n'; } else if (Arg == "--system-libs") { PrintSystemLibs = true; } else if (Arg == "--libs") { PrintLibs = true; } else if (Arg == "--libnames") { PrintLibNames = true; } else if (Arg == "--libfiles") { PrintLibFiles = true; } else if (Arg == "--components") { for (unsigned j = 0; j != array_lengthof(AvailableComponents); ++j) { // Only include non-installed components when in a development tree. if (!AvailableComponents[j].IsInstalled && !IsInDevelopmentTree) continue; OS << ' '; OS << AvailableComponents[j].Name; } OS << '\n'; } else if (Arg == "--targets-built") { OS << LLVM_TARGETS_BUILT << '\n'; } else if (Arg == "--host-target") { OS << Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE) << '\n'; } else if (Arg == "--build-mode") { OS << build_mode << '\n'; } else if (Arg == "--assertion-mode") { #if defined(NDEBUG) OS << "OFF\n"; #else OS << "ON\n"; #endif } else if (Arg == "--obj-root") { OS << ActivePrefix << '\n'; } else if (Arg == "--src-root") { OS << LLVM_SRC_ROOT << '\n'; } else { usage(); } } else { Components.push_back(Arg); } } if (!HasAnyOption) usage(); if (PrintLibs || PrintLibNames || PrintLibFiles || PrintSystemLibs) { // If no components were specified, default to "all". if (Components.empty()) Components.push_back("all"); // Construct the list of all the required libraries. std::vector<StringRef> RequiredLibs; ComputeLibsForComponents(Components, RequiredLibs, /*IncludeNonInstalled=*/IsInDevelopmentTree); if (PrintLibs || PrintLibNames || PrintLibFiles) { for (unsigned i = 0, e = RequiredLibs.size(); i != e; ++i) { StringRef Lib = RequiredLibs[i]; if (i) OS << ' '; if (PrintLibNames) { OS << Lib; } else if (PrintLibFiles) { OS << ActiveLibDir << '/' << Lib; } else if (PrintLibs) { // If this is a typical library name, include it using -l. if (Lib.startswith("lib") && Lib.endswith(".a")) { OS << "-l" << Lib.slice(3, Lib.size()-2); continue; } // Otherwise, print the full path. OS << ActiveLibDir << '/' << Lib; } } OS << '\n'; } // Print SYSTEM_LIBS after --libs. // FIXME: Each LLVM component may have its dependent system libs. if (PrintSystemLibs) OS << LLVM_SYSTEM_LIBS << '\n'; } else if (!Components.empty()) { errs() << "llvm-config: error: components given, but unused\n\n"; usage(); } return 0; }
/// \brief After the file has been processed, check to see if we got all of /// the expected diagnostics and check to see if there were any unexpected /// ones. bool DiagnosticVerifier::verifyFile(unsigned BufferID, bool shouldAutoApplyFixes) { using llvm::SMLoc; const SourceLoc BufferStartLoc = SM.getLocForBufferStart(BufferID); CharSourceRange EntireRange = SM.getRangeForBuffer(BufferID); StringRef InputFile = SM.extractText(EntireRange); StringRef BufferName = SM.getIdentifierForBuffer(BufferID); // Queue up all of the diagnostics, allowing us to sort them and emit them in // file order. std::vector<llvm::SMDiagnostic> Errors; unsigned PrevExpectedContinuationLine = 0; std::vector<ExpectedDiagnosticInfo> ExpectedDiagnostics; auto addError = [&](const char *Loc, std::string message, ArrayRef<llvm::SMFixIt> FixIts = {}) { auto loc = SourceLoc(SMLoc::getFromPointer(Loc)); auto diag = SM.GetMessage(loc, llvm::SourceMgr::DK_Error, message, {}, FixIts); Errors.push_back(diag); }; // Scan the memory buffer looking for expected-note/warning/error. for (size_t Match = InputFile.find("expected-"); Match != StringRef::npos; Match = InputFile.find("expected-", Match+1)) { // Process this potential match. If we fail to process it, just move on to // the next match. StringRef MatchStart = InputFile.substr(Match); const char *DiagnosticLoc = MatchStart.data(); llvm::SourceMgr::DiagKind ExpectedClassification; if (MatchStart.startswith("expected-note")) { ExpectedClassification = llvm::SourceMgr::DK_Note; MatchStart = MatchStart.substr(strlen("expected-note")); } else if (MatchStart.startswith("expected-warning")) { ExpectedClassification = llvm::SourceMgr::DK_Warning; MatchStart = MatchStart.substr(strlen("expected-warning")); } else if (MatchStart.startswith("expected-error")) { ExpectedClassification = llvm::SourceMgr::DK_Error; MatchStart = MatchStart.substr(strlen("expected-error")); } else continue; // Skip any whitespace before the {{. MatchStart = MatchStart.substr(MatchStart.find_first_not_of(" \t")); size_t TextStartIdx = MatchStart.find("{{"); if (TextStartIdx == StringRef::npos) { addError(MatchStart.data(), "expected {{ in expected-warning/note/error line"); continue; } int LineOffset = 0; if (TextStartIdx > 0 && MatchStart[0] == '@') { if (MatchStart[1] != '+' && MatchStart[1] != '-') { addError(MatchStart.data(), "expected '+'/'-' for line offset"); continue; } StringRef Offs; if (MatchStart[1] == '+') Offs = MatchStart.slice(2, TextStartIdx).rtrim(); else Offs = MatchStart.slice(1, TextStartIdx).rtrim(); size_t SpaceIndex = Offs.find(' '); if (SpaceIndex != StringRef::npos && SpaceIndex < TextStartIdx) { size_t Delta = Offs.size() - SpaceIndex; MatchStart = MatchStart.substr(TextStartIdx - Delta); TextStartIdx = Delta; Offs = Offs.slice(0, SpaceIndex); } else { MatchStart = MatchStart.substr(TextStartIdx); TextStartIdx = 0; } if (Offs.getAsInteger(10, LineOffset)) { addError(MatchStart.data(), "expected line offset before '{{'"); continue; } } ExpectedDiagnosticInfo Expected(DiagnosticLoc, ExpectedClassification); unsigned Count = 1; if (TextStartIdx > 0) { StringRef CountStr = MatchStart.substr(0, TextStartIdx).trim(); if (CountStr == "*") { Expected.mayAppear = true; } else { if (CountStr.getAsInteger(10, Count)) { addError(MatchStart.data(), "expected match count before '{{'"); continue; } if (Count == 0) { addError(MatchStart.data(), "expected positive match count before '{{'"); continue; } } // Resync up to the '{{'. MatchStart = MatchStart.substr(TextStartIdx); } size_t End = MatchStart.find("}}"); if (End == StringRef::npos) { addError(MatchStart.data(), "didn't find '}}' to match '{{' in expected-warning/note/error line"); continue; } llvm::SmallString<256> Buf; Expected.MessageRange = MatchStart.slice(2, End); Expected.MessageStr = Lexer::getEncodedStringSegment(Expected.MessageRange, Buf); if (PrevExpectedContinuationLine) Expected.LineNo = PrevExpectedContinuationLine; else Expected.LineNo = SM.getLineAndColumn( BufferStartLoc.getAdvancedLoc(MatchStart.data() - InputFile.data()), BufferID).first; Expected.LineNo += LineOffset; // Check if the next expected diagnostic should be in the same line. StringRef AfterEnd = MatchStart.substr(End + strlen("}}")); AfterEnd = AfterEnd.substr(AfterEnd.find_first_not_of(" \t")); if (AfterEnd.startswith("\\")) PrevExpectedContinuationLine = Expected.LineNo; else PrevExpectedContinuationLine = 0; // Scan for fix-its: {{10-14=replacement text}} StringRef ExtraChecks = MatchStart.substr(End+2).ltrim(" \t"); while (ExtraChecks.startswith("{{")) { // First make sure we have a closing "}}". size_t EndLoc = ExtraChecks.find("}}"); if (EndLoc == StringRef::npos) { addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in fix-it verification"); break; } // Allow for close braces to appear in the replacement text. while (EndLoc+2 < ExtraChecks.size() && ExtraChecks[EndLoc+2] == '}') ++EndLoc; StringRef FixItStr = ExtraChecks.slice(2, EndLoc); // Check for matching a later "}}" on a different line. if (FixItStr.find_first_of("\r\n") != StringRef::npos) { addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in " "fix-it verification"); break; } // Prepare for the next round of checks. ExtraChecks = ExtraChecks.substr(EndLoc+2).ltrim(); // Special case for specifying no fixits should appear. if (FixItStr == "none") { Expected.noFixitsMayAppear = true; continue; } // Parse the pieces of the fix-it. size_t MinusLoc = FixItStr.find('-'); if (MinusLoc == StringRef::npos) { addError(FixItStr.data(), "expected '-' in fix-it verification"); continue; } StringRef StartColStr = FixItStr.slice(0, MinusLoc); StringRef AfterMinus = FixItStr.substr(MinusLoc+1); size_t EqualLoc = AfterMinus.find('='); if (EqualLoc == StringRef::npos) { addError(AfterMinus.data(), "expected '=' after '-' in fix-it verification"); continue; } StringRef EndColStr = AfterMinus.slice(0, EqualLoc); StringRef AfterEqual = AfterMinus.substr(EqualLoc+1); ExpectedFixIt FixIt; FixIt.StartLoc = StartColStr.data()-2; FixIt.EndLoc = FixItStr.data()+EndLoc; if (StartColStr.getAsInteger(10, FixIt.StartCol)) { addError(StartColStr.data(), "invalid column number in fix-it verification"); continue; } if (EndColStr.getAsInteger(10, FixIt.EndCol)) { addError(EndColStr.data(), "invalid column number in fix-it verification"); continue; } // Translate literal "\\n" into '\n', inefficiently. StringRef fixItText = AfterEqual.slice(0, EndLoc); for (const char *current = fixItText.begin(), *end = fixItText.end(); current != end; /* in loop */) { if (*current == '\\' && current + 1 < end) { if (current[1] == 'n') { FixIt.Text += '\n'; current += 2; } else { // Handle \}, \\, etc. FixIt.Text += current[1]; current += 2; } } else { FixIt.Text += *current++; } } Expected.Fixits.push_back(FixIt); } Expected.ExpectedEnd = ExtraChecks.data(); // Don't include trailing whitespace in the expected-foo{{}} range. while (isspace(Expected.ExpectedEnd[-1])) --Expected.ExpectedEnd; // Add the diagnostic the expected number of times. for (; Count; --Count) ExpectedDiagnostics.push_back(Expected); } // Make sure all the expected diagnostics appeared. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); for (unsigned i = ExpectedDiagnostics.size(); i != 0; ) { --i; auto &expected = ExpectedDiagnostics[i]; // Check to see if we had this expected diagnostic. auto FoundDiagnosticIter = findDiagnostic(expected, BufferName); if (FoundDiagnosticIter == CapturedDiagnostics.end()) { // Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then // we're ok. Otherwise, leave it in the list. if (expected.mayAppear) ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); continue; } auto &FoundDiagnostic = *FoundDiagnosticIter; const char *IncorrectFixit = nullptr; // Verify that any expected fix-its are present in the diagnostic. for (auto fixit : expected.Fixits) { // If we found it, we're ok. if (!checkForFixIt(fixit, FoundDiagnostic, InputFile)) IncorrectFixit = fixit.StartLoc; } // If we have any expected fixits that didn't get matched, then they are // wrong. Replace the failed fixit with what actually happened. if (IncorrectFixit) { if (FoundDiagnostic.getFixIts().empty()) { addError(IncorrectFixit, "expected fix-it not seen"); continue; } // If we had an incorrect expected fixit, render it and produce a fixit // of our own. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); auto replStartLoc = SMLoc::getFromPointer(expected.Fixits[0].StartLoc); auto replEndLoc = SMLoc::getFromPointer(expected.Fixits.back().EndLoc); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(IncorrectFixit, "expected fix-it not seen; actual fix-its: " + actual, fix); } else if (expected.noFixitsMayAppear && !FoundDiagnostic.getFixIts().empty() && !expected.mayAppear) { // If there was no fixit specification, but some were produced, add a // fixit to add them in. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); auto replStartLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 8); // {{none}} length auto replEndLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 1); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(replStartLoc.getPointer(), "expected no fix-its; actual fix-it seen: " + actual, fix); } // Actually remove the diagnostic from the list, so we don't match it // again. We do have to do this after checking fix-its, though, because // the diagnostic owns its fix-its. CapturedDiagnostics.erase(FoundDiagnosticIter); // We found the diagnostic, so remove it... unless we allow an arbitrary // number of diagnostics, in which case we want to reprocess this. if (expected.mayAppear) ++i; else ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } // Check to see if we have any incorrect diagnostics. If so, diagnose them as // such. for (unsigned i = ExpectedDiagnostics.size(); i != 0; ) { --i; auto &expected = ExpectedDiagnostics[i]; // Check to see if any found diagnostics have the right line and // classification, but the wrong text. auto I = CapturedDiagnostics.begin(); for (auto E = CapturedDiagnostics.end(); I != E; ++I) { // Verify the file and line of the diagnostic. if (I->getLineNo() != (int)expected.LineNo || I->getFilename() != BufferName || I->getKind() != expected.Classification) continue; // Otherwise, we found it, break out. break; } if (I == CapturedDiagnostics.end()) continue; auto StartLoc = SMLoc::getFromPointer(expected.MessageRange.begin()); auto EndLoc = SMLoc::getFromPointer(expected.MessageRange.end()); llvm::SMFixIt fixIt(llvm::SMRange{ StartLoc, EndLoc }, I->getMessage()); addError(expected.MessageRange.begin(), "incorrect message found", fixIt); CapturedDiagnostics.erase(I); ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } // Diagnose expected diagnostics that didn't appear. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); for (auto const &expected : ExpectedDiagnostics) { std::string message = "expected "+getDiagKindString(expected.Classification) + " not produced"; // Get the range of the expected-foo{{}} diagnostic specifier. auto StartLoc = expected.ExpectedStart; auto EndLoc = expected.ExpectedEnd; // A very common case if for the specifier to be the last thing on the line. // In this case, eat any trailing whitespace. while (isspace(*EndLoc) && *EndLoc != '\n' && *EndLoc != '\r') ++EndLoc; // If we found the end of the line, we can do great things. Otherwise, // avoid nuking whitespace that might be zapped through other means. if (*EndLoc != '\n' && *EndLoc != '\r') { EndLoc = expected.ExpectedEnd; } else { // If we hit the end of line, then zap whitespace leading up to it. auto FileStart = InputFile.data(); while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; // If we got to the end of the line, and the thing before this diagnostic // is a "//" then we can remove it too. if (StartLoc-2 >= FileStart && StartLoc[-1] == '/' && StartLoc[-2] == '/') StartLoc -= 2; // Perform another round of general whitespace nuking to cleanup // whitespace before the //. while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; // If we found a \n, then we can nuke the entire line. if (StartLoc-1 != FileStart && (StartLoc[-1] == '\n' || StartLoc[-1] == '\r')) --StartLoc; } // Remove the expected-foo{{}} as a fixit. llvm::SMFixIt fixIt(llvm::SMRange{ SMLoc::getFromPointer(StartLoc), SMLoc::getFromPointer(EndLoc) }, ""); addError(expected.ExpectedStart, message, fixIt); } // Verify that there are no diagnostics (in MemoryBuffer) left in the list. for (unsigned i = 0, e = CapturedDiagnostics.size(); i != e; ++i) { if (CapturedDiagnostics[i].getFilename() != BufferName) continue; std::string Message = "unexpected "+getDiagKindString(CapturedDiagnostics[i].getKind())+ " produced: "+CapturedDiagnostics[i].getMessage().str(); addError(CapturedDiagnostics[i].getLoc().getPointer(), Message); } // Sort the diagnostics by their address in the memory buffer as the primary // key. This ensures that an "unexpected diagnostic" and // "expected diagnostic" in the same place are emitted next to each other. std::sort(Errors.begin(), Errors.end(), [&](const llvm::SMDiagnostic &lhs, const llvm::SMDiagnostic &rhs) -> bool { return lhs.getLoc().getPointer() < rhs.getLoc().getPointer(); }); // Emit all of the queue'd up errors. for (auto Err : Errors) SM.getLLVMSourceMgr().PrintMessage(llvm::errs(), Err); // If auto-apply fixits is on, rewrite the original source file. if (shouldAutoApplyFixes) autoApplyFixes(BufferID, Errors); return !Errors.empty(); }