diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 75d4f419ab1fdc1e4f1089951824afa20ca876c0..4e3eaff97a87832065710048a269100f5a922bd9 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -15,6 +15,9 @@ on: description: 'Tag to build' required: true type: string + schedule: + # * is a special character in YAML so you have to quote this string + - cron: '0 8 1 * *' permissions: contents: read # Default everything to read-only @@ -26,7 +29,7 @@ jobs: if: github.repository == 'llvm/llvm-project' outputs: release-version: ${{ steps.validate-tag.outputs.release-version }} - release: ${{ steps.validate-tag.outputs.release }} + flags: ${{ steps.validate-tag.outputs.flags }} build-dir: ${{ steps.validate-tag.outputs.build-dir }} rc-flags: ${{ steps.validate-tag.outputs.rc-flags }} ref: ${{ steps.validate-tag.outputs.ref }} @@ -50,6 +53,11 @@ jobs: tag="${{ github.ref_name }}" trimmed=$(echo ${{ inputs.tag }} | xargs) [[ "$trimmed" != "" ]] && tag="$trimmed" + if [ "$tag" = "main" ]; then + # If tag is main, then we've been triggered by a scheduled so pass so + # use the head commit as the tag. + tag=`git rev-parse HEAD` + fi if [ -n "${{ inputs.upload }}" ]; then upload="${{ inputs.upload }}" else @@ -71,7 +79,7 @@ jobs: - name: Checkout LLVM uses: actions/checkout@v4 with: - ref: ${{ inputs.tag || github.ref_name }} + ref: ${{ needs.prepare.outputs.ref }} - name: Install Ninja uses: llvm/actions/install-ninja@main @@ -140,8 +148,7 @@ jobs: - name: Build and test release run: | ${{ needs.prepare.outputs.build-dir }}/llvm-project/llvm/utils/release/test-release.sh \ - -release ${{ needs.prepare.outputs.release }} \ - ${{ needs.prepare.outputs.rc-flags }} \ + ${{ needs.prepare.outputs.flags }} \ -triple ${{ matrix.target.triple }} \ -use-ninja \ -no-checkout \ diff --git a/.github/workflows/set-release-binary-outputs.sh b/.github/workflows/set-release-binary-outputs.sh index 8a7944e7e55fa06a4ddb5443df00021d00ae324a..9bc459a24e80194d4f5fa076e5d3a8939204f668 100644 --- a/.github/workflows/set-release-binary-outputs.sh +++ b/.github/workflows/set-release-binary-outputs.sh @@ -16,19 +16,32 @@ if [[ "$github_user" != "tstellar" && "$github_user" != "tru" ]]; then echo "ERROR: User not allowed: $github_user" exit 1 fi -pattern='^llvmorg-[0-9]\+\.[0-9]\+\.[0-9]\+\(-rc[0-9]\+\)\?$' -echo "$tag" | grep -e $pattern -if [ $? != 0 ]; then - echo "ERROR: Tag '$tag' doesn't match pattern: $pattern" - exit 1 + +if echo $tag | grep -e '^[0-9a-f]\+$'; then + # This is a plain commit. + # TODO: Don't hardcode this. + release_version="18" + build_dir="$tag" + upload='false' + ref="$tag" + flags="-git-ref $tag -test-asserts" + +else + + pattern='^llvmorg-[0-9]\+\.[0-9]\+\.[0-9]\+\(-rc[0-9]\+\)\?$' + echo "$tag" | grep -e $pattern + if [ $? != 0 ]; then + echo "ERROR: Tag '$tag' doesn't match pattern: $pattern" + exit 1 + fi + release_version=`echo "$tag" | sed 's/llvmorg-//g'` + release=`echo "$release_version" | sed 's/-.*//g'` + build_dir=`echo "$release_version" | sed 's,^[^-]\+,final,' | sed 's,[^-]\+-rc\(.\+\),rc\1,'` + rc_flags=`echo "$release_version" | sed 's,^[^-]\+,-final,' | sed 's,[^-]\+-rc\(.\+\),-rc \1 -test-asserts,' | sed 's,--,-,'` + flags="-release $release $rc_flags" fi -release_version=`echo "$tag" | sed 's/llvmorg-//g'` -release=`echo "$release_version" | sed 's/-.*//g'` -build_dir=`echo "$release_version" | sed 's,^[^-]\+,final,' | sed 's,[^-]\+-rc\(.\+\),rc\1,'` -rc_flags=`echo "$release_version" | sed 's,^[^-]\+,-final,' | sed 's,[^-]\+-rc\(.\+\),-rc \1 -test-asserts,' | sed 's,--,-,'` echo "release-version=$release_version" >> $GITHUB_OUTPUT -echo "release=$release" >> $GITHUB_OUTPUT echo "build-dir=$build_dir" >> $GITHUB_OUTPUT -echo "rc-flags=$rc_flags" >> $GITHUB_OUTPUT +echo "flags=$flags" >> $GITHUB_OUTPUT echo "upload=$upload" >> $GITHUB_OUTPUT echo "ref=$tag" >> $GITHUB_OUTPUT diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index c7672285b06c09f8f99123e34e8e35dd8793c21a..f0e7a8272ad0ee491706ce8d24cb2dfcecd89d21 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -900,8 +900,8 @@ public: /// Return true if \p SymbolName was generated internally and was not present /// in the input binary. bool isInternalSymbolName(const StringRef Name) { - return Name.startswith("SYMBOLat") || Name.startswith("DATAat") || - Name.startswith("HOLEat"); + return Name.starts_with("SYMBOLat") || Name.starts_with("DATAat") || + Name.starts_with("HOLEat"); } MCSymbol *getHotTextStartSymbol() const { diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 7b78c9ba30a3032c554bc0784f8aafebd78294bc..3f96ea265e425f72380585aa6f8a08d2ac4deaa9 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1086,7 +1086,7 @@ void BinaryContext::generateSymbolHashes() { auto isPadding = [](const BinaryData &BD) { StringRef Contents = BD.getSection().getContents(); StringRef SymData = Contents.substr(BD.getOffset(), BD.getSize()); - return (BD.getName().startswith("HOLEat") || + return (BD.getName().starts_with("HOLEat") || SymData.find_first_not_of(0) == StringRef::npos); }; @@ -1326,8 +1326,8 @@ void BinaryContext::postProcessSymbolTable() { bool Valid = true; for (auto &Entry : BinaryDataMap) { BinaryData *BD = Entry.second; - if ((BD->getName().startswith("SYMBOLat") || - BD->getName().startswith("DATAat")) && + if ((BD->getName().starts_with("SYMBOLat") || + BD->getName().starts_with("DATAat")) && !BD->getParent() && !BD->getSize() && !BD->isAbsolute() && BD->getSection()) { errs() << "BOLT-WARNING: zero-sized top level symbol: " << *BD << "\n"; @@ -1410,9 +1410,9 @@ void BinaryContext::fixBinaryDataHoles() { auto isNotHole = [&Section](const binary_data_iterator &Itr) { BinaryData *BD = Itr->second; bool isHole = (!BD->getParent() && !BD->getSize() && BD->isObject() && - (BD->getName().startswith("SYMBOLat0x") || - BD->getName().startswith("DATAat0x") || - BD->getName().startswith("ANONYMOUS"))); + (BD->getName().starts_with("SYMBOLat0x") || + BD->getName().starts_with("DATAat0x") || + BD->getName().starts_with("ANONYMOUS"))); return !isHole && BD->getSection() == Section && !BD->getParent(); }; @@ -1818,14 +1818,14 @@ MarkerSymType BinaryContext::getMarkerType(const SymbolRef &Symbol) const { if (*TypeOrError != SymbolRef::ST_Unknown) return MarkerSymType::NONE; - if (*NameOrError == "$x" || NameOrError->startswith("$x.")) + if (*NameOrError == "$x" || NameOrError->starts_with("$x.")) return MarkerSymType::CODE; // $x - if (isRISCV() && NameOrError->startswith("$x")) + if (isRISCV() && NameOrError->starts_with("$x")) return MarkerSymType::CODE; - if (*NameOrError == "$d" || NameOrError->startswith("$d.")) + if (*NameOrError == "$d" || NameOrError->starts_with("$d.")) return MarkerSymType::DATA; return MarkerSymType::NONE; diff --git a/bolt/lib/Core/BinaryData.cpp b/bolt/lib/Core/BinaryData.cpp index f963406c17d58cedf4000e30fcdcea4d9b4dc4d0..0068a935800429f6b9f4cf0c56cef813f0af0486 100644 --- a/bolt/lib/Core/BinaryData.cpp +++ b/bolt/lib/Core/BinaryData.cpp @@ -65,7 +65,7 @@ bool BinaryData::hasNameRegex(StringRef NameRegex) const { bool BinaryData::nameStartsWith(StringRef Prefix) const { for (const MCSymbol *Symbol : Symbols) - if (Symbol->getName().startswith(Prefix)) + if (Symbol->getName().starts_with(Prefix)) return true; return false; } diff --git a/bolt/lib/Passes/IndirectCallPromotion.cpp b/bolt/lib/Passes/IndirectCallPromotion.cpp index f40f5e7acbf3b8bf0b5aae459011f7f60efeb591..451758161ef5e69ed69608b0b86bf8a60fcc9706 100644 --- a/bolt/lib/Passes/IndirectCallPromotion.cpp +++ b/bolt/lib/Passes/IndirectCallPromotion.cpp @@ -460,7 +460,7 @@ IndirectCallPromotion::maybeGetHotJumpTableTargets(BinaryBasicBlock &BB, if (AccessInfo.MemoryObject) { // Deal with bad/stale data - if (!AccessInfo.MemoryObject->getName().startswith( + if (!AccessInfo.MemoryObject->getName().starts_with( "JUMP_TABLE/" + Function.getOneName().str())) return JumpTableInfoType(); Index = diff --git a/bolt/lib/Passes/ReorderData.cpp b/bolt/lib/Passes/ReorderData.cpp index dc89b383552aba7224cd145993d73c5928d6bdc9..3a6654cf1e0b560e0ed6063811a329d96d693a92 100644 --- a/bolt/lib/Passes/ReorderData.cpp +++ b/bolt/lib/Passes/ReorderData.cpp @@ -408,14 +408,14 @@ bool ReorderData::markUnmoveableSymbols(BinaryContext &BC, // suffix in another. auto isPrivate = [&](const BinaryData *BD) { auto Prefix = std::string("PG") + BC.AsmInfo->getPrivateGlobalPrefix(); - return BD->getName().startswith(Prefix.str()); + return BD->getName().starts_with(Prefix.str()); }; auto Range = BC.getBinaryDataForSection(Section); bool FoundUnmoveable = false; for (auto Itr = Range.begin(); Itr != Range.end(); ++Itr) { BinaryData *Next = std::next(Itr) != Range.end() ? std::next(Itr)->second : nullptr; - if (Itr->second->getName().startswith("PG.")) { + if (Itr->second->getName().starts_with("PG.")) { BinaryData *Prev = Itr != Range.begin() ? std::prev(Itr)->second : nullptr; bool PrevIsPrivate = Prev && isPrivate(Prev); diff --git a/bolt/lib/Passes/ShrinkWrapping.cpp b/bolt/lib/Passes/ShrinkWrapping.cpp index 2dd57f3bbf3d25b6939c31ae3d1e10826abafdb4..d7b25c1279dc8b25b6aeebc97ebf34df69a0e496 100644 --- a/bolt/lib/Passes/ShrinkWrapping.cpp +++ b/bolt/lib/Passes/ShrinkWrapping.cpp @@ -1416,12 +1416,12 @@ bool ShrinkWrapping::foldIdenticalSplitEdges() { bool Changed = false; for (auto Iter = BF.begin(); Iter != BF.end(); ++Iter) { BinaryBasicBlock &BB = *Iter; - if (!BB.getName().startswith(".LSplitEdge")) + if (!BB.getName().starts_with(".LSplitEdge")) continue; for (BinaryBasicBlock &RBB : llvm::reverse(BF)) { if (&RBB == &BB) break; - if (!RBB.getName().startswith(".LSplitEdge") || !RBB.isValid() || + if (!RBB.getName().starts_with(".LSplitEdge") || !RBB.isValid() || !isIdenticalSplitEdgeBB(BC, *Iter, RBB)) continue; assert(RBB.pred_size() == 1 && "Invalid split edge BB"); diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 0b306b9965cc3dfb50bd3ddc3cf8109c3b6b006f..be1e348b338f0f025675bd0b844a68f3c412a4b9 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -1915,7 +1915,7 @@ DataAggregator::parseMMapEvent() { // PERF_RECORD_MMAP2 /: [() .*]: .* StringRef FileName = Line.rsplit(FieldSeparator).second; - if (FileName.startswith("//") || FileName.startswith("[")) { + if (FileName.starts_with("//") || FileName.starts_with("[")) { consumeRestOfLine(); return std::make_pair(StringRef(), ParsedInfo); } @@ -2168,7 +2168,7 @@ DataAggregator::getFileNameForBuildID(StringRef FileBuildID) { continue; } - if (IDPair->second.startswith(FileBuildID)) { + if (IDPair->second.starts_with(FileBuildID)) { FileName = sys::path::filename(IDPair->first); break; } diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp index 3d4db6feb51a72eb53ca287fe1c9a5fd0229b45d..aa21eb121ad65256695dfff0318058879c0b203c 100644 --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -55,7 +55,7 @@ bool hasVolatileName(const BinaryFunction &BF) { /// Return standard escaped name of the function possibly renamed by BOLT. std::string normalizeName(StringRef NameRef) { // Strip "PG." prefix used for globalized locals. - NameRef = NameRef.startswith("PG.") ? NameRef.substr(2) : NameRef; + NameRef = NameRef.starts_with("PG.") ? NameRef.substr(2) : NameRef; return getEscapedName(NameRef); } diff --git a/bolt/lib/Profile/YAMLProfileReader.cpp b/bolt/lib/Profile/YAMLProfileReader.cpp index ade562ef6fb11162cc52eda683ab3c8179dcfa5c..a4a401fd3cabf40278975d74b5713cd6d3670824 100644 --- a/bolt/lib/Profile/YAMLProfileReader.cpp +++ b/bolt/lib/Profile/YAMLProfileReader.cpp @@ -39,7 +39,7 @@ namespace bolt { bool YAMLProfileReader::isYAML(const StringRef Filename) { if (auto MB = MemoryBuffer::getFileOrSTDIN(Filename)) { StringRef Buffer = (*MB)->getBuffer(); - return Buffer.startswith("---\n"); + return Buffer.starts_with("---\n"); } else { report_error(Filename, MB.getError()); } diff --git a/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp b/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp index aa5c8344aa6f5428202050e558ad49dc6886ad91..041d0d8c2b274fecff51d7f20b4348ffac58422c 100644 --- a/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp +++ b/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp @@ -120,7 +120,7 @@ void ExecutableFileMemoryManager::updateSection( } if (!IsCode && (SectionName == ".strtab" || SectionName == ".symtab" || - SectionName == "" || SectionName.startswith(".rela."))) + SectionName == "" || SectionName.starts_with(".rela."))) return; SmallVector Buf; @@ -139,7 +139,7 @@ void ExecutableFileMemoryManager::updateSection( } BinarySection *Section = nullptr; - if (!OrgSecPrefix.empty() && SectionName.startswith(OrgSecPrefix)) { + if (!OrgSecPrefix.empty() && SectionName.starts_with(OrgSecPrefix)) { // Update the original section contents. ErrorOr OrgSection = BC.getUniqueSectionByName(SectionName.substr(OrgSecPrefix.length())); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 1e8ca569682f712cd4a2ad3cbabda406d8b4f277..a95b1650753cfdc73584080dff0a687ecce0d175 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -538,7 +538,7 @@ Error RewriteInstance::discoverStorage() { if (!opts::HeatmapMode && !(opts::AggregateOnly && BAT->enabledFor(InputFile)) && - (SectionName.startswith(getOrgSecPrefix()) || + (SectionName.starts_with(getOrgSecPrefix()) || SectionName == getBOLTTextSectionName())) return createStringError( errc::function_not_supported, @@ -778,12 +778,12 @@ void RewriteInstance::discoverFileObjects() { std::unordered_map SymbolToFileName; for (const ELFSymbolRef &Symbol : InputFile->symbols()) { Expected NameOrError = Symbol.getName(); - if (NameOrError && NameOrError->startswith("__asan_init")) { + if (NameOrError && NameOrError->starts_with("__asan_init")) { errs() << "BOLT-ERROR: input file was compiled or linked with sanitizer " "support. Cannot optimize.\n"; exit(1); } - if (NameOrError && NameOrError->startswith("__llvm_coverage_mapping")) { + if (NameOrError && NameOrError->starts_with("__llvm_coverage_mapping")) { errs() << "BOLT-ERROR: input file was compiled or linked with coverage " "support. Cannot optimize.\n"; exit(1); @@ -938,9 +938,10 @@ void RewriteInstance::discoverFileObjects() { /// It is possible we are seeing a globalized local. LLVM might treat it as /// a local if it has a "private global" prefix, e.g. ".L". Thus we have to /// change the prefix to enforce global scope of the symbol. - std::string Name = SymName.startswith(BC->AsmInfo->getPrivateGlobalPrefix()) - ? "PG" + std::string(SymName) - : std::string(SymName); + std::string Name = + SymName.starts_with(BC->AsmInfo->getPrivateGlobalPrefix()) + ? "PG" + std::string(SymName) + : std::string(SymName); // Disambiguate all local symbols before adding to symbol table. // Since we don't know if we will see a global with the same name, @@ -2723,8 +2724,8 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, BD->nameStartsWith(SymbolName) || BD->nameStartsWith("PG" + SymbolName) || (BD->nameStartsWith("ANONYMOUS") && - (BD->getSectionName().startswith(".plt") || - BD->getSectionName().endswith(".plt")))) && + (BD->getSectionName().starts_with(".plt") || + BD->getSectionName().ends_with(".plt")))) && "BOLT symbol names of all non-section relocations must match up " "with symbol names referenced in the relocation"); @@ -2740,7 +2741,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, // in relocation sections can get through here too, from .plt. assert( (IsAArch64 || BC->isRISCV() || IsSectionRelocation || - BC->getSectionNameForAddress(SymbolAddress)->startswith(".plt")) && + BC->getSectionNameForAddress(SymbolAddress)->starts_with(".plt")) && "known symbols should not resolve to anonymous locals"); if (IsSectionRelocation) { @@ -2757,7 +2758,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, Name = SymbolName; } else { if (StringRef(SymbolName) - .startswith(BC->AsmInfo->getPrivateGlobalPrefix())) + .starts_with(BC->AsmInfo->getPrivateGlobalPrefix())) Name = NR.uniquify("PG" + SymbolName); else Name = NR.uniquify(SymbolName); @@ -3464,8 +3465,8 @@ std::vector RewriteInstance::getCodeSections() { // ".text.cold.T", ".text.cold.T-1", ... ".text.cold.1", ".text.cold" // - if opts::HotFunctionsAtEnd is false, we want order // ".text.cold", ".text.cold.1", ... ".text.cold.T-1", ".text.cold.T" - if (A->getName().startswith(BC->getColdCodeSectionName()) && - B->getName().startswith(BC->getColdCodeSectionName())) { + if (A->getName().starts_with(BC->getColdCodeSectionName()) && + B->getName().starts_with(BC->getColdCodeSectionName())) { if (A->getName().size() != B->getName().size()) return (opts::HotFunctionsAtEnd) ? (A->getName().size() > B->getName().size()) @@ -5653,16 +5654,16 @@ bool RewriteInstance::willOverwriteSection(StringRef SectionName) { } bool RewriteInstance::isDebugSection(StringRef SectionName) { - if (SectionName.startswith(".debug_") || SectionName.startswith(".zdebug_") || - SectionName == ".gdb_index" || SectionName == ".stab" || - SectionName == ".stabstr") + if (SectionName.starts_with(".debug_") || + SectionName.starts_with(".zdebug_") || SectionName == ".gdb_index" || + SectionName == ".stab" || SectionName == ".stabstr") return true; return false; } bool RewriteInstance::isKSymtabSection(StringRef SectionName) { - if (SectionName.startswith("__ksymtab")) + if (SectionName.starts_with("__ksymtab")) return true; return false; diff --git a/bolt/test/X86/dwarf-test-df-logging.test b/bolt/test/X86/dwarf-test-df-logging.test index ca5e578a0845fd76c525d345851ac54233fdc408..6126e9628a31a99112b98466156ec5005e8d72dd 100644 --- a/bolt/test/X86/dwarf-test-df-logging.test +++ b/bolt/test/X86/dwarf-test-df-logging.test @@ -6,7 +6,7 @@ ; RUN: -split-dwarf-file=main.dwo -o main.o ; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-dualcu-helper.s \ ; RUN: -split-dwarf-file=helper.dwo -o helper.o -; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe +; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe -fno-pic -no-pie ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections | FileCheck -check-prefix=BOLT %s ; BOLT: BOLT-INFO: processing split DWARF diff --git a/bolt/test/X86/dwarf4-df-dualcu.test b/bolt/test/X86/dwarf4-df-dualcu.test index 5564d9ff26450472f672b16fee69951b38e53bf7..91b3e9e4cf0926c69eb894ae7c651571b111bdd0 100644 --- a/bolt/test/X86/dwarf4-df-dualcu.test +++ b/bolt/test/X86/dwarf4-df-dualcu.test @@ -5,7 +5,7 @@ ; RUN: -split-dwarf-file=main.dwo -o main.o ; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-dualcu-helper.s \ ; RUN: -split-dwarf-file=helper.dwo -o helper.o -; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe +; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe -fno-pic -no-pie ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --always-convert-to-ranges ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt diff --git a/bolt/test/X86/dwarf4-split-dwarf-no-address.test b/bolt/test/X86/dwarf4-split-dwarf-no-address.test index 5baef9238e9047dd37cdccaa9e42cf38c2676ae4..753fad06eb069fd477aaebe8ea4e77f5f331a64e 100644 --- a/bolt/test/X86/dwarf4-split-dwarf-no-address.test +++ b/bolt/test/X86/dwarf4-split-dwarf-no-address.test @@ -5,7 +5,7 @@ ; RUN: --filetype=obj %p/Inputs/dwarf4-split-dwarf-no-address-main.s -o=main.o ; RUN: llvm-mc --split-dwarf-file=helper.dwo --triple=x86_64-unknown-linux-gnu \ ; RUN: --filetype=obj %p/Inputs/dwarf4-split-dwarf-no-address-helper.s -o=helper.o -; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o helper.o -o main.exe +; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o helper.o -o main.exe -fno-pic -no-pie ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt | FileCheck -check-prefix=BOLT %s diff --git a/bolt/test/X86/dwarf5-df-dualcu.test b/bolt/test/X86/dwarf5-df-dualcu.test index 15d458d1c0251fd21e5cdc48dee0a5f9171c8cf6..deaeea03669081f670e52d529428470a3f87af23 100644 --- a/bolt/test/X86/dwarf5-df-dualcu.test +++ b/bolt/test/X86/dwarf5-df-dualcu.test @@ -5,7 +5,7 @@ ; RUN: -split-dwarf-file=main.dwo -o main.o ; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-dualcu-helper.s \ ; RUN: -split-dwarf-file=helper.dwo -o helper.o -; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe +; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe -fno-pic -no-pie ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --always-convert-to-ranges ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt &> %t/foo.txt diff --git a/bolt/test/X86/dwarf5-df-mono-dualcu.test b/bolt/test/X86/dwarf5-df-mono-dualcu.test index a6024997ba72d9bedd96433c970e28688a48a50d..12269287ef132f18fe66b8460cd2aa246674d49d 100644 --- a/bolt/test/X86/dwarf5-df-mono-dualcu.test +++ b/bolt/test/X86/dwarf5-df-mono-dualcu.test @@ -4,7 +4,7 @@ ; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-mono-main.s \ ; RUN: -split-dwarf-file=main.dwo -o main.o ; RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux-gnu %p/Inputs/dwarf5-df-mono-helper.s -o=helper.o -; RUN: %clang %cflags -gdwarf-5 main.o helper.o -o main.exe +; RUN: %clang %cflags -gdwarf-5 main.o helper.o -o main.exe -fno-pic -no-pie ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --always-convert-to-ranges ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt &> %t/foo.txt diff --git a/bolt/test/X86/dwarf5-locaddrx.test b/bolt/test/X86/dwarf5-locaddrx.test index a1d66bb359d27ae72b52e3b16d6a3be1eafe305f..00e15101f85311235f9c27c66e38a48533b118a6 100644 --- a/bolt/test/X86/dwarf5-locaddrx.test +++ b/bolt/test/X86/dwarf5-locaddrx.test @@ -3,7 +3,7 @@ ; RUN: cd %t ; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-locaddrx.s \ ; RUN: -split-dwarf-file=mainlocadddrx.dwo -o mainlocadddrx.o -; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split mainlocadddrx.o -o mainlocadddrx.exe +; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split mainlocadddrx.o -o mainlocadddrx.exe -fno-pic -no-pie ; RUN: llvm-bolt mainlocadddrx.exe -o mainlocadddrx.exe.bolt --update-debug-sections --always-convert-to-ranges ; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.exe | FileCheck -check-prefix=PRE-BOLT %s ; RUN: llvm-dwarfdump --show-form --verbose --debug-addr mainlocadddrx.exe.bolt &> %t/foo.txt diff --git a/bolt/tools/merge-fdata/merge-fdata.cpp b/bolt/tools/merge-fdata/merge-fdata.cpp index 757f0536616bec25812e517f39637e33fd4454ce..e21aeba73aca29a2154b209e53789114b7299e4a 100644 --- a/bolt/tools/merge-fdata/merge-fdata.cpp +++ b/bolt/tools/merge-fdata/merge-fdata.cpp @@ -253,7 +253,7 @@ bool isYAML(const StringRef Filename) { if (std::error_code EC = MB.getError()) report_error(Filename, EC); StringRef Buffer = MB.get()->getBuffer(); - if (Buffer.startswith("---\n")) + if (Buffer.starts_with("---\n")) return true; return false; } @@ -279,7 +279,7 @@ void mergeLegacyProfiles(const SmallVectorImpl &Filenames) { { std::lock_guard Lock(BoltedCollectionMutex); // Check if the string "boltedcollection" is in the first line - if (Buf.startswith("boltedcollection\n")) { + if (Buf.starts_with("boltedcollection\n")) { if (!BoltedCollection.value_or(true)) report_error( Filename, diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp index 7f7af7069c418877bbbe54438fd26bae44c38046..879c0d26d472a8dc83fc7129bcd7158f16e2b62e 100644 --- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp @@ -827,10 +827,10 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext( // "IsVisibleInNewNs" matcher. if (AliasQualifiedName != AliasName) { // The alias is defined in some namespace. - assert(StringRef(AliasQualifiedName).endswith("::" + AliasName)); + assert(StringRef(AliasQualifiedName).ends_with("::" + AliasName)); llvm::StringRef AliasNs = StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2); - if (!llvm::StringRef(OldNs).startswith(AliasNs)) + if (!llvm::StringRef(OldNs).starts_with(AliasNs)) continue; } std::string NameWithAliasNamespace = @@ -862,7 +862,7 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext( // If the new nested name in the new namespace is the same as it was in the // old namespace, we don't create replacement unless there can be ambiguity. if ((NestedName == ReplaceName && !Conflict) || - (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName)) + (NestedName.starts_with("::") && NestedName.drop_front(2) == ReplaceName)) return; // If the reference need to be fully-qualified, add a leading "::" unless // NewNamespace is the global namespace. @@ -891,7 +891,7 @@ void ChangeNamespaceTool::fixTypeLoc( // a typedef type, we need to use the typedef type instead. auto IsInMovedNs = [&](const NamedDecl *D) { if (!llvm::StringRef(D->getQualifiedNameAsString()) - .startswith(OldNamespace + "::")) + .starts_with(OldNamespace + "::")) return false; auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc()); if (ExpansionLoc.isInvalid()) diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp index f6f8404204ba06405ecb9dda2d80a8658c417b20..d7369b162dc10d8d87fc35f313212f819bc42101 100644 --- a/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp +++ b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp @@ -28,7 +28,7 @@ std::string createQualifiedNameForReplacement( const find_all_symbols::SymbolInfo &MatchedSymbol) { // No need to add missing qualifiers if SymbolIdentifier has a global scope // operator "::". - if (RawSymbolName.startswith("::")) + if (RawSymbolName.starts_with("::")) return std::string(RawSymbolName); std::string QualifiedName = MatchedSymbol.getQualifiedName(); @@ -42,7 +42,7 @@ std::string createQualifiedNameForReplacement( auto SymbolQualifiers = SplitQualifiers(RawSymbolName); std::string StrippedQualifiers; while (!SymbolQualifiers.empty() && - !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) { + !llvm::StringRef(QualifiedName).ends_with(SymbolQualifiers.back())) { StrippedQualifiers = "::" + SymbolQualifiers.back().str() + StrippedQualifiers; SymbolQualifiers.pop_back(); diff --git a/clang-tools-extra/clang-include-fixer/SymbolIndexManager.cpp b/clang-tools-extra/clang-include-fixer/SymbolIndexManager.cpp index 952c5fdedc291e51b3118c0e6f5c7cbfa6302727..027df3cfb2cc26760cc4289de99823d541da4d63 100644 --- a/clang-tools-extra/clang-include-fixer/SymbolIndexManager.cpp +++ b/clang-tools-extra/clang-include-fixer/SymbolIndexManager.cpp @@ -82,7 +82,7 @@ SymbolIndexManager::search(llvm::StringRef Identifier, Identifier.split(Names, "::"); bool IsFullyQualified = false; - if (Identifier.startswith("::")) { + if (Identifier.starts_with("::")) { Names.erase(Names.begin()); // Drop first (empty) element. IsFullyQualified = true; } diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp index 503fd60cb4c1b86ffb3b9e3584ad842a37e1c1d5..6d52963370ddd7ce89928b3742611ca017478339 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/PathConfig.cpp @@ -24,7 +24,7 @@ std::string getIncludePath(const SourceManager &SM, SourceLocation Loc, FilePath = SM.getFilename(Loc); if (FilePath.empty()) return ""; - if (!FilePath.endswith(".inc")) + if (!FilePath.ends_with(".inc")) break; FileID ID = SM.getFileID(Loc); Loc = SM.getIncludeLoc(ID); diff --git a/clang-tools-extra/clang-include-fixer/plugin/IncludeFixerPlugin.cpp b/clang-tools-extra/clang-include-fixer/plugin/IncludeFixerPlugin.cpp index 7908a890fcb63c659804d7a058dc93940601b1c1..ce431d443be4b46aaaabdd8af343adc0f0d6279f 100644 --- a/clang-tools-extra/clang-include-fixer/plugin/IncludeFixerPlugin.cpp +++ b/clang-tools-extra/clang-include-fixer/plugin/IncludeFixerPlugin.cpp @@ -54,9 +54,9 @@ public: // Parse the extra command line args. // FIXME: This is very limited at the moment. for (StringRef Arg : Args) { - if (Arg.startswith("-db=")) + if (Arg.starts_with("-db=")) DB = Arg.substr(strlen("-db=")); - else if (Arg.startswith("-input=")) + else if (Arg.starts_with("-input=")) Input = Arg.substr(strlen("-input=")); } diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 565f044778c946397261584fde73454c9549715a..40ac6918faf40786b1add8fb16e1c5933d76ca2e 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -390,7 +390,7 @@ static CheckersList getAnalyzerCheckersAndPackages(ClangTidyContext &Context, for (StringRef CheckName : RegisteredCheckers) { std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str()); - if (CheckName.startswith("core") || + if (CheckName.starts_with("core") || Context.isCheckEnabled(ClangTidyCheckName)) { List.emplace_back(std::string(CheckName), true); } @@ -541,7 +541,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, CommandLineArguments AdjustedArgs = Args; if (Opts.ExtraArgsBefore) { auto I = AdjustedArgs.begin(); - if (I != AdjustedArgs.end() && !StringRef(*I).startswith("-")) + if (I != AdjustedArgs.end() && !StringRef(*I).starts_with("-")) ++I; // Skip compiler binary name, if it is there. AdjustedArgs.insert(I, Opts.ExtraArgsBefore->begin(), Opts.ExtraArgsBefore->end()); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index b19a84f5dc215776f95920a6fb84315e78b2d965..0a80c996aaaade5fdb7e523ea231354d0cbb0e2f 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -62,7 +62,7 @@ protected: // appending the check name to the message in ClangTidyContext::diag and // using getCustomDiagID. std::string CheckNameInMessage = " [" + Error.DiagnosticName + "]"; - if (Message.endswith(CheckNameInMessage)) + if (Message.ends_with(CheckNameInMessage)) Message = Message.substr(0, Message.size() - CheckNameInMessage.size()); auto TidyMessage = @@ -457,7 +457,7 @@ bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName, if (Context.getGlobalOptions().LineFilter.empty()) return true; for (const FileFilter &Filter : Context.getGlobalOptions().LineFilter) { - if (FileName.endswith(Filter.Name)) { + if (FileName.ends_with(Filter.Name)) { if (Filter.LineRanges.empty()) return true; for (const FileFilter::LineRange &Range : Filter.LineRanges) { diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp index 0b1e9f59e1a70c7c27edbd005f6747ceb441bea6..e414ac8c770508fed662084f39a6e469eb42edeb 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp @@ -23,10 +23,10 @@ public: /// Records that a given file entry is needed for replaying callbacks. void addNecessaryFile(FileEntryRef File) { // Don't record modulemap files because it breaks same file detection. - if (!(File.getName().endswith("module.modulemap") || - File.getName().endswith("module.private.modulemap") || - File.getName().endswith("module.map") || - File.getName().endswith("module_private.map"))) + if (!(File.getName().ends_with("module.modulemap") || + File.getName().ends_with("module.private.modulemap") || + File.getName().ends_with("module.map") || + File.getName().ends_with("module_private.map"))) FilesToRecord.insert(File); } diff --git a/clang-tools-extra/clang-tidy/GlobList.cpp b/clang-tools-extra/clang-tidy/GlobList.cpp index 4ff9d951110630f4417e3b69b8c4cd54ee06db03..694db35106fd6363b20ab5624cb920c4eda9c108 100644 --- a/clang-tools-extra/clang-tidy/GlobList.cpp +++ b/clang-tools-extra/clang-tidy/GlobList.cpp @@ -16,7 +16,7 @@ namespace clang::tidy { // from the GlobList. static bool consumeNegativeIndicator(StringRef &GlobList) { GlobList = GlobList.trim(); - if (GlobList.startswith("-")) { + if (GlobList.starts_with("-")) { GlobList = GlobList.substr(1); return true; } diff --git a/clang-tools-extra/clang-tidy/abseil/AbseilMatcher.h b/clang-tools-extra/clang-tidy/abseil/AbseilMatcher.h index 1827f54a2bc064819fbfb6d1752af796621097d8..1eef86ddc00b955e0984cf23b2a371036578de77 100644 --- a/clang-tools-extra/clang-tidy/abseil/AbseilMatcher.h +++ b/clang-tools-extra/clang-tidy/abseil/AbseilMatcher.h @@ -52,7 +52,7 @@ AST_POLYMORPHIC_MATCHER( "profiling", "random", "status", "strings", "synchronization", "time", "types", "utility"}; return llvm::any_of(AbseilLibraries, [&](const char *Library) { - return Path.startswith(Library); + return Path.starts_with(Library); }); } diff --git a/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp b/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp index 74ef6e67f00f34213c070253c2feba7869b7ff76..4a6f17ed5f86891088e24a71382e1745cba71f25 100644 --- a/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp @@ -27,7 +27,7 @@ std::optional makeCharacterLiteral(const StringLiteral *Literal, assert(Literal->getCharByteWidth() == 1 && "StrSplit doesn't support wide char"); std::string Result = clang::tooling::fixit::getText(*Literal, Context).str(); - bool IsRawStringLiteral = StringRef(Result).startswith(R"(R")"); + bool IsRawStringLiteral = StringRef(Result).starts_with(R"(R")"); // Since raw string literal might contain unescaped non-printable characters, // we normalize them using `StringLiteral::outputString`. if (IsRawStringLiteral) { diff --git a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp index 2a367d737742dca9756c0ab0a7545258a2c960bf..8cdd5d0a564675aa7264f72cdf8984b02ef8d41d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp @@ -185,7 +185,7 @@ static bool sameName(StringRef InComment, StringRef InDecl, bool StrictMode) { static bool looksLikeExpectMethod(const CXXMethodDecl *Expect) { return Expect != nullptr && Expect->getLocation().isMacroID() && Expect->getNameInfo().getName().isIdentifier() && - Expect->getName().startswith("gmock_"); + Expect->getName().starts_with("gmock_"); } static bool areMockAndExpectMethods(const CXXMethodDecl *Mock, const CXXMethodDecl *Expect) { diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp index 7b02576a6093cb0eae04b1f6a717d0ce17005258..84e99c7fafc74b2930bea63155fa3a1506152713 100644 --- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp @@ -1550,7 +1550,7 @@ static bool isIgnoredParameter(const TheCheck &Check, const ParmVarDecl *Node) { if (!NodeTypeName.empty()) { if (llvm::any_of(Check.IgnoredParameterTypeSuffixes, [NodeTypeName](StringRef E) { - return !E.empty() && NodeTypeName.endswith(E); + return !E.empty() && NodeTypeName.ends_with(E); })) { LLVM_DEBUG(llvm::dbgs() << "\tType suffix ignored.\n"); return true; diff --git a/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp index 44db5029fd993629d43e11834668b30729b1ae05..977241e91b9a93b00a1572bbdd8e9df6c0581c67 100644 --- a/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/NotNullTerminatedResultCheck.cpp @@ -385,7 +385,7 @@ static bool isDestExprFix(const MatchFinder::MatchResult &Result, std::string TempTyStr = Dest->getType().getAsString(); StringRef TyStr = TempTyStr; - if (TyStr.startswith("char") || TyStr.startswith("wchar_t")) + if (TyStr.starts_with("char") || TyStr.starts_with("wchar_t")) return false; Diag << FixItHint::CreateInsertion(Dest->getBeginLoc(), "(char *)"); @@ -721,8 +721,8 @@ void NotNullTerminatedResultCheck::registerMatchers(MatchFinder *Finder) { // Try to match with 'wchar_t' based function calls. std::string WcharHandlerFuncName = - "::" + (CC.Name.startswith("mem") ? "w" + CC.Name.str() - : "wcs" + CC.Name.substr(3).str()); + "::" + (CC.Name.starts_with("mem") ? "w" + CC.Name.str() + : "wcs" + CC.Name.substr(3).str()); return allOf(callee(functionDecl( hasAnyName(CharHandlerFuncName, WcharHandlerFuncName))), @@ -820,13 +820,13 @@ void NotNullTerminatedResultCheck::check( } StringRef Name = FunctionExpr->getDirectCallee()->getName(); - if (Name.startswith("mem") || Name.startswith("wmem")) + if (Name.starts_with("mem") || Name.starts_with("wmem")) memoryHandlerFunctionFix(Name, Result); else if (Name == "strerror_s") strerror_sFix(Result); - else if (Name.endswith("ncmp")) + else if (Name.ends_with("ncmp")) ncmpFix(Name, Result); - else if (Name.endswith("xfrm")) + else if (Name.ends_with("xfrm")) xfrmFix(Name, Result); } @@ -835,7 +835,7 @@ void NotNullTerminatedResultCheck::memoryHandlerFunctionFix( if (isCorrectGivenLength(Result)) return; - if (Name.endswith("chr")) { + if (Name.ends_with("chr")) { memchrFix(Name, Result); return; } @@ -849,13 +849,13 @@ void NotNullTerminatedResultCheck::memoryHandlerFunctionFix( "the result from calling '%0' is not null-terminated") << Name; - if (Name.endswith("cpy")) { + if (Name.ends_with("cpy")) { memcpyFix(Name, Result, Diag); - } else if (Name.endswith("cpy_s")) { + } else if (Name.ends_with("cpy_s")) { memcpy_sFix(Name, Result, Diag); - } else if (Name.endswith("move")) { + } else if (Name.ends_with("move")) { memmoveFix(Name, Result, Diag); - } else if (Name.endswith("move_s")) { + } else if (Name.ends_with("move_s")) { isDestCapacityFix(Result, Diag); lengthArgHandle(LengthHandleKind::Increase, Result, Diag); } diff --git a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp index 6eefde369c59e52ebd3810e26b9644002af9a153..7a06df454be99871dc170f2c0e412873d04e7a29 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp @@ -81,7 +81,7 @@ static bool hasReservedDoubleUnderscore(StringRef Name, const LangOptions &LangOpts) { if (LangOpts.CPlusPlus) return Name.contains("__"); - return Name.startswith("__"); + return Name.starts_with("__"); } static std::optional diff --git a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp index fd3ca76e68a61bc9d41bfed9541d07a3a2429be6..902490f4d33c13bd3eb1f7addae6995937d0089c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SignalHandlerCheck.cpp @@ -282,7 +282,7 @@ bool isStandardFunction(const FunctionDecl *FD) { /// and every other statement that is declared in file ExprCXX.h. bool isCXXOnlyStmt(const Stmt *S) { StringRef Name = S->getStmtClassName(); - if (Name.startswith("CXX")) + if (Name.starts_with("CXX")) return true; // Check for all other class names in ExprCXX.h that have no 'CXX' prefix. return isagetBeginLoc())).endswith(".c")) + if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc())) + .ends_with(".c")) return; // Leave type spelling exactly as it was (unlike diff --git a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp index ce57b9fc3cac10a5af6a7095d44487253f918978..805dcaf3ce4025274368993b004fdc48c322e69b 100644 --- a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp @@ -66,7 +66,7 @@ public: // recent enough version of Google Test. llvm::StringRef FileName = PP->getSourceManager().getFilename( MD->getMacroInfo()->getDefinitionLoc()); - ReplacementFound = FileName.endswith("gtest/gtest-typed-test.h") && + ReplacementFound = FileName.ends_with("gtest/gtest-typed-test.h") && PP->getSpelling(MacroNameTok) == "TYPED_TEST_SUITE"; } } @@ -102,7 +102,7 @@ private: llvm::StringRef FileName = PP->getSourceManager().getFilename( MD.getMacroInfo()->getDefinitionLoc()); - if (!FileName.endswith("gtest/gtest-typed-test.h")) + if (!FileName.ends_with("gtest/gtest-typed-test.h")) return; DiagnosticBuilder Diag = Check->diag(Loc, RenameCaseToSuiteMessage); diff --git a/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp b/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp index 2f4913b2d435ac2bfa114399e94b66f6ccd83b66..c97bd48e6c3e3aff904db2d715255e1506fe465e 100644 --- a/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp @@ -40,7 +40,7 @@ void UsingNamespaceDirectiveCheck::check( bool UsingNamespaceDirectiveCheck::isStdLiteralsNamespace( const NamespaceDecl *NS) { - if (!NS->getName().endswith("literals")) + if (!NS->getName().ends_with("literals")) return false; const auto *Parent = dyn_cast_or_null(NS->getParent()); diff --git a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp index 8d35ff56de781dff19be30b9590cbe448ebe9431..42d358a15083ab038f6b9eed73d7a6c4d52fe7ac 100644 --- a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp @@ -54,11 +54,11 @@ std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename, std::replace(Guard.begin(), Guard.end(), '-', '_'); // The prevalent style in clang is LLVM_CLANG_FOO_BAR_H - if (StringRef(Guard).startswith("clang")) + if (StringRef(Guard).starts_with("clang")) Guard = "LLVM_" + Guard; // The prevalent style in flang is FORTRAN_FOO_BAR_H - if (StringRef(Guard).startswith("flang")) + if (StringRef(Guard).starts_with("flang")) Guard = "FORTRAN" + Guard.substr(sizeof("flang") - 1); return StringRef(Guard).upper(); diff --git a/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp b/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp index 3fb2e8daaebed9c9bb1dea517517eea1a8bd6d88..bdd72f85e2a27c66a611ddbf879b88cc230acd3b 100644 --- a/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp @@ -61,13 +61,13 @@ static int getPriority(StringRef Filename, bool IsAngled, bool IsMainModule) { return 0; // LLVM and clang headers are in the penultimate position. - if (Filename.startswith("llvm/") || Filename.startswith("llvm-c/") || - Filename.startswith("clang/") || Filename.startswith("clang-c/")) + if (Filename.starts_with("llvm/") || Filename.starts_with("llvm-c/") || + Filename.starts_with("clang/") || Filename.starts_with("clang-c/")) return 2; // Put these between system and llvm headers to be consistent with LLVM // clang-format style. - if (Filename.startswith("gtest/") || Filename.startswith("gmock/")) + if (Filename.starts_with("gtest/") || Filename.starts_with("gmock/")) return 3; // System headers are sorted to the end. diff --git a/clang-tools-extra/clang-tidy/misc/ConfusableTable/BuildConfusableTable.cpp b/clang-tools-extra/clang-tidy/misc/ConfusableTable/BuildConfusableTable.cpp index 79ebb2387179ea4f5e433e1897616f793a01522f..e269ab3983f36cfe53e3806d95547d647aec2aa5 100644 --- a/clang-tools-extra/clang-tidy/misc/ConfusableTable/BuildConfusableTable.cpp +++ b/clang-tools-extra/clang-tidy/misc/ConfusableTable/BuildConfusableTable.cpp @@ -27,7 +27,7 @@ int main(int argc, char *argv[]) { std::vector>> Entries; SmallVector Values; for (StringRef Line : Lines) { - if (Line.startswith("#")) + if (Line.starts_with("#")) continue; Values.clear(); diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 5ae6caedb7f4c0368c755ae9d9dc89d1b6f8400a..5e7a0e65690b7aaa704cf5c033eb92c2a11127bc 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -180,7 +180,7 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { // Since most private -> public mappings happen in a verbatim way, we // check textually here. This might go wrong in presence of symlinks or // header mappings. But that's not different than rest of the places. - if (getCurrentMainFile().endswith(PHeader)) + if (getCurrentMainFile().ends_with(PHeader)) continue; } auto StdHeader = tooling::stdlib::Header::named( diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index fa8343220dd05a399a8358d80f81014793fefa69..6bb9a349d69b13f22d587cd4fa8120c4f8f6f2ae 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -1285,7 +1285,7 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) { const auto Diag = diag(Op->getExprLoc(), Message); for (const auto &KeyValue : Result.Nodes.getMap()) { - if (StringRef(KeyValue.first).startswith("duplicate")) + if (StringRef(KeyValue.first).starts_with("duplicate")) Diag << KeyValue.second.getSourceRange(); } } diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp index e7e01bab0e9d5233c1a2ac1fa337833f938940a7..c0bf4903ec3911af762abf99f71d89947b09b732 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp @@ -849,14 +849,14 @@ std::string VariableNamer::createIndexName() { ContainerName = TheContainer->getName(); size_t Len = ContainerName.size(); - if (Len > 1 && ContainerName.endswith(Style == NS_UpperCase ? "S" : "s")) { + if (Len > 1 && ContainerName.ends_with(Style == NS_UpperCase ? "S" : "s")) { IteratorName = std::string(ContainerName.substr(0, Len - 1)); // E.g.: (auto thing : things) if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName()) return IteratorName; } - if (Len > 2 && ContainerName.endswith(Style == NS_UpperCase ? "S_" : "s_")) { + if (Len > 2 && ContainerName.ends_with(Style == NS_UpperCase ? "S_" : "s_")) { IteratorName = std::string(ContainerName.substr(0, Len - 2)); // E.g.: (auto thing : things_) if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName()) diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp index f5d13f31d7a644ddc6e55936910ba2ecd9df4764..6a295dbfd05820cc1f5a14b804ca174280fc26f7 100644 --- a/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp @@ -83,7 +83,7 @@ void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult &Result) { StringRef ContainerText = Lexer::getSourceText( CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()), *Result.SourceManager, getLangOpts()); - if (ContainerText.startswith("std::")) + if (ContainerText.starts_with("std::")) NewName = "std::" + NewName; Diag << FixItHint::CreateRemoval(MatchedDecl->getSourceRange()); diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp index b85dde5644d313fcb6d4e7c3c97610a9fd2491b2..4438f0b22063f5c7650769bee9b25b3819147448 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp @@ -41,11 +41,11 @@ AST_MATCHER_P(NamedDecl, hasAnyNameIgnoringTemplates, std::vector, // FullNameTrimmed matches any of the given Names. const StringRef FullNameTrimmedRef = FullNameTrimmed; for (const StringRef Pattern : Names) { - if (Pattern.startswith("::")) { + if (Pattern.starts_with("::")) { if (FullNameTrimmed == Pattern) return true; - } else if (FullNameTrimmedRef.endswith(Pattern) && - FullNameTrimmedRef.drop_back(Pattern.size()).endswith("::")) { + } else if (FullNameTrimmedRef.ends_with(Pattern) && + FullNameTrimmedRef.drop_back(Pattern.size()).ends_with("::")) { return true; } } diff --git a/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp index 299d4539a6ddcb01045f671b3e82891d0a2611af..6de80dcb99c60d374cc1362675f9a64c45ccd270 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp @@ -20,7 +20,7 @@ static bool doesNoDiscardMacroExist(ASTContext &Context, const llvm::StringRef &MacroId) { // Don't check for the Macro existence if we are using an attribute // either a C++17 standard attribute or pre C++17 syntax - if (MacroId.startswith("[[") || MacroId.startswith("__attribute__")) + if (MacroId.starts_with("[[") || MacroId.starts_with("__attribute__")) return true; // Otherwise look up the macro name in the context to see if its defined. diff --git a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp index b47ce2b066c65298ccd98afc8779bee6a87b9b43..7911583db30e450bbadc2225c521396ef7849204 100644 --- a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp +++ b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp @@ -62,7 +62,7 @@ public: // Parse the extra command line args. // FIXME: This is very limited at the moment. for (StringRef Arg : Args) - if (Arg.startswith("-checks=")) + if (Arg.starts_with("-checks=")) OverrideOptions.Checks = std::string(Arg.substr(strlen("-checks="))); auto Options = std::make_unique( diff --git a/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp b/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp index 4a3e43bda9172f44a812df0a767e4d89e7f585de..3e77a204d753eb2e3906ef2e93833fd2fbcdcab7 100644 --- a/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp @@ -59,17 +59,17 @@ static StringRef trySuggestX86(StringRef Name) { return {}; // [simd.alg] - if (Name.startswith("max_")) + if (Name.starts_with("max_")) return "$simd::max"; - if (Name.startswith("min_")) + if (Name.starts_with("min_")) return "$simd::min"; // [simd.binary] - if (Name.startswith("add_")) + if (Name.starts_with("add_")) return "operator+ on $simd objects"; - if (Name.startswith("sub_")) + if (Name.starts_with("sub_")) return "operator- on $simd objects"; - if (Name.startswith("mul_")) + if (Name.starts_with("mul_")) return "operator* on $simd objects"; return {}; diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp index d8dbaa7c9d73c419f5641a4dc3f02549a7f82b72..81ca33cbbdfb4b5461b54b8a0b5903c0d1186942 100644 --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp @@ -79,7 +79,7 @@ static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM, SourceRange TokRange(Loc, TokEndLoc); StringRef Comment = Lexer::getSourceText( CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts()); - if (Comment.startswith("/*") && Comment.contains('\n')) { + if (Comment.starts_with("/*") && Comment.contains('\n')) { // Multi-line block comment, insert brace before. break; } diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index 18c5e144e46fe77a00e06752b008a09d4bee5e34..03dcfa5f811095b0b2045a84c658c2d6828c62da 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -889,7 +889,7 @@ bool IdentifierNamingCheck::matchesStyle( // Ensure the name doesn't have any extra underscores beyond those specified // in the prefix and suffix. - if (Name.startswith("_") || Name.endswith("_")) + if (Name.starts_with("_") || Name.ends_with("_")) return false; if (Style.Case && !Matchers[static_cast(*Style.Case)].match(Name)) diff --git a/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp b/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp index 9140b1f51631bb3fe26a7c66bcb14da19d39aca7..ca6503753f6b45a32ae4b9fa8f95124ead2e22e9 100644 --- a/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp @@ -235,7 +235,7 @@ createIsolatedDecls(llvm::ArrayRef Snippets) { for (std::size_t I = 1; I < Snippets.size(); ++I) Decls[I - 1] = Twine(Snippets[0]) - .concat(Snippets[0].endswith(" ") ? "" : " ") + .concat(Snippets[0].ends_with(" ") ? "" : " ") .concat(Snippets[I].ltrim()) .concat(";") .str(); diff --git a/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp b/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp index 68e9dd4998473b5bb4ec928685350e627a33c911..120ec02e9ad7dc8caa7544e5757f1068fea1a4ab 100644 --- a/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp @@ -160,7 +160,7 @@ void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) { } // Otherwise we need to fix the comment. - NeedLineBreak = Comment.startswith("/*"); + NeedLineBreak = Comment.starts_with("/*"); OldCommentRange = SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength())); Message = @@ -168,7 +168,7 @@ void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) { "%0 ends with a comment that refers to a wrong namespace '") + NamespaceNameInComment + "'") .str(); - } else if (Comment.startswith("//")) { + } else if (Comment.starts_with("//")) { // Assume that this is an unrecognized form of a namespace closing line // comment. Replace it. NeedLineBreak = false; diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp index 93c31d80c11381efeb6f8b6b42a9265afa825fc5..65356cc3929c54e7a28d2c63e2244d60a53d4dc3 100644 --- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp @@ -85,7 +85,7 @@ void StaticAccessedThroughInstanceCheck::check( return; // Do not warn for CUDA built-in variables. - if (StringRef(BaseTypeName).startswith("__cuda_builtin_")) + if (StringRef(BaseTypeName).starts_with("__cuda_builtin_")) return; SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc(); diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index 0d2593e74f052b9a3259d40f7e85387ec6524dcc..9f3d6b6db6cbca1b0cc9aa3b7c71b4746f34d712 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -462,7 +462,7 @@ static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob, if (Cur.empty()) continue; Cur.consume_front("-"); - if (Cur.startswith("clang-diagnostic")) + if (Cur.starts_with("clang-diagnostic")) continue; if (Cur.contains('*')) { SmallString<128> RegexText("^"); diff --git a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp index eb21827bdeba3ccca719501e27361bd3a0ea7636..b6d9c50d0b109c1c24323e304500165a607287d3 100644 --- a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp +++ b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp @@ -19,7 +19,7 @@ namespace { StringRef removeFirstSuffix(StringRef Str, ArrayRef Suffixes) { for (StringRef Suffix : Suffixes) { - if (Str.endswith(Suffix)) { + if (Str.ends_with(Suffix)) { return Str.substr(0, Str.size() - Suffix.size()); } } @@ -73,12 +73,12 @@ determineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile, if (IsAngled) { // If the system include () ends with ".h", then it is a normal C-style // include. Otherwise assume it is a C++-style extensionless include. - return IncludeFile.endswith(".h") ? IncludeSorter::IK_CSystemInclude - : IncludeSorter::IK_CXXSystemInclude; + return IncludeFile.ends_with(".h") ? IncludeSorter::IK_CSystemInclude + : IncludeSorter::IK_CXXSystemInclude; } StringRef CanonicalInclude = makeCanonicalName(IncludeFile, Style); - if (CanonicalFile.endswith(CanonicalInclude) - || CanonicalInclude.endswith(CanonicalFile)) { + if (CanonicalFile.ends_with(CanonicalInclude) || + CanonicalInclude.ends_with(CanonicalFile)) { return IncludeSorter::IK_MainTUInclude; } if ((Style == IncludeSorter::IS_Google) || @@ -95,8 +95,9 @@ determineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile, } } if (Style == IncludeSorter::IS_Google_ObjC) { - if (IncludeFile.endswith(".generated.h") || - IncludeFile.endswith(".proto.h") || IncludeFile.endswith(".pbobjc.h")) { + if (IncludeFile.ends_with(".generated.h") || + IncludeFile.ends_with(".proto.h") || + IncludeFile.ends_with(".pbobjc.h")) { return IncludeSorter::IK_GeneratedInclude; } } diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h index 386ea738fbba5088ba5ec57e988f4e4acf48139c..045e3ffbb6a8b45e0b24f877501fbc2d05493465 100644 --- a/clang-tools-extra/clang-tidy/utils/Matchers.h +++ b/clang-tools-extra/clang-tidy/utils/Matchers.h @@ -120,7 +120,7 @@ private: private: MatchMode determineMatchMode(llvm::StringRef Regex) { - if (Regex.startswith(":") || Regex.startswith("^:")) { + if (Regex.starts_with(":") || Regex.starts_with("^:")) { return MatchMode::MatchFullyQualified; } return Regex.contains(":") ? MatchMode::MatchQualified diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 5b81ec213ff9844688d6b2db86b774ab5b60b3c5..ae79eb21de9470fa3a82aa24c0b147a9625b34b5 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -193,7 +193,7 @@ std::string printQualifiedName(const NamedDecl &ND) { Policy.AnonymousTagLocations = false; ND.printQualifiedName(OS, Policy); OS.flush(); - assert(!StringRef(QName).startswith("::")); + assert(!StringRef(QName).starts_with("::")); return QName; } @@ -696,7 +696,7 @@ std::string getQualification(ASTContext &Context, const NamedDecl *ND, llvm::ArrayRef VisibleNamespaces) { for (llvm::StringRef NS : VisibleNamespaces) { - assert(NS.endswith("::")); + assert(NS.ends_with("::")); (void)NS; } return getQualification( diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 13d788162817fb4c1833831eb634a4a988afec03..6fb2641e8793db183bd1e7f4714eb31d6c2bf32c 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -437,7 +437,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()}; // FIXME: Add traling new line if there is none at eof, workaround a crash, // see https://github.com/clangd/clangd/issues/332 - if (!IP->Contents.endswith("\n")) + if (!IP->Contents.ends_with("\n")) ParseInput.Contents.append("\n"); ParseInput.Index = Index; @@ -488,7 +488,7 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos, ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()}; // FIXME: Add traling new line if there is none at eof, workaround a crash, // see https://github.com/clangd/clangd/issues/332 - if (!IP->Contents.endswith("\n")) + if (!IP->Contents.ends_with("\n")) ParseInput.Contents.append("\n"); ParseInput.Index = Index; CB(clangd::signatureHelp(File, Pos, *PreambleData, ParseInput, @@ -661,7 +661,7 @@ void ClangdServer::codeAction(const CodeActionInputs &Params, return true; return llvm::any_of(Only, [&](llvm::StringRef Base) { return Kind.consume_front(Base) && - (Kind.empty() || Kind.startswith(".")); + (Kind.empty() || Kind.starts_with(".")); }); }; diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 5eef43e93cb519f9944c9fff0432f8ca7b1f8792..0e5f08cec440cefc0a7169ba00d66c88726d0ab6 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -610,7 +610,7 @@ private: // foo<${1:class}>(${2:int p1}). // We transform this pattern to '<$1>()$0' or '<$0>()'. - bool EmptyArgs = llvm::StringRef(*Snippet).endswith("()"); + bool EmptyArgs = llvm::StringRef(*Snippet).ends_with("()"); if (Snippet->front() == '<') return EmptyArgs ? "<$1>()$0" : "<$1>($0)"; if (Snippet->front() == '(') @@ -625,7 +625,7 @@ private: // Classes and template using aliases can only have template arguments, // e.g. Foo<${1:class}>. - if (llvm::StringRef(*Snippet).endswith("<>")) + if (llvm::StringRef(*Snippet).ends_with("<>")) return "<>"; // can happen with defaulted template arguments. return "<$0>"; } @@ -1748,7 +1748,7 @@ public: S.append("::"); // visibleNamespaces doesn't include trailing ::. if (HeuristicPrefix.Qualifier.empty()) AllScopes = Opts.AllScopes; - else if (HeuristicPrefix.Qualifier.startswith("::")) { + else if (HeuristicPrefix.Qualifier.starts_with("::")) { Scopes.QueryScopes = {""}; Scopes.UnresolvedQualifier = std::string(HeuristicPrefix.Qualifier.drop_front(2)); @@ -2130,7 +2130,7 @@ CompletionPrefix guessCompletionPrefix(llvm::StringRef Content, Result.Name = Content.slice(Rest.size(), Offset); // Consume qualifiers. - while (Rest.consume_back("::") && !Rest.endswith(":")) // reject :::: + while (Rest.consume_back("::") && !Rest.ends_with(":")) // reject :::: while (!Rest.empty() && isAsciiIdentifierContinue(Rest.back())) Rest = Rest.drop_back(); Result.Qualifier = @@ -2175,7 +2175,7 @@ CodeCompleteResult codeCompleteComment(PathRef FileName, unsigned Offset, Result.CompletionRange = CompletionRange; Result.Context = CodeCompletionContext::CCC_NaturalLanguage; for (llvm::StringRef Name : ParamNames) { - if (!Name.startswith(Prefix)) + if (!Name.starts_with(Prefix)) continue; CodeCompletion Item; Item.Name = Name.str() + "=*/"; @@ -2197,7 +2197,7 @@ maybeFunctionArgumentCommentStart(llvm::StringRef Content) { while (!Content.empty() && isAsciiIdentifierContinue(Content.back())) Content = Content.drop_back(); Content = Content.rtrim(); - if (Content.endswith("/*")) + if (Content.ends_with("/*")) return Content.size() - 2; return std::nullopt; } @@ -2408,12 +2408,12 @@ bool allowImplicitCompletion(llvm::StringRef Content, unsigned Offset) { Content = Content.substr(Pos + 1); // Complete after scope operators. - if (Content.endswith(".") || Content.endswith("->") || - Content.endswith("::") || Content.endswith("/*")) + if (Content.ends_with(".") || Content.ends_with("->") || + Content.ends_with("::") || Content.ends_with("/*")) return true; // Complete after `#include <` and #include `clear(); diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp index e116a739774b85e09dcdef391519c476ab4daad8..f43ce928463b90cd2e863fff34be2ad418215218 100644 --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -338,7 +338,7 @@ void CommandMangler::operator()(tooling::CompileCommand &Command, }; llvm::erase_if(Cmd, [](llvm::StringRef Elem) { - return Elem.startswith("--save-temps") || Elem.startswith("-save-temps"); + return Elem.starts_with("--save-temps") || Elem.starts_with("-save-temps"); }); std::vector ToAppend; @@ -587,7 +587,7 @@ const ArgStripper::Rule *ArgStripper::matchingRule(llvm::StringRef Arg, continue; // not applicable to current driver mode if (BestRule && BestRule->Priority < R.Priority) continue; // lower-priority than best candidate. - if (!Arg.startswith(R.Text)) + if (!Arg.starts_with(R.Text)) continue; // current arg doesn't match the prefix string bool PrefixMatch = Arg.size() > R.Text.size(); // Can rule apply as an exact/prefix match? diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 0c9fc27643be87a7e4883a9d5a1d3797b10d31ad..5bb2eb4a9f803fb805244f87c139ac4cb4cdb2c5 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -490,7 +490,7 @@ struct FragmentCompiler { StringRef Str = StringRef(*Arg).trim(); // Don't support negating here, its handled if the item is in the Add or // Remove list. - if (Str.startswith("-") || Str.contains(',')) { + if (Str.starts_with("-") || Str.contains(',')) { diag(Error, "Invalid clang-tidy check name", Arg.Range); return; } diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index 85f2592445f2a52449cb7f595dec7ab01649ce0d..b0cec65c39fa31dc641b395d43f7d3c4935af395 100644 --- a/clang-tools-extra/clangd/DumpAST.cpp +++ b/clang-tools-extra/clangd/DumpAST.cpp @@ -118,8 +118,8 @@ class DumpVisitor : public RecursiveASTVisitor { std::string getKind(const Decl *D) { return D->getDeclKindName(); } std::string getKind(const Stmt *S) { std::string Result = S->getStmtClassName(); - if (llvm::StringRef(Result).endswith("Stmt") || - llvm::StringRef(Result).endswith("Expr")) + if (llvm::StringRef(Result).ends_with("Stmt") || + llvm::StringRef(Result).ends_with("Expr")) Result.resize(Result.size() - 4); return Result; } diff --git a/clang-tools-extra/clangd/FileDistance.cpp b/clang-tools-extra/clangd/FileDistance.cpp index 09a9e80b7847a6a442d966192f74394f9d2ffad6..06c1a8bc92a862a6870df95039acc33334be9d5b 100644 --- a/clang-tools-extra/clangd/FileDistance.cpp +++ b/clang-tools-extra/clangd/FileDistance.cpp @@ -201,7 +201,7 @@ createScopeFileDistance(llvm::ArrayRef QueryScopes) { // place of enclosing namespaces (e.g. in implementation files). if (S == Preferred) Param.Cost = S == "" ? 4 : 0; - else if (Preferred.startswith(S) && !S.empty()) + else if (Preferred.starts_with(S) && !S.empty()) continue; // just rely on up-traversals. else Param.Cost = S == "" ? 6 : 2; diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp index 790ee9af8f4acfc8dbd12f764b9c5f51cc12bfd8..5b3e46a7b4dc167604a620540dae04f052487b78 100644 --- a/clang-tools-extra/clangd/FindSymbols.cpp +++ b/clang-tools-extra/clangd/FindSymbols.cpp @@ -41,8 +41,8 @@ struct ScoredSymbolGreater { // Returns true if \p Query can be found as a sub-sequence inside \p Scope. bool approximateScopeMatch(llvm::StringRef Scope, llvm::StringRef Query) { - assert(Scope.empty() || Scope.endswith("::")); - assert(Query.empty() || Query.endswith("::")); + assert(Scope.empty() || Scope.ends_with("::")); + assert(Query.empty() || Query.ends_with("::")); while (!Scope.empty() && !Query.empty()) { auto Colons = Scope.find("::"); assert(Colons != llvm::StringRef::npos); diff --git a/clang-tools-extra/clangd/Format.cpp b/clang-tools-extra/clangd/Format.cpp index c3e92636d1957285f00c2e6b82d43ea5b225e154..272a34d4ed79724fda8a8a4c99597ecfff99fc00 100644 --- a/clang-tools-extra/clangd/Format.cpp +++ b/clang-tools-extra/clangd/Format.cpp @@ -180,7 +180,7 @@ IncrementalChanges getIncrementalChangesAfterNewline(llvm::StringRef Code, bool NewLineIsComment = !commentMarker(Indentation).empty(); if (!CommentMarker.empty() && (NewLineIsComment || !commentMarker(NextLine).empty() || - (!TrailingTrim.empty() && !TrailingTrim.startswith("//")))) { + (!TrailingTrim.empty() && !TrailingTrim.starts_with("//")))) { // We indent the new comment to match the previous one. StringRef PreComment = Leading.take_front(CommentMarker.data() - Leading.data()); @@ -197,8 +197,8 @@ IncrementalChanges getIncrementalChangesAfterNewline(llvm::StringRef Code, } // If we put a the newline inside a {} pair, put } on its own line... - if (CommentMarker.empty() && Leading.endswith("{") && - Trailing.startswith("}")) { + if (CommentMarker.empty() && Leading.ends_with("{") && + Trailing.starts_with("}")) { cantFail( Result.Changes.add(replacement(Code, Trailing.take_front(1), "\n}"))); // ...and format it. diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp index 6005069be01160df40bcd2e24c4c83995e915113..076e636e0e2819a05ac7cb08909de62c74dc9a31 100644 --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -82,7 +82,7 @@ public: if (File) { auto IncludingFileEntry = SM.getFileEntryRefForID(SM.getFileID(HashLoc)); if (!IncludingFileEntry) { - assert(SM.getBufferName(HashLoc).startswith("<") && + assert(SM.getBufferName(HashLoc).starts_with("<") && "Expected #include location to be a file or "); // Treat as if included from the main file. IncludingFileEntry = SM.getFileEntryRefForID(MainFID); @@ -131,7 +131,7 @@ private: }; bool isLiteralInclude(llvm::StringRef Include) { - return Include.startswith("<") || Include.startswith("\""); + return Include.starts_with("<") || Include.starts_with("\""); } bool HeaderFile::valid() const { @@ -316,7 +316,7 @@ IncludeInserter::insert(llvm::StringRef VerbatimHeader, std::optional Edit; if (auto Insertion = Inserter.insert(VerbatimHeader.trim("\"<>"), - VerbatimHeader.startswith("<"), Directive)) + VerbatimHeader.starts_with("<"), Directive)) Edit = replacementToEdit(Code, *Insertion); return Edit; } diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index a868d3bb4e3fa1d0a26ab02611efdc11e37bd699..82323fe16c82b6e4e72905e6fbd4b32946f9dcf6 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -960,7 +960,7 @@ std::optional getHoverContents(const Attr *A, ParsedAST &AST) { } bool isParagraphBreak(llvm::StringRef Rest) { - return Rest.ltrim(" \t").startswith("\n"); + return Rest.ltrim(" \t").starts_with("\n"); } bool punctuationIndicatesLineBreak(llvm::StringRef Line) { @@ -984,7 +984,7 @@ bool isHardLineBreakIndicator(llvm::StringRef Rest) { if (llvm::isDigit(Rest.front())) { llvm::StringRef AfterDigit = Rest.drop_while(llvm::isDigit); - if (AfterDigit.startswith(".") || AfterDigit.startswith(")")) + if (AfterDigit.starts_with(".") || AfterDigit.starts_with(")")) return true; } return false; diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp index dda7c9f581f69c7b03517416b2ce2f08cb279d79..2f34c949349200337329b4456aff03dc891c4c57 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -95,7 +95,7 @@ bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST, // Since most private -> public mappings happen in a verbatim way, we // check textually here. This might go wrong in presence of symlinks or // header mappings. But that's not different than rest of the places. - if (AST.tuPath().endswith(PHeader)) + if (AST.tuPath().ends_with(PHeader)) return false; } } diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp index 0c4d011b80372ba95dfdda7b8b2f299b90bc943f..fadd1105691fc01e183ee19e8d66cbb482eaf45d 100644 --- a/clang-tools-extra/clangd/IncludeFixer.cpp +++ b/clang-tools-extra/clangd/IncludeFixer.cpp @@ -416,7 +416,7 @@ std::optional extractUnresolvedNameCheaply( // namespace clang { clangd::X; } // In this case, we use the "typo" specifier as extra scope instead // of using the scope assumed by sema. - if (!Spelling || llvm::StringRef(SpecifiedNS).endswith(*Spelling)) { + if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) { Result.ResolvedScope = std::move(SpecifiedNS); } else { Result.UnresolvedScope = std::move(*Spelling); diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index b540c273cbd59672b07c8eede970e2824f17ca53..6fbb310b660a178540707cb7a2cb27d6599418d5 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -1040,7 +1040,7 @@ private: if (!SourcePrefix.consume_back(ParamName)) return false; SourcePrefix = SourcePrefix.rtrim(IgnoreChars); - return SourcePrefix.endswith("/*"); + return SourcePrefix.ends_with("/*"); } // If "E" spells a single unqualified identifier, return that name. diff --git a/clang-tools-extra/clangd/JSONTransport.cpp b/clang-tools-extra/clangd/JSONTransport.cpp index 9dc0df807aa3463116093cdee3610bd759538529..346c7dfb66a1dbb01709e31ed6386470f42749b4 100644 --- a/clang-tools-extra/clangd/JSONTransport.cpp +++ b/clang-tools-extra/clangd/JSONTransport.cpp @@ -240,7 +240,7 @@ bool JSONTransport::readStandardMessage(std::string &JSON) { // We allow comments in headers. Technically this isn't part // of the LSP specification, but makes writing tests easier. - if (LineRef.startswith("#")) + if (LineRef.starts_with("#")) continue; // Content-Length is a mandatory header, and the only one we handle. @@ -304,7 +304,7 @@ bool JSONTransport::readDelimitedMessage(std::string &JSON) { while (readLine(In, Line)) { InMirror << Line; auto LineRef = Line.str().trim(); - if (LineRef.startswith("#")) // comment + if (LineRef.starts_with("#")) // comment continue; // found a delimiter diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index edd0f77b1031ef03e4da50a87948883ff671e74f..d91ce7283ecee44d5d3895c3431cc9f581b913f2 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -288,7 +288,7 @@ public: if (Glob) { // Is this clang-diagnostic-*, or *, or so? // (We ignore all other types of globs). - if (CDPrefix.startswith(Check)) { + if (CDPrefix.starts_with(Check)) { Default = Enable; Exceptions.clear(); } diff --git a/clang-tools-extra/clangd/PathMapping.cpp b/clang-tools-extra/clangd/PathMapping.cpp index 2554d34d96b9dfdb323f567a4465f9d9454c2169..4b93ff2c60c5c6035920c4cae17f7d77a9485b9d 100644 --- a/clang-tools-extra/clangd/PathMapping.cpp +++ b/clang-tools-extra/clangd/PathMapping.cpp @@ -21,7 +21,7 @@ std::optional doPathMapping(llvm::StringRef S, PathMapping::Direction Dir, const PathMappings &Mappings) { // Return early to optimize for the common case, wherein S is not a file URI - if (!S.startswith("file://")) + if (!S.starts_with("file://")) return std::nullopt; auto Uri = URI::parse(S); if (!Uri) { diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index e44aee2d47819468636501f62dbc68be226d225a..a6370649f5ad1cf3a1810c3499cbac0890b8363c 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -844,7 +844,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) { if (!S.containerName.empty()) { O << S.containerName; llvm::StringRef ContNameRef; - if (!ContNameRef.endswith("::")) { + if (!ContNameRef.ends_with("::")) { O << " "; } } diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp index 31323c08cf1ddf9086a1b583fcce7e5ad911f95a..835038423fdf3729ebff38e3d784262bb2dce855 100644 --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -891,10 +891,10 @@ llvm::StringSet<> collectWords(llvm::StringRef Content) { static bool isLikelyIdentifier(llvm::StringRef Word, llvm::StringRef Before, llvm::StringRef After) { // `foo` is an identifier. - if (Before.endswith("`") && After.startswith("`")) + if (Before.ends_with("`") && After.starts_with("`")) return true; // In foo::bar, both foo and bar are identifiers. - if (Before.endswith("::") || After.startswith("::")) + if (Before.ends_with("::") || After.starts_with("::")) return true; // Doxygen tags like \c foo indicate identifiers. // Don't search too far back. @@ -1180,7 +1180,7 @@ EligibleRegion getEligiblePoints(llvm::StringRef Code, } // Ignore namespaces that are not a prefix of the target. - if (!FullyQualifiedName.startswith(CurrentNamespace)) + if (!FullyQualifiedName.starts_with(CurrentNamespace)) return; // Prefer the namespace that shares the longest prefix with target. @@ -1213,14 +1213,14 @@ bool isHeaderFile(llvm::StringRef FileName, bool isProtoFile(SourceLocation Loc, const SourceManager &SM) { auto FileName = SM.getFilename(Loc); - if (!FileName.endswith(".proto.h") && !FileName.endswith(".pb.h")) + if (!FileName.ends_with(".proto.h") && !FileName.ends_with(".pb.h")) return false; auto FID = SM.getFileID(Loc); // All proto generated headers should start with this line. static const char *ProtoHeaderComment = "// Generated by the protocol buffer compiler. DO NOT EDIT!"; // Double check that this is an actual protobuf header. - return SM.getBufferData(FID).startswith(ProtoHeaderComment); + return SM.getBufferData(FID).starts_with(ProtoHeaderComment); } SourceLocation translatePreamblePatchLocation(SourceLocation Loc, @@ -1230,7 +1230,7 @@ SourceLocation translatePreamblePatchLocation(SourceLocation Loc, auto IncludeLoc = SM.getIncludeLoc(DefFile); // Preamble patch is included inside the builtin file. if (IncludeLoc.isValid() && SM.isWrittenInBuiltinFile(IncludeLoc) && - FE->getName().endswith(PreamblePatch::HeaderName)) { + FE->getName().ends_with(PreamblePatch::HeaderName)) { auto Presumed = SM.getPresumedLoc(Loc); // Check that line directive is pointing at main file. if (Presumed.isValid() && Presumed.getFileID().isInvalid() && diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp index ea98c7d948a2f6de1976fc5924fff7fa79370f40..d4b9b173d149da06946bd16bc6b88fb0074a3b4d 100644 --- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp +++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp @@ -146,13 +146,13 @@ struct DriverArgs { Stdlib = Cmd.CommandLine[I + 1]; } else if (Arg.consume_front("-stdlib=")) { Stdlib = Arg.str(); - } else if (Arg.startswith("-specs=")) { + } else if (Arg.starts_with("-specs=")) { // clang requires a single token like `-specs=file` or `--specs=file`, // but gcc will accept two tokens like `--specs file`. Since the // compilation database is presumably correct, we just forward the flags // as-is. Specs.push_back(Arg.str()); - } else if (Arg.startswith("--specs=")) { + } else if (Arg.starts_with("--specs=")) { Specs.push_back(Arg.str()); } else if (Arg == "--specs" && I + 1 < E) { Specs.push_back(Arg.str()); @@ -282,7 +282,7 @@ std::optional parseDriverOutput(llvm::StringRef Output) { if (!SeenIncludes && Line.trim() == SIS) { SeenIncludes = true; State = IncludesExtracting; - } else if (!SeenTarget && Line.trim().startswith(TS)) { + } else if (!SeenTarget && Line.trim().starts_with(TS)) { SeenTarget = true; llvm::StringRef TargetLine = Line.trim(); TargetLine.consume_front(TS); @@ -448,7 +448,7 @@ tooling::CompileCommand &setTarget(tooling::CompileCommand &Cmd, if (!Target.empty()) { // We do not want to override existing target with extracted one. for (llvm::StringRef Arg : Cmd.CommandLine) { - if (Arg == "-target" || Arg.startswith("--target=")) + if (Arg == "-target" || Arg.starts_with("--target=")) return Cmd; } // Just append when `--` isn't present. diff --git a/clang-tools-extra/clangd/URI.cpp b/clang-tools-extra/clangd/URI.cpp index ca65df329aeebf3c3d709cd9c07c9b1c52002c9f..11d70dc917f56bf9f1c191caf3850d7ed3a4f1a8 100644 --- a/clang-tools-extra/clangd/URI.cpp +++ b/clang-tools-extra/clangd/URI.cpp @@ -38,7 +38,7 @@ public: llvm::Expected getAbsolutePath(llvm::StringRef Authority, llvm::StringRef Body, llvm::StringRef /*HintPath*/) const override { - if (!Body.startswith("/")) + if (!Body.starts_with("/")) return error("File scheme: expect body to be an absolute path starting " "with '/': {0}", Body); @@ -153,7 +153,7 @@ URI::URI(llvm::StringRef Scheme, llvm::StringRef Authority, llvm::StringRef Body) : Scheme(Scheme), Authority(Authority), Body(Body) { assert(!Scheme.empty()); - assert((Authority.empty() || Body.startswith("/")) && + assert((Authority.empty() || Body.starts_with("/")) && "URI body must start with '/' when authority is present."); } @@ -165,8 +165,7 @@ std::string URI::toString() const { return Result; // If authority if empty, we only print body if it starts with "/"; otherwise, // the URI is invalid. - if (!Authority.empty() || llvm::StringRef(Body).startswith("/")) - { + if (!Authority.empty() || llvm::StringRef(Body).starts_with("/")) { Result.append("//"); percentEncode(Authority, Result); } diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp index 9687b36252e12ceeb73df70e43a791ffb402a63f..8221d4b1f44405abab5bb6fdf0a0a73783cdfee3 100644 --- a/clang-tools-extra/clangd/index/Merge.cpp +++ b/clang-tools-extra/clangd/index/Merge.cpp @@ -197,7 +197,7 @@ static bool prefer(const SymbolLocation &L, const SymbolLocation &R) { auto HasCodeGenSuffix = [](const SymbolLocation &Loc) { constexpr static const char *CodegenSuffixes[] = {".proto"}; return llvm::any_of(CodegenSuffixes, [&](llvm::StringRef Suffix) { - return llvm::StringRef(Loc.FileURI).endswith(Suffix); + return llvm::StringRef(Loc.FileURI).ends_with(Suffix); }); }; return HasCodeGenSuffix(L) && !HasCodeGenSuffix(R); diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp index b905f580c281c9f750601b2df420696732601357..72a4e8b007668f4a6629afdefecc89b764690a7b 100644 --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -692,7 +692,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const IndexFileOut &O) { llvm::Expected readIndexFile(llvm::StringRef Data, SymbolOrigin Origin) { - if (Data.startswith("RIFF")) { + if (Data.starts_with("RIFF")) { return readRIFF(Data, Origin); } if (auto YAMLContents = readYAML(Data, Origin)) { diff --git a/clang-tools-extra/clangd/index/StdLib.cpp b/clang-tools-extra/clangd/index/StdLib.cpp index 390c2e41f6c0f97d95f0feeaae7f1e411d5cefb5..921ab5d1c96d5cf0f5b36c7779667aca6a962883 100644 --- a/clang-tools-extra/clangd/index/StdLib.cpp +++ b/clang-tools-extra/clangd/index/StdLib.cpp @@ -167,7 +167,7 @@ SymbolSlab filter(SymbolSlab Slab, const StdLibLocation &Loc) { R.first->second = llvm::any_of( StdLibURIPrefixes, [&, URIStr(llvm::StringRef(URI))](const std::string &Prefix) { - return URIStr.startswith(Prefix); + return URIStr.starts_with(Prefix); }); } } diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index aac6676a995fedfd28fb12aabecf30fe76a132c7..cf6102db8dd317c4587e6b31a75a02d4406bb692 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -262,7 +262,7 @@ public: if (Canonical.empty()) return ""; // If we had a mapping, always use it. - assert(Canonical.startswith("<") || Canonical.startswith("\"")); + assert(Canonical.starts_with("<") || Canonical.starts_with("\"")); return Canonical; } @@ -414,7 +414,7 @@ private: PP->getHeaderSearchInfo())) { // A .inc or .def file is often included into a real header to define // symbols (e.g. LLVM tablegen files). - if (Filename.endswith(".inc") || Filename.endswith(".def")) + if (Filename.ends_with(".inc") || Filename.ends_with(".def")) // Don't use cache reentrantly due to iterator invalidation. return getIncludeHeaderUncached(SM.getFileID(SM.getIncludeLoc(FID))); // Conservatively refuse to insert #includes to files without guards. diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp index 8f504fb9b7ea304ef2f11d1bb1567dcdf1d7956a..19dc3080f9f897b8c85c4f501b0789378ee5ae82 100644 --- a/clang-tools-extra/clangd/index/dex/Dex.cpp +++ b/clang-tools-extra/clangd/index/dex/Dex.cpp @@ -395,7 +395,7 @@ generateProximityURIs(llvm::StringRef URI) { return Result; } // The root foo://bar/ is a proximity URI. - if (Path.startswith("/")) + if (Path.starts_with("/")) Result.push_back(URI.substr(0, Path.begin() + 1 - URI.data())); return Result; } diff --git a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp index 392960d6d6660d130b030b0f936ff385d2d804db..cea59ae409914c048d542a0dec254ee144e343fd 100644 --- a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp +++ b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp @@ -372,7 +372,7 @@ struct { }; std::unique_ptr openIndex(llvm::StringRef Index) { - return Index.startswith("remote:") + return Index.starts_with("remote:") ? remote::getClient(Index.drop_front(strlen("remote:")), ProjectRoot) : loadIndex(Index, SymbolOrigin::Static, /*UseDex=*/true); @@ -424,7 +424,7 @@ int main(int argc, const char *argv[]) { llvm::cl::ResetCommandLineParser(); // We reuse it for REPL commands. llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); - bool RemoteMode = llvm::StringRef(IndexLocation).startswith("remote:"); + bool RemoteMode = llvm::StringRef(IndexLocation).starts_with("remote:"); if (RemoteMode && ProjectRoot.empty()) { llvm::errs() << "--project-root is required in remote mode\n"; return -1; diff --git a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp index ca96da34e092011433717bc7769ba6ae46bbb783..00c05ebdb521663393d65ff2c0ce835fe54c036c 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp @@ -352,7 +352,7 @@ bool AddUsing::prepare(const Selection &Inputs) { splitQualifiedName(SpelledRange.text(SM)); QualifierToSpell = getNNSLAsString( QualifierToRemove, Inputs.AST->getASTContext().getPrintingPolicy()); - if (!llvm::StringRef(QualifierToSpell).endswith(SpelledQualifier) || + if (!llvm::StringRef(QualifierToSpell).ends_with(SpelledQualifier) || SpelledName.empty()) return false; // What's spelled doesn't match the qualifier. return true; diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index b84ae04072f2c19b2afd9098cda80b9a57ef164b..fef827a801c33974ef1118d31ccc402af0bb9c73 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -71,7 +71,7 @@ std::optional getSourceFile(llvm::StringRef FileName, // Returns std::nullopt if TargetNS is not a prefix of CurContext. std::optional findContextForNS(llvm::StringRef TargetNS, const DeclContext *CurContext) { - assert(TargetNS.empty() || TargetNS.endswith("::")); + assert(TargetNS.empty() || TargetNS.ends_with("::")); // Skip any non-namespace contexts, e.g. TagDecls, functions/methods. CurContext = CurContext->getEnclosingNamespaceContext(); // If TargetNS is empty, it means global ns, which is translation unit. @@ -91,7 +91,7 @@ findContextForNS(llvm::StringRef TargetNS, const DeclContext *CurContext) { llvm::StringRef CurrentContextNS(TargetContextNS); // If TargetNS is not a prefix of CurrentContext, there's no way to reach // it. - if (!CurrentContextNS.startswith(TargetNS)) + if (!CurrentContextNS.starts_with(TargetNS)) return std::nullopt; while (CurrentContextNS != TargetNS) { diff --git a/clang-tools-extra/clangd/support/Markup.cpp b/clang-tools-extra/clangd/support/Markup.cpp index 4d17a2bf2b2b869358e8c58e2ba6215957ed286b..63aff96b02056d3c43360c1df2536f5c0dd24eeb 100644 --- a/clang-tools-extra/clangd/support/Markup.cpp +++ b/clang-tools-extra/clangd/support/Markup.cpp @@ -47,7 +47,7 @@ bool looksLikeTag(llvm::StringRef Contents) { for (; !Contents.empty(); Contents = Contents.drop_front()) { if (llvm::isAlnum(Contents.front()) || llvm::isSpace(Contents.front())) continue; - if (Contents.front() == '>' || Contents.startswith("/>")) + if (Contents.front() == '>' || Contents.starts_with("/>")) return true; // May close the tag. if (Contents.front() == '=') return true; // Don't try to parse attribute values. @@ -75,7 +75,7 @@ bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, }; auto IsBullet = [&]() { return StartsLine && Before.empty() && - (After.empty() || After.startswith(" ")); + (After.empty() || After.starts_with(" ")); }; auto SpaceSurrounds = [&]() { return (After.empty() || llvm::isSpace(After.front())) && @@ -94,12 +94,12 @@ bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, // anywhere (including on another line). We must escape them all. return true; case '~': // Code block - return StartsLine && Before.empty() && After.startswith("~~"); + return StartsLine && Before.empty() && After.starts_with("~~"); case '#': { // ATX heading. if (!StartsLine || !Before.empty()) return false; llvm::StringRef Rest = After.ltrim(C); - return Rest.empty() || Rest.startswith(" "); + return Rest.empty() || Rest.starts_with(" "); } case ']': // Link or link reference. // We escape ] rather than [ here, because it's more constrained: @@ -109,7 +109,7 @@ bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, // ] by itself is a shortcut link // ][...] is an out-of-line link // Because we never emit link references, we don't need to handle these. - return After.startswith(":") || After.startswith("("); + return After.starts_with(":") || After.starts_with("("); case '=': // Setex heading. return RulerLength() > 0; case '_': // Horizontal ruler or matched delimiter. @@ -145,7 +145,7 @@ bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, case '.': // Numbered list indicator. Escape 12. -> 12\. at start of line. case ')': return StartsLine && !Before.empty() && - llvm::all_of(Before, llvm::isDigit) && After.startswith(" "); + llvm::all_of(Before, llvm::isDigit) && After.starts_with(" "); default: return false; } @@ -180,12 +180,12 @@ std::string renderInlineBlock(llvm::StringRef Input) { } // If results starts with a backtick, add spaces on both sides. The spaces // are ignored by markdown renderers. - if (llvm::StringRef(R).startswith("`") || llvm::StringRef(R).endswith("`")) + if (llvm::StringRef(R).starts_with("`") || llvm::StringRef(R).ends_with("`")) return "` " + std::move(R) + " `"; // Markdown render should ignore first and last space if both are there. We // add an extra pair of spaces in that case to make sure we render what the // user intended. - if (llvm::StringRef(R).startswith(" ") && llvm::StringRef(R).endswith(" ")) + if (llvm::StringRef(R).starts_with(" ") && llvm::StringRef(R).ends_with(" ")) return "` " + std::move(R) + " `"; return "`" + std::move(R) + "`"; } @@ -250,7 +250,7 @@ std::string renderBlocks(llvm::ArrayRef> Children, return !llvm::StringRef(TrimmedText.data(), &C - TrimmedText.data() + 1) // We allow at most two newlines. - .endswith("\n\n\n"); + .ends_with("\n\n\n"); }); return AdjustedResult; @@ -301,7 +301,7 @@ private: // Inserts two spaces after each `\n` to indent each line. First line is not // indented. std::string indentLines(llvm::StringRef Input) { - assert(!Input.endswith("\n") && "Input should've been trimmed."); + assert(!Input.ends_with("\n") && "Input should've been trimmed."); std::string IndentedR; // We'll add 2 spaces after each new line. IndentedR.reserve(Input.size() + Input.count('\n') * 2); diff --git a/clang-tools-extra/clangd/support/ThreadsafeFS.cpp b/clang-tools-extra/clangd/support/ThreadsafeFS.cpp index 87babef4ee8c88aaaa50461e4fe124a4cac37276..0e249d07d2fd9141bc2224d8e702aee49a59182c 100644 --- a/clang-tools-extra/clangd/support/ThreadsafeFS.cpp +++ b/clang-tools-extra/clangd/support/ThreadsafeFS.cpp @@ -39,7 +39,7 @@ public: // Try to guess preamble files, they can be memory-mapped even on Windows as // clangd has exclusive access to those and nothing else should touch them. llvm::StringRef FileName = llvm::sys::path::filename(Path); - if (FileName.startswith("preamble-") && FileName.endswith(".pch")) + if (FileName.starts_with("preamble-") && FileName.ends_with(".pch")) return File; return std::unique_ptr(new VolatileFile(std::move(*File))); } diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 9fd002d0eebba5f314d0bd953210bb9275ab58b9..c3ba655ee2dc6a7b0cb8bff5f3fd36773801f712 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -563,7 +563,7 @@ public: using namespace llvm::sys; // Still require "/" in body to mimic file scheme, as we want lengths of an // equivalent URI in both schemes to be the same. - if (!Body.startswith("/")) + if (!Body.starts_with("/")) return error( "Expect URI body to be an absolute path starting with '/': {0}", Body); diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp index e5c9fc540880689cce1653583087bdbc2f2bc000..e51942462fbdf87a32aaf3d59280c482dbd96c65 100644 --- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp @@ -132,11 +132,11 @@ TEST_F(BackgroundIndexTest, Config) { BackgroundIndex::Options Opts; Opts.ContextProvider = [](PathRef P) { Config C; - if (P.endswith("foo.cpp")) + if (P.ends_with("foo.cpp")) C.CompileFlags.Edits.push_back([](std::vector &Argv) { Argv = tooling::getInsertArgumentAdjuster("-Done=two")(Argv, ""); }); - if (P.endswith("baz.cpp")) + if (P.ends_with("baz.cpp")) C.Index.Background = Config::BackgroundPolicy::Skip; return Context::current().derive(Config::Key, std::move(C)); }; diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 692c6db3c51bedf5c6bc9e86a2a50ce232c6dbf1..6d387fec9b3851d10bda8b4164223b453242315e 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -59,7 +59,7 @@ MATCHER_P(named, Name, "") { return arg.Name == Name; } MATCHER_P(mainFileRefs, Refs, "") { return arg.MainFileRefs == Refs; } MATCHER_P(scopeRefs, Refs, "") { return arg.ScopeRefsInFile == Refs; } MATCHER_P(nameStartsWith, Prefix, "") { - return llvm::StringRef(arg.Name).startswith(Prefix); + return llvm::StringRef(arg.Name).starts_with(Prefix); } MATCHER_P(filterText, F, "") { return arg.FilterText == F; } MATCHER_P(scope, S, "") { return arg.Scope == S; } diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index a52b647b0029b4facb59f2eac7587bdadc69ea4a..37643e5afa2304d2aa7673fc5a4aa8a1ccf40f97 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -1935,7 +1935,7 @@ $fix[[ $diag[[#include "unused.h"]] Cfg.Diagnostics.UnusedIncludes = Config::IncludesPolicy::Strict; // Set filtering. Cfg.Diagnostics.Includes.IgnoreHeader.emplace_back( - [](llvm::StringRef Header) { return Header.endswith("ignore.h"); }); + [](llvm::StringRef Header) { return Header.ends_with("ignore.h"); }); WithContextValue WithCfg(Config::Key, std::move(Cfg)); auto AST = TU.build(); EXPECT_THAT( diff --git a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp index 38bf66a1e25eb57025d765eddd0d518c593e0e0b..2a6ae9c325b736c4dc6156fcb71c3a8652901579 100644 --- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp +++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp @@ -228,14 +228,14 @@ TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) { DirectoryBasedGlobalCompilationDatabase::Options Opts(FS); Opts.ContextProvider = [&](llvm::StringRef Path) { Config Cfg; - if (Path.endswith("a.cc")) { + if (Path.ends_with("a.cc")) { // a.cc uses another directory's CDB, so it won't be discovered. Cfg.CompileFlags.CDBSearch.Policy = Config::CDBSearchSpec::FixedDir; Cfg.CompileFlags.CDBSearch.FixedCDBPath = testPath("foo"); - } else if (Path.endswith("gen.cc")) { + } else if (Path.ends_with("gen.cc")) { // gen.cc has CDB search disabled, so it won't be discovered. Cfg.CompileFlags.CDBSearch.Policy = Config::CDBSearchSpec::NoCDBSearch; - } else if (Path.endswith("gen2.cc")) { + } else if (Path.ends_with("gen2.cc")) { // gen2.cc explicitly lists this directory, so it will be discovered. Cfg.CompileFlags.CDBSearch.Policy = Config::CDBSearchSpec::FixedDir; Cfg.CompileFlags.CDBSearch.FixedCDBPath = testRoot(); diff --git a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp index fad751bd0f7dc220d8ffb4434b7eefec6b1d2762..fa3d9c3212f9ca7ee1cf9de66c4f1d12b08d468e 100644 --- a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp @@ -280,7 +280,7 @@ TEST_F(IndexActionTest, SkipFiles) { auto unskippable2() { return S(); } )cpp"); Opts.FileFilter = [](const SourceManager &SM, FileID F) { - return !SM.getFileEntryRefForID(F)->getName().endswith("bad.h"); + return !SM.getFileEntryRefForID(F)->getName().ends_with("bad.h"); }; IndexFileIn IndexFile = runIndexingAction(MainFilePath, {"-std=c++14"}); EXPECT_THAT(*IndexFile.Symbols, @@ -333,7 +333,7 @@ TEST_F(IndexActionTest, SymbolFromCC) { void foo(); )cpp"); Opts.FileFilter = [](const SourceManager &SM, FileID F) { - return !SM.getFileEntryRefForID(F)->getName().endswith("main.h"); + return !SM.getFileEntryRefForID(F)->getName().ends_with("main.h"); }; IndexFileIn IndexFile = runIndexingAction(MainFilePath, {"-std=c++14"}); EXPECT_THAT(*IndexFile.Symbols, diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp index 6e91053632e00bfac1800f2771c2cbee097c53ae..0ca95b5fed5d31d4c30d2ce0bff2e0de468b9c12 100644 --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -58,8 +58,8 @@ struct ExpectedHint { MATCHER_P2(HintMatcher, Expected, Code, llvm::to_string(Expected)) { llvm::StringRef ExpectedView(Expected.Label); if (arg.label != ExpectedView.trim(" ") || - arg.paddingLeft != ExpectedView.startswith(" ") || - arg.paddingRight != ExpectedView.endswith(" ")) { + arg.paddingLeft != ExpectedView.starts_with(" ") || + arg.paddingRight != ExpectedView.ends_with(" ")) { *result_listener << "label is '" << arg.label << "'"; return false; } diff --git a/clang-tools-extra/clangd/unittests/InsertionPointTests.cpp b/clang-tools-extra/clangd/unittests/InsertionPointTests.cpp index 62c06bb863772f6a5fcb7f98582b6020019d05ef..3d5365a099f0ad586dd6be94fd62781caefafac4 100644 --- a/clang-tools-extra/clangd/unittests/InsertionPointTests.cpp +++ b/clang-tools-extra/clangd/unittests/InsertionPointTests.cpp @@ -38,7 +38,7 @@ TEST(InsertionPointTests, Generic) { [&](llvm::StringLiteral S) -> std::function { return [S](const Decl *D) { if (const auto *ND = llvm::dyn_cast(D)) - return llvm::StringRef(ND->getNameAsString()).startswith(S); + return llvm::StringRef(ND->getNameAsString()).starts_with(S); return false; }; }; diff --git a/clang-tools-extra/clangd/unittests/StdLibTests.cpp b/clang-tools-extra/clangd/unittests/StdLibTests.cpp index ef47141bade153f8ffb6d574a5bfac87fe7038e3..a39d34ea33811ae4171576b7c2ca823de53f6f87 100644 --- a/clang-tools-extra/clangd/unittests/StdLibTests.cpp +++ b/clang-tools-extra/clangd/unittests/StdLibTests.cpp @@ -126,7 +126,7 @@ TEST(StdLibTests, StdLibSet) { MATCHER_P(StdlibSymbol, Name, "") { return arg.Name == Name && arg.Includes.size() == 1 && - llvm::StringRef(arg.Includes.front().Header).startswith("<"); + llvm::StringRef(arg.Includes.front().Header).starts_with("<"); } TEST(StdLibTests, EndToEnd) { diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp index 51071d89a66e51bbb5a1469db9e5370ca33c43fc..81e65ede00781acb51584f3568f82ffa08602b06 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp @@ -43,7 +43,7 @@ llvm::StringRef unwrap(Context Ctx, llvm::StringRef Outer) { auto Wrapping = wrapping(Ctx); // Unwrap only if the code matches the expected wrapping. // Don't allow the begin/end wrapping to overlap! - if (Outer.startswith(Wrapping.first) && Outer.endswith(Wrapping.second) && + if (Outer.starts_with(Wrapping.first) && Outer.ends_with(Wrapping.second) && Outer.size() >= Wrapping.first.size() + Wrapping.second.size()) return Outer.drop_front(Wrapping.first.size()) .drop_back(Wrapping.second.size()); diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp index 450c4c796c141567f8620fe03b631e7d0160b91d..f1cd72f877ca21bfa7eeab6b7278383350350369 100644 --- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp +++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp @@ -126,7 +126,7 @@ analyze(llvm::ArrayRef ASTRoots, // Since most private -> public mappings happen in a verbatim way, we // check textually here. This might go wrong in presence of symlinks or // header mappings. But that's not different than rest of the places. - if (MainFile->tryGetRealPathName().endswith(PHeader)) + if (MainFile->tryGetRealPathName().ends_with(PHeader)) continue; } } diff --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp index 6e00ff93a7fe2fae384026e9db8d05bcad73a7c3..bd726cff12a97d915da4b8026fd27acfccf332ea 100644 --- a/clang-tools-extra/include-cleaner/lib/Record.cpp +++ b/clang-tools-extra/include-cleaner/lib/Record.cpp @@ -277,7 +277,7 @@ public: int CommentLine = SM.getLineNumber(CommentFID, CommentOffset); if (InMainFile) { - if (Pragma->startswith("keep")) { + if (Pragma->starts_with("keep")) { KeepStack.push_back({CommentLine, false}); } else if (Pragma->starts_with("begin_keep")) { KeepStack.push_back({CommentLine, true}); @@ -300,9 +300,10 @@ public: StringRef PublicHeader; if (Pragma->consume_front(", include ")) { // We always insert using the spelling from the pragma. - PublicHeader = save(Pragma->startswith("<") || Pragma->startswith("\"") - ? (*Pragma) - : ("\"" + *Pragma + "\"").str()); + PublicHeader = + save(Pragma->starts_with("<") || Pragma->starts_with("\"") + ? (*Pragma) + : ("\"" + *Pragma + "\"").str()); } Out->IWYUPublic.insert({CommentUID, PublicHeader}); return false; @@ -313,11 +314,11 @@ public: } auto Filename = FE->getName(); // Record export pragma. - if (Pragma->startswith("export")) { + if (Pragma->starts_with("export")) { ExportStack.push_back({CommentLine, CommentFID, save(Filename), false}); - } else if (Pragma->startswith("begin_exports")) { + } else if (Pragma->starts_with("begin_exports")) { ExportStack.push_back({CommentLine, CommentFID, save(Filename), true}); - } else if (Pragma->startswith("end_exports")) { + } else if (Pragma->starts_with("end_exports")) { // FIXME: be robust on unmatching cases. We should only pop the stack if // the begin_exports and end_exports is in the same file. if (!ExportStack.empty()) { diff --git a/clang-tools-extra/modularize/CoverageChecker.cpp b/clang-tools-extra/modularize/CoverageChecker.cpp index d8445053872bf22fbfb0fe73f7b205ce58fd81d7..1e8b0aa37ca309931c9d2c70433ffb22bc6018aa 100644 --- a/clang-tools-extra/modularize/CoverageChecker.cpp +++ b/clang-tools-extra/modularize/CoverageChecker.cpp @@ -302,7 +302,7 @@ void CoverageChecker::collectUmbrellaHeaderHeader(StringRef HeaderName) { sys::fs::current_path(PathBuf); // HeaderName will have an absolute path, so if it's the module map // directory, we remove it, also skipping trailing separator. - if (HeaderName.startswith(PathBuf)) + if (HeaderName.starts_with(PathBuf)) HeaderName = HeaderName.substr(PathBuf.size() + 1); // Save header name. ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(HeaderName)); @@ -356,8 +356,8 @@ bool CoverageChecker::collectFileSystemHeaders(StringRef IncludePath) { sys::path::append(Directory, IncludePath); if (Directory.size() == 0) Directory = "."; - if (IncludePath.startswith("/") || IncludePath.startswith("\\") || - ((IncludePath.size() >= 2) && (IncludePath[1] == ':'))) { + if (IncludePath.starts_with("/") || IncludePath.starts_with("\\") || + ((IncludePath.size() >= 2) && (IncludePath[1] == ':'))) { llvm::errs() << "error: Include path \"" << IncludePath << "\" is not relative to the module map file.\n"; return false; diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index 089f52f52ec4d341826294df72da43eafae0637a..dfca3eefe473203f5b82c82ed5b909acc0c79bd8 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -75,12 +75,11 @@ std::error_code ModularizeUtilities::loadAllHeaderListsAndDependencies() { for (auto I = InputFilePaths.begin(), E = InputFilePaths.end(); I != E; ++I) { llvm::StringRef InputPath = *I; // If it's a module map. - if (InputPath.endswith(".modulemap")) { + if (InputPath.ends_with(".modulemap")) { // Load the module map. if (std::error_code EC = loadModuleMap(InputPath)) return EC; - } - else { + } else { // Else we assume it's a header list and load it. if (std::error_code EC = loadSingleHeaderListsAndDependencies(InputPath)) { errs() << "modularize: error: Unable to get header list '" << InputPath @@ -276,7 +275,7 @@ std::error_code ModularizeUtilities::loadModuleMap( StringRef DirName(Dir.getName()); if (llvm::sys::path::filename(DirName) == "Modules") { DirName = llvm::sys::path::parent_path(DirName); - if (DirName.endswith(".framework")) { + if (DirName.ends_with(".framework")) { auto FrameworkDirOrErr = FileMgr->getDirectoryRef(DirName); if (!FrameworkDirOrErr) { // This can happen if there's a race between the above check and the @@ -444,7 +443,7 @@ static std::string replaceDotDot(StringRef Path) { llvm::sys::path::append(Buffer, *B); ++B; } - if (Path.endswith("/") || Path.endswith("\\")) + if (Path.ends_with("/") || Path.ends_with("\\")) Buffer.append(1, Path.back()); return Buffer.c_str(); } @@ -457,7 +456,7 @@ std::string ModularizeUtilities::getCanonicalPath(StringRef FilePath) { std::string Tmp(replaceDotDot(FilePath)); std::replace(Tmp.begin(), Tmp.end(), '\\', '/'); StringRef Tmp2(Tmp); - if (Tmp2.startswith("./")) + if (Tmp2.starts_with("./")) Tmp = std::string(Tmp2.substr(2)); return Tmp; } diff --git a/clang-tools-extra/modularize/PreprocessorTracker.cpp b/clang-tools-extra/modularize/PreprocessorTracker.cpp index 335195c6b199e7690ed1fa8c061507631b6d9b83..7557fb177ceb48a24b8bc10960daba160c19e31e 100644 --- a/clang-tools-extra/modularize/PreprocessorTracker.cpp +++ b/clang-tools-extra/modularize/PreprocessorTracker.cpp @@ -883,7 +883,7 @@ public: // Handle entering a header source file. void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) { // Ignore and to reduce message clutter. - if (HeaderPath.startswith("<")) + if (HeaderPath.starts_with("<")) return; HeaderHandle H = addHeader(HeaderPath); if (H != getCurrentHeaderHandle()) @@ -896,7 +896,7 @@ public: // Handle exiting a header source file. void handleHeaderExit(llvm::StringRef HeaderPath) { // Ignore and to reduce message clutter. - if (HeaderPath.startswith("<")) + if (HeaderPath.starts_with("<")) return; HeaderHandle H = findHeaderHandle(HeaderPath); HeaderHandle TH; diff --git a/clang-tools-extra/pseudo/lib/cxx/CXX.cpp b/clang-tools-extra/pseudo/lib/cxx/CXX.cpp index 46d837aec44ad3eac8806e5ae661d58f3a9607b7..4188dab31d3a91284e7dba646fab065612617ff2 100644 --- a/clang-tools-extra/pseudo/lib/cxx/CXX.cpp +++ b/clang-tools-extra/pseudo/lib/cxx/CXX.cpp @@ -28,9 +28,9 @@ static const char *CXXBNF = // User-defined string literals look like `""suffix`. bool isStringUserDefined(const Token &Tok) { - return !Tok.text().endswith("\""); + return !Tok.text().ends_with("\""); } -bool isCharUserDefined(const Token &Tok) { return !Tok.text().endswith("'"); } +bool isCharUserDefined(const Token &Tok) { return !Tok.text().ends_with("'"); } // Combinable flags describing numbers. // Clang has just one numeric_token kind, the grammar has 4. diff --git a/clang-tools-extra/pseudo/lib/grammar/GrammarBNF.cpp b/clang-tools-extra/pseudo/lib/grammar/GrammarBNF.cpp index 9706f17eab848b9b449df359a952e358d1cf0539..f1b8e06e22432c63c872c97a3991493671a6a3ae 100644 --- a/clang-tools-extra/pseudo/lib/grammar/GrammarBNF.cpp +++ b/clang-tools-extra/pseudo/lib/grammar/GrammarBNF.cpp @@ -33,11 +33,11 @@ public: assert(llvm::all_of(Specs, [](const RuleSpec &R) { - if (R.Target.endswith(OptSuffix)) + if (R.Target.ends_with(OptSuffix)) return false; return llvm::all_of( R.Sequence, [](const RuleSpec::Element &E) { - return !E.Symbol.endswith(OptSuffix); + return !E.Symbol.ends_with(OptSuffix); }); }) && "Optional symbols should be eliminated!"); @@ -225,7 +225,7 @@ private: Chunk = Chunk.trim(); if (Chunk.empty()) continue; // skip empty - if (Chunk.startswith("[") && Chunk.endswith("]")) { + if (Chunk.starts_with("[") && Chunk.ends_with("]")) { if (Out.Sequence.empty()) continue; @@ -241,7 +241,7 @@ private: bool parseAttributes( llvm::StringRef Content, std::vector> &Out) { - assert(Content.startswith("[") && Content.endswith("]")); + assert(Content.starts_with("[") && Content.ends_with("]")); auto KV = Content.drop_front().drop_back().split('='); Out.push_back({KV.first, KV.second.trim()}); @@ -299,7 +299,7 @@ private: if (Elements.empty()) return CB(); auto Front = Elements.front(); - if (!Front.Symbol.endswith(OptSuffix)) { + if (!Front.Symbol.ends_with(OptSuffix)) { Result.push_back(std::move(Front)); eliminateOptionalTail(Elements.drop_front(1), Result, CB); Result.pop_back(); diff --git a/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp b/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp index feb7ae913f9968487ebfbe82d3e12d44132e6cb1..e9ab987e493c41a2fcb701a1195ab0ae0f7560e6 100644 --- a/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp @@ -66,7 +66,7 @@ protected: "#define SOME_MACRO(x) using x\n"; std::vector Errors; std::vector Args; - if (!StringRef(Filename).endswith(".cpp")) { + if (!StringRef(Filename).ends_with(".cpp")) { Args.emplace_back("-xc++-header"); } test::runCheckOnCode( diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 4b9085d99378c6fb28fb11d509bcf4df4b777d5b..c4673c8a54c5ef531f2e77502d4338ce29c7a52d 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -336,6 +336,7 @@ set(LLVM_TOOLCHAIN_TOOLS llvm-symbolizer llvm-undname llvm-xray + opt-viewer sancov scan-build-py CACHE STRING "") diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 066e4ac5b9e54b83965d0cbc64740f12a06aaa0f..05d59d0da264f30a00a9df6f8f359a052e398fb1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -685,6 +685,9 @@ Bug Fixes in This Version (`#62157 `_) and (`#64885 `_) and (`#65568 `_) +- Fixed false positive error emitted when templated alias inside a class + used private members of the same class. + Fixes (`#41693 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 26c318dd511cbb6bea98d7c8c446ca452eeca1ed..2b57058d3f1c75fc17e31a616e9c5328ed8a00c7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2215,7 +2215,8 @@ def NotTailCalled : InheritableAttr { def : MutualExclusions<[AlwaysInline, NotTailCalled]>; def NoStackProtector : InheritableAttr { - let Spellings = [Clang<"no_stack_protector">, Declspec<"safebuffers">]; + let Spellings = [Clang<"no_stack_protector">, CXX11<"gnu", "no_stack_protector">, + C23<"gnu", "no_stack_protector">, Declspec<"safebuffers">]; let Subjects = SubjectList<[Function]>; let Documentation = [NoStackProtectorDocs]; let SimpleHandler = 1; @@ -2795,9 +2796,10 @@ def SwiftAsyncError : InheritableAttr { let Documentation = [SwiftAsyncErrorDocs]; } -def Suppress : StmtAttr { - let Spellings = [CXX11<"gsl", "suppress">]; +def Suppress : DeclOrStmtAttr { + let Spellings = [CXX11<"gsl", "suppress">, Clang<"suppress">]; let Args = [VariadicStringArgument<"DiagnosticIdentifiers">]; + let Accessors = [Accessor<"isGSL", [CXX11<"gsl", "suppress">]>]; let Documentation = [SuppressDocs]; } @@ -2881,7 +2883,7 @@ def Target : InheritableAttr { for (auto &Feature : AttrFeatures) { Feature = Feature.trim(); - if (Feature.startswith("arch=")) + if (Feature.starts_with("arch=")) return Feature.drop_front(sizeof("arch=") - 1); } return ""; @@ -2899,8 +2901,8 @@ def Target : InheritableAttr { for (auto &Feature : AttrFeatures) { Feature = Feature.trim(); - if (!Feature.startswith("no-") && !Feature.startswith("arch=") && - !Feature.startswith("fpmath=") && !Feature.startswith("tune=")) + if (!Feature.starts_with("no-") && !Feature.starts_with("arch=") && + !Feature.starts_with("fpmath=") && !Feature.starts_with("tune=")) Out.push_back(Feature); } } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a8de566db1a7d301edacf1352361c646ada95a3b..90041fa8dbb30b9b7d7be0f91eb4e03437152a29 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5267,7 +5267,74 @@ the ``int`` parameter is the one that represents the error. def SuppressDocs : Documentation { let Category = DocCatStmt; let Content = [{ -The ``[[gsl::suppress]]`` attribute suppresses specific +The ``suppress`` attribute suppresses unwanted warnings coming from static +analysis tools such as the Clang Static Analyzer. The tool will not report +any issues in source code annotated with the attribute. + +The attribute cannot be used to suppress traditional Clang warnings, because +many such warnings are emitted before the attribute is fully parsed. +Consider using ``#pragma clang diagnostic`` to control such diagnostics, +as described in `Controlling Diagnostics via Pragmas +`_. + +The ``suppress`` attribute can be placed on an individual statement in order to +suppress warnings about undesirable behavior occurring at that statement: + +.. code-block:: c++ + + int foo() { + int *x = nullptr; + ... + [[clang::suppress]] + return *x; // null pointer dereference warning suppressed here + } + +Putting the attribute on a compound statement suppresses all warnings in scope: + +.. code-block:: c++ + + int foo() { + [[clang::suppress]] { + int *x = nullptr; + ... + return *x; // warnings suppressed in the entire scope + } + } + +Some static analysis warnings are accompanied by one or more notes, and the +line of code against which the warning is emitted isn't necessarily the best +for suppression purposes. In such cases the tools are allowed to implement +additional ways to suppress specific warnings based on the attribute attached +to a note location. + +For example, the Clang Static Analyzer suppresses memory leak warnings when +the suppression attribute is placed at the allocation site (highlited by +a "note: memory is allocated"), which may be different from the line of code +at which the program "loses track" of the pointer (where the warning +is ultimately emitted): + +.. code-block:: c + + int bar1(bool coin_flip) { + __attribute__((suppress)) + int *result = (int *)malloc(sizeof(int)); + if (coin_flip) + return 1; // warning about this leak path is suppressed + + return *result; // warning about this leak path is also suppressed + } + + int bar2(bool coin_flip) { + int *result = (int *)malloc(sizeof(int)); + if (coin_flip) + return 1; // leak warning on this path NOT suppressed + + __attribute__((suppress)) + return *result; // leak warning is suppressed only on this path + } + + +When written as ``[[gsl::suppress]]``, this attribute suppresses specific clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable way. The attribute can be attached to declarations, statements, and at namespace scope. diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index 8b59b3790d7bc661361cf6f2b8f154877425658a..7465f13d552d6e41390fe1acc25f9ce55ac4451c 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -406,5 +406,21 @@ TARGET_BUILTIN(__builtin_amdgcn_cvt_pk_fp8_f32, "iffiIb", "nc", "fp8-insts") TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf8_f32, "ifiiIi", "nc", "fp8-insts") TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_fp8_f32, "ifiiIi", "nc", "fp8-insts") +//===----------------------------------------------------------------------===// +// GFX12+ only builtins. +//===----------------------------------------------------------------------===// + +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal, "vIi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_var, "vi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_wait, "vIs", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst, "bIi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst_var, "bi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_init, "vii", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_wakeup_barrier, "vi", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "b", "n", "gfx12-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts") + + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 7473e00a7bd86bae6f92d4882070f2337a169c65..06efac0cf1abd7e7a529a9b7f3616b97eebb7010 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -282,7 +282,6 @@ EXTENSION(matrix_types_scalar_division, true) EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11) EXTENSION(datasizeof, LangOpts.CPlusPlus) -FEATURE(builtin_headers_in_system_modules, LangOpts.BuiltinHeadersInSystemModules) FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables) // CUDA/HIP Features diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 0898e7d39dd7dee20301aa9926e66cefdfae7e0f..1ac182d4fce26f65f2179aaee96b4706bbb696ea 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -511,7 +511,7 @@ public: /// function(<#int x#>); /// \endcode bool isEditorPlaceholder() const { - return getName().startswith("<#") && getName().endswith("#>"); + return getName().starts_with("<#") && getName().ends_with("#>"); } /// Determine whether \p this is a name reserved for the implementation (C99 diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index 8f7881abf26f7f49f5c71cec97248c166e6b5af5..c9f9cbec7493bfc91d21cf5f423ddb703252d86a 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -309,7 +309,7 @@ namespace clang { bool isTupleSet() const { return Flags & IsTupleSet; } bool isReadZA() const { return Flags & IsReadZA; } bool isWriteZA() const { return Flags & IsWriteZA; } - + bool isReductionQV() const { return Flags & IsReductionQV; } uint64_t getBits() const { return Flags; } bool isFlagSet(uint64_t Flag) const { return Flags & Flag; } }; diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index aa9b105364a51a1004873c95e4dda5ac811268df..278a791ff760dc9131f0f3d2ff796c807dc9c457 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -1946,6 +1946,23 @@ def SVPSEL_COUNT_ALIAS_S : SInst<"svpsel_lane_c32", "}}Pm", "Pi", MergeNone, "", def SVPSEL_COUNT_ALIAS_D : SInst<"svpsel_lane_c64", "}}Pm", "Pl", MergeNone, "", [IsStreamingCompatible], []>; } +// Standalone sve2.1 builtins +let TargetGuard = "sve2p1" in { +def SVORQV : SInst<"svorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_orqv", [IsReductionQV]>; +def SVEORQV : SInst<"sveorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorqv", [IsReductionQV]>; +def SVADDQV : SInst<"svaddqv[_{d}]", "{Pd", "hfdcsilUcUsUiUl", MergeNone, "aarch64_sve_addqv", [IsReductionQV]>; +def SVANDQV : SInst<"svandqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_andqv", [IsReductionQV]>; +def SVSMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "csil", MergeNone, "aarch64_sve_smaxqv", [IsReductionQV]>; +def SVUMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "UcUsUiUl", MergeNone, "aarch64_sve_umaxqv", [IsReductionQV]>; +def SVSMINQV : SInst<"svminqv[_{d}]", "{Pd", "csil", MergeNone, "aarch64_sve_sminqv", [IsReductionQV]>; +def SVUMINQV : SInst<"svminqv[_{d}]", "{Pd", "UcUsUiUl", MergeNone, "aarch64_sve_uminqv", [IsReductionQV]>; + +def SVFMAXNMQV: SInst<"svmaxnmqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmaxnmqv", [IsReductionQV]>; +def SVFMINNMQV: SInst<"svminnmqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fminnmqv", [IsReductionQV]>; +def SVFMAXQV: SInst<"svmaxqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmaxqv", [IsReductionQV]>; +def SVFMINQV: SInst<"svminqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fminqv", [IsReductionQV]>; +} + let TargetGuard = "sve2p1|sme2" in { //FIXME: Replace IsStreamingCompatible with IsStreamingOrHasSVE2p1 when available def SVPEXT_SINGLE : SInst<"svpext_lane_{d}", "P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext", [IsStreamingCompatible], [ImmCheck<1, ImmCheck0_3>]>; @@ -2168,6 +2185,21 @@ let TargetGuard = "sme2" in { def REINTERPRET_SVBOOL_TO_SVCOUNT : Inst<"svreinterpret[_c]", "}P", "Pc", MergeNone, "", [IsStreamingCompatible], []>; def REINTERPRET_SVCOUNT_TO_SVBOOL : Inst<"svreinterpret[_b]", "P}", "Pc", MergeNone, "", [IsStreamingCompatible], []>; + + // SQDMULH + def SVSQDMULH_SINGLE_X2 : SInst<"svqdmulh[_single_{d}_x2]", "22d", "csil", MergeNone, "aarch64_sve_sqdmulh_single_vgx2", [IsStreaming], []>; + def SVSQDMULH_SINGLE_X4 : SInst<"svqdmulh[_single_{d}_x4]", "44d", "csil", MergeNone, "aarch64_sve_sqdmulh_single_vgx4", [IsStreaming], []>; + def SVSQDMULH_X2 : SInst<"svqdmulh[_{d}_x2]", "222", "csil", MergeNone, "aarch64_sve_sqdmulh_vgx2", [IsStreaming], []>; + def SVSQDMULH_X4 : SInst<"svqdmulh[_{d}_x4]", "444", "csil", MergeNone, "aarch64_sve_sqdmulh_vgx4", [IsStreaming], []>; +} + +let TargetGuard = "sve2p1|sme2" in { + // SQRSHRN / UQRSHRN + def SVQRSHRN_X2 : SInst<"svqrshrn[_n]_{0}[_{d}_x2]", "h2i", "i", MergeNone, "aarch64_sve_sqrshrn_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>; + def SVUQRSHRN_X2 : SInst<"svqrshrn[_n]_{0}[_{d}_x2]", "e2i", "Ui", MergeNone, "aarch64_sve_uqrshrn_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>; + + // SQRSHRUN + def SVSQRSHRUN_X2 : SInst<"svqrshrun[_n]_{0}[_{d}_x2]", "e2i", "i", MergeNone, "aarch64_sve_sqrshrun_x2", [IsStreamingCompatible], [ImmCheck<1, ImmCheck1_16>]>; } let TargetGuard = "sve2p1" in { diff --git a/clang/include/clang/Basic/arm_sve_sme_incl.td b/clang/include/clang/Basic/arm_sve_sme_incl.td index 040ce95a57de3dc43385269897de2e0816c5da40..0dba8493bad2d6a48e70cb3382c8161dc47debdb 100644 --- a/clang/include/clang/Basic/arm_sve_sme_incl.td +++ b/clang/include/clang/Basic/arm_sve_sme_incl.td @@ -129,6 +129,7 @@ // Z: const pointer to uint64_t // Prototype modifiers added for SVE2p1 +// {: 128b vector // }: svcount_t class MergeType { @@ -225,6 +226,7 @@ def IsSharedZA : FlagType<0x8000000000>; def IsPreservesZA : FlagType<0x10000000000>; def IsReadZA : FlagType<0x20000000000>; def IsWriteZA : FlagType<0x40000000000>; +def IsReductionQV : FlagType<0x80000000000>; // These must be kept in sync with the flags in include/clang/Basic/TargetBuiltins.h class ImmCheckType { diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 25c76cf2ad2c84ad15c2ac6a39390043477afd91..1b02087425b751516424103857846a665b76b53c 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2896,9 +2896,11 @@ defm asm_blocks : BoolFOption<"asm-blocks", LangOpts<"AsmBlocks">, Default, PosFlag, NegFlag>; -def fms_volatile : Flag<["-"], "fms-volatile">, Group, - Visibility<[ClangOption, CC1Option]>, - MarshallingInfoFlag>; +defm ms_volatile : BoolFOption<"ms-volatile", + LangOpts<"MSVolatile">, DefaultFalse, + PosFlag, + NegFlag>; def fmsc_version : Joined<["-"], "fmsc-version=">, Group, Visibility<[ClangOption, CLOption]>, HelpText<"Microsoft compiler version number to report in _MSC_VER (0 = don't define it (default))">; @@ -8217,7 +8219,7 @@ def _SLASH_winsysroot : CLJoinedOrSeparate<"winsysroot">, HelpText<"Same as \"/diasdkdir /DIA SDK\" /vctoolsdir /VC/Tools/MSVC/ \"/winsdkdir /Windows Kits/10\"">, MetaVarName<"">; def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>, - Group<_SLASH_volatile_Group>, Flags<[NoXarchOption]>, Visibility<[CLOption]>, + Visibility<[CLOption]>, Alias, HelpText<"Volatile loads and stores have standard semantics">; def _SLASH_vmb : CLFlag<"vmb">, HelpText<"Use a best-case representation method for member pointers">; @@ -8232,7 +8234,7 @@ def _SLASH_vmv : CLFlag<"vmv">, HelpText<"Set the default most-general representation to " "virtual inheritance">; def _SLASH_volatile_ms : Option<["/", "-"], "volatile:ms", KIND_FLAG>, - Group<_SLASH_volatile_Group>, Flags<[NoXarchOption]>, Visibility<[CLOption]>, + Visibility<[CLOption]>, Alias, HelpText<"Volatile loads and stores have acquire and release semantics">; def _SLASH_clang : CLJoined<"clang:">, HelpText<"Pass to the clang driver">, MetaVarName<"">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 1d7b4c729ce84e0968f78d5250c70438e86e927a..7e89e74733a090350a9e9b2d7932d9353c06580b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8737,7 +8737,7 @@ public: SourceLocation IILoc, bool DeducedTSTContext = true); - + bool RebuildingTypesInCurrentInstantiation = false; TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Name); diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index a947bd0867025c2087a6278d3c13b2cbda33bba1..276d11e80a5b21c78acd293650fadeddcf4bd1c3 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -409,8 +409,8 @@ AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental) { }; std::vector Checkers; for (StringRef CheckerName : StaticAnalyzerCheckerNames) { - if (!CheckerName.startswith("debug.") && - (IncludeExperimental || !CheckerName.startswith("alpha."))) + if (!CheckerName.starts_with("debug.") && + (IncludeExperimental || !CheckerName.starts_with("alpha."))) Checkers.push_back(CheckerName); } return Checkers; diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 8956552e7bfc21e4c0f46ecbb7e0285f0bb6f032..e762f7548e0b54186883f140bcc793378913a67b 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -19,6 +19,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Preprocessor.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" @@ -594,6 +595,9 @@ private: /// A vector of BugReports for tracking the allocated pointers and cleanup. std::vector EQClassesVector; + /// User-provided in-code suppressions. + BugSuppression UserSuppressions; + public: BugReporter(BugReporterData &d); virtual ~BugReporter(); diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h new file mode 100644 index 0000000000000000000000000000000000000000..4fd81b6275197446f3cf40acc1ef36ed9cc22dff --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h @@ -0,0 +1,53 @@ +//===- BugSuppression.h - Suppression interface -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines BugSuppression, a simple interface class encapsulating +// all user provided in-code suppressions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_SUPPRESSION_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_SUPPRESSION_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { +class Decl; + +namespace ento { +class BugReport; +class PathDiagnosticLocation; + +class BugSuppression { +public: + using DiagnosticIdentifierList = llvm::ArrayRef; + + /// Return true if the given bug report was explicitly suppressed by the user. + bool isSuppressed(const BugReport &); + + /// Return true if the bug reported at the given location was explicitly + /// suppressed by the user. + bool isSuppressed(const PathDiagnosticLocation &Location, + const Decl *DeclWithIssue, + DiagnosticIdentifierList DiagnosticIdentification); + +private: + // Overly pessimistic number, to be honest. + static constexpr unsigned EXPECTED_NUMBER_OF_SUPPRESSIONS = 8; + using CachedRanges = + llvm::SmallVector; + + llvm::DenseMap CachedSuppressionLocations; +}; + +} // end namespace ento +} // end namespace clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_SUPPRESSION_H diff --git a/clang/lib/APINotes/APINotesManager.cpp b/clang/lib/APINotes/APINotesManager.cpp index ec1fb3ffa961c95cbfba635388ff19f8751401dc..a921c8b9fce3e0e0923f4bb621234dbaa189cac3 100644 --- a/clang/lib/APINotes/APINotesManager.cpp +++ b/clang/lib/APINotes/APINotesManager.cpp @@ -198,7 +198,7 @@ static void checkPrivateAPINotesName(DiagnosticsEngine &Diags, StringRef RealFileName = llvm::sys::path::filename(File->tryGetRealPathName()); StringRef RealStem = llvm::sys::path::stem(RealFileName); - if (RealStem.endswith("_private")) + if (RealStem.ends_with("_private")) return; unsigned DiagID = diag::warn_apinotes_private_case; diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index 4dfd01dae05f2ca8944b57d778de967e4f3b6533..57d6da7a1775960beec3ea1af7e26c5b905602c4 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -745,7 +745,7 @@ public: convertCommonEntity(M, MI, M.Selector); // Check if the selector ends with ':' to determine if it takes arguments. - bool takesArguments = M.Selector.endswith(":"); + bool takesArguments = M.Selector.ends_with(":"); // Split the selector into pieces. llvm::SmallVector Args; diff --git a/clang/lib/ARCMigrate/ARCMT.cpp b/clang/lib/ARCMigrate/ARCMT.cpp index 8e398977dcd65d6ba25a17678961345f6fa842b5..b410d5f3b42a7eae63a838ee842637c376df02ba 100644 --- a/clang/lib/ARCMigrate/ARCMT.cpp +++ b/clang/lib/ARCMigrate/ARCMT.cpp @@ -201,7 +201,7 @@ createInvocationForMigration(CompilerInvocation &origCI, for (std::vector::iterator I = CInvok->getDiagnosticOpts().Warnings.begin(), E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) { - if (!StringRef(*I).startswith("error")) + if (!StringRef(*I).starts_with("error")) WarnOpts.push_back(*I); } WarnOpts.push_back("error=arc-unsafe-retained-assign"); diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index 5a25c88c65f64b4a1468dd6e681ea054b6b00ad3..ed363a46a2004439911a046271b10a34e04d3d02 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -562,7 +562,7 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) { if (ObjCCategoryDecl *CatDecl = dyn_cast(D)) { StringRef Name = CatDecl->getName(); - return Name.endswith("Deprecated"); + return Name.ends_with("Deprecated"); } return false; } @@ -1176,12 +1176,12 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx, if (!SetterMethod) { // try a different naming convention for getter: isXxxxx StringRef getterNameString = getterName->getName(); - bool IsPrefix = getterNameString.startswith("is"); + bool IsPrefix = getterNameString.starts_with("is"); // Note that we don't want to change an isXXX method of retainable object // type to property (readonly or otherwise). if (IsPrefix && GRT->isObjCRetainableType()) return false; - if (IsPrefix || getterNameString.startswith("get")) { + if (IsPrefix || getterNameString.starts_with("get")) { LengthOfPrefix = (IsPrefix ? 2 : 3); const char *CGetterName = getterNameString.data() + LengthOfPrefix; // Make sure that first character after "is" or "get" prefix can @@ -1320,11 +1320,11 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) { StringRef STRefMethodName(MethodName); size_t len = 0; - if (STRefMethodName.startswith("standard")) + if (STRefMethodName.starts_with("standard")) len = strlen("standard"); - else if (STRefMethodName.startswith("shared")) + else if (STRefMethodName.starts_with("shared")) len = strlen("shared"); - else if (STRefMethodName.startswith("default")) + else if (STRefMethodName.starts_with("default")) len = strlen("default"); else return; @@ -1341,7 +1341,7 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, StringRef LoweredMethodName(MethodName); std::string StringLoweredMethodName = LoweredMethodName.lower(); LoweredMethodName = StringLoweredMethodName; - if (!LoweredMethodName.startswith(ClassNamePostfix)) + if (!LoweredMethodName.starts_with(ClassNamePostfix)) return; if (OIT_Family == OIT_ReturnsSelf) ReplaceWithClasstype(*this, OM); diff --git a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp index 40220a2eef4910be7630a481444ea71b3eb57b5d..1e6354f71e294a90cb7164255f67786bcbafd3c8 100644 --- a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -146,7 +146,7 @@ private: ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); - if (fname.endswith("Retain") || fname.contains("Create") || + if (fname.ends_with("Retain") || fname.contains("Create") || fname.contains("Copy")) { // Do not migrate to couple of bridge transfer casts which // cancel each other out. Leave it unchanged so error gets user diff --git a/clang/lib/ARCMigrate/TransformActions.cpp b/clang/lib/ARCMigrate/TransformActions.cpp index bd5c793568671d7a4ad814d9ac6d7f57285ffcda..6bc6fed1a9032013a14f5faa54a74d7dddf7e9a5 100644 --- a/clang/lib/ARCMigrate/TransformActions.cpp +++ b/clang/lib/ARCMigrate/TransformActions.cpp @@ -431,7 +431,7 @@ bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { if (invalidTemp) return false; - return file.substr(locInfo.second).startswith(text); + return file.substr(locInfo.second).starts_with(text); } void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) { diff --git a/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp index 90b2b32b6b1be24865602a533677ab5afad27466..2808e35135dc358c832f87715a8d699e5c0e6242 100644 --- a/clang/lib/ARCMigrate/Transforms.cpp +++ b/clang/lib/ARCMigrate/Transforms.cpp @@ -95,7 +95,7 @@ bool trans::isPlusOne(const Expr *E) { ento::cocoa::isRefType(callE->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); - if (fname.endswith("Retain") || fname.contains("Create") || + if (fname.ends_with("Retain") || fname.contains("Create") || fname.contains("Copy")) return true; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e877f903b34c6bbbb1089231aec07494e1acf0c2..0395b3e47ab6f8f4b4aab79cb14231709c1572c1 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8223,7 +8223,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, // Another legacy compatibility encoding. Some ObjC qualifier and type // combinations need to be rearranged. // Rewrite "in const" from "nr" to "rn" - if (StringRef(S).endswith("nr")) + if (StringRef(S).ends_with("nr")) S.replace(S.end()-2, S.end(), "rn"); } @@ -13519,7 +13519,7 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); } else { - if (VersionStr.startswith("arch=")) + if (VersionStr.starts_with("arch=")) TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); else if (VersionStr != "default") Features.push_back((StringRef{"+"} + VersionStr).str()); diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 30a26d518386c52363645bd8ddb986c6696cbf9b..24da6f2ef32b4fc3c17d90e75b5bd4315c48d4e2 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1728,7 +1728,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { std::string TypeStr = PDecl->getASTContext().getUnqualifiedObjCPointerType(T). getAsString(Policy); Out << ' ' << TypeStr; - if (!StringRef(TypeStr).endswith("*")) + if (!StringRef(TypeStr).ends_with("*")) Out << ' '; Out << *PDecl; if (Policy.PolishForDeclaration) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index f7f8e6c73d84e21369343ff5eac81602a725480c..d0980882f402b9b7a6cd77ae20c3df211786dd43 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -222,6 +222,64 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitNE(PtrT, CE); } + case CK_IntegralComplexToBoolean: + case CK_FloatingComplexToBoolean: { + std::optional ElemT = + classifyComplexElementType(SubExpr->getType()); + if (!ElemT) + return false; + // We emit the expression (__real(E) != 0 || __imag(E) != 0) + // for us, that means (bool)E[0] || (bool)E[1] + if (!this->visit(SubExpr)) + return false; + if (!this->emitConstUint8(0, CE)) + return false; + if (!this->emitArrayElemPtrUint8(CE)) + return false; + if (!this->emitLoadPop(*ElemT, CE)) + return false; + if (*ElemT == PT_Float) { + if (!this->emitCastFloatingIntegral(PT_Bool, CE)) + return false; + } else { + if (!this->emitCast(*ElemT, PT_Bool, CE)) + return false; + } + + // We now have the bool value of E[0] on the stack. + LabelTy LabelTrue = this->getLabel(); + if (!this->jumpTrue(LabelTrue)) + return false; + + if (!this->emitConstUint8(1, CE)) + return false; + if (!this->emitArrayElemPtrPopUint8(CE)) + return false; + if (!this->emitLoadPop(*ElemT, CE)) + return false; + if (*ElemT == PT_Float) { + if (!this->emitCastFloatingIntegral(PT_Bool, CE)) + return false; + } else { + if (!this->emitCast(*ElemT, PT_Bool, CE)) + return false; + } + // Leave the boolean value of E[1] on the stack. + LabelTy EndLabel = this->getLabel(); + this->jump(EndLabel); + + this->emitLabel(LabelTrue); + if (!this->emitPopPtr(CE)) + return false; + if (!this->emitConstBool(true, CE)) + return false; + + this->fallthrough(EndLabel); + this->emitLabel(EndLabel); + + return true; + } + case CK_ToVoid: return discard(SubExpr); @@ -258,6 +316,9 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { if (BO->isLogicalOp()) return this->VisitLogicalBinOp(BO); + if (BO->getType()->isAnyComplexType()) + return this->VisitComplexBinOp(BO); + const Expr *LHS = BO->getLHS(); const Expr *RHS = BO->getRHS(); @@ -500,6 +561,107 @@ bool ByteCodeExprGen::VisitLogicalBinOp(const BinaryOperator *E) { return true; } +template +bool ByteCodeExprGen::VisitComplexBinOp(const BinaryOperator *E) { + // FIXME: We expect a pointer on the stack here. + // we should not do that, but that's part of a bigger rework. + const Expr *LHS = E->getLHS(); + const Expr *RHS = E->getRHS(); + PrimType LHSElemT = *this->classifyComplexElementType(LHS->getType()); + PrimType RHSElemT = *this->classifyComplexElementType(RHS->getType()); + + unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false); + unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false); + unsigned ResultOffset = ~0u; + if (!this->DiscardResult) + ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false); + + assert(LHSElemT == RHSElemT); + + // Save result pointer in ResultOffset + if (!this->DiscardResult) { + if (!this->emitDupPtr(E)) + return false; + if (!this->emitSetLocal(PT_Ptr, ResultOffset, E)) + return false; + } + + // Evaluate LHS and save value to LHSOffset. + if (!this->visit(LHS)) + return false; + if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) + return false; + + // Same with RHS. + if (!this->visit(RHS)) + return false; + if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) + return false; + + // Now we can get pointers to the LHS and RHS from the offsets above. + BinaryOperatorKind Op = E->getOpcode(); + for (unsigned ElemIndex = 0; ElemIndex != 2; ++ElemIndex) { + // Result pointer for the store later. + if (!this->DiscardResult) { + if (!this->emitGetLocal(PT_Ptr, ResultOffset, E)) + return false; + } + + if (!this->emitGetLocal(PT_Ptr, LHSOffset, E)) + return false; + if (!this->emitConstUint8(ElemIndex, E)) + return false; + if (!this->emitArrayElemPtrPopUint8(E)) + return false; + if (!this->emitLoadPop(LHSElemT, E)) + return false; + + if (!this->emitGetLocal(PT_Ptr, RHSOffset, E)) + return false; + if (!this->emitConstUint8(ElemIndex, E)) + return false; + if (!this->emitArrayElemPtrPopUint8(E)) + return false; + if (!this->emitLoadPop(RHSElemT, E)) + return false; + + // The actual operation. + switch (Op) { + case BO_Add: + if (LHSElemT == PT_Float) { + if (!this->emitAddf(getRoundingMode(E), E)) + return false; + } else { + if (!this->emitAdd(LHSElemT, E)) + return false; + } + break; + case BO_Sub: + if (LHSElemT == PT_Float) { + if (!this->emitSubf(getRoundingMode(E), E)) + return false; + } else { + if (!this->emitSub(LHSElemT, E)) + return false; + } + break; + + default: + return false; + } + + if (!this->DiscardResult) { + // Initialize array element with the value we just computed. + if (!this->emitInitElemPop(LHSElemT, ElemIndex, E)) + return false; + } else { + if (!this->emitPop(LHSElemT, E)) + return false; + } + } + return true; +} + template bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { QualType QT = E->getType(); @@ -671,6 +833,32 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { return true; } + if (T->isAnyComplexType()) { + unsigned NumInits = E->getNumInits(); + QualType ElemQT = E->getType()->getAs()->getElementType(); + PrimType ElemT = classifyPrim(ElemQT); + if (NumInits == 0) { + // Zero-initialize both elements. + for (unsigned I = 0; I < 2; ++I) { + if (!this->visitZeroInitializer(ElemT, ElemQT, E)) + return false; + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + } else if (NumInits == 2) { + unsigned InitIndex = 0; + for (const Expr *Init : E->inits()) { + if (!this->visit(Init)) + return false; + + if (!this->emitInitElem(ElemT, InitIndex, E)) + return false; + ++InitIndex; + } + } + return true; + } + return false; } @@ -1647,7 +1835,8 @@ template bool ByteCodeExprGen::visit(const Expr *E) { return this->discard(E); // Create local variable to hold the return value. - if (!E->isGLValue() && !classify(E->getType())) { + if (!E->isGLValue() && !E->getType()->isAnyComplexType() && + !classify(E->getType())) { std::optional LocalIndex = allocateLocal(E, /*IsExtended=*/true); if (!LocalIndex) return false; @@ -1833,6 +2022,9 @@ bool ByteCodeExprGen::dereference( return Indirect(*T); } + if (LV->getType()->isAnyComplexType()) + return visit(LV); + return false; } @@ -2092,15 +2284,33 @@ const Function *ByteCodeExprGen::getFunction(const FunctionDecl *FD) { template bool ByteCodeExprGen::visitExpr(const Expr *E) { ExprScope RootScope(this); - if (!visit(E)) - return false; - - if (E->getType()->isVoidType()) + // Void expressions. + if (E->getType()->isVoidType()) { + if (!visit(E)) + return false; return this->emitRetVoid(E); + } - if (std::optional T = classify(E)) + // Expressions with a primitive return type. + if (std::optional T = classify(E)) { + if (!visit(E)) + return false; return this->emitRet(*T, E); - return this->emitRetValue(E); + } + + // Expressions with a composite return type. + // For us, that means everything we don't + // have a PrimType for. + if (std::optional LocalOffset = this->allocateLocal(E)) { + if (!this->visitLocalInitializer(E, *LocalOffset)) + return false; + + if (!this->emitGetPtrLocal(*LocalOffset, E)) + return false; + return this->emitRetValue(E); + } + + return false; } /// Toplevel visitDecl(). @@ -2550,8 +2760,36 @@ bool ByteCodeExprGen::VisitUnaryOperator(const UnaryOperator *E) { if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E); - case UO_Real: // __real x - case UO_Imag: // __imag x + case UO_Real: { // __real x + assert(!T); + if (!this->visit(SubExpr)) + return false; + if (!this->emitConstUint8(0, E)) + return false; + if (!this->emitArrayElemPtrPopUint8(E)) + return false; + + // Since our _Complex implementation does not map to a primitive type, + // we sometimes have to do the lvalue-to-rvalue conversion here manually. + if (!SubExpr->isLValue()) + return this->emitLoadPop(classifyPrim(E->getType()), E); + return true; + } + case UO_Imag: { // __imag x + assert(!T); + if (!this->visit(SubExpr)) + return false; + if (!this->emitConstUint8(1, E)) + return false; + if (!this->emitArrayElemPtrPopUint8(E)) + return false; + + // Since our _Complex implementation does not map to a primitive type, + // we sometimes have to do the lvalue-to-rvalue conversion here manually. + if (!SubExpr->isLValue()) + return this->emitLoadPop(classifyPrim(E->getType()), E); + return true; + } case UO_Extension: return this->delegate(SubExpr); case UO_Coawait: diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index bc1d5d11a1151356e75620d448d0627ff60ba9a0..bbb13e97e725692237f5388936012e9a24a28cbd 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -65,6 +65,7 @@ public: bool VisitBinaryOperator(const BinaryOperator *E); bool VisitLogicalBinOp(const BinaryOperator *E); bool VisitPointerArithBinOp(const BinaryOperator *E); + bool VisitComplexBinOp(const BinaryOperator *E); bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E); bool VisitCallExpr(const CallExpr *E); bool VisitBuiltinCallExpr(const CallExpr *E); @@ -285,6 +286,14 @@ private: } bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E); + std::optional classifyComplexElementType(QualType T) const { + assert(T->isAnyComplexType()); + + QualType ElemType = T->getAs()->getElementType(); + + return this->classify(ElemType); + } + bool emitRecordDestruction(const Descriptor *Desc); unsigned collectBaseOffset(const RecordType *BaseType, const RecordType *DerivedType); diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 4fe6d1173f427e7923a91bb5e944c2cf45e37ed5..17abb71635839c794b2511a6e2bde2dfa7899f80 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -92,6 +92,9 @@ std::optional Context::classify(QualType T) const { if (T->isBooleanType()) return PT_Bool; + if (T->isAnyComplexType()) + return std::nullopt; + if (T->isSignedIntegerOrEnumerationType()) { switch (Ctx.getIntWidth(T)) { case 64: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 9bc42057c5f57822ed6cf980f7aaa1b14adbf2c9..0ff0bde8fd17e85b14babdc06995e034a99e8c96 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -208,6 +208,27 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) { } return Ok; } + + // Complex types. + if (const auto *CT = Ty->getAs()) { + QualType ElemTy = CT->getElementType(); + std::optional ElemT = Ctx.classify(ElemTy); + assert(ElemT); + + if (ElemTy->isIntegerType()) { + INT_TYPE_SWITCH(*ElemT, { + auto V1 = Ptr.atIndex(0).deref(); + auto V2 = Ptr.atIndex(1).deref(); + Result = APValue(V1.toAPSInt(), V2.toAPSInt()); + return true; + }); + } else if (ElemTy->isFloatingType()) { + Result = APValue(Ptr.atIndex(0).deref().getAPFloat(), + Ptr.atIndex(1).deref().getAPFloat()); + return true; + } + return false; + } llvm_unreachable("invalid value to return"); }; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 13b77e9a87725c73efd19346cafde1f43728bd9c..a82d1c3c7c622a3db101443ed6fc8aa5d144f51d 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -350,11 +350,6 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { } if (!F->isConstexpr()) { - // Don't emit anything if we're checking for a potential constant - // expression. That will happen later when actually executing. - if (S.checkingPotentialConstantExpression()) - return false; - const SourceLocation &Loc = S.Current->getLocation(OpPC); if (S.getLangOpts().CPlusPlus11) { const FunctionDecl *DiagDecl = F->getDecl(); @@ -371,13 +366,21 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { // FIXME: If DiagDecl is an implicitly-declared special member function // or an inheriting constructor, we should be much more explicit about why // it's not constexpr. - if (CD && CD->isInheritingConstructor()) + if (CD && CD->isInheritingConstructor()) { S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) << CD->getInheritedConstructor().getConstructor()->getParent(); - else + S.Note(DiagDecl->getLocation(), diag::note_declared_at); + } else { + // Don't emit anything if the function isn't defined and we're checking + // for a constant expression. It might be defined at the point we're + // actually calling it. + if (!DiagDecl->isDefined() && S.checkingPotentialConstantExpression()) + return false; + S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; - S.Note(DiagDecl->getLocation(), diag::note_declared_at); + S.Note(DiagDecl->getLocation(), diag::note_declared_at); + } } else { S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); } diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 64c971912a91d073328c835523430be6b36e1ac2..d3a6b61fd2bec9c659b24c4ab995f4459254d54f 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -147,7 +147,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) { // If the label isn't literal, or if this is an alias for an LLVM intrinsic, // do not add a "\01" prefix. - if (!ALA->getIsLiteralLabel() || ALA->getLabel().startswith("llvm.")) { + if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) { Out << ALA->getLabel(); return; } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index c59a66e103a6e3b929fa950f93414bd58c185de0..8346ad87b409b6196126164086468673b0ca48c4 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -63,7 +63,7 @@ struct msvc_hashing_ostream : public llvm::raw_svector_ostream { : llvm::raw_svector_ostream(Buffer), OS(OS) {} ~msvc_hashing_ostream() override { StringRef MangledName = str(); - bool StartsWithEscape = MangledName.startswith("\01"); + bool StartsWithEscape = MangledName.starts_with("\01"); if (StartsWithEscape) MangledName = MangledName.drop_front(1); if (MangledName.size() < 4096) { diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index f0b9d0ecaf23461ac1b846a45cb39dab0257cf1b..3b09ca40bd2a53e99f50ea8bb805e4e56bb6c4f9 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -140,7 +140,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, // Set the privacy flag if the privacy annotation in the // comma-delimited segment is at least as strict as the privacy // annotations in previous comma-delimited segments. - if (MatchedStr.startswith("mask")) { + if (MatchedStr.starts_with("mask")) { StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1); unsigned Size = MaskType.size(); if (Warn && (Size == 0 || Size > 8)) diff --git a/clang/lib/AST/RawCommentList.cpp b/clang/lib/AST/RawCommentList.cpp index c3beb23228887a8865a17268494ec46f7becb051..dffa007b6588bc05895f2789532d0f23c4586b5b 100644 --- a/clang/lib/AST/RawCommentList.cpp +++ b/clang/lib/AST/RawCommentList.cpp @@ -141,8 +141,8 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, Kind = K.first; IsTrailingComment |= K.second; - IsAlmostTrailingComment = RawText.startswith("//<") || - RawText.startswith("/*<"); + IsAlmostTrailingComment = + RawText.starts_with("//<") || RawText.starts_with("/*<"); } else { Kind = RCK_Merged; IsTrailingComment = diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index c31fb48a2addfa3a627e8344f2d8920c970056a5..afd05881cb162107501d372bbfbaeb5a6e1d1a8a 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -811,11 +811,12 @@ std::string MSAsmStmt::generateAsmString(const ASTContext &C) const { StringRef Instruction = Pieces[I]; // For vex/vex2/vex3/evex masm style prefix, convert it to att style // since we don't support masm style prefix in backend. - if (Instruction.startswith("vex ")) + if (Instruction.starts_with("vex ")) MSAsmString += '{' + Instruction.substr(0, 3).str() + '}' + Instruction.substr(3).str(); - else if (Instruction.startswith("vex2 ") || - Instruction.startswith("vex3 ") || Instruction.startswith("evex ")) + else if (Instruction.starts_with("vex2 ") || + Instruction.starts_with("vex3 ") || + Instruction.starts_with("evex ")) MSAsmString += '{' + Instruction.substr(0, 4).str() + '}' + Instruction.substr(4).str(); else diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 435bbdeda22066e8cd42255178af66e135b639ca..8ed213ca2ce0965bf9f9c22e6a5bef8287beb4c3 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -480,11 +480,11 @@ HasNameMatcher::HasNameMatcher(std::vector N) static bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) { StringRef Name = FullName; - if (!Name.endswith(Suffix)) + if (!Name.ends_with(Suffix)) return false; Name = Name.drop_back(Suffix.size()); if (!Name.empty()) { - if (!Name.endswith("::")) + if (!Name.ends_with("::")) return false; Name = Name.drop_back(2); } @@ -530,7 +530,7 @@ public: PatternSet(ArrayRef Names) { Patterns.reserve(Names.size()); for (StringRef Name : Names) - Patterns.push_back({Name, Name.startswith("::")}); + Patterns.push_back({Name, Name.starts_with("::")}); } /// Consumes the name suffix from each pattern in the set and removes the ones @@ -652,11 +652,11 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const { const StringRef FullName = OS.str(); for (const StringRef Pattern : Names) { - if (Pattern.startswith("::")) { + if (Pattern.starts_with("::")) { if (FullName == Pattern) return true; - } else if (FullName.endswith(Pattern) && - FullName.drop_back(Pattern.size()).endswith("::")) { + } else if (FullName.ends_with(Pattern) && + FullName.drop_back(Pattern.size()).ends_with("::")) { return true; } } diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp index 33a10fe838a6aa6f27fe0dc2b77c4543760a1133..27096a83b8dd603eff2dd9d42b542eb6061d3795 100644 --- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp @@ -187,10 +187,10 @@ private: break; ++TokenLength; } - if (TokenLength == 4 && Code.startswith("true")) { + if (TokenLength == 4 && Code.starts_with("true")) { Result.Kind = TokenInfo::TK_Literal; Result.Value = true; - } else if (TokenLength == 5 && Code.startswith("false")) { + } else if (TokenLength == 5 && Code.starts_with("false")) { Result.Kind = TokenInfo::TK_Literal; Result.Value = false; } else { @@ -737,7 +737,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, // Completions minus the prefix. void Parser::addCompletion(const TokenInfo &CompToken, const MatcherCompletion& Completion) { - if (StringRef(Completion.TypedText).startswith(CompToken.Text) && + if (StringRef(Completion.TypedText).starts_with(CompToken.Text) && Completion.Specificity > 0) { Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()), Completion.MatcherDecl, Completion.Specificity); diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index 13ec9b65c9f0b2ef7cd71eacceb94220a1afcb75..127e843d4ead21637f6a29c6dcd9811403df2ec6 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -726,8 +726,8 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { FF = nullptr; break; } - } else if (Name.startswith("OSAtomicCompareAndSwap") || - Name.startswith("objc_atomicCompareAndSwap")) { + } else if (Name.starts_with("OSAtomicCompareAndSwap") || + Name.starts_with("objc_atomicCompareAndSwap")) { FF = create_OSAtomicCompareAndSwap; } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) { FF = create_call_once; diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp index 59cc939b6fd15e991c4584b98c7310c379b9259f..f892980ed31386b1c6e27b085c7716b6fd856250 100644 --- a/clang/lib/Analysis/CallGraph.cpp +++ b/clang/lib/Analysis/CallGraph.cpp @@ -168,7 +168,7 @@ bool CallGraph::includeCalleeInGraph(const Decl *D) { return false; IdentifierInfo *II = FD->getIdentifier(); - if (II && II->getName().startswith("__inline")) + if (II && II->getName().starts_with("__inline")) return false; } diff --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp index 5b4fc24b6f0e2a557066dee417abd68d5aa3863f..04c5f6aa9c7450cdaf1b9a76c94f7dd3ddda3f59 100644 --- a/clang/lib/Analysis/CalledOnceCheck.cpp +++ b/clang/lib/Analysis/CalledOnceCheck.cpp @@ -973,7 +973,7 @@ private: /// Return true if the given name has conventional suffixes. static bool hasConventionalSuffix(llvm::StringRef Name) { return llvm::any_of(CONVENTIONAL_SUFFIXES, [Name](llvm::StringRef Suffix) { - return Name.endswith(Suffix); + return Name.ends_with(Suffix); }); } diff --git a/clang/lib/Analysis/CocoaConventions.cpp b/clang/lib/Analysis/CocoaConventions.cpp index 571d72e1a841656e681858332a336e539d4d9042..836859c2234585beed0dc70b65c6a443c9cc0428 100644 --- a/clang/lib/Analysis/CocoaConventions.cpp +++ b/clang/lib/Analysis/CocoaConventions.cpp @@ -26,10 +26,10 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix, // Recursively walk the typedef stack, allowing typedefs of reference types. while (const TypedefType *TD = RetTy->getAs()) { StringRef TDName = TD->getDecl()->getIdentifier()->getName(); - if (TDName.startswith(Prefix) && TDName.endswith("Ref")) + if (TDName.starts_with(Prefix) && TDName.ends_with("Ref")) return true; // XPC unfortunately uses CF-style function names, but aren't CF types. - if (TDName.startswith("xpc_")) + if (TDName.starts_with("xpc_")) return false; RetTy = TD->getDecl()->getUnderlyingType(); } @@ -43,7 +43,7 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix, return false; // Does the name start with the prefix? - return Name.startswith(Prefix); + return Name.starts_with(Prefix); } /// Returns true when the passed-in type is a CF-style reference-counted @@ -127,10 +127,9 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) { // Scan for *lowercase* 'reate' or 'opy', followed by no lowercase // character. StringRef suffix = functionName.substr(it - start); - if (suffix.startswith("reate")) { + if (suffix.starts_with("reate")) { it += 5; - } - else if (suffix.startswith("opy")) { + } else if (suffix.starts_with("opy")) { it += 3; } else { // Keep scanning. diff --git a/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp index f49087ababc44ce325c8eb08efde418da28a977f..5ac71e1d6bf64d5c8543cf01a71e44b82a606535 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp @@ -43,7 +43,7 @@ bool isCheckLikeMethod(llvm::SmallDenseSet &CheckDecls, return false; for (const CXXMethodDecl *M : ParentClass->methods()) - if (M->getDeclName().isIdentifier() && M->getName().endswith("Check")) + if (M->getDeclName().isIdentifier() && M->getName().ends_with("Check")) CheckDecls.insert(M); } diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index 4cbeb0c35b6f6642d9ecec63ba823fe34155454e..6f50d95b179f412342d76f19a243d3bcda7e693f 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -174,7 +174,7 @@ static bool isOSObjectPtr(QualType QT) { } static bool isISLObjectRef(QualType Ty) { - return StringRef(Ty.getAsString()).startswith("isl_"); + return StringRef(Ty.getAsString()).starts_with("isl_"); } static bool isOSIteratorSubclass(const Decl *D) { @@ -255,13 +255,13 @@ RetainSummaryManager::getSummaryForOSObject(const FunctionDecl *FD, // TODO: Add support for the slightly common *Matching(table) idiom. // Cf. IOService::nameMatching() etc. - these function have an unusual // contract of returning at +0 or +1 depending on their last argument. - if (FName.endswith("Matching")) { + if (FName.ends_with("Matching")) { return getPersistentStopSummary(); } // All objects returned with functions *not* starting with 'get', // or iterators, are returned at +1. - if ((!FName.startswith("get") && !FName.startswith("Get")) || + if ((!FName.starts_with("get") && !FName.starts_with("Get")) || isOSIteratorSubclass(PD)) { return getOSSummaryCreateRule(FD); } else { @@ -392,9 +392,9 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject( return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs, ArgEffect(DoNothing), ArgEffect(DoNothing)); - } else if (FName.startswith("NSLog")) { + } else if (FName.starts_with("NSLog")) { return getDoNothingSummary(); - } else if (FName.startswith("NS") && FName.contains("Insert")) { + } else if (FName.starts_with("NS") && FName.contains("Insert")) { // Allowlist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); @@ -453,9 +453,9 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject( // Check for release functions, the only kind of functions that we care // about that don't return a pointer type. - if (FName.startswith("CG") || FName.startswith("CF")) { + if (FName.starts_with("CG") || FName.starts_with("CF")) { // Test for 'CGCF'. - FName = FName.substr(FName.startswith("CGCF") ? 4 : 2); + FName = FName.substr(FName.starts_with("CGCF") ? 4 : 2); if (isRelease(FD, FName)) return getUnarySummary(FT, DecRef); diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index bb495216ca93ca587d776e1775ff12982a5ebbc0..44a4f1890d39e11bc70678b7cbc1cbe514b367f9 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -33,7 +33,7 @@ int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, const TargetInfo &Target, const LangOptions &LangOpts) { StringRef Name = Attr->getName(); // Normalize the attribute name, __foo__ becomes foo. - if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__")) Name = Name.substr(2, Name.size() - 4); // Normalize the scope name, but only for gnu and clang attributes. @@ -103,8 +103,8 @@ static StringRef normalizeAttrName(const IdentifierInfo *Name, (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" || NormalizedScopeName == "clang")); StringRef AttrName = Name->getName(); - if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") && - AttrName.endswith("__")) + if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") && + AttrName.ends_with("__")) AttrName = AttrName.slice(2, AttrName.size() - 2); return AttrName; diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index e5667d57f8cff114c316a40526e4b116ce9e2924..6c7bd50eefb7ef618ce8df9b175aa2f13d6ade1c 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -853,5 +853,5 @@ bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const { bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) { unsigned cat = getCategoryNumberForDiag(DiagID); - return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC "); + return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC "); } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 38150d1640d709d96583feab5639dbb6d0d64108..5902c6dc3ce0b48073bac9663a50e6cc82106fa0 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -604,7 +604,7 @@ LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); } static bool startsWithWord(StringRef name, StringRef word) { if (name.size() < word.size()) return false; return ((name.size() == word.size() || !isLowercase(name[word.size()])) && - name.startswith(word)); + name.starts_with(word)); } ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { @@ -742,7 +742,7 @@ SelectorTable::constructSetterSelector(IdentifierTable &Idents, std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) { StringRef Name = Sel.getNameForSlot(0); - assert(Name.startswith("set") && "invalid setter name"); + assert(Name.starts_with("set") && "invalid setter name"); return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str(); } diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 7523e509a47108c207559585d0e988371c1532ef..925217431d4d021a73154202dc50cfaf2adc5567 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -166,7 +166,8 @@ bool Module::isForBuilding(const LangOptions &LangOpts) const { // for either. if (!LangOpts.isCompilingModule() && getTopLevelModule()->IsFramework && CurrentModule == LangOpts.ModuleName && - !CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private")) + !CurrentModule.ends_with("_Private") && + TopLevelName.ends_with("_Private")) TopLevelName = TopLevelName.drop_back(8); return TopLevelName == CurrentModule; diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp index 3476103cc39d40890c6b5e37a2a045f91167089f..1cae7b937bc6ee2b676e68c5a8b9575b6dd7e9cf 100644 --- a/clang/lib/Basic/Sarif.cpp +++ b/clang/lib/Basic/Sarif.cpp @@ -74,7 +74,7 @@ static std::string fileNameToURI(StringRef Filename) { // Get the root name to see if it has a URI authority. StringRef Root = sys::path::root_name(Filename); - if (Root.startswith("//")) { + if (Root.starts_with("//")) { // There is an authority, so add it to the URI. Ret += Root.drop_front(2).str(); } else if (!Root.empty()) { diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 6cd5d618a4acaa59e26aa1c9aa74a0a8abac11a3..96b3ad9ba2f2731b1bd3a5443a0b6d1a5ceae6f5 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -551,26 +551,26 @@ ParsedTargetAttr TargetInfo::parseTargetAttr(StringRef Features) const { // TODO: Support the fpmath option. It will require checking // overall feature validity for the function with the rest of the // attributes on the function. - if (Feature.startswith("fpmath=")) + if (Feature.starts_with("fpmath=")) continue; - if (Feature.startswith("branch-protection=")) { + if (Feature.starts_with("branch-protection=")) { Ret.BranchProtection = Feature.split('=').second.trim(); continue; } // While we're here iterating check for a different target cpu. - if (Feature.startswith("arch=")) { + if (Feature.starts_with("arch=")) { if (!Ret.CPU.empty()) Ret.Duplicate = "arch="; else Ret.CPU = Feature.split("=").second.trim(); - } else if (Feature.startswith("tune=")) { + } else if (Feature.starts_with("tune=")) { if (!Ret.Tune.empty()) Ret.Duplicate = "tune="; else Ret.Tune = Feature.split("=").second.trim(); - } else if (Feature.startswith("no-")) + } else if (Feature.starts_with("no-")) Ret.Features.push_back("-" + Feature.split("-").second.str()); else Ret.Features.push_back("+" + Feature.str()); diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index e3e08b571667cce2df44ebc0658b2f4f68bcd2d8..def16c032c869e59c3acb51bd4e8dfd19880fe2b 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1062,7 +1062,7 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const { else // Pushing the original feature string to give a sema error later on // when they get checked. - if (Feature.startswith("no")) + if (Feature.starts_with("no")) Features.push_back("-" + Feature.drop_front(2).str()); else Features.push_back("+" + Feature.str()); @@ -1071,15 +1071,15 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const { for (auto &Feature : AttrFeatures) { Feature = Feature.trim(); - if (Feature.startswith("fpmath=")) + if (Feature.starts_with("fpmath=")) continue; - if (Feature.startswith("branch-protection=")) { + if (Feature.starts_with("branch-protection=")) { Ret.BranchProtection = Feature.split('=').second.trim(); continue; } - if (Feature.startswith("arch=")) { + if (Feature.starts_with("arch=")) { if (FoundArch) Ret.Duplicate = "arch="; FoundArch = true; @@ -1095,7 +1095,7 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const { Ret.Features.push_back(AI->ArchFeature.str()); // Add any extra features, after the + SplitAndAddFeatures(Split.second, Ret.Features); - } else if (Feature.startswith("cpu=")) { + } else if (Feature.starts_with("cpu=")) { if (!Ret.CPU.empty()) Ret.Duplicate = "cpu="; else { @@ -1106,14 +1106,14 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const { Ret.CPU = Split.first; SplitAndAddFeatures(Split.second, Ret.Features); } - } else if (Feature.startswith("tune=")) { + } else if (Feature.starts_with("tune=")) { if (!Ret.Tune.empty()) Ret.Duplicate = "tune="; else Ret.Tune = Feature.split("=").second.trim(); - } else if (Feature.startswith("+")) { + } else if (Feature.starts_with("+")) { SplitAndAddFeatures(Feature, Ret.Features); - } else if (Feature.startswith("no-")) { + } else if (Feature.starts_with("no-")) { StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature.split("-").second); if (!FeatureName.empty()) diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 719fc51bfc286fb57247ea71b2c7626ce49e7e83..b064ec2b3c9a6e6639074f2f4961eb43c1c68948 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -279,7 +279,7 @@ void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro(Twine("__") + Twine(CanonName) + Twine("__")); // Emit macros for gfx family e.g. gfx906 -> __GFX9__, gfx1030 -> __GFX10___ if (isAMDGCN(getTriple())) { - assert(CanonName.startswith("gfx") && "Invalid amdgcn canonical name"); + assert(CanonName.starts_with("gfx") && "Invalid amdgcn canonical name"); Builder.defineMacro(Twine("__") + Twine(CanonName.drop_back(2).upper()) + Twine("__")); } diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp index bc90d1b93d53f6daf14e10497d0df35d4fcfe508..3a65f53c524851b1188b9d7afb8597b2364fb9e0 100644 --- a/clang/lib/Basic/Targets/Mips.cpp +++ b/clang/lib/Basic/Targets/Mips.cpp @@ -196,7 +196,7 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, else Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); - if (StringRef(CPU).startswith("octeon")) + if (StringRef(CPU).starts_with("octeon")) Builder.defineMacro("__OCTEON__"); if (CPU != "mips1") { diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 5c601812f617596526cc6d2a0e22cbc23bb5e05d..c0b5db795e2708a84a05934585271e1b6009b2fe 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -42,7 +42,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple, PTXVersion = 32; for (const StringRef Feature : Opts.FeaturesAsWritten) { int PTXV; - if (!Feature.startswith("+ptx") || + if (!Feature.starts_with("+ptx") || Feature.drop_front(4).getAsInteger(10, PTXV)) continue; PTXVersion = PTXV; // TODO: should it be max(PTXVersion, PTXV)? diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 45d23022b5306b3c5e5ec41d637520dccc0cde72..60a4e0ed69c34dcc5b9106cbc4630665f64ca2d6 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -434,14 +434,14 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { Feature = Feature.trim(); StringRef AttrString = Feature.split("=").second.trim(); - if (Feature.startswith("arch=")) { + if (Feature.starts_with("arch=")) { // Override last features Ret.Features.clear(); if (FoundArch) Ret.Duplicate = "arch="; FoundArch = true; - if (AttrString.startswith("+")) { + if (AttrString.starts_with("+")) { // EXTENSION like arch=+v,+zbb SmallVector Exts; AttrString.split(Exts, ","); @@ -461,7 +461,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { // full-arch-string like arch=rv64gcv handleFullArchString(AttrString, Ret.Features); } - } else if (Feature.startswith("cpu=")) { + } else if (Feature.starts_with("cpu=")) { if (!Ret.CPU.empty()) Ret.Duplicate = "cpu="; @@ -475,7 +475,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { handleFullArchString(MarchFromCPU, Ret.Features); } } - } else if (Feature.startswith("tune=")) { + } else if (Feature.starts_with("tune=")) { if (!Ret.Tune.empty()) Ret.Duplicate = "tune="; diff --git a/clang/lib/Basic/Warnings.cpp b/clang/lib/Basic/Warnings.cpp index cc8c138233ca1d9fcc4ef04840b87fb2efb94655..cb23d844ef8f6f24538e920f80f7f483c9d50732 100644 --- a/clang/lib/Basic/Warnings.cpp +++ b/clang/lib/Basic/Warnings.cpp @@ -97,7 +97,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, // Check to see if this warning starts with "no-", if so, this is a // negative form of the option. bool isPositive = true; - if (Opt.startswith("no-")) { + if (Opt.starts_with("no-")) { isPositive = false; Opt = Opt.substr(3); } @@ -133,7 +133,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, // table. It also has the "specifier" form of -Werror=foo. GCC supports // the deprecated -Werror-implicit-function-declaration which is used by // a few projects. - if (Opt.startswith("error")) { + if (Opt.starts_with("error")) { StringRef Specifier; if (Opt.size() > 5) { // Specifier must be present. if (Opt[5] != '=' && @@ -162,7 +162,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, } // -Wfatal-errors is yet another special case. - if (Opt.startswith("fatal-errors")) { + if (Opt.starts_with("fatal-errors")) { StringRef Specifier; if (Opt.size() != 12) { if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { @@ -204,7 +204,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, // Check to see if this warning starts with "no-", if so, this is a // negative form of the option. - bool IsPositive = !Opt.startswith("no-"); + bool IsPositive = !Opt.starts_with("no-"); if (!IsPositive) Opt = Opt.substr(3); auto Severity = IsPositive ? diag::Severity::Remark diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 83d0a72aac5495f55d960f066bfff6bc4a201324..353b7930b3c1ea42a9680110462e8ea5609ecbd9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -9985,6 +9985,10 @@ CodeGenFunction::getSVEOverloadTypes(const SVETypeFlags &TypeFlags, if (TypeFlags.isOverloadCvt()) return {Ops[0]->getType(), Ops.back()->getType()}; + if (TypeFlags.isReductionQV() && !ResultType->isScalableTy() && + ResultType->isVectorTy()) + return {ResultType, Ops[1]->getType()}; + assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads"); return {DefaultType}; } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a24aeea7ae32bfc9b58a8fe5c2b024fb3d46f2e7..51a43b5f85b3cc40cb135ab04593f181f1e29369 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -5609,7 +5609,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, EmitBlock(Cont); } if (CI->getCalledFunction() && CI->getCalledFunction()->hasName() && - CI->getCalledFunction()->getName().startswith("_Z4sqrt")) { + CI->getCalledFunction()->getName().starts_with("_Z4sqrt")) { SetSqrtFPAccuracy(CI); } if (callOrInvoke) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 37d7a6755d3908c051440edb25f38a4f1c02d216..236d53bee4e8f1888782c0bd8ae46b2122b1ee75 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -637,7 +637,8 @@ void CGDebugInfo::CreateCompileUnit() { Sysroot = CGM.getHeaderSearchOpts().Sysroot; auto B = llvm::sys::path::rbegin(Sysroot); auto E = llvm::sys::path::rend(Sysroot); - auto It = std::find_if(B, E, [](auto SDK) { return SDK.endswith(".sdk"); }); + auto It = + std::find_if(B, E, [](auto SDK) { return SDK.ends_with(".sdk"); }); if (It != E) SDK = *It; } @@ -2885,7 +2886,7 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, // clang::Module object, but it won't actually be built or imported; it will // be textual. if (CreateSkeletonCU && IsRootModule && Mod.getASTFile().empty() && M) - assert(StringRef(M->Name).startswith(CGM.getLangOpts().ModuleName) && + assert(StringRef(M->Name).starts_with(CGM.getLangOpts().ModuleName) && "clang module without ASTFile must be specified by -fmodule-name"); // Return a StringRef to the remapped Path. @@ -4249,7 +4250,7 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, Flags |= llvm::DINode::FlagPrototyped; } - if (Name.startswith("\01")) + if (Name.starts_with("\01")) Name = Name.substr(1); assert((!D || !isa(D) || diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index bae8babb8efe4a8cfdbcad74c0877e3f0064ad15..0d507da5c1ba92f78ac5df4f0840c9e7edf605ac 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -277,7 +277,7 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { if (llvm::GlobalVariable *GV = dyn_cast(Val)) // ObjC EH selector entries are always global variables with // names starting like this. - if (GV->getName().startswith("OBJC_EHTYPE")) + if (GV->getName().starts_with("OBJC_EHTYPE")) return false; } else { // Check if any of the filter values have the ObjC prefix. @@ -288,7 +288,7 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { cast((*II)->stripPointerCasts())) // ObjC EH selector entries are always global variables with // names starting like this. - if (GV->getName().startswith("OBJC_EHTYPE")) + if (GV->getName().starts_with("OBJC_EHTYPE")) return false; } } @@ -1917,7 +1917,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, const VarDecl *D = cast(I.first); if (isa(D) && D->getType() == getContext().VoidPtrTy) { - assert(D->getName().startswith("frame_pointer")); + assert(D->getName().starts_with("frame_pointer")); FramePtrAddrAlloca = cast(I.second.getPointer()); break; } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 69cf7f76be9a7091742e3498c1a904ec838eafe5..ed9aaa28c257337c321592b88e3af54103c2c968 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -431,7 +431,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, /// Helper method to check if the underlying ABI is AAPCS static bool isAAPCS(const TargetInfo &TargetInfo) { - return TargetInfo.getABI().startswith("aapcs"); + return TargetInfo.getABI().starts_with("aapcs"); } LValue CodeGenFunction:: @@ -3156,7 +3156,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { auto SL = E->getFunctionName(); assert(SL != nullptr && "No StringLiteral name in PredefinedExpr"); StringRef FnName = CurFn->getName(); - if (FnName.startswith("\01")) + if (FnName.starts_with("\01")) FnName = FnName.substr(1); StringRef NameItems[] = { PredefinedExpr::getIdentKindName(E->getIdentKind()), FnName}; diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index ba52b23be018b85cda05422c1bb397788d32b07e..517f7cddebc1a2b58ff52858e9a65e34222d087a 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1850,7 +1850,7 @@ static bool hasObjCExceptionAttribute(ASTContext &Context, static llvm::GlobalValue::LinkageTypes getLinkageTypeForObjCMetadata(CodeGenModule &CGM, StringRef Section) { if (CGM.getTriple().isOSBinFormatMachO() && - (Section.empty() || Section.startswith("__DATA"))) + (Section.empty() || Section.starts_with("__DATA"))) return llvm::GlobalValue::InternalLinkage; return llvm::GlobalValue::PrivateLinkage; } @@ -6162,7 +6162,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList( // Section name is obtained by calling GetSectionName, which returns // sections in the __DATA segment on MachO. assert((!CGM.getTriple().isOSBinFormatMachO() || - SectionName.startswith("__DATA")) && + SectionName.starts_with("__DATA")) && "SectionName expected to start with __DATA on MachO"); llvm::GlobalVariable *GV = new llvm::GlobalVariable( CGM.getModule(), Init->getType(), false, diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index cbfa79e10bfefcc95eaeafdde2ea35a52e112081..868ef810f3c4e8c5d84c5b8b90d7d2f5738278f3 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -111,7 +111,7 @@ struct CGRecordLowering { /// Helper function to check if we are targeting AAPCS. bool isAAPCS() const { - return Context.getTargetInfo().getABI().startswith("aapcs"); + return Context.getTargetInfo().getABI().starts_with("aapcs"); } /// Helper function to check if the target machine is BigEndian. diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index a5cb80640641bb21cf81fa1cfab95dede66d981c..0f79a2e861d220474883cba554bc0779805c9677 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2548,7 +2548,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { ResultRegQualTys.push_back(QTy); ResultRegDests.push_back(Dest); - bool IsFlagReg = llvm::StringRef(OutputConstraint).startswith("{@cc"); + bool IsFlagReg = llvm::StringRef(OutputConstraint).starts_with("{@cc"); ResultRegIsFlagReg.push_back(IsFlagReg); llvm::Type *Ty = ConvertTypeForMem(QTy); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index bb6b1a3bc228cf9889bfc3655c48884c20410acb..753a8fd74fa696045eb0eb13920f42a4a2dac472 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -1139,7 +1139,7 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) { // Strip off a leading diagnostic code if there is one. StringRef Msg = Err.getMessage(); - if (Msg.startswith("error: ")) + if (Msg.starts_with("error: ")) Msg = Msg.substr(7); unsigned DiagID = diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b931a81bc00871b6d1de5fc0919e64467324b6cb..7ad26ace328ab2e324c3470f6265104a3a16e4f1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -225,9 +225,9 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { StringRef ABIStr = Target.getABI(); unsigned XLen = Target.getPointerWidth(LangAS::Default); unsigned ABIFLen = 0; - if (ABIStr.endswith("f")) + if (ABIStr.ends_with("f")) ABIFLen = 32; - else if (ABIStr.endswith("d")) + else if (ABIStr.ends_with("d")) ABIFLen = 64; return createRISCVTargetCodeGenInfo(CGM, XLen, ABIFLen); } @@ -308,9 +308,9 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { case llvm::Triple::loongarch64: { StringRef ABIStr = Target.getABI(); unsigned ABIFRLen = 0; - if (ABIStr.endswith("f")) + if (ABIStr.ends_with("f")) ABIFRLen = 32; - else if (ABIStr.endswith("d")) + else if (ABIStr.ends_with("d")) ABIFRLen = 64; return createLoongArchTargetCodeGenInfo( CGM, Target.getPointerWidth(LangAS::Default), ABIFRLen); @@ -1715,7 +1715,7 @@ static void AppendTargetMangling(const CodeGenModule &CGM, llvm::sort(Info.Features, [&Target](StringRef LHS, StringRef RHS) { // Multiversioning doesn't allow "no-${feature}", so we can // only have "+" prefixes here. - assert(LHS.startswith("+") && RHS.startswith("+") && + assert(LHS.starts_with("+") && RHS.starts_with("+") && "Features should always have a prefix."); return Target.multiVersionSortPriority(LHS.substr(1)) > Target.multiVersionSortPriority(RHS.substr(1)); @@ -1769,7 +1769,7 @@ static void AppendTargetClonesMangling(const CodeGenModule &CGM, } else { Out << '.'; StringRef FeatureStr = Attr->getFeatureStr(VersionIndex); - if (FeatureStr.startswith("arch=")) + if (FeatureStr.starts_with("arch=")) Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1); else Out << FeatureStr; @@ -3828,7 +3828,7 @@ namespace { if (!BuiltinID || !BI.isLibFunction(BuiltinID)) return false; StringRef BuiltinName = BI.getName(BuiltinID); - if (BuiltinName.startswith("__builtin_") && + if (BuiltinName.starts_with("__builtin_") && Name == BuiltinName.slice(strlen("__builtin_"), StringRef::npos)) { return true; } @@ -4164,7 +4164,7 @@ void CodeGenModule::emitMultiVersionFunctions() { Feature.push_back(CurFeat.trim()); } } else { - if (Version.startswith("arch=")) + if (Version.starts_with("arch=")) Architecture = Version.drop_front(sizeof("arch=") - 1); else if (Version != "default") Feature.push_back(Version); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index b16358ee117ae20707f767dcff0c58af3a89a437..56411e2240e505ea617587199fe28de761f60509 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1623,8 +1623,12 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName, OS << "Gap,"; break; case CounterMappingRegion::BranchRegion: + case CounterMappingRegion::MCDCBranchRegion: OS << "Branch,"; break; + case CounterMappingRegion::MCDCDecisionRegion: + OS << "Decision,"; + break; } OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index 8bacba65617e431c1e2911a87284875de2e0920d..cf068cbc4fcd36806f5f2d452a216aac56b8ed2a 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -146,14 +146,14 @@ static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType, // Choose the dimension of the image--this corresponds to the Dim enum in // SPIR-V (first integer parameter of OpTypeImage). - if (OpenCLName.startswith("image2d")) + if (OpenCLName.starts_with("image2d")) IntParams[0] = 1; // 1D - else if (OpenCLName.startswith("image3d")) + else if (OpenCLName.starts_with("image3d")) IntParams[0] = 2; // 2D else if (OpenCLName == "image1d_buffer") IntParams[0] = 5; // Buffer else - assert(OpenCLName.startswith("image1d") && "Unknown image type"); + assert(OpenCLName.starts_with("image1d") && "Unknown image type"); // Set the other integer parameters of OpTypeImage if necessary. Note that the // OpenCL image types don't provide any information for the Sampled or diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp index 36f828f8cae26d31193f925ed8b07f15b321923f..a7e7f169dc1419e3d64c7acbe047d56753952afe 100644 --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -34,7 +34,7 @@ static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) { // Obviously this can be improved a lot. for (StringRef Line : Lines) - if (Version == Distro::UnknownDistro && Line.startswith("ID=")) + if (Version == Distro::UnknownDistro && Line.starts_with("ID=")) Version = llvm::StringSwitch(Line.substr(3)) .Case("alpine", Distro::AlpineLinux) .Case("fedora", Distro::Fedora) @@ -60,7 +60,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) { for (StringRef Line : Lines) if (Version == Distro::UnknownDistro && - Line.startswith("DISTRIB_CODENAME=")) + Line.starts_with("DISTRIB_CODENAME=")) Version = llvm::StringSwitch(Line.substr(17)) .Case("hardy", Distro::UbuntuHardy) .Case("intrepid", Distro::UbuntuIntrepid) @@ -119,10 +119,10 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { if (File) { StringRef Data = File.get()->getBuffer(); - if (Data.startswith("Fedora release")) + if (Data.starts_with("Fedora release")) return Distro::Fedora; - if (Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS") || Data.startswith("Scientific Linux")) { + if (Data.starts_with("Red Hat Enterprise Linux") || + Data.starts_with("CentOS") || Data.starts_with("Scientific Linux")) { if (Data.contains("release 7")) return Distro::RHEL7; else if (Data.contains("release 6")) @@ -182,7 +182,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { SmallVector Lines; Data.split(Lines, "\n"); for (const StringRef &Line : Lines) { - if (!Line.trim().startswith("VERSION")) + if (!Line.trim().starts_with("VERSION")) continue; std::pair SplitLine = Line.split('='); // Old versions have split VERSION and PATCHLEVEL diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index f392f6794f857e62df637602027a56e99ad2fb9e..ff95c899c5f3d4e91770f8203001a62eafddb199 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1451,7 +1451,7 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::aarch64_32: - if (TC.getTriple().getEnvironmentName().startswith("eabi")) { + if (TC.getTriple().getEnvironmentName().starts_with("eabi")) { Diag(diag::warn_target_unrecognized_env) << TargetTriple << (TC.getTriple().getArchName().str() + "-none-elf"); @@ -1540,7 +1540,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd; File != FileEnd && !EC; File.increment(EC)) { StringRef FileName = path::filename(File->path()); - if (!FileName.startswith(Name)) + if (!FileName.starts_with(Name)) continue; if (fs::status(File->path(), FileStatus)) continue; @@ -1551,7 +1551,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, // The first line should start with "Process:", otherwise this isn't a real // .crash file. StringRef Data = CrashFile.get()->getBuffer(); - if (!Data.startswith("Process:")) + if (!Data.starts_with("Process:")) continue; // Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]" size_t ParentProcPos = Data.find("Parent Process:"); @@ -1780,7 +1780,7 @@ void Driver::generateCompilationDiagnostics( ReproCrashFilename = TempFile; llvm::sys::path::replace_extension(ReproCrashFilename, ".crash"); } - if (StringRef(TempFile).endswith(".cache")) { + if (StringRef(TempFile).ends_with(".cache")) { // In some cases (modules) we'll dump extra data to help with reproducing // the crash into a directory next to the output. VFS = llvm::sys::path::filename(TempFile); @@ -2001,7 +2001,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag," // because the latter indicates that the user put space before pushing tab // which should end up in a file completion. - const bool HasSpace = PassedFlags.endswith(","); + const bool HasSpace = PassedFlags.ends_with(","); // Parse PassedFlags by "," as all the command-line flags are passed to this // function separated by "," @@ -2041,7 +2041,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // When flag ends with '=' and there was no value completion, return empty // string and fall back to the file autocompletion. - if (SuggestedCompletions.empty() && !Cur.endswith("=")) { + if (SuggestedCompletions.empty() && !Cur.ends_with("=")) { // If the flag is in the form of "--autocomplete=-foo", // we were requested to print out all option names that start with "-foo". // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". @@ -2053,7 +2053,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // TODO: Find a good way to add them to OptTable instead and them remove // this code. for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) - if (S.startswith(Cur)) + if (S.starts_with(Cur)) SuggestedCompletions.push_back(std::string(S)); } @@ -2535,7 +2535,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, // so we can't downgrade diagnostics for `/GR-` from an error to a warning // in cc mode. (We can in cl mode because cl.exe itself only warns on // unknown flags.) - if (IsCLMode() && Ty == types::TY_Object && !Value.startswith("/")) + if (IsCLMode() && Ty == types::TY_Object && !Value.starts_with("/")) return true; Diag(clang::diag::err_drv_no_such_file) << Value; @@ -6565,7 +6565,7 @@ llvm::StringRef clang::driver::getDriverMode(StringRef ProgName, getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName(); llvm::StringRef Opt; for (StringRef Arg : Args) { - if (!Arg.startswith(OptName)) + if (!Arg.starts_with(OptName)) continue; Opt = Arg; } @@ -6606,7 +6606,7 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl &Args, else Tokenizer = &llvm::cl::TokenizeGNUCommandLine; - if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).startswith("-cc1")) + if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).starts_with("-cc1")) MarkEOLs = false; llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer); @@ -6620,7 +6620,7 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl &Args, // If -cc1 came from a response file, remove the EOL sentinels. auto FirstArg = llvm::find_if(llvm::drop_begin(Args), [](const char *A) { return A != nullptr; }); - if (FirstArg != Args.end() && StringRef(*FirstArg).startswith("-cc1")) { + if (FirstArg != Args.end() && StringRef(*FirstArg).starts_with("-cc1")) { // If -cc1 came from a response file, remove the EOL sentinels. if (MarkEOLs) { auto newEnd = std::remove(Args.begin(), Args.end(), nullptr); diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp index 203400440f9f61f13fe60023cb93382654fed0cf..a6c1581be796261ebc1530dd3460b44d6e215507 100644 --- a/clang/lib/Driver/Job.cpp +++ b/clang/lib/Driver/Job.cpp @@ -95,10 +95,10 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, // These flags are treated as a single argument (e.g., -F). StringRef FlagRef(Flag); - IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I"); + IsInclude = FlagRef.starts_with("-F") || FlagRef.starts_with("-I"); if (IsInclude) return !HaveCrashVFS; - if (FlagRef.startswith("-fmodules-cache-path=")) + if (FlagRef.starts_with("-fmodules-cache-path=")) return true; SkipNum = 0; @@ -185,8 +185,8 @@ rewriteIncludes(const llvm::ArrayRef &Args, size_t Idx, SmallString<128> NewInc; if (NumArgs == 1) { StringRef FlagRef(Args[Idx + NumArgs - 1]); - assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) && - "Expecting -I or -F"); + assert((FlagRef.starts_with("-F") || FlagRef.starts_with("-I")) && + "Expecting -I or -F"); StringRef Inc = FlagRef.slice(2, StringRef::npos); if (getAbsPath(Inc, NewInc)) { SmallString<128> NewArg(FlagRef.slice(0, 2)); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index ab19166f18c2dcf96187eb36b62b02d8edcc677b..96a57927339a970d344d1a7eafdf74bca742eea9 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -315,7 +315,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { for (const auto &DS : DriverSuffixes) { StringRef Suffix(DS.Suffix); - if (ProgName.endswith(Suffix)) { + if (ProgName.ends_with(Suffix)) { Pos = ProgName.size() - Suffix.size(); return &DS; } @@ -345,7 +345,7 @@ static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) { // added via -target as implicit first argument. const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos); - if (!DS && ProgName.endswith(".exe")) { + if (!DS && ProgName.ends_with(".exe")) { // Try again after stripping the executable suffix: // clang++.exe -> clang++ ProgName = ProgName.drop_back(StringRef(".exe").size()); diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index aed8734b2bab0ffe77caa3807bdba74849d9f25f..f9670ea6f251bd2ed7e8b4334dbd0c3cb99fd512 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -88,7 +88,7 @@ static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) { for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) { llvm::StringRef ArgString(CmdArgs[i]); - if (ArgString.startswith("-bE:") || ArgString.startswith("-bexport:") || + if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") || ArgString == "-bexpall" || ArgString == "-bexpfull") return true; @@ -96,8 +96,8 @@ static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) { if (ArgString == "-b" && i + 1 < Size) { ++i; llvm::StringRef ArgNextString(CmdArgs[i]); - if (ArgNextString.startswith("E:") || - ArgNextString.startswith("export:") || ArgNextString == "expall" || + if (ArgNextString.starts_with("E:") || + ArgNextString.starts_with("export:") || ArgNextString == "expall" || ArgNextString == "expfull") return true; } diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index cad206ea4df1bc5c4c0e032dd40d90a57f1a2dd1..56f06fc5fccb7eb75ffec08dc4fce6fe4c61f0cc 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -49,7 +49,7 @@ RocmInstallationDetector::findSPACKPackage(const Candidate &Cand, FileEnd; File != FileEnd && !EC; File.increment(EC)) { llvm::StringRef FileName = llvm::sys::path::filename(File->path()); - if (FileName.startswith(Prefix)) { + if (FileName.starts_with(Prefix)) { SubDirs.push_back(FileName); if (SubDirs.size() > 1) break; @@ -84,13 +84,13 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); - if (!FileName.endswith(Suffix)) + if (!FileName.ends_with(Suffix)) continue; StringRef BaseName; - if (FileName.endswith(Suffix2)) + if (FileName.ends_with(Suffix2)) BaseName = FileName.drop_back(Suffix2.size()); - else if (FileName.endswith(Suffix)) + else if (FileName.ends_with(Suffix)) BaseName = FileName.drop_back(Suffix.size()); const StringRef ABIVersionPrefix = "oclc_abi_version_"; @@ -124,7 +124,7 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { WavefrontSize64.On = FilePath; } else if (BaseName == "oclc_wavefrontsize64_off") { WavefrontSize64.Off = FilePath; - } else if (BaseName.startswith(ABIVersionPrefix)) { + } else if (BaseName.starts_with(ABIVersionPrefix)) { unsigned ABIVersionNumber; if (BaseName.drop_front(ABIVersionPrefix.size()) .getAsInteger(/*Redex=*/0, ABIVersionNumber)) @@ -134,7 +134,7 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { // Process all bitcode filenames that look like // ocl_isa_version_XXX.amdgcn.bc const StringRef DeviceLibPrefix = "oclc_isa_version_"; - if (!BaseName.startswith(DeviceLibPrefix)) + if (!BaseName.starts_with(DeviceLibPrefix)) continue; StringRef IsaVersionNumber = @@ -230,7 +230,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { // /llvm-amdgpu--/bin directory. // We only consider the parent directory of llvm-amdgpu package as ROCm // installation candidate for SPACK. - if (ParentName.startswith("llvm-amdgpu-")) { + if (ParentName.starts_with("llvm-amdgpu-")) { auto SPACKPostfix = ParentName.drop_front(strlen("llvm-amdgpu-")).split('-'); auto SPACKReleaseStr = SPACKPostfix.first; @@ -243,7 +243,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin // Some versions of the aomp package install to /opt/rocm/aomp/bin - if (ParentName == "llvm" || ParentName.startswith("aomp")) + if (ParentName == "llvm" || ParentName.starts_with("aomp")) ParentDir = llvm::sys::path::parent_path(ParentDir); return Candidate(ParentDir.str(), /*StrictChecking=*/true); @@ -292,7 +292,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { FileEnd; File != FileEnd && !EC; File.increment(EC)) { llvm::StringRef FileName = llvm::sys::path::filename(File->path()); - if (!FileName.startswith("rocm-")) + if (!FileName.starts_with("rocm-")) continue; if (LatestROCm.empty()) { LatestROCm = FileName.str(); diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 097258b16924442abf7b067343eea81d9c8cb0ec..912df79417ae21e4892251960d7b05640d547a93 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -228,7 +228,7 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, if (MtuneLowerCase == "native") MtuneLowerCase = std::string(llvm::sys::getHostCPUName()); if (MtuneLowerCase == "cyclone" || - StringRef(MtuneLowerCase).startswith("apple")) { + StringRef(MtuneLowerCase).starts_with("apple")) { Features.push_back("+zcm"); Features.push_back("+zcz"); } @@ -262,7 +262,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, for (const auto *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) for (StringRef Value : A->getValues()) - if (Value.startswith("-march=")) + if (Value.starts_with("-march=")) WaMArch = Value.substr(7); // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or // "-Xassembler -march" is detected. Otherwise it may return false diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index f1d7aeb555f8bd0974cc5790cd1391d27fa9c5fe..25470db2b6cebd708bb7803299b38aa43a600cf1 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -67,9 +67,9 @@ void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, // Use getValues because -Wa can have multiple arguments // e.g. -Wa,-mcpu=foo,-mcpu=bar for (StringRef Value : A->getValues()) { - if (Value.startswith("-mcpu=")) + if (Value.starts_with("-mcpu=")) CPU = Value.substr(6); - if (Value.startswith("-march=")) + if (Value.starts_with("-march=")) Arch = Value.substr(7); } } @@ -285,9 +285,9 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, // There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm. if (Value == "-mthumb") IsThumb = true; - else if (Value.startswith("-march=")) + else if (Value.starts_with("-march=")) WaMArch = Value.substr(7); - else if (Value.startswith("-mcpu=")) + else if (Value.starts_with("-mcpu=")) WaMCPU = Value.substr(6); } } @@ -528,13 +528,13 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D, // We use getValues here because you can have many options per -Wa // We will keep the last one we find for each of these for (StringRef Value : A->getValues()) { - if (Value.startswith("-mfpu=")) { + if (Value.starts_with("-mfpu=")) { WaFPU = std::make_pair(A, Value.substr(6)); - } else if (Value.startswith("-mcpu=")) { + } else if (Value.starts_with("-mcpu=")) { WaCPU = std::make_pair(A, Value.substr(6)); - } else if (Value.startswith("-mhwdiv=")) { + } else if (Value.starts_with("-mhwdiv=")) { WaHDiv = std::make_pair(A, Value.substr(8)); - } else if (Value.startswith("-march=")) { + } else if (Value.starts_with("-march=")) { WaArch = std::make_pair(A, Value.substr(7)); } } @@ -796,7 +796,7 @@ fp16_fml_fallthrough: // Propagate frame-chain model selection if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) { StringRef FrameChainOption = A->getValue(); - if (FrameChainOption.startswith("aapcs")) + if (FrameChainOption.starts_with("aapcs")) Features.push_back("+aapcs-frame-chain"); if (FrameChainOption == "aapcs+leaf") Features.push_back("+aapcs-frame-chain-leaf"); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 3e51b2b5ce8642e0ac08afc98617e96b630e2816..fef0522aaf45b8a3d34b12782bf6c4ca27ab5645 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -234,15 +234,15 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); - bool IsNegative = Name.startswith("no-"); + bool IsNegative = Name.starts_with("no-"); if (IsNegative) Name = Name.substr(3); #ifndef NDEBUG - assert(Name.startswith("avx10.") && "Invalid AVX10 feature name."); + assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name."); StringRef Version, Width; std::tie(Version, Width) = Name.substr(6).split('-'); assert(Version == "1" && "Invalid AVX10 feature name."); @@ -260,7 +260,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); // Replace -mgeneral-regs-only with -x87, -mmx, -sse @@ -269,7 +269,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, continue; } - bool IsNegative = Name.startswith("no-"); + bool IsNegative = Name.starts_with("no-"); if (A->getOption().matches(options::OPT_mapx_features_EQ) || A->getOption().matches(options::OPT_mno_apx_features_EQ)) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f95f3227aba7d03bb4956b62f39569ce6ee49768..de9fd5eaa1e020f6f6d3d43ffccb0dd4f82e9840 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -223,7 +223,7 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, for (unsigned i = 0; i != NumOptions; ++i) { StringRef Val = A->getValue(i); - bool IsDisabled = Val.startswith(DisabledPrefixIn); + bool IsDisabled = Val.starts_with(DisabledPrefixIn); // Ignore the disablement token for string matching. if (IsDisabled) Val = Val.substr(1); @@ -433,7 +433,7 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs, const char *OutputFileName) { // No need to generate a value for -object-file-name if it was provided. for (auto *Arg : Args.filtered(options::OPT_Xclang)) - if (StringRef(Arg->getValue()).startswith("-object-file-name")) + if (StringRef(Arg->getValue()).starts_with("-object-file-name")) return; if (Args.hasArg(options::OPT_object_file_name_EQ)) @@ -940,7 +940,7 @@ static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, static bool hasClangPchSignature(const Driver &D, StringRef Path) { if (llvm::ErrorOr> MemBuf = D.getVFS().getBufferForFile(Path)) - return (*MemBuf)->getBuffer().startswith("CPCH"); + return (*MemBuf)->getBuffer().starts_with("CPCH"); return false; } @@ -1715,7 +1715,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || Val.equals("2048+")) { unsigned Bits = 0; - if (Val.endswith("+")) + if (Val.ends_with("+")) Val = Val.substr(0, Val.size() - 1); else { bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; @@ -2503,7 +2503,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, case llvm::Triple::thumbeb: case llvm::Triple::arm: case llvm::Triple::armeb: - if (Value.startswith("-mimplicit-it=")) { + if (Value.starts_with("-mimplicit-it=")) { // Only store the value; the last value set takes effect. ImplicitIt = Value.split("=").second; if (CheckARMImplicitITArg(ImplicitIt)) @@ -2528,12 +2528,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-use-tcc-in-div"); continue; } - if (Value.startswith("-msoft-float")) { + if (Value.starts_with("-msoft-float")) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+soft-float"); continue; } - if (Value.startswith("-mhard-float")) { + if (Value.starts_with("-mhard-float")) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-soft-float"); continue; @@ -2570,8 +2570,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-massembler-no-warn"); } else if (Value == "--noexecstack") { UseNoExecStack = true; - } else if (Value.startswith("-compress-debug-sections") || - Value.startswith("--compress-debug-sections") || + } else if (Value.starts_with("-compress-debug-sections") || + Value.starts_with("--compress-debug-sections") || Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { CmdArgs.push_back(Value.data()); @@ -2581,13 +2581,13 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value == "-mrelax-relocations=no" || Value == "--mrelax-relocations=no") { UseRelaxRelocations = false; - } else if (Value.startswith("-I")) { + } else if (Value.starts_with("-I")) { CmdArgs.push_back(Value.data()); // We need to consume the next argument if the current arg is a plain // -I. The next arg will be the include directory. if (Value == "-I") TakeNextArg = true; - } else if (Value.startswith("-gdwarf-")) { + } else if (Value.starts_with("-gdwarf-")) { // "-gdwarf-N" options are not cc1as options. unsigned DwarfVersion = DwarfVersionNum(Value); if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. @@ -2597,30 +2597,30 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, llvm::codegenoptions::DebugInfoConstructor, DwarfVersion, llvm::DebuggerKind::Default); } - } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || - Value.startswith("-mhwdiv") || Value.startswith("-march")) { + } else if (Value.starts_with("-mcpu") || Value.starts_with("-mfpu") || + Value.starts_with("-mhwdiv") || Value.starts_with("-march")) { // Do nothing, we'll validate it later. } else if (Value == "-defsym") { - if (A->getNumValues() != 2) { - D.Diag(diag::err_drv_defsym_invalid_format) << Value; - break; - } - const char *S = A->getValue(1); - auto Pair = StringRef(S).split('='); - auto Sym = Pair.first; - auto SVal = Pair.second; - - if (Sym.empty() || SVal.empty()) { - D.Diag(diag::err_drv_defsym_invalid_format) << S; - break; - } - int64_t IVal; - if (SVal.getAsInteger(0, IVal)) { - D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; - break; - } - CmdArgs.push_back(Value.data()); - TakeNextArg = true; + if (A->getNumValues() != 2) { + D.Diag(diag::err_drv_defsym_invalid_format) << Value; + break; + } + const char *S = A->getValue(1); + auto Pair = StringRef(S).split('='); + auto Sym = Pair.first; + auto SVal = Pair.second; + + if (Sym.empty() || SVal.empty()) { + D.Diag(diag::err_drv_defsym_invalid_format) << S; + break; + } + int64_t IVal; + if (SVal.getAsInteger(0, IVal)) { + D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; + break; + } + CmdArgs.push_back(Value.data()); + TakeNextArg = true; } else if (Value == "-fdebug-compilation-dir") { CmdArgs.push_back("-fdebug-compilation-dir"); TakeNextArg = true; @@ -3331,7 +3331,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, // --param ssp-buffer-size= for (const Arg *A : Args.filtered(options::OPT__param)) { StringRef Str(A->getValue()); - if (Str.startswith("ssp-buffer-size=")) { + if (Str.starts_with("ssp-buffer-size=")) { if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector-buffer-size"); // FIXME: Verify the argument is a valid integer. @@ -5615,6 +5615,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_auto_import); } + if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile, + Triple.isX86() && D.IsCLMode())) + CmdArgs.push_back("-fms-volatile"); + // Non-PIC code defaults to -fdirect-access-external-data while PIC code // defaults to -fno-direct-access-external-data. Pass the option if different // from the default. @@ -5882,7 +5886,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef Val = A->getValue(); if (Triple.isX86() && Triple.isOSBinFormatELF()) { if (Val != "all" && Val != "labels" && Val != "none" && - !Val.startswith("list=")) + !Val.starts_with("list=")) D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); else @@ -7947,18 +7951,6 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-P"); } - unsigned VolatileOptionID; - if (getToolChain().getTriple().isX86()) - VolatileOptionID = options::OPT__SLASH_volatile_ms; - else - VolatileOptionID = options::OPT__SLASH_volatile_iso; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group)) - VolatileOptionID = A->getOption().getID(); - - if (VolatileOptionID == options::OPT__SLASH_volatile_ms) - CmdArgs.push_back("-fms-volatile"); - if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_, options::OPT__SLASH_Zc_dllexportInlines, false)) { @@ -8390,14 +8382,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, continue; auto &JArgs = J.getArguments(); for (unsigned I = 0; I < JArgs.size(); ++I) { - if (StringRef(JArgs[I]).startswith("-object-file-name=") && + if (StringRef(JArgs[I]).starts_with("-object-file-name=") && Output.isFilename()) { - ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I); - addDebugObjectName(Args, NewArgs, DebugCompilationDir, - Output.getFilename()); - NewArgs.append(JArgs.begin() + I + 1, JArgs.end()); - J.replaceArguments(NewArgs); - break; + ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I); + addDebugObjectName(Args, NewArgs, DebugCompilationDir, + Output.getFilename()); + NewArgs.append(JArgs.begin() + I + 1, JArgs.end()); + J.replaceArguments(NewArgs); + break; } } } @@ -8661,7 +8653,7 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA, getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features, false); llvm::copy_if(Features, std::back_inserter(FeatureArgs), - [](StringRef Arg) { return !Arg.startswith("-target"); }); + [](StringRef Arg) { return !Arg.starts_with("-target"); }); if (TC->getTriple().isAMDGPU()) { for (StringRef Feature : llvm::split(Arch.split(':').second, ':')) { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 31e7d68161ff1b224dfa4b49433d82242b02794d..01fb0718b4079d6a8d83dc4d38321ee3c78acc84 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -303,7 +303,7 @@ void tools::handleTargetFeaturesGroup(const Driver &D, A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); auto Proc = getCPUName(D, Args, Triple); @@ -317,7 +317,7 @@ void tools::handleTargetFeaturesGroup(const Driver &D, continue; } - bool IsNegative = Name.startswith("no-"); + bool IsNegative = Name.starts_with("no-"); if (IsNegative) Name = Name.substr(3); @@ -2336,20 +2336,20 @@ static void GetSDLFromOffloadArchive( llvm::Triple Triple(D.getTargetTriple()); bool IsMSVC = Triple.isWindowsMSVCEnvironment(); auto Ext = IsMSVC ? ".lib" : ".a"; - if (!Lib.startswith(":") && !Lib.startswith("-l")) { + if (!Lib.starts_with(":") && !Lib.starts_with("-l")) { if (llvm::sys::fs::exists(Lib)) { ArchiveOfBundles = Lib; FoundAOB = true; } } else { - if (Lib.startswith("-l")) + if (Lib.starts_with("-l")) Lib = Lib.drop_front(2); for (auto LPath : LibraryPaths) { ArchiveOfBundles.clear(); - auto LibFile = - (Lib.startswith(":") ? Lib.drop_front() - : IsMSVC ? Lib + Ext : "lib" + Lib + Ext) - .str(); + auto LibFile = (Lib.starts_with(":") ? Lib.drop_front() + : IsMSVC ? Lib + Ext + : "lib" + Lib + Ext) + .str(); for (auto Prefix : {"/libdevice/", "/"}) { auto AOB = Twine(LPath + Prefix + LibFile).str(); if (llvm::sys::fs::exists(AOB)) { diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index ef1e77974c1eaaf79f707bfc22c565024f3b5862..f7a208575cb0cf8d617ab3da73d917285af5462e 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -238,7 +238,7 @@ CudaInstallationDetector::CudaInstallationDetector( // Process all bitcode filenames that look like // libdevice.compute_XX.YY.bc const StringRef LibDeviceName = "libdevice."; - if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) + if (!(FileName.starts_with(LibDeviceName) && FileName.ends_with(".bc"))) continue; StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 692b3a3f285d744afc868a622ea7dc0aa1559de6..65846cace461e3eedf6a8c18ed53fd6f516f366d 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1010,13 +1010,13 @@ static const char *ArmMachOArchNameCPU(StringRef CPU) { // FIXME: Make sure this MachO triple mangling is really necessary. // ARMv5* normalises to ARMv5. - if (Arch.startswith("armv5")) + if (Arch.starts_with("armv5")) Arch = Arch.substr(0, 5); // ARMv6*, except ARMv6M, normalises to ARMv6. - else if (Arch.startswith("armv6") && !Arch.endswith("6m")) + else if (Arch.starts_with("armv6") && !Arch.ends_with("6m")) Arch = Arch.substr(0, 5); // ARMv7A normalises to ARMv7. - else if (Arch.endswith("v7a")) + else if (Arch.ends_with("v7a")) Arch = Arch.substr(0, 5); return Arch.data(); } @@ -1319,8 +1319,8 @@ StringRef Darwin::getSDKName(StringRef isysroot) { auto EndSDK = llvm::sys::path::rend(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { StringRef SDK = *IT; - if (SDK.endswith(".sdk")) - return SDK.slice(0, SDK.size() - 4); + if (SDK.ends_with(".sdk")) + return SDK.slice(0, SDK.size() - 4); } return ""; } @@ -1959,22 +1959,23 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, auto CreatePlatformFromSDKName = [&](StringRef SDK) -> std::optional { - if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) + if (SDK.starts_with("iPhoneOS") || SDK.starts_with("iPhoneSimulator")) return DarwinPlatform::createFromSDK( Darwin::IPhoneOS, Version, - /*IsSimulator=*/SDK.startswith("iPhoneSimulator")); - else if (SDK.startswith("MacOSX")) + /*IsSimulator=*/SDK.starts_with("iPhoneSimulator")); + else if (SDK.starts_with("MacOSX")) return DarwinPlatform::createFromSDK(Darwin::MacOS, getSystemOrSDKMacOSVersion(Version)); - else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) + else if (SDK.starts_with("WatchOS") || SDK.starts_with("WatchSimulator")) return DarwinPlatform::createFromSDK( Darwin::WatchOS, Version, - /*IsSimulator=*/SDK.startswith("WatchSimulator")); - else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) + /*IsSimulator=*/SDK.starts_with("WatchSimulator")); + else if (SDK.starts_with("AppleTVOS") || + SDK.starts_with("AppleTVSimulator")) return DarwinPlatform::createFromSDK( Darwin::TvOS, Version, - /*IsSimulator=*/SDK.startswith("AppleTVSimulator")); - else if (SDK.startswith("DriverKit")) + /*IsSimulator=*/SDK.starts_with("AppleTVSimulator")); + else if (SDK.starts_with("DriverKit")) return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version); return std::nullopt; }; @@ -2339,8 +2340,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (SDK.size() > 0) { size_t StartVer = SDK.find_first_of("0123456789"); StringRef SDKName = SDK.slice(0, StartVer); - if (!SDKName.startswith(getPlatformFamily()) && - !dropSDKNamePrefix(SDKName).startswith(getPlatformFamily())) + if (!SDKName.starts_with(getPlatformFamily()) && + !dropSDKNamePrefix(SDKName).starts_with(getPlatformFamily())) getDriver().Diag(diag::warn_incompatible_sysroot) << SDKName << getPlatformFamily(); } diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 502b9f17a06c52ff06434f206489f817f81dfcc4..41eaad3bbad0a37f1d191fc71facbc183286314a 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -182,7 +182,7 @@ void Flang::AddAArch64TargetArgs(const ArgList &Args, Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || Val.equals("2048+")) { unsigned Bits = 0; - if (Val.endswith("+")) + if (Val.ends_with("+")) Val = Val.substr(0, Val.size() - 1); else { [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index b875991844ffff5240cdb2195a77bf74945dca5e..835215a83c4037eee2e5351993fff8983432f0ff 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1084,7 +1084,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) + if (StringRef(M.includeSuffix()).starts_with("/uclibc")) Dirs.push_back( "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); else @@ -1288,7 +1288,7 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) + if (StringRef(M.includeSuffix()).starts_with("/uclibc")) Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); else Dirs.push_back("/../../../../sysroot/usr/include"); @@ -3055,7 +3055,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // the cross. Note that GCC does include some of these directories in some // configurations but this seems somewhere between questionable and simply // a bug. - if (StringRef(LibPath).startswith(SysRoot)) + if (StringRef(LibPath).starts_with(SysRoot)) addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index d0ff7d0c1310da565c02b95097d706264e73fb16..6a2a105bee32ef3e183559c0a9b4ae7771e8483e 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -54,11 +54,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef { const std::string &S = T.str(); StringRef Opt(S); - if (Opt.endswith("=")) + if (Opt.ends_with("=")) Opt = Opt.drop_back(1); - if (Opt.startswith("mno-")) + if (Opt.starts_with("mno-")) Opt = Opt.drop_front(4); - else if (Opt.startswith("m")) + else if (Opt.starts_with("m")) Opt = Opt.drop_front(1); return Args.MakeArgString(Twine(Enable ? "+" : "-") + Twine(Opt)); }; @@ -801,7 +801,7 @@ StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { CpuArg = A; StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); - if (CPU.startswith("hexagon")) + if (CPU.starts_with("hexagon")) return CPU.substr(sizeof("hexagon") - 1); return CPU; } diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index 2dfc90ef37f75d0e93e1ad77ffa514eac39e9732..7a4c2bb7ede1d5f1a9ba25ba93e7c6becdc599c5 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -92,7 +92,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) { + if (StringRef(D.Dir).starts_with(SysRoot)) { addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } @@ -110,7 +110,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) + if (StringRef(D.Dir).starts_with(SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, SysRoot + "/lib", Paths); diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp index b28d5e45706c9d6d7a382e951634e91f8ff7acec..8dc23521f400a09fb6dd288ff364ed332a4ef8d0 100644 --- a/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/clang/lib/Driver/ToolChains/MSP430.cpp @@ -166,7 +166,7 @@ void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs, return; const StringRef MCU = MCUArg->getValue(); - if (MCU.startswith("msp430i")) { + if (MCU.starts_with("msp430i")) { // 'i' should be in lower case as it's defined in TI MSP430-GCC headers CC1Args.push_back(DriverArgs.MakeArgString( "-D__MSP430i" + MCU.drop_front(7).upper() + "__")); diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 6d925555b7bb4b2d462ef91ab5eb0f0974ab1a0c..8e1e95173836ffe2c3c97fc0b916c7cfa163d584 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -302,7 +302,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (A.getOption().matches(options::OPT_l)) { StringRef Lib = A.getValue(); const char *LinkLibArg; - if (Lib.endswith(".lib")) + if (Lib.ends_with(".lib")) LinkLibArg = Args.MakeArgString(Lib); else LinkLibArg = Args.MakeArgString(Lib + ".lib"); diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 5d7f8675daf8d28c35d62bfd3d9091ba8e0beaf6..65512f16357d044d4cbfcda328983bf24b50fe68 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -86,9 +86,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); for (auto Lib : Args.getAllArgValues(options::OPT_l)) - if (StringRef(Lib).startswith("msvcr") || - StringRef(Lib).startswith("ucrt") || - StringRef(Lib).startswith("crtdll")) + if (StringRef(Lib).starts_with("msvcr") || + StringRef(Lib).starts_with("ucrt") || + StringRef(Lib).starts_with("crtdll")) return; CmdArgs.push_back("-lmsvcrt"); } diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp index bdbecaef60405c24369f7f143cbf6b8776928583..0ed0f91ad166c0b1af2d7272a5ac515ce3e0d668 100644 --- a/clang/lib/Driver/ToolChains/PPCLinux.cpp +++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -31,10 +31,10 @@ static bool GlibcSupportsFloat128(const std::string &Linker) { // Since glibc 2.34, the installed .so file is not symlink anymore. But we can // still safely assume it's newer than 2.32. - if (LinkerName.startswith("ld64.so")) + if (LinkerName.starts_with("ld64.so")) return true; - if (!LinkerName.startswith("ld-2.")) + if (!LinkerName.starts_with("ld-2.")) return false; unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0'); if (Minor < 32) diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 485730da7df1f8cd4c8016a66edb061cc65a449c..9a9792d019d5edb2fef62359e9cd07d4ed3a9fd1 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -328,7 +328,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, // If we are currently running Clang inside of the requested system root, // add its parent library path to those searched. - if (StringRef(D.Dir).startswith(D.SysRoot)) + if (StringRef(D.Dir).starts_with(D.SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths); diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index f131b6cf3baff9d7ccfc2782d3ddfe6ea9b17b57..57f4600727ec89db91c8938bbdc19f3da845fdbc 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -328,7 +328,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { StringRef Opt = A->getValue(0); - if (Opt.startswith("-emscripten-cxx-exceptions-allowed")) { + if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) { // '-mllvm -emscripten-cxx-exceptions-allowed' should be used with // '-mllvm -enable-emscripten-cxx-exceptions' bool EmEHArgExists = false; @@ -355,7 +355,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, } } - if (Opt.startswith("-wasm-enable-sjlj")) { + if (Opt.starts_with("-wasm-enable-sjlj")) { // '-mllvm -wasm-enable-sjlj' is not compatible with // '-mno-exception-handling' if (DriverArgs.hasFlag(options::OPT_mno_exception_handing, diff --git a/clang/lib/Edit/Commit.cpp b/clang/lib/Edit/Commit.cpp index 7c5aea6e5069a504b5c9c0f30ef9ae866932b530..6e785e866666f161b4a2a656cbfec1564147d5a8 100644 --- a/clang/lib/Edit/Commit.cpp +++ b/clang/lib/Edit/Commit.cpp @@ -334,7 +334,7 @@ bool Commit::canReplaceText(SourceLocation loc, StringRef text, return false; Len = text.size(); - return file.substr(Offs.getOffset()).startswith(text); + return file.substr(Offs.getOffset()).starts_with(text); } bool Commit::isAtStartOfMacroExpansion(SourceLocation loc, diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index adb34eba49703064b2748f3c8f444ecd71b04c1e..d5bf553e241240daf72277bb374b6af7cecd1381 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -697,7 +697,7 @@ static bool getLiteralInfo(SourceRange literalRange, struct Suff { static bool has(StringRef suff, StringRef &text) { - if (text.endswith(suff)) { + if (text.ends_with(suff)) { text = text.substr(0, text.size()-suff.size()); return true; } @@ -739,9 +739,9 @@ static bool getLiteralInfo(SourceRange literalRange, Info.F = UpperF ? "F" : "f"; Info.Hex = Info.Octal = false; - if (text.startswith("0x")) + if (text.starts_with("0x")) Info.Hex = true; - else if (!isFloat && !isIntZero && text.startswith("0")) + else if (!isFloat && !isIntZero && text.starts_with("0")) Info.Octal = true; SourceLocation B = literalRange.getBegin(); diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index fe282dfb19e8aa7fa9bf6ff43ee2c18b309864a7..fd62d841197d9f08e02ab3c4d906e703e19ec289 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -105,10 +105,10 @@ std::optional getRelativeIncludeName(const CompilerInstance &CI, // Special case Apple .sdk folders since the search path is typically a // symlink like `iPhoneSimulator14.5.sdk` while the file is instead // located in `iPhoneSimulator.sdk` (the real folder). - if (NI->endswith(".sdk") && DI->endswith(".sdk")) { + if (NI->ends_with(".sdk") && DI->ends_with(".sdk")) { StringRef NBasename = path::stem(*NI); StringRef DBasename = path::stem(*DI); - if (DBasename.startswith(NBasename)) + if (DBasename.starts_with(NBasename)) continue; } diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index d9675b0c94de3962fa185b87f9819bb2d844b268..53b22297ee0ea19e4e23b504baa42ea899b6bf8c 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -743,7 +743,7 @@ bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { // Filter out symbols prefixed with an underscored as they are understood to // be symbols clients should not use. - if (Record.Name.startswith("_")) + if (Record.Name.starts_with("_")) return true; return false; diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 954eeb9a6f24fc4a73a98d4d3290a274fc379cbb..473908e8fee3b3da6557e77d3c2dc6be8931e209 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -55,7 +55,7 @@ static StringRef getLineCommentIndentPrefix(StringRef Comment, })); for (StringRef KnownPrefix : KnownPrefixes) { - if (Comment.startswith(KnownPrefix)) { + if (Comment.starts_with(KnownPrefix)) { const auto PrefixLength = Comment.find_first_not_of(' ', KnownPrefix.size()); return Comment.substr(0, PrefixLength); @@ -220,8 +220,8 @@ bool switchesFormatting(const FormatToken &Token) { assert((Token.is(TT_BlockComment) || Token.is(TT_LineComment)) && "formatting regions are switched by comment tokens"); StringRef Content = Token.TokenText.substr(2).ltrim(); - return Content.startswith("clang-format on") || - Content.startswith("clang-format off"); + return Content.starts_with("clang-format on") || + Content.starts_with("clang-format off"); } unsigned @@ -271,7 +271,7 @@ BreakableStringLiteral::BreakableStringLiteral( : BreakableToken(Tok, InPPDirective, Encoding, Style), StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix), UnbreakableTailLength(UnbreakableTailLength) { - assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix)); + assert(Tok.TokenText.starts_with(Prefix) && Tok.TokenText.ends_with(Postfix)); Line = Tok.TokenText.substr( Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size()); } @@ -454,7 +454,7 @@ static bool mayReflowContent(StringRef Content) { bool hasSpecialMeaningPrefix = false; for (StringRef Prefix : {"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) { - if (Content.startswith(Prefix)) { + if (Content.starts_with(Prefix)) { hasSpecialMeaningPrefix = true; break; } @@ -471,7 +471,7 @@ static bool mayReflowContent(StringRef Content) { // characters and either the first or second character must be // non-punctuation. return Content.size() >= 2 && !hasSpecialMeaningPrefix && - !Content.endswith("\\") && + !Content.ends_with("\\") && // Note that this is UTF-8 safe, since if isPunctuation(Content[0]) is // true, then the first code point must be 1 byte long. (!isPunctuation(Content[0]) || !isPunctuation(Content[1])); @@ -488,7 +488,7 @@ BreakableBlockComment::BreakableBlockComment( "block comment section must start with a block comment"); StringRef TokenText(Tok.TokenText); - assert(TokenText.startswith("/*") && TokenText.endswith("*/")); + assert(TokenText.starts_with("/*") && TokenText.ends_with("*/")); TokenText.substr(2, TokenText.size() - 4) .split(Lines, UseCRLF ? "\r\n" : "\n"); @@ -511,7 +511,7 @@ BreakableBlockComment::BreakableBlockComment( // /* // ** blah blah blah // */ - if (Lines.size() >= 2 && Content[1].startswith("**") && + if (Lines.size() >= 2 && Content[1].starts_with("**") && static_cast(ContentColumn[1]) == StartColumn) { DecorationColumn = StartColumn; } @@ -531,10 +531,10 @@ BreakableBlockComment::BreakableBlockComment( // If the last line is empty, the closing "*/" will have a star. if (Text.empty()) break; - } else if (!Text.empty() && Decoration.startswith(Text)) { + } else if (!Text.empty() && Decoration.starts_with(Text)) { continue; } - while (!Text.startswith(Decoration)) + while (!Text.starts_with(Decoration)) Decoration = Decoration.drop_back(1); } @@ -562,13 +562,13 @@ BreakableBlockComment::BreakableBlockComment( // The last line excludes the star if LastLineNeedsDecoration is false. // For all other lines, adjust the line to exclude the star and // (optionally) the first whitespace. - unsigned DecorationSize = Decoration.startswith(Content[i]) + unsigned DecorationSize = Decoration.starts_with(Content[i]) ? Content[i].size() : Decoration.size(); if (DecorationSize) ContentColumn[i] = DecorationColumn + DecorationSize; Content[i] = Content[i].substr(DecorationSize); - if (!Decoration.startswith(Content[i])) { + if (!Decoration.starts_with(Content[i])) { IndentAtLineBreak = std::min(IndentAtLineBreak, std::max(0, ContentColumn[i])); } @@ -577,10 +577,10 @@ BreakableBlockComment::BreakableBlockComment( // Detect a multiline jsdoc comment and set DelimitersOnNewline in that case. if (Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) { - if ((Lines[0] == "*" || Lines[0].startswith("* ")) && Lines.size() > 1) { + if ((Lines[0] == "*" || Lines[0].starts_with("* ")) && Lines.size() > 1) { // This is a multiline jsdoc comment. DelimitersOnNewline = true; - } else if (Lines[0].startswith("* ") && Lines.size() == 1) { + } else if (Lines[0].starts_with("* ") && Lines.size() == 1) { // Detect a long single-line comment, like: // /** long long long */ // Below, '2' is the width of '*/'. @@ -612,7 +612,7 @@ BreakableToken::Split BreakableBlockComment::getSplit( return Split(StringRef::npos, 0); return getCommentSplit(Content[LineIndex].substr(TailOffset), ContentStartColumn, ColumnLimit, Style.TabWidth, - Encoding, Style, Decoration.endswith("*")); + Encoding, Style, Decoration.ends_with("*")); } void BreakableBlockComment::adjustWhitespace(unsigned LineIndex, @@ -623,7 +623,7 @@ void BreakableBlockComment::adjustWhitespace(unsigned LineIndex, // trimming the trailing whitespace. The backslash will be re-added later when // inserting a line break. size_t EndOfPreviousLine = Lines[LineIndex - 1].size(); - if (InPPDirective && Lines[LineIndex - 1].endswith("\\")) + if (InPPDirective && Lines[LineIndex - 1].ends_with("\\")) --EndOfPreviousLine; // Calculate the end of the non-whitespace text in the previous line. @@ -672,7 +672,7 @@ unsigned BreakableBlockComment::getRemainingLength(unsigned LineIndex, // We never need a decoration when breaking just the trailing "*/" postfix. bool HasRemainingText = Offset < Content[LineIndex].size(); if (!HasRemainingText) { - bool HasDecoration = Lines[LineIndex].ltrim().startswith(Decoration); + bool HasDecoration = Lines[LineIndex].ltrim().starts_with(Decoration); if (HasDecoration) LineLength -= Decoration.size(); } @@ -700,7 +700,7 @@ unsigned BreakableBlockComment::getContentIndent(unsigned LineIndex) const { // /** line 0 */ // is "* line 0", so we need to skip over the decoration in that case. StringRef ContentWithNoDecoration = Content[LineIndex]; - if (LineIndex == 0 && ContentWithNoDecoration.startswith("*")) + if (LineIndex == 0 && ContentWithNoDecoration.starts_with("*")) ContentWithNoDecoration = ContentWithNoDecoration.substr(1).ltrim(Blanks); StringRef FirstWord = ContentWithNoDecoration.substr( 0, ContentWithNoDecoration.find_first_of(Blanks)); @@ -853,7 +853,7 @@ bool BreakableBlockComment::mayReflow( // Content[LineIndex] may exclude the indent after the '*' decoration. In that // case, we compute the start of the comment pragma manually. StringRef IndentContent = Content[LineIndex]; - if (Lines[LineIndex].ltrim(Blanks).startswith("*")) + if (Lines[LineIndex].ltrim(Blanks).starts_with("*")) IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1); return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) && mayReflowContent(Content[LineIndex]) && !Tok.Finalized && @@ -876,7 +876,7 @@ BreakableLineCommentSection::BreakableLineCommentSection( CurrentTok = CurrentTok->Next) { LastLineTok = LineTok; StringRef TokenText(CurrentTok->TokenText); - assert((TokenText.startswith("//") || TokenText.startswith("#")) && + assert((TokenText.starts_with("//") || TokenText.starts_with("#")) && "unsupported line comment prefix, '//' and '#' are supported"); size_t FirstLineIndex = Lines.size(); TokenText.split(Lines, "\n"); @@ -913,7 +913,7 @@ BreakableLineCommentSection::BreakableLineCommentSection( // ######### // # section // ######### - if (FirstCommentChar == '#' && !TokenText.startswith("#")) + if (FirstCommentChar == '#' && !TokenText.starts_with("#")) return false; return FirstCommentChar == '\\' || isPunctuation(FirstCommentChar) || isHorizontalWhitespace(FirstCommentChar); @@ -1152,7 +1152,7 @@ bool BreakableLineCommentSection::mayReflow( // Line comments have the indent as part of the prefix, so we need to // recompute the start of the line. StringRef IndentContent = Content[LineIndex]; - if (Lines[LineIndex].startswith("//")) + if (Lines[LineIndex].starts_with("//")) IndentContent = Lines[LineIndex].substr(2); // FIXME: Decide whether we want to reflow non-regular indents: // Currently, we only reflow when the OriginalPrefix[LineIndex] matches the diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 9e4e939503dfe4a0b5dd501e14353cdb4133c664..bd319f21b05f86415bd4677cc81d2fb5c42a8523 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -161,7 +161,7 @@ static bool opensProtoMessageField(const FormatToken &LessTok, // string. For example, the delimiter of R"deli(cont)deli" is deli. static std::optional getRawStringDelimiter(StringRef TokenText) { if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'. - || !TokenText.startswith("R\"") || !TokenText.endswith("\"")) { + || !TokenText.starts_with("R\"") || !TokenText.ends_with("\"")) { return std::nullopt; } @@ -177,7 +177,7 @@ static std::optional getRawStringDelimiter(StringRef TokenText) { size_t RParenPos = TokenText.size() - Delimiter.size() - 2; if (TokenText[RParenPos] != ')') return std::nullopt; - if (!TokenText.substr(RParenPos + 1).startswith(Delimiter)) + if (!TokenText.substr(RParenPos + 1).starts_with(Delimiter)) return std::nullopt; return Delimiter; } @@ -608,7 +608,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { if (Current.is(tok::lessless) && ((Previous.is(tok::identifier) && Previous.TokenText == "endl") || - (Previous.Tok.isLiteral() && (Previous.TokenText.endswith("\\n\"") || + (Previous.Tok.isLiteral() && (Previous.TokenText.ends_with("\\n\"") || Previous.TokenText == "\'\\n\'")))) { return true; } @@ -2293,12 +2293,13 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, if (Style.isVerilog() || Style.Language == FormatStyle::LK_Java || Style.isJavaScript() || Style.isCSharp()) { BreakableStringLiteralUsingOperators::QuoteStyleType QuoteStyle; - if (Style.isJavaScript() && Text.startswith("'") && Text.endswith("'")) { + if (Style.isJavaScript() && Text.starts_with("'") && + Text.ends_with("'")) { QuoteStyle = BreakableStringLiteralUsingOperators::SingleQuotes; - } else if (Style.isCSharp() && Text.startswith("@\"") && - Text.endswith("\"")) { + } else if (Style.isCSharp() && Text.starts_with("@\"") && + Text.ends_with("\"")) { QuoteStyle = BreakableStringLiteralUsingOperators::AtDoubleQuotes; - } else if (Text.startswith("\"") && Text.endswith("\"")) { + } else if (Text.starts_with("\"") && Text.ends_with("\"")) { QuoteStyle = BreakableStringLiteralUsingOperators::DoubleQuotes; } else { return nullptr; @@ -2315,12 +2316,14 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, // FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to // reduce the overhead) for each FormatToken, which is a string, so that we // don't run multiple checks here on the hot path. - if ((Text.endswith(Postfix = "\"") && - (Text.startswith(Prefix = "@\"") || Text.startswith(Prefix = "\"") || - Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") || - Text.startswith(Prefix = "u8\"") || - Text.startswith(Prefix = "L\""))) || - (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) { + if ((Text.ends_with(Postfix = "\"") && + (Text.starts_with(Prefix = "@\"") || Text.starts_with(Prefix = "\"") || + Text.starts_with(Prefix = "u\"") || + Text.starts_with(Prefix = "U\"") || + Text.starts_with(Prefix = "u8\"") || + Text.starts_with(Prefix = "L\""))) || + (Text.starts_with(Prefix = "_T(\"") && + Text.ends_with(Postfix = "\")"))) { return std::make_unique( Current, StartColumn, Prefix, Postfix, UnbreakableTailLength, State.Line->InPPDirective, Encoding, Style); @@ -2342,7 +2345,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, bool RegularComments = [&]() { for (const FormatToken *T = &Current; T && T->is(TT_LineComment); T = T->Next) { - if (!(T->TokenText.startswith("//") || T->TokenText.startswith("#"))) + if (!(T->TokenText.starts_with("//") || T->TokenText.starts_with("#"))) return false; } return true; @@ -2754,7 +2757,7 @@ bool ContinuationIndenter::nextIsMultilineString(const LineState &State) { // We never consider raw string literals "multiline" for the purpose of // AlwaysBreakBeforeMultilineStrings implementation as they are special-cased // (see TokenAnnotator::mustBreakBefore(). - if (Current.TokenText.startswith("R\"")) + if (Current.TokenText.starts_with("R\"")) return false; if (Current.IsMultiline) return true; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 8feee7457fc31b76a09f9c9ebd9a9104db281404..668e959a9416bad1274f262ba726c389f8635449 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2346,9 +2346,9 @@ private: // NB: testing for not starting with a double quote to avoid // breaking `template strings`. (Style.JavaScriptQuotes == FormatStyle::JSQS_Single && - !Input.startswith("\"")) || + !Input.starts_with("\"")) || (Style.JavaScriptQuotes == FormatStyle::JSQS_Double && - !Input.startswith("\'"))) { + !Input.starts_with("\'"))) { continue; } @@ -2932,7 +2932,7 @@ private: }; for (auto *Line : AnnotatedLines) { - if (Line->First && (Line->First->TokenText.startswith("#") || + if (Line->First && (Line->First->TokenText.starts_with("#") || Line->First->TokenText == "__pragma" || Line->First->TokenText == "_Pragma")) { continue; @@ -3217,7 +3217,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Regroup); - bool MergeWithNextLine = Trimmed.endswith("\\"); + bool MergeWithNextLine = Trimmed.ends_with("\\"); if (!FormattingOff && !MergeWithNextLine) { if (tooling::HeaderIncludes::IncludeRegex.match(Line, &Matches)) { StringRef IncludeName = Matches[2]; @@ -3243,7 +3243,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces, Cursor); IncludesInBlock.clear(); - if (Trimmed.startswith("#pragma hdrstop")) // Precompiled headers. + if (Trimmed.starts_with("#pragma hdrstop")) // Precompiled headers. FirstIncludeBlock = true; else FirstIncludeBlock = false; @@ -3271,7 +3271,7 @@ static unsigned findJavaImportGroup(const FormatStyle &Style, unsigned LongestMatchLength = 0; for (unsigned I = 0; I < Style.JavaImportGroups.size(); I++) { const std::string &GroupPrefix = Style.JavaImportGroups[I]; - if (ImportIdentifier.startswith(GroupPrefix) && + if (ImportIdentifier.starts_with(GroupPrefix) && GroupPrefix.length() > LongestMatchLength) { LongestMatchIndex = I; LongestMatchLength = GroupPrefix.length(); @@ -3426,7 +3426,7 @@ bool isMpegTS(StringRef Code) { return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47; } -bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); } +bool isLikelyXml(StringRef Code) { return Code.ltrim().starts_with("<"); } tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, @@ -3538,7 +3538,7 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, for (const auto &Header : HeadersToDelete) { tooling::Replacements Replaces = - Includes.remove(Header.trim("\"<>"), Header.startswith("<")); + Includes.remove(Header.trim("\"<>"), Header.starts_with("<")); for (const auto &R : Replaces) { auto Err = Result.add(R); if (Err) { @@ -3560,7 +3560,7 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, (void)Matched; auto IncludeName = Matches[2]; auto Replace = - Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<"), + Includes.insert(IncludeName.trim("\"<>"), IncludeName.starts_with("<"), tooling::IncludeDirective::Include); if (Replace) { auto Err = Result.add(*Replace); @@ -3882,14 +3882,14 @@ const char *StyleOptionHelpDescription = " --style=\"{BasedOnStyle: llvm, IndentWidth: 8}\""; static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { - if (FileName.endswith(".java")) + if (FileName.ends_with(".java")) return FormatStyle::LK_Java; if (FileName.ends_with_insensitive(".js") || FileName.ends_with_insensitive(".mjs") || FileName.ends_with_insensitive(".ts")) { return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript. } - if (FileName.endswith(".m") || FileName.endswith(".mm")) + if (FileName.ends_with(".m") || FileName.ends_with(".mm")) return FormatStyle::LK_ObjC; if (FileName.ends_with_insensitive(".proto") || FileName.ends_with_insensitive(".protodevel")) { @@ -3963,7 +3963,7 @@ llvm::Expected getStyle(StringRef StyleName, StringRef FileName, llvm::SmallVector, 1> ChildFormatTextToApply; - if (StyleName.startswith("{")) { + if (StyleName.starts_with("{")) { // Parse YAML/JSON style from the command line. StringRef Source = ""; if (std::error_code ec = @@ -4123,7 +4123,7 @@ static bool isClangFormatOnOff(StringRef Comment, bool On) { static const char ClangFormatOff[] = "// clang-format off"; const unsigned Size = (On ? sizeof ClangFormatOn : sizeof ClangFormatOff) - 1; - return Comment.startswith(On ? ClangFormatOn : ClangFormatOff) && + return Comment.starts_with(On ? ClangFormatOn : ClangFormatOff) && (Comment.size() == Size || Comment[Size] == ':'); } diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 14a3c21ba44eaee9c77da15e37cd914a32518c43..3f9664f8f78a3e4d3329b04cb53ff5d776bc1cd8 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -667,7 +667,7 @@ public: /// Returns whether \p Tok is ([{ or an opening < of a template or in /// protos. bool opensScope() const { - if (is(TT_TemplateString) && TokenText.endswith("${")) + if (is(TT_TemplateString) && TokenText.ends_with("${")) return true; if (is(TT_DictLiteral) && is(tok::less)) return true; @@ -677,7 +677,7 @@ public: /// Returns whether \p Tok is )]} or a closing > of a template or in /// protos. bool closesScope() const { - if (is(TT_TemplateString) && TokenText.startswith("}")) + if (is(TT_TemplateString) && TokenText.starts_with("}")) return true; if (is(TT_DictLiteral) && is(tok::greater)) return true; @@ -743,9 +743,9 @@ public: if (isNot(tok::string_literal)) return false; StringRef Content = TokenText; - if (Content.startswith("\"") || Content.startswith("'")) + if (Content.starts_with("\"") || Content.starts_with("'")) Content = Content.drop_front(1); - if (Content.endswith("\"") || Content.endswith("'")) + if (Content.ends_with("\"") || Content.ends_with("'")) Content = Content.drop_back(1); Content = Content.trim(); return Content.size() > 1 && @@ -1823,7 +1823,7 @@ private: }; inline bool isLineComment(const FormatToken &FormatTok) { - return FormatTok.is(tok::comment) && !FormatTok.TokenText.startswith("/*"); + return FormatTok.is(tok::comment) && !FormatTok.TokenText.starts_with("/*"); } // Checks if \p FormatTok is a line comment that continues the line comment diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index e4e32e2671df57d925ab5d18af39419f7b0660eb..61430282c6f88ca09e7e2b14c25103d66a9469c2 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -711,12 +711,12 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() { bool Verbatim = false; bool Interpolated = false; - if (TokenText.startswith(R"($@")") || TokenText.startswith(R"(@$")")) { + if (TokenText.starts_with(R"($@")") || TokenText.starts_with(R"(@$")")) { Verbatim = true; Interpolated = true; - } else if (TokenText.startswith(R"(@")")) { + } else if (TokenText.starts_with(R"(@")")) { Verbatim = true; - } else if (TokenText.startswith(R"($")")) { + } else if (TokenText.starts_with(R"($")")) { Interpolated = true; } @@ -1110,7 +1110,7 @@ FormatToken *FormatTokenLexer::getNextToken() { // the comment token at the backslash, and resets the lexer to restart behind // the backslash. if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) && - FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) { + FormatTok->is(tok::comment) && FormatTok->TokenText.starts_with("//")) { size_t BackslashPos = FormatTok->TokenText.find('\\'); while (BackslashPos != StringRef::npos) { if (BackslashPos + 1 < FormatTok->TokenText.size() && diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp index 8c6722e915344fb233b78bbde6f85ee2ca4c074d..1a6a1b19e7022a080460b1dfd0a0cd152673a4bf 100644 --- a/clang/lib/Format/SortJavaScriptImports.cpp +++ b/clang/lib/Format/SortJavaScriptImports.cpp @@ -468,10 +468,10 @@ private: // URL = TokenText without the quotes. Reference.URL = Current->TokenText.substr(1, Current->TokenText.size() - 2); - if (Reference.URL.startswith("..")) { + if (Reference.URL.starts_with("..")) { Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE_PARENT; - } else if (Reference.URL.startswith(".")) { + } else if (Reference.URL.starts_with(".")) { Reference.Category = JsModuleReference::ReferenceCategory::RELATIVE; } else { Reference.Category = JsModuleReference::ReferenceCategory::ABSOLUTE; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index eaccb5881ca30f5e381f20b1e17d36894041985d..f3551af3424396967c2ec5ce1250d7d4911fd63a 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -164,6 +164,10 @@ private: TT_OverloadedOperatorLParen))) { return false; } + if (Previous.Previous->is(tok::kw_operator) && + CurrentToken->is(tok::l_paren)) { + return false; + } } FormatToken *Left = CurrentToken->Previous; @@ -1307,7 +1311,7 @@ private: if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, tok::comma, tok::star, tok::arrow, tok::amp, tok::ampamp) || // User defined literal. - Previous->TokenText.startswith("\"\"")) { + Previous->TokenText.starts_with("\"\"")) { Previous->setType(TT_OverloadedOperator); if (CurrentToken->isOneOf(tok::less, tok::greater)) break; @@ -1466,7 +1470,7 @@ private: // Mark tokens up to the trailing line comments as implicit string // literals. if (CurrentToken->isNot(tok::comment) && - !CurrentToken->TokenText.startswith("//")) { + !CurrentToken->TokenText.starts_with("//")) { CurrentToken->setType(TT_ImplicitStringLiteral); } next(); @@ -2077,8 +2081,8 @@ private: } Current.setType(TT_BinaryOperator); } else if (Current.is(tok::comment)) { - if (Current.TokenText.startswith("/*")) { - if (Current.TokenText.endswith("*/")) { + if (Current.TokenText.starts_with("/*")) { + if (Current.TokenText.ends_with("*/")) { Current.setType(TT_BlockComment); } else { // The lexer has for some reason determined a comment here. But we @@ -3724,8 +3728,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 100; if (Left.is(TT_JsTypeColon)) return 35; - if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || - (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) { + if ((Left.is(TT_TemplateString) && Left.TokenText.ends_with("${")) || + (Right.is(TT_TemplateString) && Right.TokenText.starts_with("}"))) { return 100; } // Prefer breaking call chains (".foo") over empty "{}", "[]" or "()". @@ -4224,7 +4228,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, } if (Left.is(TT_BlockComment)) { // No whitespace in x(/*foo=*/1), except for JavaScript. - return Style.isJavaScript() || !Left.TokenText.endswith("=*/"); + return Style.isJavaScript() || !Left.TokenText.ends_with("=*/"); } // Space between template and attribute. @@ -4572,8 +4576,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Next && Next->is(TT_FatArrow)) return true; } - if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || - (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) { + if ((Left.is(TT_TemplateString) && Left.TokenText.ends_with("${")) || + (Right.is(TT_TemplateString) && Right.TokenText.starts_with("}"))) { return false; } // In tagged template literals ("html`bar baz`"), there is no space between @@ -5212,7 +5216,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Left.is(TT_InheritanceComma)) { return true; } - if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\"")) { + if (Right.is(tok::string_literal) && Right.TokenText.starts_with("R\"")) { // Multiline raw string literals are special wrt. line breaks. The author // has made a deliberate choice and might have aligned the contents of the // string literal accordingly. Thus, we try keep existing line breaks. diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 57126b8dfeac5de62da5b519c1ad0e0b3b5cdc62..c38b4c884070bb74ccad00dcf8a2539a3653c30e 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1333,7 +1333,7 @@ bool UnwrappedLineParser::parseModuleImport() { // Mark tokens up to the trailing line comments as implicit string // literals. if (FormatTok->isNot(tok::comment) && - !FormatTok->TokenText.startswith("//")) { + !FormatTok->TokenText.starts_with("//")) { FormatTok->setFinalizedType(TT_ImplicitStringLiteral); } nextToken(); @@ -1371,7 +1371,7 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous); bool PreviousStartsTemplateExpr = - Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${"); + Previous->is(TT_TemplateString) && Previous->TokenText.ends_with("${"); if (PreviousMustBeValue || Previous->is(tok::r_paren)) { // If the line contains an '@' sign, the previous token might be an // annotation, which can precede another identifier/value. @@ -1385,7 +1385,7 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { return addUnwrappedLine(); bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next); bool NextEndsTemplateExpr = - Next->is(TT_TemplateString) && Next->TokenText.startswith("}"); + Next->is(TT_TemplateString) && Next->TokenText.starts_with("}"); if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr && (PreviousMustBeValue || Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus, @@ -4459,8 +4459,8 @@ continuesLineCommentSection(const FormatToken &FormatTok, return false; StringRef IndentContent = FormatTok.TokenText; - if (FormatTok.TokenText.startswith("//") || - FormatTok.TokenText.startswith("/*")) { + if (FormatTok.TokenText.starts_with("//") || + FormatTok.TokenText.starts_with("/*")) { IndentContent = FormatTok.TokenText.substr(2); } if (CommentPragmasRegex.match(IndentContent)) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b33bdad2ad81bad041c9ca791066ac347706d1e7..11f3f2c2d6425cce7f51ca5c79b28b6ac79646fd 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2829,7 +2829,7 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, "-interface-stub-version=ifs-v1" << ErrorMessage; ProgramAction = frontend::ParseSyntaxOnly; - } else if (!ArgStr.startswith("ifs-")) { + } else if (!ArgStr.starts_with("ifs-")) { std::string ErrorMessage = "Invalid interface stub format: " + ArgStr.str() + "."; Diags.Report(diag::err_drv_invalid_value) @@ -4106,13 +4106,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, // Check the version number is valid: either 3.x (0 <= x <= 9) or // y or y.0 (4 <= y <= current version). - if (!VerParts.first.startswith("0") && - !VerParts.first.getAsInteger(10, Major) && - 3 <= Major && Major <= CLANG_VERSION_MAJOR && - (Major == 3 ? VerParts.second.size() == 1 && - !VerParts.second.getAsInteger(10, Minor) - : VerParts.first.size() == Ver.size() || - VerParts.second == "0")) { + if (!VerParts.first.starts_with("0") && + !VerParts.first.getAsInteger(10, Major) && 3 <= Major && + Major <= CLANG_VERSION_MAJOR && + (Major == 3 + ? VerParts.second.size() == 1 && + !VerParts.second.getAsInteger(10, Minor) + : VerParts.first.size() == Ver.size() || VerParts.second == "0")) { // Got a valid version number. if (Major == 3 && Minor <= 8) Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8); diff --git a/clang/lib/Frontend/DependencyGraph.cpp b/clang/lib/Frontend/DependencyGraph.cpp index 6aad04370f6e7ad27efff42769186eebf8a4be31..e96669f856bb18536aa91a087c258149adad4748 100644 --- a/clang/lib/Frontend/DependencyGraph.cpp +++ b/clang/lib/Frontend/DependencyGraph.cpp @@ -110,7 +110,7 @@ void DependencyGraphCallback::OutputGraphFile() { writeNodeReference(OS, AllFiles[I]); OS << " [ shape=\"box\", label=\""; StringRef FileName = AllFiles[I].getName(); - if (FileName.startswith(SysRoot)) + if (FileName.starts_with(SysRoot)) FileName = FileName.substr(SysRoot.size()); OS << DOT::EscapeString(std::string(FileName)) << "\"];\n"; diff --git a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index 2c3a253a67d5c930ed823f447af511573bb51919..b6b37461089e4860e5f46cf8ec2b78121f08a96d 100644 --- a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -307,7 +307,7 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile, Rest = Rest.substr(Idx); } } - if (EnsureNewline && !TextToWrite.endswith(LocalEOL)) + if (EnsureNewline && !TextToWrite.ends_with(LocalEOL)) OS << MainEOL; WriteFrom = WriteTo; diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index ab8174f4f4db9216a21c912bec1346dfaee4af09..09c1460d54e1d7701542de30e34e4f738e7b1129 100644 --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -226,10 +226,10 @@ public: P = C; while (P < End) { StringRef S(P, End - P); - if (S.startswith(OpenBrace)) { + if (S.starts_with(OpenBrace)) { ++Depth; P += OpenBrace.size(); - } else if (S.startswith(CloseBrace)) { + } else if (S.starts_with(CloseBrace)) { --Depth; if (Depth == 0) { PEnd = P + CloseBrace.size(); @@ -445,7 +445,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // others. // Regex in initial directive token: -re - if (DToken.endswith("-re")) { + if (DToken.ends_with("-re")) { D.RegexKind = true; KindStr = "regex"; DToken = DToken.substr(0, DToken.size()-3); @@ -454,20 +454,19 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // Type in initial directive token: -{error|warning|note|no-diagnostics} bool NoDiag = false; StringRef DType; - if (DToken.endswith(DType="-error")) + if (DToken.ends_with(DType = "-error")) D.DL = ED ? &ED->Errors : nullptr; - else if (DToken.endswith(DType="-warning")) + else if (DToken.ends_with(DType = "-warning")) D.DL = ED ? &ED->Warnings : nullptr; - else if (DToken.endswith(DType="-remark")) + else if (DToken.ends_with(DType = "-remark")) D.DL = ED ? &ED->Remarks : nullptr; - else if (DToken.endswith(DType="-note")) + else if (DToken.ends_with(DType = "-note")) D.DL = ED ? &ED->Notes : nullptr; - else if (DToken.endswith(DType="-no-diagnostics")) { + else if (DToken.ends_with(DType = "-no-diagnostics")) { NoDiag = true; if (D.RegexKind) continue; - } - else + } else continue; DToken = DToken.substr(0, DToken.size()-DType.size()); @@ -1145,7 +1144,7 @@ std::unique_ptr Directive::create(bool RegexKind, std::string RegexStr; StringRef S = Text; while (!S.empty()) { - if (S.startswith("{{")) { + if (S.starts_with("{{")) { S = S.drop_front(2); size_t RegexMatchLength = S.find("}}"); assert(RegexMatchLength != StringRef::npos); diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index fdd54c05eedf8250436b1bff46c66178846f5f91..f8fdd402777e484695b92a87225f45f5b33bba21 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -387,6 +387,8 @@ if(ARM IN_LIST LLVM_TARGETS_TO_BUILD OR AArch64 IN_LIST LLVM_TARGETS_TO_BUILD) clang_generate_header(-gen-arm-mve-header arm_mve.td arm_mve.h) # Generate arm_cde.h clang_generate_header(-gen-arm-cde-header arm_cde.td arm_cde.h) + # Generate arm_vector_types.h + clang_generate_header(-gen-arm-vector-type arm_neon.td arm_vector_types.h) # Add headers to target specific lists list(APPEND arm_common_generated_files @@ -403,6 +405,7 @@ if(ARM IN_LIST LLVM_TARGETS_TO_BUILD OR AArch64 IN_LIST LLVM_TARGETS_TO_BUILD) "${CMAKE_CURRENT_BINARY_DIR}/arm_sve.h" "${CMAKE_CURRENT_BINARY_DIR}/arm_sme_draft_spec_subject_to_change.h" "${CMAKE_CURRENT_BINARY_DIR}/arm_bf16.h" + "${CMAKE_CURRENT_BINARY_DIR}/arm_vector_types.h" ) endif() if(RISCV IN_LIST LLVM_TARGETS_TO_BUILD) diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp index c67810ad126b6e2ddab9dafb65e1bc960ab3c518..0f79694d1faac7b9073574bece56f51de9c87526 100644 --- a/clang/lib/Index/IndexSymbol.cpp +++ b/clang/lib/Index/IndexSymbol.cpp @@ -36,7 +36,7 @@ static bool isUnitTest(const ObjCMethodDecl *D) { return false; if (!D->getReturnType()->isVoidType()) return false; - if (!D->getSelector().getNameForSlot(0).startswith("test")) + if (!D->getSelector().getNameForSlot(0).starts_with("test")) return false; return isUnitTestCase(D->getClassInterface()); } diff --git a/clang/lib/IndexSerialization/SerializablePathCollection.cpp b/clang/lib/IndexSerialization/SerializablePathCollection.cpp index bd5f861bf482e511168ca428bdf7046aacb4751b..74ed18a4f612def61128db427752da370a6f238a 100644 --- a/clang/lib/IndexSerialization/SerializablePathCollection.cpp +++ b/clang/lib/IndexSerialization/SerializablePathCollection.cpp @@ -70,11 +70,11 @@ PathPool::DirPath SerializablePathCollection::tryStoreDirPath(StringRef Dir) { const std::string OrigDir = Dir.str(); PathPool::RootDirKind Root = PathPool::RootDirKind::Regular; - if (!SysRoot.empty() && Dir.startswith(SysRoot) && + if (!SysRoot.empty() && Dir.starts_with(SysRoot) && llvm::sys::path::is_separator(Dir[SysRoot.size()])) { Root = PathPool::RootDirKind::SysRoot; Dir = Dir.drop_front(SysRoot.size()); - } else if (!WorkDir.empty() && Dir.startswith(WorkDir) && + } else if (!WorkDir.empty() && Dir.starts_with(WorkDir) && llvm::sys::path::is_separator(Dir[WorkDir.size()])) { Root = PathPool::RootDirKind::CurrentWorkDir; Dir = Dir.drop_front(WorkDir.size()); diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp index 22a1532c2d93838bf66f3dd27a1ea69d985d2d1f..00bf880726ee3e0120495e8ee71ab9973d5419e2 100644 --- a/clang/lib/Lex/HeaderMap.cpp +++ b/clang/lib/Lex/HeaderMap.cpp @@ -11,16 +11,17 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/HeaderMap.h" -#include "clang/Lex/HeaderMapTypes.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/FileManager.h" +#include "clang/Lex/HeaderMapTypes.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SwapByteOrder.h" -#include "llvm/Support/Debug.h" +#include "llvm/Support/SystemZ/zOSSupport.h" #include #include #include diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index c03cf19688d961adb9a02e33b4390b6cbf2b4748..f24013d68795aeee090d5174c1b7fedb3b0cf744 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -796,7 +796,7 @@ static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader, } else if (*I == "PrivateHeaders") { ++FoundComp; IsPrivateHeader = true; - } else if (I->endswith(".framework")) { + } else if (I->ends_with(".framework")) { StringRef Name = I->drop_back(10); // Drop .framework // Need to reset the strings and counter to support nested frameworks. FrameworkName.clear(); @@ -1085,7 +1085,7 @@ OptionalFileEntryRef HeaderSearch::LookupFile( // If the filename matches a known system header prefix, override // whether the file is a system header. for (unsigned j = SystemHeaderPrefixes.size(); j; --j) { - if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) { + if (Filename.starts_with(SystemHeaderPrefixes[j - 1].first)) { HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System : SrcMgr::C_User; break; @@ -1694,7 +1694,7 @@ bool HeaderSearch::loadModuleMapFile(FileEntryRef File, bool IsSystem, StringRef DirName(Dir->getName()); if (llvm::sys::path::filename(DirName) == "Modules") { DirName = llvm::sys::path::parent_path(DirName); - if (DirName.endswith(".framework")) + if (DirName.ends_with(".framework")) if (auto MaybeDir = FileMgr.getOptionalDirectoryRef(DirName)) Dir = *MaybeDir; // FIXME: This assert can fail if there's a race between the above check @@ -1965,10 +1965,10 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( // Special case Apple .sdk folders since the search path is typically a // symlink like `iPhoneSimulator14.5.sdk` while the file is instead // located in `iPhoneSimulator.sdk` (the real folder). - if (NI->endswith(".sdk") && DI->endswith(".sdk")) { + if (NI->ends_with(".sdk") && DI->ends_with(".sdk")) { StringRef NBasename = path::stem(*NI); StringRef DBasename = path::stem(*DI); - if (DBasename.startswith(NBasename)) + if (DBasename.starts_with(NBasename)) continue; } diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index 5b1b7c859c85d9346858ee7472f6cfd3d9838f8e..2218db15013d926506c576f8a533596ac595ee72 100644 --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -141,8 +141,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); // If use system headers while cross-compiling, emit the warning. - if (HasSysroot && (MappedPathStr.startswith("/usr/include") || - MappedPathStr.startswith("/usr/local/include"))) { + if (HasSysroot && (MappedPathStr.starts_with("/usr/include") || + MappedPathStr.starts_with("/usr/local/include"))) { Headers.getDiags().Report(diag::warn_poison_system_directories) << MappedPathStr; } diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index f4f1daab857f043696585083e3c99a0839abd1ea..50b56265f6e164d9f5f24546197db33d141d137f 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -3212,8 +3212,8 @@ bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { return false; // Check to see if we have <<<<<<< or >>>>. - if (!StringRef(CurPtr, BufferEnd - CurPtr).startswith("<<<<<<<") && - !StringRef(CurPtr, BufferEnd - CurPtr).startswith(">>>> ")) + if (!StringRef(CurPtr, BufferEnd - CurPtr).starts_with("<<<<<<<") && + !StringRef(CurPtr, BufferEnd - CurPtr).starts_with(">>>> ")) return false; // If we have a situation where we don't care about conflict markers, ignore diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index d35c282543c564d6ac94f8db51d50d38f5a4f7db..ea5d13deb11470325a4e54974a1366e528566daf 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -235,7 +235,7 @@ OptionalFileEntryRef ModuleMap::findHeader( llvm::sys::path::append(FullPathName, RelativePathName); auto NormalHdrFile = GetFile(FullPathName); - if (!NormalHdrFile && Directory->getName().endswith(".framework")) { + if (!NormalHdrFile && Directory->getName().ends_with(".framework")) { // The lack of 'framework' keyword in a module declaration it's a simple // mistake we can diagnose when the header exists within the proper // framework style path. @@ -1034,7 +1034,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, if (inferred == InferredDirectories.end()) { // We haven't looked here before. Load a module map, if there is // one. - bool IsFrameworkDir = Parent.endswith(".framework"); + bool IsFrameworkDir = Parent.ends_with(".framework"); if (OptionalFileEntryRef ModMapFile = HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) { parseModuleMapFile(*ModMapFile, Attrs.IsSystem, *ParentDir); @@ -1125,7 +1125,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Dir = FS.dir_begin(SubframeworksDirName, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { - if (!StringRef(Dir->path()).endswith(".framework")) + if (!StringRef(Dir->path()).ends_with(".framework")) continue; if (auto SubframeworkDir = FileMgr.getOptionalDirectoryRef(Dir->path())) { @@ -1337,7 +1337,7 @@ ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl &Path) { // Modules/ not Versions/A/Modules. if (llvm::sys::path::filename(Dir) == "Modules") { StringRef Parent = llvm::sys::path::parent_path(Dir); - if (Parent.endswith(".framework")) + if (Parent.ends_with(".framework")) Dir = Parent; } @@ -2119,8 +2119,8 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule->Directory = Directory; StringRef MapFileName(ModuleMapFile.getName()); - if (MapFileName.endswith("module.private.modulemap") || - MapFileName.endswith("module_private.map")) { + if (MapFileName.ends_with("module.private.modulemap") || + MapFileName.ends_with("module_private.map")) { ActiveModule->ModuleMapIsPrivate = true; } diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 14003480d7fa2e91f38a363a7932879fec2f2d9e..112bc8dc572c9271f3d4dbab133fe12c14c9d805 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -164,13 +164,13 @@ static bool isLanguageDefinedBuiltin(const SourceManager &SourceMgr, return false; // C defines macros starting with __STDC, and C++ defines macros starting with // __STDCPP - if (MacroName.startswith("__STDC")) + if (MacroName.starts_with("__STDC")) return true; // C++ defines the __cplusplus macro if (MacroName == "__cplusplus") return true; // C++ defines various feature-test macros starting with __cpp - if (MacroName.startswith("__cpp")) + if (MacroName.starts_with("__cpp")) return true; // Anything else isn't language-defined return false; @@ -646,7 +646,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, Directive = StringRef(DirectiveBuf, IdLen); } - if (Directive.startswith("if")) { + if (Directive.starts_with("if")) { StringRef Sub = Directive.substr(2); if (Sub.empty() || // "if" Sub == "def" || // "ifdef" @@ -2788,14 +2788,14 @@ static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI, return false; StringRef ValueText = II->getName(); StringRef TrimmedValue = ValueText; - if (!ValueText.startswith("__")) { - if (ValueText.startswith("_")) + if (!ValueText.starts_with("__")) { + if (ValueText.starts_with("_")) TrimmedValue = TrimmedValue.drop_front(1); else return false; } else { TrimmedValue = TrimmedValue.drop_front(2); - if (TrimmedValue.endswith("__")) + if (TrimmedValue.ends_with("__")) TrimmedValue = TrimmedValue.drop_back(2); } return TrimmedValue.equals(MacroText); diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp index 269984aae07bf288a283fbe37080aec13493c467..1feb0eb18d71e6eaa18c0acd6ba596c526b39d15 100644 --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/lib/Lex/PPExpressions.cpp @@ -267,7 +267,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, const StringRef IdentifierName = II->getName(); if (llvm::any_of(UndefPrefixes, [&IdentifierName](const std::string &Prefix) { - return IdentifierName.startswith(Prefix); + return IdentifierName.starts_with(Prefix); })) PP.Diag(PeekTok, diag::warn_pp_undef_prefix) << AddFlagValue{llvm::join(UndefPrefixes, ",")} << II; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 30c4abdbad8aa4462552d1639651f9068d1dbc17..ad02f31209b0b7804447e2430013c0933745a416 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1136,7 +1136,8 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) { const LangOptions &LangOpts = PP.getLangOpts(); // Normalize the feature name, __foo__ becomes foo. - if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4) + if (Feature.starts_with("__") && Feature.ends_with("__") && + Feature.size() >= 4) Feature = Feature.substr(2, Feature.size() - 4); #define FEATURE(Name, Predicate) .Case(#Name, Predicate) @@ -1162,7 +1163,7 @@ static bool HasExtension(const Preprocessor &PP, StringRef Extension) { const LangOptions &LangOpts = PP.getLangOpts(); // Normalize the extension name, __foo__ becomes foo. - if (Extension.startswith("__") && Extension.endswith("__") && + if (Extension.starts_with("__") && Extension.ends_with("__") && Extension.size() >= 4) Extension = Extension.substr(2, Extension.size() - 4); @@ -1691,9 +1692,9 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // as being "builtin functions", even if the syntax isn't a valid // function call (for example, because the builtin takes a type // argument). - if (II->getName().startswith("__builtin_") || - II->getName().startswith("__is_") || - II->getName().startswith("__has_")) + if (II->getName().starts_with("__builtin_") || + II->getName().starts_with("__is_") || + II->getName().starts_with("__has_")) return true; return llvm::StringSwitch(II->getName()) .Case("__array_rank", true) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index ece3698967e2f67e0c7044f3a179a3742985b2d4..ed006f9d67de454c43e85c43007aef8da6f13ae1 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -84,7 +84,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, DeclaratorContext Context, /// Normalizes an attribute name by dropping prefixed and suffixed __. static StringRef normalizeAttrName(StringRef Name) { - if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__")) return Name.drop_front(2).drop_back(2); return Name; } @@ -7854,7 +7854,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool IsUnqual = Tok.is(tok::kw_typeof_unqual); const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (getLangOpts().C23 && !II->getName().startswith("__")) + if (getLangOpts().C23 && !II->getName().starts_with("__")) Diag(Tok.getLocation(), diag::warn_c23_compat_keyword) << Tok.getName(); Token OpTok = Tok; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 2fc364fc811b3245f9a37fac80920ad81872e3f2..ef9ea6575205cdf31f79462d456b54d14d416e8b 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1311,18 +1311,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( D.takeAttributes(Attributes); } - // Helper to emit a warning if we see a CUDA host/device/global attribute - // after '(...)'. nvcc doesn't accept this. - auto WarnIfHasCUDATargetAttr = [&] { - if (getLangOpts().CUDA) - for (const ParsedAttr &A : Attributes) - if (A.getKind() == ParsedAttr::AT_CUDADevice || - A.getKind() == ParsedAttr::AT_CUDAHost || - A.getKind() == ParsedAttr::AT_CUDAGlobal) - Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position) - << A.getAttrName()->getName(); - }; - MultiParseScope TemplateParamScope(*this); if (Tok.is(tok::less)) { Diag(Tok, getLangOpts().CPlusPlus20 @@ -1377,91 +1365,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( bool HasSpecifiers = false; SourceLocation MutableLoc; - auto ParseConstexprAndMutableSpecifiers = [&] { - // GNU-style attributes must be parsed before the mutable specifier to - // be compatible with GCC. MSVC-style attributes must be parsed before - // the mutable specifier to be compatible with MSVC. - MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes); - // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update - // the DeclEndLoc. - SourceLocation ConstexprLoc; - SourceLocation ConstevalLoc; - SourceLocation StaticLoc; - - tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc, - ConstevalLoc, DeclEndLoc); - - DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro); - - addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS); - addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); - }; - - auto ParseLambdaSpecifiers = - [&](MutableArrayRef ParamInfo, - SourceLocation EllipsisLoc) { - // Parse exception-specification[opt]. - ExceptionSpecificationType ESpecType = EST_None; - SourceRange ESpecRange; - SmallVector DynamicExceptions; - SmallVector DynamicExceptionRanges; - ExprResult NoexceptExpr; - CachedTokens *ExceptionSpecTokens; - - ESpecType = tryParseExceptionSpecification( - /*Delayed=*/false, ESpecRange, DynamicExceptions, - DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); - - if (ESpecType != EST_None) - DeclEndLoc = ESpecRange.getEnd(); - - // Parse attribute-specifier[opt]. - if (MaybeParseCXX11Attributes(Attributes)) - DeclEndLoc = Attributes.Range.getEnd(); - - // Parse OpenCL addr space attribute. - if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, - tok::kw___constant, tok::kw___generic)) { - ParseOpenCLQualifiers(DS.getAttributes()); - ConsumeToken(); - } - - SourceLocation FunLocalRangeEnd = DeclEndLoc; - - // Parse trailing-return-type[opt]. - if (Tok.is(tok::arrow)) { - FunLocalRangeEnd = Tok.getLocation(); - SourceRange Range; - TrailingReturnType = ParseTrailingReturnType( - Range, /*MayBeFollowedByDirectInit*/ false); - TrailingReturnTypeLoc = Range.getBegin(); - if (Range.getEnd().isValid()) - DeclEndLoc = Range.getEnd(); - } - - SourceLocation NoLoc; - D.AddTypeInfo( - DeclaratorChunk::getFunction( - /*HasProto=*/true, - /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), - ParamInfo.size(), EllipsisLoc, RParenLoc, - /*RefQualifierIsLvalueRef=*/true, - /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange, - DynamicExceptions.data(), DynamicExceptionRanges.data(), - DynamicExceptions.size(), - NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, - /*ExceptionSpecTokens*/ nullptr, - /*DeclsInPrototype=*/std::nullopt, LParenLoc, FunLocalRangeEnd, - D, TrailingReturnType, TrailingReturnTypeLoc, &DS), - std::move(Attributes), DeclEndLoc); - - Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); - - if (HasParentheses && Tok.is(tok::kw_requires)) - ParseTrailingRequiresClause(D); - }; - ParseScope Prototype(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | Scope::DeclScope); @@ -1511,18 +1414,104 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( << FixItHint::CreateInsertion(Tok.getLocation(), "() "); } - if (HasParentheses || HasSpecifiers) - ParseConstexprAndMutableSpecifiers(); + if (HasParentheses || HasSpecifiers) { + // GNU-style attributes must be parsed before the mutable specifier to + // be compatible with GCC. MSVC-style attributes must be parsed before + // the mutable specifier to be compatible with MSVC. + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attributes); + // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update + // the DeclEndLoc. + SourceLocation ConstexprLoc; + SourceLocation ConstevalLoc; + SourceLocation StaticLoc; + + tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc, ConstexprLoc, + ConstevalLoc, DeclEndLoc); + + DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc, Intro); + + addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS); + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); + addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); + } Actions.ActOnLambdaClosureParameters(getCurScope(), ParamInfo); if (!HasParentheses) Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); - if (HasSpecifiers || HasParentheses) - ParseLambdaSpecifiers(ParamInfo, EllipsisLoc); + if (HasSpecifiers || HasParentheses) { + // Parse exception-specification[opt]. + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + SmallVector DynamicExceptions; + SmallVector DynamicExceptionRanges; + ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens; + + ESpecType = tryParseExceptionSpecification( + /*Delayed=*/false, ESpecRange, DynamicExceptions, + DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); + + if (ESpecType != EST_None) + DeclEndLoc = ESpecRange.getEnd(); + + // Parse attribute-specifier[opt]. + if (MaybeParseCXX11Attributes(Attributes)) + DeclEndLoc = Attributes.Range.getEnd(); + + // Parse OpenCL addr space attribute. + if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic)) { + ParseOpenCLQualifiers(DS.getAttributes()); + ConsumeToken(); + } + + SourceLocation FunLocalRangeEnd = DeclEndLoc; + + // Parse trailing-return-type[opt]. + if (Tok.is(tok::arrow)) { + FunLocalRangeEnd = Tok.getLocation(); + SourceRange Range; + TrailingReturnType = + ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit=*/false); + TrailingReturnTypeLoc = Range.getBegin(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + SourceLocation NoLoc; + D.AddTypeInfo(DeclaratorChunk::getFunction( + /*HasProto=*/true, + /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), + ParamInfo.size(), EllipsisLoc, RParenLoc, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, + ESpecRange, DynamicExceptions.data(), + DynamicExceptionRanges.data(), DynamicExceptions.size(), + NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, + /*ExceptionSpecTokens*/ nullptr, + /*DeclsInPrototype=*/std::nullopt, LParenLoc, + FunLocalRangeEnd, D, TrailingReturnType, + TrailingReturnTypeLoc, &DS), + std::move(Attributes), DeclEndLoc); - WarnIfHasCUDATargetAttr(); + Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc); + + if (HasParentheses && Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + } + + // Emit a warning if we see a CUDA host/device/global attribute + // after '(...)'. nvcc doesn't accept this. + if (getLangOpts().CUDA) { + for (const ParsedAttr &A : Attributes) + if (A.getKind() == ParsedAttr::AT_CUDADevice || + A.getKind() == ParsedAttr::AT_CUDAHost || + A.getKind() == ParsedAttr::AT_CUDAGlobal) + Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position) + << A.getAttrName()->getName(); + } Prototype.Exit(); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index ec67faf7dcaf863985a2b595e517d3007ff3fa68..b703c2d9b8e04d831c1908dc26b689332879866d 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2645,7 +2645,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, auto &SrcMgr = PP.getSourceManager(); auto FE = SrcMgr.getFileEntryRefForID(SrcMgr.getFileID(AtLoc)); if (FE && llvm::sys::path::parent_path(FE->getDir().getName()) - .endswith(".framework")) + .ends_with(".framework")) Diags.Report(AtLoc, diag::warn_atimport_in_framework_header); } diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp index 0896221dd0bdeb5672b89ea2d450f6faa78b8d3c..0e6ae365064463bf6a6866a8a21c6a5c4a1dcb7a 100644 --- a/clang/lib/Rewrite/Rewriter.cpp +++ b/clang/lib/Rewrite/Rewriter.cpp @@ -386,7 +386,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range, } if (parentSpace.size() >= startSpace.size()) return true; - if (!startSpace.startswith(parentSpace)) + if (!startSpace.starts_with(parentSpace)) return true; StringRef indent = startSpace.substr(parentSpace.size()); @@ -399,7 +399,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range, while (isWhitespaceExceptNL(MB[i])) ++i; StringRef origIndent = MB.substr(offs, i-offs); - if (origIndent.startswith(startSpace)) + if (origIndent.starts_with(startSpace)) RB.InsertText(offs, indent, /*InsertAfter=*/false); } diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 9caa1a8431e9021cf01cf45930e211acc4a467fe..350bd78b57107bbfaa0dde13af5ec7c18af9b503 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -630,15 +630,16 @@ bool PrintingCodeCompleteConsumer::isResultFilteredOut( StringRef Filter, CodeCompletionResult Result) { switch (Result.Kind) { case CodeCompletionResult::RK_Declaration: - return !(Result.Declaration->getIdentifier() && - Result.Declaration->getIdentifier()->getName().startswith(Filter)); + return !( + Result.Declaration->getIdentifier() && + Result.Declaration->getIdentifier()->getName().starts_with(Filter)); case CodeCompletionResult::RK_Keyword: - return !StringRef(Result.Keyword).startswith(Filter); + return !StringRef(Result.Keyword).starts_with(Filter); case CodeCompletionResult::RK_Macro: - return !Result.Macro->getName().startswith(Filter); + return !Result.Macro->getName().starts_with(Filter); case CodeCompletionResult::RK_Pattern: return !(Result.Pattern->getTypedText() && - StringRef(Result.Pattern->getTypedText()).startswith(Filter)); + StringRef(Result.Pattern->getTypedText()).starts_with(Filter)); } llvm_unreachable("Unknown code completion result Kind."); } diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 44a40215b90dfb4c3b5ca3e75de7aabde4b4169e..b3b19b7ed7ffffde3ef5fbedc9819ce70dfcdfa3 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -30,6 +30,20 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T, return nullptr; const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); + if (isa(Ty)) { + if (auto *Record = dyn_cast(CurContext)) { + if (isa(Record) || + Record->getDescribedClassTemplate()) { + const Type *ICNT = Record->getTypeForDecl(); + QualType Injected = + cast(ICNT)->getInjectedSpecializationType(); + + if (Ty == Injected->getCanonicalTypeInternal().getTypePtr()) + return Record; + } + } + } + if (const RecordType *RecordTy = dyn_cast(Ty)) { CXXRecordDecl *Record = cast(RecordTy->getDecl()); if (!Record->isDependentContext() || @@ -37,10 +51,12 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T, return Record; return nullptr; - } else if (isa(Ty)) - return cast(Ty)->getDecl(); - else - return nullptr; + } + + if (auto *ICNT = dyn_cast(Ty)) + return ICNT->getDecl(); + + return nullptr; } /// Compute the DeclContext that is associated with the given type. diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index cdb6e9584e9554104e3b4921f15d4752440661fe..254c272b8093d0cf68fc00a6041b3dd115d10e6e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1219,7 +1219,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (IsChkVariant) { FunctionName = FunctionName.drop_front(std::strlen("__builtin___")); FunctionName = FunctionName.drop_back(std::strlen("_chk")); - } else if (FunctionName.startswith("__builtin_")) { + } else if (FunctionName.starts_with("__builtin_")) { FunctionName = FunctionName.drop_front(std::strlen("__builtin_")); } return FunctionName; @@ -18270,15 +18270,14 @@ static bool isSetterLikeSelector(Selector sel) { StringRef str = sel.getNameForSlot(0); while (!str.empty() && str.front() == '_') str = str.substr(1); - if (str.startswith("set")) + if (str.starts_with("set")) str = str.substr(3); - else if (str.startswith("add")) { + else if (str.starts_with("add")) { // Specially allow 'addOperationWithBlock:'. - if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock")) + if (sel.getNumArgs() == 1 && str.starts_with("addOperationWithBlock")) return false; str = str.substr(3); - } - else + } else return false; if (str.empty()) return true; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 143968b4ab0442fe017705f21dccbef066c164ab..c44be0df9b0a853f2ee2fcb88e59691a5398f27c 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -9798,7 +9798,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector( Results.ExitScope(); if (!AtParameterName && !SelIdents.empty() && - SelIdents.front()->getName().startswith("init")) { + SelIdents.front()->getName().starts_with("init")) { for (const auto &M : PP.macros()) { if (M.first->getName() != "NS_DESIGNATED_INITIALIZER") continue; @@ -10110,7 +10110,7 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { } const StringRef &Dirname = llvm::sys::path::filename(Dir); - const bool isQt = Dirname.startswith("Qt") || Dirname == "ActiveQt"; + const bool isQt = Dirname.starts_with("Qt") || Dirname == "ActiveQt"; const bool ExtensionlessHeaders = IsSystem || isQt || Dir.ends_with(".framework/Headers"); std::error_code EC; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 19d972ed8ab2d830ec9b099d3a820ff00561bc03..be6a136ef37bc4e9e290aac066d833395d5ae525 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15800,7 +15800,7 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) { } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { - return ActOnFinishFunctionBody(D, BodyArg, false); + return ActOnFinishFunctionBody(D, BodyArg, /*IsInstantiation=*/false); } /// RAII object that pops an ExpressionEvaluationContext when exiting a function @@ -16005,7 +16005,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, return StartTok.consume_front("const") && (StartTok.empty() || isWhitespace(StartTok[0]) || - StartTok.startswith("/*") || StartTok.startswith("//")); + StartTok.starts_with("/*") || StartTok.starts_with("//")); }; auto findBeginLoc = [&]() { @@ -16359,7 +16359,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // Extension in C99 (defaults to error). Legal in C89, but warn about it. unsigned diag_id; - if (II.getName().startswith("__builtin_")) + if (II.getName().starts_with("__builtin_")) diag_id = diag::warn_builtin_unknown; // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported. else if (getLangOpts().C99) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 59e456fd9f729837de00d86e5511db839d960c6d..5b29b05dee54b3e95032df22b729594fda8ea7dd 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1809,8 +1809,8 @@ static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { /// Normalize the attribute, __foo__ becomes foo. /// Returns true if normalization was applied. static bool normalizeName(StringRef &AttrName) { - if (AttrName.size() > 4 && AttrName.startswith("__") && - AttrName.endswith("__")) { + if (AttrName.size() > 4 && AttrName.starts_with("__") && + AttrName.ends_with("__")) { AttrName = AttrName.drop_front(2).drop_back(2); return true; } @@ -3605,7 +3605,7 @@ bool Sema::checkTargetClonesAttrString( } } else { // Other targets ( currently X86 ) - if (Cur.startswith("arch=")) { + if (Cur.starts_with("arch=")) { if (!Context.getTargetInfo().isValidCPUName( Cur.drop_front(sizeof("arch=") - 1))) return Diag(CurLoc, diag::warn_unsupported_target_attribute) @@ -3623,7 +3623,7 @@ bool Sema::checkTargetClonesAttrString( StringsBuffer.push_back(Cur); } } - if (Str.rtrim().endswith(",")) + if (Str.rtrim().ends_with(",")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; return false; @@ -5225,8 +5225,16 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.checkAtLeastNumArgs(S, 1)) + if (AL.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress) { + // Suppression attribute with GSL spelling requires at least 1 argument. + if (!AL.checkAtLeastNumArgs(S, 1)) + return; + } else if (!isa(D)) { + // Analyzer suppression applies only to variables and statements. + S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str) + << AL << 0 << "variables and statements"; return; + } std::vector DiagnosticIdentifiers; for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { @@ -5235,8 +5243,6 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr)) return; - // FIXME: Warn if the rule name is unknown. This is tricky because only - // clang-tidy knows about available rules. DiagnosticIdentifiers.push_back(RuleName); } D->addAttr(::new (S.Context) @@ -5819,7 +5825,7 @@ struct IntrinToName { static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, ArrayRef Map, const char *IntrinNames) { - if (AliasName.startswith("__arm_")) + if (AliasName.starts_with("__arm_")) AliasName = AliasName.substr(6); const IntrinToName *It = llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) { @@ -6663,10 +6669,10 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, // Check whether this will be mapped to a getter or setter of a property. bool IsGetter = false, IsSetter = false; - if (Name.startswith("getter:")) { + if (Name.starts_with("getter:")) { IsGetter = true; Name = Name.substr(7); - } else if (Name.startswith("setter:")) { + } else if (Name.starts_with("setter:")) { IsSetter = true; Name = Name.substr(7); } @@ -7292,7 +7298,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D, } } - if (!Space.startswith("space")) { + if (!Space.starts_with("space")) { S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; return; } diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index cdfa6ad3f281a4359bf4b0da41233a50f1eefa9f..c3b95e168a605166c9f4a3e96f1297cd43ca64e4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -296,7 +296,7 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, const NamedDecl *ND, RealizedPlatform = S.Context.getTargetInfo().getPlatformName(); // Warn about implementing unavailable methods, unless the unavailable // is for an app extension. - if (RealizedPlatform.endswith("_app_extension")) + if (RealizedPlatform.ends_with("_app_extension")) return; S.Diag(ImplLoc, diag::warn_unavailable_def); S.Diag(ND->getLocation(), diag::note_method_declared_at) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d629be083d8c38c2da587dd40210f19ee23deb86..c7185d56cc99739882d5f7a75aed0d2f81ba0a24 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13808,12 +13808,12 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, StringRef RHSStrRef = RHSStr; // Do not diagnose literals with digit separators, binary, hexadecimal, octal // literals. - if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") || - RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") || - LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") || - RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") || - (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) || - (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) || + if (LHSStrRef.starts_with("0b") || LHSStrRef.starts_with("0B") || + RHSStrRef.starts_with("0b") || RHSStrRef.starts_with("0B") || + LHSStrRef.starts_with("0x") || LHSStrRef.starts_with("0X") || + RHSStrRef.starts_with("0x") || RHSStrRef.starts_with("0X") || + (LHSStrRef.size() > 1 && LHSStrRef.starts_with("0")) || + (RHSStrRef.size() > 1 && RHSStrRef.starts_with("0")) || LHSStrRef.contains('\'') || RHSStrRef.contains('\'')) return; @@ -15508,7 +15508,7 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, if (const ObjCMessageExpr *ME = dyn_cast(Ex)) { Selector S = ME->getSelector(); StringRef SelArg0 = S.getNameForSlot(0); - if (SelArg0.startswith("performSelector")) + if (SelArg0.starts_with("performSelector")) Diag = diag::warn_objc_pointer_masking_performSelector; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5ca6b232df66a560b97751c73f3c6ff87cb978d5..4028b2d642b21239c028fb3d2235994a23e06970 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -465,7 +465,8 @@ class InitListChecker { void FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, InitListExpr *ILE, bool &RequiresSecondPass, - bool FillWithNoInit = false); + bool FillWithNoInit = false, + bool WarnIfMissing = false); void FillInEmptyInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass, InitListExpr *OuterILE, unsigned OuterIndex, @@ -654,11 +655,16 @@ void InitListChecker::FillInEmptyInitForBase( } } -void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, - const InitializedEntity &ParentEntity, - InitListExpr *ILE, - bool &RequiresSecondPass, - bool FillWithNoInit) { +static bool hasAnyDesignatedInits(const InitListExpr *IL) { + return llvm::any_of(*IL, [=](const Stmt *Init) { + return isa_and_nonnull(Init); + }); +} + +void InitListChecker::FillInEmptyInitForField( + unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, + InitListExpr *ILE, bool &RequiresSecondPass, bool FillWithNoInit, + bool WarnIfMissing) { SourceLocation Loc = ILE->getEndLoc(); unsigned NumInits = ILE->getNumInits(); InitializedEntity MemberEntity @@ -726,15 +732,52 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, if (hadError || VerifyOnly) { // Do nothing - } else if (Init < NumInits) { - ILE->setInit(Init, MemberInit.getAs()); - } else if (!isa(MemberInit.get())) { - // Empty initialization requires a constructor call, so - // extend the initializer list to include the constructor - // call and make a note that we'll need to take another pass - // through the initializer list. - ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs()); - RequiresSecondPass = true; + } else { + if (WarnIfMissing) { + auto CheckAnonMember = [&](const FieldDecl *FD, + auto &&CheckAnonMember) -> FieldDecl * { + FieldDecl *Uninitialized = nullptr; + RecordDecl *RD = FD->getType()->getAsRecordDecl(); + assert(RD && "Not anonymous member checked?"); + for (auto *F : RD->fields()) { + FieldDecl *UninitializedFieldInF = nullptr; + if (F->isAnonymousStructOrUnion()) + UninitializedFieldInF = CheckAnonMember(F, CheckAnonMember); + else if (!F->isUnnamedBitfield() && + !F->getType()->isIncompleteArrayType() && + !F->hasInClassInitializer()) + UninitializedFieldInF = F; + + if (RD->isUnion() && !UninitializedFieldInF) + return nullptr; + if (!Uninitialized) + Uninitialized = UninitializedFieldInF; + } + return Uninitialized; + }; + + FieldDecl *FieldToDiagnose = nullptr; + if (Field->isAnonymousStructOrUnion()) + FieldToDiagnose = CheckAnonMember(Field, CheckAnonMember); + else if (!Field->isUnnamedBitfield() && + !Field->getType()->isIncompleteArrayType()) + FieldToDiagnose = Field; + + if (FieldToDiagnose) + SemaRef.Diag(Loc, diag::warn_missing_field_initializers) + << FieldToDiagnose; + } + + if (Init < NumInits) { + ILE->setInit(Init, MemberInit.getAs()); + } else if (!isa(MemberInit.get())) { + // Empty initialization requires a constructor call, so + // extend the initializer list to include the constructor + // call and make a note that we'll need to take another pass + // through the initializer list. + ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs()); + RequiresSecondPass = true; + } } } else if (InitListExpr *InnerILE = dyn_cast(ILE->getInit(Init))) { @@ -802,9 +845,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, } } } else { + InitListExpr *SForm = + ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm(); // The fields beyond ILE->getNumInits() are default initialized, so in // order to leave them uninitialized, the ILE is expanded and the extra // fields are then filled with NoInitExpr. + + // Some checks that are required for missing fields warning are bound to + // how many elements the initializer list originally was provided; perform + // them before the list is expanded. + bool WarnIfMissingField = + !SForm->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && + ILE->getNumInits(); + + // Disable check for missing fields when designators are used in C to + // match gcc behaviour. + // FIXME: Should we emulate possible gcc warning bug? + WarnIfMissingField &= + SemaRef.getLangOpts().CPlusPlus || !hasAnyDesignatedInits(SForm); + unsigned NumElems = numStructUnionElements(ILE->getType()); if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember()) ++NumElems; @@ -832,7 +891,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, return; FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass, - FillWithNoInit); + FillWithNoInit, WarnIfMissingField); if (hadError) return; @@ -947,13 +1006,6 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, } } -static bool hasAnyDesignatedInits(const InitListExpr *IL) { - for (const Stmt *Init : *IL) - if (isa_and_nonnull(Init)) - return true; - return false; -} - InitListChecker::InitListChecker( Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution, @@ -2225,12 +2277,8 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = - !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; - llvm::SmallPtrSet InitializedFields; - while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); SourceLocation InitLoc = Init->getBeginLoc(); @@ -2254,24 +2302,17 @@ void InitListChecker::CheckStructUnionTypes( // Find the field named by the designated initializer. DesignatedInitExpr::Designator *D = DIE->getDesignator(0); - if (!VerifyOnly && D->isFieldDesignator()) { + if (!VerifyOnly && D->isFieldDesignator() && !DesignatedInitFailed) { FieldDecl *F = D->getFieldDecl(); - InitializedFields.insert(F); - if (!DesignatedInitFailed) { - QualType ET = SemaRef.Context.getBaseElementType(F->getType()); - if (checkDestructorReference(ET, InitLoc, SemaRef)) { - hadError = true; - return; - } + QualType ET = SemaRef.Context.getBaseElementType(F->getType()); + if (checkDestructorReference(ET, InitLoc, SemaRef)) { + hadError = true; + return; } } InitializedSomething = true; - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) - CheckForMissingFields = false; continue; } @@ -2350,7 +2391,6 @@ void InitListChecker::CheckStructUnionTypes( CheckSubElementType(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); InitializedSomething = true; - InitializedFields.insert(*Field); if (RD->isUnion() && StructuredList) { // Initialize the first field within the union. @@ -2360,28 +2400,6 @@ void InitListChecker::CheckStructUnionTypes( ++Field; } - // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { - // It is possible we have one or more unnamed bitfields remaining. - // Find first (if any) named field and emit warning. - for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, - end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) - continue; - - if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() && - !it->getType()->isIncompleteArrayType()) { - SemaRef.Diag(IList->getSourceRange().getEnd(), - diag::warn_missing_field_initializers) - << *it; - break; - } - } - } - // Check that any remaining fields can be value-initialized if we're not // building a structured list. (If we are, we'll check this later.) if (!StructuredList && Field != FieldEnd && !RD->isUnion() && diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 9282ceb8dee03de050315306ade7710f0f40f97d..db0cbd5ec6d6ca6c9efe0ebe8b7943bf21844dec 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -268,7 +268,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, StringRef FirstComponentName = Path[0].first->getName(); if (!getSourceManager().isInSystemHeader(Path[0].second) && (FirstComponentName == "std" || - (FirstComponentName.startswith("std") && + (FirstComponentName.starts_with("std") && llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit)))) Diag(Path[0].second, diag::warn_reserved_module_name) << Path[0].first; diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp index 0d411fca0f9c8275489fb476c1850714f49d5b44..e4642e4da016a44d3c770a178f48c56784ebd2d6 100644 --- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp +++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp @@ -43,7 +43,7 @@ struct RVVIntrinsicDef { struct RVVOverloadIntrinsicDef { // Indexes of RISCVIntrinsicManagerImpl::IntrinsicList. - SmallVector Indexes; + SmallVector Indexes; }; } // namespace @@ -162,7 +162,7 @@ private: // List of all RVV intrinsic. std::vector IntrinsicList; // Mapping function name to index of IntrinsicList. - StringMap Intrinsics; + StringMap Intrinsics; // Mapping function name to RVVOverloadIntrinsicDef. StringMap OverloadIntrinsics; @@ -174,7 +174,7 @@ private: // Create FunctionDecl for a vector intrinsic. void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II, - Preprocessor &PP, unsigned Index, + Preprocessor &PP, uint32_t Index, bool IsOverload); void ConstructRVVIntrinsics(ArrayRef Recs, @@ -386,7 +386,7 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic( Record.HasFRMRoundModeOp); // Put into IntrinsicList. - size_t Index = IntrinsicList.size(); + uint32_t Index = IntrinsicList.size(); IntrinsicList.push_back({BuiltinName, Signature}); // Creating mapping to Intrinsics. @@ -403,7 +403,7 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic( void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II, Preprocessor &PP, - unsigned Index, + uint32_t Index, bool IsOverload) { ASTContext &Context = S.Context; RVVIntrinsicDef &IDef = IntrinsicList[Index]; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 725d8efe3828d659dbbeb58b91571a1453db50c3..0d0a7bcebab4e89279a67008378bf740c5665ddb 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -53,6 +53,13 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { + if (A.getAttributeSpellingListIndex() == SuppressAttr::CXX11_gsl_suppress && + A.getNumArgs() < 1) { + // Suppression attribute with GSL spelling requires at least 1 argument. + S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) << A << 1; + return nullptr; + } + std::vector DiagnosticIdentifiers; for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) { StringRef RuleName; @@ -60,8 +67,6 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr)) return nullptr; - // FIXME: Warn if the rule name is unknown. This is tricky because only - // clang-tidy knows about available rules. DiagnosticIdentifiers.push_back(RuleName); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f10abeaba0d4517ed5df60d4fbaae7919b7d829a..cca7d61306156455b5a6092754f55139e714e1dd 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/SaveAndRestore.h" #include #include @@ -3990,9 +3991,14 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Inst.isInvalid()) return QualType(); - CanonType = SubstType(Pattern->getUnderlyingType(), - TemplateArgLists, AliasTemplate->getLocation(), - AliasTemplate->getDeclName()); + { + Sema::ContextRAII SavedContext(*this, Pattern->getDeclContext()); + if (RebuildingTypesInCurrentInstantiation) + SavedContext.pop(); + CanonType = + SubstType(Pattern->getUnderlyingType(), TemplateArgLists, + AliasTemplate->getLocation(), AliasTemplate->getDeclName()); + } if (CanonType.isNull()) { // If this was enable_if and we failed to find the nested type // within enable_if in a SFINAE context, dig out the specific @@ -11392,6 +11398,8 @@ TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, if (!T || !T->getType()->isInstantiationDependentType()) return T; + llvm::SaveAndRestore DisableContextSwitchForTypeAliases( + RebuildingTypesInCurrentInstantiation, true); CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name); return Rebuilder.TransformType(T); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 83610503ed9b16b12089c54dc5e8766ef5272bbc..a376f20fa4f4e08540b3a86ac5a9ac1e96f88b6d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5371,7 +5371,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, !(D.getIdentifier() && ((D.getIdentifier()->getName() == "printf" && LangOpts.getOpenCLCompatibleVersion() >= 120) || - D.getIdentifier()->getName().startswith("__")))) { + D.getIdentifier()->getName().starts_with("__")))) { S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function); D.setInvalidType(true); } @@ -8360,12 +8360,25 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, // not to need a separate attribute) if (!(S.Context.getTargetInfo().hasFeature("neon") || S.Context.getTargetInfo().hasFeature("mve") || - IsTargetCUDAAndHostARM)) { + S.Context.getTargetInfo().hasFeature("sve") || + S.Context.getTargetInfo().hasFeature("sme") || + IsTargetCUDAAndHostARM) && + VecKind == VectorKind::Neon) { + S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) + << Attr << "'neon', 'mve', 'sve' or 'sme'"; + Attr.setInvalid(); + return; + } + if (!(S.Context.getTargetInfo().hasFeature("neon") || + S.Context.getTargetInfo().hasFeature("mve") || + IsTargetCUDAAndHostARM) && + VecKind == VectorKind::NeonPoly) { S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr << "'neon' or 'mve'"; Attr.setInvalid(); return; } + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index bd6655cc1e3fa352daf2e3a2145f5a8357cd36b2..fedc6db3723aac815aba0f6c1e60376868a53b7c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -1045,8 +1045,8 @@ bool ObjCDeallocChecker::isReleasedByCIFilterDealloc( StringRef IvarName = PropImpl->getPropertyIvarDecl()->getName(); const char *ReleasePrefix = "input"; - if (!(PropName.startswith(ReleasePrefix) || - IvarName.startswith(ReleasePrefix))) { + if (!(PropName.starts_with(ReleasePrefix) || + IvarName.starts_with(ReleasePrefix))) { return false; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index dbba12bb4355c3a48b20a523d75f44b232e4deea..afc5e6b48008d869d0d1077df33f04abcc1c8f24 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -140,7 +140,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { if (!II) // if no identifier, not a simple C function return; StringRef Name = II->getName(); - if (Name.startswith("__builtin_")) + if (Name.starts_with("__builtin_")) Name = Name.substr(10); // Set the evaluation function by switching on the callee name. @@ -763,7 +763,7 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 }; StringRef Name = FD->getIdentifier()->getName(); - if (Name.startswith("__builtin_")) + if (Name.starts_with("__builtin_")) Name = Name.substr(10); int ArgIndex = diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 5f44c9476928dd827ccff91267835437f165be85..86f446fc411ca2bdccd1e044f60f7525790ad133 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -183,7 +183,7 @@ public: // Files autogenerated by DriverKit IIG contain some dead stores that // we don't want to report. - if (Data.startswith("/* iig")) + if (Data.starts_with("/* iig")) return true; return false; diff --git a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp index 8e02ef74c66863ef9ebe2a42ade8946681070eed..5637941a58f0260053fc4331563fab1a3ef61f7e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp @@ -73,7 +73,7 @@ decltype(auto) bindAssignmentToDecl(const char *DeclName) { static bool isTest(const Decl *D) { if (const auto* ND = dyn_cast(D)) { std::string DeclName = ND->getNameAsString(); - if (StringRef(DeclName).startswith("test")) + if (StringRef(DeclName).starts_with("test")) return true; } if (const auto *OD = dyn_cast(D)) { diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp index b77e9bf09a33204c57dd52275b3f129bb1299a39..70f911fc66abca8625a384f97e28a7568d80bf32 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -817,9 +817,9 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg, // Handle the case where the receiver is an NSString // These special NSString methods draw to the screen - if (!(SelectorName.startswith("drawAtPoint") || - SelectorName.startswith("drawInRect") || - SelectorName.startswith("drawWithRect"))) + if (!(SelectorName.starts_with("drawAtPoint") || + SelectorName.starts_with("drawInRect") || + SelectorName.starts_with("drawWithRect"))) return; SVal svTitle = msg.getReceiverSVal(); diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c5e4add501886a4d4b654d89d972c210ccba092e..79ab05f2c7866aa2a45e81f2b7b4295f3b01cc4e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -3150,16 +3150,16 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // transferred. Again, though, we can't be sure that the object will use // free() to deallocate the memory, so we can't model it explicitly. StringRef FirstSlot = Msg->getSelector().getNameForSlot(0); - if (FirstSlot.endswith("NoCopy")) + if (FirstSlot.ends_with("NoCopy")) return true; // If the first selector starts with addPointer, insertPointer, // or replacePointer, assume we are dealing with NSPointerArray or similar. // This is similar to C++ containers (vector); we still might want to check // that the pointers get freed by following the container itself. - if (FirstSlot.startswith("addPointer") || - FirstSlot.startswith("insertPointer") || - FirstSlot.startswith("replacePointer") || + if (FirstSlot.starts_with("addPointer") || + FirstSlot.starts_with("insertPointer") || + FirstSlot.starts_with("replacePointer") || FirstSlot.equals("valueWithPointer")) { return true; } @@ -3199,7 +3199,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // White list the 'XXXNoCopy' CoreFoundation functions. // We specifically check these before - if (FName.endswith("NoCopy")) { + if (FName.ends_with("NoCopy")) { // Look for the deallocator argument. We know that the memory ownership // is not transferred only if the deallocator argument is // 'kCFAllocatorNull'. diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 627b51af6bd44af45a43c8e4e89e41cf3af75f14..06f1ad00eaf20ddd6e3fbb9533db127c7ffe2c16 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -890,7 +890,7 @@ void NullabilityChecker::checkPostCall(const CallEvent &Call, // of CG calls. const SourceManager &SM = C.getSourceManager(); StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getBeginLoc())); - if (llvm::sys::path::filename(FilePath).startswith("CG")) { + if (llvm::sys::path::filename(FilePath).starts_with("CG")) { State = State->set(Region, Nullability::Contradicted); C.addTransition(State); return; @@ -992,7 +992,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M, // In order to reduce the noise in the diagnostics generated by this checker, // some framework and programming style based heuristics are used. These // heuristics are for Cocoa APIs which have NS prefix. - if (Name.startswith("NS")) { + if (Name.starts_with("NS")) { // Developers rely on dynamic invariants such as an item should be available // in a collection, or a collection is not empty often. Those invariants can // not be inferred by any static analysis tool. To not to bother the users diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp index 4636fd1605118f776c5afb51f82b26e9287360ba..08ad6877cbe6b6523417caf8f36f8c78f11c1ebf 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp @@ -50,7 +50,7 @@ void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D, const std::string &PropTypeName(T->getPointeeType().getCanonicalType() .getUnqualifiedType() .getAsString()); - if (!StringRef(PropTypeName).startswith("NSMutable")) + if (!StringRef(PropTypeName).starts_with("NSMutable")) return; const ObjCImplDecl *ImplD = nullptr; diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 9532254e3c459681bef893d7f4905fd5040d778a..f3e0a5f9f314aded8b40e30a8a919d1ab6d400dd 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -12,12 +12,15 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -2139,15 +2142,14 @@ PathSensitiveBugReport::PathSensitiveBugReport( "checkers to emit warnings, because checkers should depend on " "*modeling*, not *diagnostics*."); - assert( - (bt.getCheckerName().startswith("debug") || - !isHidden(ErrorNode->getState() - ->getAnalysisManager() - .getCheckerManager() - ->getCheckerRegistryData(), - bt.getCheckerName())) && - "Hidden checkers musn't emit diagnostics as they are by definition " - "non-user facing!"); + assert((bt.getCheckerName().starts_with("debug") || + !isHidden(ErrorNode->getState() + ->getAnalysisManager() + .getCheckerManager() + ->getCheckerRegistryData(), + bt.getCheckerName())) && + "Hidden checkers musn't emit diagnostics as they are by definition " + "non-user facing!"); } void PathSensitiveBugReport::addVisitor( @@ -2425,6 +2427,12 @@ PathSensitiveBugReport::getLocation() const { } if (S) { + // Attributed statements usually have corrupted begin locations, + // it's OK to ignore attributes for our purposes and deal with + // the actual annotated statement. + if (const auto *AS = dyn_cast(S)) + S = AS->getSubStmt(); + // For member expressions, return the location of the '.' or '->'. if (const auto *ME = dyn_cast(S)) return PathDiagnosticLocation::createMemberLoc(ME, SM); @@ -2897,6 +2905,10 @@ void BugReporter::emitReport(std::unique_ptr R) { if (!ValidSourceLoc) return; + // If the user asked to suppress this report, we should skip it. + if (UserSuppressions.isSuppressed(*R)) + return; + // Compute the bug report's hash to determine its equivalence class. llvm::FoldingSetNodeID ID; R->Profile(ID); @@ -3064,8 +3076,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { // See whether we need to silence the checker/package. for (const std::string &CheckerOrPackage : getAnalyzerOptions().SilencedCheckersAndPackages) { - if (report->getBugType().getCheckerName().startswith( - CheckerOrPackage)) + if (report->getBugType().getCheckerName().starts_with(CheckerOrPackage)) return; } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 4a9d130c240aec307dce9fc4189a257b9f3645df..2f9965036b9ef91fe9181c50fad3c88269f5e739 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -3372,7 +3372,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor( FullSourceLoc Loc = BR.getLocation().asLocation(); while (Loc.isMacroID()) { Loc = Loc.getSpellingLoc(); - if (SM.getFilename(Loc).endswith("sys/queue.h")) { + if (SM.getFilename(Loc).ends_with("sys/queue.h")) { BR.markInvalid(getTag(), nullptr); return; } diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5991e47a5388752c4a6318fd89d6e1610d8c3df --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp @@ -0,0 +1,169 @@ +//===- BugSuppression.cpp - Suppression interface -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" + +using namespace clang; +using namespace ento; + +namespace { + +using Ranges = llvm::SmallVectorImpl; + +inline bool hasSuppression(const Decl *D) { + // FIXME: Implement diagnostic identifier arguments + // (checker names, "hashtags"). + if (const auto *Suppression = D->getAttr()) + return !Suppression->isGSL() && + (Suppression->diagnosticIdentifiers().empty()); + return false; +} +inline bool hasSuppression(const AttributedStmt *S) { + // FIXME: Implement diagnostic identifier arguments + // (checker names, "hashtags"). + return llvm::any_of(S->getAttrs(), [](const Attr *A) { + const auto *Suppression = dyn_cast(A); + return Suppression && !Suppression->isGSL() && + (Suppression->diagnosticIdentifiers().empty()); + }); +} + +template inline SourceRange getRange(const NodeType *Node) { + return Node->getSourceRange(); +} +template <> inline SourceRange getRange(const AttributedStmt *S) { + // Begin location for attributed statement node seems to be ALWAYS invalid. + // + // It is unlikely that we ever report any warnings on suppression + // attribute itself, but even if we do, we wouldn't want that warning + // to be suppressed by that same attribute. + // + // Long story short, we can use inner statement and it's not going to break + // anything. + return getRange(S->getSubStmt()); +} + +inline bool isLessOrEqual(SourceLocation LHS, SourceLocation RHS, + const SourceManager &SM) { + // SourceManager::isBeforeInTranslationUnit tests for strict + // inequality, when we need a non-strict comparison (bug + // can be reported directly on the annotated note). + // For this reason, we use the following equivalence: + // + // A <= B <==> !(B < A) + // + return !SM.isBeforeInTranslationUnit(RHS, LHS); +} + +inline bool fullyContains(SourceRange Larger, SourceRange Smaller, + const SourceManager &SM) { + // Essentially this means: + // + // Larger.fullyContains(Smaller) + // + // However, that method has a very trivial implementation and couldn't + // compare regular locations and locations from macro expansions. + // We could've converted everything into regular locations as a solution, + // but the following solution seems to be the most bulletproof. + return isLessOrEqual(Larger.getBegin(), Smaller.getBegin(), SM) && + isLessOrEqual(Smaller.getEnd(), Larger.getEnd(), SM); +} + +class CacheInitializer : public RecursiveASTVisitor { +public: + static void initialize(const Decl *D, Ranges &ToInit) { + CacheInitializer(ToInit).TraverseDecl(const_cast(D)); + } + + bool VisitVarDecl(VarDecl *VD) { + // Bug location could be somewhere in the init value of + // a freshly declared variable. Even though it looks like the + // user applied attribute to a statement, it will apply to a + // variable declaration, and this is where we check for it. + return VisitAttributedNode(VD); + } + + bool VisitAttributedStmt(AttributedStmt *AS) { + // When we apply attributes to statements, it actually creates + // a wrapper statement that only contains attributes and the wrapped + // statement. + return VisitAttributedNode(AS); + } + +private: + template bool VisitAttributedNode(NodeType *Node) { + if (hasSuppression(Node)) { + // TODO: In the future, when we come up with good stable IDs for checkers + // we can return a list of kinds to ignore, or all if no arguments + // were provided. + addRange(getRange(Node)); + } + // We should keep traversing AST. + return true; + } + + void addRange(SourceRange R) { + if (R.isValid()) { + Result.push_back(R); + } + } + + CacheInitializer(Ranges &R) : Result(R) {} + Ranges &Result; +}; + +} // end anonymous namespace + +// TODO: Introduce stable IDs for checkers and check for those here +// to be more specific. Attribute without arguments should still +// be considered as "suppress all". +// It is already much finer granularity than what we have now +// (i.e. removing the whole function from the analysis). +bool BugSuppression::isSuppressed(const BugReport &R) { + PathDiagnosticLocation Location = R.getLocation(); + PathDiagnosticLocation UniqueingLocation = R.getUniqueingLocation(); + const Decl *DeclWithIssue = R.getDeclWithIssue(); + + return isSuppressed(Location, DeclWithIssue, {}) || + isSuppressed(UniqueingLocation, DeclWithIssue, {}); +} + +bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location, + const Decl *DeclWithIssue, + DiagnosticIdentifierList Hashtags) { + if (!Location.isValid() || DeclWithIssue == nullptr) + return false; + + // While some warnings are attached to AST nodes (mostly path-sensitive + // checks), others are simply associated with a plain source location + // or range. Figuring out the node based on locations can be tricky, + // so instead, we traverse the whole body of the declaration and gather + // information on ALL suppressions. After that we can simply check if + // any of those suppressions affect the warning in question. + // + // Traversing AST of a function is not a heavy operation, but for + // large functions with a lot of bugs it can make a dent in performance. + // In order to avoid this scenario, we cache traversal results. + auto InsertionResult = CachedSuppressionLocations.insert( + std::make_pair(DeclWithIssue, CachedRanges{})); + Ranges &SuppressionRanges = InsertionResult.first->second; + if (InsertionResult.second) { + // We haven't checked this declaration for suppressions yet! + CacheInitializer::initialize(DeclWithIssue, SuppressionRanges); + } + + SourceRange BugRange = Location.asRange(); + const SourceManager &SM = Location.getManager(); + + return llvm::any_of(SuppressionRanges, + [BugRange, &SM](SourceRange Suppression) { + return fullyContains(Suppression, BugRange, SM); + }); +} diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt index 3df93374dada753bf1edaf821f532bace6c63de2..8672876c0608d0de06d81785081e309ea2765c2a 100644 --- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangStaticAnalyzerCore BlockCounter.cpp BugReporter.cpp BugReporterVisitors.cpp + BugSuppression.cpp CallDescription.cpp CallEvent.cpp Checker.cpp diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index d004c12bf2c1e8b36d372badf6041ea6c78a5e68..0ac1d91b79beb5ac2d00838a45b2097f15b8fe32 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -659,17 +659,17 @@ bool AnyFunctionCall::argumentsMayEscape() const { // - CoreFoundation functions that end with "NoCopy" can free a passed-in // buffer even if it is const. - if (FName.endswith("NoCopy")) + if (FName.ends_with("NoCopy")) return true; // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. - if (FName.startswith("NS") && FName.contains("Insert")) + if (FName.starts_with("NS") && FName.contains("Insert")) return true; // - Many CF containers allow objects to escape through custom // allocators/deallocators upon container construction. (PR12101) - if (FName.startswith("CF") || FName.startswith("CG")) { + if (FName.starts_with("CF") || FName.starts_with("CG")) { return StrInStrNoCase(FName, "InsertValue") != StringRef::npos || StrInStrNoCase(FName, "AddValue") != StringRef::npos || StrInStrNoCase(FName, "SetValue") != StringRef::npos || diff --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index c25165cce1287650a9b64f0e35b37edc231f948c..d6d4cec9dd3d4d01dd5ab2ffb9fbbeab337e4ddb 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -105,10 +105,11 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, if (FName.equals(Name)) return true; - if (FName.startswith("__inline") && FName.contains(Name)) + if (FName.starts_with("__inline") && FName.contains(Name)) return true; - if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name)) + if (FName.starts_with("__") && FName.ends_with("_chk") && + FName.contains(Name)) return true; return false; diff --git a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp index 1b3e8b11549dd9d5b029649e6b94adcd52d8b971..b9c6278991f43f6a8092390a7e2b83106fb9bd89 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp @@ -82,7 +82,7 @@ static constexpr char PackageSeparator = '.'; static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) { // Does the checker's full name have the package as a prefix? - if (!Checker.FullName.startswith(PackageName)) + if (!Checker.FullName.starts_with(PackageName)) return false; // Is the package actually just the name of a specific checker? @@ -158,7 +158,7 @@ void CheckerRegistryData::printCheckerWithDescList( continue; } - if (Checker.FullName.startswith("alpha")) { + if (Checker.FullName.starts_with("alpha")) { if (AnOpts.ShowCheckerHelpAlpha) Print(Out, Checker, ("(Enable only for development!) " + Checker.Desc).str()); @@ -228,7 +228,7 @@ void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts, } if (Option.DevelopmentStatus == "alpha" || - Entry.first.startswith("alpha")) { + Entry.first.starts_with("alpha")) { if (AnOpts.ShowCheckerOptionAlphaList) Print(Out, FullOption, llvm::Twine("(Enable only for development!) " + Desc).str()); diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 142acab7cd081d4ed884d7aaa3623a319eec6443..b6ef40595e3c97a5e218516f84d5d325263a7540 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -308,7 +308,7 @@ public: bool VisitFunctionDecl(FunctionDecl *FD) { IdentifierInfo *II = FD->getIdentifier(); - if (II && II->getName().startswith("__inline")) + if (II && II->getName().starts_with("__inline")) return true; // We skip function template definitions, as their semantics is diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index f0d3f43c414c6e715b47045dcf7261adc235a8bf..317df90a7781e243f178897019173bfc9a8c1983 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -310,8 +310,8 @@ template void CheckerRegistry::resolveDependencies() { "Failed to find the dependency of a checker!"); // We do allow diagnostics from unit test/example dependency checkers. - assert((DependencyIt->FullName.startswith("test") || - DependencyIt->FullName.startswith("example") || IsWeak || + assert((DependencyIt->FullName.starts_with("test") || + DependencyIt->FullName.starts_with("example") || IsWeak || DependencyIt->IsHidden) && "Strong dependencies are modeling checkers, and as such " "non-user facing! Mark them hidden in Checkers.td!"); diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp index a04694e628de4041be05fdaf2121db9409f13a69..bb9f7dc7e7e3d439f97608d50eee874bdec57180 100644 --- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp +++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp @@ -464,7 +464,7 @@ PrototypeDescriptor::parsePrototypeDescriptor( PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back(); // Compute the vector type transformers, it can only appear one time. - if (PrototypeDescriptorStr.startswith("(")) { + if (PrototypeDescriptorStr.starts_with("(")) { assert(VTM == VectorTypeModifier::NoModifier && "VectorTypeModifier should only have one modifier"); size_t Idx = PrototypeDescriptorStr.find(')'); diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp index 52e57976ac09117422d21e999dcaa83bc1c188a0..356b4bd5a1b85cbef27c0cc3e8436cf19afd9e22 100644 --- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp +++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp @@ -371,7 +371,7 @@ SyntaxTree::Impl::getRelativeName(const NamedDecl *ND, // Strip the qualifier, if Val refers to something in the current scope. // But leave one leading ':' in place, so that we know that this is a // relative path. - if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix)) + if (!ContextPrefix.empty() && StringRef(Val).starts_with(ContextPrefix)) Val = Val.substr(ContextPrefix.size() + 1); return Val; } diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp index e40df625737841e67c2e06a855cf43c335626f09..df4c74205b0874d7ed5e40cb54f6e633974c1c79 100644 --- a/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -45,12 +45,12 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { StringRef Arg = Args[i]; // Skip output commands. if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) { - return Arg.startswith(OutputCommand); + return Arg.starts_with(OutputCommand); })) continue; - if (!Arg.startswith("-fcolor-diagnostics") && - !Arg.startswith("-fdiagnostics-color")) + if (!Arg.starts_with("-fcolor-diagnostics") && + !Arg.starts_with("-fdiagnostics-color")) AdjustedArgs.push_back(Args[i]); // If we strip a color option, make sure we strip any preceeding `-Xclang` // option as well. @@ -73,7 +73,7 @@ ArgumentsAdjuster getClangStripOutputAdjuster() { CommandLineArguments AdjustedArgs; for (size_t i = 0, e = Args.size(); i < e; ++i) { StringRef Arg = Args[i]; - if (!Arg.startswith("-o")) + if (!Arg.starts_with("-o")) AdjustedArgs.push_back(Args[i]); if (Arg == "-o") { @@ -102,11 +102,11 @@ ArgumentsAdjuster getClangStripDependencyFileAdjuster() { // When not using the cl driver mode, dependency file generation options // begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and // -MMD. - if (!UsingClDriver && Arg.startswith("-M")) + if (!UsingClDriver && Arg.starts_with("-M")) continue; // Under MSVC's cl driver mode, dependency file generation is controlled // using /showIncludes - if (Arg.startswith("/showIncludes") || Arg.startswith("-showIncludes")) + if (Arg.starts_with("/showIncludes") || Arg.starts_with("-showIncludes")) continue; AdjustedArgs.push_back(Args[i]); @@ -159,7 +159,7 @@ ArgumentsAdjuster getStripPluginsAdjuster() { // -Xclang if (I + 4 < E && Args[I] == "-Xclang" && (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" || - llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") || + llvm::StringRef(Args[I + 1]).starts_with("-plugin-arg-") || Args[I + 1] == "-add-plugin") && Args[I + 2] == "-Xclang") { I += 3; diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp index fdf6015508d94ba3686413a925797c65c30a2975..87ad8f25a1ab4ed0094e4e98352cd06e112d6806 100644 --- a/clang/lib/Tooling/CompilationDatabase.cpp +++ b/clang/lib/Tooling/CompilationDatabase.cpp @@ -204,7 +204,7 @@ public: // which don't support these options. struct FilterUnusedFlags { bool operator() (StringRef S) { - return (S == "-no-integrated-as") || S.startswith("-Wa,"); + return (S == "-no-integrated-as") || S.starts_with("-Wa,"); } }; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp index 3e53c8fc57408754544d6da182bfa3d3ae95e342..6f71650a3982c08448e2aaea676257e99a619314 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp @@ -290,7 +290,7 @@ DependencyScanningWorkerFilesystem::status(const Twine &Path) { SmallString<256> OwnedFilename; StringRef Filename = Path.toStringRef(OwnedFilename); - if (Filename.endswith(".pcm")) + if (Filename.ends_with(".pcm")) return getUnderlyingFS().status(Path); llvm::ErrorOr Result = getOrCreateFileSystemEntry(Filename); @@ -350,7 +350,7 @@ DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) { SmallString<256> OwnedFilename; StringRef Filename = Path.toStringRef(OwnedFilename); - if (Filename.endswith(".pcm")) + if (Filename.ends_with(".pcm")) return getUnderlyingFS().openFileForRead(Path); llvm::ErrorOr Result = getOrCreateFileSystemEntry(Filename); diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index f65da413bb87c35d46ceb76d5daf1d085d7d27d7..bfaa897851041db83e56818b357246df76b8441e 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -119,6 +119,8 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) { // units. CI.getFrontendOpts().Inputs.clear(); CI.getFrontendOpts().OutputFile.clear(); + // LLVM options are not going to affect the AST + CI.getFrontendOpts().LLVMArgs.clear(); // TODO: Figure out better way to set options to their default value. CI.getCodeGenOpts().MainFileName.clear(); @@ -530,7 +532,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { // this file in the proper directory and relies on the rest of Clang to // handle it like normal. With explicitly built modules we don't need // to play VFS tricks, so replace it with the correct module map. - if (StringRef(IFI.Filename).endswith("__inferred_module.map")) { + if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) { MDC.addFileDep(MD, ModuleMap->getName()); return; } @@ -548,7 +550,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { if (!(IFI.TopLevel && IFI.ModuleMap)) return; if (StringRef(IFI.FilenameAsRequested) - .endswith("__inferred_module.map")) + .ends_with("__inferred_module.map")) return; MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested); }); diff --git a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp index 0b3c4de08ab8593e8206c43ae4272d85335693f4..52b634e2e1af8a5a283e40e51b5d7bb7ba270d43 100644 --- a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp @@ -21,7 +21,7 @@ bool isIf(llvm::StringRef Line) { if (!Line.consume_front("#")) return false; Line = Line.ltrim(); - return Line.startswith("if"); + return Line.starts_with("if"); } // Is Line an #error directive mentioning includes? @@ -30,7 +30,7 @@ bool isErrorAboutInclude(llvm::StringRef Line) { if (!Line.consume_front("#")) return false; Line = Line.ltrim(); - if (!Line.startswith("error")) + if (!Line.starts_with("error")) return false; return Line.contains_insensitive( "includ"); // Matches "include" or "including". @@ -54,7 +54,7 @@ bool isImportLine(llvm::StringRef Line) { if (!Line.consume_front("#")) return false; Line = Line.ltrim(); - return Line.startswith("import"); + return Line.starts_with("import"); } llvm::StringRef getFileContents(FileEntryRef FE, const SourceManager &SM) { diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp index 15a2024c4788870d83cbae1a9e15d7d7ad381e1b..d275222ac6b5874bf2db91eb4f93244154b11274 100644 --- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -196,10 +196,10 @@ IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style, ? llvm::Regex::NoFlags : llvm::Regex::IgnoreCase); } - IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") || - FileName.endswith(".cpp") || FileName.endswith(".c++") || - FileName.endswith(".cxx") || FileName.endswith(".m") || - FileName.endswith(".mm"); + IsMainFile = FileName.ends_with(".c") || FileName.ends_with(".cc") || + FileName.ends_with(".cpp") || FileName.ends_with(".c++") || + FileName.ends_with(".cxx") || FileName.ends_with(".m") || + FileName.ends_with(".mm"); if (!Style.IncludeIsMainSourceRegex.empty()) { llvm::Regex MainFileRegex(Style.IncludeIsMainSourceRegex); IsMainFile |= MainFileRegex.match(FileName); @@ -234,7 +234,7 @@ int IncludeCategoryManager::getSortIncludePriority(StringRef IncludeName, return Ret; } bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const { - if (!IncludeName.startswith("\"")) + if (!IncludeName.starts_with("\"")) return false; IncludeName = @@ -357,8 +357,8 @@ HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled, if (It != ExistingIncludes.end()) { for (const auto &Inc : It->second) if (Inc.Directive == Directive && - ((IsAngled && StringRef(Inc.Name).startswith("<")) || - (!IsAngled && StringRef(Inc.Name).startswith("\"")))) + ((IsAngled && StringRef(Inc.Name).starts_with("<")) || + (!IsAngled && StringRef(Inc.Name).starts_with("\"")))) return std::nullopt; } std::string Quoted = @@ -400,8 +400,8 @@ tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName, if (Iter == ExistingIncludes.end()) return Result; for (const auto &Inc : Iter->second) { - if ((IsAngled && StringRef(Inc.Name).startswith("\"")) || - (!IsAngled && StringRef(Inc.Name).startswith("<"))) + if ((IsAngled && StringRef(Inc.Name).starts_with("\"")) || + (!IsAngled && StringRef(Inc.Name).starts_with("<"))) continue; llvm::Error Err = Result.add(tooling::Replacement( FileName, Inc.R.getOffset(), Inc.R.getLength(), "")); diff --git a/clang/lib/Tooling/Refactoring/AtomicChange.cpp b/clang/lib/Tooling/Refactoring/AtomicChange.cpp index 7237393f00e57e239e025d164fd317a3ee3f2a2b..3d5ae2fed014c441aeba7271c9f15967089d2009 100644 --- a/clang/lib/Tooling/Refactoring/AtomicChange.cpp +++ b/clang/lib/Tooling/Refactoring/AtomicChange.cpp @@ -150,7 +150,7 @@ createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code, for (const auto &Change : Changes) { for (llvm::StringRef Header : Change.getInsertedHeaders()) { std::string EscapedHeader = - Header.startswith("<") || Header.startswith("\"") + Header.starts_with("<") || Header.starts_with("\"") ? Header.str() : ("\"" + Header + "\"").str(); std::string ReplacementText = "#include " + EscapedHeader; diff --git a/clang/lib/Tooling/Refactoring/Lookup.cpp b/clang/lib/Tooling/Refactoring/Lookup.cpp index 9468d4d032a7945ba3d653240522408627459ce0..52799f16fab2a99b1dc28ad1fd57e602416f080e 100644 --- a/clang/lib/Tooling/Refactoring/Lookup.cpp +++ b/clang/lib/Tooling/Refactoring/Lookup.cpp @@ -98,7 +98,7 @@ static StringRef getBestNamespaceSubstr(const DeclContext *DeclA, // from NewName if it has an identical prefix. std::string NS = "::" + cast(DeclA)->getQualifiedNameAsString() + "::"; - if (NewName.startswith(NS)) + if (NewName.starts_with(NS)) return NewName.substr(NS.size()); // No match yet. Strip of a namespace from the end of the chain and try @@ -128,9 +128,9 @@ static std::string disambiguateSpellingInScope(StringRef Spelling, StringRef QName, const DeclContext &UseContext, SourceLocation UseLoc) { - assert(QName.startswith("::")); - assert(QName.endswith(Spelling)); - if (Spelling.startswith("::")) + assert(QName.starts_with("::")); + assert(QName.ends_with(Spelling)); + if (Spelling.starts_with("::")) return std::string(Spelling); auto UnspelledSpecifier = QName.drop_back(Spelling.size()); @@ -146,7 +146,7 @@ static std::string disambiguateSpellingInScope(StringRef Spelling, UseLoc = SM.getSpellingLoc(UseLoc); auto IsAmbiguousSpelling = [&](const llvm::StringRef CurSpelling) { - if (CurSpelling.startswith("::")) + if (CurSpelling.starts_with("::")) return false; // Lookup the first component of Spelling in all enclosing namespaces // and check if there is any existing symbols with the same name but in @@ -160,7 +160,7 @@ static std::string disambiguateSpellingInScope(StringRef Spelling, // ambiguous. For example, a reference in a header file should not be // affected by a potentially ambiguous name in some file that includes // the header. - if (!TrimmedQName.startswith(Res->getQualifiedNameAsString()) && + if (!TrimmedQName.starts_with(Res->getQualifiedNameAsString()) && SM.isBeforeInTranslationUnit( SM.getSpellingLoc(Res->getLocation()), UseLoc)) return true; @@ -187,7 +187,7 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, const DeclContext *UseContext, const NamedDecl *FromDecl, StringRef ReplacementString) { - assert(ReplacementString.startswith("::") && + assert(ReplacementString.starts_with("::") && "Expected fully-qualified name!"); // We can do a raw name replacement when we are not inside the namespace for diff --git a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index 9cdeeec0574b4d0749d38983c81a9c6613ccfa9a..c18f9290471fe4262db39a126b7bd8d9a8dc643f 100644 --- a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -562,8 +562,8 @@ createRenameAtomicChanges(llvm::ArrayRef USRs, ReplacedName = tooling::replaceNestedName( RenameInfo.Specifier, RenameInfo.Begin, RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl, - NewName.startswith("::") ? NewName.str() - : ("::" + NewName).str()); + NewName.starts_with("::") ? NewName.str() + : ("::" + NewName).str()); } else { // This fixes the case where type `T` is a parameter inside a function // type (e.g. `std::function`) and the DeclContext of `T` @@ -578,13 +578,13 @@ createRenameAtomicChanges(llvm::ArrayRef USRs, SM, TranslationUnitDecl->getASTContext().getLangOpts()); // Add the leading "::" back if the name written in the code contains // it. - if (ActualName.startswith("::") && !NewName.startswith("::")) { + if (ActualName.starts_with("::") && !NewName.starts_with("::")) { ReplacedName = "::" + NewName.str(); } } } // If the NewName contains leading "::", add it back. - if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) + if (NewName.starts_with("::") && NewName.substr(2) == ReplacedName) ReplacedName = NewName.str(); } Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index e292fa724d2bb712122e69042d8e09ee55d08edf..33bfa8d3d81f1e3da6f127259c305ac1f98e1312 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -255,7 +255,7 @@ llvm::Expected getAbsolutePath(llvm::vfs::FileSystem &FS, StringRef File) { StringRef RelativePath(File); // FIXME: Should '.\\' be accepted on Win32? - if (RelativePath.startswith("./")) { + if (RelativePath.starts_with("./")) { RelativePath = RelativePath.substr(strlen("./")); } @@ -294,9 +294,9 @@ void addTargetAndModeForProgramName(std::vector &CommandLine, for (auto Token = ++CommandLine.begin(); Token != CommandLine.end(); ++Token) { StringRef TokenRef(*Token); - ShouldAddTarget = ShouldAddTarget && !TokenRef.startswith(TargetOPT) && + ShouldAddTarget = ShouldAddTarget && !TokenRef.starts_with(TargetOPT) && !TokenRef.equals(TargetOPTLegacy); - ShouldAddMode = ShouldAddMode && !TokenRef.startswith(DriverModeOPT); + ShouldAddMode = ShouldAddMode && !TokenRef.starts_with(DriverModeOPT); } if (ShouldAddMode) { CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode); @@ -507,7 +507,7 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, void *MainAddr) { // Allow users to override the resource dir. for (StringRef Arg : Args) - if (Arg.startswith("-resource-dir")) + if (Arg.starts_with("-resource-dir")) return; // If there's no override in place add our resource dir. diff --git a/clang/lib/Tooling/Transformer/SourceCode.cpp b/clang/lib/Tooling/Transformer/SourceCode.cpp index 30009537b5923ced0ea42ff86d91492fae7799a9..6aae834b0db563ea336dfdfabf431c28b8e3ac94 100644 --- a/clang/lib/Tooling/Transformer/SourceCode.cpp +++ b/clang/lib/Tooling/Transformer/SourceCode.cpp @@ -425,7 +425,7 @@ CharSourceRange tooling::getAssociatedRange(const Decl &Decl, for (llvm::StringRef Prefix : {"[[", "__attribute__(("}) { // Handle whitespace between attribute prefix and attribute value. - if (BeforeAttrStripped.endswith(Prefix)) { + if (BeforeAttrStripped.ends_with(Prefix)) { // Move start to start position of prefix, which is // length(BeforeAttr) - length(BeforeAttrStripped) + length(Prefix) // positions to the left. diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66490e973988bb5409bf55f029e44a9b8823578a --- /dev/null +++ b/clang/test/AST/Interp/complex.cpp @@ -0,0 +1,126 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s +// RUN: %clang_cc1 -verify=ref %s + +// expected-no-diagnostics +// ref-no-diagnostics + +constexpr _Complex double z1 = {1.0, 2.0}; +static_assert(__real(z1) == 1.0, ""); +static_assert(__imag(z1) == 2.0, ""); + +constexpr double setter() { + _Complex float d = {1.0, 2.0}; + + __imag(d) = 4.0; + return __imag(d); +} +static_assert(setter() == 4, ""); + +constexpr _Complex double getter() { + return {1.0, 3.0}; +} +constexpr _Complex double D = getter(); +static_assert(__real(D) == 1.0, ""); +static_assert(__imag(D) == 3.0, ""); + + +constexpr _Complex int I1 = {1, 2}; +static_assert(__real(I1) == 1, ""); +static_assert(__imag(I1) == 2, ""); + + +constexpr _Complex double D1 = {}; +static_assert(__real(D1) == 0, ""); +static_assert(__imag(D1) == 0, ""); + +constexpr _Complex int I2 = {}; +static_assert(__real(I2) == 0, ""); +static_assert(__imag(I2) == 0, ""); + + +/// Standalone complex expressions. +static_assert(__real((_Complex float){1.0, 3.0}) == 1.0, ""); + + +#if 0 +/// FIXME: This should work in the new interpreter. +constexpr _Complex double D2 = {12}; +static_assert(__real(D2) == 12, ""); +static_assert(__imag(D2) == 12, ""); + +constexpr _Complex int I3 = {15}; +static_assert(__real(I3) == 15, ""); +static_assert(__imag(I3) == 15, ""); +#endif + +/// FIXME: This should work in the new interpreter as well. +// constexpr _Complex _BitInt(8) A = 0;// = {4}; + +namespace CastToBool { + constexpr _Complex int F = {0, 1}; + static_assert(F, ""); + constexpr _Complex int F2 = {1, 0}; + static_assert(F2, ""); + constexpr _Complex int F3 = {0, 0}; + static_assert(!F3, ""); + + constexpr _Complex unsigned char F4 = {0, 1}; + static_assert(F4, ""); + constexpr _Complex unsigned char F5 = {1, 0}; + static_assert(F5, ""); + constexpr _Complex unsigned char F6 = {0, 0}; + static_assert(!F6, ""); + + constexpr _Complex float F7 = {0, 1}; + static_assert(F7, ""); + constexpr _Complex float F8 = {1, 0}; + static_assert(F8, ""); + constexpr _Complex double F9 = {0, 0}; + static_assert(!F9, ""); +} + +namespace BinOps { +namespace Add { + constexpr _Complex float A = { 13.0, 2.0 }; + constexpr _Complex float B = { 2.0, 1.0 }; + constexpr _Complex float C = A + B; + static_assert(__real(C) == 15.0, ""); + static_assert(__imag(C) == 3.0, ""); + + constexpr _Complex float D = B + A; + static_assert(__real(D) == 15.0, ""); + static_assert(__imag(D) == 3.0, ""); + + constexpr _Complex unsigned int I1 = { 5, 10 }; + constexpr _Complex unsigned int I2 = { 40, 2 }; + constexpr _Complex unsigned int I3 = I1 + I2; + static_assert(__real(I3) == 45, ""); + static_assert(__imag(I3) == 12, ""); +} + +namespace Sub { + constexpr _Complex float A = { 13.0, 2.0 }; + constexpr _Complex float B = { 2.0, 1.0 }; + constexpr _Complex float C = A - B; + static_assert(__real(C) == 11.0, ""); + static_assert(__imag(C) == 1.0, ""); + + constexpr _Complex float D = B - A; + static_assert(__real(D) == -11.0, ""); + static_assert(__imag(D) == -1.0, ""); + + constexpr _Complex unsigned int I1 = { 5, 10 }; + constexpr _Complex unsigned int I2 = { 40, 2 }; + constexpr _Complex unsigned int I3 = I1 - I2; + static_assert(__real(I3) == -35, ""); + static_assert(__imag(I3) == 8, ""); + + using Bobble = _Complex float; + constexpr _Complex float A_ = { 13.0, 2.0 }; + constexpr Bobble B_ = { 2.0, 1.0 }; + constexpr _Complex float D_ = A_ - B_; + static_assert(__real(D_) == 11.0, ""); + static_assert(__imag(D_) == 1.0, ""); +} + +} diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index ab562e70606b6721c95d66cbdb9ad7f7afd27a47..179a195098b1327879b16d80791e876be90d3c43 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -267,6 +267,17 @@ namespace InvalidCall { // ref-error {{must be initialized by a constant expression}} \ // ref-note {{in call to 'SS()'}} + + /// This should not emit a diagnostic. + constexpr int f(); + constexpr int a() { + return f(); + } + constexpr int f() { + return 5; + } + static_assert(a() == 5, ""); + } namespace CallWithArgs { diff --git a/clang/test/Analysis/suppression-attr-doc.cpp b/clang/test/Analysis/suppression-attr-doc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1208842799ed9a1d635019b63518d6e354cf6221 --- /dev/null +++ b/clang/test/Analysis/suppression-attr-doc.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix \ +// RUN: -analyzer-disable-checker=core.uninitialized \ +// RUN: -verify %s + +// NOTE: These tests correspond to examples provided in documentation +// of [[clang::suppress]]. If you break them intentionally, it's likely that +// you need to update the documentation! + +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); + +int foo_initial() { + int *x = nullptr; + return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} +} + +int foo1() { + int *x = nullptr; + [[clang::suppress]] + return *x; // null pointer dereference warning suppressed here +} + +int foo2() { + [[clang::suppress]] { + int *x = nullptr; + return *x; // null pointer dereference warning suppressed here + } +} + +int bar_initial(bool coin_flip) { + int *result = (int *)malloc(sizeof(int)); + if (coin_flip) + return 1; // There's no warning here YET, but it will show up if the other one is suppressed. + + return *result; // expected-warning{{Potential leak of memory pointed to by 'result'}} +} + +int bar1(bool coin_flip) { + __attribute__((suppress)) + int *result = (int *)malloc(sizeof(int)); + if (coin_flip) + return 1; // warning about this leak path is suppressed + + return *result; // warning about this leak path also suppressed +} + +int bar2(bool coin_flip) { + int *result = (int *)malloc(sizeof(int)); + if (coin_flip) + return 1; // expected-warning{{Potential leak of memory pointed to by 'result'}} + + __attribute__((suppress)) + return *result; // leak warning is suppressed only on this path +} diff --git a/clang/test/Analysis/suppression-attr.m b/clang/test/Analysis/suppression-attr.m new file mode 100644 index 0000000000000000000000000000000000000000..8ba8dda722721b2b1257fc7302d5cb18795b5eb4 --- /dev/null +++ b/clang/test/Analysis/suppression-attr.m @@ -0,0 +1,271 @@ +// RUN: %clang_analyze_cc1 -fblocks \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=osx.cocoa.MissingSuperCall \ +// RUN: -analyzer-checker=osx.cocoa.NSError \ +// RUN: -analyzer-checker=osx.ObjCProperty \ +// RUN: -analyzer-checker=osx.cocoa.RetainCount \ +// RUN: -analyzer-checker=unix.Malloc \ +// RUN: -analyzer-checker=alpha.core.CastToStruct \ +// RUN: -Wno-unused-value -Wno-objc-root-class -verify %s + +#define SUPPRESS __attribute__((suppress)) +#define SUPPRESS_SPECIFIC(...) __attribute__((suppress(__VA_ARGS__))) + +@protocol NSObject +- (id)retain; +- (oneway void)release; +@end +@interface NSObject { +} +- (id)init; ++ (id)alloc; +@end +typedef int NSInteger; +typedef char BOOL; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@class NSDictionary; +@interface NSError : NSObject { +} ++ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict; +@end + +@interface NSMutableString : NSObject +@end + +typedef __typeof__(sizeof(int)) size_t; +void *malloc(size_t); +void free(void *); + +void dereference_1() { + int *x = 0; + *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} +} + +void dereference_suppression_1() { + int *x = 0; + SUPPRESS { *x; } // no-warning +} + +void dereference_2() { + int *x = 0; + if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + } +} + +void dereference_suppression_2() { + int *x = 0; + SUPPRESS if (*x) { // no-warning + } +} + +void dereference_suppression_2a() { + int *x = 0; + // FIXME: Implement suppressing individual checkers. + SUPPRESS_SPECIFIC("core.NullDereference") if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + } +} + +void dereference_suppression_2b() { + int *x = 0; + // This is not a MallocChecker issue so it shouldn't be suppressed. (Though the attribute + // doesn't really understand any of those arguments yet.) + SUPPRESS_SPECIFIC("unix.Malloc") if (*x) { // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + } +} + +void dereference_3(int cond) { + int *x = 0; + if (cond) { + (*x)++; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + } +} + +void dereference_suppression_3(int cond) { + int *x = 0; + SUPPRESS if (cond) { + (*x)++; // no-warning + } +} + +void dereference_4() { + int *x = 0; + int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} +} + +void dereference_suppression_4() { + int *x = 0; + SUPPRESS int y = *x; // no-warning +} + +void dereference_5() { + int *x = 0; + int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + int z = *x; // no-warning (duplicate) +} + +void dereference_suppression_5_1() { + int *x = 0; + SUPPRESS int y = *x; // no-warning + int z = *x; // no-warning (duplicate) +} + +void dereference_suppression_5_2() { + int *x = 0; + int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + SUPPRESS int z = *x; // no-warning +} + +void do_deref(int *y) { + *y = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'y')}} +} + +void dereference_interprocedural() { + int *x = 0; + do_deref(x); +} + +void do_deref_suppressed(int *y) { + SUPPRESS *y = 1; // no-warning +} + +void dereference_interprocedural_suppressed() { + int *x = 0; + do_deref_suppressed(x); +} + +int malloc_leak_1() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; + return *x; // expected-warning{{Potential leak of memory pointed to by 'x'}} +} + +int malloc_leak_suppression_1_1() { + SUPPRESS int *x = (int *)malloc(sizeof(int)); + *x = 42; + return *x; +} + +int malloc_leak_suppression_1_2() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; + SUPPRESS return *x; +} + +void malloc_leak_2() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; +} // expected-warning{{Potential leak of memory pointed to by 'x'}} + +void malloc_leak_suppression_2_1() { + SUPPRESS int *x = (int *)malloc(sizeof(int)); + *x = 42; +} + +// TODO: reassess when we decide what to do with declaration annotations +void malloc_leak_suppression_2_2() /* SUPPRESS */ { + int *x = (int *)malloc(sizeof(int)); + *x = 42; +} // expected-warning{{Potential leak of memory pointed to by 'x'}} + +// TODO: reassess when we decide what to do with declaration annotations +/* SUPPRESS */ void malloc_leak_suppression_2_3() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; +} // expected-warning{{Potential leak of memory pointed to by 'x'}} + +void malloc_leak_suppression_2_4(int cond) { + int *x = (int *)malloc(sizeof(int)); + *x = 42; + SUPPRESS; + // FIXME: The warning should be suppressed but dead symbol elimination + // happens too late. +} // expected-warning{{Potential leak of memory pointed to by 'x'}} + +void retain_release_leak_1() { + [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object of type 'NSMutableString *'}} +} + +void retain_release_leak_suppression_1() { + SUPPRESS { [[NSMutableString alloc] init]; } +} + +void retain_release_leak_2(int cond) { + id obj = [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object stored into 'obj'}} + if (cond) { + [obj release]; + } +} + +void retain_release_leak__suppression_2(int cond) { + SUPPRESS id obj = [[NSMutableString alloc] init]; + if (cond) { + [obj release]; + } +} + +@interface UIResponder : NSObject { +} +- (char)resignFirstResponder; +@end + +@interface Test : UIResponder { +} +@property(copy) NSMutableString *mutableStr; +// expected-warning@-1 {{Property of mutable type 'NSMutableString' has 'copy' attribute; an immutable object will be stored instead}} +@end +@implementation Test + +- (BOOL)resignFirstResponder { + return 0; +} // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'Test' is missing a [super resignFirstResponder] call}} + +- (void)methodWhichMayFail:(NSError **)error { + // expected-warning@-1 {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred}} +} +@end + +@interface TestSuppress : UIResponder { +} +// TODO: reassess when we decide what to do with declaration annotations +@property(copy) /* SUPPRESS */ NSMutableString *mutableStr; +// expected-warning@-1 {{Property of mutable type 'NSMutableString' has 'copy' attribute; an immutable object will be stored instead}} +@end +@implementation TestSuppress + +// TODO: reassess when we decide what to do with declaration annotations +- (BOOL)resignFirstResponder /* SUPPRESS */ { + return 0; +} // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'TestSuppress' is missing a [super resignFirstResponder] call}} + +// TODO: reassess when we decide what to do with declaration annotations +- (void)methodWhichMayFail:(NSError **)error /* SUPPRESS */ { + // expected-warning@-1 {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred}} +} +@end + +struct AB { + int A, B; +}; + +struct ABC { + int A, B, C; +}; + +void ast_checker_1() { + struct AB Ab; + struct ABC *Abc; + Abc = (struct ABC *)&Ab; // expected-warning {{Casting data to a larger structure type and accessing a field can lead to memory access errors or data corruption}} +} + +void ast_checker_suppress_1() { + struct AB Ab; + struct ABC *Abc; + SUPPRESS { Abc = (struct ABC *)&Ab; } +} diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp index 2d46502e1d9b352d3463d56fac513789432ed23b..2b33a4ef566dadff328bd65300d74ee6e1892d26 100644 --- a/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp @@ -2,11 +2,12 @@ // The example given in the standard (this is rejected for other reasons anyway). template struct A; -template using B = typename A::U; // expected-error {{no type named 'U' in 'A'}} +template using B = typename A::U; // expected-error {{no type named 'U' in 'A'}} + // expected-note@-1 {{in instantiation of template class 'A' requested here}} template struct A { typedef B U; // expected-note {{in instantiation of template type alias 'B' requested here}} }; -B b; +B b; // expected-note {{in instantiation of template type alias 'B' requested here}} template using U = int; diff --git a/clang/test/ClangScanDeps/strip-llvm-args.m b/clang/test/ClangScanDeps/strip-llvm-args.m new file mode 100644 index 0000000000000000000000000000000000000000..ca8eab7729232b16d08fdcc8b3631155943bd638 --- /dev/null +++ b/clang/test/ClangScanDeps/strip-llvm-args.m @@ -0,0 +1,46 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|DIR|%/t|g" %t/cdb1.json.template > %t/cdb1.json + +// RUN: clang-scan-deps -compilation-database %t/cdb1.json -format experimental-full > %t/result1.txt +// RUN: FileCheck %s -input-file %t/result1.txt + +// CHECK: "modules": [ +// CHECK-NEXT: { +// CHECK: "command-line": [ +// CHECK-NOT: "-mllvm" +// CHECK: ] +// CHECK: "name": "A" +// CHECK: } +// CHECK-NOT: "name": "A" +// CHECK: "translation-units" + +//--- cdb1.json.template +[ + { + "directory": "DIR", + "command": "clang -Imodules/A -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fimplicit-module-maps -fsyntax-only DIR/t1.m", + "file": "DIR/t1.m" + }, + { + "directory": "DIR", + "command": "clang -Imodules/A -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fimplicit-module-maps -mllvm -stackmap-version=2 -fsyntax-only DIR/t2.m", + "file": "DIR/t2.m" + } +] + +//--- modules/A/module.modulemap + +module A { + umbrella header "A.h" +} + +//--- modules/A/A.h + +typedef int A_t; + +//--- t1.m +@import A; + +//--- t2.m +@import A; diff --git a/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_sqdmulh.c b/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_sqdmulh.c new file mode 100644 index 0000000000000000000000000000000000000000..6bbd23ccd32a521b36f5a86cde6a0af61baa1024 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_sqdmulh.c @@ -0,0 +1,584 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: aarch64-registered-target + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED,A5) A1##A3##A5 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4,A5) A1##A2##A3##A4##A5 +#endif + +// Single, x2 + +// CHECK-LABEL: @test_svqdmulh_single_s8_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN]], i64 16) +// CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv16i8( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP3]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: ret [[TMP6]] +// +// CPP-CHECK-LABEL: @_Z26test_svqdmulh_single_s8_x210svint8x2_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN]], i64 16) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv16i8( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP3]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: ret [[TMP6]] +// +svint8x2_t test_svqdmulh_single_s8_x2(svint8x2_t zdn, svint8_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s8_x2,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_single_s16_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN]], i64 8) +// CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv8i16( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP3]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: ret [[TMP6]] +// +// CPP-CHECK-LABEL: @_Z27test_svqdmulh_single_s16_x211svint16x2_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN]], i64 8) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv8i16( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP3]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP6]] +// +svint16x2_t test_svqdmulh_single_s16_x2(svint16x2_t zdn, svint16_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s16_x2,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_single_s32_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv4i32( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP3]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: ret [[TMP6]] +// +// CPP-CHECK-LABEL: @_Z27test_svqdmulh_single_s32_x211svint32x2_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv4i32( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP3]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP6]] +// +svint32x2_t test_svqdmulh_single_s32_x2(svint32x2_t zdn, svint32_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s32_x2,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_single_s64_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN]], i64 2) +// CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv2i64( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP3]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP4]], [[TMP5]], i64 2) +// CHECK-NEXT: ret [[TMP6]] +// +// CPP-CHECK-LABEL: @_Z27test_svqdmulh_single_s64_x211svint64x2_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN]], i64 2) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.single.vgx2.nxv2i64( [[TMP0]], [[TMP1]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP2]], 0 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP3]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP2]], 1 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP4]], [[TMP5]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP6]] +// +svint64x2_t test_svqdmulh_single_s64_x2(svint64x2_t zdn, svint64_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s64_x2,,,)(zdn, zm); +} + +// Single, x4 + +// CHECK-LABEL: @test_svqdmulh_single_s8_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 16) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 32) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 48) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv16i8( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 16) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP8]], [[TMP9]], i64 32) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP10]], [[TMP11]], i64 48) +// CHECK-NEXT: ret [[TMP12]] +// +// CPP-CHECK-LABEL: @_Z26test_svqdmulh_single_s8_x410svint8x4_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 16) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 32) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 48) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv16i8( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 16) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP8]], [[TMP9]], i64 32) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP10]], [[TMP11]], i64 48) +// CPP-CHECK-NEXT: ret [[TMP12]] +// +svint8x4_t test_svqdmulh_single_s8_x4(svint8x4_t zdn, svint8_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s8_x4,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_single_s16_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 8) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 16) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 24) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv8i16( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 8) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP8]], [[TMP9]], i64 16) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP10]], [[TMP11]], i64 24) +// CHECK-NEXT: ret [[TMP12]] +// +// CPP-CHECK-LABEL: @_Z27test_svqdmulh_single_s16_x411svint16x4_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 8) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 16) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 24) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv8i16( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 8) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP8]], [[TMP9]], i64 16) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP10]], [[TMP11]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP12]] +// +svint16x4_t test_svqdmulh_single_s16_x4(svint16x4_t zdn, svint16_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s16_x4,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_single_s32_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 8) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 12) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv4i32( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 4) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP8]], [[TMP9]], i64 8) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP10]], [[TMP11]], i64 12) +// CHECK-NEXT: ret [[TMP12]] +// +// CPP-CHECK-LABEL: @_Z27test_svqdmulh_single_s32_x411svint32x4_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 8) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 12) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv4i32( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 4) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP8]], [[TMP9]], i64 8) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP10]], [[TMP11]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP12]] +// +svint32x4_t test_svqdmulh_single_s32_x4(svint32x4_t zdn, svint32_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s32_x4,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_single_s64_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 2) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 4) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 6) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv2i64( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 2) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP8]], [[TMP9]], i64 4) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP10]], [[TMP11]], i64 6) +// CHECK-NEXT: ret [[TMP12]] +// +// CPP-CHECK-LABEL: @_Z27test_svqdmulh_single_s64_x411svint64x4_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 2) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 4) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 6) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.single.vgx4.nxv2i64( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[ZM:%.*]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 2) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP4]], 2 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP8]], [[TMP9]], i64 4) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP4]], 3 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP10]], [[TMP11]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP12]] +// +svint64x4_t test_svqdmulh_single_s64_x4(svint64x4_t zdn, svint64_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_single_s64_x4,,,)(zdn, zm); +} + +// Multi, x2 + +// CHECK-LABEL: @test_svqdmulh_s8_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN]], i64 16) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZM]], i64 16) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv16i8( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP6]], [[TMP7]], i64 16) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: @_Z19test_svqdmulh_s8_x210svint8x2_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZDN]], i64 16) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv32i8( [[ZM]], i64 16) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv16i8( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP6]], [[TMP7]], i64 16) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint8x2_t test_svqdmulh_s8_x2(svint8x2_t zdn, svint8x2_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s8_x2,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_s16_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN]], i64 8) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZM]], i64 8) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv8i16( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP6]], [[TMP7]], i64 8) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: @_Z20test_svqdmulh_s16_x211svint16x2_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZDN]], i64 8) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv16i16( [[ZM]], i64 8) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv8i16( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP6]], [[TMP7]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint16x2_t test_svqdmulh_s16_x2(svint16x2_t zdn, svint16x2_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s16_x2,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_s32_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZM]], i64 4) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv4i32( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP6]], [[TMP7]], i64 4) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: @_Z20test_svqdmulh_s32_x211svint32x2_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZDN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZM]], i64 4) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv4i32( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP6]], [[TMP7]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint32x2_t test_svqdmulh_s32_x2(svint32x2_t zdn, svint32x2_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s32_x2,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_s64_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN]], i64 2) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZM]], i64 2) +// CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv2i64( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP5]], i64 0) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP6]], [[TMP7]], i64 2) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: @_Z20test_svqdmulh_s64_x211svint64x2_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZDN]], i64 2) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv4i64( [[ZM]], i64 2) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call { , } @llvm.aarch64.sve.sqdmulh.vgx2.nxv2i64( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]]) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , } [[TMP4]], 0 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP5]], i64 0) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , } [[TMP4]], 1 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP6]], [[TMP7]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint64x2_t test_svqdmulh_s64_x2(svint64x2_t zdn, svint64x2_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s64_x2,,,)(zdn, zm); +} + +// Multi, x4 + +// CHECK-LABEL: @test_svqdmulh_s8_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 16) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 32) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 48) +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM]], i64 16) +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM]], i64 32) +// CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM]], i64 48) +// CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv16i8( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP9]], i64 0) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP10]], [[TMP11]], i64 16) +// CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP12]], [[TMP13]], i64 32) +// CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP14]], [[TMP15]], i64 48) +// CHECK-NEXT: ret [[TMP16]] +// +// CPP-CHECK-LABEL: @_Z19test_svqdmulh_s8_x410svint8x4_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 16) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 32) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZDN]], i64 48) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM]], i64 16) +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM]], i64 32) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv16i8.nxv64i8( [[ZM]], i64 48) +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv16i8( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP9]], i64 0) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP10]], [[TMP11]], i64 16) +// CPP-CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CPP-CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP12]], [[TMP13]], i64 32) +// CPP-CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CPP-CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP14]], [[TMP15]], i64 48) +// CPP-CHECK-NEXT: ret [[TMP16]] +// +svint8x4_t test_svqdmulh_s8_x4(svint8x4_t zdn, svint8x4_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s8_x4,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_s16_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 8) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 16) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 24) +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM]], i64 8) +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM]], i64 24) +// CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv8i16( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP9]], i64 0) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP10]], [[TMP11]], i64 8) +// CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP12]], [[TMP13]], i64 16) +// CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP14]], [[TMP15]], i64 24) +// CHECK-NEXT: ret [[TMP16]] +// +// CPP-CHECK-LABEL: @_Z20test_svqdmulh_s16_x411svint16x4_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 8) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 16) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZDN]], i64 24) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM]], i64 8) +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv8i16.nxv32i16( [[ZM]], i64 24) +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv8i16( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP9]], i64 0) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP10]], [[TMP11]], i64 8) +// CPP-CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CPP-CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP12]], [[TMP13]], i64 16) +// CPP-CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CPP-CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP14]], [[TMP15]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP16]] +// +svint16x4_t test_svqdmulh_s16_x4(svint16x4_t zdn, svint16x4_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s16_x4,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_s32_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 8) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 12) +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM]], i64 4) +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM]], i64 12) +// CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv4i32( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP9]], i64 0) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP10]], [[TMP11]], i64 4) +// CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP12]], [[TMP13]], i64 8) +// CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP14]], [[TMP15]], i64 12) +// CHECK-NEXT: ret [[TMP16]] +// +// CPP-CHECK-LABEL: @_Z20test_svqdmulh_s32_x411svint32x4_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 8) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZDN]], i64 12) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM]], i64 4) +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv16i32( [[ZM]], i64 12) +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv4i32( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP9]], i64 0) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP10]], [[TMP11]], i64 4) +// CPP-CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CPP-CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP12]], [[TMP13]], i64 8) +// CPP-CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CPP-CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP14]], [[TMP15]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP16]] +// +svint32x4_t test_svqdmulh_s32_x4(svint32x4_t zdn, svint32x4_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s32_x4,,,)(zdn, zm); +} + +// CHECK-LABEL: @test_svqdmulh_s64_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 2) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 4) +// CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 6) +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM:%.*]], i64 0) +// CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM]], i64 2) +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM]], i64 6) +// CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv2i64( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP9]], i64 0) +// CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP10]], [[TMP11]], i64 2) +// CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP12]], [[TMP13]], i64 4) +// CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP14]], [[TMP15]], i64 6) +// CHECK-NEXT: ret [[TMP16]] +// +// CPP-CHECK-LABEL: @_Z20test_svqdmulh_s64_x411svint64x4_tS_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 2) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 4) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZDN]], i64 6) +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM]], i64 2) +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = tail call @llvm.vector.extract.nxv2i64.nxv8i64( [[ZM]], i64 6) +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call { , , , } @llvm.aarch64.sve.sqdmulh.vgx4.nxv2i64( [[TMP0]], [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]]) +// CPP-CHECK-NEXT: [[TMP9:%.*]] = extractvalue { , , , } [[TMP8]], 0 +// CPP-CHECK-NEXT: [[TMP10:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP9]], i64 0) +// CPP-CHECK-NEXT: [[TMP11:%.*]] = extractvalue { , , , } [[TMP8]], 1 +// CPP-CHECK-NEXT: [[TMP12:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP10]], [[TMP11]], i64 2) +// CPP-CHECK-NEXT: [[TMP13:%.*]] = extractvalue { , , , } [[TMP8]], 2 +// CPP-CHECK-NEXT: [[TMP14:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP12]], [[TMP13]], i64 4) +// CPP-CHECK-NEXT: [[TMP15:%.*]] = extractvalue { , , , } [[TMP8]], 3 +// CPP-CHECK-NEXT: [[TMP16:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP14]], [[TMP15]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP16]] +// +svint64x4_t test_svqdmulh_s64_x4(svint64x4_t zdn, svint64x4_t zm) __arm_streaming { + return SVE_ACLE_FUNC(svqdmulh,_s64_x4,,,)(zdn, zm); +} diff --git a/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_fp_reduce.c b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_fp_reduce.c new file mode 100644 index 0000000000000000000000000000000000000000..e58cf4e49a37f92c8ca2db3d19db54beb5349430 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_fp_reduce.c @@ -0,0 +1,285 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +#include +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +// FADDQV + +// CHECK-LABEL: @test_svaddqv_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.addqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <8 x half> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_f16u10__SVBool_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.addqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <8 x half> [[TMP1]] +// +float16x8_t test_svaddqv_f16(svbool_t pg, svfloat16_t op) +{ + return SVE_ACLE_FUNC(svaddqv,,_f16,)(pg, op); +} + +// CHECK-LABEL: @test_svaddqv_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.addqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <4 x float> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_f32u10__SVBool_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.addqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <4 x float> [[TMP1]] +// +float32x4_t test_svaddqv_f32(svbool_t pg, svfloat32_t op) +{ + return SVE_ACLE_FUNC(svaddqv,,_f32,)(pg, op); +} + +// CHECK-LABEL: @test_svaddqv_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.addqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <2 x double> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_f64u10__SVBool_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.addqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <2 x double> [[TMP1]] +// +float64x2_t test_svaddqv_f64(svbool_t pg, svfloat64_t op) +{ + return SVE_ACLE_FUNC(svaddqv,,_f64,)(pg, op); +} + + +// FMAXQV + +// CHECK-LABEL: @test_svmaxqv_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fmaxqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <8 x half> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_f16u10__SVBool_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fmaxqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <8 x half> [[TMP1]] +// +float16x8_t test_svmaxqv_f16(svbool_t pg, svfloat16_t op) +{ + return SVE_ACLE_FUNC(svmaxqv,,_f16,)(pg, op); +} + +// CHECK-LABEL: @test_svmaxqv_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fmaxqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <4 x float> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_f32u10__SVBool_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fmaxqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <4 x float> [[TMP1]] +// +float32x4_t test_svmaxqv_f32(svbool_t pg, svfloat32_t op) +{ + return SVE_ACLE_FUNC(svmaxqv,,_f32,)(pg, op); +} + +// CHECK-LABEL: @test_svmaxqv_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fmaxqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <2 x double> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_f64u10__SVBool_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fmaxqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <2 x double> [[TMP1]] +// +float64x2_t test_svmaxqv_f64(svbool_t pg, svfloat64_t op) +{ + return SVE_ACLE_FUNC(svmaxqv,,_f64,)(pg, op); +} + + +// FMINQV + +// CHECK-LABEL: @test_svminqv_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fminqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <8 x half> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_f16u10__SVBool_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fminqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <8 x half> [[TMP1]] +// +float16x8_t test_svminqv_f16(svbool_t pg, svfloat16_t op) +{ + return SVE_ACLE_FUNC(svminqv,,_f16,)(pg, op); +} + +// CHECK-LABEL: @test_svminqv_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fminqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <4 x float> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_f32u10__SVBool_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fminqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <4 x float> [[TMP1]] +// +float32x4_t test_svminqv_f32(svbool_t pg, svfloat32_t op) +{ + return SVE_ACLE_FUNC(svminqv,,_f32,)(pg, op); +} + +// CHECK-LABEL: @test_svminqv_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fminqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <2 x double> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_f64u10__SVBool_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fminqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <2 x double> [[TMP1]] +// +float64x2_t test_svminqv_f64(svbool_t pg, svfloat64_t op) +{ + return SVE_ACLE_FUNC(svminqv,,_f64,)(pg, op); +} + + +// FMAXNMQV + +// CHECK-LABEL: @test_svmaxnmqv_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fmaxnmqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <8 x half> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z18test_svmaxnmqv_f16u10__SVBool_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fmaxnmqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <8 x half> [[TMP1]] +// +float16x8_t test_svmaxnmqv_f16(svbool_t pg, svfloat16_t op) +{ + return SVE_ACLE_FUNC(svmaxnmqv,,_f16,)(pg, op); +} + +// CHECK-LABEL: @test_svmaxnmqv_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fmaxnmqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <4 x float> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z18test_svmaxnmqv_f32u10__SVBool_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fmaxnmqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <4 x float> [[TMP1]] +// +float32x4_t test_svmaxnmqv_f32(svbool_t pg, svfloat32_t op) +{ + return SVE_ACLE_FUNC(svmaxnmqv,,_f32,)(pg, op); +} + +// CHECK-LABEL: @test_svmaxnmqv_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fmaxnmqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <2 x double> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z18test_svmaxnmqv_f64u10__SVBool_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fmaxnmqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <2 x double> [[TMP1]] +// +float64x2_t test_svmaxnmqv_f64(svbool_t pg, svfloat64_t op) +{ + return SVE_ACLE_FUNC(svmaxnmqv,,_f64,)(pg, op); +} + + +// FMINNMQV + +// CHECK-LABEL: @test_svminnmqv_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fminnmqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <8 x half> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z18test_svminnmqv_f16u10__SVBool_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x half> @llvm.aarch64.sve.fminnmqv.v8f16.nxv8f16( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <8 x half> [[TMP1]] +// +float16x8_t test_svminnmqv_f16(svbool_t pg, svfloat16_t op) +{ + return SVE_ACLE_FUNC(svminnmqv,,_f16,)(pg, op); +} + +// CHECK-LABEL: @test_svminnmqv_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fminnmqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <4 x float> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z18test_svminnmqv_f32u10__SVBool_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x float> @llvm.aarch64.sve.fminnmqv.v4f32.nxv4f32( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <4 x float> [[TMP1]] +// +float32x4_t test_svminnmqv_f32(svbool_t pg, svfloat32_t op) +{ + return SVE_ACLE_FUNC(svminnmqv,,_f32,)(pg, op); +} + +// CHECK-LABEL: @test_svminnmqv_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fminnmqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CHECK-NEXT: ret <2 x double> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z18test_svminnmqv_f64u10__SVBool_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x double> @llvm.aarch64.sve.fminnmqv.v2f64.nxv2f64( [[TMP0]], [[OP:%.*]]) +// CPP-CHECK-NEXT: ret <2 x double> [[TMP1]] +// +float64x2_t test_svminnmqv_f64(svbool_t pg, svfloat64_t op) +{ + return SVE_ACLE_FUNC(svminnmqv,,_f64,)(pg, op); +} diff --git a/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_int_reduce.c b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_int_reduce.c new file mode 100644 index 0000000000000000000000000000000000000000..b395b4d1323ed5ebf685cf62b1c8c38b273e1b32 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_int_reduce.c @@ -0,0 +1,783 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + + +// ADDQV + +// CHECK-LABEL: @test_svaddqv_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.addqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svaddqv_s8u10__SVBool_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.addqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_svaddqv_s8(svbool_t pg, svint8_t op1) { + return SVE_ACLE_FUNC(svaddqv,_s8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.addqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_s16u10__SVBool_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.addqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +int16x8_t test_svaddqv_s16(svbool_t pg, svint16_t op1) { + return SVE_ACLE_FUNC(svaddqv,_s16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.addqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_s32u10__SVBool_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.addqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +int32x4_t test_svaddqv_s32(svbool_t pg, svint32_t op1) { + return SVE_ACLE_FUNC(svaddqv,_s32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.addqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_s64u10__SVBool_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.addqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +int64x2_t test_svaddqv_s64(svbool_t pg, svint64_t op1) { + return SVE_ACLE_FUNC(svaddqv,_s64,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.addqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svaddqv_u8u10__SVBool_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.addqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_svaddqv_u8(svbool_t pg, svuint8_t op1) { + return SVE_ACLE_FUNC(svaddqv,_u8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.addqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_u16u10__SVBool_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.addqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +uint16x8_t test_svaddqv_u16(svbool_t pg, svuint16_t op1) { + return SVE_ACLE_FUNC(svaddqv,_u16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.addqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_u32u10__SVBool_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.addqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +uint32x4_t test_svaddqv_u32(svbool_t pg, svuint32_t op1) { + return SVE_ACLE_FUNC(svaddqv,_u32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svaddqv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.addqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svaddqv_u64u10__SVBool_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.addqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +uint64x2_t test_svaddqv_u64(svbool_t pg, svuint64_t op1) { + return SVE_ACLE_FUNC(svaddqv,_u64,,)(pg, op1); +} + + +// ANDQV + +// CHECK-LABEL: @test_svandqv_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.andqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svandqv_s8u10__SVBool_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.andqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_svandqv_s8(svbool_t pg, svint8_t op1) { + return SVE_ACLE_FUNC(svandqv,_s8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.andqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svandqv_s16u10__SVBool_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.andqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +int16x8_t test_svandqv_s16(svbool_t pg, svint16_t op1) { + return SVE_ACLE_FUNC(svandqv,_s16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.andqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svandqv_s32u10__SVBool_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.andqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +int32x4_t test_svandqv_s32(svbool_t pg, svint32_t op1) { + return SVE_ACLE_FUNC(svandqv,_s32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.andqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svandqv_s64u10__SVBool_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.andqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +int64x2_t test_svandqv_s64(svbool_t pg, svint64_t op1) { + return SVE_ACLE_FUNC(svandqv,_s64,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.andqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svandqv_u8u10__SVBool_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.andqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_svandqv_u8(svbool_t pg, svuint8_t op1) { + return SVE_ACLE_FUNC(svandqv,_u8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.andqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svandqv_u16u10__SVBool_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.andqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +uint16x8_t test_svandqv_u16(svbool_t pg, svuint16_t op1) { + return SVE_ACLE_FUNC(svandqv,_u16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.andqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svandqv_u32u10__SVBool_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.andqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +uint32x4_t test_svandqv_u32(svbool_t pg, svuint32_t op1) { + return SVE_ACLE_FUNC(svandqv,_u32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svandqv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.andqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svandqv_u64u10__SVBool_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.andqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +uint64x2_t test_svandqv_u64(svbool_t pg, svuint64_t op1) { + return SVE_ACLE_FUNC(svandqv,_u64,,)(pg, op1); +} + + +// EORQV + +// CHECK-LABEL: @test_sveorqv_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.eorqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_sveorqv_s8u10__SVBool_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.eorqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_sveorqv_s8(svbool_t pg, svint8_t op1) { + return SVE_ACLE_FUNC(sveorqv,_s8,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.eorqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_sveorqv_s16u10__SVBool_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.eorqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +int16x8_t test_sveorqv_s16(svbool_t pg, svint16_t op1) { + return SVE_ACLE_FUNC(sveorqv,_s16,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.eorqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_sveorqv_s32u10__SVBool_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.eorqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +int32x4_t test_sveorqv_s32(svbool_t pg, svint32_t op1) { + return SVE_ACLE_FUNC(sveorqv,_s32,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.eorqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_sveorqv_s64u10__SVBool_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.eorqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +int64x2_t test_sveorqv_s64(svbool_t pg, svint64_t op1) { + return SVE_ACLE_FUNC(sveorqv,_s64,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.eorqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_sveorqv_u8u10__SVBool_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.eorqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_sveorqv_u8(svbool_t pg, svuint8_t op1) { + return SVE_ACLE_FUNC(sveorqv,_u8,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.eorqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_sveorqv_u16u10__SVBool_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.eorqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +uint16x8_t test_sveorqv_u16(svbool_t pg, svuint16_t op1) { + return SVE_ACLE_FUNC(sveorqv,_u16,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.eorqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_sveorqv_u32u10__SVBool_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.eorqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +uint32x4_t test_sveorqv_u32(svbool_t pg, svuint32_t op1) { + return SVE_ACLE_FUNC(sveorqv,_u32,,)(pg, op1); +} + +// CHECK-LABEL: @test_sveorqv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.eorqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_sveorqv_u64u10__SVBool_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.eorqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +uint64x2_t test_sveorqv_u64(svbool_t pg, svuint64_t op1) { + return SVE_ACLE_FUNC(sveorqv,_u64,,)(pg, op1); +} + + +// ORQV + +// CHECK-LABEL: @test_svorqv_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.orqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z14test_svorqv_s8u10__SVBool_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.orqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_svorqv_s8(svbool_t pg, svint8_t op1) { + return SVE_ACLE_FUNC(svorqv,_s8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.orqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z15test_svorqv_s16u10__SVBool_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.orqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +int16x8_t test_svorqv_s16(svbool_t pg, svint16_t op1) { + return SVE_ACLE_FUNC(svorqv,_s16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.orqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z15test_svorqv_s32u10__SVBool_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.orqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +int32x4_t test_svorqv_s32(svbool_t pg, svint32_t op1) { + return SVE_ACLE_FUNC(svorqv,_s32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.orqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z15test_svorqv_s64u10__SVBool_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.orqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +int64x2_t test_svorqv_s64(svbool_t pg, svint64_t op1) { + return SVE_ACLE_FUNC(svorqv,_s64,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.orqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z14test_svorqv_u8u10__SVBool_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.orqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_svorqv_u8(svbool_t pg, svuint8_t op1) { + return SVE_ACLE_FUNC(svorqv,_u8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.orqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z15test_svorqv_u16u10__SVBool_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.orqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +uint16x8_t test_svorqv_u16(svbool_t pg, svuint16_t op1) { + return SVE_ACLE_FUNC(svorqv,_u16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.orqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z15test_svorqv_u32u10__SVBool_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.orqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +uint32x4_t test_svorqv_u32(svbool_t pg, svuint32_t op1) { + return SVE_ACLE_FUNC(svorqv,_u32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svorqv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.orqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z15test_svorqv_u64u10__SVBool_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.orqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +uint64x2_t test_svorqv_u64(svbool_t pg, svuint64_t op1) { + return SVE_ACLE_FUNC(svorqv,_u64,,)(pg, op1); +} + + +// SMAXQV + +// CHECK-LABEL: @test_svmaxqv_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.smaxqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svmaxqv_s8u10__SVBool_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.smaxqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_svmaxqv_s8(svbool_t pg, svint8_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_s8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svmaxqv_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.smaxqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_s16u10__SVBool_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.smaxqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +int16x8_t test_svmaxqv_s16(svbool_t pg, svint16_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_s16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svmaxqv_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.smaxqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_s32u10__SVBool_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.smaxqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +int32x4_t test_svmaxqv_s32(svbool_t pg, svint32_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_s32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svmaxqv_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.smaxqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_s64u10__SVBool_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.smaxqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +int64x2_t test_svmaxqv_s64(svbool_t pg, svint64_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_s64,,)(pg, op1); +} + + +// UMAXQV + +// CHECK-LABEL: @test_svmaxqv_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.umaxqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svmaxqv_u8u10__SVBool_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.umaxqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_svmaxqv_u8(svbool_t pg, svuint8_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_u8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svmaxqv_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.umaxqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_u16u10__SVBool_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.umaxqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +uint16x8_t test_svmaxqv_u16(svbool_t pg, svuint16_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_u16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svmaxqv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.umaxqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_u32u10__SVBool_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.umaxqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +uint32x4_t test_svmaxqv_u32(svbool_t pg, svuint32_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_u32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svmaxqv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.umaxqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svmaxqv_u64u10__SVBool_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.umaxqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +uint64x2_t test_svmaxqv_u64(svbool_t pg, svuint64_t op1) { + return SVE_ACLE_FUNC(svmaxqv,_u64,,)(pg, op1); +} + + +// SMINQV + +// CHECK-LABEL: @test_svminqv_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.sminqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svminqv_s8u10__SVBool_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.sminqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +int8x16_t test_svminqv_s8(svbool_t pg, svint8_t op1) { + return SVE_ACLE_FUNC(svminqv,_s8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svminqv_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.sminqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_s16u10__SVBool_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.sminqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +int16x8_t test_svminqv_s16(svbool_t pg, svint16_t op1) { + return SVE_ACLE_FUNC(svminqv,_s16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svminqv_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.sminqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_s32u10__SVBool_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.sminqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +int32x4_t test_svminqv_s32(svbool_t pg, svint32_t op1) { + return SVE_ACLE_FUNC(svminqv,_s32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svminqv_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.sminqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_s64u10__SVBool_tu11__SVInt64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.sminqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +int64x2_t test_svminqv_s64(svbool_t pg, svint64_t op1) { + return SVE_ACLE_FUNC(svminqv,_s64,,)(pg, op1); +} + + +// UMINQV + +// CHECK-LABEL: @test_svminqv_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.uminqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_svminqv_u8u10__SVBool_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call <16 x i8> @llvm.aarch64.sve.uminqv.v16i8.nxv16i8( [[PG:%.*]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <16 x i8> [[TMP0]] +// +uint8x16_t test_svminqv_u8(svbool_t pg, svuint8_t op1) { + return SVE_ACLE_FUNC(svminqv,_u8,,)(pg, op1); +} + +// CHECK-LABEL: @test_svminqv_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.uminqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_u16u10__SVBool_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <8 x i16> @llvm.aarch64.sve.uminqv.v8i16.nxv8i16( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <8 x i16> [[TMP1]] +// +uint16x8_t test_svminqv_u16(svbool_t pg, svuint16_t op1) { + return SVE_ACLE_FUNC(svminqv,_u16,,)(pg, op1); +} + +// CHECK-LABEL: @test_svminqv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.uminqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_u32u10__SVBool_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <4 x i32> @llvm.aarch64.sve.uminqv.v4i32.nxv4i32( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <4 x i32> [[TMP1]] +// +uint32x4_t test_svminqv_u32(svbool_t pg, svuint32_t op1) { + return SVE_ACLE_FUNC(svminqv,_u32,,)(pg, op1); +} + +// CHECK-LABEL: @test_svminqv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.uminqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +// CPP-CHECK-LABEL: @_Z16test_svminqv_u64u10__SVBool_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i64> @llvm.aarch64.sve.uminqv.v2i64.nxv2i64( [[TMP0]], [[OP1:%.*]]) +// CPP-CHECK-NEXT: ret <2 x i64> [[TMP1]] +// +uint64x2_t test_svminqv_u64(svbool_t pg, svuint64_t op1) { + return SVE_ACLE_FUNC(svminqv,_u64,,)(pg, op1); +} diff --git a/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_qrshr.c b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_qrshr.c new file mode 100644 index 0000000000000000000000000000000000000000..6ebf224db92377cb7c398ece8b54c04876d167fe --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2p1-intrinsics/acle_sve2p1_qrshr.c @@ -0,0 +1,79 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme2 -S -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme2 -target-feature +sme-f64f64 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED,A5) A1##A3##A5 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4,A5) A1##A2##A3##A4##A5 +#endif + + +// SQRSHRN x 2 + +// CHECK-LABEL: @test_svqrshrn_s16_s32_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.sqrshrn.x2.nxv4i32( [[TMP0]], [[TMP1]], i32 16) +// CHECK-NEXT: ret [[TMP2]] +// +// CPP-CHECK-LABEL: @_Z24test_svqrshrn_s16_s32_x211svint32x2_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.sqrshrn.x2.nxv4i32( [[TMP0]], [[TMP1]], i32 16) +// CPP-CHECK-NEXT: ret [[TMP2]] +// +svint16_t test_svqrshrn_s16_s32_x2(svint32x2_t zn) __arm_streaming_compatible { + return SVE_ACLE_FUNC(svqrshrn,_n,_s16,_s32_x2,)(zn, 16); +} + +// UQRSHRN x 2 + +// CHECK-LABEL: @test_svqrshrn_u16_u32_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.uqrshrn.x2.nxv4i32( [[TMP0]], [[TMP1]], i32 16) +// CHECK-NEXT: ret [[TMP2]] +// +// CPP-CHECK-LABEL: @_Z24test_svqrshrn_u16_u32_x212svuint32x2_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.uqrshrn.x2.nxv4i32( [[TMP0]], [[TMP1]], i32 16) +// CPP-CHECK-NEXT: ret [[TMP2]] +// +svuint16_t test_svqrshrn_u16_u32_x2(svuint32x2_t zn) __arm_streaming_compatible { + return SVE_ACLE_FUNC(svqrshrn,_n,_u16,_u32_x2,)(zn, 16); +} + +// SQRSHRUN x 2 + +// CHECK-LABEL: @test_svqrshrun_u16_s32_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN:%.*]], i64 0) +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN]], i64 4) +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.sqrshrun.x2.nxv4i32( [[TMP0]], [[TMP1]], i32 16) +// CHECK-NEXT: ret [[TMP2]] +// +// CPP-CHECK-LABEL: @_Z25test_svqrshrun_u16_s32_x211svint32x2_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN:%.*]], i64 0) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.vector.extract.nxv4i32.nxv8i32( [[ZN]], i64 4) +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.sqrshrun.x2.nxv4i32( [[TMP0]], [[TMP1]], i32 16) +// CPP-CHECK-NEXT: ret [[TMP2]] +// +svuint16_t test_svqrshrun_u16_s32_x2(svint32x2_t zn) __arm_streaming_compatible { + return SVE_ACLE_FUNC(svqrshrun,_n,_u16,_s32_x2,)(zn, 16); +} diff --git a/clang/test/CodeGen/arm-vector_type-params-returns.c b/clang/test/CodeGen/arm-vector_type-params-returns.c new file mode 100644 index 0000000000000000000000000000000000000000..14c3512ab81a9fa6069ff6fce339b7e4a45e09e2 --- /dev/null +++ b/clang/test/CodeGen/arm-vector_type-params-returns.c @@ -0,0 +1,136 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3 + +// RUN: %clang_cc1 -DSVE_HEADER -triple aarch64 -target-feature +sve -emit-llvm -O2 -o - %s | opt -S -passes=mem2reg,sroa | FileCheck %s +// RUN: %clang_cc1 -DSVE_HEADER -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o - /dev/null %s + +// RUN: %clang_cc1 -DNEON_HEADER -triple aarch64 -target-feature +sve -emit-llvm -O2 -o - %s | opt -S -passes=mem2reg,sroa | FileCheck %s +// RUN: %clang_cc1 -DNEON_HEADER -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o - /dev/null %s + +// RUN: %clang_cc1 -DSVE_HEADER -DNEON_HEADER -triple aarch64 -target-feature +sve -emit-llvm -O2 -o - %s | opt -S -passes=mem2reg,sroa | FileCheck %s +// RUN: %clang_cc1 -DSVE_HEADER -DNEON_HEADER -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o - /dev/null %s + +// RUN: %clang_cc1 -DNEON_HEADER -DSVE_HEADER2 -triple aarch64 -target-feature +sve -emit-llvm -O2 -o - %s | opt -S -passes=mem2reg,sroa | FileCheck %s +// RUN: %clang_cc1 -DNEON_HEADER -DSVE_HEADER2 -triple aarch64-none-linux-gnu -target-feature +sve2p1 -S -disable-O0-optnone -Werror -Wall -o - /dev/null %s + +// REQUIRES: aarch64-registered-target + +#ifdef SVE_HEADER + #include +#endif + +#ifdef NEON_HEADER + #include +#endif + +#ifdef SVE_HEADER_2 + #include +#endif + +// function return types +// CHECK-LABEL: define dso_local <8 x half> @test_ret_v8f16( +// CHECK-SAME: <8 x half> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <8 x half> [[V]] +// +float16x8_t test_ret_v8f16(float16x8_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <4 x float> @test_ret_v4f32( +// CHECK-SAME: <4 x float> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <4 x float> [[V]] +// +float32x4_t test_ret_v4f32(float32x4_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <2 x double> @test_ret_v2f64( +// CHECK-SAME: <2 x double> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <2 x double> [[V]] +// +float64x2_t test_ret_v2f64(float64x2_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <8 x bfloat> @test_ret_v8bf16( +// CHECK-SAME: <8 x bfloat> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <8 x bfloat> [[V]] +// +bfloat16x8_t test_ret_v8bf16(bfloat16x8_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <16 x i8> @test_ret_v16s8( +// CHECK-SAME: <16 x i8> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <16 x i8> [[V]] +// +int8x16_t test_ret_v16s8(int8x16_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <8 x i16> @test_ret_v8s16( +// CHECK-SAME: <8 x i16> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <8 x i16> [[V]] +// +int16x8_t test_ret_v8s16(int16x8_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <4 x i32> @test_ret_v32s4( +// CHECK-SAME: <4 x i32> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <4 x i32> [[V]] +// +int32x4_t test_ret_v32s4(int32x4_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <2 x i64> @test_ret_v64s2( +// CHECK-SAME: <2 x i64> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <2 x i64> [[V]] +// +int64x2_t test_ret_v64s2(int64x2_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <16 x i8> @test_ret_v16u8( +// CHECK-SAME: <16 x i8> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <16 x i8> [[V]] +// +uint8x16_t test_ret_v16u8(uint8x16_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <8 x i16> @test_ret_v8u16( +// CHECK-SAME: <8 x i16> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <8 x i16> [[V]] +// +uint16x8_t test_ret_v8u16(uint16x8_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <4 x i32> @test_ret_v32u4( +// CHECK-SAME: <4 x i32> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <4 x i32> [[V]] +// +uint32x4_t test_ret_v32u4(uint32x4_t v) { + return v; +} + +// CHECK-LABEL: define dso_local <2 x i64> @test_ret_v64u2( +// CHECK-SAME: <2 x i64> noundef returned [[V:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret <2 x i64> [[V]] +// +uint64x2_t test_ret_v64u2(uint64x2_t v) { + return v; +} diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx12-err.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx12-err.cl new file mode 100644 index 0000000000000000000000000000000000000000..5e0153c42825e35decbc4ddf6458923aae107c88 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx12-err.cl @@ -0,0 +1,24 @@ +// REQUIRES: amdgpu-registered-target + +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx1200 -verify -S -emit-llvm -o - %s + +kernel void builtins_amdgcn_s_barrier_signal_err(global int* in, global int* out, int barrier) { + + __builtin_amdgcn_s_barrier_signal(barrier); // expected-error {{'__builtin_amdgcn_s_barrier_signal' must be a constant integer}} + __builtin_amdgcn_s_barrier_wait(-1); + *out = *in; +} + +kernel void builtins_amdgcn_s_barrier_wait_err(global int* in, global int* out, int barrier) { + + __builtin_amdgcn_s_barrier_signal(-1); + __builtin_amdgcn_s_barrier_wait(barrier); // expected-error {{'__builtin_amdgcn_s_barrier_wait' must be a constant integer}} + *out = *in; +} + +kernel void builtins_amdgcn_s_barrier_signal_isfirst_err(global int* in, global int* out, int barrier) { + + __builtin_amdgcn_s_barrier_signal_isfirst(barrier); // expected-error {{'__builtin_amdgcn_s_barrier_signal_isfirst' must be a constant integer}} + __builtin_amdgcn_s_barrier_wait(-1); + *out = *in; +} diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx12.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx12.cl new file mode 100644 index 0000000000000000000000000000000000000000..b8d281531e218e6116519fb82cef4787a6e85104 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx12.cl @@ -0,0 +1,174 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -cl-std=CL2.0 -O0 -triple amdgcn-unknown-unknown -target-cpu gfx1200 -S -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: @test_s_barrier_signal( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.signal(i32 -1) +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.wait(i16 -1) +// CHECK-NEXT: ret void +// +void test_s_barrier_signal() +{ + __builtin_amdgcn_s_barrier_signal(-1); + __builtin_amdgcn_s_barrier_wait(-1); +} + +// CHECK-LABEL: @test_s_barrier_signal_var( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-NEXT: store i32 [[A:%.*]], ptr addrspace(5) [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[A_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.signal.var(i32 [[TMP0]]) +// CHECK-NEXT: ret void +// +void test_s_barrier_signal_var(int a) +{ + __builtin_amdgcn_s_barrier_signal_var(a); +} + +// CHECK-LABEL: @test_s_barrier_signal_isfirst( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: store ptr [[A:%.*]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: store ptr [[B:%.*]], ptr addrspace(5) [[B_ADDR]], align 8 +// CHECK-NEXT: store ptr [[C:%.*]], ptr addrspace(5) [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = call i1 @llvm.amdgcn.s.barrier.signal.isfirst(i32 1) +// CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK: if.then: +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr addrspace(5) [[B_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: br label [[IF_END:%.*]] +// CHECK: if.else: +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr addrspace(5) [[C_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP2]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: br label [[IF_END]] +// CHECK: if.end: +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.wait(i16 1) +// CHECK-NEXT: ret void +// +void test_s_barrier_signal_isfirst(int* a, int* b, int *c) +{ + if(__builtin_amdgcn_s_barrier_signal_isfirst(1)) + a = b; + else + a = c; + + __builtin_amdgcn_s_barrier_wait(1); +} + +// CHECK-LABEL: @test_s_barrier_isfirst_var( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[D_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-NEXT: store ptr [[A:%.*]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: store ptr [[B:%.*]], ptr addrspace(5) [[B_ADDR]], align 8 +// CHECK-NEXT: store ptr [[C:%.*]], ptr addrspace(5) [[C_ADDR]], align 8 +// CHECK-NEXT: store i32 [[D:%.*]], ptr addrspace(5) [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[D_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = call i1 @llvm.amdgcn.s.barrier.signal.isfirst.var(i32 [[TMP0]]) +// CHECK-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK: if.then: +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr addrspace(5) [[B_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP2]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: br label [[IF_END:%.*]] +// CHECK: if.else: +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr addrspace(5) [[C_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP3]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: br label [[IF_END]] +// CHECK: if.end: +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.wait(i16 1) +// CHECK-NEXT: ret void +// +void test_s_barrier_isfirst_var(int* a, int* b, int *c, int d) +{ + if ( __builtin_amdgcn_s_barrier_signal_isfirst_var(d)) + a = b; + else + a = c; + + __builtin_amdgcn_s_barrier_wait(1); + +} + +// CHECK-LABEL: @test_s_barrier_init( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-NEXT: store i32 [[A:%.*]], ptr addrspace(5) [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[A_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.init(i32 1, i32 [[TMP0]]) +// CHECK-NEXT: ret void +// +void test_s_barrier_init(int a) +{ + __builtin_amdgcn_s_barrier_init(1, a); +} + +// CHECK-LABEL: @test_s_barrier_join( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.join(i32 1) +// CHECK-NEXT: ret void +// +void test_s_barrier_join() +{ + __builtin_amdgcn_s_barrier_join(1); +} + +// CHECK-LABEL: @test_s_wakeup_barrier( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @llvm.amdgcn.s.barrier.join(i32 1) +// CHECK-NEXT: ret void +// +void test_s_wakeup_barrier() +{ + __builtin_amdgcn_s_barrier_join(1); +} + +// CHECK-LABEL: @test_s_barrier_leave( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[C_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: store ptr [[A:%.*]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: store ptr [[B:%.*]], ptr addrspace(5) [[B_ADDR]], align 8 +// CHECK-NEXT: store ptr [[C:%.*]], ptr addrspace(5) [[C_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = call i1 @llvm.amdgcn.s.barrier.leave() +// CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK: if.then: +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr addrspace(5) [[B_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP1]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: br label [[IF_END:%.*]] +// CHECK: if.else: +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr addrspace(5) [[C_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP2]], ptr addrspace(5) [[A_ADDR]], align 8 +// CHECK-NEXT: br label [[IF_END]] +// CHECK: if.end: +// CHECK-NEXT: ret void +// +void test_s_barrier_leave(int* a, int* b, int *c) +{ + if (__builtin_amdgcn_s_barrier_leave()) + a = b; + else + a = c; +} + +// CHECK-LABEL: @test_s_get_barrier_state( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-NEXT: [[STATE:%.*]] = alloca i32, align 4, addrspace(5) +// CHECK-NEXT: store i32 [[A:%.*]], ptr addrspace(5) [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.amdgcn.s.get.barrier.state(i32 [[TMP0]]) +// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(5) [[STATE]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(5) [[STATE]], align 4 +// CHECK-NEXT: ret i32 [[TMP2]] +// +unsigned test_s_get_barrier_state(int a) +{ + unsigned State = __builtin_amdgcn_s_get_barrier_state(a); + return State; +} diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 81d1b907eced188c5c7096aca6e9c751f9973eb3..5b6dfe308a76eae703bc216db2410369ae59e6d4 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -272,10 +272,12 @@ // RUN: not %clang_cl /vmg /vmm /vms -### -- %s 2>&1 | FileCheck -check-prefix=VMX %s // VMX: '/vms' not allowed with '/vmm' -// RUN: %clang_cl /volatile:iso -### -- %s 2>&1 | FileCheck -check-prefix=VOLATILE-ISO %s +// RUN: %clang_cl --target=i686-pc-win32 /volatile:iso -### -- %s 2>&1 | FileCheck -check-prefix=VOLATILE-ISO %s +// RUN: %clang_cl --target=aarch64-pc-win32 -### -- %s 2>&1 | FileCheck -check-prefix=VOLATILE-ISO %s // VOLATILE-ISO-NOT: "-fms-volatile" -// RUN: %clang_cl /volatile:ms -### -- %s 2>&1 | FileCheck -check-prefix=VOLATILE-MS %s +// RUN: %clang_cl --target=aarch64-pc-win32 /volatile:ms -### -- %s 2>&1 | FileCheck -check-prefix=VOLATILE-MS %s +// RUN: %clang_cl --target=i686-pc-win32 -### -- %s 2>&1 | FileCheck -check-prefix=VOLATILE-MS %s // VOLATILE-MS: "-fms-volatile" // RUN: %clang_cl /W0 -### -- %s 2>&1 | FileCheck -check-prefix=W0 %s diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index ebe8a0520bf0fca399484e2391896a9d74161683..c8b44e056e58f76fe433fcc3176fc49c1831c4b6 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -611,3 +611,9 @@ // CHECK-INT-OBJEMITTER-NOT: unsupported option '-fintegrated-objemitter' for target // RUN: not %clang -### -fno-integrated-objemitter --target=x86_64 %s 2>&1 | FileCheck -check-prefix=CHECK-NOINT-OBJEMITTER %s // CHECK-NOINT-OBJEMITTER: unsupported option '-fno-integrated-objemitter' for target + +// RUN: %clang -### --target=aarch64-windows-msvc %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MS-VOLATILE %s +// RUN: %clang -### --target=aarch64-windows-msvc -fms-volatile %s 2>&1 | FileCheck -check-prefix=CHECK-MS-VOLATILE %s +// RUN: %clang -### --target=aarch64-windows-msvc -fno-ms-volatile %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MS-VOLATILE %s +// CHECK-MS-VOLATILE: -fms-volatile +// CHECK-NO-MS-VOLATILE-NOT: -fms-volatile diff --git a/clang/test/Driver/darwin-builtin-modules.c b/clang/test/Driver/darwin-builtin-modules.c index 215f2b8d2c142ac66c34a42bffef7cdf2b8bfd91..1c56e13bfb9293b438b601e791b82180b4210059 100644 --- a/clang/test/Driver/darwin-builtin-modules.c +++ b/clang/test/Driver/darwin-builtin-modules.c @@ -9,19 +9,3 @@ // RUN: %clang -isysroot %S/Inputs/MacOSX99.0.sdk -target x86_64-apple-macos98.0 -### %s 2>&1 | FileCheck --check-prefix=CHECK_FUTURE %s // RUN: %clang -isysroot %S/Inputs/MacOSX99.0.sdk -target x86_64-apple-macos99.0 -### %s 2>&1 | FileCheck --check-prefix=CHECK_FUTURE %s // CHECK_FUTURE-NOT: -fbuiltin-headers-in-system-modules - - -// Check that builtin_headers_in_system_modules is only set if -fbuiltin-headers-in-system-modules and -fmodules are both set. - -// RUN: %clang -isysroot %S/Inputs/iPhoneOS13.0.sdk -target arm64-apple-ios13.0 -fsyntax-only %s -Xclang -verify=no-feature -// RUN: %clang -isysroot %S/Inputs/iPhoneOS13.0.sdk -target arm64-apple-ios13.0 -fsyntax-only %s -fmodules -Xclang -verify=yes-feature -// RUN: %clang -isysroot %S/Inputs/MacOSX99.0.sdk -target x86_64-apple-macos99.0 -fsyntax-only %s -Xclang -verify=no-feature -// RUN: %clang -isysroot %S/Inputs/MacOSX99.0.sdk -target x86_64-apple-macos99.0 -fsyntax-only %s -fmodules -Xclang -verify=no-feature - -#if __has_feature(builtin_headers_in_system_modules) -#error "has builtin_headers_in_system_modules" -// yes-feature-error@-1 {{}} -#else -#error "no builtin_headers_in_system_modules" -// no-feature-error@-1 {{}} -#endif diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c index 6fc921a8c6ee155d65d9a2d762487f6392da8194..35208b2eae8fbd329e46983149179eca73f98bd1 100644 --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -1056,12 +1056,12 @@ // CHECK-ZFBFMIN-EXT: __riscv_zfbfmin 8000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ -// RUN: -march=rv32i_zicfilp0p2 -x c -E -dM %s \ +// RUN: -march=rv32i_zicfilp0p4 -x c -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-ZICFILP-EXT %s // RUN: %clang --target=riscv64 -menable-experimental-extensions \ -// RUN: -march=rv64i_zicfilp0p2 -x c -E -dM %s \ +// RUN: -march=rv64i_zicfilp0p4 -x c -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-ZICFILP-EXT %s -// CHECK-ZICFILP-EXT: __riscv_zicfilp 2000{{$}} +// CHECK-ZICFILP-EXT: __riscv_zicfilp 4000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ // RUN: -march=rv32i_zicond1p0 -x c -E -dM %s \ diff --git a/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_target.cpp b/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_target.cpp index f41030c18e932bc68037046a87685fa9bdff0747..2f771ca170e76aab1b3fd8e5a42f299bf485567c 100644 --- a/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_target.cpp +++ b/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_target.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify -emit-llvm -o - -ferror-limit 100 %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -fsyntax-only -verify -emit-llvm -o - -ferror-limit 100 %s // REQUIRES: aarch64-registered-target // Test that functions with the correct target attributes can use the correct SVE intrinsics. @@ -29,4 +29,5 @@ void __attribute__((target("sve2-sha3"))) test_sve2_sha3() void __attribute__((target("sve2"))) test_f16(svbool_t pg) { svlogb_f16_z(pg, svundef_f16()); -} \ No newline at end of file +} + diff --git a/clang/test/Sema/arm-vector-types-support.c b/clang/test/Sema/arm-vector-types-support.c index fa101afa3122adee457589f8165b0192b3bbd827..83a83ddfe780170cde85da81058b22d425ced113 100644 --- a/clang/test/Sema/arm-vector-types-support.c +++ b/clang/test/Sema/arm-vector-types-support.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -triple armv7 -fsyntax-only -verify -typedef __attribute__((neon_vector_type(2))) int int32x2_t; // expected-error{{'neon_vector_type' attribute is not supported on targets missing 'neon' or 'mve'; specify an appropriate -march= or -mcpu=}} +typedef __attribute__((neon_vector_type(2))) int int32x2_t; // expected-error{{'neon_vector_type' attribute is not supported on targets missing 'neon', 'mve', 'sve' or 'sme'; specify an appropriate -march= or -mcpu=}} typedef __attribute__((neon_polyvector_type(16))) short poly8x16_t; // expected-error{{'neon_polyvector_type' attribute is not supported on targets missing 'neon' or 'mve'; specify an appropriate -march= or -mcpu=}} typedef __attribute__((arm_sve_vector_bits(256))) void nosveflag; // expected-error{{'arm_sve_vector_bits' attribute is not supported on targets missing 'sve'; specify an appropriate -march= or -mcpu=}} diff --git a/clang/test/Sema/missing-field-initializers.c b/clang/test/Sema/missing-field-initializers.c index 1e65b2d62e1ab84c0ca01db8a7cdece6f8a1d8b8..8653591ff1187a6f78aa706b696a6af77b0f4e00 100644 --- a/clang/test/Sema/missing-field-initializers.c +++ b/clang/test/Sema/missing-field-initializers.c @@ -18,7 +18,7 @@ struct Foo bar1[] = { 1, 2, 1, 2, 1 -}; // expected-warning {{missing field 'b' initializer}} +}; // expected-warning@-1 {{missing field 'b' initializer}} struct Foo bar2[] = { {}, {}, {} }; diff --git a/clang/test/Sema/no_stack_protector.c b/clang/test/Sema/no_stack_protector.c index 0007435901e8405689ba2a6262e67ba00b942885..1ecd46bc624ceb14dbda75549ef28d0dcbe88d4d 100644 --- a/clang/test/Sema/no_stack_protector.c +++ b/clang/test/Sema/no_stack_protector.c @@ -1,4 +1,7 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s + +[[gnu::no_stack_protector]] void test1(void) {} +[[clang::no_stack_protector]] void test2(void) {} void __attribute__((no_stack_protector)) foo(void) {} int __attribute__((no_stack_protector)) var; // expected-warning {{'no_stack_protector' attribute only applies to functions}} diff --git a/clang/test/Sema/no_stack_protector.cpp b/clang/test/Sema/no_stack_protector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..160e3d32a9389a782da8c7a0f9b769ba44211306 --- /dev/null +++ b/clang/test/Sema/no_stack_protector.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// expected-no-diagnostics + +[[gnu::no_stack_protector]] void test1() {} +[[clang::no_stack_protector]] void test2() {} diff --git a/clang/test/SemaCUDA/neon-attrs.cu b/clang/test/SemaCUDA/neon-attrs.cu index a72b03f3bbbd7e31dc9777c78db46d92546ba625..129056741ac9a46ae7811768369a45f0c7166829 100644 --- a/clang/test/SemaCUDA/neon-attrs.cu +++ b/clang/test/SemaCUDA/neon-attrs.cu @@ -15,7 +15,8 @@ // quiet-no-diagnostics typedef __attribute__((neon_vector_type(4))) float float32x4_t; -// expected-error@-1 {{'neon_vector_type' attribute is not supported on targets missing 'neon' or 'mve'}} +// expected-error@-1 {{'neon_vector_type' attribute is not supported on targets missing 'neon', 'mve', 'sve' or 'sme'}} +// expect typedef unsigned char poly8_t; typedef __attribute__((neon_polyvector_type(8))) poly8_t poly8x8_t; // expected-error@-1 {{'neon_polyvector_type' attribute is not supported on targets missing 'neon' or 'mve'}} diff --git a/clang/test/SemaCXX/alias-template.cpp b/clang/test/SemaCXX/alias-template.cpp index 5189405e23db567a3f877033e40f4092e65d1b84..dca63e15f5bb8a283935986a5948873af5a222a3 100644 --- a/clang/test/SemaCXX/alias-template.cpp +++ b/clang/test/SemaCXX/alias-template.cpp @@ -192,3 +192,68 @@ int g = sfinae_me(); // expected-error{{no matching function for call to 's namespace NullExceptionDecl { template auto get = []() { try { } catch(...) {}; return I; }; // expected-error{{initializer contains unexpanded parameter pack 'I'}} } + +namespace GH41693 { +// No errors when a type alias defined in a class or a friend of a class +// accesses private members of the same class. +struct S { +private: + template static constexpr void Impl() {} + +public: + template using U = decltype(Impl()); +}; + +using X = S::U; +struct Y { +private: + static constexpr int x=0; + + template + static constexpr int y=0; + + template + static constexpr int foo(); + +public: + template + using bar1 = decltype(foo()); + using bar2 = decltype(x); + template + using bar3 = decltype(y); +}; + + +using type1 = Y::bar1; +using type2 = Y::bar2; +using type3 = Y::bar3; + +struct theFriend{ + template + using theAlias = decltype(&T::i); +}; + +class theC{ + int i; + public: + friend struct theFriend; +}; + +int foo(){ + (void)sizeof(theFriend::theAlias); +} + +// Test case that regressed with the first iteration of the fix for GH41693. +template class SP { + T* data; +}; + +template class A { + static SP foo(); +}; + +template using TRet = SP>; + +template TRet A::foo() { return TRet{};}; + +} diff --git a/clang/test/SemaCXX/attr-suppress.cpp b/clang/test/SemaCXX/attr-suppress.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb5e2ac7ce20667aa7aa57176f49d7ef9c70c4d5 --- /dev/null +++ b/clang/test/SemaCXX/attr-suppress.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify + +[[gsl::suppress("globally")]]; + +namespace N { +[[gsl::suppress("in-a-namespace")]]; +} + +[[gsl::suppress("readability-identifier-naming")]] void f_() { + int *p; + [[gsl::suppress("type", "bounds")]] { + p = reinterpret_cast(7); + } + + [[gsl::suppress]] int x; // expected-error {{'suppress' attribute takes at least 1 argument}} + [[gsl::suppress()]] int y; // expected-error {{'suppress' attribute takes at least 1 argument}} + int [[gsl::suppress("r")]] z; // expected-error {{'suppress' attribute cannot be applied to types}} + [[gsl::suppress(f_)]] float f; // expected-error {{expected string literal as argument of 'suppress' attribute}} +} + +union [[gsl::suppress("type.1")]] U { + int i; + float f; +}; + +[[clang::suppress]]; +// expected-error@-1 {{'suppress' attribute only applies to variables and statements}} + +namespace N { +[[clang::suppress("in-a-namespace")]]; +// expected-error@-1 {{'suppress' attribute only applies to variables and statements}} +} // namespace N + +[[clang::suppress]] int global = 42; + +[[clang::suppress]] void foo() { + // expected-error@-1 {{'suppress' attribute only applies to variables and statements}} + [[clang::suppress]] int *p; + + [[clang::suppress]] int a = 0; // no-warning + [[clang::suppress()]] int b = 1; // no-warning + [[clang::suppress("a")]] int c = a + b; // no-warning + [[clang::suppress("a", "b")]] b = c - a; // no-warning + + [[clang::suppress("a", "b")]] if (b == 10) a += 4; // no-warning + [[clang::suppress]] while (true) {} // no-warning + [[clang::suppress]] switch (a) { // no-warning + default: + c -= 10; + } + + int [[clang::suppress("r")]] z; + // expected-error@-1 {{'suppress' attribute cannot be applied to types}} + [[clang::suppress(foo)]] float f; + // expected-error@-1 {{expected string literal as argument of 'suppress' attribute}} +} + +class [[clang::suppress("type.1")]] V { + // expected-error@-1 {{'suppress' attribute only applies to variables and statements}} + int i; + float f; +}; diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp index 510ace58c35a6aaaf5a308013f121d532f495156..0d977e07ed034e0f423cb0ed2f37d52d943ea357 100644 --- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp +++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,pedantic,override,reorder -pedantic-errors // RUN: %clang_cc1 -std=c++17 %s -verify=expected,pedantic,override,reorder -Wno-c++20-designator -pedantic-errors -// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,pedantic -Werror=c99-designator -Wno-reorder-init-list -Wno-initializer-overrides +// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,pedantic -Werror=c99-designator -Wno-reorder-init-list -Wno-initializer-overrides -Werror=nested-anon-types -Werror=gnu-anonymous-struct // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,reorder -Wno-c99-designator -Werror=reorder-init-list -Wno-initializer-overrides // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,override -Wno-c99-designator -Wno-reorder-init-list -Werror=initializer-overrides // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides @@ -39,6 +39,7 @@ A a1 = { }; int arr[3] = {[1] = 5}; // pedantic-error {{array designators are a C99 extension}} B b = {.a.x = 0}; // pedantic-error {{nested designators are a C99 extension}} + // wmissing-warning@-1 {{missing field 'y' initializer}} A a2 = { .x = 1, // pedantic-error {{mixture of designated and non-designated initializers in the same initializer list is a C99 extension}} 2 // pedantic-note {{first non-designated initializer is here}} @@ -60,7 +61,6 @@ B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is B b3 = {.a = 1, 2}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}} B b4 = {.a = 1, 2, 3}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}} expected-error {{excess elements}} B b5 = {.a = nullptr}; // expected-error {{cannot initialize}} - // wmissing-warning@-1 {{missing field 'y' initializer}} struct C { int :0, x, :0, y, :0; }; C c = { .x = 1, // override-note {{previous}} @@ -247,3 +247,87 @@ void foo() { // } } + +namespace GH70384 { + +struct A { + int m; + union { int a; float n = 0; }; +}; + +struct B { + int m; + int b; + union { int a ; }; +}; + +union CU { + int a = 1; + double b; +}; + +struct C { + int a; + union { int b; CU c;}; +}; + +struct CC { + int a; + CU c; +}; + +void foo() { + A a = A{.m = 0}; + A aa = {0}; + A aaa = {.a = 7}; // wmissing-warning {{missing field 'm' initializer}} + B b = {.m = 1, .b = 3 }; //wmissing-warning {{missing field 'a' initializer}} + B bb = {1}; // wmissing-warning {{missing field 'b' initializer}} + // wmissing-warning@-1 {{missing field 'a' initializer}} + C c = {.a = 1}; // wmissing-warning {{missing field 'b' initializer}} + CC cc = {.a = 1}; // wmissing-warning {{missing field 'c' initializer}} +} + +struct C1 { + int m; + union { float b; union {int n = 1; }; }; + // pedantic-error@-1 {{anonymous types declared in an anonymous union are an extension}} +}; + +struct C2 { + int m; + struct { float b; int n = 1; }; // pedantic-error {{anonymous structs are a GNU extension}} +}; + +struct C3 { + int m; + struct { float b = 1; union {int a;}; int n = 1; }; + // pedantic-error@-1 {{anonymous structs are a GNU extension}} + // pedantic-error@-2 {{anonymous types declared in an anonymous struct are an extension}} +}; + +C1 c = C1{.m = 1}; +C1 cc = C1{.b = 1}; // wmissing-warning {{missing field 'm' initializer}} +C2 c1 = C2{.m = 1}; // wmissing-warning {{missing field 'b' initializer}} +C2 c22 = C2{.m = 1, .b = 1}; +C3 c2 = C3{.b = 1}; // wmissing-warning {{missing field 'a' initializer}} + // wmissing-warning@-1 {{missing field 'm' initializer}} + +struct C4 { + union { + struct { int n; }; // pedantic-error {{anonymous structs are a GNU extension}} + // pedantic-error@-1 {{anonymous types declared in an anonymous union are an extension}} + int m = 0; }; + int z; +}; +C4 a = {.z = 1}; + +struct C5 { + int a; + struct { // pedantic-error {{anonymous structs are a GNU extension}} + int x; + struct { int y = 0; }; // pedantic-error {{anonymous types declared in an anonymous struct are an extension}} + // pedantic-error@-1 {{anonymous structs are a GNU extension}} + }; +}; +C5 c5 = C5{.a = 0}; //wmissing-warning {{missing field 'x' initializer}} +} diff --git a/clang/test/SemaCXX/suppress.cpp b/clang/test/SemaCXX/suppress.cpp deleted file mode 100644 index 29544b3c573ccc8695589605675ad1f54d33a75b..0000000000000000000000000000000000000000 --- a/clang/test/SemaCXX/suppress.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify - -[[gsl::suppress("globally")]]; - -namespace N { - [[gsl::suppress("in-a-namespace")]]; -} - -[[gsl::suppress("readability-identifier-naming")]] -void f_() { - int *p; - [[gsl::suppress("type", "bounds")]] { - p = reinterpret_cast(7); - } - - [[gsl::suppress]] int x; // expected-error {{'suppress' attribute takes at least 1 argument}} - [[gsl::suppress()]] int y; // expected-error {{'suppress' attribute takes at least 1 argument}} - int [[gsl::suppress("r")]] z; // expected-error {{'suppress' attribute cannot be applied to types}} - [[gsl::suppress(f_)]] float f; // expected-error {{expected string literal as argument of 'suppress' attribut}} -} - -union [[gsl::suppress("type.1")]] U { - int i; - float f; -}; diff --git a/clang/test/SemaObjC/attr-suppress.m b/clang/test/SemaObjC/attr-suppress.m new file mode 100644 index 0000000000000000000000000000000000000000..ade8f94ec5895ef6d4f7a86780408be98527737b --- /dev/null +++ b/clang/test/SemaObjC/attr-suppress.m @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks %s -verify + +#define SUPPRESS1 __attribute__((suppress)) +#define SUPPRESS2(...) __attribute__((suppress(__VA_ARGS__))) + +SUPPRESS1 int global = 42; + +SUPPRESS1 void foo() { + // expected-error@-1 {{'suppress' attribute only applies to variables and statements}} + SUPPRESS1 int *p; + + SUPPRESS1 int a = 0; // no-warning + SUPPRESS2() + int b = 1; // no-warning + SUPPRESS2("a") + int c = a + b; // no-warning + SUPPRESS2("a", "b") { b = c - a; } // no-warning + + SUPPRESS2("a", "b") + if (b == 10) + a += 4; // no-warning + SUPPRESS1 while (1) {} // no-warning + SUPPRESS1 switch (a) { // no-warning + default: + c -= 10; + } + + // GNU-style attributes and C++11 attributes apply to different things when + // written like this. GNU attribute gets attached to the declaration, while + // C++11 attribute ends up on the type. + int SUPPRESS2("r") z; + SUPPRESS2(foo) + float f; + // expected-error@-2 {{expected string literal as argument of 'suppress' attribute}} +} + +union SUPPRESS2("type.1") U { + // expected-error@-1 {{'suppress' attribute only applies to variables and statements}} + int i; + float f; +}; + +SUPPRESS1 @interface Test { + // expected-error@-1 {{'suppress' attribute only applies to variables and statements}} +} +@property SUPPRESS2("prop") int *prop; +// expected-error@-1 {{'suppress' attribute only applies to variables and statements}} +- (void)bar:(int)x SUPPRESS1; +// expected-error@-1 {{'suppress' attribute only applies to variables and statements}} +@end diff --git a/clang/tools/arcmt-test/arcmt-test.cpp b/clang/tools/arcmt-test/arcmt-test.cpp index 53229ac570bc188fd40680d4be5f6d5c39e979d5..b61f38e9905dba7cfe8ac07229a7cb47e1feebb4 100644 --- a/clang/tools/arcmt-test/arcmt-test.cpp +++ b/clang/tools/arcmt-test/arcmt-test.cpp @@ -230,7 +230,7 @@ static bool verifyTransformedFiles(ArrayRef resultFiles) { for (ArrayRef::iterator I = resultFiles.begin(), E = resultFiles.end(); I != E; ++I) { StringRef fname(*I); - if (!fname.endswith(".result")) { + if (!fname.ends_with(".result")) { errs() << "error: filename '" << fname << "' does not have '.result' extension\n"; return true; diff --git a/clang/tools/c-arcmt-test/c-arcmt-test.c b/clang/tools/c-arcmt-test/c-arcmt-test.c index 3bbb2d5d6a8564ab1223cc4bd40e516a54da3bcf..00999f188c7dcedc1540b824394cb0e77c402bcb 100644 --- a/clang/tools/c-arcmt-test/c-arcmt-test.c +++ b/clang/tools/c-arcmt-test/c-arcmt-test.c @@ -1,8 +1,9 @@ /* c-arcmt-test.c */ #include "clang-c/Index.h" -#include +#include "llvm/Support/AutoConvert.h" #include +#include #include #if defined(_WIN32) #include @@ -107,6 +108,14 @@ static void flush_atexit(void) { } int main(int argc, const char **argv) { +#ifdef __MVS__ + if (enableAutoConversion(fileno(stdout)) == -1) + fprintf(stderr, "Setting conversion on stdout failed\n"); + + if (enableAutoConversion(fileno(stderr)) == -1) + fprintf(stderr, "Setting conversion on stderr failed\n"); +#endif + thread_info client_data; atexit(flush_atexit); diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 2c0c9cb8eb5e42fd701ad8a13d96a35f28dc7cd0..6fa400a0675b7a84e43712b6e3969d239e71117d 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -8,6 +8,7 @@ #include "clang-c/Documentation.h" #include "clang-c/Index.h" #include "clang/Config/config.h" +#include "llvm/Support/AutoConvert.h" #include #include #include @@ -5150,6 +5151,14 @@ static void flush_atexit(void) { int main(int argc, const char **argv) { thread_info client_data; +#ifdef __MVS__ + if (enableAutoConversion(fileno(stdout)) == -1) + fprintf(stderr, "Setting conversion on stdout failed\n"); + + if (enableAutoConversion(fileno(stderr)) == -1) + fprintf(stderr, "Setting conversion on stderr failed\n"); +#endif + atexit(flush_atexit); #ifdef CLANG_HAVE_LIBXML diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp index 769727eedec721612cdd81958321548db5a10b88..c048f335f91ca1e7c43fa5bf7e8813c5eb89bd55 100644 --- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp +++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp @@ -181,7 +181,7 @@ static int HandleFiles(ArrayRef SourceFiles, // process them directly in HandleAST, otherwise put them // on a list for ClangTool to handle. for (StringRef Src : SourceFiles) { - if (Src.endswith(".ast")) { + if (Src.ends_with(".ast")) { if (!HandleAST(Src)) { return 1; } diff --git a/clang/tools/clang-format/git-clang-format.bat b/clang/tools/clang-format/git-clang-format.bat index d4bc5172989cb098e2b1290b5c3906d590562911..9965cd4312fe39eec0d3395050f3d8664d373566 100644 --- a/clang/tools/clang-format/git-clang-format.bat +++ b/clang/tools/clang-format/git-clang-format.bat @@ -1 +1 @@ -py -3 git-clang-format %* +py -3 %~pn0 %* diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index 5d2fe98fe56011588a4fa21748cd2c9bc10565a8..bd2fd02c6a3e8f93b519e54050d178da3d263add 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -1151,7 +1151,7 @@ linkAndWrapDeviceFiles(SmallVectorImpl &LinkerInputFiles, std::optional findFile(StringRef Dir, StringRef Root, const Twine &Name) { SmallString<128> Path; - if (Dir.startswith("=")) + if (Dir.starts_with("=")) sys::path::append(Path, Root, Dir.substr(1), Name); else sys::path::append(Path, Dir, Name); @@ -1188,7 +1188,7 @@ searchLibraryBaseName(StringRef Name, StringRef Root, /// `-lfoo` or `-l:libfoo.a`. std::optional searchLibrary(StringRef Input, StringRef Root, ArrayRef SearchPaths) { - if (Input.startswith(":") || Input.ends_with(".lib")) + if (Input.starts_with(":") || Input.ends_with(".lib")) return findFromSearchPaths(Input.drop_front(), Root, SearchPaths); return searchLibraryBaseName(Input, Root, SearchPaths); } diff --git a/clang/tools/clang-refactor/ClangRefactor.cpp b/clang/tools/clang-refactor/ClangRefactor.cpp index d362eecf06d8a5a62193ff9826f41b20478f32be..175a2b8234e9acd9c8efb1f1661c14c6381af409 100644 --- a/clang/tools/clang-refactor/ClangRefactor.cpp +++ b/clang/tools/clang-refactor/ClangRefactor.cpp @@ -146,7 +146,7 @@ private: std::unique_ptr SourceSelectionArgument::fromString(StringRef Value) { - if (Value.startswith("test:")) { + if (Value.starts_with("test:")) { StringRef Filename = Value.drop_front(strlen("test:")); std::optional ParsedTestSelection = findTestSelectionRanges(Filename); diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index 5663c2c5a6c9285450cbc850741e4e45afc11b49..b9b287127015fd920d66e7097b331a843cb6166a 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -234,7 +234,7 @@ int main(int argc, const char **argv) { while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); - if (L.endswith("\\")) { + if (L.ends_with("\\")) { // FIXME: Support #ifdef X \ ... Input += L.drop_back(1); LE.setPrompt("clang-repl... "); diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index f11c933d9576565a91a936121988f78ce2ecb149..75aa4ae97c618c4efc13104eec2ff267a0b18405 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -830,9 +830,9 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { // Also, clang-cl adds ".obj" extension if none is found. if ((Arg == "-o" || Arg == "/o") && I != R) LastO = I[-1]; // Next argument (reverse iterator) - else if (Arg.startswith("/Fo") || Arg.startswith("-Fo")) + else if (Arg.starts_with("/Fo") || Arg.starts_with("-Fo")) LastO = Arg.drop_front(3).str(); - else if (Arg.startswith("/o") || Arg.startswith("-o")) + else if (Arg.starts_with("/o") || Arg.starts_with("-o")) LastO = Arg.drop_front(2).str(); if (!LastO.empty() && !llvm::sys::path::has_extension(LastO)) diff --git a/clang/tools/diagtool/TreeView.cpp b/clang/tools/diagtool/TreeView.cpp index 4f5d3fd3ef0a89c8869fc83e097acc94efedbcef..eae16243d3d59cb42f296b8807c4e42ff01d9dee 100644 --- a/clang/tools/diagtool/TreeView.cpp +++ b/clang/tools/diagtool/TreeView.cpp @@ -160,7 +160,7 @@ int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { break; case 1: RootGroup = argv[0]; - if (RootGroup.startswith("-W")) + if (RootGroup.starts_with("-W")) RootGroup = RootGroup.substr(2); if (RootGroup == "everything") ShowAll = true; diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp index 531b5b4a61c1804452918c3caab702440a3571e6..4adc7f7ad0dac397c26fe126030ea2a3728569c5 100644 --- a/clang/tools/driver/driver.cpp +++ b/clang/tools/driver/driver.cpp @@ -122,7 +122,7 @@ static void ApplyOneQAOverride(raw_ostream &OS, GetStableCStr(SavedStrings, Edit.substr(1)); OS << "### Adding argument " << Str << " at end\n"; Args.push_back(Str); - } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") && + } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") && Edit.slice(2, Edit.size() - 1).contains('/')) { StringRef MatchPattern = Edit.substr(2).split('/').first; StringRef ReplPattern = Edit.substr(2).split('/').second; @@ -403,7 +403,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { } // Handle -cc1 integrated tools. - if (Args.size() >= 2 && StringRef(Args[1]).startswith("-cc1")) + if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1")) return ExecuteCC1Tool(Args, ToolContext); // Handle options that need handling before the real command line parsing in diff --git a/clang/tools/libclang/CIndexUSRs.cpp b/clang/tools/libclang/CIndexUSRs.cpp index 75bb3b01299f10b16f8f9290db1b2d6c13aac333..be7c670cca0113617ef07b874ff875f96bc9dc4e 100644 --- a/clang/tools/libclang/CIndexUSRs.cpp +++ b/clang/tools/libclang/CIndexUSRs.cpp @@ -28,7 +28,7 @@ using namespace clang::index; //===----------------------------------------------------------------------===// static inline StringRef extractUSRSuffix(StringRef s) { - return s.startswith("c:") ? s.substr(2) : ""; + return s.starts_with("c:") ? s.substr(2) : ""; } bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl &Buf) { diff --git a/clang/unittests/Analysis/CloneDetectionTest.cpp b/clang/unittests/Analysis/CloneDetectionTest.cpp index fe65fab98c5ed47a3b900958e19976b20b84f2c4..738f6efd2018d77733520848fe987b0a9a5b107c 100644 --- a/clang/unittests/Analysis/CloneDetectionTest.cpp +++ b/clang/unittests/Analysis/CloneDetectionTest.cpp @@ -42,7 +42,7 @@ public: for (const StmtSequence &Arg : {A, B}) { if (const auto *D = dyn_cast(Arg.getContainingDecl())) { - if (D->getName().startswith("bar")) + if (D->getName().starts_with("bar")) return false; } } diff --git a/clang/unittests/Driver/ModuleCacheTest.cpp b/clang/unittests/Driver/ModuleCacheTest.cpp index 6a0f68f26a6767a96688cc362756d20fd3c6bf2d..48744415647e68471f53bbb8827b55a5669a42b9 100644 --- a/clang/unittests/Driver/ModuleCacheTest.cpp +++ b/clang/unittests/Driver/ModuleCacheTest.cpp @@ -22,6 +22,6 @@ TEST(ModuleCacheTest, GetTargetAndMode) { Driver::getDefaultModuleCachePath(Buf); StringRef Path = Buf; EXPECT_TRUE(Path.find("clang") != Path.npos); - EXPECT_TRUE(Path.endswith("ModuleCache")); + EXPECT_TRUE(Path.ends_with("ModuleCache")); } } // end anonymous namespace. diff --git a/clang/unittests/Driver/MultilibBuilderTest.cpp b/clang/unittests/Driver/MultilibBuilderTest.cpp index 60fe10ac3ba556e9851f474635517727a5226b01..e23fe7e2441db534148ca3b54191e99f88e45b97 100644 --- a/clang/unittests/Driver/MultilibBuilderTest.cpp +++ b/clang/unittests/Driver/MultilibBuilderTest.cpp @@ -144,7 +144,7 @@ TEST(MultilibBuilderTest, SetFilterObject) { << "Size before filter was incorrect. Contents:\n" << MS; MS.FilterOut([](const Multilib &M) { - return StringRef(M.gccSuffix()).startswith("/p"); + return StringRef(M.gccSuffix()).starts_with("/p"); }); ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* orange */ + 1 /* orange/pear */ + 1 /* orange/plum */ + @@ -152,7 +152,7 @@ TEST(MultilibBuilderTest, SetFilterObject) { << "Size after filter was incorrect. Contents:\n" << MS; for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { - ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p")) + ASSERT_FALSE(StringRef(I->gccSuffix()).starts_with("/p")) << "The filter should have removed " << *I; } } diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index acbbb87390d5e9ae3a26586ac290f34059bd671c..a9b5f3c700315c49d0234587edfa2f61a7cedab8 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -531,7 +531,7 @@ TEST(ToolChainTest, CommandOutput) { const auto &InFile = CmdCompile->getInputInfos().front().getFilename(); EXPECT_STREQ(InFile, "foo.cpp"); auto ObjFile = CmdCompile->getOutputFilenames().front(); - EXPECT_TRUE(StringRef(ObjFile).endswith(".o")); + EXPECT_TRUE(StringRef(ObjFile).ends_with(".o")); const auto &CmdLink = Jobs.getJobs().back(); const auto LinkInFile = CmdLink->getInputInfos().front().getFilename(); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 65b1f0f4b57659870048ca86e2e00d863402afae..8e6935319b2f3d6da5b40a0d7b2d3bfaddc71b0d 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -298,6 +298,17 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) { ASSERT_EQ(Tokens.size(), 12u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::identifier, TT_TypeName); EXPECT_TOKEN(Tokens[3], tok::star, TT_PointerOrReference); + + Tokens = annotate("class Foo {\n" + " void operator<() {}\n" + " Foo &f;\n" + "};"); + ASSERT_EQ(Tokens.size(), 17u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::kw_operator, TT_FunctionDeclarationName); + EXPECT_TOKEN(Tokens[5], tok::less, TT_OverloadedOperator); + EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_OverloadedOperatorLParen); + EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_FunctionLBrace); + EXPECT_TOKEN(Tokens[11], tok::amp, TT_PointerOrReference); } TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) { diff --git a/clang/unittests/Frontend/OutputStreamTest.cpp b/clang/unittests/Frontend/OutputStreamTest.cpp index 9cb101ecff8aafe025dd306f4f484396dfc9d609..7d360f661daa30f05a9c9db790dea8ac537ab5cc 100644 --- a/clang/unittests/Frontend/OutputStreamTest.cpp +++ b/clang/unittests/Frontend/OutputStreamTest.cpp @@ -42,7 +42,7 @@ TEST(FrontendOutputTests, TestOutputStream) { bool Success = ExecuteCompilerInvocation(&Compiler); EXPECT_TRUE(Success); EXPECT_TRUE(!IRBuffer.empty()); - EXPECT_TRUE(StringRef(IRBuffer.data()).startswith("BC")); + EXPECT_TRUE(StringRef(IRBuffer.data()).starts_with("BC")); } TEST(FrontendOutputTests, TestVerboseOutputStreamShared) { diff --git a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp b/clang/unittests/Interpreter/IncrementalProcessingTest.cpp index f43b3ddac68f941ee5e7f1c37fdde94527a6d5c7..accdf682896340b4f570f0ef665d664231024202 100644 --- a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp +++ b/clang/unittests/Interpreter/IncrementalProcessingTest.cpp @@ -44,7 +44,7 @@ const char TestProgram2[] = "extern \"C\" int funcForProg2() { return 42; }\n" const Function *getGlobalInit(llvm::Module *M) { for (const auto &Func : *M) - if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_")) + if (Func.hasName() && Func.getName().starts_with("_GLOBAL__sub_I_")) return &Func; return nullptr; diff --git a/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp b/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp index cd78014eae9d61ce53f0c43d76192398c9601f46..aace4b991b5ecabac79f7493d839b005cfc7a8bc 100644 --- a/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp +++ b/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp @@ -15,10 +15,10 @@ namespace ento { TEST(StaticAnalyzerOptions, getRegisteredCheckers) { auto IsDebugChecker = [](StringRef CheckerName) { - return CheckerName.startswith("debug"); + return CheckerName.starts_with("debug"); }; auto IsAlphaChecker = [](StringRef CheckerName) { - return CheckerName.startswith("alpha"); + return CheckerName.starts_with("alpha"); }; const auto &AllCheckers = AnalyzerOptions::getRegisteredCheckers(/*IncludeExperimental=*/true); diff --git a/clang/unittests/Tooling/HeaderIncludesTest.cpp b/clang/unittests/Tooling/HeaderIncludesTest.cpp index 256aa825554c5073ba9f0d8d4c83d13297a9cee8..929156a11d0d9a23b5cbe3547d79d3f1fc826e17 100644 --- a/clang/unittests/Tooling/HeaderIncludesTest.cpp +++ b/clang/unittests/Tooling/HeaderIncludesTest.cpp @@ -23,9 +23,9 @@ protected: std::string insert(llvm::StringRef Code, llvm::StringRef Header, IncludeDirective Directive = IncludeDirective::Include) { HeaderIncludes Includes(FileName, Code, Style); - assert(Header.startswith("\"") || Header.startswith("<")); - auto R = - Includes.insert(Header.trim("\"<>"), Header.startswith("<"), Directive); + assert(Header.starts_with("\"") || Header.starts_with("<")); + auto R = Includes.insert(Header.trim("\"<>"), Header.starts_with("<"), + Directive); if (!R) return std::string(Code); auto Result = applyAllReplacements(Code, Replacements(*R)); @@ -35,8 +35,9 @@ protected: std::string remove(llvm::StringRef Code, llvm::StringRef Header) { HeaderIncludes Includes(FileName, Code, Style); - assert(Header.startswith("\"") || Header.startswith("<")); - auto Replaces = Includes.remove(Header.trim("\"<>"), Header.startswith("<")); + assert(Header.starts_with("\"") || Header.starts_with("<")); + auto Replaces = + Includes.remove(Header.trim("\"<>"), Header.starts_with("<")); auto Result = applyAllReplacements(Code, Replaces); EXPECT_TRUE(static_cast(Result)); return *Result; diff --git a/clang/unittests/libclang/LibclangTest.cpp b/clang/unittests/libclang/LibclangTest.cpp index 60904bc3baf89e1aae7970deed12c06dac69335b..87075a46d75187b0d8a1e2c3fa4be877a93f00ae 100644 --- a/clang/unittests/libclang/LibclangTest.cpp +++ b/clang/unittests/libclang/LibclangTest.cpp @@ -451,8 +451,8 @@ public: const auto Filename = llvm::sys::path::filename(File->path()); EXPECT_EQ(Filename.size(), std::strlen("preamble-%%%%%%.pch")); - EXPECT_TRUE(Filename.startswith("preamble-")); - EXPECT_TRUE(Filename.endswith(".pch")); + EXPECT_TRUE(Filename.starts_with("preamble-")); + EXPECT_TRUE(Filename.ends_with(".pch")); const auto Status = File->status(); ASSERT_TRUE(Status); @@ -659,7 +659,7 @@ TEST_F(LibclangReparseTest, FileName) { clang_disposeString(cxname); cxname = clang_File_tryGetRealPathName(cxf); - ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp")); + ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).ends_with("main.cpp")); clang_disposeString(cxname); } diff --git a/clang/utils/TableGen/ASTTableGen.cpp b/clang/utils/TableGen/ASTTableGen.cpp index 60f563d9a1ffc8b8eed2ff1d81251805a1604e19..54288ff6a03be3b7203bec275d167d35d95f7f39 100644 --- a/clang/utils/TableGen/ASTTableGen.cpp +++ b/clang/utils/TableGen/ASTTableGen.cpp @@ -33,7 +33,7 @@ llvm::StringRef clang::tblgen::HasProperties::getName() const { static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) { StringRef nodeName = node->getName(); - if (!nodeName.endswith(suffix)) { + if (!nodeName.ends_with(suffix)) { PrintFatalError(node->getLoc(), Twine("name of node doesn't end in ") + suffix); } diff --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp index fae889d68346c33c8ad22c8ad67eb63843722562..f0bd0865c1c8b56fac081ea70f4e4a433c90583e 100644 --- a/clang/utils/TableGen/MveEmitter.cpp +++ b/clang/utils/TableGen/MveEmitter.cpp @@ -882,7 +882,7 @@ public: } else if (V->varnameUsed()) { std::string Type = V->typeName(); OS << V->typeName(); - if (!StringRef(Type).endswith("*")) + if (!StringRef(Type).ends_with("*")) OS << " "; OS << V->varname() << " = "; } @@ -1680,7 +1680,7 @@ void EmitterBase::EmitBuiltinCG(raw_ostream &OS) { for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { StringRef Type = MG.ParamTypes[i]; OS << " " << Type; - if (!Type.endswith("*")) + if (!Type.ends_with("*")) OS << " "; OS << " Param" << utostr(i) << ";\n"; } @@ -1833,7 +1833,7 @@ void MveEmitter::EmitHeader(raw_ostream &OS) { // prototype. std::string RetTypeName = Int.returnType()->cName(); - if (!StringRef(RetTypeName).endswith("*")) + if (!StringRef(RetTypeName).ends_with("*")) RetTypeName += " "; std::vector ArgTypeNames; @@ -2078,7 +2078,7 @@ void CdeEmitter::EmitHeader(raw_ostream &OS) { // Make strings for the types involved in the function's // prototype. std::string RetTypeName = Int.returnType()->cName(); - if (!StringRef(RetTypeName).endswith("*")) + if (!StringRef(RetTypeName).ends_with("*")) RetTypeName += " "; std::vector ArgTypeNames; diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp index 4b112972a1ec98195a91983a2040a8e4196a17a9..e5f79ba99c5c81c5ec1c121c1241992679448758 100644 --- a/clang/utils/TableGen/NeonEmitter.cpp +++ b/clang/utils/TableGen/NeonEmitter.cpp @@ -593,6 +593,8 @@ public: // Emit arm_bf16.h.inc void runBF16(raw_ostream &o); + void runVectorTypes(raw_ostream &o); + // Emit all the __builtin prototypes used in arm_neon.h, arm_fp16.h and // arm_bf16.h void runHeader(raw_ostream &o); @@ -2355,13 +2357,7 @@ void NeonEmitter::run(raw_ostream &OS) { OS << "#include \n"; - // Emit NEON-specific scalar typedefs. - OS << "typedef float float32_t;\n"; - OS << "typedef __fp16 float16_t;\n"; - - OS << "#ifdef __aarch64__\n"; - OS << "typedef double float64_t;\n"; - OS << "#endif\n\n"; + OS << "#include \n"; // For now, signedness of polynomial types depends on target OS << "#ifdef __aarch64__\n"; @@ -2374,10 +2370,7 @@ void NeonEmitter::run(raw_ostream &OS) { OS << "typedef int16_t poly16_t;\n"; OS << "typedef int64_t poly64_t;\n"; OS << "#endif\n"; - - emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl", OS); - - emitNeonTypeDefs("bQb", OS); + emitNeonTypeDefs("PcQPcPsQPsPlQPl", OS); OS << "#define __ai static __inline__ __attribute__((__always_inline__, " "__nodebug__))\n\n"; @@ -2546,6 +2539,38 @@ void NeonEmitter::runFP16(raw_ostream &OS) { OS << "#endif /* __ARM_FP16_H */\n"; } +void NeonEmitter::runVectorTypes(raw_ostream &OS) { + OS << "/*===---- arm_vector_types - ARM vector type " + "------===\n" + " *\n" + " *\n" + " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " + "Exceptions.\n" + " * See https://llvm.org/LICENSE.txt for license information.\n" + " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" + " *\n" + " *===-----------------------------------------------------------------" + "------===\n" + " */\n\n"; + OS << "#if !defined(__ARM_NEON_H) && !defined(__ARM_SVE_H)\n"; + OS << "#error \"This file should not be used standalone. Please include" + " arm_neon.h or arm_sve.h instead\"\n\n"; + OS << "#endif\n"; + OS << "#ifndef __ARM_NEON_TYPES_H\n"; + OS << "#define __ARM_NEON_TYPES_H\n"; + OS << "typedef float float32_t;\n"; + OS << "typedef __fp16 float16_t;\n"; + + OS << "#ifdef __aarch64__\n"; + OS << "typedef double float64_t;\n"; + OS << "#endif\n\n"; + + emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQd", OS); + + emitNeonTypeDefs("bQb", OS); + OS << "#endif // __ARM_NEON_TYPES_H\n"; +} + void NeonEmitter::runBF16(raw_ostream &OS) { OS << "/*===---- arm_bf16.h - ARM BF16 intrinsics " "-----------------------------------===\n" @@ -2640,6 +2665,10 @@ void clang::EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { NeonEmitter(Records).runHeader(OS); } +void clang::EmitVectorTypes(RecordKeeper &Records, raw_ostream &OS) { + NeonEmitter(Records).runVectorTypes(OS); +} + void clang::EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { llvm_unreachable("Neon test generation no longer implemented!"); } diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index b8a1fb4bab0f499d74cc1e0c2cf9128c32d8754d..9361b99506377d126da4e19ae8c071a98c9d07f7 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -97,6 +97,7 @@ public: bool isScalar() const { return NumVectors == 0; } bool isVector() const { return NumVectors > 0; } bool isScalableVector() const { return isVector() && IsScalable; } + bool isFixedLengthVector() const { return isVector() && !IsScalable; } bool isChar() const { return ElementBitwidth == 8; } bool isVoid() const { return Void & !Pointer; } bool isDefault() const { return DefaultType; } @@ -466,7 +467,8 @@ std::string SVEType::builtin_str() const { return S; } - assert(isScalableVector() && "Unsupported type"); + if (isFixedLengthVector()) + return "V" + utostr(getNumElements() * NumVectors) + S; return "q" + utostr(getNumElements() * NumVectors) + S; } @@ -499,7 +501,7 @@ std::string SVEType::str() const { if (!isScalarPredicate() && !isPredicateVector() && !isSvcount()) S += utostr(ElementBitwidth); - if (!isScalableVector() && isVector()) + if (isFixedLengthVector()) S += "x" + utostr(getNumElements()); if (NumVectors > 1) S += "x" + utostr(NumVectors); @@ -610,6 +612,11 @@ void SVEType::applyModifier(char Mod) { Bitwidth = 16; ElementBitwidth = 1; break; + case '{': + IsScalable = false; + Bitwidth = 128; + NumVectors = 1; + break; case 's': case 'a': Bitwidth = ElementBitwidth; @@ -1286,6 +1293,7 @@ void SVEEmitter::createHeader(raw_ostream &OS) { OS << "typedef __SVBfloat16_t svbfloat16_t;\n"; OS << "#include \n"; + OS << "#include \n"; OS << "typedef __SVFloat32_t svfloat32_t;\n"; OS << "typedef __SVFloat64_t svfloat64_t;\n"; @@ -1730,4 +1738,5 @@ void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) { SVEEmitter(Records).createSMERangeChecks(OS); } + } // End namespace clang diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index 7efb6c731d3e5ee2c1f202f556d1c6eee62e4f31..3ad46b95984ec752eb033b78fb8262ad109ba5d2 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -73,6 +73,7 @@ enum ActionType { GenArmNeon, GenArmFP16, GenArmBF16, + GenArmVectorType, GenArmNeonSema, GenArmNeonTest, GenArmMveHeader, @@ -229,6 +230,8 @@ cl::opt Action( clEnumValN(GenArmNeon, "gen-arm-neon", "Generate arm_neon.h for clang"), clEnumValN(GenArmFP16, "gen-arm-fp16", "Generate arm_fp16.h for clang"), clEnumValN(GenArmBF16, "gen-arm-bf16", "Generate arm_bf16.h for clang"), + clEnumValN(GenArmVectorType, "gen-arm-vector-type", + "Generate arm_vector_types.h for clang"), clEnumValN(GenArmNeonSema, "gen-arm-neon-sema", "Generate ARM NEON sema support for clang"), clEnumValN(GenArmNeonTest, "gen-arm-neon-test", @@ -449,6 +452,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenArmFP16: EmitFP16(Records, OS); break; + case GenArmVectorType: + EmitVectorTypes(Records, OS); + break; case GenArmBF16: EmitBF16(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index d8f447069376bca352b74dbd55df337573078562..ef255612f4b8b8537142e56cdaf70d89bddcf8aa 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -97,6 +97,7 @@ void EmitNeon(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitFP16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitBF16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitNeonSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitVectorTypes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitNeonTest(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitSveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); diff --git a/clang/www/analyzer/faq.html b/clang/www/analyzer/faq.html index 72ca27eb8c36b907e3306d4d3040634bf3a9d551..156d383db2f2343d26d8190b1348eff9f614dba7 100644 --- a/clang/www/analyzer/faq.html +++ b/clang/www/analyzer/faq.html @@ -195,12 +195,45 @@ int foo(int length) {

Q: How can I suppress a specific analyzer warning?

-

There is currently no solid mechanism for suppressing an analyzer warning, -although this is currently being investigated. When you encounter an analyzer -bug/false positive, check if it's one of the issues discussed above or if the -analyzer annotations can -resolve the issue. Second, please report it to -help us improve user experience. As the last resort, consider using __clang_analyzer__ macro +

When you encounter an analyzer bug/false positive, check if it's one of the +issues discussed above or if the analyzer +annotations can +resolve the issue by helping the static analyzer understand the code better. +Second, please report it to help us improve +user experience.

+ +

Sometimes there's really no "good" way to eliminate the issue. In such cases +you can "silence" it directly by annotating the problematic line of code with +the help of Clang attribute 'suppress': + +

+int foo() {
+  int *x = nullptr;
+  ...
+  [[clang::suppress]] {
+    // all warnings in this scope are suppressed
+    int y = *x;
+  }
+
+  // null pointer dereference warning suppressed on the next line
+  [[clang::suppress]]
+  return *x
+}
+
+int bar(bool coin_flip) {
+  // suppress all memory leak warnings about this allocation
+  [[clang::suppress]]
+  int *result = (int *)malloc(sizeof(int));
+
+  if (coin_flip)
+    return 0;      // including this leak path
+
+  return *result;  // as well as this leak path
+}
+
+ + +

You can also consider using __clang_analyzer__ macro described below.

Q: How can I selectively exclude code the analyzer examines?

diff --git a/compiler-rt/include/sanitizer/hwasan_interface.h b/compiler-rt/include/sanitizer/hwasan_interface.h index abe310c0666948300c2c4a8f352ec60d89456870..407f488a24a617f67822b57b1e1b623f0c53426b 100644 --- a/compiler-rt/include/sanitizer/hwasan_interface.h +++ b/compiler-rt/include/sanitizer/hwasan_interface.h @@ -44,6 +44,10 @@ void SANITIZER_CDECL __hwasan_tag_memory(const volatile void *p, void *SANITIZER_CDECL __hwasan_tag_pointer(const volatile void *p, unsigned char tag); +/// Get tag from the pointer. +unsigned char SANITIZER_CDECL +__hwasan_get_tag_from_pointer(const volatile void *p); + // Set memory tag from the current SP address to the given address to zero. // This is meant to annotate longjmp and other non-local jumps. // This function needs to know the (almost) exact destination frame address; diff --git a/compiler-rt/lib/asan/asan_fuchsia.cpp b/compiler-rt/lib/asan/asan_fuchsia.cpp index 2b15504123bee7c95908ffb7dc0f99290d469327..12625e9d75833de9537c29cb366aabb5be30e773 100644 --- a/compiler-rt/lib/asan/asan_fuchsia.cpp +++ b/compiler-rt/lib/asan/asan_fuchsia.cpp @@ -240,6 +240,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { // So this doesn't install any atexit hook like on other platforms. void InstallAtExitCheckLeaks() {} +void InstallAtForkHandler() {} + } // namespace __asan namespace __lsan { diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h index 5b97e77882cd67482e16947545f0290b81490d02..2944ebe213b5d56991a2d954c7871e6242bf1209 100644 --- a/compiler-rt/lib/asan/asan_internal.h +++ b/compiler-rt/lib/asan/asan_internal.h @@ -126,6 +126,7 @@ void *AsanDlSymNext(const char *sym); bool HandleDlopenInit(); void InstallAtExitCheckLeaks(); +void InstallAtForkHandler(); #define ASAN_ON_ERROR() \ if (&__asan_on_error) \ diff --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp index e1f66641617cc14b4336ccc25d012ff1194d5772..206551b6ef910e5a806dfa33dd06af90adcaa152 100644 --- a/compiler-rt/lib/asan/asan_posix.cpp +++ b/compiler-rt/lib/asan/asan_posix.cpp @@ -148,6 +148,30 @@ void PlatformTSDDtor(void *tsd) { } #endif +void InstallAtForkHandler() { + auto before = []() { + if (CAN_SANITIZE_LEAKS) { + __lsan::LockGlobal(); + } + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the + // stuff we need. + __lsan::LockThreads(); + __lsan::LockAllocator(); + StackDepotLockAll(); + }; + auto after = []() { + StackDepotUnlockAll(); + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock + // the stuff we need. + __lsan::UnlockAllocator(); + __lsan::UnlockThreads(); + if (CAN_SANITIZE_LEAKS) { + __lsan::UnlockGlobal(); + } + }; + pthread_atfork(before, after, after); +} + void InstallAtExitCheckLeaks() { if (CAN_SANITIZE_LEAKS) { if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index 04ecd20821fa6deea8a38fcceb85bf8e49fa0435..a61deed7382b0291c212ef4c3a0c7fe5875d8cfd 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -71,16 +71,16 @@ static void CheckUnwind() { } // -------------------------- Globals --------------------- {{{1 -static int asan_inited = 0; -static int asan_init_is_running = 0; +static StaticSpinMutex asan_inited_mutex; +static atomic_uint8_t asan_inited = {0}; -static void SetAsanInited() { asan_inited = 1; } - -static void SetAsanInitIsRunning(u32 val) { asan_init_is_running = val; } - -bool AsanInited() { return asan_inited == 1; } +static void SetAsanInited() { + atomic_store(&asan_inited, 1, memory_order_release); +} -static bool AsanInitIsRunning() { return asan_init_is_running == 1; } +bool AsanInited() { + return atomic_load(&asan_inited, memory_order_acquire) == 1; +} bool replace_intrin_cached; @@ -390,12 +390,10 @@ void PrintAddressSpaceLayout() { kHighShadowBeg > kMidMemEnd); } -static void AsanInitInternal() { +static bool AsanInitInternal() { if (LIKELY(AsanInited())) - return; + return true; SanitizerToolName = "AddressSanitizer"; - CHECK(!AsanInitIsRunning() && "ASan init calls itself!"); - SetAsanInitIsRunning(1); CacheBinaryName(); @@ -408,9 +406,8 @@ static void AsanInitInternal() { // Stop performing init at this point if we are being loaded via // dlopen() and the platform supports it. if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) { - SetAsanInitIsRunning(0); VReport(1, "AddressSanitizer init is being performed for dlopen().\n"); - return; + return false; } AsanCheckIncompatibleRT(); @@ -471,7 +468,6 @@ static void AsanInitInternal() { // should be set to 1 prior to initializing the threads. replace_intrin_cached = flags()->replace_intrin; SetAsanInited(); - SetAsanInitIsRunning(0); if (flags()->atexit) Atexit(asan_atexit); @@ -497,6 +493,8 @@ static void AsanInitInternal() { InstallAtExitCheckLeaks(); } + InstallAtForkHandler(); + #if CAN_SANITIZE_UB __ubsan::InitAsPlugin(); #endif @@ -515,22 +513,27 @@ static void AsanInitInternal() { VReport(1, "AddressSanitizer Init done\n"); WaitForDebugger(flags()->sleep_after_init, "after init"); + + return true; } // Initialize as requested from some part of ASan runtime library (interceptors, // allocator, etc). void AsanInitFromRtl() { - CHECK(!AsanInitIsRunning()); - if (UNLIKELY(!AsanInited())) - AsanInitInternal(); + if (LIKELY(AsanInited())) + return; + SpinMutexLock lock(&asan_inited_mutex); + AsanInitInternal(); } bool TryAsanInitFromRtl() { - if (UNLIKELY(AsanInitIsRunning())) + if (LIKELY(AsanInited())) + return true; + if (!asan_inited_mutex.TryLock()) return false; - if (UNLIKELY(!AsanInited())) - AsanInitInternal(); - return true; + bool result = AsanInitInternal(); + asan_inited_mutex.Unlock(); + return result; } #if ASAN_DYNAMIC @@ -603,7 +606,7 @@ static void UnpoisonFakeStack() { using namespace __asan; void NOINLINE __asan_handle_no_return() { - if (AsanInitIsRunning()) + if (UNLIKELY(!AsanInited())) return; if (!PlatformUnpoisonStacks()) @@ -633,7 +636,7 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) { // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { AsanActivate(); - AsanInitInternal(); + AsanInitFromRtl(); } void __asan_version_mismatch_check() { diff --git a/compiler-rt/lib/asan/asan_win.cpp b/compiler-rt/lib/asan/asan_win.cpp index d5a30f471e2b0d45de18820b983a15d662dfbb56..f16ce677618e4fe58d895f94fc8fb2a1eeeb93f0 100644 --- a/compiler-rt/lib/asan/asan_win.cpp +++ b/compiler-rt/lib/asan/asan_win.cpp @@ -203,6 +203,8 @@ void InitializePlatformInterceptors() { void InstallAtExitCheckLeaks() {} +void InstallAtForkHandler() {} + void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp index 2f6cb10caf1be602b8aad0fb985a056e7bd6b067..52780becbdb264394b6bbc04a607b93b361bb752 100644 --- a/compiler-rt/lib/hwasan/hwasan.cpp +++ b/compiler-rt/lib/hwasan/hwasan.cpp @@ -678,6 +678,8 @@ uptr __hwasan_tag_pointer(uptr p, u8 tag) { return AddTagToPointer(p, tag); } +u8 __hwasan_get_tag_from_pointer(uptr p) { return GetTagFromPointer(p); } + void __hwasan_handle_longjmp(const void *sp_dst) { uptr dst = (uptr)sp_dst; // HWASan does not support tagged SP. diff --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h index 37ef482228511064d1e16ea8bd6055e2f0f5d582..df21375e81671fb13165f7334da1e428db9cc284 100644 --- a/compiler-rt/lib/hwasan/hwasan.h +++ b/compiler-rt/lib/hwasan/hwasan.h @@ -104,9 +104,9 @@ static inline void *UntagPtr(const void *tagged_ptr) { } static inline uptr AddTagToPointer(uptr p, tag_t tag) { - return InTaggableRegion(p) - ? ((p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift)) - : p; + return InTaggableRegion(p) ? ((p & ~kAddressTagMask) | + ((uptr)(tag & kTagMask) << kAddressTagShift)) + : p; } namespace __hwasan { diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h index e7804cc4903343238511e993d4234fa6ffbfa2bc..8f2f77dad917d27fdf77559ac9a4b25e51a42932 100644 --- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -160,6 +160,9 @@ void __hwasan_tag_memory(uptr p, u8 tag, uptr sz); SANITIZER_INTERFACE_ATTRIBUTE uptr __hwasan_tag_pointer(uptr p, u8 tag); +SANITIZER_INTERFACE_ATTRIBUTE +u8 __hwasan_get_tag_from_pointer(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_tag_mismatch(uptr addr, u8 ts); diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp index f01fa427641347b8a44de7da8260ecaf3b12a80e..3271a955e7ed102de886e750c631a62597f9f555 100644 --- a/compiler-rt/lib/hwasan/hwasan_linux.cpp +++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp @@ -523,12 +523,24 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { void HwasanInstallAtForkHandler() { auto before = []() { - HwasanAllocatorLock(); + if (CAN_SANITIZE_LEAKS) { + __lsan::LockGlobal(); + } + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the + // stuff we need. + __lsan::LockThreads(); + __lsan::LockAllocator(); StackDepotLockAll(); }; auto after = []() { StackDepotUnlockAll(); - HwasanAllocatorUnlock(); + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock + // the stuff we need. + __lsan::UnlockAllocator(); + __lsan::UnlockThreads(); + if (CAN_SANITIZE_LEAKS) { + __lsan::UnlockGlobal(); + } }; pthread_atfork(before, after, after); } diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index ce36547580e6e60ccdaaa6bfb697d50c47ebac22..3e14a718513d7f3d1c26cb2a59bfd6168a16930c 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -68,6 +68,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, } Print("Creating : "); } + ClearShadowForThreadStackAndTLS(); } void Thread::InitStackRingBuffer(uptr stack_buffer_start, diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp index 6b223603c6a79c4f5c1645386f3ad98edadc6946..7a27b600f203f7f9e397cfebd7b69c302956c8cf 100644 --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -101,6 +101,7 @@ extern "C" void __lsan_init() { InstallDeadlySignalHandlers(LsanOnDeadlySignal); InitializeMainThread(); InstallAtExitCheckLeaks(); + InstallAtForkHandler(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); diff --git a/compiler-rt/lib/lsan/lsan.h b/compiler-rt/lib/lsan/lsan.h index 757edec8e104f906206520ce6207d99b6a02cd06..0074ad5308785cf875f2dde66c5269f1e0612dac 100644 --- a/compiler-rt/lib/lsan/lsan.h +++ b/compiler-rt/lib/lsan/lsan.h @@ -40,6 +40,7 @@ void InitializeInterceptors(); void ReplaceSystemMalloc(); void LsanOnDeadlySignal(int signo, void *siginfo, void *context); void InstallAtExitCheckLeaks(); +void InstallAtForkHandler(); #define ENSURE_LSAN_INITED \ do { \ diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index 8b1af5b629fbce10edbaaf7e23092b4d324a1757..e24839c984b346e087a511d4c1311acfa5a3e20d 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -42,6 +42,9 @@ namespace __lsan { // also to protect the global list of root regions. static Mutex global_mutex; +void LockGlobal() SANITIZER_ACQUIRE(global_mutex) { global_mutex.Lock(); } +void UnlockGlobal() SANITIZER_RELEASE(global_mutex) { global_mutex.Unlock(); } + Flags lsan_flags; void DisableCounterUnderflow() { diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index d3e768363e93b96e9162ea2ea165752cd231471e..c598b62105873e36bde865f71f2c510cbbff431b 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -120,6 +120,10 @@ void GetRunningThreadsLocked(InternalMmapVector *threads); void LockAllocator(); void UnlockAllocator(); +// Lock/unlock global mutext. +void LockGlobal(); +void UnlockGlobal(); + // Returns the address range occupied by the global allocator object. void GetAllocatorGlobalRange(uptr *begin, uptr *end); // If p points into a chunk that has been allocated to the user, returns its diff --git a/compiler-rt/lib/lsan/lsan_fuchsia.cpp b/compiler-rt/lib/lsan/lsan_fuchsia.cpp index 4edac9757a9c4927649acd1e15ecf8f664566aa0..ba59bc9b71e3325d28802ef262b55ae1fb14a1cd 100644 --- a/compiler-rt/lib/lsan/lsan_fuchsia.cpp +++ b/compiler-rt/lib/lsan/lsan_fuchsia.cpp @@ -80,6 +80,7 @@ void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) { // On Fuchsia, leak detection is done by a special hook after atexit hooks. // So this doesn't install any atexit hook like on other platforms. void InstallAtExitCheckLeaks() {} +void InstallAtForkHandler() {} // ASan defines this to check its `halt_on_error` flag. bool UseExitcodeOnLeak() { return true; } diff --git a/compiler-rt/lib/lsan/lsan_posix.cpp b/compiler-rt/lib/lsan/lsan_posix.cpp index d99e1cc0105ef768487d44e3ef6c954be358452a..3677f0141a2f02f3a2048185bac2e371adfbb2e0 100644 --- a/compiler-rt/lib/lsan/lsan_posix.cpp +++ b/compiler-rt/lib/lsan/lsan_posix.cpp @@ -14,11 +14,13 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_POSIX -#include "lsan.h" -#include "lsan_allocator.h" -#include "lsan_thread.h" -#include "sanitizer_common/sanitizer_stacktrace.h" -#include "sanitizer_common/sanitizer_tls_get_addr.h" +# include + +# include "lsan.h" +# include "lsan_allocator.h" +# include "lsan_thread.h" +# include "sanitizer_common/sanitizer_stacktrace.h" +# include "sanitizer_common/sanitizer_tls_get_addr.h" namespace __lsan { @@ -98,6 +100,22 @@ void InstallAtExitCheckLeaks() { Atexit(DoLeakCheck); } +void InstallAtForkHandler() { + auto before = []() { + LockGlobal(); + LockThreads(); + LockAllocator(); + StackDepotLockAll(); + }; + auto after = []() { + StackDepotUnlockAll(); + UnlockAllocator(); + UnlockThreads(); + UnlockGlobal(); + }; + pthread_atfork(before, after, after); +} + } // namespace __lsan #endif // SANITIZER_POSIX diff --git a/compiler-rt/lib/msan/msan.cpp b/compiler-rt/lib/msan/msan.cpp index c4f47dea1104321198fab79f4e6d5a47d5bd0732..3cdf10c149902c276282ff684fb1e864290dd3bd 100644 --- a/compiler-rt/lib/msan/msan.cpp +++ b/compiler-rt/lib/msan/msan.cpp @@ -449,6 +449,7 @@ void __msan_init() { __sanitizer_set_report_path(common_flags()->log_path); InitializeInterceptors(); + InstallAtForkHandler(); CheckASLR(); InitTlsSize(); InstallDeadlySignalHandlers(MsanOnDeadlySignal); diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h index b3a9c641b4fb298c7ed60488081b46ddbe560657..25fa2212bdadd31769a697ea1d5d8b55e2ed9287 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -336,6 +336,8 @@ void *MsanTSDGet(); void MsanTSDSet(void *tsd); void MsanTSDDtor(void *tsd); +void InstallAtForkHandler(); + } // namespace __msan #endif // MSAN_H diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp index c3b0f8512e82d83755ddff431980a9e7db520a0d..72a7f980d39fb03c6a5148adcccfab1855621d72 100644 --- a/compiler-rt/lib/msan/msan_allocator.cpp +++ b/compiler-rt/lib/msan/msan_allocator.cpp @@ -159,6 +159,10 @@ void MsanAllocatorInit() { max_malloc_size = kMaxAllowedMallocSize; } +void LockAllocator() { allocator.ForceLock(); } + +void UnlockAllocator() { allocator.ForceUnlock(); } + AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) { CHECK(ms); CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache)); diff --git a/compiler-rt/lib/msan/msan_allocator.h b/compiler-rt/lib/msan/msan_allocator.h index 364331d964068e562379a141833955eb2915fe16..c2a38a401f3b6b02383db3da5045899b3557418c 100644 --- a/compiler-rt/lib/msan/msan_allocator.h +++ b/compiler-rt/lib/msan/msan_allocator.h @@ -28,5 +28,8 @@ struct MsanThreadLocalMallocStorage { MsanThreadLocalMallocStorage() {} }; +void LockAllocator(); +void UnlockAllocator(); + } // namespace __msan #endif // MSAN_ALLOCATOR_H diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index c2d740e7762b4bfdb0e012e340384667f606e229..2c9f2c01e14b061be12e4effabfeb266d91bc875 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -1326,24 +1326,6 @@ static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) { return res; } -static void BeforeFork() { - StackDepotLockAll(); - ChainedOriginDepotLockAll(); -} - -static void AfterFork() { - ChainedOriginDepotUnlockAll(); - StackDepotUnlockAll(); -} - -INTERCEPTOR(int, fork, void) { - ENSURE_MSAN_INITED(); - BeforeFork(); - int pid = REAL(fork)(); - AfterFork(); - return pid; -} - // NetBSD ships with openpty(3) in -lutil, that needs to be prebuilt explicitly // with MSan. #if SANITIZER_LINUX @@ -1933,7 +1915,6 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(atexit); INTERCEPT_FUNCTION(__cxa_atexit); INTERCEPT_FUNCTION(shmat); - INTERCEPT_FUNCTION(fork); MSAN_MAYBE_INTERCEPT_OPENPTY; MSAN_MAYBE_INTERCEPT_FORKPTY; diff --git a/compiler-rt/lib/msan/msan_linux.cpp b/compiler-rt/lib/msan/msan_linux.cpp index bced00ba242822414018b39859c92dcbf4406ce6..04af6f4b27ac8921c2fd52a9b6b36a0f25573366 100644 --- a/compiler-rt/lib/msan/msan_linux.cpp +++ b/compiler-rt/lib/msan/msan_linux.cpp @@ -14,23 +14,25 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -#include "msan.h" -#include "msan_report.h" -#include "msan_thread.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_procmaps.h" +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include "msan.h" +# include "msan_allocator.h" +# include "msan_chained_origin_depot.h" +# include "msan_report.h" +# include "msan_thread.h" +# include "sanitizer_common/sanitizer_common.h" +# include "sanitizer_common/sanitizer_procmaps.h" +# include "sanitizer_common/sanitizer_stackdepot.h" namespace __msan { @@ -256,6 +258,22 @@ void MsanTSDDtor(void *tsd) { } #endif +void InstallAtForkHandler() { + auto before = []() { + // Usually we lock ThreadRegistry, but msan does not have one. + LockAllocator(); + StackDepotLockAll(); + ChainedOriginDepotLockAll(); + }; + auto after = []() { + ChainedOriginDepotUnlockAll(); + StackDepotUnlockAll(); + UnlockAllocator(); + // Usually we unlock ThreadRegistry, but msan does not have one. + }; + pthread_atfork(before, after, after); +} + } // namespace __msan #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/compiler-rt/test/hwasan/TestCases/tag-ptr.cpp b/compiler-rt/test/hwasan/TestCases/tag-ptr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f00e7913bb155d8ad3c835c1004ec4ff154697a --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/tag-ptr.cpp @@ -0,0 +1,24 @@ +// RUN: %clangxx_hwasan -O0 %s -o %t && %run %t + +#include +#include +#include +#include +#include + +int main() { + auto p = std::make_unique(); + std::set ptrs; + for (unsigned i = 0;; ++i) { + void *ptr = __hwasan_tag_pointer(p.get(), i); + if (!ptrs.insert(ptr).second) + break; + fprintf(stderr, "%p, %u, %u\n", ptr, i, __hwasan_get_tag_from_pointer(ptr)); + assert(__hwasan_get_tag_from_pointer(ptr) == i); + } +#ifdef __x86_64__ + assert(ptrs.size() == 8); +#else + assert(ptrs.size() == 256); +#endif +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c new file mode 100644 index 0000000000000000000000000000000000000000..1b4a0ad6140db40f8bf94a3c3e6e51d0e528cfd2 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c @@ -0,0 +1,93 @@ +// RUN: %clang -O0 %s -o %t && %env_tool_opts=die_after_fork=0 %run %t + +// The test uses pthread barriers which are not available on Darwin. +// UNSUPPORTED: darwin + +// Forking in multithread environment is unsupported. However we already have +// some workarounds, and will add more, so this is the test. +// The test try to check two things: +// 1. Internal mutexes used by `inparent` thread do not deadlock `inchild` +// thread. +// 2. Stack poisoned by `inparent` is not poisoned in `inchild` thread. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sanitizer_common/sanitizer_specific.h" + +static const size_t kBufferSize = 1 << 20; + +pthread_barrier_t bar; + +// Without appropriate workarounds this code can cause the forked process to +// start with locked internal mutexes. +void ShouldNotDeadlock() { + // Don't bother with leaks, we try to trigger allocator or lsan deadlock. + __lsan_disable(); + void *volatile p = malloc(10); + __lsan_do_recoverable_leak_check(); + free(p); + __lsan_enable(); +} + +// Prevent stack buffer cleanup by instrumentation. +#define NOSAN __attribute__((no_sanitize("address", "hwaddress", "memory"))) + +NOSAN static void *inparent(void *arg) { + char t[kBufferSize]; + make_mem_bad(t, sizeof(t)); + + pthread_barrier_wait(&bar); + + for (;;) + ShouldNotDeadlock(); + + return 0; +} + +NOSAN static void *inchild(void *arg) { + char t[kBufferSize]; + check_mem_is_good(t, sizeof(t)); + ShouldNotDeadlock(); + return 0; +} + +int main(void) { +#if __has_feature(hwaddress_sanitizer) + __hwasan_enable_allocator_tagging(); +#endif + + pid_t pid; + + pthread_barrier_init(&bar, NULL, 2); + pthread_t thread_id; + while (pthread_create(&thread_id, 0, &inparent, 0) != 0) { + } + pthread_barrier_wait(&bar); + + pid = fork(); + switch (pid) { + case -1: + perror("fork"); + return -1; + case 0: + while (pthread_create(&thread_id, 0, &inchild, 0) != 0) { + } + break; + default: { + int status; + while (waitpid(-1, &status, __WALL) != pid) { + } + assert(WIFEXITED(status) && WEXITSTATUS(status) == 0); + break; + } + } + + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/sanitizer_specific.h b/compiler-rt/test/sanitizer_common/sanitizer_specific.h index 1a802020cfd66836d7dec9aebd46f9c46ba9885f..99a4dd98c614a1eaed0c979606f5e8d3f69f08f0 100644 --- a/compiler-rt/test/sanitizer_common/sanitizer_specific.h +++ b/compiler-rt/test/sanitizer_common/sanitizer_specific.h @@ -1,6 +1,12 @@ #ifndef __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__ #define __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__ +#include + +__attribute__((weak)) int __lsan_do_recoverable_leak_check() { return 0; } +__attribute__((weak)) void __lsan_disable(void) {} +__attribute__((weak)) void __lsan_enable(void) {} + #ifndef __has_feature # define __has_feature(x) 0 #endif @@ -10,6 +16,8 @@ static void check_mem_is_good(void *p, size_t s) { __msan_check_mem_is_initialized(p, s); } +static void make_mem_good(void *p, size_t s) { __msan_unpoison(p, s); } +static void make_mem_bad(void *p, size_t s) { __msan_poison(p, s); } #elif __has_feature(address_sanitizer) # include # include @@ -17,8 +25,40 @@ static void check_mem_is_good(void *p, size_t s) { if (__asan_region_is_poisoned(p, s)) abort(); } +static void make_mem_good(void *p, size_t s) { + __asan_unpoison_memory_region(p, s); +} +static void make_mem_bad(void *p, size_t s) { + __asan_poison_memory_region(p, s); +} +#elif __has_feature(hwaddress_sanitizer) +# include +# include +static void check_mem_is_good(void *p, size_t s) { + if (__hwasan_test_shadow(p, s) != -1) + abort(); +} +static void make_mem_good(void *p, size_t s) { + __hwasan_tag_memory(p, __hwasan_get_tag_from_pointer(p), s); +} +static void make_mem_bad(void *p, size_t s) { + uint8_t tag = ~__hwasan_get_tag_from_pointer(p); + if (!tag) { + // Nothing wrong with tag zero, but non-zero tags help to detect never + // tagged memory. + tag = 1; + } + __hwasan_tag_memory(p, tag, s); + // With misaligned `p` or short granules we can't guarantee tag mismatch. + if (__hwasan_test_shadow(p, s) != 0) + abort(); + if (s > 1 && __hwasan_test_shadow(((char *)p) + s - 1, 1) != 0) + abort(); +} #else static void check_mem_is_good(void *p, size_t s) {} +static void make_mem_good(void *p, size_t s) {} +static void make_mem_bad(void *p, size_t s) {} #endif -#endif // __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__ \ No newline at end of file +#endif // __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__ diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index 980fde881373249d9127c8e965e329ccea964194..b91303387f3d710d6bf4159f0ae433bca7cf261c 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -280,6 +280,10 @@ public: // Miscellaneous //===--------------------------------------------------------------------===// + /// Generate IR for Evaluation \p eval. + virtual void genEval(pft::Evaluation &eval, + bool unstructuredContext = true) = 0; + /// Return options controlling lowering behavior. const Fortran::lower::LoweringOptions &getLoweringOptions() const { return loweringOptions; diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h index 2abcc6547bbabf6343272695b7bd257f9fa38742..a79c67dfe6de862be6bd704d445e1757cd0781f8 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRType.h +++ b/flang/include/flang/Optimizer/Dialect/FIRType.h @@ -118,8 +118,8 @@ inline bool isa_derived(mlir::Type t) { return t.isa(); } /// Is `t` type(c_ptr) or type(c_funptr)? inline bool isa_builtin_cptr_type(mlir::Type t) { if (auto recTy = t.dyn_cast_or_null()) - return recTy.getName().endswith("T__builtin_c_ptr") || - recTy.getName().endswith("T__builtin_c_funptr"); + return recTy.getName().ends_with("T__builtin_c_ptr") || + recTy.getName().ends_with("T__builtin_c_funptr"); return false; } diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp index a6b8f1a9d29ee4746ebf67c39bb3d4f154178b1f..555ac91f6dc7c077cdfec74390b0b4e631a9ef6c 100644 --- a/flang/lib/Frontend/CompilerInstance.cpp +++ b/flang/lib/Frontend/CompilerInstance.cpp @@ -257,7 +257,7 @@ getExplicitAndImplicitNVPTXTargetFeatures(clang::DiagnosticsEngine &diags, llvm::StringRef userKeyString(llvm::StringRef(userFeature).drop_front(1)); implicitFeaturesMap[userKeyString.str()] = (userFeature[0] == '+'); // Check if the user provided a PTX version - if (userKeyString.startswith("ptx")) + if (userKeyString.starts_with("ptx")) ptxVer = true; } diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index bc09dec17b7ae341285d0278dcffc19be1ae8786..4cad640562c619067002a9a6bcff3057b5873613 100644 --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -131,7 +131,7 @@ updateDiagEngineForOptRemarks(clang::DiagnosticsEngine &diagsEng, // Check to see if this opt starts with "no-", if so, this is a // negative form of the option. - bool isPositive = !remarkOpt.startswith("no-"); + bool isPositive = !remarkOpt.starts_with("no-"); if (!isPositive) remarkOpt = remarkOpt.substr(3); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 7e64adc3c144c9647510220c746315b91d93ad32..6ca910d26967421371f492fcb7b2473484dccea8 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -839,6 +839,11 @@ public: } } + void genEval(Fortran::lower::pft::Evaluation &eval, + bool unstructuredContext) override final { + genFIR(eval, unstructuredContext); + } + //===--------------------------------------------------------------------===// // Utility methods //===--------------------------------------------------------------------===// diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp index 4186d6158fb1d040aa994f32aba22ee4a4ae0277..a60ca92a8733e360071b4a8a4eae1cc69f70ab06 100644 --- a/flang/lib/Lower/IO.cpp +++ b/flang/lib/Lower/IO.cpp @@ -641,7 +641,8 @@ static void genNamelistIO(Fortran::lower::AbstractConverter &converter, mlir::Location loc = converter.getCurrentLocation(); makeNextConditionalOn(builder, loc, checkResult, ok); mlir::Type argType = funcOp.getFunctionType().getInput(1); - mlir::Value groupAddr = getNamelistGroup(converter, symbol, stmtCtx); + mlir::Value groupAddr = + getNamelistGroup(converter, symbol.GetUltimate(), stmtCtx); groupAddr = builder.createConvert(loc, argType, groupAddr); llvm::SmallVector args = {cookie, groupAddr}; ok = builder.create(loc, funcOp, args).getResult(0); diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp index eeba87fcd151169ac0f2abdf5ea2b16ffa6dd1b1..12b8ea82884d9d1f16b4808eb98762722bda4314 100644 --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -2117,12 +2117,8 @@ static void createBodyOfOp( for (const Fortran::semantics::Symbol *arg : args) loopVarTypeSize = std::max(loopVarTypeSize, arg->GetUltimate().size()); mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize); - llvm::SmallVector tiv; - llvm::SmallVector locs; - for (int i = 0; i < (int)args.size(); i++) { - tiv.push_back(loopVarType); - locs.push_back(loc); - } + llvm::SmallVector tiv(args.size(), loopVarType); + llvm::SmallVector locs(args.size(), loc); firOpBuilder.createBlock(&op.getRegion(), {}, tiv, locs); int argIndex = 0; // The argument is not currently in memory, so make a temporary for the diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp index 32ed539c775b827c1bec544720017c3adbe60ab8..8e224c17edad1955d4a059957c46b565601024d4 100644 --- a/flang/lib/Lower/PFTBuilder.cpp +++ b/flang/lib/Lower/PFTBuilder.cpp @@ -149,22 +149,22 @@ public: // Modules IEEE_FEATURES, IEEE_EXCEPTIONS, and IEEE_ARITHMETIC get common // declarations from several __fortran_... support module files. llvm::StringRef modName = toStringRef(modSym.name()); - if (!modName.startswith("ieee_") && !modName.startswith("__fortran_")) + if (!modName.starts_with("ieee_") && !modName.starts_with("__fortran_")) return; llvm::StringRef procName = toStringRef(procSym.name()); - if (!procName.startswith("ieee_")) + if (!procName.starts_with("ieee_")) return; lower::pft::FunctionLikeUnit *proc = evaluationListStack.back()->back().getOwningProcedure(); proc->hasIeeeAccess = true; - if (!procName.startswith("ieee_set_")) + if (!procName.starts_with("ieee_set_")) return; - if (procName.startswith("ieee_set_modes_") || - procName.startswith("ieee_set_status_")) + if (procName.starts_with("ieee_set_modes_") || + procName.starts_with("ieee_set_status_")) proc->mayModifyHaltingMode = proc->mayModifyRoundingMode = true; - else if (procName.startswith("ieee_set_halting_mode_")) + else if (procName.starts_with("ieee_set_halting_mode_")) proc->mayModifyHaltingMode = true; - else if (procName.startswith("ieee_set_rounding_mode_")) + else if (procName.starts_with("ieee_set_rounding_mode_")) proc->mayModifyRoundingMode = true; } diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index 45c75fc5dd28bc0534daefff90fd721fde6dee92..ff5dbff04360a034d4ea28eef7eda31c83e5de3d 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -1418,13 +1418,13 @@ mlir::Value toValue(const fir::ExtendedValue &val, fir::FirOpBuilder &builder, //===----------------------------------------------------------------------===// static bool isIntrinsicModuleProcedure(llvm::StringRef name) { - return name.startswith("c_") || name.startswith("compiler_") || - name.startswith("ieee_") || name.startswith("__ppc_"); + return name.starts_with("c_") || name.starts_with("compiler_") || + name.starts_with("ieee_") || name.starts_with("__ppc_"); } static bool isCoarrayIntrinsic(llvm::StringRef name) { - return name.startswith("atomic_") || name.startswith("co_") || - name.contains("image") || name.endswith("cobound") || + return name.starts_with("atomic_") || name.starts_with("co_") || + name.contains("image") || name.ends_with("cobound") || name.equals("team_number"); } @@ -1433,7 +1433,7 @@ static bool isCoarrayIntrinsic(llvm::StringRef name) { /// {_[ail]?[0-9]+}*, such as _1 or _a4. llvm::StringRef genericName(llvm::StringRef specificName) { const std::string builtin = "__builtin_"; - llvm::StringRef name = specificName.startswith(builtin) + llvm::StringRef name = specificName.starts_with(builtin) ? specificName.drop_front(builtin.size()) : specificName; size_t size = name.size(); diff --git a/flang/lib/Optimizer/Dialect/Support/KindMapping.cpp b/flang/lib/Optimizer/Dialect/Support/KindMapping.cpp index c71e3939dc31d28b0704d230fb66d346e18b7560..bcb112186aeefa7af868dda11e1b0e60e64ad269 100644 --- a/flang/lib/Optimizer/Dialect/Support/KindMapping.cpp +++ b/flang/lib/Optimizer/Dialect/Support/KindMapping.cpp @@ -180,7 +180,7 @@ static MatchResult parseInt(unsigned &result, const char *&ptr, static mlir::LogicalResult matchString(const char *&ptr, const char *endPtr, llvm::StringRef literal) { llvm::StringRef s(ptr, endPtr - ptr); - if (s.startswith(literal)) { + if (s.starts_with(literal)) { ptr += literal.size(); return mlir::success(); } diff --git a/flang/lib/Optimizer/Support/InternalNames.cpp b/flang/lib/Optimizer/Support/InternalNames.cpp index 6138c1f425d62cdc4de1558d7cdef8411c4b6827..d99245f0a012e6664b3265a12729dd6a31665418 100644 --- a/flang/lib/Optimizer/Support/InternalNames.cpp +++ b/flang/lib/Optimizer/Support/InternalNames.cpp @@ -240,7 +240,7 @@ llvm::StringRef fir::NameUniquer::doProgramEntry() { std::pair fir::NameUniquer::deconstruct(llvm::StringRef uniq) { - if (uniq.startswith("_Q")) { + if (uniq.starts_with("_Q")) { llvm::SmallVector modules; llvm::SmallVector procs; std::int64_t blockId = 0; diff --git a/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp b/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp index 3eddb9e61ae3b3df4aad127678795b2eff8bc03c..8ecf7fb44f15d049b9ed975a71cacc143d0eca26 100644 --- a/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp +++ b/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp @@ -1279,11 +1279,11 @@ void SimplifyIntrinsicsPass::runOnOperation() { // RTNAME(Sum)(const Descriptor &x, const char *source, int line, // int dim, const Descriptor *mask) // - if (funcName.startswith(RTNAME_STRING(Sum))) { + if (funcName.starts_with(RTNAME_STRING(Sum))) { simplifyIntOrFloatReduction(call, kindMap, genRuntimeSumBody); return; } - if (funcName.startswith(RTNAME_STRING(DotProduct))) { + if (funcName.starts_with(RTNAME_STRING(DotProduct))) { LLVM_DEBUG(llvm::dbgs() << "Handling " << funcName << "\n"); LLVM_DEBUG(llvm::dbgs() << "Call operation:\n"; op->dump(); llvm::dbgs() << "\n"); @@ -1350,23 +1350,23 @@ void SimplifyIntrinsicsPass::runOnOperation() { llvm::dbgs() << "\n"); return; } - if (funcName.startswith(RTNAME_STRING(Maxval))) { + if (funcName.starts_with(RTNAME_STRING(Maxval))) { simplifyIntOrFloatReduction(call, kindMap, genRuntimeMaxvalBody); return; } - if (funcName.startswith(RTNAME_STRING(Count))) { + if (funcName.starts_with(RTNAME_STRING(Count))) { simplifyLogicalDim0Reduction(call, kindMap, genRuntimeCountBody); return; } - if (funcName.startswith(RTNAME_STRING(Any))) { + if (funcName.starts_with(RTNAME_STRING(Any))) { simplifyLogicalDim1Reduction(call, kindMap, genRuntimeAnyBody); return; } - if (funcName.endswith(RTNAME_STRING(All))) { + if (funcName.ends_with(RTNAME_STRING(All))) { simplifyLogicalDim1Reduction(call, kindMap, genRuntimeAllBody); return; } - if (funcName.startswith(RTNAME_STRING(Minloc))) { + if (funcName.starts_with(RTNAME_STRING(Minloc))) { simplifyMinlocReduction(call, kindMap); return; } diff --git a/flang/lib/Parser/source.cpp b/flang/lib/Parser/source.cpp index d0fe399424e1395bbe525631c63b562f196a01e4..4b4fed64a1a40a3bd61edc1480ac301683b7202c 100644 --- a/flang/lib/Parser/source.cpp +++ b/flang/lib/Parser/source.cpp @@ -46,7 +46,7 @@ void SourceFile::RecordLineStarts() { void SourceFile::IdentifyPayload() { llvm::StringRef content{buf_->getBufferStart(), buf_->getBufferSize()}; constexpr llvm::StringLiteral UTF8_BOM{"\xef\xbb\xbf"}; - if (content.startswith(UTF8_BOM)) { + if (content.starts_with(UTF8_BOM)) { bom_end_ = UTF8_BOM.size(); encoding_ = Encoding::UTF_8; } diff --git a/flang/test/Lower/namelist.f90 b/flang/test/Lower/namelist.f90 index bba7a0ea19774d2f31b017b6ce68913286456c2e..9fdd8a2c8f61314789879f3ff0d8c1cdbd10d28d 100644 --- a/flang/test/Lower/namelist.f90 +++ b/flang/test/Lower/namelist.f90 @@ -1,88 +1,144 @@ -! RUN: bbc -emit-fir -hlfir=false -o - %s | FileCheck %s +! RUN: bbc -emit-fir -o - %s | FileCheck %s -! CHECK-LABEL: func @_QQmain +! CHECK-LABEL: c.func @_QQmain program p - ! CHECK-DAG: [[ccc:%[0-9]+]] = fir.alloca !fir.array<4x!fir.char<1,3>> {bindc_name = "ccc", uniq_name = "_QFEccc"} - ! CHECK-DAG: [[jjj:%[0-9]+]] = fir.alloca i32 {bindc_name = "jjj", uniq_name = "_QFEjjj"} + ! CHECK: %[[V_1:[0-9]+]] = fir.alloca !fir.box>>> + ! CHECK: %[[V_2:[0-9]+]] = fir.alloca !fir.box> + ! CHECK: %[[V_3:[0-9]+]] = fir.alloca !fir.box>>> + ! CHECK: %[[V_4:[0-9]+]] = fir.alloca !fir.box> + ! CHECK: %[[V_5:[0-9]+]] = fir.alloca !fir.array<4x!fir.char<1,3>> {bindc_name = "ccc", uniq_name = "_QFEccc"} + ! CHECK: %[[V_6:[0-9]+]] = fir.shape %c4{{.*}} : (index) -> !fir.shape<1> + ! CHECK: %[[V_7:[0-9]+]] = fir.declare %[[V_5]](%[[V_6]]) typeparams %c3{{.*}} {uniq_name = "_QFEccc"} : (!fir.ref>>, !fir.shape<1>, index) -> !fir.ref>> + ! CHECK: %[[V_8:[0-9]+]] = fir.alloca i32 {bindc_name = "jjj", uniq_name = "_QFEjjj"} + ! CHECK: %[[V_9:[0-9]+]] = fir.declare %[[V_8]] {uniq_name = "_QFEjjj"} : (!fir.ref) -> !fir.ref + ! CHECK: fir.store %c17{{.*}} to %[[V_9]] : !fir.ref character*3 ccc(4) namelist /nnn/ jjj, ccc jjj = 17 ccc = ["aa ", "bb ", "cc ", "dd "] - ! CHECK: [[cookie:%[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput - ! CHECK: fir.alloca !fir.array<2xtuple, !fir.ref>>> - ! CHECK: fir.undefined - ! CHECK: fir.address_of - ! CHECK: fir.insert_value - ! CHECK: fir.embox [[jjj]] - ! CHECK: fir.insert_value - ! CHECK: fir.address_of - ! CHECK: fir.insert_value - ! CHECK: fir.embox [[ccc]] - ! CHECK: fir.insert_value - ! CHECK: fir.alloca tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> - ! CHECK: fir.address_of - ! CHECK-COUNT-4: fir.insert_value - ! CHECK: fir.call @_FortranAioOutputNamelist([[cookie]] - ! CHECK: fir.call @_FortranAioEndIoStatement([[cookie]] + + ! CHECK: %[[V_23:[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput + ! CHECK: %[[V_24:[0-9]+]] = fir.alloca !fir.array<2xtuple, !fir.ref>>> + ! CHECK: %[[V_25:[0-9]+]] = fir.undefined !fir.array<2xtuple, !fir.ref>>> + ! CHECK: %[[V_26:[0-9]+]] = fir.address_of(@_QQclX6A6A6A00) : !fir.ref> + ! CHECK: %[[V_27:[0-9]+]] = fir.convert %[[V_26]] : (!fir.ref>) -> !fir.ref + ! CHECK: %[[V_28:[0-9]+]] = fir.insert_value %[[V_25]], %[[V_27]], [0 : index, 0 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: %[[V_29:[0-9]+]] = fir.embox %[[V_9]] : (!fir.ref) -> !fir.box> + ! CHECK: fir.store %[[V_29]] to %[[V_4]] : !fir.ref>> + ! CHECK: %[[V_30:[0-9]+]] = fir.convert %[[V_4]] : (!fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_31:[0-9]+]] = fir.insert_value %[[V_28]], %[[V_30]], [0 : index, 1 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref>) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: %[[V_32:[0-9]+]] = fir.address_of(@_QQclX63636300) : !fir.ref> + ! CHECK: %[[V_33:[0-9]+]] = fir.convert %[[V_32]] : (!fir.ref>) -> !fir.ref + ! CHECK: %[[V_34:[0-9]+]] = fir.insert_value %[[V_31]], %[[V_33]], [1 : index, 0 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: %[[V_35:[0-9]+]] = fir.embox %[[V_7]](%[[V_6]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>>> + ! CHECK: fir.store %[[V_35]] to %[[V_3]] : !fir.ref>>>> + ! CHECK: %[[V_36:[0-9]+]] = fir.convert %[[V_3]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: %[[V_37:[0-9]+]] = fir.insert_value %[[V_34]], %[[V_36]], [1 : index, 1 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref>) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: fir.store %[[V_37]] to %[[V_24]] : !fir.ref, !fir.ref>>>> + ! CHECK: %[[V_38:[0-9]+]] = fir.alloca tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_39:[0-9]+]] = fir.undefined tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_40:[0-9]+]] = fir.address_of(@_QQclX6E6E6E00) : !fir.ref> + ! CHECK: %[[V_41:[0-9]+]] = fir.convert %[[V_40]] : (!fir.ref>) -> !fir.ref + ! CHECK: %[[V_42:[0-9]+]] = fir.insert_value %[[V_39]], %[[V_41]], [0 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_43:[0-9]+]] = fir.insert_value %[[V_42]], %c2{{.*}}, [1 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, i64) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_44:[0-9]+]] = fir.insert_value %[[V_43]], %[[V_24]], [2 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref, !fir.ref>>>>) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_45:[0-9]+]] = fir.address_of(@default.nonTbpDefinedIoTable) : !fir.ref, !fir.ref, i32, i1>>>, i1>> + ! CHECK: %[[V_46:[0-9]+]] = fir.convert %[[V_45]] : (!fir.ref, !fir.ref, i32, i1>>>, i1>>) -> !fir.ref + ! CHECK: %[[V_47:[0-9]+]] = fir.insert_value %[[V_44]], %[[V_46]], [3 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: fir.store %[[V_47]] to %[[V_38]] : !fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>> + ! CHECK: %[[V_48:[0-9]+]] = fir.convert %[[V_38]] : (!fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_49:[0-9]+]] = fir.call @_FortranAioOutputNamelist(%[[V_23]], %[[V_48]]) fastmath : (!fir.ref, !fir.ref>) -> i1 + ! CHECK: %[[V_50:[0-9]+]] = fir.call @_FortranAioEndIoStatement(%[[V_23]]) fastmath : (!fir.ref) -> i32 write(*, nnn) jjj = 27 - ! CHECK: fir.coordinate_of ccc(4) = "zz " - ! CHECK: [[cookie:%[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput - ! CHECK: fir.alloca !fir.array<2xtuple, !fir.ref>>> - ! CHECK: fir.undefined - ! CHECK: fir.address_of - ! CHECK: fir.insert_value - ! CHECK: fir.embox [[jjj]] - ! CHECK: fir.insert_value - ! CHECK: fir.address_of - ! CHECK: fir.insert_value - ! CHECK: fir.embox [[ccc]] - ! CHECK: fir.insert_value - ! CHECK: fir.alloca tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> - ! CHECK: fir.address_of - ! CHECK-COUNT-4: fir.insert_value - ! CHECK: fir.call @_FortranAioOutputNamelist([[cookie]] - ! CHECK: fir.call @_FortranAioEndIoStatement([[cookie]] + ! CHECK: %[[V_58:[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput + ! CHECK: %[[V_59:[0-9]+]] = fir.alloca !fir.array<2xtuple, !fir.ref>>> + ! CHECK: fir.store %[[V_29]] to %[[V_2]] : !fir.ref>> + ! CHECK: %[[V_60:[0-9]+]] = fir.convert %[[V_2]] : (!fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_61:[0-9]+]] = fir.insert_value %[[V_28]], %[[V_60]], [0 : index, 1 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref>) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: %[[V_62:[0-9]+]] = fir.insert_value %[[V_61]], %[[V_33]], [1 : index, 0 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: fir.store %[[V_35]] to %[[V_1]] : !fir.ref>>>> + ! CHECK: %[[V_63:[0-9]+]] = fir.convert %[[V_1]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: %[[V_64:[0-9]+]] = fir.insert_value %[[V_62]], %[[V_63]], [1 : index, 1 : index] : (!fir.array<2xtuple, !fir.ref>>>, !fir.ref>) -> !fir.array<2xtuple, !fir.ref>>> + ! CHECK: fir.store %[[V_64]] to %[[V_59]] : !fir.ref, !fir.ref>>>> + ! CHECK: %[[V_65:[0-9]+]] = fir.alloca tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_66:[0-9]+]] = fir.insert_value %[[V_43]], %[[V_59]], [2 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref, !fir.ref>>>>) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_67:[0-9]+]] = fir.insert_value %[[V_66]], %[[V_46]], [3 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: fir.store %[[V_67]] to %[[V_65]] : !fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>> + ! CHECK: %[[V_68:[0-9]+]] = fir.convert %[[V_65]] : (!fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_69:[0-9]+]] = fir.call @_FortranAioOutputNamelist(%[[V_58]], %[[V_68]]) fastmath : (!fir.ref, !fir.ref>) -> i1 + ! CHECK: %[[V_70:[0-9]+]] = fir.call @_FortranAioEndIoStatement(%[[V_58]]) fastmath : (!fir.ref) -> i32 write(*, nnn) + + call rename end -! CHECK-LABEL: sss +! CHECK-LABEL: c.func @_QPsss subroutine sss + ! CHECK: %[[V_0:[0-9]+]] = fir.alloca !fir.box>> + ! CHECK: %[[V_1:[0-9]+]] = fir.alloca !fir.array<3xi32> {bindc_name = "xxx", uniq_name = "_QFsssExxx"} + ! CHECK: %[[V_2:[0-9]+]] = fir.shape_shift %c11{{.*}}, %c3{{.*}} : (index, index) -> !fir.shapeshift<1> + ! CHECK: %[[V_3:[0-9]+]] = fir.declare %[[V_1]](%[[V_2]]) {uniq_name = "_QFsssExxx"} : (!fir.ref>, !fir.shapeshift<1>) -> !fir.ref> integer xxx(11:13) + + ! CHECK: %[[V_7:[0-9]+]] = fir.call @_FortranAioBeginExternalListInput + ! CHECK: %[[V_8:[0-9]+]] = fir.alloca !fir.array<1xtuple, !fir.ref>>> + ! CHECK: %[[V_9:[0-9]+]] = fir.undefined !fir.array<1xtuple, !fir.ref>>> + ! CHECK: %[[V_10:[0-9]+]] = fir.address_of(@_QQclX78787800) : !fir.ref> + ! CHECK: %[[V_11:[0-9]+]] = fir.convert %[[V_10]] : (!fir.ref>) -> !fir.ref + ! CHECK: %[[V_12:[0-9]+]] = fir.insert_value %[[V_9]], %[[V_11]], [0 : index, 0 : index] : (!fir.array<1xtuple, !fir.ref>>>, !fir.ref) -> !fir.array<1xtuple, !fir.ref>>> + ! CHECK: %[[V_13:[0-9]+]] = fir.embox %[[V_3]](%[[V_2]]) : (!fir.ref>, !fir.shapeshift<1>) -> !fir.box>> + ! CHECK: fir.store %[[V_13]] to %[[V_0]] : !fir.ref>>> + ! CHECK: %[[V_14:[0-9]+]] = fir.convert %[[V_0]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: %[[V_15:[0-9]+]] = fir.insert_value %[[V_12]], %[[V_14]], [0 : index, 1 : index] : (!fir.array<1xtuple, !fir.ref>>>, !fir.ref>) -> !fir.array<1xtuple, !fir.ref>>> + ! CHECK: fir.store %[[V_15]] to %[[V_8]] : !fir.ref, !fir.ref>>>> + ! CHECK: %[[V_16:[0-9]+]] = fir.alloca tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_17:[0-9]+]] = fir.undefined tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_18:[0-9]+]] = fir.address_of(@_QQclX72727200) : !fir.ref> + ! CHECK: %[[V_19:[0-9]+]] = fir.convert %[[V_18]] : (!fir.ref>) -> !fir.ref + ! CHECK: %[[V_20:[0-9]+]] = fir.insert_value %[[V_17]], %[[V_19]], [0 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_21:[0-9]+]] = fir.insert_value %[[V_20]], %c1{{.*}}, [1 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, i64) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_22:[0-9]+]] = fir.insert_value %[[V_21]], %[[V_8]], [2 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref, !fir.ref>>>>) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: %[[V_23:[0-9]+]] = fir.address_of(@default.nonTbpDefinedIoTable) : !fir.ref, !fir.ref, i32, i1>>>, i1>> + ! CHECK: %[[V_24:[0-9]+]] = fir.convert %[[V_23]] : (!fir.ref, !fir.ref, i32, i1>>>, i1>>) -> !fir.ref + ! CHECK: %[[V_25:[0-9]+]] = fir.insert_value %[[V_22]], %[[V_24]], [3 : index] : (tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref>, !fir.ref) -> tuple, i64, !fir.ref, !fir.ref>>>>, !fir.ref> + ! CHECK: fir.store %[[V_25]] to %[[V_16]] : !fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>> + ! CHECK: %[[V_26:[0-9]+]] = fir.convert %[[V_16]] : (!fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_27:[0-9]+]] = fir.call @_FortranAioInputNamelist(%[[V_7]], %[[V_26]]) fastmath : (!fir.ref, !fir.ref>) -> i1 + ! CHECK: %[[V_28:[0-9]+]] = fir.call @_FortranAioEndIoStatement(%[[V_7]]) fastmath : (!fir.ref) -> i32 namelist /rrr/ xxx - ! CHECK: [[xxx:%[0-9]+]] = fir.alloca {{.*}} = "xxx" - ! CHECK: [[cookie:%[0-9]+]] = fir.call @_FortranAioBeginExternalListInput - ! CHECK: alloca - ! CHECK: undefined - ! CHECK: fir.address_of{{.*}}787878 - ! CHECK: fir.insert_value - ! CHECK: fir.shape_shift %c11 - ! CHECK: fir.embox [[xxx]] - ! CHECK: fir.insert_value - ! CHECK: fir.alloca - ! CHECK: fir.undefined - ! CHECK: fir.address_of{{.*}}727272 - ! CHECK-COUNT-3: fir.insert_value - ! CHECK: fir.call @_FortranAioInputNamelist([[cookie]] - ! CHECK: fir.call @_FortranAioEndIoStatement([[cookie]] read(*, rrr) end -! CHECK-LABEL: global_pointer +! CHECK-LABEL: c.func @_QPglobal_pointer subroutine global_pointer real,pointer,save::ptrarray(:) - ! CHECK: %[[a0:.*]] = fir.address_of + ! CHECK: %[[V_4:[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput + ! CHECK: %[[V_5:[0-9]+]] = fir.address_of(@_QFglobal_pointerNmygroup) : !fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>> + ! CHECK: %[[V_6:[0-9]+]] = fir.convert %[[V_5]] : (!fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_7:[0-9]+]] = fir.call @_FortranAioOutputNamelist(%[[V_4]], %[[V_6]]) fastmath : (!fir.ref, !fir.ref>) -> i1 + ! CHECK: %[[V_8:[0-9]+]] = fir.call @_FortranAioEndIoStatement(%[[V_4]]) fastmath : (!fir.ref) -> i32 namelist/mygroup/ptrarray - ! CHECK: %[[a1:.*]] = fir.convert %[[a0]] - ! CHECK: %[[a2:.*]] = fir.call @_FortranAioBeginExternalListOutput({{.*}}, %[[a1]], {{.*}}) {{.*}}: (i32, !fir.ref, i32) -> !fir.ref - ! CHECK: %[[a3:.*]] = fir.address_of - ! CHECK: %[[a4:.*]] = fir.convert %[[a3]] - ! CHECK: %[[a5:.*]] = fir.call @_FortranAioOutputNamelist(%[[a2]], %[[a4]]) - ! CHECK: %[[a6:.*]] = fir.call @_FortranAioEndIoStatement(%[[a2]]) write(10, nml=mygroup) end - ! CHECK-DAG: fir.global linkonce @_QQclX6A6A6A00 constant : !fir.char<1,4> - ! CHECK-DAG: fir.global linkonce @_QQclX63636300 constant : !fir.char<1,4> - ! CHECK-DAG: fir.global linkonce @_QQclX6E6E6E00 constant : !fir.char<1,4> +module mmm + real rrr + namelist /aaa/ rrr +end + +! CHECK-LABEL: c.func @_QPrename +subroutine rename + use mmm, bbb => aaa + rrr = 3. + ! CHECK: %[[V_4:[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput + ! CHECK: %[[V_5:[0-9]+]] = fir.address_of(@_QMmmmNaaa) : !fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>> + ! CHECK: %[[V_6:[0-9]+]] = fir.convert %[[V_5]] : (!fir.ref, i64, !fir.ref, !fir.ref>>>>, !fir.ref>>) -> !fir.ref> + ! CHECK: %[[V_7:[0-9]+]] = fir.call @_FortranAioOutputNamelist(%[[V_4]], %[[V_6]]) fastmath : (!fir.ref, !fir.ref>) -> i1 + ! CHECK: %[[V_8:[0-9]+]] = fir.call @_FortranAioEndIoStatement(%[[V_4]]) fastmath : (!fir.ref) -> i32 + write(*,bbb) +end + +! CHECK-NOT: bbb +! CHECK: fir.string_lit "aaa\00"(4) : !fir.char<1,4> diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp index 99fa66b0dc8e266a84fac7227fbf6b104b65ab24..c4e56a862c861359311a035e8d71342df1d7d5bd 100644 --- a/flang/tools/flang-driver/driver.cpp +++ b/flang/tools/flang-driver/driver.cpp @@ -99,13 +99,13 @@ int main(int argc, const char **argv) { auto firstArg = std::find_if(args.begin() + 1, args.end(), [](const char *a) { return a != nullptr; }); if (firstArg != args.end()) { - if (llvm::StringRef(args[1]).startswith("-cc1")) { + if (llvm::StringRef(args[1]).starts_with("-cc1")) { llvm::errs() << "error: unknown integrated tool '" << args[1] << "'. " << "Valid tools include '-fc1'.\n"; return 1; } // Call flang-new frontend - if (llvm::StringRef(args[1]).startswith("-fc1")) { + if (llvm::StringRef(args[1]).starts_with("-fc1")) { return executeFC1Tool(args); } } diff --git a/flang/unittests/Frontend/CompilerInstanceTest.cpp b/flang/unittests/Frontend/CompilerInstanceTest.cpp index 6dbbf9b4e1bbd3cbb96117bc456b42352c52560c..35f1ec1748a3f69fd6e67ab613d59650a716805e 100644 --- a/flang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/flang/unittests/Frontend/CompilerInstanceTest.cpp @@ -55,7 +55,7 @@ TEST(CompilerInstance, SanityCheckForFileManager) { llvm::ArrayRef fileContent = sf->content(); EXPECT_FALSE(fileContent.size() == 0); EXPECT_TRUE( - llvm::StringRef(fileContent.data()).startswith("InputSourceFile")); + llvm::StringRef(fileContent.data()).starts_with("InputSourceFile")); // 4. Delete the test file ec = llvm::sys::fs::remove(inputFile); diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp index d57154cb1001c7295e2b45f2283e8929b62d8c2a..6ec15832d96d3cb11aec687c8cc5a30d93ece45e 100644 --- a/flang/unittests/Frontend/FrontendActionTest.cpp +++ b/flang/unittests/Frontend/FrontendActionTest.cpp @@ -112,7 +112,7 @@ TEST_F(FrontendActionTest, TestInputOutput) { EXPECT_TRUE(success); EXPECT_TRUE(!outputFileBuffer.empty()); EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data()) - .startswith("End Program arithmetic")); + .starts_with("End Program arithmetic")); } TEST_F(FrontendActionTest, PrintPreprocessedInput) { @@ -143,7 +143,7 @@ TEST_F(FrontendActionTest, PrintPreprocessedInput) { EXPECT_TRUE(success); EXPECT_TRUE(!outputFileBuffer.empty()); EXPECT_TRUE( - llvm::StringRef(outputFileBuffer.data()).startswith("program b\n")); + llvm::StringRef(outputFileBuffer.data()).starts_with("program b\n")); } TEST_F(FrontendActionTest, ParseSyntaxOnly) { diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index 726e58f376eaa766e30e7b2ced0f37300c947c75..85f6b59264eb06d29254135dff4571acaf205927 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -205,7 +205,12 @@ def SysSelectAPI : PublicAPI<"sys/select.h"> { } def SysSocketAPI : PublicAPI<"sys/socket.h"> { - let Types = ["struct sockaddr", "sa_family_t"]; + let Types = [ + "sa_family_t", + "socklen_t", + "struct sockaddr", + "struct sockaddr_un", + ]; } def SysResourceAPI : PublicAPI<"sys/resource.h"> { diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 13b81d3b7ca702c7d4f0b4be523de6403fe32a2c..1c93063e25e90c08c64857824e6333ec43c6016c 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -153,9 +153,6 @@ set(TARGET_LIBC_ENTRYPOINTS # sys/sendfile entrypoints libc.src.sys.sendfile.sendfile - # sys/socket.h entrypoints - libc.src.sys.socket.socket - # sys/stat.h entrypoints libc.src.sys.stat.chmod libc.src.sys.stat.fchmod @@ -557,6 +554,10 @@ if(LLVM_LIBC_FULL_BUILD) # sys/select.h entrypoints libc.src.sys.select.select + + # sys/socket.h entrypoints + libc.src.sys.socket.socket + libc.src.sys.socket.bind ) endif() diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 429c0f1f12866a8988f469b32b30dc126cbf2ed3..59c6c4a9bb4200045aff79905a8f6bc9eaf1094a 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -417,8 +417,10 @@ add_gen_header( DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_socket_macros - .llvm-libc-types.struct_sockaddr .llvm-libc-types.sa_family_t + .llvm-libc-types.socklen_t + .llvm-libc-types.struct_sockaddr + .llvm-libc-types.struct_sockaddr_un ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/linux/fcntl-macros.h b/libc/include/llvm-libc-macros/linux/fcntl-macros.h index cdd1cf22d7b69cbdc0d128d86651feef4278c7db..495c5ec780edb0ee76bd735b74120011c4e25f3a 100644 --- a/libc/include/llvm-libc-macros/linux/fcntl-macros.h +++ b/libc/include/llvm-libc-macros/linux/fcntl-macros.h @@ -46,31 +46,6 @@ #define O_RDWR 00000002 #define O_WRONLY 00000001 -// File mode flags -#define S_IRWXU 0700 -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#define S_IXUSR 0100 -#define S_IRWXG 070 -#define S_IRGRP 040 -#define S_IWGRP 020 -#define S_IXGRP 010 -#define S_IRWXO 07 -#define S_IROTH 04 -#define S_IWOTH 02 -#define S_IXOTH 01 -#define S_ISUID 04000 -#define S_ISGID 02000 - -// File type flags -#define S_IFMT 0170000 -#define S_IFDIR 0040000 -#define S_IFCHR 0020000 -#define S_IFBLK 0060000 -#define S_IFREG 0100000 -#define S_FIFO 0010000 -#define S_IFLNK 0120000 - // Special directory FD to indicate that the path argument to // openat is relative to the current directory. #define AT_FDCWD -100 diff --git a/libc/include/llvm-libc-macros/linux/sys-stat-macros.h b/libc/include/llvm-libc-macros/linux/sys-stat-macros.h index 3be743328a26bb71315161e9732f0365c26a0f80..48606cfa08ce935f685eb09177a06a891c1bf887 100644 --- a/libc/include/llvm-libc-macros/linux/sys-stat-macros.h +++ b/libc/include/llvm-libc-macros/linux/sys-stat-macros.h @@ -10,7 +10,7 @@ #define __LLVM_LIBC_MACROS_LINUX_SYS_STAT_MACROS_H // Definitions from linux/stat.h -#define S_IFMT 00170000 +#define S_IFMT 0170000 #define S_IFSOCK 0140000 #define S_IFLNK 0120000 #define S_IFREG 0100000 diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 225ad780c4d01f2412b806aca38a5e5e5a5c271f..500900ffa0bbb05ed2a6aa12cd66d861771af09b 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -89,6 +89,8 @@ add_header(__getoptargv_t HDR __getoptargv_t.h) add_header(wchar_t HDR wchar_t.h) add_header(wint_t HDR wint_t.h) add_header(sa_family_t HDR sa_family_t.h) +add_header(socklen_t HDR socklen_t.h) +add_header(struct_sockaddr_un HDR struct_sockaddr_un.h) add_header(struct_sockaddr HDR struct_sockaddr.h) add_header(rpc_opcodes_t HDR rpc_opcodes_t.h) add_header(ACTION HDR ACTION.h) diff --git a/libc/include/llvm-libc-types/socklen_t.h b/libc/include/llvm-libc-types/socklen_t.h new file mode 100644 index 0000000000000000000000000000000000000000..3134a53390e71ed420de55e6cdf87b47c2156cac --- /dev/null +++ b/libc/include/llvm-libc-types/socklen_t.h @@ -0,0 +1,18 @@ +//===-- Definition of socklen_t type ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_SOCKLEN_T_H__ +#define __LLVM_LIBC_TYPES_SOCKLEN_T_H__ + +// The posix standard only says of socklen_t that it must be an integer type of +// width of at least 32 bits. The long type is defined as being at least 32 +// bits, so an unsigned long should be fine. + +typedef unsigned long socklen_t; + +#endif // __LLVM_LIBC_TYPES_SOCKLEN_T_H__ diff --git a/libc/include/llvm-libc-types/struct_sockaddr.h b/libc/include/llvm-libc-types/struct_sockaddr.h index 1ef907904ca3ec182ce2cec3bbceccdbae16c18c..9a6214c7d3e6b9b837e3a434d706a339dd38dea9 100644 --- a/libc/include/llvm-libc-types/struct_sockaddr.h +++ b/libc/include/llvm-libc-types/struct_sockaddr.h @@ -1,4 +1,4 @@ -//===-- Definition of struct stat -----------------------------------------===// +//===-- Definition of struct sockaddr -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef __LLVM_LIBC_TYPES_STRUCT_STAT_H__ -#define __LLVM_LIBC_TYPES_STRUCT_STAT_H__ +#ifndef __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_H__ +#define __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_H__ #include @@ -15,7 +15,7 @@ struct sockaddr { sa_family_t sa_family; // sa_data is a variable length array. It is provided with a length of one // here as a placeholder. - char sa_data[1]; + char sa_data[]; }; -#endif // __LLVM_LIBC_TYPES_STRUCT_STAT_H__ +#endif // __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_H__ diff --git a/libc/include/llvm-libc-types/struct_sockaddr_un.h b/libc/include/llvm-libc-types/struct_sockaddr_un.h new file mode 100644 index 0000000000000000000000000000000000000000..9c3efea279256ec2927de18cba579bf94abdf843 --- /dev/null +++ b/libc/include/llvm-libc-types/struct_sockaddr_un.h @@ -0,0 +1,22 @@ +//===-- Definition of struct sockaddr_un ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_UN_H__ +#define __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_UN_H__ + +#include + +// This is the sockaddr specialization for AF_UNIX or AF_LOCAL sockets, as +// defined by posix. + +struct sockaddr_un { + sa_family_t sun_family; /* AF_UNIX */ + char sun_path[108]; /* Pathname */ +}; + +#endif // __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_UN_H__ diff --git a/libc/spec/posix.td b/libc/spec/posix.td index c7acf6d25a2d8739b8e639d1fcd149497c37990c..7e1cf892135acf99c3f305736310e41c5e149350 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -81,9 +81,14 @@ def RestrictedFdSetPtr : RestrictedPtrType; def GetoptArgvT : NamedType<"__getoptargv_t">; +def SAFamilyType : NamedType<"sa_family_t">; +def SocklenType : NamedType<"socklen_t">; + def StructSockAddr : NamedType<"struct sockaddr">; def StructSockAddrPtr : PtrType; -def SAFamilyType : NamedType<"sa_family_t">; +def ConstStructSockAddrPtr : ConstType; + +def StructSockAddrUn : NamedType<"struct sockaddr_un">; def POSIX : StandardSpec<"POSIX"> { PtrType CharPtr = PtrType; @@ -1400,7 +1405,10 @@ def POSIX : StandardSpec<"POSIX"> { Macro<"SOCK_PACKET">, ], // Macros [ - StructSockAddr, SAFamilyType, + SAFamilyType, + StructSockAddr, + StructSockAddrUn, + SocklenType, ], // Types [], // Enumerations [ @@ -1409,6 +1417,11 @@ def POSIX : StandardSpec<"POSIX"> { RetValSpec, [ArgSpec, ArgSpec, ArgSpec] >, + FunctionSpec< + "bind", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, ] // Functions >; diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h index 65c53921181a73a6a783d01d37faa73916640d4b..d1e26de22ef1308e34f1d0ee4458b35a66c3b3c6 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -20,14 +20,6 @@ namespace LIBC_NAMESPACE { namespace fputil { -template struct MantissaWidth { - static constexpr unsigned VALUE = FloatProperties::MANTISSA_WIDTH; -}; - -template struct ExponentWidth { - static constexpr unsigned VALUE = FloatProperties::EXPONENT_WIDTH; -}; - // A generic class to represent single precision, double precision, and quad // precision IEEE 754 floating point formats. // On most platforms, the 'float' type corresponds to single precision floating @@ -36,71 +28,74 @@ template struct ExponentWidth { // floating numbers. On x86 platforms however, the 'long double' type maps to // an x87 floating point format. This format is an IEEE 754 extension format. // It is handled as an explicit specialization of this class. -template struct FPBits { +template struct FPBits : private FloatProperties { static_assert(cpp::is_floating_point_v, "FPBits instantiated with invalid type."); + using typename FloatProperties::UIntType; + using FloatProperties::BIT_WIDTH; + using FloatProperties::EXP_MANT_MASK; + using FloatProperties::EXPONENT_MASK; + using FloatProperties::EXPONENT_BIAS; + using FloatProperties::EXPONENT_WIDTH; + using FloatProperties::MANTISSA_MASK; + using FloatProperties::MANTISSA_WIDTH; + using FloatProperties::QUIET_NAN_MASK; + using FloatProperties::SIGN_MASK; // Reinterpreting bits as an integer value and interpreting the bits of an // integer value as a floating point value is used in tests. So, a convenient // type is provided for such reinterpretations. - using FloatProp = FloatProperties; - using UIntType = typename FloatProp::UIntType; - UIntType bits; LIBC_INLINE constexpr void set_mantissa(UIntType mantVal) { - mantVal &= (FloatProp::MANTISSA_MASK); - bits &= ~(FloatProp::MANTISSA_MASK); + mantVal &= MANTISSA_MASK; + bits &= ~MANTISSA_MASK; bits |= mantVal; } LIBC_INLINE constexpr UIntType get_mantissa() const { - return bits & FloatProp::MANTISSA_MASK; + return bits & MANTISSA_MASK; } LIBC_INLINE constexpr void set_biased_exponent(UIntType expVal) { - expVal = (expVal << (FloatProp::MANTISSA_WIDTH)) & FloatProp::EXPONENT_MASK; - bits &= ~(FloatProp::EXPONENT_MASK); + expVal = (expVal << MANTISSA_WIDTH) & EXPONENT_MASK; + bits &= ~EXPONENT_MASK; bits |= expVal; } LIBC_INLINE constexpr uint16_t get_biased_exponent() const { - return uint16_t((bits & FloatProp::EXPONENT_MASK) >> - (FloatProp::MANTISSA_WIDTH)); + return uint16_t((bits & EXPONENT_MASK) >> MANTISSA_WIDTH); } // The function return mantissa with the implicit bit set iff the current // value is a valid normal number. LIBC_INLINE constexpr UIntType get_explicit_mantissa() { return ((get_biased_exponent() > 0 && !is_inf_or_nan()) - ? (FloatProp::MANTISSA_MASK + 1) + ? (MANTISSA_MASK + 1) : 0) | - (FloatProp::MANTISSA_MASK & bits); + (MANTISSA_MASK & bits); } LIBC_INLINE constexpr void set_sign(bool signVal) { - bits |= FloatProp::SIGN_MASK; + bits |= SIGN_MASK; if (!signVal) - bits -= FloatProp::SIGN_MASK; + bits -= SIGN_MASK; } LIBC_INLINE constexpr bool get_sign() const { - return (bits & FloatProp::SIGN_MASK) != 0; + return (bits & SIGN_MASK) != 0; } static_assert(sizeof(T) == sizeof(UIntType), "Data type and integral representation have different sizes."); - static constexpr int EXPONENT_BIAS = (1 << (ExponentWidth::VALUE - 1)) - 1; - static constexpr int MAX_EXPONENT = (1 << ExponentWidth::VALUE) - 1; + static constexpr int MAX_EXPONENT = (1 << EXPONENT_WIDTH) - 1; static constexpr UIntType MIN_SUBNORMAL = UIntType(1); - static constexpr UIntType MAX_SUBNORMAL = - (UIntType(1) << MantissaWidth::VALUE) - 1; - static constexpr UIntType MIN_NORMAL = - (UIntType(1) << MantissaWidth::VALUE); + static constexpr UIntType MAX_SUBNORMAL = (UIntType(1) << MANTISSA_WIDTH) - 1; + static constexpr UIntType MIN_NORMAL = (UIntType(1) << MANTISSA_WIDTH); static constexpr UIntType MAX_NORMAL = - ((UIntType(MAX_EXPONENT) - 1) << MantissaWidth::VALUE) | MAX_SUBNORMAL; + ((UIntType(MAX_EXPONENT) - 1) << MANTISSA_WIDTH) | MAX_SUBNORMAL; // We don't want accidental type promotions/conversions, so we require exact // type match. @@ -151,32 +146,29 @@ template struct FPBits { } LIBC_INLINE constexpr bool is_inf() const { - return (bits & FloatProp::EXP_MANT_MASK) == FloatProp::EXPONENT_MASK; + return (bits & EXP_MANT_MASK) == EXPONENT_MASK; } LIBC_INLINE constexpr bool is_nan() const { - return (bits & FloatProp::EXP_MANT_MASK) > FloatProp::EXPONENT_MASK; + return (bits & EXP_MANT_MASK) > EXPONENT_MASK; } LIBC_INLINE constexpr bool is_quiet_nan() const { - return (bits & FloatProp::EXP_MANT_MASK) == - (FloatProp::EXPONENT_MASK | FloatProp::QUIET_NAN_MASK); + return (bits & EXP_MANT_MASK) == (EXPONENT_MASK | QUIET_NAN_MASK); } LIBC_INLINE constexpr bool is_inf_or_nan() const { - return (bits & FloatProp::EXPONENT_MASK) == FloatProp::EXPONENT_MASK; + return (bits & EXPONENT_MASK) == EXPONENT_MASK; } LIBC_INLINE static constexpr T zero(bool sign = false) { - return FPBits(sign ? FloatProp::SIGN_MASK : UIntType(0)).get_val(); + return FPBits(sign ? SIGN_MASK : UIntType(0)).get_val(); } LIBC_INLINE static constexpr T neg_zero() { return zero(true); } LIBC_INLINE static constexpr T inf(bool sign = false) { - return FPBits((sign ? FloatProp::SIGN_MASK : UIntType(0)) | - FloatProp::EXPONENT_MASK) - .get_val(); + return FPBits((sign ? SIGN_MASK : UIntType(0)) | EXPONENT_MASK).get_val(); } LIBC_INLINE static constexpr T neg_inf() { return inf(true); } @@ -204,7 +196,7 @@ template struct FPBits { } LIBC_INLINE static constexpr T build_quiet_nan(UIntType v) { - return build_nan(FloatProp::QUIET_NAN_MASK | v); + return build_nan(QUIET_NAN_MASK | v); } // The function convert integer number and unbiased exponent to proper float @@ -220,7 +212,7 @@ template struct FPBits { LIBC_INLINE static constexpr FPBits make_value(UIntType number, int ep) { FPBits result; // offset: +1 for sign, but -1 for implicit first bit - int lz = cpp::countl_zero(number) - FloatProp::EXPONENT_WIDTH; + int lz = cpp::countl_zero(number) - EXPONENT_WIDTH; number <<= lz; ep -= lz; diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h index 42d9e1b3f8cec5c96458ec1822da1fe3a830ae71..ad6b72db0524fc76015c15b8e2fb3e0061c95243 100644 --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -124,7 +124,7 @@ LIBC_INLINE T hypot(T x, T y) { uint16_t y_exp = y_bits.get_biased_exponent(); uint16_t exp_diff = (x_exp > y_exp) ? (x_exp - y_exp) : (y_exp - x_exp); - if ((exp_diff >= MantissaWidth::VALUE + 2) || (x == 0) || (y == 0)) { + if ((exp_diff >= FPBits_t::MANTISSA_WIDTH + 2) || (x == 0) || (y == 0)) { return abs(x) + abs(y); } @@ -148,7 +148,7 @@ LIBC_INLINE T hypot(T x, T y) { out_exp = a_exp; // Add an extra bit to simplify the final rounding bit computation. - constexpr UIntType ONE = UIntType(1) << (MantissaWidth::VALUE + 1); + constexpr UIntType ONE = UIntType(1) << (FPBits_t::MANTISSA_WIDTH + 1); a_mant <<= 1; b_mant <<= 1; @@ -158,7 +158,7 @@ LIBC_INLINE T hypot(T x, T y) { if (a_exp != 0) { leading_one = ONE; a_mant |= ONE; - y_mant_width = MantissaWidth::VALUE + 1; + y_mant_width = FPBits_t::MANTISSA_WIDTH + 1; } else { leading_one = internal::find_leading_one(a_mant, y_mant_width); a_exp = 1; @@ -258,7 +258,7 @@ LIBC_INLINE T hypot(T x, T y) { } } - y_new |= static_cast(out_exp) << MantissaWidth::VALUE; + y_new |= static_cast(out_exp) << FPBits_t::MANTISSA_WIDTH; return cpp::bit_cast(y_new); } diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h index 08adb074b121fa1564abb04a0f99b54cc137b5f5..51b58ba29bab89ff6753191e1a99c41addc0b64e 100644 --- a/libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/libc/src/__support/FPUtil/ManipulationFunctions.h @@ -130,7 +130,7 @@ LIBC_INLINE T ldexp(T x, int exp) { // early. Because the result of the ldexp operation can be a subnormal number, // we need to accommodate the (mantissaWidht + 1) worth of shift in // calculating the limit. - int exp_limit = FPBits::MAX_EXPONENT + MantissaWidth::VALUE + 1; + int exp_limit = FPBits::MAX_EXPONENT + FPBits::MANTISSA_WIDTH + 1; if (exp > exp_limit) return bits.get_sign() ? T(FPBits::neg_inf()) : T(FPBits::inf()); diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h index 8c4b24803bec1d31d61dc5229adb70adf0250008..b0ae8d0040ea19282f7851e46f70f347c47af8d7 100644 --- a/libc/src/__support/FPUtil/NearestIntegerOperations.h +++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h @@ -36,7 +36,7 @@ LIBC_INLINE T trunc(T x) { // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. - if (exponent >= static_cast(MantissaWidth::VALUE)) + if (exponent >= static_cast(FPBits::MANTISSA_WIDTH)) return x; // If the exponent is such that abs(x) is less than 1, then return 0. @@ -47,7 +47,7 @@ LIBC_INLINE T trunc(T x) { return T(0.0); } - int trim_size = MantissaWidth::VALUE - exponent; + int trim_size = FPBits::MANTISSA_WIDTH - exponent; bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size); return T(bits); } @@ -65,7 +65,7 @@ LIBC_INLINE T ceil(T x) { // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. - if (exponent >= static_cast(MantissaWidth::VALUE)) + if (exponent >= static_cast(FPBits::MANTISSA_WIDTH)) return x; if (exponent <= -1) { @@ -75,7 +75,7 @@ LIBC_INLINE T ceil(T x) { return T(1.0); } - uint32_t trim_size = MantissaWidth::VALUE - exponent; + uint32_t trim_size = FPBits::MANTISSA_WIDTH - exponent; bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size); T trunc_value = T(bits); @@ -114,7 +114,7 @@ LIBC_INLINE T round(T x) { // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. - if (exponent >= static_cast(MantissaWidth::VALUE)) + if (exponent >= static_cast(FPBits::MANTISSA_WIDTH)) return x; if (exponent == -1) { @@ -133,7 +133,7 @@ LIBC_INLINE T round(T x) { return T(0.0); } - uint32_t trim_size = MantissaWidth::VALUE - exponent; + uint32_t trim_size = FPBits::MANTISSA_WIDTH - exponent; bool half_bit_set = bool(bits.get_mantissa() & (UIntType(1) << (trim_size - 1))); bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size); @@ -167,7 +167,7 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) { // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. - if (exponent >= static_cast(MantissaWidth::VALUE)) + if (exponent >= static_cast(FPBits::MANTISSA_WIDTH)) return x; if (exponent <= -1) { @@ -188,7 +188,7 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) { } } - uint32_t trim_size = MantissaWidth::VALUE - exponent; + uint32_t trim_size = FPBits::MANTISSA_WIDTH - exponent; FPBits new_bits = bits; new_bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size); T trunc_value = T(new_bits); diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h index d3236316a87995165f6aa2ad1e03e561b5c936bf..397a3bb41673b093a1f8be162c12c8ca9d417dd1 100644 --- a/libc/src/__support/FPUtil/NormalFloat.h +++ b/libc/src/__support/FPUtil/NormalFloat.h @@ -32,7 +32,7 @@ template struct NormalFloat { "NormalFloat template parameter has to be a floating point type."); using UIntType = typename FPBits::UIntType; - static constexpr UIntType ONE = (UIntType(1) << MantissaWidth::VALUE); + static constexpr UIntType ONE = (UIntType(1) << FPBits::MANTISSA_WIDTH); // Unbiased exponent value. int32_t exponent; @@ -40,7 +40,7 @@ template struct NormalFloat { UIntType mantissa; // We want |UIntType| to have atleast one bit more than the actual mantissa // bit width to accommodate the implicit 1 value. - static_assert(sizeof(UIntType) * 8 >= MantissaWidth::VALUE + 1, + static_assert(sizeof(UIntType) * 8 >= FPBits::MANTISSA_WIDTH + 1, "Bad type for mantissa in NormalFloat."); bool sign; @@ -92,7 +92,7 @@ template struct NormalFloat { LIBC_INLINE operator T() const { int biased_exponent = exponent + FPBits::EXPONENT_BIAS; // Max exponent is of the form 0xFF...E. That is why -2 and not -1. - constexpr int MAX_EXPONENT_VALUE = (1 << ExponentWidth::VALUE) - 2; + constexpr int MAX_EXPONENT_VALUE = (1 << FPBits::EXPONENT_WIDTH) - 2; if (biased_exponent > MAX_EXPONENT_VALUE) { return sign ? T(FPBits::neg_inf()) : T(FPBits::inf()); } @@ -105,7 +105,7 @@ template struct NormalFloat { unsigned shift = SUBNORMAL_EXPONENT - exponent; // Since exponent > subnormalExponent, shift is strictly greater than // zero. - if (shift <= MantissaWidth::VALUE + 1) { + if (shift <= FPBits::MANTISSA_WIDTH + 1) { // Generate a subnormal number. Might lead to loss of precision. // We round to nearest and round halfway cases to even. const UIntType shift_out_mask = (UIntType(1) << shift) - 1; @@ -163,7 +163,7 @@ private: LIBC_INLINE unsigned evaluate_normalization_shift(UIntType m) { unsigned shift = 0; - for (; (ONE & m) == 0 && (shift < MantissaWidth::VALUE); + for (; (ONE & m) == 0 && (shift < FPBits::MANTISSA_WIDTH); m <<= 1, ++shift) ; return shift; @@ -208,21 +208,21 @@ NormalFloat::init_from_bits(FPBits bits) { } template <> LIBC_INLINE NormalFloat::operator long double() const { - int biased_exponent = exponent + FPBits::EXPONENT_BIAS; + using LDBits = FPBits; + int biased_exponent = exponent + LDBits::EXPONENT_BIAS; // Max exponent is of the form 0xFF...E. That is why -2 and not -1. - constexpr int MAX_EXPONENT_VALUE = - (1 << ExponentWidth::VALUE) - 2; + constexpr int MAX_EXPONENT_VALUE = (1 << LDBits::EXPONENT_WIDTH) - 2; if (biased_exponent > MAX_EXPONENT_VALUE) { - return sign ? FPBits::neg_inf() : FPBits::inf(); + return sign ? LDBits::neg_inf() : LDBits::inf(); } FPBits result(0.0l); result.set_sign(sign); - constexpr int SUBNORMAL_EXPONENT = -FPBits::EXPONENT_BIAS + 1; + constexpr int SUBNORMAL_EXPONENT = -LDBits::EXPONENT_BIAS + 1; if (exponent < SUBNORMAL_EXPONENT) { unsigned shift = SUBNORMAL_EXPONENT - exponent; - if (shift <= MantissaWidth::VALUE + 1) { + if (shift <= LDBits::MANTISSA_WIDTH + 1) { // Generate a subnormal number. Might lead to loss of precision. // We round to nearest and round halfway cases to even. const UIntType shift_out_mask = (UIntType(1) << shift) - 1; diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h index 61a1401c30e827c63882c7f3fdf0ceec2a593124..3c4d943a7c71fb64d0428528e197ad45639a9eda 100644 --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -159,11 +159,10 @@ template <> LIBC_INLINE double fma(double x, double y, double z) { UInt128 prod_mant = x_mant * y_mant << 10; int prod_lsb_exp = - x_exp + y_exp - - (FPBits::EXPONENT_BIAS + 2 * MantissaWidth::VALUE + 10); + x_exp + y_exp - (FPBits::EXPONENT_BIAS + 2 * FPBits::MANTISSA_WIDTH + 10); z_mant <<= 64; - int z_lsb_exp = z_exp - (MantissaWidth::VALUE + 64); + int z_lsb_exp = z_exp - (FPBits::MANTISSA_WIDTH + 64); bool round_bit = false; bool sticky_bits = false; bool z_shifted = false; diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h index 7502660c88a133da54b71fc870c62318c6f36374..f30586f9d7f341ed226e6f307e1ddee55c69249f 100644 --- a/libc/src/__support/FPUtil/generic/FMod.h +++ b/libc/src/__support/FPUtil/generic/FMod.h @@ -167,11 +167,11 @@ template struct FModFastMathWrapper { template class FModDivisionSimpleHelper { private: - using intU_t = typename FPBits::UIntType; + using UIntType = typename FPBits::UIntType; public: - LIBC_INLINE constexpr static intU_t - execute(int exp_diff, int sides_zeroes_count, intU_t m_x, intU_t m_y) { + LIBC_INLINE constexpr static UIntType + execute(int exp_diff, int sides_zeroes_count, UIntType m_x, UIntType m_y) { while (exp_diff > sides_zeroes_count) { exp_diff -= sides_zeroes_count; m_x <<= sides_zeroes_count; @@ -186,23 +186,22 @@ public: template class FModDivisionInvMultHelper { private: using FPB = FPBits; - using intU_t = typename FPB::UIntType; + using UIntType = typename FPB::UIntType; public: - LIBC_INLINE constexpr static intU_t - execute(int exp_diff, int sides_zeroes_count, intU_t m_x, intU_t m_y) { + LIBC_INLINE constexpr static UIntType + execute(int exp_diff, int sides_zeroes_count, UIntType m_x, UIntType m_y) { if (exp_diff > sides_zeroes_count) { - intU_t inv_hy = (cpp::numeric_limits::max() / m_y); + UIntType inv_hy = (cpp::numeric_limits::max() / m_y); while (exp_diff > sides_zeroes_count) { exp_diff -= sides_zeroes_count; - intU_t hd = - (m_x * inv_hy) >> (FPB::FloatProp::BIT_WIDTH - sides_zeroes_count); + UIntType hd = (m_x * inv_hy) >> (FPB::BIT_WIDTH - sides_zeroes_count); m_x <<= sides_zeroes_count; m_x -= hd * m_y; while (LIBC_UNLIKELY(m_x > m_y)) m_x -= m_y; } - intU_t hd = (m_x * inv_hy) >> (FPB::FloatProp::BIT_WIDTH - exp_diff); + UIntType hd = (m_x * inv_hy) >> (FPB::BIT_WIDTH - exp_diff); m_x <<= exp_diff; m_x -= hd * m_y; while (LIBC_UNLIKELY(m_x > m_y)) @@ -223,7 +222,7 @@ class FMod { private: using FPB = FPBits; - using intU_t = typename FPB::UIntType; + using UIntType = typename FPB::UIntType; LIBC_INLINE static constexpr FPB eval_internal(FPB sx, FPB sy) { @@ -237,11 +236,11 @@ private: int e_y = sy.get_biased_exponent(); // Most common case where |y| is "very normal" and |x/y| < 2^EXPONENT_WIDTH - if (LIBC_LIKELY(e_y > int(FPB::FloatProp::MANTISSA_WIDTH) && - e_x - e_y <= int(FPB::FloatProp::EXPONENT_WIDTH))) { - intU_t m_x = sx.get_explicit_mantissa(); - intU_t m_y = sy.get_explicit_mantissa(); - intU_t d = (e_x == e_y) ? (m_x - m_y) : (m_x << (e_x - e_y)) % m_y; + if (LIBC_LIKELY(e_y > int(FPB::MANTISSA_WIDTH) && + e_x - e_y <= int(FPB::EXPONENT_WIDTH))) { + UIntType m_x = sx.get_explicit_mantissa(); + UIntType m_y = sy.get_explicit_mantissa(); + UIntType d = (e_x == e_y) ? (m_x - m_y) : (m_x << (e_x - e_y)) % m_y; if (d == 0) return FPB(FPB::zero()); // iy - 1 because of "zero power" for number with power 1 @@ -255,11 +254,11 @@ private: } // Note that hx is not subnormal by conditions above. - intU_t m_x = sx.get_explicit_mantissa(); + UIntType m_x = sx.get_explicit_mantissa(); e_x--; - intU_t m_y = sy.get_explicit_mantissa(); - int lead_zeros_m_y = FPB::FloatProp::EXPONENT_WIDTH; + UIntType m_y = sy.get_explicit_mantissa(); + int lead_zeros_m_y = FPB::EXPONENT_WIDTH; if (LIBC_LIKELY(e_y > 0)) { e_y--; } else { @@ -282,9 +281,8 @@ private: { // Shift hx left until the end or n = 0 - int left_shift = exp_diff < int(FPB::FloatProp::EXPONENT_WIDTH) - ? exp_diff - : FPB::FloatProp::EXPONENT_WIDTH; + int left_shift = + exp_diff < int(FPB::EXPONENT_WIDTH) ? exp_diff : FPB::EXPONENT_WIDTH; m_x <<= left_shift; exp_diff -= left_shift; } diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h index 5bde9589fdc012c5686656f21d3d7c515f2b5a5a..cd5ec58bcdbd5fe94d78b782908f9cf90e2ededf 100644 --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -37,7 +37,7 @@ template LIBC_INLINE void normalize(int &exponent, typename FPBits::UIntType &mantissa) { const int shift = cpp::countl_zero(mantissa) - - (8 * sizeof(mantissa) - 1 - MantissaWidth::VALUE); + (8 * sizeof(mantissa) - 1 - FPBits::MANTISSA_WIDTH); exponent -= shift; mantissa <<= shift; } @@ -72,7 +72,7 @@ LIBC_INLINE cpp::enable_if_t, T> sqrt(T x) { } else { // IEEE floating points formats. using UIntType = typename FPBits::UIntType; - constexpr UIntType ONE = UIntType(1) << MantissaWidth::VALUE; + constexpr UIntType ONE = UIntType(1) << FPBits::MANTISSA_WIDTH; FPBits bits(x); @@ -147,7 +147,8 @@ LIBC_INLINE cpp::enable_if_t, T> sqrt(T x) { // Remove hidden bit and append the exponent field. x_exp = ((x_exp >> 1) + FPBits::EXPONENT_BIAS); - y = (y - ONE) | (static_cast(x_exp) << MantissaWidth::VALUE); + y = (y - ONE) | + (static_cast(x_exp) << FPBits::MANTISSA_WIDTH); switch (quick_get_round()) { case FE_TONEAREST: diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h index 2f25be54e0bc3626085687fac6b3ae50e1942eb5..46ca796aeb4b60e29d8e53471066767f14753482 100644 --- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h +++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h @@ -23,7 +23,7 @@ namespace x86 { LIBC_INLINE void normalize(int &exponent, UInt128 &mantissa) { const unsigned int shift = static_cast( cpp::countl_zero(static_cast(mantissa)) - - (8 * sizeof(uint64_t) - 1 - MantissaWidth::VALUE)); + (8 * sizeof(uint64_t) - 1 - FPBits::MANTISSA_WIDTH)); exponent -= shift; mantissa <<= shift; } @@ -36,16 +36,16 @@ LIBC_INLINE long double sqrt(long double x); // Shift-and-add algorithm. #if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80) LIBC_INLINE long double sqrt(long double x) { - using UIntType = typename FPBits::UIntType; - constexpr UIntType ONE = UIntType(1) - << int(MantissaWidth::VALUE); + using LDBits = FPBits; + using UIntType = typename LDBits::UIntType; + constexpr UIntType ONE = UIntType(1) << int(LDBits::MANTISSA_WIDTH); FPBits bits(x); if (bits.is_inf_or_nan()) { if (bits.get_sign() && (bits.get_mantissa() == 0)) { // sqrt(-Inf) = NaN - return FPBits::build_quiet_nan(ONE >> 1); + return LDBits::build_quiet_nan(ONE >> 1); } else { // sqrt(NaN) = NaN // sqrt(+Inf) = +Inf @@ -57,7 +57,7 @@ LIBC_INLINE long double sqrt(long double x) { return x; } else if (bits.get_sign()) { // sqrt( negative numbers ) = NaN - return FPBits::build_quiet_nan(ONE >> 1); + return LDBits::build_quiet_nan(ONE >> 1); } else { int x_exp = bits.get_explicit_exponent(); UIntType x_mant = bits.get_mantissa(); @@ -110,9 +110,8 @@ LIBC_INLINE long double sqrt(long double x) { } // Append the exponent field. - x_exp = ((x_exp >> 1) + FPBits::EXPONENT_BIAS); - y |= (static_cast(x_exp) - << (MantissaWidth::VALUE + 1)); + x_exp = ((x_exp >> 1) + LDBits::EXPONENT_BIAS); + y |= (static_cast(x_exp) << (LDBits::MANTISSA_WIDTH + 1)); switch (quick_get_round()) { case FE_TONEAREST: diff --git a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h index f1ef928f2308194321eb5913e8e0eba32aeccb72..a31667528be2b0081c94eabcd73c3e810348b32f 100644 --- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h +++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h @@ -26,74 +26,73 @@ namespace LIBC_NAMESPACE { namespace fputil { -template <> struct FPBits { - using UIntType = UInt128; +template <> struct FPBits : private FloatProperties { + using typename FloatProperties::UIntType; + using FloatProperties::BIT_WIDTH; + using FloatProperties::EXP_MANT_MASK; + using FloatProperties::EXPONENT_MASK; + using FloatProperties::EXPONENT_BIAS; + using FloatProperties::EXPONENT_WIDTH; + using FloatProperties::MANTISSA_MASK; + using FloatProperties::MANTISSA_WIDTH; + using FloatProperties::QUIET_NAN_MASK; + using FloatProperties::SIGN_MASK; - static constexpr int EXPONENT_BIAS = 0x3FFF; static constexpr int MAX_EXPONENT = 0x7FFF; static constexpr UIntType MIN_SUBNORMAL = UIntType(1); // Subnormal numbers include the implicit bit in x86 long double formats. - static constexpr UIntType MAX_SUBNORMAL = - (UIntType(1) << (MantissaWidth::VALUE)) - 1; - static constexpr UIntType MIN_NORMAL = - (UIntType(3) << MantissaWidth::VALUE); + static constexpr UIntType MAX_SUBNORMAL = (UIntType(1) << MANTISSA_WIDTH) - 1; + static constexpr UIntType MIN_NORMAL = (UIntType(3) << MANTISSA_WIDTH); static constexpr UIntType MAX_NORMAL = - (UIntType(MAX_EXPONENT - 1) << (MantissaWidth::VALUE + 1)) | - (UIntType(1) << MantissaWidth::VALUE) | MAX_SUBNORMAL; - - using FloatProp = FloatProperties; + (UIntType(MAX_EXPONENT - 1) << (MANTISSA_WIDTH + 1)) | + (UIntType(1) << MANTISSA_WIDTH) | MAX_SUBNORMAL; UIntType bits; LIBC_INLINE constexpr void set_mantissa(UIntType mantVal) { - mantVal &= (FloatProp::MANTISSA_MASK); - bits &= ~(FloatProp::MANTISSA_MASK); + mantVal &= MANTISSA_MASK; + bits &= ~MANTISSA_MASK; bits |= mantVal; } LIBC_INLINE constexpr UIntType get_mantissa() const { - return bits & FloatProp::MANTISSA_MASK; + return bits & MANTISSA_MASK; } LIBC_INLINE constexpr UIntType get_explicit_mantissa() const { // The x86 80 bit float represents the leading digit of the mantissa // explicitly. This is the mask for that bit. - constexpr UIntType EXPLICIT_BIT_MASK = - (UIntType(1) << FloatProp::MANTISSA_WIDTH); - return bits & (FloatProp::MANTISSA_MASK | EXPLICIT_BIT_MASK); + constexpr UIntType EXPLICIT_BIT_MASK = UIntType(1) << MANTISSA_WIDTH; + return bits & (MANTISSA_MASK | EXPLICIT_BIT_MASK); } LIBC_INLINE constexpr void set_biased_exponent(UIntType expVal) { - expVal = - (expVal << (FloatProp::BIT_WIDTH - 1 - FloatProp::EXPONENT_WIDTH)) & - FloatProp::EXPONENT_MASK; - bits &= ~(FloatProp::EXPONENT_MASK); + expVal = (expVal << (BIT_WIDTH - 1 - EXPONENT_WIDTH)) & EXPONENT_MASK; + bits &= ~EXPONENT_MASK; bits |= expVal; } LIBC_INLINE constexpr uint16_t get_biased_exponent() const { - return uint16_t((bits & FloatProp::EXPONENT_MASK) >> - (FloatProp::BIT_WIDTH - 1 - FloatProp::EXPONENT_WIDTH)); + return uint16_t((bits & EXPONENT_MASK) >> (BIT_WIDTH - 1 - EXPONENT_WIDTH)); } LIBC_INLINE constexpr void set_implicit_bit(bool implicitVal) { - bits &= ~(UIntType(1) << FloatProp::MANTISSA_WIDTH); - bits |= (UIntType(implicitVal) << FloatProp::MANTISSA_WIDTH); + bits &= ~(UIntType(1) << MANTISSA_WIDTH); + bits |= (UIntType(implicitVal) << MANTISSA_WIDTH); } LIBC_INLINE constexpr bool get_implicit_bit() const { - return bool((bits & (UIntType(1) << FloatProp::MANTISSA_WIDTH)) >> - FloatProp::MANTISSA_WIDTH); + return bool((bits & (UIntType(1) << MANTISSA_WIDTH)) >> MANTISSA_WIDTH); } LIBC_INLINE constexpr void set_sign(bool signVal) { - bits &= ~(FloatProp::SIGN_MASK); - UIntType sign1 = UIntType(signVal) << (FloatProp::BIT_WIDTH - 1); + bits &= ~SIGN_MASK; + UIntType sign1 = UIntType(signVal) << (BIT_WIDTH - 1); bits |= sign1; } LIBC_INLINE constexpr bool get_sign() const { - return bool((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1)); + return bool((bits & SIGN_MASK) >> (BIT_WIDTH - 1)); } LIBC_INLINE constexpr FPBits() : bits(0) {} @@ -117,7 +116,7 @@ template <> struct FPBits { LIBC_INLINE constexpr UIntType uintval() { // We zero the padding bits as they can contain garbage. - return bits & FloatProp::FP_MASK; + return bits & FP_MASK; } LIBC_INLINE constexpr long double get_val() const { @@ -196,7 +195,7 @@ template <> struct FPBits { } LIBC_INLINE static constexpr long double build_quiet_nan(UIntType v) { - return build_nan(FloatProp::QUIET_NAN_MASK | v); + return build_nan(QUIET_NAN_MASK | v); } LIBC_INLINE static constexpr long double min_normal() { diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h index 5e32f766ad58636f3efa75119462de8380e06458..653b6a48f3cc53b212f96878e6b4b36c0be6517b 100644 --- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h +++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h @@ -46,7 +46,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) { using UIntType = FPBits::UIntType; constexpr UIntType SIGN_VAL = (UIntType(1) << 79); constexpr UIntType MANTISSA_MASK = - (UIntType(1) << MantissaWidth::VALUE) - 1; + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1; UIntType int_val = from_bits.uintval(); if (from < 0.0l) { if (from > to) { @@ -117,8 +117,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) { } } - UIntType implicit_bit = - int_val & (UIntType(1) << MantissaWidth::VALUE); + UIntType implicit_bit = int_val & (UIntType(1) << FPBits::MANTISSA_WIDTH); if (implicit_bit == UIntType(0)) raise_except_if_required(FE_UNDERFLOW | FE_INEXACT); diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp index 2d4cea5b53c5815c8ff9a3f5a1387a27c8b17c2a..b84da64cbe6358957a86b93d33aa5a0044693f20 100644 --- a/libc/src/__support/File/linux/file.cpp +++ b/libc/src/__support/File/linux/file.cpp @@ -17,6 +17,7 @@ #include // For mode_t and other flags to the open syscall #include +#include // For S_IS*, S_IF*, and S_IR* flags. #include // For syscall numbers namespace LIBC_NAMESPACE { diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h index be105830a91ac1c25e7b9ed47ed34846c98345b5..d53bb4b4c62b15958fd7a96feac8bdb6d272f524 100644 --- a/libc/src/__support/float_to_string.h +++ b/libc/src/__support/float_to_string.h @@ -416,7 +416,7 @@ class FloatToString { int exponent; FloatProp::UIntType mantissa; - static constexpr int MANT_WIDTH = fputil::MantissaWidth::VALUE; + static constexpr int MANT_WIDTH = fputil::FPBits::MANTISSA_WIDTH; static constexpr int EXP_BIAS = fputil::FPBits::EXPONENT_BIAS; public: diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h index 2a6f15c018f1ecbd0707d46957fa8ab3df407e99..3807d3ff572162ddc633ead9a31e5a9c35258b16 100644 --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -71,7 +71,7 @@ LIBC_INLINE cpp::optional> eisel_lemire(ExpandedFloat init_num, RoundDirection round = RoundDirection::Nearest) { using FPBits = typename fputil::FPBits; - using FloatProp = typename FPBits::FloatProp; + using FloatProp = typename fputil::FloatProperties; using UIntType = typename FPBits::UIntType; UIntType mantissa = init_num.mantissa; @@ -184,7 +184,7 @@ LIBC_INLINE cpp::optional> eisel_lemire(ExpandedFloat init_num, RoundDirection round) { using FPBits = typename fputil::FPBits; - using FloatProp = typename FPBits::FloatProp; + using FloatProp = typename fputil::FloatProperties; using UIntType = typename FPBits::UIntType; UIntType mantissa = init_num.mantissa; @@ -322,7 +322,7 @@ LIBC_INLINE FloatConvertReturn simple_decimal_conversion(const char *__restrict numStart, RoundDirection round = RoundDirection::Nearest) { using FPBits = typename fputil::FPBits; - using FloatProp = typename FPBits::FloatProp; + using FloatProp = typename fputil::FloatProperties; using UIntType = typename FPBits::UIntType; int32_t exp2 = 0; @@ -516,7 +516,7 @@ LIBC_INLINE cpp::optional> clinger_fast_path(ExpandedFloat init_num, RoundDirection round = RoundDirection::Nearest) { using FPBits = typename fputil::FPBits; - using FloatProp = typename FPBits::FloatProp; + using FloatProp = typename fputil::FloatProperties; using UIntType = typename FPBits::UIntType; UIntType mantissa = init_num.mantissa; @@ -724,7 +724,7 @@ LIBC_INLINE FloatConvertReturn binary_exp_to_float(ExpandedFloat init_num, bool truncated, RoundDirection round) { using FPBits = typename fputil::FPBits; - using FloatProp = typename FPBits::FloatProp; + using FloatProp = typename fputil::FloatProperties; using UIntType = typename FPBits::UIntType; UIntType mantissa = init_num.mantissa; diff --git a/libc/src/math/generic/acoshf.cpp b/libc/src/math/generic/acoshf.cpp index 9438be1bee74eb4614739319a35f200b17c5f568..142c17795d083a2cbfa359935539fc207cd50956 100644 --- a/libc/src/math/generic/acoshf.cpp +++ b/libc/src/math/generic/acoshf.cpp @@ -34,7 +34,7 @@ LLVM_LIBC_FUNCTION(float, acoshf, (float x)) { if (LIBC_UNLIKELY(x_u >= 0x4f8ffb03)) { // Check for exceptional values. - uint32_t x_abs = x_u & FPBits_t::FloatProp::EXP_MANT_MASK; + uint32_t x_abs = x_u & FPBits_t::EXP_MANT_MASK; if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { // x is +inf or NaN. return x; diff --git a/libc/src/math/generic/asinf.cpp b/libc/src/math/generic/asinf.cpp index f40a08e752ed3989247f3462cc77f79f90591e55..5406e6660d78415370547dc030e8339c629633ec 100644 --- a/libc/src/math/generic/asinf.cpp +++ b/libc/src/math/generic/asinf.cpp @@ -108,8 +108,7 @@ LLVM_LIBC_FUNCTION(float, asinf, (float x)) { fputil::set_errno_if_required(EDOM); fputil::raise_except_if_required(FE_INVALID); } - return x + - FPBits::build_nan(1 << (fputil::MantissaWidth::VALUE - 1)); + return x + FPBits::build_nan(1 << (FPBits::MANTISSA_WIDTH - 1)); } // Check for exceptional values diff --git a/libc/src/math/generic/asinhf.cpp b/libc/src/math/generic/asinhf.cpp index 6bde08d42a429cdd3533b0ea389399c8c95709d9..5b2f63d3fe144e9700536d5716eb57ff3e1128b2 100644 --- a/libc/src/math/generic/asinhf.cpp +++ b/libc/src/math/generic/asinhf.cpp @@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(float, asinhf, (float x)) { using FPBits_t = typename fputil::FPBits; FPBits_t xbits(x); uint32_t x_u = xbits.uintval(); - uint32_t x_abs = x_u & FPBits_t::FloatProp::EXP_MANT_MASK; + uint32_t x_abs = x_u & FPBits_t::EXP_MANT_MASK; // |x| <= 2^-3 if (LIBC_UNLIKELY(x_abs <= 0x3e80'0000U)) { diff --git a/libc/src/math/generic/atanhf.cpp b/libc/src/math/generic/atanhf.cpp index 839ef5b076ac35576a854c837687e160ecd4de84..dfec28e9a44a7234a27cb941080d2663b9ad4414 100644 --- a/libc/src/math/generic/atanhf.cpp +++ b/libc/src/math/generic/atanhf.cpp @@ -17,7 +17,7 @@ LLVM_LIBC_FUNCTION(float, atanhf, (float x)) { using FPBits = typename fputil::FPBits; FPBits xbits(x); bool sign = xbits.get_sign(); - uint32_t x_abs = xbits.uintval() & FPBits::FloatProp::EXP_MANT_MASK; + uint32_t x_abs = xbits.uintval() & FPBits::EXP_MANT_MASK; // |x| >= 1.0 if (LIBC_UNLIKELY(x_abs >= 0x3F80'0000U)) { diff --git a/libc/src/math/generic/erff.cpp b/libc/src/math/generic/erff.cpp index a7b0897c3b58cb76a900c1b5429fac53e145ad49..d63fb8e31384d2415343b02d2de257d9de83bbf2 100644 --- a/libc/src/math/generic/erff.cpp +++ b/libc/src/math/generic/erff.cpp @@ -154,7 +154,7 @@ LLVM_LIBC_FUNCTION(float, erff, (float x)) { double xd = static_cast(x); double xsq = xd * xd; - const uint32_t EIGHT = 3 << FPBits::FloatProp::MANTISSA_WIDTH; + const uint32_t EIGHT = 3 << FPBits::MANTISSA_WIDTH; int idx = static_cast(FPBits(x_abs + EIGHT).get_val()); double x4 = xsq * xsq; diff --git a/libc/src/math/generic/explogxf.h b/libc/src/math/generic/explogxf.h index 77ec9cb94e085455355f4a4e776516268e25e618..3dae5af068b4b010c0f49c93cfa5ca3812ef73cf 100644 --- a/libc/src/math/generic/explogxf.h +++ b/libc/src/math/generic/explogxf.h @@ -280,12 +280,11 @@ LIBC_INLINE static double log2_eval(double x) { double result = 0; result += bs.get_exponent(); - int p1 = - (bs.get_mantissa() >> (FPB::FloatProp::MANTISSA_WIDTH - LOG_P1_BITS)) & - (LOG_P1_SIZE - 1); + int p1 = (bs.get_mantissa() >> (FPB::MANTISSA_WIDTH - LOG_P1_BITS)) & + (LOG_P1_SIZE - 1); - bs.bits &= FPB::FloatProp::MANTISSA_MASK >> LOG_P1_BITS; - bs.set_biased_exponent(FPB::FloatProp::EXPONENT_BIAS); + bs.bits &= FPB::MANTISSA_MASK >> LOG_P1_BITS; + bs.set_biased_exponent(FPB::EXPONENT_BIAS); double dx = (bs.get_val() - 1.0) * LOG_P1_1_OVER[p1]; // Taylor series for log(2,1+x) @@ -311,12 +310,11 @@ LIBC_INLINE static double log_eval(double x) { // p1 is the leading 7 bits of mx, i.e. // p1 * 2^(-7) <= m_x < (p1 + 1) * 2^(-7). - int p1 = static_cast(bs.get_mantissa() >> - (FPB::FloatProp::MANTISSA_WIDTH - 7)); + int p1 = static_cast(bs.get_mantissa() >> (FPB::MANTISSA_WIDTH - 7)); // Set bs to (1 + (mx - p1*2^(-7)) - bs.bits &= FPB::FloatProp::MANTISSA_MASK >> 7; - bs.set_biased_exponent(FPB::FloatProp::EXPONENT_BIAS); + bs.bits &= FPB::MANTISSA_MASK >> 7; + bs.set_biased_exponent(FPB::EXPONENT_BIAS); // dx = (mx - p1*2^(-7)) / (1 + p1*2^(-7)). double dx = (bs.get_val() - 1.0) * ONE_OVER_F[p1]; diff --git a/libc/src/math/generic/hypotf.cpp b/libc/src/math/generic/hypotf.cpp index 389de3c450299d479ad4c53a1daf8e9568b79ab3..5795291a043ae6eeb944cfedcedf84ea58fea058 100644 --- a/libc/src/math/generic/hypotf.cpp +++ b/libc/src/math/generic/hypotf.cpp @@ -23,7 +23,7 @@ LLVM_LIBC_FUNCTION(float, hypotf, (float x, float y)) { uint16_t y_exp = y_bits.get_biased_exponent(); uint16_t exp_diff = (x_exp > y_exp) ? (x_exp - y_exp) : (y_exp - x_exp); - if (exp_diff >= fputil::MantissaWidth::VALUE + 2) { + if (exp_diff >= FPBits::MANTISSA_WIDTH + 2) { return fputil::abs(x) + fputil::abs(y); } diff --git a/libc/src/math/generic/inv_trigf_utils.h b/libc/src/math/generic/inv_trigf_utils.h index c88ded20b5bf24f4da93451cd1cad2d22604ba62..2ecd033ecbed6d5816e8404009097f9e6fbb84c9 100644 --- a/libc/src/math/generic/inv_trigf_utils.h +++ b/libc/src/math/generic/inv_trigf_utils.h @@ -51,7 +51,7 @@ LIBC_INLINE double atan_eval(double x) { FPB bs(x); bool sign = bs.get_sign(); - auto x_abs = bs.uintval() & FPB::FloatProp::EXP_MANT_MASK; + auto x_abs = bs.uintval() & FPB::EXP_MANT_MASK; if (x_abs <= umin) { double pe = LIBC_NAMESPACE::fputil::polyeval( @@ -64,7 +64,8 @@ LIBC_INLINE double atan_eval(double x) { double one_over_x2 = one_over_x_m * one_over_x_m; double pe = LIBC_NAMESPACE::fputil::polyeval( one_over_x2, ATAN_K[0], ATAN_K[1], ATAN_K[2], ATAN_K[3]); - return fputil::multiply_add(pe, one_over_x_m, sign ? (-M_MATH_PI_2) : (M_MATH_PI_2)); + return fputil::multiply_add(pe, one_over_x_m, + sign ? (-M_MATH_PI_2) : (M_MATH_PI_2)); } double pos_x = FPB(x_abs).get_val(); diff --git a/libc/src/math/generic/log1p.cpp b/libc/src/math/generic/log1p.cpp index c8b45fd57b42f8803bdd1102e7ff31085d6b89a1..757f2793cb9cf794ac3f574a0c8cae3e5ac416fd 100644 --- a/libc/src/math/generic/log1p.cpp +++ b/libc/src/math/generic/log1p.cpp @@ -873,8 +873,8 @@ LIBC_INLINE double log1p_accurate(int e_x, int index, LLVM_LIBC_FUNCTION(double, log1p, (double x)) { using FPBits_t = typename fputil::FPBits; constexpr int EXPONENT_BIAS = FPBits_t::EXPONENT_BIAS; - constexpr int MANTISSA_WIDTH = FPBits_t::FloatProp::MANTISSA_WIDTH; - constexpr uint64_t MANTISSA_MASK = FPBits_t::FloatProp::MANTISSA_MASK; + constexpr int MANTISSA_WIDTH = FPBits_t::MANTISSA_WIDTH; + constexpr uint64_t MANTISSA_MASK = FPBits_t::MANTISSA_MASK; FPBits_t xbits(x); uint64_t x_u = xbits.uintval(); @@ -969,7 +969,7 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) { // Scaling factior = 2^(-xh_bits.get_exponent()) uint64_t s_u = (static_cast(EXPONENT_BIAS) << (MANTISSA_WIDTH + 1)) - - (x_u & FPBits_t::FloatProp::EXPONENT_MASK); + (x_u & FPBits_t::EXPONENT_MASK); // When the exponent of x is 2^1023, its inverse, 2^(-1023), is subnormal. const double EXPONENT_CORRECTION[2] = {0.0, 0x1.0p-1023}; double scaling = FPBits_t(s_u).get_val() + EXPONENT_CORRECTION[s_u == 0]; diff --git a/libc/src/math/generic/log1pf.cpp b/libc/src/math/generic/log1pf.cpp index fd3cf4647fd0da93f3c9bb5330b8118eb2f6047e..fabd2bdc31bf3b511ae6812e470fe476f580257b 100644 --- a/libc/src/math/generic/log1pf.cpp +++ b/libc/src/math/generic/log1pf.cpp @@ -56,8 +56,8 @@ LIBC_INLINE float log(double x) { // Get the 8 highest bits, use 7 bits (excluding the implicit hidden bit) for // lookup tables. - int f_index = static_cast( - xbits.get_mantissa() >> 45); // fputil::MantissaWidth::VALUE - 7 + int f_index = static_cast(xbits.get_mantissa() >> + (fputil::FPBits::MANTISSA_WIDTH - 7)); // Set bits to 1.m xbits.set_biased_exponent(0x3FF); diff --git a/libc/src/math/generic/sincosf.cpp b/libc/src/math/generic/sincosf.cpp index 7ed1c4381078b1f2460d9106db3c26829e680203..c5694fd1bea58052043d22e8a0c3843405879e60 100644 --- a/libc/src/math/generic/sincosf.cpp +++ b/libc/src/math/generic/sincosf.cpp @@ -148,8 +148,7 @@ LLVM_LIBC_FUNCTION(void, sincosf, (float x, float *sinp, float *cosp)) { fputil::set_errno_if_required(EDOM); fputil::raise_except_if_required(FE_INVALID); } - *sinp = - x + FPBits::build_nan(1 << (fputil::MantissaWidth::VALUE - 1)); + *sinp = x + FPBits::build_nan(1 << (FPBits::MANTISSA_WIDTH - 1)); *cosp = *sinp; return; } diff --git a/libc/src/math/generic/sinhf.cpp b/libc/src/math/generic/sinhf.cpp index 2f48ddbc0f88d3c47531636b343632536f935cc0..db6794620b068c7dede0e529e8c7c13adcd6aa98 100644 --- a/libc/src/math/generic/sinhf.cpp +++ b/libc/src/math/generic/sinhf.cpp @@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(float, sinhf, (float x)) { using FPBits = typename fputil::FPBits; FPBits xbits(x); - uint32_t x_abs = xbits.uintval() & FPBits::FloatProp::EXP_MANT_MASK; + uint32_t x_abs = xbits.uintval() & FPBits::EXP_MANT_MASK; // When |x| >= 90, or x is inf or nan if (LIBC_UNLIKELY(x_abs >= 0x42b4'0000U || x_abs <= 0x3da0'0000U)) { @@ -57,8 +57,7 @@ LLVM_LIBC_FUNCTION(float, sinhf, (float x)) { int rounding = fputil::quick_get_round(); if (sign) { if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) - return FPBits(FPBits::MAX_NORMAL | FPBits::FloatProp::SIGN_MASK) - .get_val(); + return FPBits(FPBits::MAX_NORMAL | FPBits::SIGN_MASK).get_val(); } else { if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) return FPBits(FPBits::MAX_NORMAL).get_val(); diff --git a/libc/src/math/generic/tanhf.cpp b/libc/src/math/generic/tanhf.cpp index 7d9f86cf9044b237941896b150f16779aeee882b..a0046d3dabc62d08400f7deac3833177aa910358 100644 --- a/libc/src/math/generic/tanhf.cpp +++ b/libc/src/math/generic/tanhf.cpp @@ -24,7 +24,7 @@ LLVM_LIBC_FUNCTION(float, tanhf, (float x)) { using FPBits = typename fputil::FPBits; FPBits xbits(x); uint32_t x_u = xbits.uintval(); - uint32_t x_abs = x_u & FPBits::FloatProp::EXP_MANT_MASK; + uint32_t x_abs = x_u & FPBits::EXP_MANT_MASK; // When |x| >= 15, or x is inf or nan, or |x| <= 0.078125 if (LIBC_UNLIKELY((x_abs >= 0x4170'0000U) || (x_abs <= 0x3da0'0000U))) { diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h index ca522710040696354de0ddf22f3c04bf6aa573fb..98b573646f7c317197ce9a79a8a1227abc859387 100644 --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -478,7 +478,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer, const FormatSection &to_conv, fputil::FPBits float_bits) { // signed because later we use -MANT_WIDTH - constexpr int32_t MANT_WIDTH = fputil::MantissaWidth::VALUE; + constexpr int32_t MANT_WIDTH = fputil::FloatProperties::MANTISSA_WIDTH; bool is_negative = float_bits.get_sign(); int exponent = float_bits.get_explicit_exponent(); @@ -591,7 +591,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer, const FormatSection &to_conv, fputil::FPBits float_bits) { // signed because later we use -MANT_WIDTH - constexpr int32_t MANT_WIDTH = fputil::MantissaWidth::VALUE; + constexpr int32_t MANT_WIDTH = fputil::FloatProperties::MANTISSA_WIDTH; bool is_negative = float_bits.get_sign(); int exponent = float_bits.get_explicit_exponent(); MantissaInt mantissa = float_bits.get_explicit_mantissa(); @@ -754,7 +754,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer, const FormatSection &to_conv, fputil::FPBits float_bits) { // signed because later we use -MANT_WIDTH - constexpr int32_t MANT_WIDTH = fputil::MantissaWidth::VALUE; + constexpr int32_t MANT_WIDTH = fputil::FloatProperties::MANTISSA_WIDTH; bool is_negative = float_bits.get_sign(); int exponent = float_bits.get_explicit_exponent(); MantissaInt mantissa = float_bits.get_explicit_mantissa(); diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h index 1f105492e8e5a3944608ce3f3384769b4581a0fd..cb10e219388be8a1a2f1532976cc5750326093f0 100644 --- a/libc/src/stdio/printf_core/float_hex_converter.h +++ b/libc/src/stdio/printf_core/float_hex_converter.h @@ -25,10 +25,10 @@ namespace LIBC_NAMESPACE { namespace printf_core { -using MantissaInt = fputil::FPBits::UIntType; - LIBC_INLINE int convert_float_hex_exp(Writer *writer, const FormatSection &to_conv) { + using LDBits = fputil::FPBits; + using MantissaInt = LDBits::UIntType; // All of the letters will be defined relative to variable a, which will be // the appropriate case based on the name of the conversion. This converts any // conversion name into the letter 'a' with the appropriate case. @@ -40,18 +40,19 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer, bool is_inf_or_nan; uint32_t mantissa_width; if (to_conv.length_modifier == LengthModifier::L) { - mantissa_width = fputil::MantissaWidth::VALUE; - fputil::FPBits::UIntType float_raw = to_conv.conv_val_raw; - fputil::FPBits float_bits(float_raw); + mantissa_width = LDBits::MANTISSA_WIDTH; + LDBits::UIntType float_raw = to_conv.conv_val_raw; + LDBits float_bits(float_raw); is_negative = float_bits.get_sign(); exponent = float_bits.get_explicit_exponent(); mantissa = float_bits.get_explicit_mantissa(); is_inf_or_nan = float_bits.is_inf_or_nan(); } else { - mantissa_width = fputil::MantissaWidth::VALUE; - fputil::FPBits::UIntType float_raw = - static_cast::UIntType>(to_conv.conv_val_raw); - fputil::FPBits float_bits(float_raw); + using LBits = fputil::FPBits; + mantissa_width = LBits::MANTISSA_WIDTH; + LBits::UIntType float_raw = + static_cast(to_conv.conv_val_raw); + LBits float_bits(float_raw); is_negative = float_bits.get_sign(); exponent = float_bits.get_explicit_exponent(); mantissa = float_bits.get_explicit_mantissa(); @@ -86,7 +87,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer, // for the extra implicit bit. We use the larger of the two possible values // since the size must be constant. constexpr size_t MANT_BUFF_LEN = - (fputil::MantissaWidth::VALUE / BITS_IN_HEX_DIGIT) + 1; + (LDBits::MANTISSA_WIDTH / BITS_IN_HEX_DIGIT) + 1; char mant_buffer[MANT_BUFF_LEN]; size_t mant_len = (mantissa_width / BITS_IN_HEX_DIGIT) + 1; @@ -157,8 +158,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer, // 15 -> 5 // 11 -> 4 // 8 -> 3 - constexpr size_t EXP_LEN = - (((fputil::ExponentWidth::VALUE * 5) + 15) / 16) + 1; + constexpr size_t EXP_LEN = (((LDBits::EXPONENT_WIDTH * 5) + 15) / 16) + 1; char exp_buffer[EXP_LEN]; bool exp_is_negative = false; diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt index c54d32eb7afdb1adf07630323f32f2c9a52838f4..a4d51fb9a11eef19d5fe512b552b8ccfd63516e1 100644 --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -268,18 +268,27 @@ if(LLVM_LIBC_INCLUDE_SCUDO) set(SCUDO_DEPS "") include(${LIBC_SOURCE_DIR}/../compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake) - if(NOT (LIBC_TARGET_ARCHITECTURE IN_LIST ALL_SCUDO_STANDALONE_SUPPORTED_ARCH)) - message(FATAL_ERROR "Architecture ${LIBC_TARGET_ARCHITECTURE} is not supported by SCUDO. + + # scudo distinguishes riscv32 and riscv64, so we need to translate the architecture + set(LIBC_TARGET_ARCHITECTURE_FOR_SCUDO ${LIBC_TARGET_ARCHITECTURE}) + if(LIBC_TARGET_ARCHITECTURE_IS_RISCV64) + set(LIBC_TARGET_ARCHITECTURE_FOR_SCUDO riscv64) + elseif(LIBC_TARGET_ARCHITECTURE_IS_RISCV32) + set(LIBC_TARGET_ARCHITECTURE_FOR_SCUDO riscv32) + endif() + + if(NOT (LIBC_TARGET_ARCHITECTURE_FOR_SCUDO IN_LIST ALL_SCUDO_STANDALONE_SUPPORTED_ARCH)) + message(FATAL_ERROR "Architecture ${LIBC_TARGET_ARCHITECTURE_FOR_SCUDO} is not supported by SCUDO. Either disable LLVM_LIBC_INCLUDE_SCUDO or change your target architecture.") endif() - list(APPEND SCUDO_DEPS RTScudoStandalone.${LIBC_TARGET_ARCHITECTURE} - RTScudoStandaloneCWrappers.${LIBC_TARGET_ARCHITECTURE}) + list(APPEND SCUDO_DEPS RTScudoStandalone.${LIBC_TARGET_ARCHITECTURE_FOR_SCUDO} + RTScudoStandaloneCWrappers.${LIBC_TARGET_ARCHITECTURE_FOR_SCUDO}) list(APPEND SCUDO_DEPS - RTGwpAsan.${LIBC_TARGET_ARCHITECTURE} - RTGwpAsanBacktraceLibc.${LIBC_TARGET_ARCHITECTURE} - RTGwpAsanSegvHandler.${LIBC_TARGET_ARCHITECTURE} + RTGwpAsan.${LIBC_TARGET_ARCHITECTURE_FOR_SCUDO} + RTGwpAsanBacktraceLibc.${LIBC_TARGET_ARCHITECTURE_FOR_SCUDO} + RTGwpAsanSegvHandler.${LIBC_TARGET_ARCHITECTURE_FOR_SCUDO} ) add_entrypoint_external( diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt index 7079d6e4466c68311a088ea70bb8504687a22ce7..e0bc48735a031465093ed511cdc5d4c0cc23e964 100644 --- a/libc/src/sys/socket/CMakeLists.txt +++ b/libc/src/sys/socket/CMakeLists.txt @@ -9,3 +9,9 @@ add_entrypoint_object( .${LIBC_TARGET_OS}.socket ) +add_entrypoint_object( + bind + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.bind +) diff --git a/libc/src/sys/socket/bind.h b/libc/src/sys/socket/bind.h new file mode 100644 index 0000000000000000000000000000000000000000..62e6221bf1b2d74f6b69fca1b4f95bbab5caeba6 --- /dev/null +++ b/libc/src/sys/socket/bind.h @@ -0,0 +1,20 @@ +//===-- Implementation header for bind --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_SOCKET_BIND_H +#define LLVM_LIBC_SRC_SYS_SOCKET_BIND_H + +#include + +namespace LIBC_NAMESPACE { + +int bind(int domain, const struct sockaddr *address, socklen_t address_len); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_SYS_SOCKET_BIND_H diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt index 41bcc9c9055f4769d8a68c3b125ffc80636887f9..fc9febdec2cc3c3b77213ad28dbb5b4dbe266c44 100644 --- a/libc/src/sys/socket/linux/CMakeLists.txt +++ b/libc/src/sys/socket/linux/CMakeLists.txt @@ -10,3 +10,16 @@ add_entrypoint_object( libc.src.__support.OSUtil.osutil libc.src.errno.errno ) + +add_entrypoint_object( + bind + SRCS + bind.cpp + HDRS + ../bind.h + DEPENDS + libc.include.sys_syscall + libc.include.sys_socket + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) diff --git a/libc/src/sys/socket/linux/bind.cpp b/libc/src/sys/socket/linux/bind.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36afc646d29f6d0f10de6074b1073ac4b0e9ed4c --- /dev/null +++ b/libc/src/sys/socket/linux/bind.cpp @@ -0,0 +1,43 @@ +//===-- Linux implementation of bind --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/sys/socket/bind.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include "src/errno/libc_errno.h" + +#include // For SYS_SOCKET socketcall number. +#include // For syscall numbers. + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(int, bind, + (int domain, const struct sockaddr *address, + socklen_t address_len)) { +#ifdef SYS_socket + int ret = + LIBC_NAMESPACE::syscall_impl(SYS_bind, domain, address, address_len); +#elif defined(SYS_socketcall) + unsigned long sockcall_args[3] = {static_cast(domain), + reinterpret_cast(address), + static_cast(address_len)}; + int ret = LIBC_NAMESPACE::syscall_impl(SYS_socketcall, SYS_BIND, + sockcall_args); +#else +#error "socket and socketcall syscalls unavailable for this platform." +#endif + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return ret; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/sys/socket/linux/socket.cpp b/libc/src/sys/socket/linux/socket.cpp index 6429fd12013ea04397ff1f89b8e525e7a70fd9a5..90a7dc632e26960aab6cf24962269900c9096839 100644 --- a/libc/src/sys/socket/linux/socket.cpp +++ b/libc/src/sys/socket/linux/socket.cpp @@ -23,7 +23,9 @@ LLVM_LIBC_FUNCTION(int, socket, (int domain, int type, int protocol)) { int ret = LIBC_NAMESPACE::syscall_impl(SYS_socket, domain, type, protocol); #elif defined(SYS_socketcall) - unsigned long sockcall_args[3] = {domain, type, protocol}; + unsigned long sockcall_args[3] = {static_cast(domain), + static_cast(type), + static_cast(protocol)}; int ret = LIBC_NAMESPACE::syscall_impl(SYS_socketcall, SYS_SOCKET, sockcall_args); #else diff --git a/libc/test/src/fcntl/creat_test.cpp b/libc/test/src/fcntl/creat_test.cpp index ca926b30e62faf72134abfaf973d372765fafe3b..ef30d8862c45f263bdc93b9d96a10c80f503d9bd 100644 --- a/libc/test/src/fcntl/creat_test.cpp +++ b/libc/test/src/fcntl/creat_test.cpp @@ -13,6 +13,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcCreatTest, CreatAndOpen) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_FILE = "testdata/creat.test"; diff --git a/libc/test/src/math/FDimTest.h b/libc/test/src/math/FDimTest.h index 3118c3661013e7cf97101e8cdb28adba09145972..3fb82ed8bca2ced18689ce45edd4e8089289665f 100644 --- a/libc/test/src/math/FDimTest.h +++ b/libc/test/src/math/FDimTest.h @@ -74,9 +74,9 @@ public: private: // constexpr does not work on FPBits yet, so we cannot have these constants as // static. - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); + const T nan = T(FPBits::build_quiet_nan(1)); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); }; diff --git a/libc/test/src/math/FmaTest.h b/libc/test/src/math/FmaTest.h index c2573d03792692fa9d27481176c2bc96fad46dea..94412b7021df37934d64d488dd9182fe33b67ea5 100644 --- a/libc/test/src/math/FmaTest.h +++ b/libc/test/src/math/FmaTest.h @@ -23,11 +23,11 @@ private: using Func = T (*)(T, T, T); using FPBits = LIBC_NAMESPACE::fputil::FPBits; using UIntType = typename FPBits::UIntType; - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); + const T nan = T(FPBits::build_quiet_nan(1)); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); UIntType get_random_bit_pattern() { UIntType bits{0}; diff --git a/libc/test/src/math/FrexpTest.h b/libc/test/src/math/FrexpTest.h index 19c98872e0411671bf445d22f1dee1442ab543c6..2f93987b1ea75f7aff3155e5665ef224cc5f2818 100644 --- a/libc/test/src/math/FrexpTest.h +++ b/libc/test/src/math/FrexpTest.h @@ -20,7 +20,7 @@ template class FrexpTest : public LIBC_NAMESPACE::testing::Test { DECLARE_SPECIAL_CONSTANTS(T) static constexpr UIntType HIDDEN_BIT = - UIntType(1) << LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + UIntType(1) << LIBC_NAMESPACE::fputil::FloatProperties::MANTISSA_WIDTH; public: typedef T (*FrexpFunc)(T, int *); diff --git a/libc/test/src/math/ILogbTest.h b/libc/test/src/math/ILogbTest.h index e51a5d7a2544cdc3877c8a93cb7c49d10563ddfd..9e12b4515c28525d66755425f729d108eaf27f78 100644 --- a/libc/test/src/math/ILogbTest.h +++ b/libc/test/src/math/ILogbTest.h @@ -24,15 +24,12 @@ public: template void test_special_numbers(typename ILogbFunc::Func func) { - EXPECT_EQ(FP_ILOGB0, func(T(LIBC_NAMESPACE::fputil::FPBits::zero()))); - EXPECT_EQ(FP_ILOGB0, - func(T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()))); - - EXPECT_EQ(FP_ILOGBNAN, - func(T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)))); - - EXPECT_EQ(INT_MAX, func(T(LIBC_NAMESPACE::fputil::FPBits::inf()))); - EXPECT_EQ(INT_MAX, func(T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()))); + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero()))); + EXPECT_EQ(FP_ILOGB0, func(T(FPBits::neg_zero()))); + EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(1)))); + EXPECT_EQ(INT_MAX, func(T(FPBits::inf()))); + EXPECT_EQ(INT_MAX, func(T(FPBits::neg_inf()))); } template diff --git a/libc/test/src/math/LdExpTest.h b/libc/test/src/math/LdExpTest.h index a75c8ef31a2cf83e9e279008eff5ec7553a0919e..5ebba62a3dbb8acd620a7950860b0c2cb0d80f58 100644 --- a/libc/test/src/math/LdExpTest.h +++ b/libc/test/src/math/LdExpTest.h @@ -23,16 +23,15 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat; using UIntType = typename FPBits::UIntType; - static constexpr UIntType MANTISSA_WIDTH = - LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + static constexpr UIntType MANTISSA_WIDTH = FPBits::MANTISSA_WIDTH; // A normalized mantissa to be used with tests. static constexpr UIntType MANTISSA = NormalFloat::ONE + 0x1234; - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T nan = T(FPBits::build_quiet_nan(1)); public: typedef T (*LdExpFunc)(T, int); diff --git a/libc/test/src/math/LogbTest.h b/libc/test/src/math/LogbTest.h index c2cf4f1f1483336cd34106c4529c614868e4276e..3912385623ef19f486f75e2417efcd1d2265cf57 100644 --- a/libc/test/src/math/LogbTest.h +++ b/libc/test/src/math/LogbTest.h @@ -20,7 +20,7 @@ template class LogbTest : public LIBC_NAMESPACE::testing::Test { DECLARE_SPECIAL_CONSTANTS(T) static constexpr UIntType HIDDEN_BIT = - UIntType(1) << LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + UIntType(1) << LIBC_NAMESPACE::fputil::FloatProperties::MANTISSA_WIDTH; public: typedef T (*LogbFunc)(T); diff --git a/libc/test/src/math/NextAfterTest.h b/libc/test/src/math/NextAfterTest.h index 57a801dfb28a316ae9f0a2d623217f199f2a3359..ca34753871b9606ba6d483857351887e6eb2c9d5 100644 --- a/libc/test/src/math/NextAfterTest.h +++ b/libc/test/src/math/NextAfterTest.h @@ -20,7 +20,6 @@ template class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; - using MantissaWidth = LIBC_NAMESPACE::fputil::MantissaWidth; using UIntType = typename FPBits::UIntType; static constexpr int BIT_WIDTH_OF_TYPE = @@ -165,7 +164,7 @@ public: ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(x_bits.get_biased_exponent() - 1)); ASSERT_EQ(result_bits.get_mantissa(), - (UIntType(1) << MantissaWidth::VALUE) - 1); + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1); result = func(x, T(33.0)); result_bits = FPBits(result); @@ -179,7 +178,7 @@ public: ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(x_bits.get_biased_exponent() - 1)); ASSERT_EQ(result_bits.get_mantissa(), - (UIntType(1) << MantissaWidth::VALUE) - 1); + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1); result = func(x, T(-33.0)); result_bits = FPBits(result); diff --git a/libc/test/src/math/RemQuoTest.h b/libc/test/src/math/RemQuoTest.h index 6da0756c3a1b3de2859970bbe100a6e666cb9c8e..a345e8b72e78d02f8d0bbca63ad318f34b8ca0e1 100644 --- a/libc/test/src/math/RemQuoTest.h +++ b/libc/test/src/math/RemQuoTest.h @@ -23,11 +23,11 @@ class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; using UIntType = typename FPBits::UIntType; - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T nan = T(FPBits::build_quiet_nan(1)); public: typedef T (*RemQuoFunc)(T, T, int *); diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h index 1a976e97359eb76ab108a1a7ca824767c851946c..feee040c72f88dd85694c41ae2c1fcc7c247cda2 100644 --- a/libc/test/src/math/RoundToIntegerTest.h +++ b/libc/test/src/math/RoundToIntegerTest.h @@ -32,11 +32,11 @@ private: using FPBits = LIBC_NAMESPACE::fputil::FPBits; using UIntType = typename FPBits::UIntType; - const F zero = F(LIBC_NAMESPACE::fputil::FPBits::zero()); - const F neg_zero = F(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); - const F inf = F(LIBC_NAMESPACE::fputil::FPBits::inf()); - const F neg_inf = F(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const F nan = F(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); + const F zero = F(FPBits::zero()); + const F neg_zero = F(FPBits::neg_zero()); + const F inf = F(FPBits::inf()); + const F neg_inf = F(FPBits::neg_inf()); + const F nan = F(FPBits::build_quiet_nan(1)); static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1); static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1); @@ -192,8 +192,7 @@ public: FPBits bits(F(1.0)); bits.set_biased_exponent(EXPONENT_LIMIT + FPBits::EXPONENT_BIAS); bits.set_sign(1); - bits.set_mantissa(UIntType(0x1) - << (LIBC_NAMESPACE::fputil::MantissaWidth::VALUE - 1)); + bits.set_mantissa(UIntType(0x1) << (FPBits::MANTISSA_WIDTH - 1)); F x = F(bits); if (TestModes) { diff --git a/libc/test/src/math/SqrtTest.h b/libc/test/src/math/SqrtTest.h index 24f14b78d2f0f5d850c3335a61e9e0b2d2b3e1d8..ab14e30d3ded6ff9fb45ed46d9840bac6b3820c8 100644 --- a/libc/test/src/math/SqrtTest.h +++ b/libc/test/src/math/SqrtTest.h @@ -20,7 +20,7 @@ template class SqrtTest : public LIBC_NAMESPACE::testing::Test { DECLARE_SPECIAL_CONSTANTS(T) static constexpr UIntType HIDDEN_BIT = - UIntType(1) << LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + UIntType(1) << LIBC_NAMESPACE::fputil::FloatProperties::MANTISSA_WIDTH; public: typedef T (*SqrtFunc)(T); diff --git a/libc/test/src/math/smoke/FDimTest.h b/libc/test/src/math/smoke/FDimTest.h index 3118c3661013e7cf97101e8cdb28adba09145972..3fb82ed8bca2ced18689ce45edd4e8089289665f 100644 --- a/libc/test/src/math/smoke/FDimTest.h +++ b/libc/test/src/math/smoke/FDimTest.h @@ -74,9 +74,9 @@ public: private: // constexpr does not work on FPBits yet, so we cannot have these constants as // static. - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); + const T nan = T(FPBits::build_quiet_nan(1)); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); }; diff --git a/libc/test/src/math/smoke/FmaTest.h b/libc/test/src/math/smoke/FmaTest.h index 3c1c120d77d450864efdb08040e0524bb0ada331..1da9652bfee155efb743ce1b6900b36930850e2f 100644 --- a/libc/test/src/math/smoke/FmaTest.h +++ b/libc/test/src/math/smoke/FmaTest.h @@ -19,11 +19,11 @@ private: using Func = T (*)(T, T, T); using FPBits = LIBC_NAMESPACE::fputil::FPBits; using UIntType = typename FPBits::UIntType; - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); + const T nan = T(FPBits::build_quiet_nan(1)); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); public: void test_special_numbers(Func func) { diff --git a/libc/test/src/math/smoke/FrexpTest.h b/libc/test/src/math/smoke/FrexpTest.h index 3ff169091cc9a38f1bf48a50f8d965c59e7a4d49..643a151d89c7da81fc30494ae5a52f92061d7d02 100644 --- a/libc/test/src/math/smoke/FrexpTest.h +++ b/libc/test/src/math/smoke/FrexpTest.h @@ -17,7 +17,7 @@ template class FrexpTest : public LIBC_NAMESPACE::testing::Test { DECLARE_SPECIAL_CONSTANTS(T) static constexpr UIntType HIDDEN_BIT = - UIntType(1) << LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + UIntType(1) << LIBC_NAMESPACE::fputil::FloatProperties::MANTISSA_WIDTH; public: typedef T (*FrexpFunc)(T, int *); diff --git a/libc/test/src/math/smoke/ILogbTest.h b/libc/test/src/math/smoke/ILogbTest.h index e51a5d7a2544cdc3877c8a93cb7c49d10563ddfd..9e12b4515c28525d66755425f729d108eaf27f78 100644 --- a/libc/test/src/math/smoke/ILogbTest.h +++ b/libc/test/src/math/smoke/ILogbTest.h @@ -24,15 +24,12 @@ public: template void test_special_numbers(typename ILogbFunc::Func func) { - EXPECT_EQ(FP_ILOGB0, func(T(LIBC_NAMESPACE::fputil::FPBits::zero()))); - EXPECT_EQ(FP_ILOGB0, - func(T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()))); - - EXPECT_EQ(FP_ILOGBNAN, - func(T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)))); - - EXPECT_EQ(INT_MAX, func(T(LIBC_NAMESPACE::fputil::FPBits::inf()))); - EXPECT_EQ(INT_MAX, func(T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()))); + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero()))); + EXPECT_EQ(FP_ILOGB0, func(T(FPBits::neg_zero()))); + EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(1)))); + EXPECT_EQ(INT_MAX, func(T(FPBits::inf()))); + EXPECT_EQ(INT_MAX, func(T(FPBits::neg_inf()))); } template diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h index a75c8ef31a2cf83e9e279008eff5ec7553a0919e..5ebba62a3dbb8acd620a7950860b0c2cb0d80f58 100644 --- a/libc/test/src/math/smoke/LdExpTest.h +++ b/libc/test/src/math/smoke/LdExpTest.h @@ -23,16 +23,15 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat; using UIntType = typename FPBits::UIntType; - static constexpr UIntType MANTISSA_WIDTH = - LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + static constexpr UIntType MANTISSA_WIDTH = FPBits::MANTISSA_WIDTH; // A normalized mantissa to be used with tests. static constexpr UIntType MANTISSA = NormalFloat::ONE + 0x1234; - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T nan = T(FPBits::build_quiet_nan(1)); public: typedef T (*LdExpFunc)(T, int); diff --git a/libc/test/src/math/smoke/LogbTest.h b/libc/test/src/math/smoke/LogbTest.h index 34cf92c19ed8b1b1e7532de7bdd55f00c35cc71a..41b356fe0524e604e7721bcba7af79533332696f 100644 --- a/libc/test/src/math/smoke/LogbTest.h +++ b/libc/test/src/math/smoke/LogbTest.h @@ -17,7 +17,7 @@ template class LogbTest : public LIBC_NAMESPACE::testing::Test { DECLARE_SPECIAL_CONSTANTS(T) static constexpr UIntType HIDDEN_BIT = - UIntType(1) << LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + UIntType(1) << LIBC_NAMESPACE::fputil::FloatProperties::MANTISSA_WIDTH; public: typedef T (*LogbFunc)(T); diff --git a/libc/test/src/math/smoke/NextAfterTest.h b/libc/test/src/math/smoke/NextAfterTest.h index 29098e0f49a45755d9000fc12dcddecd3f6b6a1d..90155a8b293f84366459fd434b6285321149ae91 100644 --- a/libc/test/src/math/smoke/NextAfterTest.h +++ b/libc/test/src/math/smoke/NextAfterTest.h @@ -31,7 +31,6 @@ template class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; - using MantissaWidth = LIBC_NAMESPACE::fputil::MantissaWidth; using UIntType = typename FPBits::UIntType; static constexpr int BIT_WIDTH_OF_TYPE = @@ -176,7 +175,7 @@ public: ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(x_bits.get_biased_exponent() - 1)); ASSERT_EQ(result_bits.get_mantissa(), - (UIntType(1) << MantissaWidth::VALUE) - 1); + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1); result = func(x, T(33.0)); result_bits = FPBits(result); @@ -190,7 +189,7 @@ public: ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(x_bits.get_biased_exponent() - 1)); ASSERT_EQ(result_bits.get_mantissa(), - (UIntType(1) << MantissaWidth::VALUE) - 1); + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1); result = func(x, T(-33.0)); result_bits = FPBits(result); diff --git a/libc/test/src/math/smoke/NextTowardTest.h b/libc/test/src/math/smoke/NextTowardTest.h index 111d8017e691d36841de58843b062be46f0e0c4b..bd719275a41552f6fb0afe09e688eb6dc62ea72a 100644 --- a/libc/test/src/math/smoke/NextTowardTest.h +++ b/libc/test/src/math/smoke/NextTowardTest.h @@ -33,7 +33,6 @@ template class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; using ToFPBits = LIBC_NAMESPACE::fputil::FPBits; - using MantissaWidth = LIBC_NAMESPACE::fputil::MantissaWidth; using UIntType = typename FPBits::UIntType; static constexpr int BIT_WIDTH_OF_TYPE = @@ -190,7 +189,7 @@ public: ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(x_bits.get_biased_exponent() - 1)); ASSERT_EQ(result_bits.get_mantissa(), - (UIntType(1) << MantissaWidth::VALUE) - 1); + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1); result = func(x, 33.0); result_bits = FPBits(result); @@ -204,7 +203,7 @@ public: ASSERT_EQ(result_bits.get_biased_exponent(), uint16_t(x_bits.get_biased_exponent() - 1)); ASSERT_EQ(result_bits.get_mantissa(), - (UIntType(1) << MantissaWidth::VALUE) - 1); + (UIntType(1) << FPBits::MANTISSA_WIDTH) - 1); result = func(x, -33.0); result_bits = FPBits(result); diff --git a/libc/test/src/math/smoke/RemQuoTest.h b/libc/test/src/math/smoke/RemQuoTest.h index 5a5d143777502351321ae86d7a97e5f5e4e31b5e..514190b6b31caa623aca11a0048a6c09f1d7778a 100644 --- a/libc/test/src/math/smoke/RemQuoTest.h +++ b/libc/test/src/math/smoke/RemQuoTest.h @@ -20,11 +20,11 @@ class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test { using FPBits = LIBC_NAMESPACE::fputil::FPBits; using UIntType = typename FPBits::UIntType; - const T zero = T(LIBC_NAMESPACE::fputil::FPBits::zero()); - const T neg_zero = T(LIBC_NAMESPACE::fputil::FPBits::neg_zero()); - const T inf = T(LIBC_NAMESPACE::fputil::FPBits::inf()); - const T neg_inf = T(LIBC_NAMESPACE::fputil::FPBits::neg_inf()); - const T nan = T(LIBC_NAMESPACE::fputil::FPBits::build_quiet_nan(1)); + const T zero = T(FPBits::zero()); + const T neg_zero = T(FPBits::neg_zero()); + const T inf = T(FPBits::inf()); + const T neg_inf = T(FPBits::neg_inf()); + const T nan = T(FPBits::build_quiet_nan(1)); public: typedef T (*RemQuoFunc)(T, T, int *); diff --git a/libc/test/src/math/smoke/SqrtTest.h b/libc/test/src/math/smoke/SqrtTest.h index d4b2f9dd2624f1d1e10ad62bdf93c53bcae621b8..dffff520cd69e87a23984fdb29ae882b2591e74e 100644 --- a/libc/test/src/math/smoke/SqrtTest.h +++ b/libc/test/src/math/smoke/SqrtTest.h @@ -17,7 +17,7 @@ template class SqrtTest : public LIBC_NAMESPACE::testing::Test { DECLARE_SPECIAL_CONSTANTS(T) static constexpr UIntType HIDDEN_BIT = - UIntType(1) << LIBC_NAMESPACE::fputil::MantissaWidth::VALUE; + UIntType(1) << LIBC_NAMESPACE::fputil::FloatProperties::MANTISSA_WIDTH; public: typedef T (*SqrtFunc)(T); diff --git a/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp b/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp index 7e6bb0aaca92518f0f465c9df7174b2f28d16909..0870deeeb5d801076a8fbe1af489be46dd999cb7 100644 --- a/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp +++ b/libc/test/src/sys/resource/getrlimit_setrlimit_test.cpp @@ -17,6 +17,7 @@ #include "test/UnitTest/Test.h" #include +#include TEST(LlvmLibcResourceLimitsTest, SetNoFileLimit) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt index 4380597e5515799083bb4d90489c8c12a59a4ab8..666dc28c7e4ee199f955b013c645b6fe0e91bd95 100644 --- a/libc/test/src/sys/socket/linux/CMakeLists.txt +++ b/libc/test/src/sys/socket/linux/CMakeLists.txt @@ -12,3 +12,19 @@ add_libc_unittest( libc.src.sys.socket.socket libc.src.unistd.close ) + + +add_libc_unittest( + bind_test + SUITE + libc_sys_socket_unittests + SRCS + bind_test.cpp + DEPENDS + libc.include.sys_socket + libc.src.errno.errno + libc.src.sys.socket.socket + libc.src.sys.socket.bind + libc.src.stdio.remove + libc.src.unistd.close +) diff --git a/libc/test/src/sys/socket/linux/bind_test.cpp b/libc/test/src/sys/socket/linux/bind_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a3a1c227c9b58efca1851737dad9f317ea614b1 --- /dev/null +++ b/libc/test/src/sys/socket/linux/bind_test.cpp @@ -0,0 +1,55 @@ +//===-- Unittests for bind ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/sys/socket/bind.h" +#include "src/sys/socket/socket.h" + +#include "src/stdio/remove.h" +#include "src/unistd/close.h" + +#include "src/errno/libc_errno.h" +#include "test/UnitTest/LibcTest.h" +#include "test/UnitTest/Test.h" + +#include // For AF_UNIX and SOCK_DGRAM + +TEST(LlvmLibcSocketTest, BindLocalSocket) { + + const char *FILENAME = "bind_file.test"; + auto SOCK_PATH = libc_make_test_file_path(FILENAME); + + int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_DGRAM, 0); + ASSERT_GE(sock, 0); + ASSERT_EQ(libc_errno, 0); + + struct sockaddr_un my_addr; + + my_addr.sun_family = AF_UNIX; + unsigned int i = 0; + for (; + SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t)); + ++i) + my_addr.sun_path[i] = SOCK_PATH[i]; + my_addr.sun_path[i] = '\0'; + + // It's important that the path fits in the struct, if it doesn't then we + // can't try to bind to the file. + ASSERT_LT( + i, static_cast(sizeof(sockaddr_un) - sizeof(sa_family_t))); + + int result = + LIBC_NAMESPACE::bind(sock, reinterpret_cast(&my_addr), + sizeof(struct sockaddr_un)); + + ASSERT_EQ(result, 0); + ASSERT_EQ(libc_errno, 0); + + LIBC_NAMESPACE::close(sock); + + LIBC_NAMESPACE::remove(SOCK_PATH); +} diff --git a/libc/test/src/sys/socket/linux/socket_test.cpp b/libc/test/src/sys/socket/linux/socket_test.cpp index 9037888441a357f674db0a40843e1e9d94a2205f..9d5bfacde0a4099344d186fc5502aacdbcd3d740 100644 --- a/libc/test/src/sys/socket/linux/socket_test.cpp +++ b/libc/test/src/sys/socket/linux/socket_test.cpp @@ -13,10 +13,10 @@ #include "src/errno/libc_errno.h" #include "test/UnitTest/Test.h" -#include // For AF_LOCAL and SOCK_DGRAM +#include // For AF_UNIX and SOCK_DGRAM TEST(LlvmLibcSocketTest, LocalSocket) { - int sock = LIBC_NAMESPACE::socket(AF_LOCAL, SOCK_DGRAM, 0); + int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_DGRAM, 0); ASSERT_GE(sock, 0); ASSERT_EQ(libc_errno, 0); diff --git a/libc/test/src/unistd/access_test.cpp b/libc/test/src/unistd/access_test.cpp index ed1fe96f4f4a1672312168bd678733516f4a4ee9..7d4b3be443fed492146df25d4238e5e0735f8f74 100644 --- a/libc/test/src/unistd/access_test.cpp +++ b/libc/test/src/unistd/access_test.cpp @@ -14,6 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include #include TEST(LlvmLibcAccessTest, CreateAndTest) { diff --git a/libc/test/src/unistd/dup2_test.cpp b/libc/test/src/unistd/dup2_test.cpp index ff870db0334c93dca4086650484583a1e5ed5481..d46c4b919ce72cb315ee5bb7b0445d940d2d898c 100644 --- a/libc/test/src/unistd/dup2_test.cpp +++ b/libc/test/src/unistd/dup2_test.cpp @@ -16,6 +16,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcdupTest, ReadAndWriteViaDup) { constexpr int DUPFD = 0xD0; libc_errno = 0; diff --git a/libc/test/src/unistd/dup3_test.cpp b/libc/test/src/unistd/dup3_test.cpp index 279cfbfea1b144be6a3b1e0bcd3f8b28d2cc8f02..d2d544d5d9a12f854b308eeed99f8bdbbbe7e2d2 100644 --- a/libc/test/src/unistd/dup3_test.cpp +++ b/libc/test/src/unistd/dup3_test.cpp @@ -16,6 +16,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + // The tests here are exactly the same as those of dup2. We only test the // plumbing of the dup3 syscall and not the dup3 functionality itself as it is // a simple syscall wrapper. Testing dup3 functionality is beyond the scope of diff --git a/libc/test/src/unistd/dup_test.cpp b/libc/test/src/unistd/dup_test.cpp index 38c439125db3d7bb65bf81f2318f2449abe8f0d7..856b004fbe65d58f74464305a63e051262e5db61 100644 --- a/libc/test/src/unistd/dup_test.cpp +++ b/libc/test/src/unistd/dup_test.cpp @@ -16,6 +16,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcdupTest, ReadAndWriteViaDup) { libc_errno = 0; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; diff --git a/libc/test/src/unistd/ftruncate_test.cpp b/libc/test/src/unistd/ftruncate_test.cpp index ae743b385e220dbe611e230c0f737e61185c760b..fc68348e32ec6672987ceb6090bd47d4fa59dbf1 100644 --- a/libc/test/src/unistd/ftruncate_test.cpp +++ b/libc/test/src/unistd/ftruncate_test.cpp @@ -17,6 +17,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + namespace cpp = LIBC_NAMESPACE::cpp; TEST(LlvmLibcFtruncateTest, CreateAndTruncate) { diff --git a/libc/test/src/unistd/isatty_test.cpp b/libc/test/src/unistd/isatty_test.cpp index fce4a3e5f5062aa383a8ff7ece89cf3644804a92..7bf8dd708bfa6f371523e890cc198c5fd9a6ad01 100644 --- a/libc/test/src/unistd/isatty_test.cpp +++ b/libc/test/src/unistd/isatty_test.cpp @@ -13,6 +13,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; diff --git a/libc/test/src/unistd/link_test.cpp b/libc/test/src/unistd/link_test.cpp index b1b9383cb62ee07f7abcd16f88e51849a498f06b..2d5aa7588b08b902e761755666161f99c98d4ffb 100644 --- a/libc/test/src/unistd/link_test.cpp +++ b/libc/test/src/unistd/link_test.cpp @@ -14,6 +14,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcLinkTest, CreateAndUnlink) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_FILE = "testdata/link.test"; diff --git a/libc/test/src/unistd/linkat_test.cpp b/libc/test/src/unistd/linkat_test.cpp index 2ef41cd4e75f6a7840b85ce93a12ed0257518e39..d1ffe37d63b48c71573e57323196ad8eca168fb4 100644 --- a/libc/test/src/unistd/linkat_test.cpp +++ b/libc/test/src/unistd/linkat_test.cpp @@ -14,6 +14,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcLinkatTest, CreateAndUnlink) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_DIR = "testdata"; diff --git a/libc/test/src/unistd/pread_pwrite_test.cpp b/libc/test/src/unistd/pread_pwrite_test.cpp index 6819f559424f3e03eea69248552b013ce1e3974b..f90d1341c20108abd955176c9335edd9d6b58e97 100644 --- a/libc/test/src/unistd/pread_pwrite_test.cpp +++ b/libc/test/src/unistd/pread_pwrite_test.cpp @@ -17,6 +17,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcUniStd, PWriteAndPReadBackTest) { // The strategy here is that we first create a file and write to it. Next, // we open that file again and write at an offset. Finally, we open the diff --git a/libc/test/src/unistd/read_write_test.cpp b/libc/test/src/unistd/read_write_test.cpp index 20b51bb8082b1209c84912ecaae3b571f32c98d0..3007d4c38711579e1c99896178fd57cdbc0e5b36 100644 --- a/libc/test/src/unistd/read_write_test.cpp +++ b/libc/test/src/unistd/read_write_test.cpp @@ -15,6 +15,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcUniStd, WriteAndReadBackTest) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_FILE = "__unistd_read_write.test"; diff --git a/libc/test/src/unistd/symlink_test.cpp b/libc/test/src/unistd/symlink_test.cpp index 84d963b7a207ce8f86d2a68cdb4bcdc26384c9e4..b25cfa4f857699592808c051c3f19ce1e8523e3b 100644 --- a/libc/test/src/unistd/symlink_test.cpp +++ b/libc/test/src/unistd/symlink_test.cpp @@ -14,6 +14,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcSymlinkTest, CreateAndUnlink) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_FILE_BASE = "symlink.test"; diff --git a/libc/test/src/unistd/symlinkat_test.cpp b/libc/test/src/unistd/symlinkat_test.cpp index b0308787f2052a2644fd80648c283f140acf1d78..8aba2daee8cf3830431ad06d12c90adfbf5ad2f2 100644 --- a/libc/test/src/unistd/symlinkat_test.cpp +++ b/libc/test/src/unistd/symlinkat_test.cpp @@ -14,6 +14,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcSymlinkatTest, CreateAndUnlink) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_DIR = "testdata"; diff --git a/libc/test/src/unistd/syscall_test.cpp b/libc/test/src/unistd/syscall_test.cpp index 211b27c3188c4d89e06fbdecd11bef497177d8fd..6a5ca47f8d494a8fc19ca58f64db206aab0e1570 100644 --- a/libc/test/src/unistd/syscall_test.cpp +++ b/libc/test/src/unistd/syscall_test.cpp @@ -12,6 +12,7 @@ #include "test/UnitTest/Test.h" #include +#include // For S_* flags. #include // For syscall numbers. #include diff --git a/libc/test/src/unistd/truncate_test.cpp b/libc/test/src/unistd/truncate_test.cpp index 15940321e5ad456a7e12054a4cb9ede727bb88cf..6d8a3b8e53f7281e08b474bf6fcd9138d2b10a27 100644 --- a/libc/test/src/unistd/truncate_test.cpp +++ b/libc/test/src/unistd/truncate_test.cpp @@ -17,6 +17,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + namespace cpp = LIBC_NAMESPACE::cpp; TEST(LlvmLibcTruncateTest, CreateAndTruncate) { diff --git a/libc/test/src/unistd/unlink_test.cpp b/libc/test/src/unistd/unlink_test.cpp index 8a64f88ee6f26db0b59f0a965bd691745f6fc4b2..77f65b5ecc6a1a12d9c00c4e587b0d0f9c5c1da0 100644 --- a/libc/test/src/unistd/unlink_test.cpp +++ b/libc/test/src/unistd/unlink_test.cpp @@ -13,6 +13,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcUnlinkTest, CreateAndUnlink) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_FILE = "testdata/unlink.test"; diff --git a/libc/test/src/unistd/unlinkat_test.cpp b/libc/test/src/unistd/unlinkat_test.cpp index 5953085bf12b66ca7379223f511a18378f5bf7f7..22a20bc6ad07bce4cf23cdb3dab45da6a2f2e623 100644 --- a/libc/test/src/unistd/unlinkat_test.cpp +++ b/libc/test/src/unistd/unlinkat_test.cpp @@ -14,6 +14,8 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" +#include + TEST(LlvmLibcUnlinkatTest, CreateAndDeleteTest) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; constexpr const char *TEST_DIR = "testdata"; diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index e3dffadf4ed9674fae495f71cebf6927d4366dc0..68146dff64c4e3e8eea0bacfb6cd7a59f0f50023 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -468,7 +468,7 @@ public: mpfr_sub(inputMPFR.value, value, inputMPFR.value, MPFR_RNDN); mpfr_abs(inputMPFR.value, inputMPFR.value, MPFR_RNDN); mpfr_mul_2si(inputMPFR.value, inputMPFR.value, - -thisExponent + int(fputil::MantissaWidth::VALUE), + -thisExponent + int(fputil::FPBits::MANTISSA_WIDTH), MPFR_RNDN); return inputMPFR; } @@ -496,12 +496,12 @@ public: mpfr_sub(minMPFR.value, pivot.value, minMPFR.value, MPFR_RNDN); mpfr_mul_2si(minMPFR.value, minMPFR.value, - -minExponent + int(fputil::MantissaWidth::VALUE), + -minExponent + int(fputil::FPBits::MANTISSA_WIDTH), MPFR_RNDN); mpfr_sub(maxMPFR.value, maxMPFR.value, pivot.value, MPFR_RNDN); mpfr_mul_2si(maxMPFR.value, maxMPFR.value, - -maxExponent + int(fputil::MantissaWidth::VALUE), + -maxExponent + int(fputil::FPBits::MANTISSA_WIDTH), MPFR_RNDN); mpfr_add(minMPFR.value, minMPFR.value, maxMPFR.value, MPFR_RNDN); diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index 7751bf1efc59d202427f1a9bc48a490b8e9f1034..75cb63222da35c52aaa5f9b8c084216e143809bf 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -651,6 +651,19 @@ get_sanitizer_flags(SANITIZER_FLAGS "${LLVM_USE_SANITIZER}") add_library(cxx-sanitizer-flags INTERFACE) target_compile_options(cxx-sanitizer-flags INTERFACE ${SANITIZER_FLAGS}) +# _LIBCPP_INSTRUMENTED_WITH_ASAN informs that library was built with ASan. +# Defining _LIBCPP_INSTRUMENTED_WITH_ASAN while building the library with ASan is required. +# Normally, the _LIBCPP_INSTRUMENTED_WITH_ASAN flag is used to keep information whether +# dylibs are built with AddressSanitizer. However, when building libc++, +# this flag needs to be defined so that the resulting dylib has all ASan functionalities guarded by this flag. +# If the _LIBCPP_INSTRUMENTED_WITH_ASAN flag is not defined, then parts of the ASan instrumentation code in libc++ +# will not be compiled into it, resulting in false positives. +# For context, read: https://github.com/llvm/llvm-project/pull/72677#pullrequestreview-1765402800 +string(FIND "${LLVM_USE_SANITIZER}" "Address" building_with_asan) +if (NOT "${building_with_asan}" STREQUAL "-1") + config_define(ON _LIBCPP_INSTRUMENTED_WITH_ASAN) +endif() + # Link system libraries ======================================================= function(cxx_link_system_libraries target) if (NOT MSVC) @@ -664,15 +677,17 @@ function(cxx_link_system_libraries target) target_add_link_flags_if_supported(${target} PRIVATE "--unwindlib=none") endif() - if (LIBCXX_USE_COMPILER_RT) - find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY) - if (LIBCXX_BUILTINS_LIBRARY) - target_link_libraries(${target} PRIVATE "${LIBCXX_BUILTINS_LIBRARY}") + if (MSVC) + if (LIBCXX_USE_COMPILER_RT) + find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY) + if (LIBCXX_BUILTINS_LIBRARY) + target_link_libraries(${target} PRIVATE "${LIBCXX_BUILTINS_LIBRARY}") + endif() + elseif (LIBCXX_HAS_GCC_LIB) + target_link_libraries(${target} PRIVATE gcc) + elseif (LIBCXX_HAS_GCC_S_LIB) + target_link_libraries(${target} PRIVATE gcc_s) endif() - elseif (LIBCXX_HAS_GCC_LIB) - target_link_libraries(${target} PRIVATE gcc) - elseif (LIBCXX_HAS_GCC_S_LIB) - target_link_libraries(${target} PRIVATE gcc_s) endif() if (LIBCXX_HAS_ATOMIC_LIB) diff --git a/libcxx/cmake/config-ix.cmake b/libcxx/cmake/config-ix.cmake index a365517936e7565abb0db90ac5fc55072eb11f8b..1e8c2f5ce463213b572af12c23be28a4811bbfd8 100644 --- a/libcxx/cmake/config-ix.cmake +++ b/libcxx/cmake/config-ix.cmake @@ -45,7 +45,9 @@ else() endif() endif() -if (CXX_SUPPORTS_NOSTDLIBXX_FLAG OR C_SUPPORTS_NODEFAULTLIBS_FLAG) +# Only link against compiler-rt manually if we use -nodefaultlibs, since +# otherwise the compiler will do the right thing on its own. +if (NOT CXX_SUPPORTS_NOSTDLIBXX_FLAG AND C_SUPPORTS_NODEFAULTLIBS_FLAG) if (LIBCXX_USE_COMPILER_RT) include(HandleCompilerRT) find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY @@ -73,6 +75,9 @@ if (CXX_SUPPORTS_NOSTDLIBXX_FLAG OR C_SUPPORTS_NODEFAULTLIBS_FLAG) moldname mingwex msvcrt) list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) endif() +endif() + +if (CXX_SUPPORTS_NOSTDLIBXX_FLAG OR C_SUPPORTS_NODEFAULTLIBS_FLAG) if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") endif () diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst index e8b4a95dbcffae15126aef3c55072041df8180ec..c7769bae6bb17d809c849c9c08fd337630e56a9b 100644 --- a/libcxx/docs/index.rst +++ b/libcxx/docs/index.rst @@ -202,6 +202,11 @@ Design Documents Build Bots and Test Coverage ============================ +.. image:: https://github.com/llvm/llvm-project/actions/workflows/libcxx-build-and-test.yaml/badge.svg?branch=main&event=schedule + :target: https://github.com/llvm/llvm-project/actions/workflows/libcxx-build-and-test.yaml?query=event%3Aschedule + :alt: Build and Test libc++ + +* `Github Actions CI pipeline `_ * `Buildkite CI pipeline `_ * `LLVM Buildbot Builders `_ * :ref:`Adding New CI Jobs ` diff --git a/libcxx/include/__chrono/day.h b/libcxx/include/__chrono/day.h index c907c036c146ad08e52f7ac461ca32de7be280ce..d908453d5b082265f80dbb61e939ec11ada70595 100644 --- a/libcxx/include/__chrono/day.h +++ b/libcxx/include/__chrono/day.h @@ -46,7 +46,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const day& __lhs, const day& __rhs) noexcept { return static_cast(__lhs) == static_cast(__rhs); } -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const day& __lhs, const day& __rhs) noexcept { +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const day& __lhs, const day& __rhs) noexcept { return static_cast(__lhs) <=> static_cast(__rhs); } diff --git a/libcxx/include/__chrono/hh_mm_ss.h b/libcxx/include/__chrono/hh_mm_ss.h index 5bd452e57fa3c2175a022159c19bd1c362442c11..0adee2d60db8a4a8a9b2cb417554be5392759169 100644 --- a/libcxx/include/__chrono/hh_mm_ss.h +++ b/libcxx/include/__chrono/hh_mm_ss.h @@ -87,17 +87,17 @@ private: }; _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(hh_mm_ss); -_LIBCPP_HIDE_FROM_ABI constexpr bool is_am(const hours& __h) noexcept { return __h >= hours( 0) && __h < hours(12); } -_LIBCPP_HIDE_FROM_ABI constexpr bool is_pm(const hours& __h) noexcept { return __h >= hours(12) && __h < hours(24); } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_am(const hours& __h) noexcept { return __h >= hours( 0) && __h < hours(12); } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_pm(const hours& __h) noexcept { return __h >= hours(12) && __h < hours(24); } -_LIBCPP_HIDE_FROM_ABI constexpr hours make12(const hours& __h) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr hours make12(const hours& __h) noexcept { if (__h == hours( 0)) return hours(12); else if (__h <= hours(12)) return __h; else return __h - hours(12); } -_LIBCPP_HIDE_FROM_ABI constexpr hours make24(const hours& __h, bool __is_pm) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr hours make24(const hours& __h, bool __is_pm) noexcept { if (__is_pm) return __h == hours(12) ? __h : __h + hours(12); diff --git a/libcxx/include/__chrono/month.h b/libcxx/include/__chrono/month.h index 7566e4ed29983f49f2d1a0fc1a02adff06dbfc67..2dee5d8c6c70d4085762c455e55809bff9315db3 100644 --- a/libcxx/include/__chrono/month.h +++ b/libcxx/include/__chrono/month.h @@ -46,7 +46,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const month& __lhs, const month& __rhs) noexcept { return static_cast(__lhs) == static_cast(__rhs); } -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const month& __lhs, const month& __rhs) noexcept { +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const month& __lhs, const month& __rhs) noexcept { return static_cast(__lhs) <=> static_cast(__rhs); } diff --git a/libcxx/include/__chrono/monthday.h b/libcxx/include/__chrono/monthday.h index 03fd7503a6b435ce256b880905a196a2f9ba35be..8403d9ec4eebe25c825f927688de510256709aab 100644 --- a/libcxx/include/__chrono/monthday.h +++ b/libcxx/include/__chrono/monthday.h @@ -59,7 +59,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const month_day& __lhs, const month_day& __rhs) noexcept { return __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); } -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const month_day& __lhs, const month_day& __rhs) noexcept { +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const month_day& __lhs, const month_day& __rhs) noexcept { if (auto __c = __lhs.month() <=> __rhs.month(); __c != 0) return __c; return __lhs.day() <=> __rhs.day(); @@ -69,7 +69,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const month& __lhs, const day& __rhs) noexcept { return month_day{__lhs, __rhs}; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const day& __lhs, const month& __rhs) noexcept { return __rhs / __lhs; } @@ -77,11 +77,11 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const month& __lhs, int __rhs) noexcept { return __lhs / day(__rhs); } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(int __lhs, const day& __rhs) noexcept { return month(__lhs) / __rhs; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const day& __lhs, int __rhs) noexcept { return month(__rhs) / __lhs; } @@ -99,7 +99,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const month_day_last& __lhs, const month_day_last& __rhs) noexcept { return __lhs.month() == __rhs.month(); } -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const month_day_last& __lhs, const month_day_last& __rhs) noexcept { return __lhs.month() <=> __rhs.month(); } diff --git a/libcxx/include/__chrono/weekday.h b/libcxx/include/__chrono/weekday.h index 776d8ed3124caa726c5da58cbc38df70ef4c400c..292fcb40dc30613d5ae6547f6c7202d6ca111da1 100644 --- a/libcxx/include/__chrono/weekday.h +++ b/libcxx/include/__chrono/weekday.h @@ -85,7 +85,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>=(const weekday& __lhs, const weekday& __rhs) noexcept { return !(__lhs < __rhs); } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator+(const weekday& __lhs, const days& __rhs) noexcept { auto const __mu = static_cast(__lhs.c_encoding()) + __rhs.count(); @@ -93,15 +93,15 @@ weekday operator+(const weekday& __lhs, const days& __rhs) noexcept return weekday{static_cast(__mu - __yr * 7)}; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator+(const days& __lhs, const weekday& __rhs) noexcept { return __rhs + __lhs; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator-(const weekday& __lhs, const days& __rhs) noexcept { return __lhs + -__rhs; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr days operator-(const weekday& __lhs, const weekday& __rhs) noexcept { const int __wdu = __lhs.c_encoding() - __rhs.c_encoding(); diff --git a/libcxx/include/__chrono/year_month.h b/libcxx/include/__chrono/year_month.h index d1657b61015b9fb95a00e81ef7dcdc499f6fa6ba..320cf588ccd30e3943f55bdf74929b293b555324 100644 --- a/libcxx/include/__chrono/year_month.h +++ b/libcxx/include/__chrono/year_month.h @@ -53,13 +53,13 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const year_month& __lhs, const year_month& __rhs) noexcept { return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month(); } -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const year_month& __lhs, const year_month& __rhs) noexcept { +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const year_month& __lhs, const year_month& __rhs) noexcept { if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0) return __c; return __lhs.month() <=> __rhs.month(); } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const year_month& __lhs, const months& __rhs) noexcept { int __dmi = static_cast(static_cast(__lhs.month())) - 1 + __rhs.count(); @@ -68,27 +68,27 @@ year_month operator+(const year_month& __lhs, const months& __rhs) noexcept return (__lhs.year() + years(__dy)) / month(static_cast(__dmi)); } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const months& __lhs, const year_month& __rhs) noexcept { return __rhs + __lhs; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const year_month& __lhs, const years& __rhs) noexcept { return (__lhs.year() + __rhs) / __lhs.month(); } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const years& __lhs, const year_month& __rhs) noexcept { return __rhs + __lhs; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr months operator-(const year_month& __lhs, const year_month& __rhs) noexcept { return (__lhs.year() - __rhs.year()) + months(static_cast(__lhs.month()) - static_cast(__rhs.month())); } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator-(const year_month& __lhs, const months& __rhs) noexcept { return __lhs + -__rhs; } -_LIBCPP_HIDE_FROM_ABI constexpr +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator-(const year_month& __lhs, const years& __rhs) noexcept { return __lhs + -__rhs; } diff --git a/libcxx/include/__chrono/year_month_day.h b/libcxx/include/__chrono/year_month_day.h index ed5903f7d3f6956bb22c82fbfb6e4dbdcaaf7b1a..e84d2f8a838b40bc3f0f9fe7242add3c01418bfa 100644 --- a/libcxx/include/__chrono/year_month_day.h +++ b/libcxx/include/__chrono/year_month_day.h @@ -110,7 +110,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const year_month_day& __lhs, const year_month_day& __rhs) noexcept { return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); } -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const year_month_day& __lhs, const year_month_day& __rhs) noexcept { if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0) return __c; diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in index 6cade6f10d8acc1e9afe2795b1c1fe683d5d988f..7c002c5bfcf8e77f84e0cf14254b358d0896356f 100644 --- a/libcxx/include/__config_site.in +++ b/libcxx/include/__config_site.in @@ -29,6 +29,7 @@ #cmakedefine _LIBCPP_HAS_NO_WIDE_CHARACTERS #cmakedefine _LIBCPP_HAS_NO_STD_MODULES #cmakedefine _LIBCPP_HAS_NO_TIME_ZONE_DATABASE +#cmakedefine _LIBCPP_INSTRUMENTED_WITH_ASAN // PSTL backends #cmakedefine _LIBCPP_PSTL_CPU_BACKEND_SERIAL diff --git a/libcxx/include/__ranges/lazy_split_view.h b/libcxx/include/__ranges/lazy_split_view.h index 2c654bfd325a63c23305e3f3d8499e52ca9dc5b5..8ed4bcfdeb56d4b3f04d2a9c37340a56259738bf 100644 --- a/libcxx/include/__ranges/lazy_split_view.h +++ b/libcxx/include/__ranges/lazy_split_view.h @@ -437,7 +437,7 @@ lazy_split_view(_Range&&, range_value_t<_Range>) namespace views { namespace __lazy_split_view { -struct __fn : __range_adaptor_closure<__fn> { +struct __fn { template [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Pattern&& __pattern) const diff --git a/libcxx/include/__ranges/split_view.h b/libcxx/include/__ranges/split_view.h index a27ac4ef7a1965ac4c3a9d7055d8fd4a8f961a83..7f03be3c346a42ce9882df191b635bc3c0e7e6fa 100644 --- a/libcxx/include/__ranges/split_view.h +++ b/libcxx/include/__ranges/split_view.h @@ -194,7 +194,7 @@ public: namespace views { namespace __split_view { -struct __fn : __range_adaptor_closure<__fn> { +struct __fn { // clang-format off template _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h index 4204017d9249bcf8ce7cabbc0d594d967e7c7b41..518375d684abdd3cc85fc1c413bcc28c3cf2f36e 100644 --- a/libcxx/include/__ranges/take_view.h +++ b/libcxx/include/__ranges/take_view.h @@ -180,10 +180,9 @@ public: return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; } - template + template requires sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> - _LIBCPP_HIDE_FROM_ABI - friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) { + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const _Iter<_OtherConst>& __lhs, const __sentinel& __rhs) { return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; } }; diff --git a/libcxx/include/__variant/monostate.h b/libcxx/include/__variant/monostate.h index 8fec34008f2d5d8751008b6afd0748ecd318ec30..2944e41ac70426f6697124ef6d373471b617f6e5 100644 --- a/libcxx/include/__variant/monostate.h +++ b/libcxx/include/__variant/monostate.h @@ -25,25 +25,25 @@ _LIBCPP_BEGIN_NAMESPACE_STD struct _LIBCPP_TEMPLATE_VIS monostate {}; -_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(monostate, monostate) noexcept { return true; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(monostate, monostate) noexcept { return true; } # if _LIBCPP_STD_VER >= 20 -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(monostate, monostate) noexcept { +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; } # else // _LIBCPP_STD_VER >= 20 -_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(monostate, monostate) noexcept { return false; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator!=(monostate, monostate) noexcept { return false; } -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(monostate, monostate) noexcept { return false; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<(monostate, monostate) noexcept { return false; } -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(monostate, monostate) noexcept { return false; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>(monostate, monostate) noexcept { return false; } -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(monostate, monostate) noexcept { return true; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<=(monostate, monostate) noexcept { return true; } -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(monostate, monostate) noexcept { return true; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>=(monostate, monostate) noexcept { return true; } # endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/cmath b/libcxx/include/cmath index 37f3c63fcef8a83c0221766244a503948bd1877f..e8a2acf078cd58cc011a47ca21d89d2112380856 100644 --- a/libcxx/include/cmath +++ b/libcxx/include/cmath @@ -798,13 +798,13 @@ _Fp __lerp(_Fp __a, _Fp __b, _Fp __t) noexcept { return __x < __b ? __x : __b; } -_LIBCPP_HIDE_FROM_ABI constexpr float +_LIBCPP_HIDE_FROM_ABI inline constexpr float lerp(float __a, float __b, float __t) _NOEXCEPT { return __lerp(__a, __b, __t); } -_LIBCPP_HIDE_FROM_ABI constexpr double +_LIBCPP_HIDE_FROM_ABI inline constexpr double lerp(double __a, double __b, double __t) _NOEXCEPT { return __lerp(__a, __b, __t); } -_LIBCPP_HIDE_FROM_ABI constexpr long double +_LIBCPP_HIDE_FROM_ABI inline constexpr long double lerp(long double __a, long double __b, long double __t) _NOEXCEPT { return __lerp(__a, __b, __t); } template diff --git a/libcxx/include/complex b/libcxx/include/complex index 7017f25e6c5e0bfd12a4b2bfb1ee8ee2216f9d10..44579b1ad528548dcdf8daa26a872a732a52ce72 100644 --- a/libcxx/include/complex +++ b/libcxx/include/complex @@ -1503,34 +1503,34 @@ inline namespace literals { inline namespace complex_literals { - _LIBCPP_HIDE_FROM_ABI constexpr complex operator""il(long double __im) + _LIBCPP_HIDE_FROM_ABI inline constexpr complex operator""il(long double __im) { return { 0.0l, __im }; } - _LIBCPP_HIDE_FROM_ABI constexpr complex operator""il(unsigned long long __im) + _LIBCPP_HIDE_FROM_ABI inline constexpr complex operator""il(unsigned long long __im) { return { 0.0l, static_cast(__im) }; } - _LIBCPP_HIDE_FROM_ABI constexpr complex operator""i(long double __im) + _LIBCPP_HIDE_FROM_ABI inline constexpr complex operator""i(long double __im) { return { 0.0, static_cast(__im) }; } - _LIBCPP_HIDE_FROM_ABI constexpr complex operator""i(unsigned long long __im) + _LIBCPP_HIDE_FROM_ABI inline constexpr complex operator""i(unsigned long long __im) { return { 0.0, static_cast(__im) }; } - _LIBCPP_HIDE_FROM_ABI constexpr complex operator""if(long double __im) + _LIBCPP_HIDE_FROM_ABI inline constexpr complex operator""if(long double __im) { return { 0.0f, static_cast(__im) }; } - _LIBCPP_HIDE_FROM_ABI constexpr complex operator""if(unsigned long long __im) + _LIBCPP_HIDE_FROM_ABI inline constexpr complex operator""if(unsigned long long __im) { return { 0.0f, static_cast(__im) }; } diff --git a/libcxx/include/cstddef b/libcxx/include/cstddef index 3844d4a373323dbdfc17933ac7212aaa87bd7af4..24be0fe780585b187636e4c0348f68fe7a129124 100644 --- a/libcxx/include/cstddef +++ b/libcxx/include/cstddef @@ -71,7 +71,7 @@ namespace std // purposefully not versioned { enum class byte : unsigned char {}; -_LIBCPP_HIDE_FROM_ABI constexpr byte operator| (byte __lhs, byte __rhs) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator| (byte __lhs, byte __rhs) noexcept { return static_cast( static_cast( @@ -79,10 +79,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr byte operator| (byte __lhs, byte __rhs) noexce )); } -_LIBCPP_HIDE_FROM_ABI constexpr byte& operator|=(byte& __lhs, byte __rhs) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte& operator|=(byte& __lhs, byte __rhs) noexcept { return __lhs = __lhs | __rhs; } -_LIBCPP_HIDE_FROM_ABI constexpr byte operator& (byte __lhs, byte __rhs) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator& (byte __lhs, byte __rhs) noexcept { return static_cast( static_cast( @@ -90,10 +90,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr byte operator& (byte __lhs, byte __rhs) noexce )); } -_LIBCPP_HIDE_FROM_ABI constexpr byte& operator&=(byte& __lhs, byte __rhs) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte& operator&=(byte& __lhs, byte __rhs) noexcept { return __lhs = __lhs & __rhs; } -_LIBCPP_HIDE_FROM_ABI constexpr byte operator^ (byte __lhs, byte __rhs) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator^ (byte __lhs, byte __rhs) noexcept { return static_cast( static_cast( @@ -101,10 +101,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr byte operator^ (byte __lhs, byte __rhs) noexce )); } -_LIBCPP_HIDE_FROM_ABI constexpr byte& operator^=(byte& __lhs, byte __rhs) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte& operator^=(byte& __lhs, byte __rhs) noexcept { return __lhs = __lhs ^ __rhs; } -_LIBCPP_HIDE_FROM_ABI constexpr byte operator~ (byte __b) noexcept +_LIBCPP_HIDE_FROM_ABI inline constexpr byte operator~ (byte __b) noexcept { return static_cast( static_cast( diff --git a/libcxx/include/deque b/libcxx/include/deque index b5d094dc415ddfd4eaddb9ee6b78876f96ae944a..d45793c502a9a74db6430d290f5442214ccfe242 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -967,12 +967,18 @@ public: // For more details, see the "Using libc++" documentation page or // the documentation for __sanitizer_annotate_contiguous_container. _LIBCPP_HIDE_FROM_ABI void __annotate_double_ended_contiguous_container( - [[__maybe_unused__]] const void* __beg, - [[__maybe_unused__]] const void* __end, - [[__maybe_unused__]] const void* __old_con_beg, - [[__maybe_unused__]] const void* __old_con_end, - [[__maybe_unused__]] const void* __new_con_beg, - [[__maybe_unused__]] const void* __new_con_end) const { + const void* __beg, + const void* __end, + const void* __old_con_beg, + const void* __old_con_end, + const void* __new_con_beg, + const void* __new_con_end) const { + (void)__beg; + (void)__end; + (void)__old_con_beg; + (void)__old_con_end; + (void)__new_con_beg; + (void)__new_con_end; #ifndef _LIBCPP_HAS_NO_ASAN if (__beg != nullptr && __asan_annotate_container_with_allocator<_Allocator>::value) __sanitizer_annotate_double_ended_contiguous_container( @@ -982,10 +988,14 @@ public: _LIBCPP_HIDE_FROM_ABI void __annotate_from_to( - [[__maybe_unused__]] size_type __beg, - [[__maybe_unused__]] size_type __end, - [[__maybe_unused__]] __asan_annotation_type __annotation_type, - [[__maybe_unused__]] __asan_annotation_place __place) const _NOEXCEPT { + size_type __beg, + size_type __end, + __asan_annotation_type __annotation_type, + __asan_annotation_place __place) const _NOEXCEPT { + (void)__beg; + (void)__end; + (void)__annotation_type; + (void)__place; #ifndef _LIBCPP_HAS_NO_ASAN // __beg - index of the first item to annotate // __end - index behind the last item to annotate (so last item + 1) diff --git a/libcxx/include/string b/libcxx/include/string index 9c97abefcb8d07c607be406acd21e6e28fb313d0..5bb4e941af36f74666bb5a891579dc07d92600f7 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -649,6 +649,17 @@ basic_string operator""s( const char32_t *str, size_t len ); _LIBCPP_PUSH_MACROS #include <__undef_macros> +#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN) +# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// This macro disables AddressSanitizer (ASan) instrumentation for a specific function, +// allowing memory accesses that would normally trigger ASan errors to proceed without crashing. +// This is useful for accessing parts of objects memory, which should not be accessed, +// such as unused bytes in short strings, that should never be accessed +// by other parts of the program. +#else +# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS +#endif +#define _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED false _LIBCPP_BEGIN_NAMESPACE_STD @@ -706,6 +717,9 @@ struct __init_with_sentinel_tag {}; template class basic_string { +private: + using __default_allocator_type = allocator<_CharT>; + public: typedef basic_string __self; typedef basic_string_view<_CharT, _Traits> __self_view; @@ -860,6 +874,7 @@ private: __set_long_pointer(__allocation); __set_long_size(__size); } + __annotate_new(__size); } template @@ -882,7 +897,9 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string() _NOEXCEPT_(is_nothrow_default_constructible::value) - : __r_(__value_init_tag(), __default_init_tag()) {} + : __r_(__value_init_tag(), __default_init_tag()) { + __annotate_new(0); + } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const allocator_type& __a) #if _LIBCPP_STD_VER <= 14 @@ -890,44 +907,65 @@ public: #else _NOEXCEPT #endif - : __r_(__value_init_tag(), __a) {} + : __r_(__value_init_tag(), __a) { + __annotate_new(0); + } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str) + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str) : __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) { if (!__str.__is_long()) + { __r_.first() = __str.__r_.first(); + __annotate_new(__get_short_size()); + } else __init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str, const allocator_type& __a) + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str, const allocator_type& __a) : __r_(__default_init_tag(), __a) { if (!__str.__is_long()) + { __r_.first() = __str.__r_.first(); + __annotate_new(__get_short_size()); + } else __init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size()); } #ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + basic_string(basic_string&& __str) # if _LIBCPP_STD_VER <= 14 _NOEXCEPT_(is_nothrow_move_constructible::value) # else _NOEXCEPT # endif - : __r_(std::move(__str.__r_)) { + // Turning off ASan instrumentation for variable initialization with _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS + // does not work consistently during initialization of __r_, so we instead unpoison __str's memory manually first. + // __str's memory needs to be unpoisoned only in the case where it's a short string. + : __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) { __str.__r_.first() = __rep(); + __str.__annotate_new(0); + if(!__is_long()) + __annotate_new(size()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str, const allocator_type& __a) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + basic_string(basic_string&& __str, const allocator_type& __a) : __r_(__default_init_tag(), __a) { if (__str.__is_long() && __a != __str.__alloc()) // copy, not move __init(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size()); else { if (__libcpp_is_constant_evaluated()) __r_.first() = __rep(); + if (!__str.__is_long()) + __str.__annotate_delete(); __r_.first() = __str.__r_.first(); __str.__r_.first() = __rep(); + __str.__annotate_new(0); + if(!__is_long() && this != &__str) + __annotate_new(size()); } } #endif // _LIBCPP_CXX03_LANG @@ -1085,6 +1123,7 @@ public: #endif // _LIBCPP_CXX03_LANG inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); } @@ -1092,7 +1131,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator __self_view() const _NOEXCEPT { return __self_view(data(), size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(const basic_string& __str); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& __str); template ::value && !__is_same_uncvref<_Tp, basic_string>::value, int> = 0> @@ -1102,8 +1141,8 @@ public: } #ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(basic_string&& __str) - _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& + operator=(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { __move_assign(__str, integral_constant()); return *this; } @@ -1116,7 +1155,7 @@ public: #if _LIBCPP_STD_VER >= 23 basic_string& operator=(nullptr_t) = delete; #endif - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(value_type __c); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(value_type __c); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT @@ -1339,12 +1378,22 @@ public: void __move_assign(basic_string&& __str, size_type __pos, size_type __len) { // Pilfer the allocation from __str. _LIBCPP_ASSERT_INTERNAL(__alloc() == __str.__alloc(), "__move_assign called with wrong allocator"); + size_type __old_sz = __str.size(); + if (!__str.__is_long()) + __str.__annotate_delete(); __r_.first() = __str.__r_.first(); __str.__r_.first() = __rep(); + __str.__annotate_new(0); _Traits::move(data(), data() + __pos, __len); __set_size(__len); _Traits::assign(data()[__len], value_type()); + + if (!__is_long()) { + __annotate_new(__len); + } else if(__old_sz > __len) { + __annotate_shrink(__old_sz); + } } #endif @@ -1742,7 +1791,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend(size_type __target_capacity); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool __is_long() const _NOEXCEPT { if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) { return __r_.first().__l.__is_long_; @@ -1782,6 +1831,7 @@ private: value_type* __p; if (__cap - __sz >= __n) { + __annotate_increase(__n); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -1808,7 +1858,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void __set_short_size(size_type __s) _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL( __s < __min_cap, "__s should never be greater than or equal to the short string capacity"); @@ -1816,7 +1866,7 @@ private: __r_.first().__s.__is_long_ = false; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS size_type __get_short_size() const _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL( !__r_.first().__s.__is_long_, "String has to be short when trying to get the short size"); @@ -1866,6 +1916,43 @@ private: const_pointer __get_pointer() const _NOEXCEPT {return __is_long() ? __get_long_pointer() : __get_short_pointer();} + // The following functions are no-ops outside of AddressSanitizer mode. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container(const void* __old_mid, const void* __new_mid) const { + (void)__old_mid; + (void)__new_mid; +#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN) + const void* __begin = data(); + const void* __end = data() + capacity() + 1; + if (!__libcpp_is_constant_evaluated() && __begin != nullptr && is_same::value) + __sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid); +#endif + } + + // ASan: short string is poisoned if and only if this function returns true. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __asan_short_string_is_annotated() const _NOEXCEPT { + return _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED && !__libcpp_is_constant_evaluated(); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + capacity() + 1, data() + __current_size + 1); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_delete() const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_increase(size_type __n) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + __n); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_shrink(size_type __old_size) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + __old_size + 1, data() + size() + 1); + } + template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT @@ -1968,6 +2055,7 @@ private: } else { + __annotate_delete(); allocator_type __a = __str.__alloc(); auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap()); __begin_lifetime(__allocation.ptr, __allocation.count); @@ -1977,6 +2065,7 @@ private: __set_long_pointer(__allocation.ptr); __set_long_cap(__allocation.count); __set_long_size(__str.size()); + __annotate_new(__get_long_size()); } } } @@ -1989,7 +2078,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __move_assign(basic_string& __str, false_type) _NOEXCEPT_(__alloc_traits::is_always_equal::value); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void __move_assign(basic_string& __str, true_type) #if _LIBCPP_STD_VER >= 17 _NOEXCEPT; @@ -2024,18 +2113,28 @@ private: // Assigns the value in __s, guaranteed to be __n < __min_cap in length. inline _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_short(const value_type* __s, size_type __n) { + size_type __old_size = size(); + if (__n > __old_size) + __annotate_increase(__n - __old_size); pointer __p = __is_long() ? (__set_long_size(__n), __get_long_pointer()) : (__set_short_size(__n), __get_short_pointer()); traits_type::move(std::__to_address(__p), __s, __n); traits_type::assign(__p[__n], value_type()); + if (__old_size > __n) + __annotate_shrink(__old_size); return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __null_terminate_at(value_type* __p, size_type __newsz) { + size_type __old_size = size(); + if (__newsz > __old_size) + __annotate_increase(__newsz - __old_size); __set_size(__newsz); traits_type::assign(__p[__newsz], value_type()); + if (__old_size > __newsz) + __annotate_shrink(__old_size); return *this; } @@ -2142,6 +2241,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template @@ -2170,6 +2270,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_ty } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template @@ -2194,6 +2295,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external( __set_long_size(__sz); } traits_type::copy(std::__to_address(__p), __s, __sz + 1); + __annotate_new(__sz); } template @@ -2223,6 +2325,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c) } traits_type::assign(std::__to_address(__p), __n, __c); traits_type::assign(__p[__n], value_type()); + __annotate_new(__n); } template @@ -2238,6 +2341,7 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) { __r_.first() = __rep(); + __annotate_new(0); #ifndef _LIBCPP_HAS_NO_EXCEPTIONS try @@ -2249,6 +2353,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputItera } catch (...) { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); throw; @@ -2309,6 +2414,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_size( throw; } #endif // _LIBCPP_HAS_NO_EXCEPTIONS + __annotate_new(__sz); } template @@ -2325,6 +2431,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __annotate_delete(); auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); @@ -2344,6 +2451,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace __old_sz = __n_copy + __n_add + __sec_cp_sz; __set_long_size(__old_sz); traits_type::assign(__p[__old_sz], value_type()); + __annotate_new(__old_cap + __delta_cap); } // __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it @@ -2366,6 +2474,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __annotate_delete(); auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); @@ -2396,6 +2505,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace( __grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add); _LIBCPP_SUPPRESS_DEPRECATED_POP __set_long_size(__old_sz - __n_del + __n_add); + __annotate_new(__old_sz - __n_del + __n_add); } // assign @@ -2408,10 +2518,15 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias( const value_type* __s, size_type __n) { size_type __cap = __is_short ? static_cast(__min_cap) : __get_long_cap(); if (__n < __cap) { + size_type __old_size = __is_short ? __get_short_size() : __get_long_size(); + if (__n > __old_size) + __annotate_increase(__n - __old_size); pointer __p = __is_short ? __get_short_pointer() : __get_long_pointer(); __is_short ? __set_short_size(__n) : __set_long_size(__n); traits_type::copy(std::__to_address(__p), __s, __n); traits_type::assign(__p[__n], value_type()); + if (__old_size > __n) + __annotate_shrink(__old_size); } else { size_type __sz = __is_short ? __get_short_size() : __get_long_size(); __grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s); @@ -2426,6 +2541,9 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_external( const value_type* __s, size_type __n) { size_type __cap = capacity(); if (__cap >= __n) { + size_type __old_size = size(); + if (__n > __old_size) + __annotate_increase(__n - __old_size); value_type* __p = std::__to_address(__get_pointer()); traits_type::move(__p, __s, __n); return __null_terminate_at(__p, __n); @@ -2453,11 +2571,15 @@ basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) { size_type __cap = capacity(); + size_type __old_size = size(); if (__cap < __n) { size_type __sz = size(); __grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz); + __annotate_increase(__n); } + else if(__n > __old_size) + __annotate_increase(__n - __old_size); value_type* __p = std::__to_address(__get_pointer()); traits_type::assign(__p, __n, __c); return __null_terminate_at(__p, __n); @@ -2468,24 +2590,26 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::operator=(value_type __c) { - pointer __p; - if (__is_long()) - { - __p = __get_long_pointer(); - __set_long_size(1); - } - else - { - __p = __get_short_pointer(); - __set_short_size(1); - } - traits_type::assign(*__p, __c); - traits_type::assign(*++__p, value_type()); - return *this; + pointer __p; + size_type __old_size = size(); + if (__old_size == 0) + __annotate_increase(1); + if (__is_long()) { + __p = __get_long_pointer(); + __set_long_size(1); + } else { + __p = __get_short_pointer(); + __set_short_size(1); + } + traits_type::assign(*__p, __c); + traits_type::assign(*++__p, value_type()); + if (__old_size > 1) + __annotate_shrink(__old_size); + return *this; } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str) { @@ -2493,7 +2617,12 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str) __copy_assign_alloc(__str); if (!__is_long()) { if (!__str.__is_long()) { + size_type __old_size = __get_short_size(); + if (__get_short_size() < __str.__get_short_size()) + __annotate_increase(__str.__get_short_size() - __get_short_size()); __r_.first() = __str.__r_.first(); + if (__old_size > __get_short_size()) + __annotate_shrink(__old_size); } else { return __assign_no_alias(__str.data(), __str.size()); } @@ -2519,7 +2648,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, fa } template -inline _LIBCPP_CONSTEXPR_SINCE_CXX20 +inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, true_type) #if _LIBCPP_STD_VER >= 17 @@ -2528,6 +2657,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr _NOEXCEPT_(is_nothrow_move_assignable::value) #endif { + __annotate_delete(); if (__is_long()) { __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); @@ -2535,13 +2665,35 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr if (!is_nothrow_move_assignable::value) { __set_short_size(0); traits_type::assign(__get_short_pointer()[0], value_type()); + __annotate_new(0); } #endif } + size_type __str_old_size = __str.size(); + bool __str_was_short = !__str.__is_long(); + __move_assign_alloc(__str); __r_.first() = __str.__r_.first(); __str.__set_short_size(0); traits_type::assign(__str.__get_short_pointer()[0], value_type()); + + if (__str_was_short && this != &__str) + __str.__annotate_shrink(__str_old_size); + else + // ASan annotations: was long, so object memory is unpoisoned as new. + // Or is same as *this, and __annotate_delete() was called. + __str.__annotate_new(0); + + // ASan annotations: Guard against `std::string s; s = std::move(s);` + // You can find more here: https://en.cppreference.com/w/cpp/utility/move + // Quote: "Unless otherwise specified, all standard library objects that have been moved + // from are placed in a "valid but unspecified state", meaning the object's class + // invariants hold (so functions without preconditions, such as the assignment operator, + // can be safely used on the object after it was moved from):" + // Quote: "v = std::move(v); // the value of v is unspecified" + if (!__is_long() && &__str != this) + // If it is long string, delete was never called on original __str's buffer. + __annotate_new(__get_short_size()); } #endif @@ -2587,6 +2739,7 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _ _LIBCPP_ASSERT_INTERNAL( __string_is_trivial_iterator<_Iterator>::value, "The iterator type given to `__assign_trivial` must be trivial"); + size_type __old_size = size(); size_type __cap = capacity(); if (__cap < __n) { // Unlike `append` functions, if the input range points into the string itself, there is no case that the input @@ -2597,12 +2750,17 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _ // object itself stays valid even if reallocation happens. size_type __sz = size(); __grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz); + __annotate_increase(__n); } + else if (__n > __old_size) + __annotate_increase(__n - __old_size); pointer __p = __get_pointer(); for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); traits_type::assign(*__p, value_type()); __set_size(__n); + if (__n < __old_size) + __annotate_shrink(__old_size); } template @@ -2663,6 +2821,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_ty { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); traits_type::copy(__p + __sz, __s, __n); __sz += __n; @@ -2686,6 +2845,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c) size_type __sz = size(); if (__cap - __sz < __n) __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer(); traits_type::assign(std::__to_address(__p) + __sz, __n, __c); __sz += __n; @@ -2705,6 +2865,7 @@ basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n) size_type __sz = size(); if (__cap - __sz < __n) __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer(); __sz += __n; __set_size(__sz); @@ -2733,8 +2894,10 @@ basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c) if (__sz == __cap) { __grow_by_without_replace(__cap, 1, __sz, __sz, 0); + __annotate_increase(1); __is_short = false; // the string is always long after __grow_by - } + } else + __annotate_increase(1); pointer __p = __get_pointer(); if (__is_short) { @@ -2766,6 +2929,7 @@ basic_string<_CharT, _Traits, _Allocator>::append( { if (__cap - __sz < __n) __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer() + __sz; for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); @@ -2831,6 +2995,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_t { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) @@ -2864,6 +3029,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n value_type* __p; if (__cap - __sz >= __n) { + __annotate_increase(__n); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) @@ -2972,6 +3138,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, value_ty } else { + __annotate_increase(1); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -3002,6 +3169,8 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __ value_type* __p = std::__to_address(__get_pointer()); if (__n1 != __n2) { + if (__n2 > __n1) + __annotate_increase(__n2 - __n1); size_type __n_move = __sz - __pos - __n1; if (__n_move != 0) { @@ -3046,20 +3215,18 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __ __n1 = std::min(__n1, __sz - __pos); size_type __cap = capacity(); value_type* __p; - if (__cap - __sz + __n1 >= __n2) - { - __p = std::__to_address(__get_pointer()); - if (__n1 != __n2) - { - size_type __n_move = __sz - __pos - __n1; - if (__n_move != 0) - traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); - } - } - else - { - __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); - __p = std::__to_address(__get_long_pointer()); + if (__cap - __sz + __n1 >= __n2) { + __p = std::__to_address(__get_pointer()); + if (__n1 != __n2) { + if (__n2 > __n1) + __annotate_increase(__n2 - __n1); + size_type __n_move = __sz - __pos - __n1; + if (__n_move != 0) + traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); + } + } else { + __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); + __p = std::__to_address(__get_long_pointer()); } traits_type::assign(__p + __pos, __n2, __c); return __null_terminate_at(__p, __sz - (__n1 - __n2)); @@ -3187,6 +3354,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { + size_type __old_size = size(); if (__is_long()) { traits_type::assign(*__get_long_pointer(), value_type()); @@ -3197,6 +3365,7 @@ basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT traits_type::assign(*__get_short_pointer(), value_type()); __set_short_size(0); } + __annotate_shrink(__old_size); } template @@ -3259,6 +3428,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) { + __annotate_delete(); size_type __cap = capacity(); size_type __sz = size(); @@ -3315,6 +3485,7 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target } else __set_short_size(__sz); + __annotate_new(__sz); } template @@ -3365,8 +3536,16 @@ basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str) __alloc_traits::propagate_on_container_swap::value || __alloc_traits::is_always_equal::value || __alloc() == __str.__alloc(), "swapping non-equal allocators"); + if (!__is_long()) + __annotate_delete(); + if (this != &__str && !__str.__is_long()) + __str.__annotate_delete(); std::swap(__r_.first(), __str.__r_.first()); std::__swap_allocator(__alloc(), __str.__alloc()); + if (!__is_long()) + __annotate_new(__get_short_size()); + if (this != &__str && !__str.__is_long()) + __str.__annotate_new(__str.__get_short_size()); } // find @@ -3854,12 +4033,12 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__clear_and_shrink() _NOEXCEPT { - clear(); - if(__is_long()) - { - __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1); - __r_.first() = __rep(); - } + clear(); + if (__is_long()) { + __annotate_delete(); + __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1); + __r_.first() = __rep(); + } } // operator== diff --git a/libcxx/include/vector b/libcxx/include/vector index fd2d5e11f0ea4e7557347216a12895a6bda6bfaa..d010a1f6ec9f91f41a343778950a064c0bd30b96 100644 --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -852,11 +852,15 @@ private: // the documentation for __sanitizer_annotate_contiguous_container. _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - void __annotate_contiguous_container([[__maybe_unused__]] const void *__beg, - [[__maybe_unused__]] const void *__end, - [[__maybe_unused__]] const void *__old_mid, - [[__maybe_unused__]] const void *__new_mid) const - { + void __annotate_contiguous_container(const void *__beg, + const void *__end, + const void *__old_mid, + const void *__new_mid) const + { + (void)__beg; + (void)__end; + (void)__old_mid; + (void)__new_mid; #ifndef _LIBCPP_HAS_NO_ASAN if (!__libcpp_is_constant_evaluated() && __beg != nullptr && __asan_annotate_container_with_allocator<_Allocator>::value) __sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid); diff --git a/libcxx/modules/std/string.inc b/libcxx/modules/std/string.inc index 8366690fd9d37d078863cee7f80b18c54b56fb1a..c83ee7643f87e9a8acc6b6a1af5030dcf9919064 100644 --- a/libcxx/modules/std/string.inc +++ b/libcxx/modules/std/string.inc @@ -67,15 +67,10 @@ export namespace std { // [basic.string.hash], hash support using std::hash; - // TODO MODULES is this a bug? -#if _LIBCPP_STD_VER >= 23 - using std::operator""s; -#else inline namespace literals { inline namespace string_literals { // [basic.string.literals], suffix for basic_string literals using std::literals::string_literals::operator""s; } // namespace string_literals - } // namespace literals -#endif + } // namespace literals } // namespace std diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/user_defined_char_type.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/user_defined_char_type.pass.cpp index d7b4b816d975b9fc37dba095984da1c369642b7c..9a4a2f0d5657e1d8bc980d5f88bf24d79a3bb96c 100644 --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/user_defined_char_type.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/user_defined_char_type.pass.cpp @@ -16,8 +16,6 @@ #include #include -#include "test_macros.h" - struct Char { Char() = default; Char(char c) : underlying_(c) {} @@ -73,15 +71,53 @@ struct char_traits { static int_type eof() { return char_traits::eof(); } }; +// This ctype specialization treats all characters as spaces template <> -class ctype : public locale::facet { +class ctype : public locale::facet, public ctype_base { public: + using char_type = Char; static locale::id id; - Char toupper(Char c) const { return Char(std::toupper(c.underlying_)); } - const char* widen(const char* first, const char* last, Char* dst) const { - for (; first != last;) - *dst++ = Char(*first++); - return last; + explicit ctype(std::size_t refs = 0) : locale::facet(refs) {} + + bool is(mask m, char_type) const { return m & ctype_base::space; } + const char_type* is(const char_type* low, const char_type* high, mask* vec) const { + for (; low != high; ++low) + *vec++ = ctype_base::space; + return high; + } + + const char_type* scan_is(mask m, const char_type* beg, const char_type* end) const { + for (; beg != end; ++beg) + if (this->is(m, *beg)) + return beg; + return end; + } + + const char_type* scan_not(mask m, const char_type* beg, const char_type* end) const { + for (; beg != end; ++beg) + if (!this->is(m, *beg)) + return beg; + return end; + } + + char_type toupper(char_type c) const { return c; } + const char_type* toupper(char_type*, const char_type* end) const { return end; } + + char_type tolower(char_type c) const { return c; } + const char_type* tolower(char_type*, const char_type* end) const { return end; } + + char_type widen(char c) const { return char_type(c); } + const char* widen(const char* beg, const char* end, char_type* dst) const { + for (; beg != end; ++beg, ++dst) + *dst = char_type(*beg); + return end; + } + + char narrow(char_type c, char /*dflt*/) const { return c.underlying_; } + const char_type* narrow(const char_type* beg, const char_type* end, char /*dflt*/, char* dst) const { + for (; beg != end; ++beg, ++dst) + *dst = beg->underlying_; + return end; } }; diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp index da4bd9fbbe1794f9df9c3b30be4591a14b102438..6bfa0ab487ba1ba45b77f768edb50c4dd3aed8b6 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp @@ -40,10 +40,16 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); -static_assert( CanBePiped); -static_assert( CanBePiped); -static_assert(!CanBePiped); -static_assert(!CanBePiped); +// Regression test for #75002, views::lazy_split shouldn't be a range adaptor closure +static_assert(!CanBePiped); +static_assert(!CanBePiped); +static_assert(!CanBePiped); +static_assert(!CanBePiped); + +static_assert(CanBePiped); +static_assert(CanBePiped); +static_assert(!CanBePiped); +static_assert(!CanBePiped); static_assert(std::same_as); diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp index cd12011daeab5d5997053a0eb560641e0bab901b..85d13ac5c29dfbc9aab8ec6fabb2633ddf255e23 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/adaptor.pass.cpp @@ -39,10 +39,16 @@ static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); -static_assert( CanBePiped); -static_assert( CanBePiped); -static_assert(!CanBePiped); -static_assert(!CanBePiped); +// Regression test for #75002, views::split shouldn't be a range adaptor closure +static_assert(!CanBePiped); +static_assert(!CanBePiped); +static_assert(!CanBePiped); +static_assert(!CanBePiped); + +static_assert(CanBePiped); +static_assert(CanBePiped); +static_assert(!CanBePiped); +static_assert(!CanBePiped); static_assert(std::same_as); diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp similarity index 83% rename from libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp index c949eb7cc08469aa378bedf73a4797cf11d1e993..15b2b5476e86dd742fc750ee4eb29c49745eb733 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/base.pass.cpp @@ -8,10 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 -// sentinel() = default; -// constexpr explicit sentinel(sentinel_t end); -// constexpr sentinel(sentinel s) -// requires Const && convertible_to, sentinel_t>; +// constexpr sentinel_t base() const; #include #include diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp similarity index 77% rename from libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp index 9d1bdaa82d95dc1d7fbc9f377ccf1d3ff394ddbe..8928371939c87251e5a3eeddd1a9323a98678e90 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp @@ -34,14 +34,14 @@ constexpr bool test() { { // Test the conversion from "sentinel" to "sentinel-to-const". - using TakeView = std::ranges::take_view; - using Sentinel = std::ranges::sentinel_t; + using TakeView = std::ranges::take_view; + using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(std::is_convertible_v); - TakeView tv = TakeView(MoveOnlyView(buffer), 4); - Sentinel s = tv.end(); + TakeView tv = TakeView(MoveOnlyView(buffer), 4); + Sentinel s = tv.end(); ConstSentinel cs = s; - cs = s; // test assignment also + cs = s; // test assignment also assert(tv.begin() + 4 == s); assert(tv.begin() + 4 == cs); assert(std::as_const(tv).begin() + 4 == s); @@ -50,12 +50,12 @@ constexpr bool test() { { // Test the constructor from "base-sentinel" to "sentinel". - using TakeView = std::ranges::take_view; - using Sentinel = std::ranges::sentinel_t; + using TakeView = std::ranges::take_view; + using Sentinel = std::ranges::sentinel_t; sentinel_wrapper sw1 = MoveOnlyView(buffer).end(); - static_assert( std::is_constructible_v>); + static_assert(std::is_constructible_v>); static_assert(!std::is_convertible_v, Sentinel>); - auto s = Sentinel(sw1); + auto s = Sentinel(sw1); std::same_as> auto sw2 = s.base(); assert(base(sw2) == base(sw1)); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6f433e30f60db2128abea66ea75f00564c2b85c --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// friend constexpr bool operator==(const CI& y, const sentinel& x); +// template +// requires sentinel_for, iterator_t>> +// friend constexpr bool operator==(const CI& y, const sentinel& x); + +#include +#include +#include +#include +#include + +#include "test_comparisons.h" +#include "test_iterators.h" + +template +using MaybeConstIterator = cpp20_input_iterator>; + +template +class CrossConstComparableSentinel { + using Base = std::conditional_t; + Base base_; + +public: + CrossConstComparableSentinel() = default; + constexpr explicit CrossConstComparableSentinel(Base base) : base_(base) {} + + friend constexpr bool operator==(const MaybeConstIterator& it, const CrossConstComparableSentinel& se) { + return base(it) == se.base_; + } + + friend constexpr bool operator==(const MaybeConstIterator& it, const CrossConstComparableSentinel& se) { + return base(it) == se.base_; + } +}; + +static_assert(std::sentinel_for, MaybeConstIterator>); +static_assert(std::sentinel_for, MaybeConstIterator>); +static_assert(std::sentinel_for, MaybeConstIterator>); +static_assert(std::sentinel_for, MaybeConstIterator>); + +struct CrossConstComparableView : std::ranges::view_base { + template + constexpr explicit CrossConstComparableView(int (&arr)[N]) : b_(arr), e_(arr + N) {} + + constexpr MaybeConstIterator begin() { return MaybeConstIterator{b_}; } + constexpr CrossConstComparableSentinel end() { return CrossConstComparableSentinel{e_}; } + + constexpr MaybeConstIterator begin() const { return MaybeConstIterator{b_}; } + constexpr CrossConstComparableSentinel end() const { return CrossConstComparableSentinel{e_}; } + +private: + int* b_; + int* e_; +}; + +static_assert(std::ranges::range); +static_assert(std::ranges::range); + +struct NonCrossConstComparableView : std::ranges::view_base { + int* begin(); + sentinel_wrapper end(); + + long* begin() const; + sentinel_wrapper end() const; +}; + +static_assert(std::ranges::range); +static_assert(std::ranges::range); + +template +concept weakly_equality_comparable_with = requires(const T& t, const U& u) { + t == u; + t != u; + u == t; + u != t; +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + using CrossConstComparableTakeView = std::ranges::take_view; + + { // Compare CI with sentinel + { // Const == true + AssertEqualityReturnBool, + std::ranges::sentinel_t>(); + const CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true)); + assert(testEquality(tv.begin(), tv.end(), false)); + } + + { // Const == false + AssertEqualityReturnBool, + std::ranges::sentinel_t>(); + CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true)); + assert(testEquality(std::ranges::next(tv.begin(), 1), tv.end(), false)); + } + } + + { // Compare CI with sentinel + { // Const == true + AssertEqualityReturnBool, + std::ranges::sentinel_t>(); + CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 4), tv.end(), true)); + assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 2), tv.end(), false)); + } + + { // Const == false + AssertEqualityReturnBool, + std::ranges::sentinel_t>(); + CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4); + assert(testEquality(std::ranges::next(tv.begin(), 4), std::as_const(tv).end(), true)); + assert(testEquality(std::ranges::next(tv.begin(), 3), std::as_const(tv).end(), false)); + } + } + + { // Check invalid comparisons between CI and sentinel + using TakeView = std::ranges::take_view; + static_assert( + !weakly_equality_comparable_with, std::ranges::sentinel_t>); + static_assert( + !weakly_equality_comparable_with, std::ranges::sentinel_t>); + + // Those should be valid + static_assert( + weakly_equality_comparable_with, std::ranges::sentinel_t>); + static_assert(weakly_equality_comparable_with, + std::ranges::sentinel_t>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp deleted file mode 100644 index eb265a7e034817fc436062089c497fca9f878610..0000000000000000000000000000000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/eq.pass.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// sentinel() = default; -// constexpr explicit sentinel(sentinel_t end); -// constexpr sentinel(sentinel s) -// requires Const && convertible_to, sentinel_t>; - -#include -#include - -#include "test_macros.h" -#include "test_iterators.h" -#include "../types.h" - -constexpr bool test() { - int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - - { - { - const std::ranges::take_view tv(MoveOnlyView{buffer}, 4); - assert(tv.end() == std::ranges::next(tv.begin(), 4)); - assert(std::ranges::next(tv.begin(), 4) == tv.end()); - } - - { - std::ranges::take_view tv(MoveOnlyView{buffer}, 4); - assert(tv.end() == std::ranges::next(tv.begin(), 4)); - assert(std::ranges::next(tv.begin(), 4) == tv.end()); - } - } - - { - std::ranges::take_view tvNonConst(MoveOnlyView{buffer}, 4); - const std::ranges::take_view tvConst(MoveOnlyView{buffer}, 4); - assert(tvNonConst.end() == std::ranges::next(tvConst.begin(), 4)); - assert(std::ranges::next(tvConst.begin(), 4) == tvNonConst.end()); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp index e1d20662e41de89083c82aa4c9621e34feb56f7c..61867cfb087b9392fe42497dfd8a6002c768a46d 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp @@ -15,6 +15,7 @@ #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" #include "test_macros.h" @@ -28,6 +29,7 @@ TEST_CONSTEXPR_CXX20 void test_invariant(S s, test_allocator_statistics& alloc_s while (s.size() < s.capacity()) s.push_back(typename S::value_type()); assert(s.size() == s.capacity()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS catch (...) { @@ -43,10 +45,12 @@ TEST_CONSTEXPR_CXX20 void test_string(const Alloc& a) { { S const s((Alloc(a))); assert(s.capacity() >= 0); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { S const s(3, 'x', Alloc(a)); assert(s.capacity() >= 3); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #if TEST_STD_VER >= 11 // Check that we perform SSO @@ -54,6 +58,7 @@ TEST_CONSTEXPR_CXX20 void test_string(const Alloc& a) { S const s; assert(s.capacity() > 0); ASSERT_NOEXCEPT(s.capacity()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #endif } @@ -63,18 +68,22 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(test_allocator()); test_string(test_allocator(3)); test_string(min_allocator()); + test_string(safe_allocator()); { test_allocator_statistics alloc_stats; typedef std::basic_string, test_allocator > S; S s((test_allocator(&alloc_stats))); test_invariant(s, alloc_stats); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.assign(10, 'a'); s.erase(5); test_invariant(s, alloc_stats); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.assign(100, 'a'); s.erase(50); test_invariant(s, alloc_stats); + LIBCPP_ASSERT(is_string_asan_correct(s)); } return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp index 3a308de9b7569a3fa230081eab0b5c21b68bc1cc..643ea4a3bdad486d3205848b02d18c28026a640b 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp @@ -15,31 +15,39 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s) { s.clear(); assert(s.size() == 0); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template TEST_CONSTEXPR_CXX20 void test_string() { S s; test(s); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.assign(10, 'a'); s.erase(5); + LIBCPP_ASSERT(is_string_asan_correct(s)); test(s); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.assign(100, 'a'); s.erase(50); + LIBCPP_ASSERT(is_string_asan_correct(s)); test(s); + LIBCPP_ASSERT(is_string_asan_correct(s)); } TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp index b740901be1c4d5b59c03ffb05b2ac0cb1b0c4ce2..43414da3794a5f8e34114eb3be05d9c35abe888a 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template void test(typename S::size_type min_cap, typename S::size_type erased_index) { @@ -33,6 +34,7 @@ void test(typename S::size_type min_cap, typename S::size_type erased_index) { assert(s == s0); assert(s.capacity() <= old_cap); assert(s.capacity() >= s.size()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -47,6 +49,7 @@ bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d35a5bcefc46aece41645cacbd4bb6b6555c9eba --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// This test verifies that the ASan annotations for basic_string objects remain accurate +// after invoking basic_string::reserve(size_type __requested_capacity). +// Different types are used to confirm that ASan works correctly with types of different sizes. +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test() { + S short_s1(3, 'a'), long_s1(100, 'c'); + short_s1.reserve(0x1337); + long_s1.reserve(0x1337); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_ASSERT(is_string_asan_correct(long_s1)); + + short_s1.clear(); + long_s1.clear(); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_ASSERT(is_string_asan_correct(long_s1)); + + short_s1.reserve(0x1); + long_s1.reserve(0x1); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_ASSERT(is_string_asan_correct(long_s1)); + + S short_s2(3, 'a'), long_s2(100, 'c'); + short_s2.reserve(0x1); + long_s2.reserve(0x1); + + LIBCPP_ASSERT(is_string_asan_correct(short_s2)); + LIBCPP_ASSERT(is_string_asan_correct(long_s2)); +} + +int main(int, char**) { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif +#if TEST_STD_VER >= 11 + test(); + test(); +#endif +#if TEST_STD_VER >= 20 + test(); +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp index dfb3b270f750ec708a1f08f7e25b18ed65ad603b..30c171680a23c4ea1bf0f6ffd30d118e0b3a1ffd 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp @@ -20,6 +20,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -28,6 +29,7 @@ test(typename S::size_type min_cap, typename S::size_type erased_index, typename s.erase(erased_index); assert(s.size() == erased_index); assert(s.capacity() >= min_cap); // Check that we really have at least this capacity. + LIBCPP_ASSERT(is_string_asan_correct(s)); #if TEST_STD_VER > 17 typename S::size_type old_cap = s.capacity(); @@ -39,6 +41,7 @@ test(typename S::size_type min_cap, typename S::size_type erased_index, typename assert(s == s0); assert(s.capacity() >= res_arg); assert(s.capacity() >= s.size()); + LIBCPP_ASSERT(is_string_asan_correct(s)); #if TEST_STD_VER > 17 assert(s.capacity() >= old_cap); // reserve never shrinks as of P0966 (C++20) #endif diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp index bbe6551a0ff1181dc1e99b8b09d476607662f952..edc8b67808b8566d733c6f78b617244c99a9b26d 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp @@ -19,6 +19,7 @@ #include "make_string.h" #include "test_macros.h" +#include "asan_testing.h" template constexpr void test_appending(std::size_t k, size_t N, size_t new_capacity) { @@ -37,6 +38,7 @@ constexpr void test_appending(std::size_t k, size_t N, size_t new_capacity) { const S expected = S(k, 'a') + S(N - k, 'b'); assert(s == expected); assert(s.c_str()[N] == '\0'); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -55,6 +57,7 @@ constexpr void test_truncating(std::size_t o, size_t N) { const S expected = S(N - 1, 'a') + S(1, 'b'); assert(s == expected); assert(s.c_str()[N] == '\0'); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -76,11 +79,14 @@ constexpr bool test() { void test_value_categories() { std::string s; s.resize_and_overwrite(10, [](char*&&, std::size_t&&) { return 0; }); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.resize_and_overwrite(10, [](char* const&, const std::size_t&) { return 0; }); + LIBCPP_ASSERT(is_string_asan_correct(s)); struct RefQualified { int operator()(char*, std::size_t) && { return 0; } }; s.resize_and_overwrite(10, RefQualified{}); + LIBCPP_ASSERT(is_string_asan_correct(s)); } int main(int, char**) { diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp index 487b12d9df87f338790464511ce8a20bdf8f4657..7cf4b7ca3b6efd65bfd39ef39b2de240b97a987b 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) { @@ -23,6 +24,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) { s.resize(n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) { @@ -61,6 +63,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp index 3b6adc0b0afeb191710cb3d2a2f84bb1eb847b6b..e3b925ca8bcdbde5a67ba250a539b213f7e4027d 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, typename S::value_type c, S expected) { @@ -23,6 +24,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, typename S::value_t s.resize(n, c); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) { @@ -57,12 +59,23 @@ TEST_CONSTEXPR_CXX20 void test_string() { 'a', S("12345678901234567890123456789012345678901234567890aaaaaaaaaa")); test(S(), S::npos, 'a', S("not going to happen")); + //ASan: + test(S(), 21, 'a', S("aaaaaaaaaaaaaaaaaaaaa")); + test(S(), 22, 'a', S("aaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 23, 'a', S("aaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 24, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 29, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 30, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 31, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 32, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 33, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); } TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp index 66eefdd383dc08ec74dab113292fe3b41b9f6e2e..057050cdcf7fa3a486e5827e3b426431dcb68eef 100644 --- a/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s) { @@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s) { assert(s == s0); assert(s.capacity() <= old_cap); assert(s.capacity() >= s.size()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -43,12 +45,19 @@ TEST_CONSTEXPR_CXX20 void test_string() { s.assign(100, 'a'); s.erase(50); test(s); + + s.assign(100, 'a'); + for (int i = 0; i <= 9; ++i) { + s.erase(90 - 10 * i); + test(s); + } } TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp index a6b625b7b0e8113ef4a0657042e4d43ecf465524..dcf697bed752fa4a6860e53cfde5a6b790984c54 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp @@ -23,6 +23,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(SV sv, std::size_t pos, std::size_t n) { @@ -38,6 +39,7 @@ TEST_CONSTEXPR_CXX20 void test(SV sv, std::size_t pos, std::size_t n) { assert(T::compare(s2.data(), sv.data() + pos, rlen) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) { @@ -113,6 +115,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(test_allocator(8)); #if TEST_STD_VER >= 11 test_string(min_allocator()); + test_string(safe_allocator()); #endif { diff --git a/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp index 97a0566ba031b00daf5ed71fd11c67ed884a3428..91beac37764db48b43a6694cb02de473bf20296a 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test() { @@ -31,6 +32,7 @@ TEST_CONSTEXPR_CXX20 void test() { assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { #if TEST_STD_VER > 14 @@ -46,6 +48,7 @@ TEST_CONSTEXPR_CXX20 void test() { assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type(5)); + LIBCPP_ASSERT(is_string_asan_correct(s)); } } @@ -65,6 +68,7 @@ TEST_CONSTEXPR_CXX20 void test2() { assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { # if TEST_STD_VER > 14 @@ -80,6 +84,7 @@ TEST_CONSTEXPR_CXX20 void test2() { assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } } @@ -89,6 +94,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test, test_allocator > >(); #if TEST_STD_VER >= 11 test2, min_allocator > >(); + test2, safe_allocator > >(); test2, explicit_allocator > >(); #endif diff --git a/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp index e7d18b4ca87179d9cdcdd479e0329a91901210ba..49a90872c56faede921759f8d4770e06ddce481b 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp @@ -17,6 +17,7 @@ #include #include "test_macros.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { // Test that assignment from {} and {ptr, len} are allowed and are not @@ -25,11 +26,37 @@ TEST_CONSTEXPR_CXX20 bool test() { std::string s = "hello world"; s = {}; assert(s.empty()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { std::string s = "hello world"; s = {"abc", 2}; assert(s == "ab"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + std::string s = "hello world"; + s = {"It'sALongString!NoSSO!qwertyuiop", 30}; + assert(s == "It'sALongString!NoSSO!qwertyui"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!"; + s = {"It'sALongString!NoSSO!qwertyuiop", 30}; + assert(s == "It'sALongString!NoSSO!qwertyui"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!"; + s = {"abc", 2}; + assert(s == "ab"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!"; + s = {"abc", 0}; + assert(s == ""); + LIBCPP_ASSERT(is_string_asan_correct(s)); } return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp index 3cffc82e94835263a94d77b951cbb419c860483b..1019dc8bca5df520cb188818d7a7c421c19132c4 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s1, typename S::value_type s2) { @@ -24,6 +25,7 @@ TEST_CONSTEXPR_CXX20 void test(S s1, typename S::value_type s2) { assert(s1.size() == 1); assert(T::eq(s1[0], s2)); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); } template @@ -38,6 +40,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp index 3afe76e88316f99cf9a6ff6d3a98a23f1bcdc7d1..f65f8e97c98249c74053179db722c490e99e58b4 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s1) { @@ -24,6 +25,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1) { assert(s2 == s1); assert(s2.capacity() >= s2.size()); assert(s2.get_allocator() == s1.get_allocator()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -40,6 +43,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(test_allocator(3)); #if TEST_STD_VER >= 11 test_string(min_allocator()); + test_string(safe_allocator()); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp index 6b0040376a424ec1afd709707f82e8d831c2798a..b0045cb4afbba585274006712371632e260aea90 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" #ifndef TEST_HAS_NO_EXCEPTIONS struct alloc_imp { @@ -83,6 +84,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1, const typename S::allocator_type& a) { assert(s2 == s1); assert(s2.capacity() >= s2.size()); assert(s2.get_allocator() == a); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -99,6 +102,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(test_allocator(3)); #if TEST_STD_VER >= 11 test_string(min_allocator()); + test_string(safe_allocator()); #endif #if TEST_STD_VER >= 11 diff --git a/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp index eb522aafa243024ba51ab74f6ac204d4ca3329d4..2e98fccb5394bba6c34b2d9c5b903eb6fad5147c 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S s1, const S& s2) { @@ -23,6 +24,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1, const S& s2) { LIBCPP_ASSERT(s1.__invariants()); assert(s1 == s2); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -47,6 +50,7 @@ TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif #if TEST_STD_VER >= 11 diff --git a/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp index 3993a40dd5a165c24c7cd654571bb34273088991..fc263f9820cb5b79f14d2c201a3d7d38fc5400d7 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "test_allocator.h" +#include "asan_testing.h" #if TEST_STD_VER >= 11 // Test the noexcept specification, which is a conforming extension @@ -30,6 +31,7 @@ LIBCPP_STATIC_ASSERT(!std::is_nothrow_default_constructible< TEST_CONSTEXPR_CXX20 bool test() { std::string str; assert(str.empty()); + LIBCPP_ASSERT(is_string_asan_correct(str)); return true; } diff --git a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp index 3ae5b74a3504a04120744cda413fc2231f4d3195..7f33237de4631da4c9b92df152460cec5ab15db3 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp @@ -19,6 +19,7 @@ #include "../../../containers/from_range_helpers.h" #include "../../../containers/sequences/from_range_sequence_containers.h" #include "test_macros.h" +#include "asan_testing.h" template concept StringHasFromRangeAllocCtr = @@ -70,6 +71,7 @@ constexpr void test_with_input(std::vector input) { LIBCPP_ASSERT(c.__invariants()); assert(c.size() == static_cast(std::distance(c.begin(), c.end()))); assert(std::ranges::equal(in, c)); + LIBCPP_ASSERT(is_string_asan_correct(c)); } { // (range, allocator) @@ -80,6 +82,7 @@ constexpr void test_with_input(std::vector input) { assert(c.get_allocator() == alloc); assert(c.size() == static_cast(std::distance(c.begin(), c.end()))); assert(std::ranges::equal(in, c)); + LIBCPP_ASSERT(is_string_asan_correct(c)); } } diff --git a/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp index b2dab03506f03a46cef6a5929ade9402b0f184d7..83c3dfdfa79dded9958390709d019b338f67e1db 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp @@ -26,6 +26,7 @@ #include "deduction_guides_sfinae_checks.h" #include "test_allocator.h" +#include "asan_testing.h" int main(int, char**) { using Char = char16_t; @@ -33,12 +34,14 @@ int main(int, char**) { { std::basic_string c(std::from_range, std::array()); static_assert(std::is_same_v>); + LIBCPP_ASSERT(is_string_asan_correct(c)); } { using Alloc = test_allocator; std::basic_string c(std::from_range, std::array(), Alloc()); static_assert(std::is_same_v, Alloc>>); + LIBCPP_ASSERT(is_string_asan_correct(c)); } // Note: defining `value_type` is a workaround because one of the deduction guides will end up instantiating diff --git a/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp index 5b7e8bde2e6e877ee13b155e7beeda6bd23286e5..ebdcc523f055d4ab40177b94eb74de1f3e024631 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" // clang-format off template