diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 81e9246de9b58..78a9cb77ff7d9 100755 --- a/.ci/generate-buildkite-pipeline-premerge +++ b/.ci/generate-buildkite-pipeline-premerge @@ -91,7 +91,7 @@ function add-dependencies() { echo "${project}" case ${project} in bolt) - for p in lld llvm; do + for p in clang lld llvm; do echo $p done ;; diff --git a/.ci/monolithic-linux.sh b/.ci/monolithic-linux.sh index b347c443da677..b00a4b984a1d2 100755 --- a/.ci/monolithic-linux.sh +++ b/.ci/monolithic-linux.sh @@ -48,7 +48,6 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D LLVM_LIT_ARGS="-v --xunit-xml-output ${BUILD_DIR}/test-results.xml --timeout=1200 --time-tests" \ -D LLVM_ENABLE_LLD=ON \ -D CMAKE_CXX_FLAGS=-gmlt \ - -D BOLT_CLANG_EXE=/usr/bin/clang \ -D LLVM_CCACHE_BUILD=ON \ -D MLIR_ENABLE_BINDINGS_PYTHON=ON diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 9cf64417d3cb2..d608ea449f1d4 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -1,3 +1,6 @@ +BOLT: + - bolt/**/* + ClangIR: - clang/include/clang/CIR/**/* - clang/lib/CIR/**/* @@ -467,6 +470,7 @@ backend:m68k: libc++: - libcxx/** + - .github/workflows/libcxx-* libc++abi: - libcxxabi/** diff --git a/bolt/include/bolt/Passes/BinaryPasses.h b/bolt/include/bolt/Passes/BinaryPasses.h index 8d89ef8b5484f..5d7692559eda8 100644 --- a/bolt/include/bolt/Passes/BinaryPasses.h +++ b/bolt/include/bolt/Passes/BinaryPasses.h @@ -400,8 +400,7 @@ class PrintProfileStats : public BinaryFunctionPass { /// dyno stats categories. class PrintProgramStats : public BinaryFunctionPass { public: - explicit PrintProgramStats(const cl::opt &PrintPass) - : BinaryFunctionPass(PrintPass) {} + explicit PrintProgramStats() : BinaryFunctionPass(false) {} const char *getName() const override { return "print-stats"; } bool shouldPrint(const BinaryFunction &) const override { return false; } diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index af832b4c7c84c..41a92e7ba01e8 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -422,10 +422,18 @@ class RewriteInstance { /// Section name used for extra BOLT code in addition to .text. static StringRef getBOLTTextSectionName() { return ".bolt.text"; } + /// Symbol markers for BOLT reserved area. + static StringRef getBOLTReservedStart() { return "__bolt_reserved_start"; } + static StringRef getBOLTReservedEnd() { return "__bolt_reserved_end"; } + /// Common section names. static StringRef getEHFrameSectionName() { return ".eh_frame"; } + static StringRef getEHFrameHdrSectionName() { return ".eh_frame_hdr"; } static StringRef getRelaDynSectionName() { return ".rela.dyn"; } + /// FILE symbol name used for local fragments of global functions. + static StringRef getBOLTFileSymbolName() { return "bolt-pseudo.o"; } + /// An instance of the input binary we are processing, externally owned. llvm::object::ELFObjectFileBase *InputFile; @@ -490,6 +498,9 @@ class RewriteInstance { /// Store all non-zero symbols in this map for a quick address lookup. std::map FileSymRefs; + /// FILE symbols used for disambiguating split function parents. + std::vector FileSymbols; + std::unique_ptr DebugInfoRewriter; std::unique_ptr BAT; diff --git a/bolt/include/bolt/Utils/NameResolver.h b/bolt/include/bolt/Utils/NameResolver.h index 2e3ac20a532d7..ccffa5633245c 100644 --- a/bolt/include/bolt/Utils/NameResolver.h +++ b/bolt/include/bolt/Utils/NameResolver.h @@ -28,10 +28,23 @@ class NameResolver { static constexpr char Sep = '/'; public: - /// Return unique version of the \p Name in the form "Name". + /// Return the number of uniquified versions of a given \p Name. + uint64_t getUniquifiedNameCount(StringRef Name) const { + if (Counters.contains(Name)) + return Counters.at(Name); + return 0; + } + + /// Return unique version of the \p Name in the form "Name". + std::string getUniqueName(StringRef Name, const uint64_t ID) const { + return (Name + Twine(Sep) + Twine(ID)).str(); + } + + /// Register new version of \p Name and return unique version in the form + /// "Name". std::string uniquify(StringRef Name) { const uint64_t ID = ++Counters[Name]; - return (Name + Twine(Sep) + Twine(ID)).str(); + return getUniqueName(Name, ID); } /// For uniquified \p Name, return the original form (that may no longer be diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 0b2a4e86561f3..70e324cc0165b 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -14,6 +14,7 @@ #include "bolt/Profile/DataAggregator.h" #include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryFunction.h" +#include "bolt/Passes/BinaryPasses.h" #include "bolt/Profile/BoltAddressTranslation.h" #include "bolt/Profile/Heatmap.h" #include "bolt/Profile/YAMLProfileWriter.h" @@ -611,6 +612,7 @@ Error DataAggregator::readProfile(BinaryContext &BC) { if (std::error_code EC = writeBATYAML(BC, opts::SaveProfile)) report_error("cannot create output data file", EC); } + BC.logBOLTErrorsAndQuitOnFatal(PrintProgramStats().runOnFunctions(BC)); } return Error::success(); diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp index be4888ccfa564..cbb7199a53ddd 100644 --- a/bolt/lib/Rewrite/BinaryPassManager.cpp +++ b/bolt/lib/Rewrite/BinaryPassManager.cpp @@ -356,7 +356,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { // order they're registered. // Run this pass first to use stats for the original functions. - Manager.registerPass(std::make_unique(NeverPrint)); + Manager.registerPass(std::make_unique()); if (opts::PrintProfileStats) Manager.registerPass(std::make_unique(NeverPrint)); diff --git a/bolt/lib/Rewrite/BoltDiff.cpp b/bolt/lib/Rewrite/BoltDiff.cpp index fa43b7a2f92c2..74b5ca18abce4 100644 --- a/bolt/lib/Rewrite/BoltDiff.cpp +++ b/bolt/lib/Rewrite/BoltDiff.cpp @@ -292,7 +292,7 @@ class RewriteInstanceDiff { } } } - PrintProgramStats PPS(opts::NeverPrint); + PrintProgramStats PPS; outs() << "* BOLT-DIFF: Starting print program stats pass for binary 1\n"; RI1.BC->logBOLTErrorsAndQuitOnFatal(PPS.runOnFunctions(*RI1.BC)); outs() << "* BOLT-DIFF: Starting print program stats pass for binary 2\n"; diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index d96199e020d31..17077b4fa2487 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -248,6 +248,9 @@ class LinuxKernelRewriter final : public MetadataRewriter { /// Update ORC data in the binary. Error rewriteORCTables(); + /// Validate written ORC tables after binary emission. + Error validateORCTables(); + /// Static call table handling. Error readStaticCalls(); Error rewriteStaticCalls(); @@ -358,6 +361,9 @@ class LinuxKernelRewriter final : public MetadataRewriter { if (Error E = updateStaticKeysJumpTablePostEmit()) return E; + if (Error E = validateORCTables()) + return E; + return Error::success(); } }; @@ -837,6 +843,32 @@ Error LinuxKernelRewriter::rewriteORCTables() { return Error::success(); } +Error LinuxKernelRewriter::validateORCTables() { + if (!ORCUnwindIPSection) + return Error::success(); + + const uint64_t IPSectionAddress = ORCUnwindIPSection->getAddress(); + DataExtractor IPDE = DataExtractor(ORCUnwindIPSection->getOutputContents(), + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + DataExtractor::Cursor IPCursor(0); + uint64_t PrevIP = 0; + for (uint32_t Index = 0; Index < NumORCEntries; ++Index) { + const uint64_t IP = + IPSectionAddress + IPCursor.tell() + (int32_t)IPDE.getU32(IPCursor); + if (!IPCursor) + return createStringError(errc::executable_format_error, + "out of bounds while reading ORC IP table: %s", + toString(IPCursor.takeError()).c_str()); + + assert(IP >= PrevIP && "Unsorted ORC table detected"); + (void)PrevIP; + PrevIP = IP; + } + + return Error::success(); +} + /// The static call site table is created by objtool and contains entries in the /// following format: /// diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 4e0096cf988ae..23f79e3c135a7 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -840,6 +840,7 @@ void RewriteInstance::discoverFileObjects() { continue; if (cantFail(Symbol.getType()) == SymbolRef::ST_File) { + FileSymbols.emplace_back(Symbol); StringRef Name = cantFail(std::move(NameOrError), "cannot get symbol name for file"); // Ignore Clang LTO artificial FILE symbol as it is not always generated, @@ -1062,6 +1063,11 @@ void RewriteInstance::discoverFileObjects() { continue; } + if (SymName == getBOLTReservedStart() || SymName == getBOLTReservedEnd()) { + registerName(SymbolSize); + continue; + } + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: considering symbol " << UniqueName << " for function\n"); @@ -1340,6 +1346,7 @@ void RewriteInstance::discoverFileObjects() { } registerFragments(); + FileSymbols.clear(); } Error RewriteInstance::discoverRtFiniAddress() { @@ -1417,50 +1424,134 @@ void RewriteInstance::registerFragments() { if (!BC->HasSplitFunctions) return; + // Process fragments with ambiguous parents separately as they are typically a + // vanishing minority of cases and require expensive symbol table lookups. + std::vector> AmbiguousFragments; for (auto &BFI : BC->getBinaryFunctions()) { BinaryFunction &Function = BFI.second; if (!Function.isFragment()) continue; - unsigned ParentsFound = 0; for (StringRef Name : Function.getNames()) { - StringRef BaseName, Suffix; - std::tie(BaseName, Suffix) = Name.split('/'); + StringRef BaseName = NR.restore(Name); + const bool IsGlobal = BaseName == Name; const size_t ColdSuffixPos = BaseName.find(".cold"); if (ColdSuffixPos == StringRef::npos) continue; - // For cold function with local (foo.cold/1) symbol, prefer a parent with - // local symbol as well (foo/1) over global symbol (foo). - std::string ParentName = BaseName.substr(0, ColdSuffixPos).str(); + StringRef ParentName = BaseName.substr(0, ColdSuffixPos); const BinaryData *BD = BC->getBinaryDataByName(ParentName); - if (Suffix != "") { - ParentName.append(Twine("/", Suffix).str()); - const BinaryData *BDLocal = BC->getBinaryDataByName(ParentName); - if (BDLocal || !BD) - BD = BDLocal; - } - if (!BD) { - if (opts::Verbosity >= 1) - BC->outs() << "BOLT-INFO: parent function not found for " << Name - << "\n"; + const uint64_t NumPossibleLocalParents = + NR.getUniquifiedNameCount(ParentName); + // The most common case: single local parent fragment. + if (!BD && NumPossibleLocalParents == 1) { + BD = BC->getBinaryDataByName(NR.getUniqueName(ParentName, 1)); + } else if (BD && (!NumPossibleLocalParents || IsGlobal)) { + // Global parent and either no local candidates (second most common), or + // the fragment is global as well (uncommon). + } else { + // Any other case: need to disambiguate using FILE symbols. + AmbiguousFragments.emplace_back(ParentName, &Function); continue; } - const uint64_t Address = BD->getAddress(); - BinaryFunction *BF = BC->getBinaryFunctionAtAddress(Address); - if (!BF) { - if (opts::Verbosity >= 1) - BC->outs() << formatv( - "BOLT-INFO: parent function not found at {0:x}\n", Address); - continue; + if (BD) { + BinaryFunction *BF = BC->getFunctionForSymbol(BD->getSymbol()); + if (BF) { + BC->registerFragment(Function, *BF); + continue; + } } - BC->registerFragment(Function, *BF); - ++ParentsFound; - } - if (!ParentsFound) { BC->errs() << "BOLT-ERROR: parent function not found for " << Function << '\n'; exit(1); } } + + if (AmbiguousFragments.empty()) + return; + + if (!BC->hasSymbolsWithFileName()) { + BC->errs() << "BOLT-ERROR: input file has split functions but does not " + "have FILE symbols. If the binary was stripped, preserve " + "FILE symbols with --keep-file-symbols strip option"; + exit(1); + } + + // The first global symbol is identified by the symbol table sh_info value. + // Used as local symbol search stopping point. + auto *ELF64LEFile = cast(InputFile); + const ELFFile &Obj = ELF64LEFile->getELFFile(); + auto *SymTab = llvm::find_if(cantFail(Obj.sections()), [](const auto &Sec) { + return Sec.sh_type == ELF::SHT_SYMTAB; + }); + assert(SymTab); + // Symtab sh_info contains the value one greater than the symbol table index + // of the last local symbol. + ELFSymbolRef LocalSymEnd = ELF64LEFile->toSymbolRef(SymTab, SymTab->sh_info); + + for (auto &[ParentName, BF] : AmbiguousFragments) { + const uint64_t Address = BF->getAddress(); + + // Get fragment's own symbol + const auto SymIt = FileSymRefs.find(Address); + if (SymIt == FileSymRefs.end()) { + BC->errs() + << "BOLT-ERROR: symbol lookup failed for function at address 0x" + << Twine::utohexstr(Address) << '\n'; + exit(1); + } + + // Find containing FILE symbol + ELFSymbolRef Symbol = SymIt->second; + auto FSI = llvm::upper_bound(FileSymbols, Symbol); + if (FSI == FileSymbols.begin()) { + BC->errs() << "BOLT-ERROR: owning FILE symbol not found for symbol " + << cantFail(Symbol.getName()) << '\n'; + exit(1); + } + + ELFSymbolRef StopSymbol = LocalSymEnd; + if (FSI != FileSymbols.end()) + StopSymbol = *FSI; + + uint64_t ParentAddress{0}; + + // BOLT split fragment symbols are emitted just before the main function + // symbol. + for (ELFSymbolRef NextSymbol = Symbol; NextSymbol < StopSymbol; + NextSymbol.moveNext()) { + StringRef Name = cantFail(NextSymbol.getName()); + if (Name == ParentName) { + ParentAddress = cantFail(NextSymbol.getValue()); + goto registerParent; + } + if (Name.starts_with(ParentName)) + // With multi-way splitting, there are multiple fragments with different + // suffixes. Parent follows the last fragment. + continue; + break; + } + + // Iterate over local file symbols and check symbol names to match parent. + for (ELFSymbolRef Symbol(FSI[-1]); Symbol < StopSymbol; Symbol.moveNext()) { + if (cantFail(Symbol.getName()) == ParentName) { + ParentAddress = cantFail(Symbol.getAddress()); + break; + } + } + +registerParent: + // No local parent is found, use global parent function. + if (!ParentAddress) + if (BinaryData *ParentBD = BC->getBinaryDataByName(ParentName)) + ParentAddress = ParentBD->getAddress(); + + if (BinaryFunction *ParentBF = + BC->getBinaryFunctionAtAddress(ParentAddress)) { + BC->registerFragment(*BF, *ParentBF); + continue; + } + BC->errs() << "BOLT-ERROR: parent function not found for " << *BF << '\n'; + exit(1); + } } void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress, @@ -1725,12 +1816,6 @@ void RewriteInstance::adjustFunctionBoundaries() { if (!Function.isSymbolValidInScope(Symbol, SymbolSize)) break; - // Ignore unnamed symbols. Used, for example, by debugging info on RISC-V. - if (BC->isRISCV() && cantFail(Symbol.getName()).empty()) { - ++NextSymRefI; - continue; - } - // Skip basic block labels. This happens on RISC-V with linker relaxation // enabled because every branch needs a relocation and corresponding // symbol. We don't want to add such symbols as entry points. @@ -3532,6 +3617,26 @@ void RewriteInstance::updateMetadata() { void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) { BC->deregisterUnusedSections(); + // Check if the input has a space reserved for BOLT. + BinaryData *StartBD = BC->getBinaryDataByName(getBOLTReservedStart()); + BinaryData *EndBD = BC->getBinaryDataByName(getBOLTReservedEnd()); + if (!StartBD != !EndBD) { + BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: " + << getBOLTReservedStart() << ", " << getBOLTReservedEnd() + << '\n'; + exit(1); + } + + if (StartBD) { + PHDRTableOffset = 0; + PHDRTableAddress = 0; + NewTextSegmentAddress = 0; + NewTextSegmentOffset = 0; + NextAvailableAddress = StartBD->getAddress(); + BC->outs() + << "BOLT-INFO: using reserved space for allocating new sections\n"; + } + // If no new .eh_frame was written, remove relocated original .eh_frame. BinarySection *RelocatedEHFrameSection = getSection(".relocated" + getEHFrameSectionName()); @@ -3551,6 +3656,18 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) { // Map the rest of the sections. mapAllocatableSections(MapSection); + + if (StartBD) { + const uint64_t ReservedSpace = EndBD->getAddress() - StartBD->getAddress(); + const uint64_t AllocatedSize = NextAvailableAddress - StartBD->getAddress(); + if (ReservedSpace < AllocatedSize) { + BC->errs() << "BOLT-ERROR: reserved space (" << ReservedSpace << " byte" + << (ReservedSpace == 1 ? "" : "s") + << ") is smaller than required for new allocations (" + << AllocatedSize << " bytes)\n"; + exit(1); + } + } } std::vector RewriteInstance::getCodeSections() { @@ -3792,7 +3909,7 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) { // Add the new text section aggregating all existing code sections. // This is pseudo-section that serves a purpose of creating a corresponding // entry in section header table. - int64_t NewTextSectionSize = + const uint64_t NewTextSectionSize = NextAvailableAddress - NewTextSectionStartAddress; if (NewTextSectionSize) { const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, @@ -3875,7 +3992,7 @@ void RewriteInstance::mapAllocatableSections( if (PHDRTableAddress) { // Segment size includes the size of the PHDR area. NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress; - } else { + } else if (NewTextSegmentAddress) { // Existing PHDR table would be updated. NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress; } @@ -3914,7 +4031,7 @@ void RewriteInstance::patchELFPHDRTable() { assert(!PHDRTableAddress && "unexpected address for program header table"); PHDRTableOffset = Obj.getHeader().e_phoff; if (NewWritableSegmentSize) { - BC->errs() << "Unable to add writable segment with UseGnuStack option\n"; + BC->errs() << "BOLT-ERROR: unable to add writable segment\n"; exit(1); } } @@ -3924,19 +4041,15 @@ void RewriteInstance::patchELFPHDRTable() { if (!NewWritableSegmentSize) { if (PHDRTableAddress) NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress; - else + else if (NewTextSegmentAddress) NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress; } else { NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress; } + const uint64_t SavedPos = OS.tell(); OS.seek(PHDRTableOffset); - bool ModdedGnuStack = false; - (void)ModdedGnuStack; - bool AddedSegment = false; - (void)AddedSegment; - auto createNewTextPhdr = [&]() { ELF64LEPhdrTy NewPhdr; NewPhdr.p_type = ELF::PT_LOAD; @@ -3952,40 +4065,55 @@ void RewriteInstance::patchELFPHDRTable() { NewPhdr.p_filesz = NewTextSegmentSize; NewPhdr.p_memsz = NewTextSegmentSize; NewPhdr.p_flags = ELF::PF_X | ELF::PF_R; - // FIXME: Currently instrumentation is experimental and the runtime data - // is emitted with code, thus everything needs to be writable - if (opts::Instrument) + if (opts::Instrument) { + // FIXME: Currently instrumentation is experimental and the runtime data + // is emitted with code, thus everything needs to be writable. NewPhdr.p_flags |= ELF::PF_W; + } NewPhdr.p_align = BC->PageAlign; return NewPhdr; }; - auto createNewWritableSectionsPhdr = [&]() { - ELF64LEPhdrTy NewPhdr; - NewPhdr.p_type = ELF::PT_LOAD; - NewPhdr.p_offset = getFileOffsetForAddress(NewWritableSegmentAddress); - NewPhdr.p_vaddr = NewWritableSegmentAddress; - NewPhdr.p_paddr = NewWritableSegmentAddress; - NewPhdr.p_filesz = NewWritableSegmentSize; - NewPhdr.p_memsz = NewWritableSegmentSize; - NewPhdr.p_align = BC->RegularPageSize; - NewPhdr.p_flags = ELF::PF_R | ELF::PF_W; - return NewPhdr; + auto writeNewSegmentPhdrs = [&]() { + if (PHDRTableAddress || NewTextSegmentSize) { + ELF64LE::Phdr NewPhdr = createNewTextPhdr(); + OS.write(reinterpret_cast(&NewPhdr), sizeof(NewPhdr)); + } + + if (NewWritableSegmentSize) { + ELF64LEPhdrTy NewPhdr; + NewPhdr.p_type = ELF::PT_LOAD; + NewPhdr.p_offset = getFileOffsetForAddress(NewWritableSegmentAddress); + NewPhdr.p_vaddr = NewWritableSegmentAddress; + NewPhdr.p_paddr = NewWritableSegmentAddress; + NewPhdr.p_filesz = NewWritableSegmentSize; + NewPhdr.p_memsz = NewWritableSegmentSize; + NewPhdr.p_align = BC->RegularPageSize; + NewPhdr.p_flags = ELF::PF_R | ELF::PF_W; + OS.write(reinterpret_cast(&NewPhdr), sizeof(NewPhdr)); + } }; + bool ModdedGnuStack = false; + bool AddedSegment = false; + // Copy existing program headers with modifications. for (const ELF64LE::Phdr &Phdr : cantFail(Obj.program_headers())) { ELF64LE::Phdr NewPhdr = Phdr; - if (PHDRTableAddress && Phdr.p_type == ELF::PT_PHDR) { - NewPhdr.p_offset = PHDRTableOffset; - NewPhdr.p_vaddr = PHDRTableAddress; - NewPhdr.p_paddr = PHDRTableAddress; - NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum; - NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum; - } else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { - ErrorOr EHFrameHdrSec = - BC->getUniqueSectionByName(getNewSecPrefix() + ".eh_frame_hdr"); + switch (Phdr.p_type) { + case ELF::PT_PHDR: + if (PHDRTableAddress) { + NewPhdr.p_offset = PHDRTableOffset; + NewPhdr.p_vaddr = PHDRTableAddress; + NewPhdr.p_paddr = PHDRTableAddress; + NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum; + NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum; + } + break; + case ELF::PT_GNU_EH_FRAME: { + ErrorOr EHFrameHdrSec = BC->getUniqueSectionByName( + getNewSecPrefix() + getEHFrameHdrSectionName()); if (EHFrameHdrSec && EHFrameHdrSec->isAllocatable() && EHFrameHdrSec->isFinalized()) { NewPhdr.p_offset = EHFrameHdrSec->getOutputFileOffset(); @@ -3994,37 +4122,38 @@ void RewriteInstance::patchELFPHDRTable() { NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize(); NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize(); } - } else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) { - NewPhdr = createNewTextPhdr(); - ModdedGnuStack = true; - } else if (!opts::UseGnuStack && Phdr.p_type == ELF::PT_DYNAMIC) { - // Insert the new header before DYNAMIC. - ELF64LE::Phdr NewTextPhdr = createNewTextPhdr(); - OS.write(reinterpret_cast(&NewTextPhdr), - sizeof(NewTextPhdr)); - if (NewWritableSegmentSize) { - ELF64LEPhdrTy NewWritablePhdr = createNewWritableSectionsPhdr(); - OS.write(reinterpret_cast(&NewWritablePhdr), - sizeof(NewWritablePhdr)); + break; + } + case ELF::PT_GNU_STACK: + if (opts::UseGnuStack) { + // Overwrite the header with the new text segment header. + NewPhdr = createNewTextPhdr(); + ModdedGnuStack = true; } - AddedSegment = true; + break; + case ELF::PT_DYNAMIC: + if (!opts::UseGnuStack) { + // Insert new headers before DYNAMIC. + writeNewSegmentPhdrs(); + AddedSegment = true; + } + break; } OS.write(reinterpret_cast(&NewPhdr), sizeof(NewPhdr)); } if (!opts::UseGnuStack && !AddedSegment) { - // Append the new header to the end of the table. - ELF64LE::Phdr NewTextPhdr = createNewTextPhdr(); - OS.write(reinterpret_cast(&NewTextPhdr), sizeof(NewTextPhdr)); - if (NewWritableSegmentSize) { - ELF64LEPhdrTy NewWritablePhdr = createNewWritableSectionsPhdr(); - OS.write(reinterpret_cast(&NewWritablePhdr), - sizeof(NewWritablePhdr)); - } + // Append new headers to the end of the table. + writeNewSegmentPhdrs(); + } + + if (opts::UseGnuStack && !ModdedGnuStack) { + BC->errs() + << "BOLT-ERROR: could not find PT_GNU_STACK program header to modify\n"; + exit(1); } - assert((!opts::UseGnuStack || ModdedGnuStack) && - "could not find GNU_STACK program header to modify"); + OS.seek(SavedPos); } namespace { @@ -4050,9 +4179,8 @@ void RewriteInstance::rewriteNoteSections() { const ELFFile &Obj = ELF64LEFile->getELFFile(); raw_fd_ostream &OS = Out->os(); - uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress); - assert(NextAvailableOffset >= FirstNonAllocatableOffset && - "next available offset calculation failure"); + uint64_t NextAvailableOffset = std::max( + getFileOffsetForAddress(NextAvailableAddress), FirstNonAllocatableOffset); OS.seek(NextAvailableOffset); // Copy over non-allocatable section contents and update file offsets. @@ -4493,6 +4621,8 @@ void RewriteInstance::updateELFSymbolTable( // Symbols for the new symbol table. std::vector Symbols; + bool EmittedColdFileSymbol = false; + auto getNewSectionIndex = [&](uint32_t OldIndex) { // For dynamic symbol table, the section index could be wrong on the input, // and its value is ignored by the runtime if it's different from @@ -4551,6 +4681,20 @@ void RewriteInstance::updateELFSymbolTable( Symbols.emplace_back(ICFSymbol); } if (Function.isSplit()) { + // Prepend synthetic FILE symbol to prevent local cold fragments from + // colliding with existing symbols with the same name. + if (!EmittedColdFileSymbol && + FunctionSymbol.getBinding() == ELF::STB_GLOBAL) { + ELFSymTy FileSymbol; + FileSymbol.st_shndx = ELF::SHN_ABS; + FileSymbol.st_name = AddToStrTab(getBOLTFileSymbolName()); + FileSymbol.st_value = 0; + FileSymbol.st_size = 0; + FileSymbol.st_other = 0; + FileSymbol.setBindingAndType(ELF::STB_LOCAL, ELF::STT_FILE); + Symbols.emplace_back(FileSymbol); + EmittedColdFileSymbol = true; + } for (const FunctionFragment &FF : Function.getLayout().getSplitFragments()) { if (FF.getAddress()) { @@ -4775,7 +4919,7 @@ void RewriteInstance::updateELFSymbolTable( ++NumHotDataSymsUpdated; } - if (*SymbolName == "_end") + if (*SymbolName == "_end" && NextAvailableAddress > Symbol.st_value) updateSymbolValue(*SymbolName, NextAvailableAddress); if (IsDynSym) @@ -4889,13 +5033,6 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile *File) { std::vector NewSectionIndex; getOutputSections(File, NewSectionIndex); - // Set pointer at the end of the output file, so we can pwrite old symbol - // tables if we need to. - uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress); - assert(NextAvailableOffset >= FirstNonAllocatableOffset && - "next available offset calculation failure"); - Out->os().seek(NextAvailableOffset); - // Update dynamic symbol table. const ELFShdrTy *DynSymSection = nullptr; for (const ELFShdrTy &Section : cantFail(Obj.sections())) { @@ -5432,6 +5569,17 @@ uint64_t RewriteInstance::getNewFunctionOrDataAddress(uint64_t OldAddress) { if (BD && BD->isMoved()) return BD->getOutputAddress(); + if (const BinaryFunction *BF = + BC->getBinaryFunctionContainingAddress(OldAddress)) { + if (BF->isEmitted()) { + BC->errs() << "BOLT-ERROR: unable to get new address corresponding to " + "input address 0x" + << Twine::utohexstr(OldAddress) << " in function " << *BF + << ". Consider adding this function to --skip-funcs=...\n"; + exit(1); + } + } + return 0; } @@ -5449,10 +5597,10 @@ void RewriteInstance::rewriteFile() { auto Streamer = BC->createStreamer(OS); // Make sure output stream has enough reserved space, otherwise // pwrite() will fail. - uint64_t Offset = OS.seek(getFileOffsetForAddress(NextAvailableAddress)); - (void)Offset; - assert(Offset == getFileOffsetForAddress(NextAvailableAddress) && - "error resizing output file"); + uint64_t Offset = std::max(getFileOffsetForAddress(NextAvailableAddress), + FirstNonAllocatableOffset); + Offset = OS.seek(Offset); + assert((Offset != (uint64_t)-1) && "Error resizing output file"); // Overwrite functions with fixed output address. This is mostly used by // non-relocation mode, with one exception: injected functions are covered @@ -5671,7 +5819,8 @@ void RewriteInstance::writeEHFrameHeader() { BC->AsmInfo->getCodePointerSize())); check_error(std::move(Er), "failed to parse EH frame"); - LLVM_DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n"); + LLVM_DEBUG(dbgs() << "BOLT: writing a new " << getEHFrameHdrSectionName() + << '\n'); NextAvailableAddress = appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign); @@ -5683,25 +5832,35 @@ void RewriteInstance::writeEHFrameHeader() { std::vector NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader( RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress, FailedAddresses); - assert(Out->os().tell() == EHFrameHdrFileOffset && "offset mismatch"); + Out->os().seek(EHFrameHdrFileOffset); Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size()); const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, /*IsText=*/false, /*IsAllocatable=*/true); - BinarySection *OldEHFrameHdrSection = getSection(".eh_frame_hdr"); + BinarySection *OldEHFrameHdrSection = getSection(getEHFrameHdrSectionName()); if (OldEHFrameHdrSection) - OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() + ".eh_frame_hdr"); + OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() + + getEHFrameHdrSectionName()); BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection( - getNewSecPrefix() + ".eh_frame_hdr", ELF::SHT_PROGBITS, Flags, nullptr, - NewEHFrameHdr.size(), /*Alignment=*/1); + getNewSecPrefix() + getEHFrameHdrSectionName(), ELF::SHT_PROGBITS, Flags, + nullptr, NewEHFrameHdr.size(), /*Alignment=*/1); EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset); EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress); - EHFrameHdrSec.setOutputName(".eh_frame_hdr"); + EHFrameHdrSec.setOutputName(getEHFrameHdrSectionName()); NextAvailableAddress += EHFrameHdrSec.getOutputSize(); + if (const BinaryData *ReservedEnd = + BC->getBinaryDataByName(getBOLTReservedEnd())) { + if (NextAvailableAddress > ReservedEnd->getAddress()) { + BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName() + << " into reserved space\n"; + exit(1); + } + } + // Merge new .eh_frame with the relocated original so that gdb can locate all // FDEs. if (RelocatedEHFrameSection) { diff --git a/bolt/test/RISCV/unnamed-sym-no-entry.c b/bolt/test/RISCV/fake-label-no-entry.c similarity index 85% rename from bolt/test/RISCV/unnamed-sym-no-entry.c rename to bolt/test/RISCV/fake-label-no-entry.c index 605bbc00aeec4..bd125263101bb 100644 --- a/bolt/test/RISCV/unnamed-sym-no-entry.c +++ b/bolt/test/RISCV/fake-label-no-entry.c @@ -5,12 +5,12 @@ // RUN: %clang %cflags -g -Wl,-q -o %t %s -/// Verify that the binary indeed contains an unnamed symbol at _start +/// Verify that the binary indeed contains a fake label ".L0 " at _start. // RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=CHECK-ELF // CHECK-ELF-DAG: [[#%x,START:]] {{.*}} FUNC GLOBAL DEFAULT [[#%d,SECTION:]] _start{{$}} -// CHECK-ELF-DAG: [[#%x,START]] {{.*}} NOTYPE LOCAL DEFAULT [[#SECTION]] {{$}} +// CHECK-ELF-DAG: [[#%x,START]] {{.*}} NOTYPE LOCAL DEFAULT [[#SECTION]] .L0 {{$}} -/// Verify that BOLT did not create an extra entry point for the unnamed symbol +/// Verify that BOLT did not create an extra entry point for the fake label. // RUN: llvm-bolt -o %t.bolt %t --print-cfg | FileCheck %s // CHECK: Binary Function "_start" after building cfg { // CHECK: IsMultiEntry: 0 diff --git a/bolt/test/X86/cdsplit-symbol-names.s b/bolt/test/X86/cdsplit-symbol-names.s index e2259276e2554..e53863e22246d 100644 --- a/bolt/test/X86/cdsplit-symbol-names.s +++ b/bolt/test/X86/cdsplit-symbol-names.s @@ -10,6 +10,7 @@ # RUN: --call-scale=2 --data=%t.fdata --reorder-blocks=ext-tsp # RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS-WARM +# CHECK-SYMS-WARM: 0000000000000000 l df *ABS* 0000000000000000 bolt-pseudo.o # CHECK-SYMS-WARM: .text.warm # CHECK-SYMS-WARM-SAME: chain.warm # CHECK-SYMS-WARM: .text.cold diff --git a/bolt/test/X86/fragment-lite.s b/bolt/test/X86/fragment-lite.s index 97069bf8096e1..32d1f5a98b64a 100644 --- a/bolt/test/X86/fragment-lite.s +++ b/bolt/test/X86/fragment-lite.s @@ -3,35 +3,42 @@ # RUN: split-file %s %t # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz.s -o %t.baz.o +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz2.s -o %t.baz2.o # RUN: link_fdata %s %t.o %t.main.fdata # RUN: link_fdata %s %t.baz.o %t.baz.fdata -# RUN: merge-fdata %t.main.fdata %t.baz.fdata > %t.fdata -# RUN: %clang %cflags %t.o %t.baz.o -o %t.exe -Wl,-q +# RUN: link_fdata %s %t.baz2.o %t.baz2.fdata +# RUN: merge-fdata %t.main.fdata %t.baz.fdata %t.baz2.fdata > %t.fdata +# RUN: %clang %cflags %t.o %t.baz.o %t.baz2.o -o %t.exe -Wl,-q # RUN: llvm-bolt %t.exe -o %t.out --lite=1 --data %t.fdata -v=1 -print-cfg \ # RUN: 2>&1 | FileCheck %s # CHECK: BOLT-INFO: processing main.cold.1 as a sibling of non-ignored function -# CHECK: BOLT-INFO: processing foo.cold.1/1 as a sibling of non-ignored function -# CHECK: BOLT-INFO: processing bar.cold.1/1 as a sibling of non-ignored function +# CHECK: BOLT-INFO: processing foo.cold.1/1(*2) as a sibling of non-ignored function +# CHECK: BOLT-INFO: processing bar.cold.1/1(*2) as a sibling of non-ignored function # CHECK: BOLT-INFO: processing baz.cold.1 as a sibling of non-ignored function -# CHECK: BOLT-INFO: processing baz.cold.1/1 as a sibling of non-ignored function +# CHECK: BOLT-INFO: processing baz.cold.1/1(*2) as a sibling of non-ignored function +# CHECK: BOLT-INFO: processing baz.cold.1/2(*2) as a sibling of non-ignored function # CHECK: Binary Function "main.cold.1" after building cfg # CHECK: Parent : main -# CHECK: Binary Function "foo.cold.1/1" after building cfg +# CHECK: Binary Function "foo.cold.1/1(*2)" after building cfg # CHECK: Parent : foo -# CHECK: Binary Function "bar.cold.1/1" after building cfg -# CHECK: Parent : bar/1 +# CHECK: Binary Function "bar.cold.1/1(*2)" after building cfg +# CHECK: Parent : bar/1(*2) # CHECK: Binary Function "baz.cold.1" after building cfg # CHECK: Parent : baz{{$}} -# CHECK: Binary Function "baz.cold.1/1" after building cfg -# CHECK: Parent : baz/1 +# CHECK: Binary Function "baz.cold.1/1(*2)" after building cfg +# CHECK: Parent : baz/1(*2) + +# CHECK: Binary Function "baz.cold.1/2(*2)" after building cfg +# CHECK: Parent : baz/2(*2) #--- main.s +.file "main.s" .globl main .type main, %function main: @@ -126,6 +133,7 @@ baz.cold.1: .size baz.cold.1, .-baz.cold.1 #--- baz.s +.file "baz.s" .local baz .type baz, %function baz: @@ -149,3 +157,29 @@ baz.cold.1: retq .cfi_endproc .size baz.cold.1, .-baz.cold.1 + +#--- baz2.s +.file "baz2.s" + .local baz + .type baz, %function +baz: + .cfi_startproc +# FDATA: 0 [unknown] 0 1 baz/2 0 1 0 + cmpl $0x0, %eax + je baz.cold.1 + retq + .cfi_endproc +.size baz, .-baz + + .section .text.cold + .local baz.cold.1 + .type baz.cold.1, %function +baz.cold.1: + .cfi_startproc + pushq %rbp + movq %rsp, %rbp + movl $0x0, %eax + popq %rbp + retq + .cfi_endproc +.size baz.cold.1, .-baz.cold.1 diff --git a/bolt/test/X86/indirect-goto-pie.test b/bolt/test/X86/indirect-goto-pie.test new file mode 100644 index 0000000000000..039ff5c41d3d6 --- /dev/null +++ b/bolt/test/X86/indirect-goto-pie.test @@ -0,0 +1,16 @@ +# Check that llvm-bolt fails to process PIC binaries with computed goto, as the +# support is not there yet for correctly updating dynamic relocations +# referencing code inside functions. + +REQUIRES: x86_64-linux + +RUN: %clang %S/Inputs/indirect_goto.c -o %t -fpic -pie -Wl,-q +RUN: not llvm-bolt %t -o %t.bolt --relocs=1 --print-cfg --print-only=main \ +RUN: |& FileCheck %s + +# Check that processing works if main() is skipped. +RUN: llvm-bolt %t -o %t.bolt --relocs=1 --skip-funcs=main + +CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW + +CHECK: BOLT-ERROR: unable to get new address diff --git a/bolt/test/X86/pre-aggregated-perf.test b/bolt/test/X86/pre-aggregated-perf.test index e8c3f64239a27..0bd44720f1b7a 100644 --- a/bolt/test/X86/pre-aggregated-perf.test +++ b/bolt/test/X86/pre-aggregated-perf.test @@ -11,7 +11,14 @@ REQUIRES: system-linux RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: perf2bolt %t.exe -o %t --pa -p %p/Inputs/pre-aggregated.txt -w %t.new \ -RUN: --profile-use-dfs +RUN: --profile-use-dfs | FileCheck %s + +RUN: llvm-bolt %t.exe -data %t -o %t.null | FileCheck %s +RUN: llvm-bolt %t.exe -data %t.new -o %t.null | FileCheck %s +RUN: llvm-bolt %t.exe -p %p/Inputs/pre-aggregated.txt --pa -o %t.null | FileCheck %s + +CHECK: BOLT-INFO: 4 out of 7 functions in the binary (57.1%) have non-empty execution profile + RUN: cat %t | sort | FileCheck %s -check-prefix=PERF2BOLT RUN: cat %t.new | FileCheck %s -check-prefix=NEWFORMAT diff --git a/bolt/test/X86/register-fragments-bolt-symbols.s b/bolt/test/X86/register-fragments-bolt-symbols.s new file mode 100644 index 0000000000000..fa9b70e0b2d89 --- /dev/null +++ b/bolt/test/X86/register-fragments-bolt-symbols.s @@ -0,0 +1,32 @@ +# Test the heuristics for matching BOLT-added split functions. + +# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %S/cdsplit-symbol-names.s -o %t.main.o +# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.chain.o +# RUN: link_fdata %S/cdsplit-symbol-names.s %t.main.o %t.fdata +# RUN: sed -i 's|chain|chain/2|g' %t.fdata +# RUN: llvm-strip --strip-unneeded %t.main.o +# RUN: llvm-objcopy --localize-symbol=chain %t.main.o +# RUN: %clang %cflags %t.chain.o %t.main.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=randomN \ +# RUN: --reorder-blocks=ext-tsp --enable-bat --bolt-seed=7 --data=%t.fdata +# RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS + +# RUN: link_fdata %s %t.bolt %t.preagg PREAGG +# PREAGG: B X:0 #chain.cold.0# 1 0 +# RUN: perf2bolt %t.bolt -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml -v=1 \ +# RUN: | FileCheck %s --check-prefix=CHECK-REGISTER + +# CHECK-SYMS: l df *ABS* [[#]] chain.s +# CHECK-SYMS: l F .bolt.org.text [[#]] chain +# CHECK-SYMS: l F .text.cold [[#]] chain.cold.0 +# CHECK-SYMS: l F .text [[#]] chain +# CHECK-SYMS: l df *ABS* [[#]] bolt-pseudo.o + +# CHECK-REGISTER: BOLT-INFO: marking chain.cold.0/1(*2) as a fragment of chain/2(*2) + +.file "chain.s" + .text + .type chain, @function +chain: + ret + .size chain, .-chain diff --git a/bolt/test/X86/shrinkwrapping-do-not-pessimize.s b/bolt/test/X86/shrinkwrapping-do-not-pessimize.s index a57131131423e..3fdd5f5e38fe0 100644 --- a/bolt/test/X86/shrinkwrapping-do-not-pessimize.s +++ b/bolt/test/X86/shrinkwrapping-do-not-pessimize.s @@ -53,6 +53,6 @@ end_if_1: .size _start, .-_start .data -rel: .quad end_if_1 +rel: .quad _start # CHECK: BOLT-INFO: Shrink wrapping moved 0 spills inserting load/stores and 0 spills inserting push/pops diff --git a/bolt/test/runtime/X86/Inputs/indirect_goto.c b/bolt/test/runtime/X86/Inputs/indirect_goto.c deleted file mode 100644 index b781e9e03b6d4..0000000000000 --- a/bolt/test/runtime/X86/Inputs/indirect_goto.c +++ /dev/null @@ -1,18 +0,0 @@ -int main(int argc, char *argv[]) { - static const void *T1[] = { &&L1, &&L2 }; - static const void *T2[] = { &&L2, &&L3 }; - - const void **T = (argc > 1) ? T1 : T2; - - int i = 0; - -L0: - goto *T[argc]; -L1: - ++i; -L2: - i++; -L3: - i++; - return i; -} diff --git a/bolt/test/runtime/X86/indirect-goto-pie.test b/bolt/test/runtime/X86/indirect-goto-pie.test deleted file mode 100644 index 76089fda3abfb..0000000000000 --- a/bolt/test/runtime/X86/indirect-goto-pie.test +++ /dev/null @@ -1,10 +0,0 @@ -# Check llvm-bolt processes binaries compiled from sources that use indirect goto. -REQUIRES: x86_64-linux - -RUN: %clang %S/Inputs/indirect_goto.c -o %t -fpic -pie -Wl,-q -RUN: llvm-bolt %t -o %t.bolt --relocs=1 --print-cfg --print-only=main \ -RUN: |& FileCheck %s -# The test fails as we don't update corresponding dynamic relocations. -RUN: not %t.bolt - -CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp index 84e99c7fafc74..10868129e76da 100644 --- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp @@ -967,7 +967,8 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, // Get out the qualifiers of the original type. This will always be // re-applied to the WorkType to ensure it is the same qualification as the // original From was. - auto QualifiersToApply = From.split().Quals.getAsOpaqueValue(); + auto FastQualifiersToApply = static_cast( + From.split().Quals.getAsOpaqueValue() & Qualifiers::FastMask); // LValue->RValue is irrelevant for the check, because it is a thing to be // done at a call site, and will be performed if need be performed. @@ -993,7 +994,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, // "const double -> double". LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Conversion between numerics.\n"); - WorkType = QualType{ToBuiltin, QualifiersToApply}; + WorkType = QualType{ToBuiltin, FastQualifiersToApply}; } const auto *FromEnum = WorkType->getAs(); @@ -1002,7 +1003,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, // Unscoped enumerations (or enumerations in C) convert to numerics. LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Unscoped enum to numeric.\n"); - WorkType = QualType{ToBuiltin, QualifiersToApply}; + WorkType = QualType{ToBuiltin, FastQualifiersToApply}; } else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumerationType()) { // Numeric types convert to enumerations only in C. if (Ctx.getLangOpts().CPlusPlus) { @@ -1013,7 +1014,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Numeric to unscoped enum.\n"); - WorkType = QualType{ToEnum, QualifiersToApply}; + WorkType = QualType{ToEnum, FastQualifiersToApply}; } // Check for pointer conversions. @@ -1022,14 +1023,14 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, if (FromPtr && ToPtr) { if (ToPtr->isVoidPointerType()) { LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. To void pointer.\n"); - WorkType = QualType{ToPtr, QualifiersToApply}; + WorkType = QualType{ToPtr, FastQualifiersToApply}; } const auto *FromRecordPtr = FromPtr->getPointeeCXXRecordDecl(); const auto *ToRecordPtr = ToPtr->getPointeeCXXRecordDecl(); if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) { LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived* to Base*\n"); - WorkType = QualType{ToPtr, QualifiersToApply}; + WorkType = QualType{ToPtr, FastQualifiersToApply}; } } @@ -1039,7 +1040,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, const auto *ToRecord = To->getAsCXXRecordDecl(); if (isDerivedToBase(FromRecord, ToRecord)) { LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n"); - WorkType = QualType{ToRecord->getTypeForDecl(), QualifiersToApply}; + WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply}; } if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) { @@ -1054,7 +1055,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, !ToFunctionPtr->hasNoexceptExceptionSpec()) { LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. noexcept function " "pointer to non-noexcept.\n"); - WorkType = QualType{ToPtr, QualifiersToApply}; + WorkType = QualType{ToPtr, FastQualifiersToApply}; } } diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 6852db6c2ee31..8005d6e91c060 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -16,6 +16,7 @@ add_clang_library(clangTidyModernizeModule MakeSharedCheck.cpp MakeSmartPtrCheck.cpp MakeUniqueCheck.cpp + MinMaxUseInitializerListCheck.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp RawStringLiteralCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp new file mode 100644 index 0000000000000..45f7700463d57 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp @@ -0,0 +1,271 @@ +//===--- MinMaxUseInitializerListCheck.cpp - clang-tidy -------------------===// +// +// 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 "MinMaxUseInitializerListCheck.h" +#include "../utils/ASTUtils.h" +#include "../utils/LexerUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" + +using namespace clang; + +namespace { + +struct FindArgsResult { + const Expr *First; + const Expr *Last; + const Expr *Compare; + SmallVector Args; +}; + +} // anonymous namespace + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +static FindArgsResult findArgs(const CallExpr *Call) { + FindArgsResult Result; + Result.First = nullptr; + Result.Last = nullptr; + Result.Compare = nullptr; + + // check if the function has initializer list argument + if (Call->getNumArgs() < 3) { + auto ArgIterator = Call->arguments().begin(); + + const auto *InitListExpr = + dyn_cast(*ArgIterator); + const auto *InitList = + InitListExpr != nullptr + ? dyn_cast( + InitListExpr->getSubExpr()->IgnoreImplicit()) + : nullptr; + + if (InitList) { + Result.Args.append(InitList->inits().begin(), InitList->inits().end()); + Result.First = *ArgIterator; + Result.Last = *ArgIterator; + + // check if there is a comparison argument + std::advance(ArgIterator, 1); + if (ArgIterator != Call->arguments().end()) + Result.Compare = *ArgIterator; + + return Result; + } + Result.Args = SmallVector(Call->arguments()); + } else { + // if it has 3 arguments then the last will be the comparison + Result.Compare = *(std::next(Call->arguments().begin(), 2)); + Result.Args = SmallVector(llvm::drop_end(Call->arguments())); + } + Result.First = Result.Args.front(); + Result.Last = Result.Args.back(); + + return Result; +} + +static SmallVector +generateReplacements(const MatchFinder::MatchResult &Match, + const CallExpr *TopCall, const FindArgsResult &Result, + const bool IgnoreNonTrivialTypes, + const std::uint64_t IgnoreTrivialTypesOfSizeAbove) { + SmallVector FixItHints; + const SourceManager &SourceMngr = *Match.SourceManager; + const LangOptions &LanguageOpts = Match.Context->getLangOpts(); + + const QualType ResultType = TopCall->getDirectCallee() + ->getReturnType() + .getCanonicalType() + .getNonReferenceType() + .getUnqualifiedType(); + + // check if the type is trivial + const bool IsResultTypeTrivial = ResultType.isTrivialType(*Match.Context); + + if ((!IsResultTypeTrivial && IgnoreNonTrivialTypes)) + return FixItHints; + + if (IsResultTypeTrivial && + static_cast( + Match.Context->getTypeSizeInChars(ResultType).getQuantity()) > + IgnoreTrivialTypesOfSizeAbove) + return FixItHints; + + for (const Expr *Arg : Result.Args) { + const auto *InnerCall = dyn_cast(Arg->IgnoreParenImpCasts()); + + // If the argument is not a nested call + if (!InnerCall) { + // check if typecast is required + const QualType ArgType = Arg->IgnoreParenImpCasts() + ->getType() + .getCanonicalType() + .getUnqualifiedType(); + + if (ArgType == ResultType) + continue; + + const StringRef ArgText = Lexer::getSourceText( + CharSourceRange::getTokenRange(Arg->getSourceRange()), SourceMngr, + LanguageOpts); + + const auto Replacement = Twine("static_cast<") + .concat(ResultType.getAsString(LanguageOpts)) + .concat(">(") + .concat(ArgText) + .concat(")") + .str(); + + FixItHints.push_back( + FixItHint::CreateReplacement(Arg->getSourceRange(), Replacement)); + continue; + } + + const FindArgsResult InnerResult = findArgs(InnerCall); + + // if the nested call doesn't have arguments skip it + if (!InnerResult.First || !InnerResult.Last) + continue; + + // if the nested call is not the same as the top call + if (InnerCall->getDirectCallee()->getQualifiedNameAsString() != + TopCall->getDirectCallee()->getQualifiedNameAsString()) + continue; + + // if the nested call doesn't have the same compare function + if ((Result.Compare || InnerResult.Compare) && + !utils::areStatementsIdentical(Result.Compare, InnerResult.Compare, + *Match.Context)) + continue; + + // remove the function call + FixItHints.push_back( + FixItHint::CreateRemoval(InnerCall->getCallee()->getSourceRange())); + + // remove the parentheses + const auto LParen = utils::lexer::findNextTokenSkippingComments( + InnerCall->getCallee()->getEndLoc(), SourceMngr, LanguageOpts); + if (LParen.has_value() && LParen->is(tok::l_paren)) + FixItHints.push_back( + FixItHint::CreateRemoval(SourceRange(LParen->getLocation()))); + FixItHints.push_back( + FixItHint::CreateRemoval(SourceRange(InnerCall->getRParenLoc()))); + + // if the inner call has an initializer list arg + if (InnerResult.First == InnerResult.Last) { + // remove the initializer list braces + FixItHints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(InnerResult.First->getBeginLoc()))); + FixItHints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(InnerResult.First->getEndLoc()))); + } + + const SmallVector InnerReplacements = generateReplacements( + Match, InnerCall, InnerResult, IgnoreNonTrivialTypes, + IgnoreTrivialTypesOfSizeAbove); + + FixItHints.append(InnerReplacements); + + if (InnerResult.Compare) { + // find the comma after the value arguments + const auto Comma = utils::lexer::findNextTokenSkippingComments( + InnerResult.Last->getEndLoc(), SourceMngr, LanguageOpts); + + // remove the comma and the comparison + if (Comma.has_value() && Comma->is(tok::comma)) + FixItHints.push_back( + FixItHint::CreateRemoval(SourceRange(Comma->getLocation()))); + + FixItHints.push_back( + FixItHint::CreateRemoval(InnerResult.Compare->getSourceRange())); + } + } + + return FixItHints; +} + +MinMaxUseInitializerListCheck::MinMaxUseInitializerListCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoreNonTrivialTypes(Options.get("IgnoreNonTrivialTypes", true)), + IgnoreTrivialTypesOfSizeAbove( + Options.get("IgnoreTrivialTypesOfSizeAbove", 32L)), + Inserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void MinMaxUseInitializerListCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreNonTrivialTypes", IgnoreNonTrivialTypes); + Options.store(Opts, "IgnoreTrivialTypesOfSizeAbove", + IgnoreTrivialTypesOfSizeAbove); + Options.store(Opts, "IncludeStyle", Inserter.getStyle()); +} + +void MinMaxUseInitializerListCheck::registerMatchers(MatchFinder *Finder) { + auto CreateMatcher = [](const StringRef FunctionName) { + auto FuncDecl = functionDecl(hasName(FunctionName)); + auto Expression = callExpr(callee(FuncDecl)); + + return callExpr(callee(FuncDecl), + anyOf(hasArgument(0, Expression), + hasArgument(1, Expression), + hasArgument(0, cxxStdInitializerListExpr())), + unless(hasParent(Expression))) + .bind("topCall"); + }; + + Finder->addMatcher(CreateMatcher("::std::max"), this); + Finder->addMatcher(CreateMatcher("::std::min"), this); +} + +void MinMaxUseInitializerListCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + Inserter.registerPreprocessor(PP); +} + +void MinMaxUseInitializerListCheck::check( + const MatchFinder::MatchResult &Match) { + + const auto *TopCall = Match.Nodes.getNodeAs("topCall"); + + const FindArgsResult Result = findArgs(TopCall); + const SmallVector Replacements = + generateReplacements(Match, TopCall, Result, IgnoreNonTrivialTypes, + IgnoreTrivialTypesOfSizeAbove); + + if (Replacements.empty()) + return; + + const DiagnosticBuilder Diagnostic = + diag(TopCall->getBeginLoc(), + "do not use nested 'std::%0' calls, use an initializer list instead") + << TopCall->getDirectCallee()->getName() + << Inserter.createIncludeInsertion( + Match.SourceManager->getFileID(TopCall->getBeginLoc()), + ""); + + // if the top call doesn't have an initializer list argument + if (Result.First != Result.Last) { + // add { and } insertions + Diagnostic << FixItHint::CreateInsertion(Result.First->getBeginLoc(), "{"); + + Diagnostic << FixItHint::CreateInsertion( + Lexer::getLocForEndOfToken(Result.Last->getEndLoc(), 0, + *Match.SourceManager, + Match.Context->getLangOpts()), + "}"); + } + + Diagnostic << Replacements; +} + +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.h b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.h new file mode 100644 index 0000000000000..577d126530761 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.h @@ -0,0 +1,56 @@ +//===--- MinMaxUseInitializerListCheck.h - clang-tidy -----------*- 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_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MINMAXUSEINITIALIZERLISTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MINMAXUSEINITIALIZERLISTCHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/IncludeInserter.h" + +namespace clang::tidy::modernize { + +/// Replaces nested ``std::min`` and ``std::max`` calls with an initializer list +/// where applicable. +/// +/// For example: +/// +/// \code +/// int a = std::max(std::max(i, j), k); +/// \endcode +/// +/// This code is transformed to: +/// +/// \code +/// int a = std::max({i, j, k}); +/// \endcode +class MinMaxUseInitializerListCheck : public ClangTidyCheck { +public: + MinMaxUseInitializerListCheck(StringRef Name, ClangTidyContext *Context); + + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void check(const ast_matchers::MatchFinder::MatchResult &Match) override; + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus11; + } + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + bool IgnoreNonTrivialTypes; + std::uint64_t IgnoreTrivialTypesOfSizeAbove; + utils::IncludeInserter Inserter; +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MINMAXUSEINITIALIZERLISTCHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index e96cf274f58cf..776558433c5ba 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -18,6 +18,7 @@ #include "MacroToEnumCheck.h" #include "MakeSharedCheck.h" #include "MakeUniqueCheck.h" +#include "MinMaxUseInitializerListCheck.h" #include "PassByValueCheck.h" #include "RawStringLiteralCheck.h" #include "RedundantVoidArgCheck.h" @@ -68,6 +69,8 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck("modernize-macro-to-enum"); CheckFactories.registerCheck("modernize-make-shared"); CheckFactories.registerCheck("modernize-make-unique"); + CheckFactories.registerCheck( + "modernize-min-max-use-initializer-list"); CheckFactories.registerCheck("modernize-pass-by-value"); CheckFactories.registerCheck( "modernize-use-designated-initializers"); diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h index 6c32a4edb4ff9..f1591bae44657 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h @@ -19,7 +19,7 @@ class UseNullptrCheck : public ClangTidyCheck { bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { // FIXME this should be CPlusPlus11 but that causes test cases to // erroneously fail. - return LangOpts.CPlusPlus; + return LangOpts.CPlusPlus || LangOpts.C23; } void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp index 48bca41f4a3b1..f077040a35295 100644 --- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp @@ -64,8 +64,11 @@ void AvoidReturnWithVoidValueCheck::check( << BraceInsertionHints.closingBraceFixIt(); } Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc()); - if (!Result.Nodes.getNodeAs("function_parent") || - SurroundingBlock->body_back() != VoidReturn) + const auto *FunctionParent = + Result.Nodes.getNodeAs("function_parent"); + if (!FunctionParent || + (SurroundingBlock && SurroundingBlock->body_back() != VoidReturn)) + // If this is not the last statement in a function body, we add a `return`. Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1), " return;", true); } diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index dd772d6920254..41065fc8e8785 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -28,6 +28,7 @@ add_clang_library(clangTidyReadabilityModule IsolateDeclarationCheck.cpp MagicNumbersCheck.cpp MakeMemberFunctionConstCheck.cpp + MathMissingParenthesesCheck.cpp MisleadingIndentationCheck.cpp MisplacedArrayIndexCheck.cpp NamedParameterCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp new file mode 100644 index 0000000000000..65fd296094915 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp @@ -0,0 +1,99 @@ +//===--- MathMissingParenthesesCheck.cpp - clang-tidy ---------------------===// +// +// 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 "MathMissingParenthesesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +void MathMissingParenthesesCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(binaryOperator(unless(hasParent(binaryOperator())), + unless(isAssignmentOperator()), + unless(isComparisonOperator()), + unless(hasAnyOperatorName("&&", "||")), + hasDescendant(binaryOperator())) + .bind("binOp"), + this); +} + +static int getPrecedence(const BinaryOperator *BinOp) { + if (!BinOp) + return 0; + switch (BinOp->getOpcode()) { + case BO_Mul: + case BO_Div: + case BO_Rem: + return 5; + case BO_Add: + case BO_Sub: + return 4; + case BO_And: + return 3; + case BO_Xor: + return 2; + case BO_Or: + return 1; + default: + return 0; + } +} +static void addParantheses(const BinaryOperator *BinOp, + const BinaryOperator *ParentBinOp, + ClangTidyCheck *Check, + const clang::SourceManager &SM, + const clang::LangOptions &LangOpts) { + if (!BinOp) + return; + + int Precedence1 = getPrecedence(BinOp); + int Precedence2 = getPrecedence(ParentBinOp); + + if (ParentBinOp != nullptr && Precedence1 != Precedence2) { + const clang::SourceLocation StartLoc = BinOp->getBeginLoc(); + const clang::SourceLocation EndLoc = + clang::Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0, SM, LangOpts); + + auto Diag = + Check->diag(StartLoc, + "'%0' has higher precedence than '%1'; add parentheses to " + "explicitly specify the order of operations") + << (Precedence1 > Precedence2 ? BinOp->getOpcodeStr() + : ParentBinOp->getOpcodeStr()) + << (Precedence1 > Precedence2 ? ParentBinOp->getOpcodeStr() + : BinOp->getOpcodeStr()) + << SourceRange(StartLoc, EndLoc); + + if (EndLoc.isValid()) { + Diag << FixItHint::CreateInsertion(StartLoc, "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + } + } + + addParantheses(dyn_cast(BinOp->getLHS()->IgnoreImpCasts()), + BinOp, Check, SM, LangOpts); + addParantheses(dyn_cast(BinOp->getRHS()->IgnoreImpCasts()), + BinOp, Check, SM, LangOpts); +} + +void MathMissingParenthesesCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *BinOp = Result.Nodes.getNodeAs("binOp"); + std::vector< + std::pair>> + Insertions; + const SourceManager &SM = *Result.SourceManager; + const clang::LangOptions &LO = Result.Context->getLangOpts(); + addParantheses(BinOp, nullptr, this, SM, LO); +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h new file mode 100644 index 0000000000000..9a9d2b3cfaaba --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h @@ -0,0 +1,34 @@ +//===--- MathMissingParenthesesCheck.h - clang-tidy -------------*- 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_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +/// Check for mising parantheses in mathematical expressions that involve +/// operators of different priorities. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability/math-missing-parentheses.html +class MathMissingParenthesesCheck : public ClangTidyCheck { +public: + MathMissingParenthesesCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index 376b84683df74..d61c0ba39658e 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -32,6 +32,7 @@ #include "IsolateDeclarationCheck.h" #include "MagicNumbersCheck.h" #include "MakeMemberFunctionConstCheck.h" +#include "MathMissingParenthesesCheck.h" #include "MisleadingIndentationCheck.h" #include "MisplacedArrayIndexCheck.h" #include "NamedParameterCheck.h" @@ -105,6 +106,8 @@ class ReadabilityModule : public ClangTidyModule { "readability-identifier-naming"); CheckFactories.registerCheck( "readability-implicit-bool-conversion"); + CheckFactories.registerCheck( + "readability-math-missing-parentheses"); CheckFactories.registerCheck( "readability-redundant-inline-specifier"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.cpp b/clang-tools-extra/clangd/CodeCompletionStrings.cpp index 2075e5965f181..9b4442b0bb76f 100644 --- a/clang-tools-extra/clangd/CodeCompletionStrings.cpp +++ b/clang-tools-extra/clangd/CodeCompletionStrings.cpp @@ -253,7 +253,7 @@ void getSignature(const CodeCompletionString &CCS, std::string *Signature, if (!IncludeFunctionArguments && ResultKind == CodeCompletionResult::RK_Declaration) TruncateSnippetAt.emplace(Snippet->size()); - LLVM_FALLTHROUGH; + [[fallthrough]]; case CodeCompletionString::CK_RightParen: case CodeCompletionString::CK_LeftBracket: case CodeCompletionString::CK_RightBracket: diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 799a549ff0816..94437857cecca 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -854,7 +854,7 @@ TEST_F(TargetDeclTest, DependentExprs) { } }; )cpp"; - EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()"); + EXPECT_DECLS("MemberExpr", "void foo()"); // Similar to above but base expression involves a function call. Code = R"cpp( @@ -872,7 +872,7 @@ TEST_F(TargetDeclTest, DependentExprs) { } }; )cpp"; - EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()"); + EXPECT_DECLS("MemberExpr", "void foo()"); // Similar to above but uses a function pointer. Code = R"cpp( @@ -891,7 +891,7 @@ TEST_F(TargetDeclTest, DependentExprs) { } }; )cpp"; - EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()"); + EXPECT_DECLS("MemberExpr", "void foo()"); // Base expression involves a member access into this. Code = R"cpp( @@ -962,7 +962,7 @@ TEST_F(TargetDeclTest, DependentExprs) { void Foo() { this->[[find]](); } }; )cpp"; - EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()"); + EXPECT_DECLS("MemberExpr", "void find()"); } TEST_F(TargetDeclTest, DependentTypes) { diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp index 4156921d83edf..30b9b1902aa9c 100644 --- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -621,7 +621,7 @@ sizeof...($TemplateParameter[[Elements]]); struct $Class_def[[Foo]] { int $Field_decl[[Waldo]]; void $Method_def[[bar]]() { - $Class[[Foo]]().$Field_dependentName[[Waldo]]; + $Class[[Foo]]().$Field[[Waldo]]; } template $Bracket[[<]]typename $TemplateParameter_def[[U]]$Bracket[[>]] void $Method_def[[bar1]]() { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 5b1feffb89ea0..5956ccb925485 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -100,13 +100,15 @@ Improvements to clang-tidy - Improved :program:`run-clang-tidy.py` script. Added argument `-source-filter` to filter source files from the compilation database, via a RegEx. In a similar fashion to what `-header-filter` does for header files. + - Improved :program:`check_clang_tidy.py` script. Added argument `-export-fixes` to aid in clang-tidy and test development. + - Fixed bug where big values for unsigned check options overflowed into negative values - when being printed with ``--dump-config``. + when being printed with `--dump-config`. -- Fixed ``--verify-config`` option not properly parsing checks when using the - literal operator in the ``.clang-tidy`` config. +- Fixed `--verify-config` option not properly parsing checks when using the + literal operator in the `.clang-tidy` config. New checks ^^^^^^^^^^ @@ -131,6 +133,12 @@ New checks to reading out-of-bounds data due to inadequate or incorrect string null termination. +- New :doc:`modernize-min-max-use-initializer-list + ` check. + + Replaces nested ``std::min`` and ``std::max`` calls with an initializer list + where applicable. + - New :doc:`modernize-use-designated-initializers ` check. @@ -143,6 +151,12 @@ New checks Enforces consistent style for enumerators' initialization, covering three styles: none, first only, or all initialized explicitly. +- New :doc:`readability-math-missing-parentheses + ` check. + + Check for missing parentheses in mathematical expressions that involve + operators of different priorities. + - New :doc:`readability-use-std-min-max ` check. @@ -224,7 +238,7 @@ Changes in existing checks - Improved :doc:`google-explicit-constructor ` check to better handle - ``C++-20`` `explicit(bool)`. + C++20 `explicit(bool)`. - Improved :doc:`google-global-names-in-headers ` check by replacing the local @@ -237,13 +251,18 @@ Changes in existing checks check by ignoring other functions with same prefixes as the target specific functions. +- Improved :doc:`linuxkernel-must-check-errs + ` check documentation to + consistently use the check's proper name. + - Improved :doc:`llvm-header-guard ` check by replacing the local option `HeaderFileExtensions` by the global option of the same name. - Improved :doc:`misc-const-correctness ` check by avoiding infinite recursion - for recursive forwarding reference. + for recursive functions with forwarding reference parameters and reference + variables which refer to themselves. - Improved :doc:`misc-definitions-in-headers ` check by replacing the local @@ -269,6 +288,10 @@ Changes in existing checks don't remove parentheses used in ``sizeof`` calls when they have array index accesses as arguments. +- Improved :doc:`modernize-use-nullptr + ` check to include support for C23, + which also has introduced the ``nullptr`` keyword. + - Improved :doc:`modernize-use-override ` check to also remove any trailing whitespace when deleting the ``virtual`` keyword. @@ -324,13 +347,9 @@ Miscellaneous ^^^^^^^^^^^^^ - Fixed incorrect formatting in :program:`clang-apply-replacements` when no - ``--format`` option is specified. Now :program:`clang-apply-replacements` + `--format` option is specified. Now :program:`clang-apply-replacements` applies formatting only with the option. -- Fixed the :doc:`linuxkernel-must-check-errs - ` documentation to consistently - use the check's proper name. - Improvements to include-fixer ----------------------------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/env33-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/env33-c.rst index c5321b07f7f84..9271c9ecccc00 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cert/env33-c.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cert/env33-c.rst @@ -10,4 +10,4 @@ but does not actually attempt to execute a command. This check corresponds to the CERT C Coding Standard rule `ENV33-C. Do not call system() -`_. +`_. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 5d9d487f75f9c..49747ff896ba5 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -276,6 +276,7 @@ Clang-Tidy Checks :doc:`modernize-macro-to-enum `, "Yes" :doc:`modernize-make-shared `, "Yes" :doc:`modernize-make-unique `, "Yes" + :doc:`modernize-min-max-use-initializer-list `, "Yes" :doc:`modernize-pass-by-value `, "Yes" :doc:`modernize-raw-string-literal `, "Yes" :doc:`modernize-redundant-void-arg `, "Yes" @@ -363,6 +364,7 @@ Clang-Tidy Checks :doc:`readability-isolate-declaration `, "Yes" :doc:`readability-magic-numbers `, :doc:`readability-make-member-function-const `, "Yes" + :doc:`readability-math-missing-parentheses `, "Yes" :doc:`readability-misleading-indentation `, :doc:`readability-misplaced-array-index `, "Yes" :doc:`readability-named-parameter `, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/min-max-use-initializer-list.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/min-max-use-initializer-list.rst new file mode 100644 index 0000000000000..d6721a25629b0 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/min-max-use-initializer-list.rst @@ -0,0 +1,50 @@ +.. title:: clang-tidy - modernize-min-max-use-initializer-list + +modernize-min-max-use-initializer-list +====================================== + +Replaces nested ``std::min`` and ``std::max`` calls with an initializer list +where applicable. + +For instance, consider the following code: + +.. code-block:: cpp + + int a = std::max(std::max(i, j), k); + +The check will transform the above code to: + +.. code-block:: cpp + + int a = std::max({i, j, k}); + +Performance Considerations +========================== + +While this check simplifies the code and makes it more readable, it may cause +performance degradation for non-trivial types due to the need to copy objects +into the initializer list. + +To avoid this, it is recommended to use `std::ref` or `std::cref` for +non-trivial types: + +.. code-block:: cpp + + std::string b = std::max({std::ref(i), std::ref(j), std::ref(k)}); + +Options +======= + +.. option:: IncludeStyle + + A string specifying which include-style is used, `llvm` or `google`. Default + is `llvm`. + +.. option:: IgnoreNonTrivialTypes + + A boolean specifying whether to ignore non-trivial types. Default is `true`. + +.. option:: IgnoreTrivialTypesOfSizeAbove + + An integer specifying the size (in bytes) above which trivial types are + ignored. Default is `32`. \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst index 5e1ba858adf3a..25e17fee0a3d6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst @@ -4,7 +4,7 @@ modernize-use-nullptr ===================== The check converts the usage of null pointer constants (e.g. ``NULL``, ``0``) -to use the new C++11 ``nullptr`` keyword. +to use the new C++11 and C23 ``nullptr`` keyword. Example ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst new file mode 100644 index 0000000000000..21d66daab334c --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst @@ -0,0 +1,27 @@ +.. title:: clang-tidy - readability-math-missing-parentheses + +readability-math-missing-parentheses +==================================== + +Check for missing parentheses in mathematical expressions that involve operators +of different priorities. + +Parentheses in mathematical expressions clarify the order +of operations, especially with different-priority operators. Lengthy or multiline +expressions can obscure this order, leading to coding errors. IDEs can aid clarity +by highlighting parentheses. Explicitly using parentheses also clarifies what the +developer had in mind when writing the expression. Ensuring their presence reduces +ambiguity and errors, promoting clearer and more maintainable code. + +Before: + +.. code-block:: c++ + + int x = 1 + 2 * 3 - 4 / 5; + + +After: + +.. code-block:: c++ + + int x = 1 + (2 * 3) - (4 / 5); \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp index 574efe7bd9147..ae61b17ca14d2 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp @@ -309,6 +309,8 @@ struct HeapArray { // Ok, since destruc HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok other._data = nullptr; // Ok + // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t' + // FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types. other.size = 0; } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp new file mode 100644 index 0000000000000..51ab9bda975f1 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp @@ -0,0 +1,305 @@ +// RUN: %check_clang_tidy %s modernize-min-max-use-initializer-list %t + +// CHECK-FIXES: #include +namespace utils { +template +T max(T a, T b) { + return (a < b) ? b : a; +} +} // namespace utils + +namespace std { +template< class T > +struct initializer_list { + initializer_list()=default; + initializer_list(T*,int){} + const T* begin() const {return nullptr;} + const T* end() const {return nullptr;} +}; + +template +ForwardIt min_element(ForwardIt first, ForwardIt last) +{ + if (first == last) + return last; + + ForwardIt smallest = first; + + while (++first != last) + if (*first < *smallest) + smallest = first; + + return smallest; +} + +template +ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp) +{ + if (first == last) + return last; + + ForwardIt smallest = first; + + while (++first != last) + if (comp(*first, *smallest)) + smallest = first; + + return smallest; +} + +template +ForwardIt max_element(ForwardIt first, ForwardIt last) +{ + if (first == last) + return last; + + ForwardIt largest = first; + + while (++first != last) + if (*largest < *first) + largest = first; + + return largest; +} + +template +ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp) +{ + if (first == last) + return last; + + ForwardIt largest = first; + + while(++first != last) + if (comp(*largest, *first)) + largest = first; + + return largest; +} + +template< class T > +const T& max( const T& a, const T& b ) { + return (a < b) ? b : a; +}; + +template< class T > +T max(std::initializer_list ilist) +{ + return *std::max_element(ilist.begin(), ilist.end()); +} + +template< class T, class Compare > +const T& max( const T& a, const T& b, Compare comp ) { + return (comp(a, b)) ? b : a; +}; + +template< class T, class Compare > +T max(std::initializer_list ilist, Compare comp) { + return *std::max_element(ilist.begin(), ilist.end(), comp); +}; + +template< class T > +const T& min( const T& a, const T& b ) { + return (b < a) ? b : a; +}; + +template< class T > +T min(std::initializer_list ilist) +{ + return *std::min_element(ilist.begin(), ilist.end()); +} + + +template< class T, class Compare > +const T& min( const T& a, const T& b, Compare comp ) { + return (comp(b, a)) ? b : a; +}; + +template< class T, class Compare > +T min(std::initializer_list ilist, Compare comp) { + return *std::min_element(ilist.begin(), ilist.end(), comp); +}; + +} // namespace std + +using namespace std; + +namespace { +bool fless_than(int a, int b) { +return a < b; +} + +bool fgreater_than(int a, int b) { +return a > b; +} +auto less_than = [](int a, int b) { return a < b; }; +auto greater_than = [](int a, int b) { return a > b; }; + +int max1 = std::max(1, std::max(2, 3)); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max1 = std::max({1, 2, 3}); + +int min1 = std::min(1, std::min(2, 3)); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int min1 = std::min({1, 2, 3}); + +int max2 = std::max(1, std::max(2, std::max(3, 4))); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max2 = std::max({1, 2, 3, 4}); + +int max2b = std::max(std::max(std::max(1, 2), std::max(3, 4)), std::max(std::max(5, 6), std::max(7, 8))); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max2b = std::max({1, 2, 3, 4, 5, 6, 7, 8}); + +int max2c = std::max(std::max(1, std::max(2, 3)), 4); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max2c = std::max({1, 2, 3, 4}); + +int max2d = std::max(std::max({1, 2, 3}), 4); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max2d = std::max({1, 2, 3, 4}); + + +int max2e = std::max(1, max(2, max(3, 4))); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max2e = std::max({1, 2, 3, 4}); + +int min2 = std::min(1, std::min(2, std::min(3, 4))); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int min2 = std::min({1, 2, 3, 4}); + +int max3 = std::max(std::max(4, 5), std::min(2, std::min(3, 1))); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max3 = std::max({4, 5, std::min({2, 3, 1})}); + +int min3 = std::min(std::min(4, 5), std::max(2, std::max(3, 1))); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int min3 = std::min({4, 5, std::max({2, 3, 1})}); + +int max4 = std::max(1, std::max(2, 3, greater_than), less_than); +// CHECK-FIXES: int max4 = std::max(1, std::max(2, 3, greater_than), less_than); + +int min4 = std::min(1, std::min(2, 3, greater_than), less_than); +// CHECK-FIXES: int min4 = std::min(1, std::min(2, 3, greater_than), less_than); + +int max5 = std::max(1, std::max(2, 3), less_than); +// CHECK-FIXES: int max5 = std::max(1, std::max(2, 3), less_than); + +int min5 = std::min(1, std::min(2, 3), less_than); +// CHECK-FIXES: int min5 = std::min(1, std::min(2, 3), less_than); + +int max6 = std::max(1, std::max(2, 3, greater_than), greater_than); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max6 = std::max({1, 2, 3 }, greater_than); + +int min6 = std::min(1, std::min(2, 3, greater_than), greater_than); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int min6 = std::min({1, 2, 3 }, greater_than); + +int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than); +// CHECK-FIXES: int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than); + +int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than); +// CHECK-FIXES: int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than); + +int max8 = std::max(1, std::max(2, 3, fless_than), less_than); +// CHECK-FIXES: int max8 = std::max(1, std::max(2, 3, fless_than), less_than) + +int min8 = std::min(1, std::min(2, 3, fless_than), less_than); +// CHECK-FIXES: int min8 = std::min(1, std::min(2, 3, fless_than), less_than); + +int max9 = std::max(1, std::max(2, 3, fless_than), fless_than); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max9 = std::max({1, 2, 3 }, fless_than); + +int min9 = std::min(1, std::min(2, 3, fless_than), fless_than); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int min9 = std::min({1, 2, 3 }, fless_than); + +int min10 = std::min(std::min(4, 5), std::max(2, utils::max(3, 1))); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int min10 = std::min({4, 5, std::max(2, utils::max(3, 1))}); + +int max10 = std::max({std::max(1, 2), std::max({5, 6, 1}), 2, std::min({1, 2, 4})}); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int max10 = std::max({1, 2, 5, 6, 1, 2, std::min({1, 2, 4})}); + +int typecastTest = std::max(std::max(0U, 0.0f), 0); +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int typecastTest = std::max({static_cast(0U), static_cast(0.0f), 0}); + +int typecastTest1 = std::max(std::max(0U, 0.0f), 0L); +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int typecastTest1 = std::max({static_cast(0U), static_cast(0.0f), 0L}); + +int typecastTest2 = std::max(std::max(10U, 20.0f), 30); +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int typecastTest2 = std::max({static_cast(10U), static_cast(20.0f), 30}); + +int typecastTest3 = std::max(std::max(0U, std::max(0.0f, 1.0f)), 0); +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int typecastTest3 = std::max({static_cast(0U), static_cast(0.0f), static_cast(1.0f), 0}); + +#define max3f(a, b, c) std::max(a, std::max(b, c)) +// CHECK-FIXES: #define max3f(a, b, c) std::max(a, std::max(b, c)) + +#define value 4545 +int macroVarMax = std::max(value, std::max(1, 2)); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int macroVarMax = std::max({value, 1, 2}); + +#define value2 45U +int macroVarMax2 = std::max(1, std::max(value2, 2.0f)); +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: int macroVarMax2 = std::max({1, static_cast(value2), static_cast(2.0f)}); + +// True-negative tests +int maxTN1 = std::max(1, 2); +// CHECK-FIXES: int maxTN1 = std::max(1, 2); + +int maxTN2 = std::max({1, 2, 3}); +// CHECK-FIXES: int maxTN2 = std::max({1, 2, 3}); + +int maxTN3 = std::max({1, 2, 3}, less_than); +// CHECK-FIXES: int maxTN3 = std::max({1, 2, 3}, less_than); + +// non-trivial types +struct A { + int a; + A(int a) : a(a) {} + bool operator<(const A &rhs) const { return a < rhs.a; } +}; + +A maxNT1 = std::max(A(1), A(2)); +// CHECK-FIXES: A maxNT1 = std::max(A(1), A(2)); + +A maxNT2 = std::max(A(1), std::max(A(2), A(3))); +// CHECK-FIXES: A maxNT2 = std::max(A(1), std::max(A(2), A(3))); + +A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; }); +// CHECK-FIXES: A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; }); + +// Trivial type with size greater than 32 +struct B { + // 9*4 = 36 bytes > 32 bytes + int a[9]; + + bool operator<(const B& rhs) const { + return a[0] < rhs.a[0]; + } +}; + +B maxTT1 = std::max(B(), B()); +// CHECK-FIXES: B maxTT1 = std::max(B(), B()); + +B maxTT2 = std::max(B(), std::max(B(), B())); +// CHECK-FIXES: B maxTT2 = std::max(B(), std::max(B(), B())); + +B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); +// CHECK-FIXES: B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); + + +} // namespace + diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp index 559031cf4d9bd..4abb9c8555970 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp @@ -260,6 +260,8 @@ template struct Template { Template() = default; Template(const Template &Other) : Field(Other.Field) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' + // CHECK-FIXES: Template(const Template &Other) = default; Template &operator=(const Template &Other); void foo(const T &t); int Field; @@ -269,8 +271,12 @@ Template &Template::operator=(const Template &Other) { Field = Other.Field; return *this; } +// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default' +// CHECK-FIXES: Template &Template::operator=(const Template &Other) = default; + Template T1; + // Dependent types. template struct DT1 { @@ -284,6 +290,9 @@ DT1 &DT1::operator=(const DT1 &Other) { Field = Other.Field; return *this; } +// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default' +// CHECK-FIXES: DT1 &DT1::operator=(const DT1 &Other) = default; + DT1 Dt1; template @@ -303,6 +312,9 @@ DT2 &DT2::operator=(const DT2 &Other) { struct T { typedef int TT; }; +// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default' +// CHECK-FIXES: DT2 &DT2::operator=(const DT2 &Other) = default; + DT2 Dt2; // Default arguments. diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c new file mode 100644 index 0000000000000..6fb879b91e41c --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c @@ -0,0 +1,139 @@ +// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- -std=c23 + +#define NULL 0 + +void test_assignment() { + int *p1 = 0; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr [modernize-use-nullptr] + // CHECK-FIXES: int *p1 = nullptr; + p1 = 0; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr + // CHECK-FIXES: p1 = nullptr; + + int *p2 = NULL; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr + // CHECK-FIXES: int *p2 = nullptr; + + p2 = p1; + // CHECK-FIXES: p2 = p1; + + const int null = 0; + int *p3 = &null; + + p3 = NULL; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr + // CHECK-FIXES: p3 = nullptr; + + int *p4 = p3; + + int i1 = 0; + + int i2 = NULL; + + int i3 = null; + + int *p5, *p6, *p7; + p5 = p6 = p7 = NULL; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr + // CHECK-FIXES: p5 = p6 = p7 = nullptr; +} + +void test_function(int *p) {} + +void test_function_no_ptr_param(int i) {} + +void test_function_call() { + test_function(0); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr + // CHECK-FIXES: test_function(nullptr); + + test_function(NULL); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr + // CHECK-FIXES: test_function(nullptr); + + test_function_no_ptr_param(0); +} + +char *test_function_return1() { + return 0; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr + // CHECK-FIXES: return nullptr; +} + +void *test_function_return2() { + return NULL; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr + // CHECK-FIXES: return nullptr; +} + +int test_function_return4() { + return 0; +} + +int test_function_return5() { + return NULL; +} + +int *test_function_return_cast1() { + return(int)0; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr + // CHECK-FIXES: return nullptr; +} + +int *test_function_return_cast2() { +#define RET return + RET(int)0; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr + // CHECK-FIXES: RET nullptr; +#undef RET +} + +// Test parentheses expressions resulting in a nullptr. +int *test_parentheses_expression1() { + return(0); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr + // CHECK-FIXES: return(nullptr); +} + +int *test_parentheses_expression2() { + return((int)(0.0f)); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr + // CHECK-FIXES: return(nullptr); +} + +int *test_nested_parentheses_expression() { + return((((0)))); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr + // CHECK-FIXES: return((((nullptr)))); +} + +void test_const_pointers() { + const int *const_p1 = 0; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr + // CHECK-FIXES: const int *const_p1 = nullptr; + const int *const_p2 = NULL; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr + // CHECK-FIXES: const int *const_p2 = nullptr; + const int *const_p3 = (int)0; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr + // CHECK-FIXES: const int *const_p3 = nullptr; + const int *const_p4 = (int)0.0f; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr + // CHECK-FIXES: const int *const_p4 = nullptr; +} + +void test_nested_implicit_cast_expr() { + int func0(void*, void*); + int func1(int, void*, void*); + + (double)func1(0, 0, 0); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr + // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use nullptr + // CHECK-FIXES: (double)func1(0, nullptr, nullptr); + (double)func1(func0(0, 0), 0, 0); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use nullptr + // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use nullptr + // CHECK-MESSAGES: :[[@LINE-3]]:30: warning: use nullptr + // CHECK-MESSAGES: :[[@LINE-4]]:33: warning: use nullptr + // CHECK-FIXES: (double)func1(func0(nullptr, nullptr), nullptr, nullptr); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.c b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.c index c2ccbbd811715..1218b837199c0 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.c +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.c @@ -1,4 +1,4 @@ -// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- | count 0 +// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- -std=c17 | count 0 // Note: this test expects no diagnostics, but FileCheck cannot handle that, // hence the use of | count 0. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp new file mode 100644 index 0000000000000..a6045c079a482 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp @@ -0,0 +1,142 @@ +// RUN: %check_clang_tidy %s readability-math-missing-parentheses %t + +#define MACRO_AND & +#define MACRO_ADD + +#define MACRO_OR | +#define MACRO_MULTIPLY * +#define MACRO_XOR ^ +#define MACRO_SUBTRACT - +#define MACRO_DIVIDE / + +int foo(){ + return 5; +} + +int bar(){ + return 4; +} + +int sink(int); +#define FUN(ARG) (sink(ARG)) +#define FUN2(ARG) sink((ARG)) +#define FUN3(ARG) sink(ARG) +#define FUN4(ARG) sink(1 + ARG) +#define FUN5(ARG) sink(4 * ARG) + +class fun{ +public: + int A; + double B; + fun(){ + A = 5; + B = 5.4; + } +}; + +void f(){ + //CHECK-MESSAGES: :[[@LINE+2]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int a = 1 + (2 * 3); + int a = 1 + 2 * 3; + + int a_negative = 1 + (2 * 3); // No warning + + int b = 1 + 2 + 3; // No warning + + int c = 1 * 2 * 3; // No warning + + //CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+2]]:25: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int d = 1 + (2 * 3) - (4 / 5); + int d = 1 + 2 * 3 - 4 / 5; + + int d_negative = 1 + (2 * 3) - (4 / 5); // No warning + + //CHECK-MESSAGES: :[[@LINE+4]]:13: warning: '&' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '+' has higher precedence than '&'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+2]]:25: warning: '*' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int e = (1 & (2 + 3)) | (4 * 5); + int e = 1 & 2 + 3 | 4 * 5; + + int e_negative = (1 & (2 + 3)) | (4 * 5); // No warning + + //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int f = (1 * -2) + 4; + int f = 1 * -2 + 4; + + int f_negative = (1 * -2) + 4; // No warning + + //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int g = (1 * 2 * 3) + 4 + 5; + int g = 1 * 2 * 3 + 4 + 5; + + int g_negative = (1 * 2 * 3) + 4 + 5; // No warning + + //CHECK-MESSAGES: :[[@LINE+4]]:13: warning: '&' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+3]]:19: warning: '+' has higher precedence than '&'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+2]]:27: warning: '*' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int h = (120 & (2 + 3)) | (22 * 5); + int h = 120 & 2 + 3 | 22 * 5; + + int h_negative = (120 & (2 + 3)) | (22 * 5); // No warning + + int i = 1 & 2 & 3; // No warning + + int j = 1 | 2 | 3; // No warning + + int k = 1 ^ 2 ^ 3; // No warning + + //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '+' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int l = (1 + 2) ^ 3; + int l = 1 + 2 ^ 3; + + int l_negative = (1 + 2) ^ 3; // No warning + + //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int m = (2 * foo()) + bar(); + int m = 2 * foo() + bar(); + + int m_negative = (2 * foo()) + bar(); // No warning + + //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int n = (1.05 * foo()) + double(bar()); + int n = 1.05 * foo() + double(bar()); + + int n_negative = (1.05 * foo()) + double(bar()); // No warning + + //CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int o = 1 + (obj.A * 3) + obj.B; + fun obj; + int o = 1 + obj.A * 3 + obj.B; + + int o_negative = 1 + (obj.A * 3) + obj.B; // No warning + + //CHECK-MESSAGES: :[[@LINE+2]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int p = 1U + (2 * 3); + int p = 1U + 2 * 3; + + int p_negative = 1U + (2 * 3); // No warning + + //CHECK-MESSAGES: :[[@LINE+7]]:13: warning: '+' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+6]]:25: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+5]]:53: warning: '&' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+4]]:53: warning: '^' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+3]]:77: warning: '-' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-MESSAGES: :[[@LINE+2]]:94: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + //CHECK-FIXES: int q = (1 MACRO_ADD (2 MACRO_MULTIPLY 3)) MACRO_OR ((4 MACRO_AND 5) MACRO_XOR (6 MACRO_SUBTRACT (7 MACRO_DIVIDE 8))); + int q = 1 MACRO_ADD 2 MACRO_MULTIPLY 3 MACRO_OR 4 MACRO_AND 5 MACRO_XOR 6 MACRO_SUBTRACT 7 MACRO_DIVIDE 8; // No warning + + //CHECK-MESSAGES: :[[@LINE+1]]:21: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + int r = FUN(0 + 1 * 2); + + //CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + int s = FUN2(0 + 1 * 2); + + //CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + int t = FUN3(0 + 1 * 2); + + //CHECK-MESSAGES: :[[@LINE+1]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + int u = FUN4(1 * 2); + + //CHECK-MESSAGES: :[[@LINE+1]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] + int v = FUN5(0 + 1); +} diff --git a/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp b/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp index f01ebd1ec67d7..b16ec56e321bd 100644 --- a/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp +++ b/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp @@ -21,6 +21,12 @@ void foo() { // CHECK: --- // CHECK-NEXT: - Callback: PragmaDirective +// CHECK-NEXT: Loc: ":{{.+}}:1" +// CHECK-NEXT: Introducer: PIK_HashPragma +// CHECK-NEXT: - Callback: PragmaDirective +// CHECK-NEXT: Loc: ":{{.+}}:1" +// CHECK-NEXT: Introducer: PIK_HashPragma +// CHECK-NEXT: - Callback: PragmaDirective // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:3:1" // CHECK-NEXT: Introducer: PIK_HashPragma // CHECK-NEXT: - Callback: PragmaDiagnosticPush diff --git a/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp b/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp index 932b0eb93c90e..f5bf9ac2b955d 100644 --- a/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp +++ b/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp @@ -18,6 +18,12 @@ // CHECK: --- // CHECK-NEXT: - Callback: PragmaDirective +// CHECK-NEXT: Loc: ":{{.+}}:1" +// CHECK-NEXT: Introducer: PIK_HashPragma +// CHECK-NEXT: - Callback: PragmaDirective +// CHECK-NEXT: Loc: ":{{.+}}:1" +// CHECK-NEXT: Introducer: PIK_HashPragma +// CHECK-NEXT: - Callback: PragmaDirective // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:3:1" // CHECK-NEXT: Introducer: PIK_HashPragma // CHECK-NEXT: - Callback: PragmaComment @@ -67,7 +73,7 @@ // CHECK-NEXT: Introducer: PIK_HashPragma // CHECK-NEXT: - Callback: PragmaMessage // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:13:9" -// CHECK-NEXT: Namespace: +// CHECK-NEXT: Namespace: // CHECK-NEXT: Kind: PMK_Message // CHECK-NEXT: Str: message argument // CHECK-NEXT: - Callback: PragmaDirective diff --git a/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp b/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp index 31f61027994f7..ed33d37eb3d59 100644 --- a/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp +++ b/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp @@ -6,6 +6,12 @@ // CHECK: --- // CHECK-NEXT: - Callback: PragmaDirective +// CHECK-NEXT: Loc: ":{{.+}}:1" +// CHECK-NEXT: Introducer: PIK_HashPragma +// CHECK-NEXT: - Callback: PragmaDirective +// CHECK-NEXT: Loc: ":{{.+}}:1" +// CHECK-NEXT: Introducer: PIK_HashPragma +// CHECK-NEXT: - Callback: PragmaDirective // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:1" // CHECK-NEXT: Introducer: PIK_HashPragma // CHECK-NEXT: - Callback: PragmaOpenCLExtension diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 9fbf896c0e873..7f0faf9395d47 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -166,6 +166,10 @@ if(CLANG_ENABLE_LIBXML2) endif() if(CLANG_ENABLE_CIR) + if (CLANG_BUILT_STANDALONE) + message(FATAL_ERROR + "ClangIR is not yet supported in the standalone build.") + endif() if (NOT "${LLVM_ENABLE_PROJECTS}" MATCHES "MLIR|mlir") message(FATAL_ERROR "Cannot build ClangIR without MLIR in LLVM_ENABLE_PROJECTS") diff --git a/clang/cmake/caches/Release.cmake b/clang/cmake/caches/Release.cmake index bd1f688d61a7e..c0bfcbdfc1c2a 100644 --- a/clang/cmake/caches/Release.cmake +++ b/clang/cmake/caches/Release.cmake @@ -1,93 +1,94 @@ # Plain options configure the first build. # BOOTSTRAP_* options configure the second build. # BOOTSTRAP_BOOTSTRAP_* options configure the third build. +# PGO Builds have 3 stages (stage1, stage2-instrumented, stage2) +# non-PGO Builds have 2 stages (stage1, stage2) -# General Options + +function (set_final_stage_var name value type) + if (LLVM_RELEASE_ENABLE_PGO) + set(BOOTSTRAP_BOOTSTRAP_${name} ${value} CACHE ${type} "") + else() + set(BOOTSTRAP_${name} ${value} CACHE ${type} "") + endif() +endfunction() + +function (set_instrument_and_final_stage_var name value type) + # This sets the varaible for the final stage in non-PGO builds and in + # the stage2-instrumented stage for PGO builds. + set(BOOTSTRAP_${name} ${value} CACHE ${type} "") + if (LLVM_RELEASE_ENABLE_PGO) + # Set the variable in the final stage for PGO builds. + set(BOOTSTRAP_BOOTSTRAP_${name} ${value} CACHE ${type} "") + endif() +endfunction() + +# General Options: +# If you want to override any of the LLVM_RELEASE_* variables you can set them +# on the command line via -D, but you need to do this before you pass this +# cache file to CMake via -C. e.g. +# +# cmake -D LLVM_RELEASE_ENABLE_PGO=ON -C Release.cmake set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "") set(LLVM_RELEASE_ENABLE_PGO OFF CACHE BOOL "") - +set(LLVM_RELEASE_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "") +set(LLVM_RELEASE_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "") +# Note we don't need to add install here, since it is one of the pre-defined +# steps. +set(LLVM_RELEASE_FINAL_STAGE_TARGETS "clang;package;check-all;check-llvm;check-clang" CACHE STRING "") set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "") -# Stage 1 Bootstrap Setup +# Stage 1 Options +set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "") set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "") + +set(STAGE1_PROJECTS "clang") +set(STAGE1_RUNTIMES "") + if (LLVM_RELEASE_ENABLE_PGO) + list(APPEND STAGE1_PROJECTS "lld") + list(APPEND STAGE1_RUNTIMES "compiler-rt") set(CLANG_BOOTSTRAP_TARGETS generate-profdata - stage2 + stage2-package stage2-clang - stage2-distribution stage2-install - stage2-install-distribution - stage2-install-distribution-toolchain stage2-check-all stage2-check-llvm - stage2-check-clang - stage2-test-suite CACHE STRING "") -else() - set(CLANG_BOOTSTRAP_TARGETS - clang - check-all - check-llvm - check-clang - test-suite - stage3 - stage3-clang - stage3-check-all - stage3-check-llvm - stage3-check-clang - stage3-install - stage3-test-suite CACHE STRING "") -endif() + stage2-check-clang CACHE STRING "") -# Stage 1 Options -set(STAGE1_PROJECTS "clang") -set(STAGE1_RUNTIMES "") + # Configuration for stage2-instrumented + set(BOOTSTRAP_CLANG_ENABLE_BOOTSTRAP ON CACHE STRING "") + # This enables the build targets for the final stage which is called stage2. + set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS ${LLVM_RELEASE_FINAL_STAGE_TARGETS} CACHE STRING "") + set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED IR CACHE STRING "") + set(BOOTSTRAP_LLVM_ENABLE_RUNTIMES "compiler-rt" CACHE STRING "") + set(BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang;lld" CACHE STRING "") -if (LLVM_RELEASE_ENABLE_PGO) - list(APPEND STAGE1_PROJECTS "lld") - list(APPEND STAGE1_RUNTIMES "compiler-rt") +else() + if (LLVM_RELEASE_ENABLE_LTO) + list(APPEND STAGE1_PROJECTS "lld") + endif() + # Any targets added here will be given the target name stage2-${target}, so + # if you want to run them you can just use: + # ninja -C $BUILDDIR stage2-${target} + set(CLANG_BOOTSTRAP_TARGETS ${LLVM_RELEASE_FINAL_STAGE_TARGETS} CACHE STRING "") endif() +# Stage 1 Common Config set(LLVM_ENABLE_RUNTIMES ${STAGE1_RUNTIMES} CACHE STRING "") set(LLVM_ENABLE_PROJECTS ${STAGE1_PROJECTS} CACHE STRING "") -set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "") - -# Stage 2 Bootstrap Setup -set(BOOTSTRAP_CLANG_ENABLE_BOOTSTRAP ON CACHE STRING "") -set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS - clang - check-all - check-llvm - check-clang CACHE STRING "") - -# Stage 2 Options -set(STAGE2_PROJECTS "clang") -set(STAGE2_RUNTIMES "") - -if (LLVM_RELEASE_ENABLE_LTO OR LLVM_RELEASE_ENABLE_PGO) - list(APPEND STAGE2_PROJECTS "lld") -endif() - -if (LLVM_RELEASE_ENABLE_PGO) - set(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED IR CACHE STRING "") - list(APPEND STAGE2_RUNTIMES "compiler-rt") - set(BOOTSTRAP_LLVM_ENABLE_LTO ${LLVM_RELEASE_ENABLE_LTO}) - if (LLVM_RELEASE_ENABLE_LTO) - set(BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "") - endif() +# stage2-instrumented and Final Stage Config: +# Options that need to be set in both the instrumented stage (if we are doing +# a pgo build) and the final stage. +set_instrument_and_final_stage_var(CMAKE_POSITION_INDEPENDENT_CODE "ON" STRING) +set_instrument_and_final_stage_var(LLVM_ENABLE_LTO "${LLVM_RELEASE_ENABLE_LTO}" STRING) +if (LLVM_RELEASE_ENABLE_LTO) + set_instrument_and_final_stage_var(LLVM_ENABLE_LLD "ON" BOOL) endif() -set(BOOTSTRAP_LLVM_ENABLE_PROJECTS ${STAGE2_PROJECTS} CACHE STRING "") -set(BOOTSTRAP_LLVM_ENABLE_RUNTIMES ${STAGE2_RUNTIMES} CACHE STRING "") -if (NOT LLVM_RELEASE_ENABLE_PGO) - set(BOOTSTRAP_LLVM_TARGETS_TO_BUILD Native CACHE STRING "") -endif() +# Final Stage Config (stage2) +set_final_stage_var(LLVM_ENABLE_RUNTIMES "${LLVM_RELEASE_ENABLE_RUNTIMES}" STRING) +set_final_stage_var(LLVM_ENABLE_PROJECTS "${LLVM_RELEASE_ENABLE_PROJECTS}" STRING) -# Stage 3 Options -set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "") -set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "") -set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LTO ${LLVM_RELEASE_ENABLE_LTO} CACHE STRING "") -if (LLVM_RELEASE_ENABLE_LTO) - set(BOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD ON CACHE BOOL "") -endif() diff --git a/clang/cmake/caches/VectorEngine.cmake b/clang/cmake/caches/VectorEngine.cmake index e3976f3206db5..2f968a21cc407 100644 --- a/clang/cmake/caches/VectorEngine.cmake +++ b/clang/cmake/caches/VectorEngine.cmake @@ -40,6 +40,7 @@ set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_CRT OFF CACHE BOOL "") set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "") set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "") +set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_CTX_PROFILE OFF CACHE BOOL "") set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_PROFILE OFF CACHE BOOL "") set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_MEMPROF OFF CACHE BOOL "") set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_BUILD_ORC OFF CACHE BOOL "") @@ -52,6 +53,7 @@ set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_SANITIZERS OFF CACHE BOOL "" set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "") set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_PROFILE ON CACHE BOOL "") +set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_CTX_PROFILE OFF CACHE BOOL "") set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_MEMPROF OFF CACHE BOOL "") set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_ORC OFF CACHE BOOL "") set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_BUILD_GWP_ASAN OFF CACHE BOOL "") diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 2a8162680b3f1..eb0376ba6223d 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -711,6 +711,8 @@ even-odd element pair with indices ``i * 2`` and ``i * 2 + 1`` with power of 2, the vector is widened with neutral elements for the reduction at the end to the next power of 2. +These reductions support both fixed-sized and scalable vector types. + Example: .. code-block:: c++ @@ -1493,6 +1495,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C+ ``if consteval`` __cpp_if_consteval C++23 C++20 ``static operator()`` __cpp_static_call_operator C++23 C++03 Attributes on Lambda-Expressions C++23 C++11 +Attributes on Structured Bindings __cpp_structured_bindings C++26 C++03 ``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03 -------------------------------------------- -------------------------------- ------------- ------------- Designated initializers (N494) C99 C89 @@ -2928,7 +2931,7 @@ Query for this feature with ``__has_builtin(__builtin_dump_struct)`` ``__builtin_shufflevector`` is used to express generic vector permutation/shuffle/swizzle operations. This builtin is also very important for the implementation of various target-specific header files like -````. +````. This builtin can be used within constant expressions. **Syntax**: @@ -2955,7 +2958,7 @@ for the implementation of various target-specific header files like // Concatenate every other element of 8-element vectors V1 and V2. __builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14) - // Shuffle v1 with some elements being undefined + // Shuffle v1 with some elements being undefined. Not allowed in constexpr. __builtin_shufflevector(v1, v1, 3, -1, 1, -1) **Description**: @@ -2968,6 +2971,7 @@ starting with the first vector, continuing into the second vector. Thus, if ``vec1`` is a 4-element vector, index 5 would refer to the second element of ``vec2``. An index of -1 can be used to indicate that the corresponding element in the returned vector is a don't care and can be optimized by the backend. +Values of -1 are not supported in constant expressions. The result of ``__builtin_shufflevector`` is a vector with the same element type as ``vec1``/``vec2`` but that has an element count equal to the number of @@ -2982,7 +2986,8 @@ Query for this feature with ``__has_builtin(__builtin_shufflevector)``. ``__builtin_convertvector`` is used to express generic vector type-conversion operations. The input vector and the output vector -type must have the same number of elements. +type must have the same number of elements. This builtin can be used within +constant expressions. **Syntax**: @@ -5593,3 +5598,25 @@ but the expression has no runtime effects. Type- and value-dependent expressions are not supported yet. This facility is designed to aid with testing name lookup machinery. + +Predefined Macros +================= + +`__GCC_DESTRUCTIVE_SIZE` and `__GCC_CONSTRUCTIVE_SIZE` +------------------------------------------------------ +Specify the mimum offset between two objects to avoid false sharing and the +maximum size of contiguous memory to promote true sharing, respectively. These +macros are predefined in all C and C++ language modes, but can be redefined on +the command line with ``-D`` to specify different values as needed or can be +undefined on the command line with ``-U`` to disable support for the feature. + +**Note: the values the macros expand to are not guaranteed to be stable. They +are are affected by architectures and CPU tuning flags, can change between +releases of Clang and will not match the values defined by other compilers such +as GCC.** + +Compiling different TUs depending on these flags (including use of +``std::hardware_constructive_interference`` or +``std::hardware_destructive_interference``) with different compilers, macro +definitions, or architecture flags will lead to ODR violations and should be +avoided. \ No newline at end of file diff --git a/clang/docs/LibTooling.rst b/clang/docs/LibTooling.rst index df50dcebf9b83..87d84321ab283 100644 --- a/clang/docs/LibTooling.rst +++ b/clang/docs/LibTooling.rst @@ -63,15 +63,22 @@ and automatic location of the compilation database using source files paths. #include "llvm/Support/CommandLine.h" using namespace clang::tooling; + using namespace llvm; // Apply a custom category to all command-line options so that they are the // only ones displayed. - static llvm::cl::OptionCategory MyToolCategory("my-tool options"); + static cl::OptionCategory MyToolCategory("my-tool options"); int main(int argc, const char **argv) { - // CommonOptionsParser constructor will parse arguments and create a - // CompilationDatabase. In case of error it will terminate the program. - CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); + // CommonOptionsParser::create will parse arguments and create a + // CompilationDatabase. + auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory); + if (!ExpectedParser) { + // Fail gracefully for unsupported options. + llvm::errs() << ExpectedParser.takeError(); + return 1; + } + CommonOptionsParser& OptionsParser = ExpectedParser.get(); // Use OptionsParser.getCompilations() and OptionsParser.getSourcePathList() // to retrieve CompilationDatabase and the list of input file paths. @@ -133,7 +140,12 @@ version of this example tool is also checked into the clang tree at static cl::extrahelp MoreHelp("\nMore help text...\n"); int main(int argc, const char **argv) { - CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); + auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory); + if (!ExpectedParser) { + llvm::errs() << ExpectedParser.takeError(); + return 1; + } + CommonOptionsParser& OptionsParser = ExpectedParser.get(); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); return Tool.run(newFrontendActionFactory().get()); diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index f8146bc365e83..5e63b2c0f0be6 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -310,7 +310,9 @@ implementation. +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc | dispatch construct and function variant argument adjustment | :part:`worked on` | D99537, D99679 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ -| misc | assume and assumes directives | :part:`worked on` | | +| misc | assumes directives | :part:`worked on` | | ++------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ +| misc | assume directive | :part:`worked on` | | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc | nothing directive | :good:`done` | D123286 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 64526ed6d06f5..2c5308fbcb319 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -63,6 +63,12 @@ ABI Changes in This Version MSVC uses a different mangling for these objects, compatibility is not affected. (#GH85423). +- Fixed Microsoft calling convention for returning certain classes with a + templated constructor. If a class has a templated constructor, it should + be returned indirectly even if it meets all the other requirements for + returning a class in a register. This affects some uses of std::pair. + (#GH86384). + AST Dumping Potentially Breaking Changes ---------------------------------------- @@ -90,6 +96,18 @@ C++ Language Changes -------------------- - Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223). +C++17 Feature Support +^^^^^^^^^^^^^^^^^^^^^ +- Clang now exposes ``__GCC_DESTRUCTIVE_SIZE`` and ``__GCC_CONSTRUCTIVE_SIZE`` + predefined macros to support standard library implementations of + ``std::hardware_destructive_interference_size`` and + ``std::hardware_constructive_interference_size``, respectively. These macros + are predefined in all C and C++ language modes. The values the macros + expand to are not stable between releases of Clang and do not need to match + the values produced by GCC, so these macros should not be used from header + files because they may not be stable across multiple TUs (the values may vary + based on compiler version as well as CPU tuning). #GH60174 + C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -131,6 +149,9 @@ C++2c Feature Support - Implemented `P2573R2: = delete("should have a reason"); `_ +- Implemented `P0609R3: Attributes for Structured Bindings `_ + +- Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary `_. Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -207,6 +228,20 @@ Non-comprehensive list of changes in this release - ``__typeof_unqual__`` is available in all C modes as an extension, which behaves like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``. +- ``__builtin_reduce_{add|mul|xor|or|and|min|max}`` builtins now support scalable vectors. + +* Shared libraries linked with either the ``-ffast-math``, ``-Ofast``, or + ``-funsafe-math-optimizations`` flags will no longer enable flush-to-zero + floating-point mode by default. This decision can be overridden with use of + ``-mdaz-ftz``. This behavior now matches GCC's behavior. + (`#57589 `_) + +* ``-fdenormal-fp-math=preserve-sign`` is no longer implied by ``-ffast-math`` + on x86 systems. + +- Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may + now be used within constant expressions. + New Compiler Flags ------------------ - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and @@ -221,6 +256,10 @@ New Compiler Flags - ``-fexperimental-modules-reduced-bmi`` enables the Reduced BMI for C++20 named modules. See the document of standard C++ modules for details. +- ``-fexperimental-late-parse-attributes`` enables an experimental feature to + allow late parsing certain attributes in specific contexts where they would + not normally be late parsed. + Deprecated Compiler Flags ------------------------- @@ -375,6 +414,18 @@ Improvements to Clang's diagnostics - Clang now diagnoses requires expressions with explicit object parameters. +- Clang now looks up members of the current instantiation in the template definition context + if the current instantiation has no dependent base classes. + + .. code-block:: c++ + + template + struct A { + int f() { + return this->x; // error: no member named 'x' in 'A' + } + }; + Improvements to Clang's time-trace ---------------------------------- @@ -421,6 +472,9 @@ Bug Fixes in This Version - Clang now correctly generates overloads for bit-precise integer types for builtin operators in C++. Fixes #GH82998. +- Fix crash when destructor definition is preceded with an equals sign. + Fixes (#GH89544). + - When performing mixed arithmetic between ``_Complex`` floating-point types and integers, Clang now correctly promotes the integer to its corresponding real floating-point type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated @@ -436,6 +490,10 @@ Bug Fixes in This Version - Fixed an assertion failure on invalid InitListExpr in C89 mode (#GH88008). +- Fixed missing destructor calls when we branch from middle of an expression. + This could happen through a branch in stmt-expr or in an expression containing a coroutine + suspension. Fixes (#GH63818) (#GH88478). + - Clang will no longer diagnose an erroneous non-dependent ``switch`` condition during instantiation, and instead will only diagnose it once, during checking of the function template. @@ -564,6 +622,14 @@ Bug Fixes to C++ Support - Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()`` function returns a large or negative value. Fixes (#GH89407). - Fixed a use-after-free bug in parsing of type constraints with default arguments that involve lambdas. (#GH67235) +- Fixed bug in which the body of a consteval lambda within a template was not parsed as within an + immediate function context. +- Fix CTAD for ``std::initializer_list``. This allows ``std::initializer_list{1, 2, 3}`` to be deduced as + ``std::initializer_list`` as intended. +- Fix a bug on template partial specialization whose template parameter is `decltype(auto)`. +- Fix a bug on template partial specialization with issue on deduction of nontype template parameter + whose type is `decltype(auto)`. Fixes (#GH68885). +- Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,6 +682,10 @@ Arm and AArch64 Support * Arm Cortex-A78AE (cortex-a78ae). * Arm Cortex-A520AE (cortex-a520ae). * Arm Cortex-A720AE (cortex-a720ae). + * Arm Cortex-R82AE (cortex-r82ae). + * Arm Neoverse-N3 (neoverse-n3). + * Arm Neoverse-V3 (neoverse-v3). + * Arm Neoverse-V3AE (neoverse-v3ae). Android Support ^^^^^^^^^^^^^^^ @@ -672,6 +742,11 @@ AIX Support WebAssembly Support ^^^^^^^^^^^^^^^^^^^ +The -mcpu=generic configuration now enables multivalue and reference-types.These +proposals are standardized and available in all major engines. Enabling +multivalue here only enables the language feature but does not turn on the +multivalue ABI (this enables non-ABI uses of multivalue, like exnref). + AVR Support ^^^^^^^^^^^ @@ -710,6 +785,9 @@ clang-format libclang -------- +- ``clang_getSpellingLocation`` now correctly resolves macro expansions; that + is, it returns the spelling location instead of the expansion location. + Static Analyzer --------------- diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 8df40566fcba3..370de7d9c769e 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1452,8 +1452,6 @@ floating point semantic models: precise (the default), strict, and fast. "fenv_access", "off", "on", "off" "rounding_mode", "tonearest", "dynamic", "tonearest" "contract", "on", "off", "fast" - "denormal_fp_math", "IEEE", "IEEE", "IEEE" - "denormal_fp32_math", "IEEE","IEEE", "IEEE" "support_math_errno", "on", "on", "off" "no_honor_nans", "off", "off", "on" "no_honor_infinities", "off", "off", "on" @@ -1462,6 +1460,14 @@ floating point semantic models: precise (the default), strict, and fast. "allow_approximate_fns", "off", "off", "on" "allow_reassociation", "off", "off", "on" +The ``-ffp-model`` option does not modify the ``fdenormal-fp-math`` +setting, but it does have an impact on whether ``crtfastmath.o`` is +linked. Because linking ``crtfastmath.o`` has a global effect on the +program, and because the global denormal handling can be changed in +other ways, the state of ``fdenormal-fp-math`` handling cannot +be assumed in any function based on fp-model. See :ref:`crtfastmath.o` +for more details. + .. option:: -ffast-math Enable fast-math mode. This option lets the @@ -1506,7 +1512,8 @@ floating point semantic models: precise (the default), strict, and fast. * ``-ffp-contract=fast`` - Note: ``-ffast-math`` causes ``crtfastmath.o`` to be linked with code. See + Note: ``-ffast-math`` causes ``crtfastmath.o`` to be linked with code unless + ``-shared`` or ``-mno-daz-ftz`` is present. See :ref:`crtfastmath.o` for more details. .. option:: -fno-fast-math @@ -1536,7 +1543,6 @@ floating point semantic models: precise (the default), strict, and fast. Also, this option resets following options to their target-dependent defaults. * ``-f[no-]math-errno`` - * ``-fdenormal-fp-math=`` There is ambiguity about how ``-ffp-contract``, ``-ffast-math``, and ``-fno-fast-math`` behave when combined. To keep the value of @@ -1559,8 +1565,8 @@ floating point semantic models: precise (the default), strict, and fast. ``-ffp-contract`` setting is determined by the default value of ``-ffp-contract``. - Note: ``-fno-fast-math`` implies ``-fdenormal-fp-math=ieee``. - ``-fno-fast-math`` causes ``crtfastmath.o`` to not be linked with code. + Note: ``-fno-fast-math`` causes ``crtfastmath.o`` to not be linked with code + unless ``-mdaz-ftz`` is present. .. option:: -fdenormal-fp-math= @@ -1690,9 +1696,7 @@ floating point semantic models: precise (the default), strict, and fast. * ``-fno-associative-math`` * ``-fno-reciprocal-math`` * ``-fsigned-zeros`` - * ``-ftrapping-math`` * ``-ffp-contract=on`` - * ``-fdenormal-fp-math=ieee`` There is ambiguity about how ``-ffp-contract``, ``-funsafe-math-optimizations``, and ``-fno-unsafe-math-optimizations`` @@ -1938,10 +1942,13 @@ by using ``#pragma STDC FENV_ROUND`` with a value other than ``FE_DYNAMIC``. A note about ``crtfastmath.o`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``-ffast-math`` and ``-funsafe-math-optimizations`` cause ``crtfastmath.o`` to be -automatically linked, which adds a static constructor that sets the FTZ/DAZ +``-ffast-math`` and ``-funsafe-math-optimizations`` without the ``-shared`` +option cause ``crtfastmath.o`` to be +automatically linked, which adds a static constructor that sets the FTZ/DAZ bits in MXCSR, affecting not only the current compilation unit but all static -and shared libraries included in the program. +and shared libraries included in the program. This decision can be overridden +by using either the flag ``-mdaz-ftz`` or ``-mno-daz-ftz`` to respectively +link or not link ``crtfastmath.o``. .. _FLT_EVAL_METHOD: @@ -2314,6 +2321,8 @@ are listed below. on ELF targets when using the integrated assembler. This flag currently only has an effect on ELF targets. +.. _funique_internal_linkage_names: + .. option:: -f[no]-unique-internal-linkage-names Controls whether Clang emits a unique (best-effort) symbol name for internal @@ -2443,27 +2452,41 @@ usual build cycle when using sample profilers for optimization: usual build flags that you always build your application with. The only requirement is that DWARF debug info including source line information is generated. This DWARF information is important for the profiler to be able - to map instructions back to source line locations. + to map instructions back to source line locations. The usefulness of this + DWARF information can be improved with the ``-fdebug-info-for-profiling`` + and ``-funique-internal-linkage-names`` options. - On Linux, ``-g`` or just ``-gline-tables-only`` is sufficient: + On Linux: .. code-block:: console - $ clang++ -O2 -gline-tables-only code.cc -o code + $ clang++ -O2 -gline-tables-only \ + -fdebug-info-for-profiling -funique-internal-linkage-names \ + code.cc -o code While MSVC-style targets default to CodeView debug information, DWARF debug information is required to generate source-level LLVM profiles. Use ``-gdwarf`` to include DWARF debug information: - .. code-block:: console + .. code-block:: winbatch + + > clang-cl /O2 -gdwarf -gline-tables-only ^ + /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^ + code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf - $ clang-cl -O2 -gdwarf -gline-tables-only coff-profile.cpp -fuse-ld=lld -link -debug:dwarf +.. note:: + + :ref:`-funique-internal-linkage-names ` + generates unique names based on given command-line source file paths. If + your build system uses absolute source paths and these paths may change + between steps 1 and 4, then the uniqued function names may change and result + in unused profile data. Consider omitting this option in such cases. 2. Run the executable under a sampling profiler. The specific profiler you use does not really matter, as long as its output can be converted into the format that the LLVM optimizer understands. - Two such profilers are the the Linux Perf profiler + Two such profilers are the Linux Perf profiler (https://perf.wiki.kernel.org/) and Intel's Sampling Enabling Product (SEP), available as part of `Intel VTune `_. @@ -2477,7 +2500,9 @@ usual build cycle when using sample profilers for optimization: .. code-block:: console - $ perf record -b ./code + $ perf record -b -e BR_INST_RETIRED.NEAR_TAKEN:uppp ./code + + If the event above is unavailable, ``branches:u`` is probably next-best. Note the use of the ``-b`` flag. This tells Perf to use the Last Branch Record (LBR) to record call chains. While this is not strictly required, @@ -2527,21 +2552,42 @@ usual build cycle when using sample profilers for optimization: that executes faster than the original one. Note that you are not required to build the code with the exact same arguments that you used in the first step. The only requirement is that you build the code - with ``-gline-tables-only`` and ``-fprofile-sample-use``. + with the same debug info options and ``-fprofile-sample-use``. + + On Linux: .. code-block:: console - $ clang++ -O2 -gline-tables-only -fprofile-sample-use=code.prof code.cc -o code + $ clang++ -O2 -gline-tables-only \ + -fdebug-info-for-profiling -funique-internal-linkage-names \ + -fprofile-sample-use=code.prof code.cc -o code - [OPTIONAL] Sampling-based profiles can have inaccuracies or missing block/ - edge counters. The profile inference algorithm (profi) can be used to infer - missing blocks and edge counts, and improve the quality of profile data. - Enable it with ``-fsample-profile-use-profi``. + On Windows: - .. code-block:: console + .. code-block:: winbatch + + > clang-cl /O2 -gdwarf -gline-tables-only ^ + /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^ + /fprofile-sample-use=code.prof code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf + + [OPTIONAL] Sampling-based profiles can have inaccuracies or missing block/ + edge counters. The profile inference algorithm (profi) can be used to infer + missing blocks and edge counts, and improve the quality of profile data. + Enable it with ``-fsample-profile-use-profi``. For example, on Linux: + + .. code-block:: console + + $ clang++ -fsample-profile-use-profi -O2 -gline-tables-only \ + -fdebug-info-for-profiling -funique-internal-linkage-names \ + -fprofile-sample-use=code.prof code.cc -o code + + On Windows: + + .. code-block:: winbatch - $ clang++ -O2 -gline-tables-only -fprofile-sample-use=code.prof \ - -fsample-profile-use-profi code.cc -o code + > clang-cl /clang:-fsample-profile-use-profi /O2 -gdwarf -gline-tables-only ^ + /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^ + /fprofile-sample-use=code.prof code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf Sample Profile Formats """""""""""""""""""""" diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index fb748d23a53d0..0d87df36ced0e 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1462,6 +1462,99 @@ checker). Default value of the option is ``true``. +.. _unix-Stream: + +unix.Stream (C) +""""""""""""""" +Check C stream handling functions: +``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``. + +The checker maintains information about the C stream objects (``FILE *``) and +can detect error conditions related to use of streams. The following conditions +are detected: + +* The ``FILE *`` pointer passed to the function is NULL (the single exception is + ``fflush`` where NULL is allowed). +* Use of stream after close. +* Opened stream is not closed. +* Read from a stream after end-of-file. (This is not a fatal error but reported + by the checker. Stream remains in EOF state and the read operation fails.) +* Use of stream when the file position is indeterminate after a previous failed + operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are + allowed in this state. +* Invalid 3rd ("``whence``") argument to ``fseek``. + +The stream operations are by this checker usually split into two cases, a success +and a failure case. However, in the case of write operations (like ``fwrite``, +``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of +unwanted reports on projects that don't have error checks around the write +operations, so by default the checker assumes that write operations always succeed. +This behavior can be controlled by the ``Pedantic`` flag: With +``-analyzer-config unix.Stream:Pedantic=true`` the checker will model the +cases where a write operation fails and report situations where this leads to +erroneous behavior. (The default is ``Pedantic=false``, where write operations +are assumed to succeed.) + +.. code-block:: c + + void test1() { + FILE *p = fopen("foo", "r"); + } // warn: opened file is never closed + + void test2() { + FILE *p = fopen("foo", "r"); + fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL + fclose(p); + } + + void test3() { + FILE *p = fopen("foo", "r"); + if (p) { + fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR + fclose(p); + } + } + + void test4() { + FILE *p = fopen("foo", "r"); + if (!p) + return; + + fclose(p); + fclose(p); // warn: stream already closed + } + + void test5() { + FILE *p = fopen("foo", "r"); + if (!p) + return; + + fgetc(p); + if (!ferror(p)) + fgetc(p); // warn: possible read after end-of-file + + fclose(p); + } + + void test6() { + FILE *p = fopen("foo", "r"); + if (!p) + return; + + fgetc(p); + if (!feof(p)) + fgetc(p); // warn: file position may be indeterminate after I/O error + + fclose(p); + } + +**Limitations** + +The checker does not track the correspondence between integer file descriptors +and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not +treated specially and are therefore often not recognized (because these streams +are usually not opened explicitly by the program, and are global variables). + .. _osx-checkers: osx @@ -3116,99 +3209,6 @@ Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fcl fclose(F); // warn: closing a previously closed file stream } -.. _alpha-unix-Stream: - -alpha.unix.Stream (C) -""""""""""""""""""""" -Check C stream handling functions: -``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``. - -The checker maintains information about the C stream objects (``FILE *``) and -can detect error conditions related to use of streams. The following conditions -are detected: - -* The ``FILE *`` pointer passed to the function is NULL (the single exception is - ``fflush`` where NULL is allowed). -* Use of stream after close. -* Opened stream is not closed. -* Read from a stream after end-of-file. (This is not a fatal error but reported - by the checker. Stream remains in EOF state and the read operation fails.) -* Use of stream when the file position is indeterminate after a previous failed - operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are - allowed in this state. -* Invalid 3rd ("``whence``") argument to ``fseek``. - -The stream operations are by this checker usually split into two cases, a success -and a failure case. However, in the case of write operations (like ``fwrite``, -``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of -unwanted reports on projects that don't have error checks around the write -operations, so by default the checker assumes that write operations always succeed. -This behavior can be controlled by the ``Pedantic`` flag: With -``-analyzer-config alpha.unix.Stream:Pedantic=true`` the checker will model the -cases where a write operation fails and report situations where this leads to -erroneous behavior. (The default is ``Pedantic=false``, where write operations -are assumed to succeed.) - -.. code-block:: c - - void test1() { - FILE *p = fopen("foo", "r"); - } // warn: opened file is never closed - - void test2() { - FILE *p = fopen("foo", "r"); - fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL - fclose(p); - } - - void test3() { - FILE *p = fopen("foo", "r"); - if (p) { - fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR - fclose(p); - } - } - - void test4() { - FILE *p = fopen("foo", "r"); - if (!p) - return; - - fclose(p); - fclose(p); // warn: stream already closed - } - - void test5() { - FILE *p = fopen("foo", "r"); - if (!p) - return; - - fgetc(p); - if (!ferror(p)) - fgetc(p); // warn: possible read after end-of-file - - fclose(p); - } - - void test6() { - FILE *p = fopen("foo", "r"); - if (!p) - return; - - fgetc(p); - if (!feof(p)) - fgetc(p); // warn: file position may be indeterminate after I/O error - - fclose(p); - } - -**Limitations** - -The checker does not track the correspondence between integer file descriptors -and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not -treated specially and are therefore often not recognized (because these streams -are usually not opened explicitly by the program, and are global variables). - .. _alpha-unix-cstring-BufferOverlap: alpha.unix.cstring.BufferOverlap (C) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 0c9c661b2baec..8de64454bb678 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -1644,8 +1644,9 @@ enum CXCursorKind { CXCursor_ObjCSelfExpr = 146, /** OpenMP 5.0 [2.1.5, Array Section]. + * OpenACC 3.3 [2.7.1, Data Specification for Data Clauses (Sub Arrays)] */ - CXCursor_OMPArraySectionExpr = 147, + CXCursor_ArraySectionExpr = 147, /** Represents an @available(...) check. */ diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index 93bb045d6a667..026a4a431e734 100644 --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -675,6 +675,11 @@ class TagInfo : public CommonTypeInfo { LLVM_PREFERRED_TYPE(bool) unsigned IsFlagEnum : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned SwiftCopyableSpecified : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned SwiftCopyable : 1; + public: std::optional SwiftImportAs; std::optional SwiftRetainOp; @@ -682,7 +687,9 @@ class TagInfo : public CommonTypeInfo { std::optional EnumExtensibility; - TagInfo() : HasFlagEnum(0), IsFlagEnum(0) {} + TagInfo() + : HasFlagEnum(0), IsFlagEnum(0), SwiftCopyableSpecified(false), + SwiftCopyable(false) {} std::optional isFlagEnum() const { if (HasFlagEnum) @@ -694,6 +701,15 @@ class TagInfo : public CommonTypeInfo { IsFlagEnum = Value.value_or(false); } + std::optional isSwiftCopyable() const { + return SwiftCopyableSpecified ? std::optional(SwiftCopyable) + : std::nullopt; + } + void setSwiftCopyable(std::optional Value) { + SwiftCopyableSpecified = Value.has_value(); + SwiftCopyable = Value.value_or(false); + } + TagInfo &operator|=(const TagInfo &RHS) { static_cast(*this) |= RHS; @@ -710,6 +726,9 @@ class TagInfo : public CommonTypeInfo { if (!EnumExtensibility) EnumExtensibility = RHS.EnumExtensibility; + if (!SwiftCopyableSpecified) + setSwiftCopyable(RHS.isSwiftCopyable()); + return *this; } @@ -724,6 +743,7 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) { LHS.SwiftRetainOp == RHS.SwiftRetainOp && LHS.SwiftReleaseOp == RHS.SwiftReleaseOp && LHS.isFlagEnum() == RHS.isFlagEnum() && + LHS.isSwiftCopyable() == RHS.isSwiftCopyable() && LHS.EnumExtensibility == RHS.EnumExtensibility; } diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index e591adc76f94d..1f371bc1230d4 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -455,7 +455,7 @@ class ASTContext : public RefCountedBase { /// initialization of another module). struct PerModuleInitializers { llvm::SmallVector Initializers; - llvm::SmallVector LazyInitializers; + llvm::SmallVector LazyInitializers; void resolve(ASTContext &Ctx); }; @@ -1059,7 +1059,7 @@ class ASTContext : public RefCountedBase { /// or an ImportDecl nominating another module that has initializers. void addModuleInitializer(Module *M, Decl *Init); - void addLazyModuleInitializers(Module *M, ArrayRef IDs); + void addLazyModuleInitializers(Module *M, ArrayRef IDs); /// Get the initializations to perform when importing a module, if any. ArrayRef getModuleInitializers(Module *M); @@ -1132,7 +1132,8 @@ class ASTContext : public RefCountedBase { CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLQueueTy, OCLReserveIDTy; CanQualType IncompleteMatrixIdxTy; - CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy; + CanQualType ArraySectionTy; + CanQualType OMPArrayShapingTy, OMPIteratorTy; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ CanQualType Id##Ty; #include "clang/Basic/OpenCLExtensionTypes.def" @@ -2201,6 +2202,16 @@ class ASTContext : public RefCountedBase { return getQualifiedType(type.getUnqualifiedType(), Qs); } + /// \brief Return a type with the given __ptrauth qualifier. + QualType getPointerAuthType(QualType Ty, PointerAuthQualifier PointerAuth) { + assert(!Ty.getPointerAuth()); + assert(PointerAuth); + + Qualifiers Qs; + Qs.setPointerAuth(PointerAuth); + return getQualifiedType(Ty, Qs); + } + unsigned char getFixedPointScale(QualType Ty) const; unsigned char getFixedPointIBits(QualType Ty) const; llvm::FixedPointSemantics getFixedPointSemantics(QualType Ty) const; diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 216dc9eef08b6..bf7c204e4ad73 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -844,6 +844,12 @@ class ASTNodeTraverser } } + void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *E) { + if (E->hasExplicitTemplateArgs()) + for (auto Arg : E->template_arguments()) + Visit(Arg.getArgument()); + } + void VisitRequiresExpr(const RequiresExpr *E) { for (auto *D : E->getLocalParameters()) Visit(D); diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index 1f2797cc70145..ab036f1d445ac 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -213,9 +213,9 @@ class DataStreamBasicReader : public BasicReaderBase { } Qualifiers readQualifiers() { - static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t), + static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint64_t), "update this if the value size changes"); - uint32_t value = asImpl().readUInt32(); + uint64_t value = asImpl().readUInt64(); return Qualifiers::fromOpaqueValue(value); } diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index 07afa388de2c1..8e42fcaad1d38 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -196,9 +196,9 @@ class DataStreamBasicWriter : public BasicWriterBase { } void writeQualifiers(Qualifiers value) { - static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t), + static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t), "update this if the value size changes"); - asImpl().writeUInt32(value.getAsOpaqueValue()); + asImpl().writeUInt64(value.getAsOpaqueValue()); } void writeExceptionSpecInfo( diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index c04f6f6f12719..0a36fdc5d9c0f 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -320,7 +320,7 @@ PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) PLACEHOLDER_TYPE(IncompleteMatrixIdx, IncompleteMatrixIdxTy) // A placeholder type for OpenMP array sections. -PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy) +PLACEHOLDER_TYPE(ArraySection, ArraySectionTy) // A placeholder type for OpenMP array shaping operation. PLACEHOLDER_TYPE(OMPArrayShaping, OMPArrayShapingTy) diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 6f3da2dad8d55..3f3ae14716af6 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -95,7 +95,7 @@ class DesignatedInitExpr; class ParenListExpr; class PseudoObjectExpr; class AtomicExpr; -class OMPArraySectionExpr; +class ArraySectionExpr; class OMPArrayShapingExpr; class OMPIteratorExpr; class ObjCArrayLiteral; @@ -195,7 +195,7 @@ ExprDependence computeDependence(ParenListExpr *E); ExprDependence computeDependence(PseudoObjectExpr *E); ExprDependence computeDependence(AtomicExpr *E); -ExprDependence computeDependence(OMPArraySectionExpr *E); +ExprDependence computeDependence(ArraySectionExpr *E); ExprDependence computeDependence(OMPArrayShapingExpr *E); ExprDependence computeDependence(OMPIteratorExpr *E); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index ba3aed72febd0..d6a42de59419c 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -157,7 +157,7 @@ class PragmaCommentDecl final SourceLocation CommentLoc, PragmaMSCommentKind CommentKind, StringRef Arg); - static PragmaCommentDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static PragmaCommentDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned ArgSize); PragmaMSCommentKind getCommentKind() const { return CommentKind; } @@ -192,7 +192,7 @@ class PragmaDetectMismatchDecl final SourceLocation Loc, StringRef Name, StringRef Value); static PragmaDetectMismatchDecl * - CreateDeserialized(ASTContext &C, DeclID ID, unsigned NameValueSize); + CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NameValueSize); StringRef getName() const { return getTrailingObjects(); } StringRef getValue() const { return getTrailingObjects() + ValueStart; } @@ -519,7 +519,7 @@ class LabelDecl : public NamedDecl { static LabelDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, SourceLocation GnuLabelL); - static LabelDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static LabelDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); LabelStmt *getStmt() const { return TheStmt; } void setStmt(LabelStmt *T) { TheStmt = T; } @@ -582,7 +582,7 @@ class NamespaceDecl : public NamedDecl, public DeclContext, IdentifierInfo *Id, NamespaceDecl *PrevDecl, bool Nested); - static NamespaceDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static NamespaceDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); using redecl_range = redeclarable_base::redecl_range; using redecl_iterator = redeclarable_base::redecl_iterator; @@ -1147,7 +1147,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S); - static VarDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static VarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -1729,7 +1729,7 @@ class ImplicitParamDecl : public VarDecl { static ImplicitParamDecl *Create(ASTContext &C, QualType T, ImplicitParamKind ParamKind); - static ImplicitParamDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ImplicitParamDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *Id, QualType Type, @@ -1783,7 +1783,7 @@ class ParmVarDecl : public VarDecl { TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg); - static ParmVarDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ParmVarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -2179,7 +2179,7 @@ class FunctionDecl : public DeclaratorDecl, bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause); - static FunctionDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); DeclarationNameInfo getNameInfo() const { return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); @@ -3137,7 +3137,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable { TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle); - static FieldDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static FieldDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Returns the index of this field within its record, /// as appropriate for passing to ASTRecordLayout::getFieldOffset. @@ -3312,7 +3312,7 @@ class EnumConstantDecl : public ValueDecl, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E, const llvm::APSInt &V); - static EnumConstantDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static EnumConstantDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); const Expr *getInitExpr() const { return (const Expr*) Init; } Expr *getInitExpr() { return (Expr*) Init; } @@ -3358,7 +3358,7 @@ class IndirectFieldDecl : public ValueDecl, QualType T, llvm::MutableArrayRef CH); - static IndirectFieldDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static IndirectFieldDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); using chain_iterator = ArrayRef::const_iterator; @@ -3543,7 +3543,7 @@ class TypedefDecl : public TypedefNameDecl { static TypedefDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, TypeSourceInfo *TInfo); - static TypedefDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static TypedefDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -3568,7 +3568,7 @@ class TypeAliasDecl : public TypedefNameDecl { static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, TypeSourceInfo *TInfo); - static TypeAliasDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static TypeAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -3978,7 +3978,7 @@ class EnumDecl : public TagDecl { IdentifierInfo *Id, EnumDecl *PrevDecl, bool IsScoped, bool IsScopedUsingClassTag, bool IsFixed); - static EnumDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static EnumDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Overrides to provide correct range when there's an enum-base specifier /// with forward declarations. @@ -4183,7 +4183,7 @@ class RecordDecl : public TagDecl { static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr); - static RecordDecl *CreateDeserialized(const ASTContext &C, DeclID ID); + static RecordDecl *CreateDeserialized(const ASTContext &C, GlobalDeclID ID); RecordDecl *getPreviousDecl() { return cast_or_null( @@ -4434,7 +4434,7 @@ class FileScopeAsmDecl : public Decl { StringLiteral *Str, SourceLocation AsmLoc, SourceLocation RParenLoc); - static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceLocation getAsmLoc() const { return getLocation(); } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -4470,7 +4470,7 @@ class TopLevelStmtDecl : public Decl, public DeclContext { public: static TopLevelStmtDecl *Create(ASTContext &C, Stmt *Statement); - static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; Stmt *getStmt() { return Statement; } @@ -4564,7 +4564,7 @@ class BlockDecl : public Decl, public DeclContext { public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); - static BlockDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static BlockDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceLocation getCaretLocation() const { return getLocation(); } @@ -4718,7 +4718,7 @@ class CapturedDecl final static CapturedDecl *Create(ASTContext &C, DeclContext *DC, unsigned NumParams); - static CapturedDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static CapturedDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumParams); Stmt *getBody() const override; @@ -4852,7 +4852,7 @@ class ImportDecl final : public Decl, SourceLocation EndLoc); /// Create a new, deserialized module import declaration. - static ImportDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static ImportDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumLocations); /// Retrieve the module that was imported by the import declaration. @@ -4893,7 +4893,7 @@ class ExportDecl final : public Decl, public DeclContext { public: static ExportDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation ExportLoc); - static ExportDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ExportDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceLocation getExportLoc() const { return getLocation(); } SourceLocation getRBraceLoc() const { return RBraceLoc; } @@ -4932,7 +4932,7 @@ class EmptyDecl : public Decl { public: static EmptyDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); - static EmptyDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static EmptyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Empty; } @@ -4958,7 +4958,7 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace); - static HLSLBufferDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(getLocStart(), RBraceLoc); diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index d8cafc3d81526..e43e812cd9455 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -15,6 +15,7 @@ #include "clang/AST/ASTDumperUtils.h" #include "clang/AST/AttrIterator.h" +#include "clang/AST/DeclID.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/SelectorLocationsKind.h" #include "clang/Basic/IdentifierTable.h" @@ -239,9 +240,6 @@ class alignas(8) Decl { ModulePrivate }; - /// An ID number that refers to a declaration in an AST file. - using DeclID = uint32_t; - protected: /// The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is @@ -361,7 +359,7 @@ class alignas(8) Decl { /// \param Ctx The context in which we will allocate memory. /// \param ID The global ID of the deserialized declaration. /// \param Extra The amount of extra space to allocate after the object. - void *operator new(std::size_t Size, const ASTContext &Ctx, DeclID ID, + void *operator new(std::size_t Size, const ASTContext &Ctx, GlobalDeclID ID, std::size_t Extra = 0); /// Allocate memory for a non-deserialized declaration. @@ -779,10 +777,10 @@ class alignas(8) Decl { /// Retrieve the global declaration ID associated with this /// declaration, which specifies where this Decl was loaded from. - DeclID getGlobalID() const { + GlobalDeclID getGlobalID() const { if (isFromASTFile()) - return *((const DeclID *)this - 1); - return 0; + return (*((const GlobalDeclID *)this - 1)); + return GlobalDeclID(); } /// Retrieve the global ID of the module that owns this particular diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index a7644d2a19d24..fb52ac804849d 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -120,7 +120,7 @@ class AccessSpecDecl : public Decl { return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); } - static AccessSpecDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static AccessSpecDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -579,7 +579,8 @@ class CXXRecordDecl : public RecordDecl { TypeSourceInfo *Info, SourceLocation Loc, unsigned DependencyKind, bool IsGeneric, LambdaCaptureDefault CaptureDefault); - static CXXRecordDecl *CreateDeserialized(const ASTContext &C, DeclID ID); + static CXXRecordDecl *CreateDeserialized(const ASTContext &C, + GlobalDeclID ID); bool isDynamicClass() const { return data().Polymorphic || data().NumVBases != 0; @@ -1980,7 +1981,8 @@ class CXXDeductionGuideDecl : public FunctionDecl { CXXConstructorDecl *Ctor = nullptr, DeductionCandidate Kind = DeductionCandidate::Normal); - static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); ExplicitSpecifier getExplicitSpecifier() { return ExplicitSpec; } const ExplicitSpecifier getExplicitSpecifier() const { return ExplicitSpec; } @@ -2035,7 +2037,8 @@ class RequiresExprBodyDecl : public Decl, public DeclContext { static RequiresExprBodyDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc); - static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -2078,7 +2081,7 @@ class CXXMethodDecl : public FunctionDecl { ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, Expr *TrailingRequiresClause = nullptr); - static CXXMethodDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); bool isStatic() const; bool isInstance() const { return !isStatic(); } @@ -2579,7 +2582,7 @@ class CXXConstructorDecl final friend class ASTDeclWriter; friend TrailingObjects; - static CXXConstructorDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, uint64_t AllocKind); static CXXConstructorDecl * Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, @@ -2822,7 +2825,7 @@ class CXXDestructorDecl : public CXXMethodDecl { bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause = nullptr); - static CXXDestructorDecl *CreateDeserialized(ASTContext & C, DeclID ID); + static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg); @@ -2881,7 +2884,7 @@ class CXXConversionDecl : public CXXMethodDecl { bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, Expr *TrailingRequiresClause = nullptr); - static CXXConversionDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); ExplicitSpecifier getExplicitSpecifier() { return getCanonicalDecl()->ExplicitSpec; @@ -2948,7 +2951,7 @@ class LinkageSpecDecl : public Decl, public DeclContext { SourceLocation ExternLoc, SourceLocation LangLoc, LinkageSpecLanguageIDs Lang, bool HasBraces); - static LinkageSpecDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static LinkageSpecDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Return the language specified by this linkage specification. LinkageSpecLanguageIDs getLanguage() const { @@ -3096,7 +3099,7 @@ class UsingDirectiveDecl : public NamedDecl { SourceLocation IdentLoc, NamedDecl *Nominated, DeclContext *CommonAncestor); - static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(UsingLoc, getLocation()); @@ -3157,7 +3160,7 @@ class NamespaceAliasDecl : public NamedDecl, SourceLocation IdentLoc, NamedDecl *Namespace); - static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); using redecl_range = redeclarable_base::redecl_range; using redecl_iterator = redeclarable_base::redecl_iterator; @@ -3254,7 +3257,7 @@ class LifetimeExtendedTemporaryDecl final LifetimeExtendedTemporaryDecl(Temp, EDec, Mangling); } static LifetimeExtendedTemporaryDecl *CreateDeserialized(ASTContext &C, - DeclID ID) { + GlobalDeclID ID) { return new (C, ID) LifetimeExtendedTemporaryDecl(EmptyShell{}); } @@ -3357,7 +3360,7 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable { UsingShadowDecl(UsingShadow, C, DC, Loc, Name, Introducer, Target); } - static UsingShadowDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static UsingShadowDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); using redecl_range = redeclarable_base::redecl_range; using redecl_iterator = redeclarable_base::redecl_iterator; @@ -3566,7 +3569,7 @@ class UsingDecl : public BaseUsingDecl, public Mergeable { const DeclarationNameInfo &NameInfo, bool HasTypenameKeyword); - static UsingDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static UsingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -3645,7 +3648,7 @@ class ConstructorUsingShadowDecl final : public UsingShadowDecl { UsingDecl *Using, NamedDecl *Target, bool IsVirtual); static ConstructorUsingShadowDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + GlobalDeclID ID); /// Override the UsingShadowDecl's getIntroducer, returning the UsingDecl that /// introduced this. @@ -3757,7 +3760,7 @@ class UsingEnumDecl : public BaseUsingDecl, public Mergeable { SourceLocation UsingL, SourceLocation EnumL, SourceLocation NameL, TypeSourceInfo *EnumType); - static UsingEnumDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static UsingEnumDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -3830,7 +3833,7 @@ class UsingPackDecl final NamedDecl *InstantiatedFrom, ArrayRef UsingDecls); - static UsingPackDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static UsingPackDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions); SourceRange getSourceRange() const override LLVM_READONLY { @@ -3923,8 +3926,8 @@ class UnresolvedUsingValueDecl : public ValueDecl, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, SourceLocation EllipsisLoc); - static UnresolvedUsingValueDecl * - CreateDeserialized(ASTContext &C, DeclID ID); + static UnresolvedUsingValueDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -4014,8 +4017,8 @@ class UnresolvedUsingTypenameDecl SourceLocation TargetNameLoc, DeclarationName TargetName, SourceLocation EllipsisLoc); - static UnresolvedUsingTypenameDecl * - CreateDeserialized(ASTContext &C, DeclID ID); + static UnresolvedUsingTypenameDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); /// Retrieves the canonical declaration of this declaration. UnresolvedUsingTypenameDecl *getCanonicalDecl() override { @@ -4045,7 +4048,7 @@ class UnresolvedUsingIfExistsDecl final : public NamedDecl { SourceLocation Loc, DeclarationName Name); static UnresolvedUsingIfExistsDecl *CreateDeserialized(ASTContext &Ctx, - DeclID ID); + GlobalDeclID ID); static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingIfExists; } @@ -4073,7 +4076,7 @@ class StaticAssertDecl : public Decl { SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *Message, SourceLocation RParenLoc, bool Failed); - static StaticAssertDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static StaticAssertDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); Expr *getAssertExpr() { return AssertExprAndFailed.getPointer(); } const Expr *getAssertExpr() const { return AssertExprAndFailed.getPointer(); } @@ -4120,7 +4123,7 @@ class BindingDecl : public ValueDecl { static BindingDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id); - static BindingDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static BindingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Get the expression to which this declaration is bound. This may be null /// in two different cases: while parsing the initializer for the @@ -4189,7 +4192,7 @@ class DecompositionDecl final QualType T, TypeSourceInfo *TInfo, StorageClass S, ArrayRef Bindings); - static DecompositionDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static DecompositionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumBindings); ArrayRef bindings() const { @@ -4246,7 +4249,7 @@ class MSPropertyDecl : public DeclaratorDecl { SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, SourceLocation StartL, IdentifierInfo *Getter, IdentifierInfo *Setter); - static MSPropertyDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static MSPropertyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); static bool classof(const Decl *D) { return D->getKind() == MSProperty; } @@ -4300,7 +4303,7 @@ class MSGuidDecl : public ValueDecl, MSGuidDecl(DeclContext *DC, QualType T, Parts P); static MSGuidDecl *Create(const ASTContext &C, QualType T, Parts P); - static MSGuidDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static MSGuidDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); // Only ASTContext::getMSGuidDecl and deserialization create these. friend class ASTContext; @@ -4353,7 +4356,7 @@ class UnnamedGlobalConstantDecl : public ValueDecl, static UnnamedGlobalConstantDecl *Create(const ASTContext &C, QualType T, const APValue &APVal); static UnnamedGlobalConstantDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + GlobalDeclID ID); // Only ASTContext::getUnnamedGlobalConstantDecl and deserialization create // these. diff --git a/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h index c4734ab578953..e169c48592192 100644 --- a/clang/include/clang/AST/DeclContextInternals.h +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -42,11 +42,12 @@ class StoredDeclsList { /// external declarations. DeclsAndHasExternalTy Data; - template - void erase_if(Fn ShouldErase) { + template DeclListNode::Decls *erase_if(Fn ShouldErase) { Decls List = Data.getPointer(); + if (!List) - return; + return nullptr; + ASTContext &C = getASTContext(); DeclListNode::Decls NewHead = nullptr; DeclListNode::Decls *NewLast = nullptr; @@ -79,6 +80,17 @@ class StoredDeclsList { Data.setPointer(NewHead); assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!"); + + if (!Data.getPointer()) + // All declarations are erased. + return nullptr; + else if (NewHead.is()) + // The list only contains a declaration, the header itself. + return (DeclListNode::Decls *)&Data; + else { + assert(NewLast && NewLast->is() && "Not the tail?"); + return NewLast; + } } void erase(NamedDecl *ND) { @@ -160,12 +172,16 @@ class StoredDeclsList { void replaceExternalDecls(ArrayRef Decls) { // Remove all declarations that are either external or are replaced with - // external declarations. - erase_if([Decls](NamedDecl *ND) { + // external declarations with higher visibilities. + DeclListNode::Decls *Tail = erase_if([Decls](NamedDecl *ND) { if (ND->isFromASTFile()) return true; + // FIXME: Can we get rid of this loop completely? for (NamedDecl *D : Decls) - if (D->declarationReplaces(ND, /*IsKnownNewer=*/false)) + // Only replace the local declaration if the external declaration has + // higher visibilities. + if (D->getModuleOwnershipKind() <= ND->getModuleOwnershipKind() && + D->declarationReplaces(ND, /*IsKnownNewer=*/false)) return true; return false; }); @@ -185,24 +201,15 @@ class StoredDeclsList { DeclsAsList = Node; } - DeclListNode::Decls Head = Data.getPointer(); - if (Head.isNull()) { + if (!Data.getPointer()) { Data.setPointer(DeclsAsList); return; } - // Find the end of the existing list. - // FIXME: It would be possible to preserve information from erase_if to - // avoid this rescan looking for the end of the list. - DeclListNode::Decls *Tail = &Head; - while (DeclListNode *Node = Tail->dyn_cast()) - Tail = &Node->Rest; - // Append the Decls. DeclListNode *Node = C.AllocateDeclListNode(Tail->get()); Node->Rest = DeclsAsList; *Tail = Node; - Data.setPointer(Head); } /// Return the list of all the decls. diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h index b56627a5337d6..9789282f351a5 100644 --- a/clang/include/clang/AST/DeclFriend.h +++ b/clang/include/clang/AST/DeclFriend.h @@ -112,7 +112,7 @@ class FriendDecl final Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, SourceLocation FriendL, ArrayRef FriendTypeTPLists = std::nullopt); - static FriendDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned FriendTypeNumTPLists); /// If this friend declaration names an (untemplated but possibly diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h new file mode 100644 index 0000000000000..614ba06b63860 --- /dev/null +++ b/clang/include/clang/AST/DeclID.h @@ -0,0 +1,227 @@ +//===--- DeclID.h - ID number for deserialized declarations ----*- 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 DeclID class family to describe the deserialized +// declarations. The DeclID is widely used in AST via LazyDeclPtr, or calls to +// `ExternalASTSource::getExternalDecl`. It will be helpful for type safety to +// require the use of `DeclID` to explicit. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLID_H +#define LLVM_CLANG_AST_DECLID_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/iterator.h" + +namespace clang { + +/// Predefined declaration IDs. +/// +/// These declaration IDs correspond to predefined declarations in the AST +/// context, such as the NULL declaration ID. Such declarations are never +/// actually serialized, since they will be built by the AST context when +/// it is created. +enum PredefinedDeclIDs { + /// The NULL declaration. + PREDEF_DECL_NULL_ID = 0, + + /// The translation unit. + PREDEF_DECL_TRANSLATION_UNIT_ID = 1, + + /// The Objective-C 'id' type. + PREDEF_DECL_OBJC_ID_ID = 2, + + /// The Objective-C 'SEL' type. + PREDEF_DECL_OBJC_SEL_ID = 3, + + /// The Objective-C 'Class' type. + PREDEF_DECL_OBJC_CLASS_ID = 4, + + /// The Objective-C 'Protocol' type. + PREDEF_DECL_OBJC_PROTOCOL_ID = 5, + + /// The signed 128-bit integer type. + PREDEF_DECL_INT_128_ID = 6, + + /// The unsigned 128-bit integer type. + PREDEF_DECL_UNSIGNED_INT_128_ID = 7, + + /// The internal 'instancetype' typedef. + PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, + + /// The internal '__builtin_va_list' typedef. + PREDEF_DECL_BUILTIN_VA_LIST_ID = 9, + + /// The internal '__va_list_tag' struct, if any. + PREDEF_DECL_VA_LIST_TAG = 10, + + /// The internal '__builtin_ms_va_list' typedef. + PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11, + + /// The predeclared '_GUID' struct. + PREDEF_DECL_BUILTIN_MS_GUID_ID = 12, + + /// The extern "C" context. + PREDEF_DECL_EXTERN_C_CONTEXT_ID = 13, + + /// The internal '__make_integer_seq' template. + PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 14, + + /// The internal '__NSConstantString' typedef. + PREDEF_DECL_CF_CONSTANT_STRING_ID = 15, + + /// The internal '__NSConstantString' tag type. + PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 16, + + /// The internal '__type_pack_element' template. + PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17, +}; + +/// The number of declaration IDs that are predefined. +/// +/// For more information about predefined declarations, see the +/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. +const unsigned int NUM_PREDEF_DECL_IDS = 18; + +/// GlobalDeclID means DeclID in the current ASTContext and LocalDeclID means +/// DeclID specific to a certain ModuleFile. Specially, in ASTWriter, the +/// LocalDeclID to the ModuleFile been writting is equal to the GlobalDeclID. +/// Outside the serializer, all the DeclID been used should be GlobalDeclID. +/// We can translate a LocalDeclID to the GlobalDeclID by +/// `ASTReader::getGlobalDeclID()`. + +class DeclIDBase { +public: + /// An ID number that refers to a declaration in an AST file. + /// + /// The ID numbers of declarations are consecutive (in order of + /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved. + /// At the start of a chain of precompiled headers, declaration ID 1 is + /// used for the translation unit declaration. + /// + /// DeclID should only be used directly in serialization. All other users + /// should use LocalDeclID or GlobalDeclID. + using DeclID = uint32_t; + +protected: + DeclIDBase() : ID(PREDEF_DECL_NULL_ID) {} + explicit DeclIDBase(DeclID ID) : ID(ID) {} + +public: + DeclID get() const { return ID; } + + explicit operator DeclID() const { return ID; } + + explicit operator PredefinedDeclIDs() const { return (PredefinedDeclIDs)ID; } + + bool isValid() const { return ID != PREDEF_DECL_NULL_ID; } + + bool isInvalid() const { return ID == PREDEF_DECL_NULL_ID; } + + friend bool operator==(const DeclIDBase &LHS, const DeclIDBase &RHS) { + return LHS.ID == RHS.ID; + } + friend bool operator!=(const DeclIDBase &LHS, const DeclIDBase &RHS) { + return LHS.ID != RHS.ID; + } + // We may sort the decl ID. + friend bool operator<(const DeclIDBase &LHS, const DeclIDBase &RHS) { + return LHS.ID < RHS.ID; + } + friend bool operator>(const DeclIDBase &LHS, const DeclIDBase &RHS) { + return LHS.ID > RHS.ID; + } + friend bool operator<=(const DeclIDBase &LHS, const DeclIDBase &RHS) { + return LHS.ID <= RHS.ID; + } + friend bool operator>=(const DeclIDBase &LHS, const DeclIDBase &RHS) { + return LHS.ID >= RHS.ID; + } + +protected: + DeclID ID; +}; + +class LocalDeclID : public DeclIDBase { + using Base = DeclIDBase; + +public: + LocalDeclID() : Base() {} + LocalDeclID(PredefinedDeclIDs ID) : Base(ID) {} + explicit LocalDeclID(DeclID ID) : Base(ID) {} + + LocalDeclID &operator++() { + ++ID; + return *this; + } + + LocalDeclID operator++(int) { + LocalDeclID Ret = *this; + ++(*this); + return Ret; + } +}; + +class GlobalDeclID : public DeclIDBase { + using Base = DeclIDBase; + +public: + GlobalDeclID() : Base() {} + explicit GlobalDeclID(DeclID ID) : Base(ID) {} + + // For DeclIDIterator to be able to convert a GlobalDeclID + // to a LocalDeclID. + explicit operator LocalDeclID() const { return LocalDeclID(this->ID); } +}; + +/// A helper iterator adaptor to convert the iterators to +/// `SmallVector` to the iterators to `SmallVector`. +template +class DeclIDIterator + : public llvm::iterator_adaptor_base, + const FromTy *, + std::forward_iterator_tag, ToTy> { +public: + DeclIDIterator() : DeclIDIterator::iterator_adaptor_base(nullptr) {} + + DeclIDIterator(const FromTy *ID) + : DeclIDIterator::iterator_adaptor_base(ID) {} + + ToTy operator*() const { return ToTy(*this->I); } + + bool operator==(const DeclIDIterator &RHS) const { return this->I == RHS.I; } +}; + +} // namespace clang + +namespace llvm { +template <> struct DenseMapInfo { + using GlobalDeclID = clang::GlobalDeclID; + using DeclID = GlobalDeclID::DeclID; + + static GlobalDeclID getEmptyKey() { + return GlobalDeclID(DenseMapInfo::getEmptyKey()); + } + + static GlobalDeclID getTombstoneKey() { + return GlobalDeclID(DenseMapInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const GlobalDeclID &Key) { + return DenseMapInfo::getHashValue(Key.get()); + } + + static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) { + return L == R; + } +}; + +} // namespace llvm + +#endif diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 7780afa6f1cf5..d2cc61ca19f8a 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -236,7 +236,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { ObjCImplementationControl impControl = ObjCImplementationControl::None, bool HasRelatedResultType = false); - static ObjCMethodDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); ObjCMethodDecl *getCanonicalDecl() override; const ObjCMethodDecl *getCanonicalDecl() const { @@ -614,7 +614,8 @@ class ObjCTypeParamDecl : public TypedefNameDecl { IdentifierInfo *name, SourceLocation colonLoc, TypeSourceInfo *boundInfo); - static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, DeclID ID); + static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, + GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -789,7 +790,7 @@ class ObjCPropertyDecl : public NamedDecl { TypeSourceInfo *TSI, PropertyControl propControl = None); - static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } @@ -1279,7 +1280,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc = SourceLocation(), bool isInternal = false); - static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, DeclID ID); + static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, + GlobalDeclID ID); /// Retrieve the type parameters of this class. /// @@ -1969,7 +1971,7 @@ class ObjCIvarDecl : public FieldDecl { TypeSourceInfo *TInfo, AccessControl ac, Expr *BW = nullptr, bool synthesized = false); - static ObjCIvarDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCIvarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Return the class interface that this ivar is logically contained /// in; this is either the interface where the ivar was declared, or the @@ -2039,7 +2041,8 @@ class ObjCAtDefsFieldDecl : public FieldDecl { SourceLocation IdLoc, IdentifierInfo *Id, QualType T, Expr *BW); - static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -2142,7 +2145,7 @@ class ObjCProtocolDecl : public ObjCContainerDecl, SourceLocation atStartLoc, ObjCProtocolDecl *PrevDecl); - static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); const ObjCProtocolList &getReferencedProtocols() const { assert(hasDefinition() && "No definition available!"); @@ -2361,7 +2364,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl { ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc = SourceLocation(), SourceLocation IvarRBraceLoc = SourceLocation()); - static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } @@ -2558,7 +2561,8 @@ class ObjCCategoryImplDecl : public ObjCImplDecl { Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, ObjCInterfaceDecl *classInterface, SourceLocation nameLoc, SourceLocation atStartLoc, SourceLocation CategoryNameLoc); - static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); ObjCCategoryDecl *getCategoryDecl() const; @@ -2640,7 +2644,8 @@ class ObjCImplementationDecl : public ObjCImplDecl { SourceLocation IvarLBraceLoc=SourceLocation(), SourceLocation IvarRBraceLoc=SourceLocation()); - static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); /// init_iterator - Iterates through the ivar initializer list. using init_iterator = CXXCtorInitializer **; @@ -2780,7 +2785,7 @@ class ObjCCompatibleAliasDecl : public NamedDecl { ObjCInterfaceDecl* aliasedClass); static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + GlobalDeclID ID); const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; } ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } @@ -2851,7 +2856,8 @@ class ObjCPropertyImplDecl : public Decl { ObjCIvarDecl *ivarDecl, SourceLocation ivarLoc); - static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; diff --git a/clang/include/clang/AST/DeclOpenMP.h b/clang/include/clang/AST/DeclOpenMP.h index c7ede7f2157fe..e542c3c8e66b0 100644 --- a/clang/include/clang/AST/DeclOpenMP.h +++ b/clang/include/clang/AST/DeclOpenMP.h @@ -59,7 +59,7 @@ template class OMPDeclarativeDirective : public U { } template - static T *createEmptyDirective(const ASTContext &C, unsigned ID, + static T *createEmptyDirective(const ASTContext &C, GlobalDeclID ID, unsigned NumClauses, unsigned NumChildren, Params &&... P) { auto *Inst = new (C, ID, size(NumClauses, NumChildren)) @@ -133,7 +133,7 @@ class OMPThreadPrivateDecl final : public OMPDeclarativeDirective { SourceLocation L, ArrayRef VL); static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, - DeclID ID, unsigned N); + GlobalDeclID ID, unsigned N); typedef MutableArrayRef::iterator varlist_iterator; typedef ArrayRef::iterator varlist_const_iterator; @@ -214,7 +214,7 @@ class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext { QualType T, OMPDeclareReductionDecl *PrevDeclInScope); /// Create deserialized declare reduction node. static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + GlobalDeclID ID); /// Get combiner expression of the declare reduction construct. Expr *getCombiner() { return Combiner; } @@ -318,8 +318,8 @@ class OMPDeclareMapperDecl final : public OMPDeclarativeDirective, ArrayRef Clauses, OMPDeclareMapperDecl *PrevDeclInScope); /// Creates deserialized declare mapper node. - static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, DeclID ID, - unsigned N); + static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID, unsigned N); using clauselist_iterator = MutableArrayRef::iterator; using clauselist_const_iterator = ArrayRef::iterator; @@ -397,7 +397,8 @@ class OMPCapturedExprDecl final : public VarDecl { IdentifierInfo *Id, QualType T, SourceLocation StartLoc); - static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -427,7 +428,7 @@ class OMPRequiresDecl final : public OMPDeclarativeDirective { static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, ArrayRef CL); /// Create deserialized requires node. - static OMPRequiresDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static OMPRequiresDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned N); using clauselist_iterator = MutableArrayRef::iterator; @@ -495,7 +496,7 @@ class OMPAllocateDecl final : public OMPDeclarativeDirective { static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, ArrayRef VL, ArrayRef CL); - static OMPAllocateDecl *CreateDeserialized(ASTContext &C, DeclID ID, + static OMPAllocateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NVars, unsigned NClauses); typedef MutableArrayRef::iterator varlist_iterator; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 231bda44a9fcf..3ee03eebdb8ca 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -797,7 +797,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// /// The first value in the array is the number of specializations/partial /// specializations that follow. - Decl::DeclID *LazySpecializations = nullptr; + GlobalDeclID *LazySpecializations = nullptr; /// The set of "injected" template arguments used within this /// template. @@ -1087,7 +1087,8 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl { NamedDecl *Decl); /// Create an empty function template node. - static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -1204,9 +1205,9 @@ class TemplateTypeParmDecl final : public TypeDecl, bool Typename, bool ParameterPack, bool HasTypeConstraint = false, std::optional NumExpanded = std::nullopt); static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, - DeclID ID); + GlobalDeclID ID); static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, - DeclID ID, + GlobalDeclID ID, bool HasTypeConstraint); /// Whether this template type parameter was declared with @@ -1413,11 +1414,10 @@ class NonTypeTemplateParmDecl final QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos); + static NonTypeTemplateParmDecl * + CreateDeserialized(ASTContext &C, GlobalDeclID ID, bool HasTypeConstraint); static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, - DeclID ID, - bool HasTypeConstraint); - static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, - DeclID ID, + GlobalDeclID ID, unsigned NumExpandedTypes, bool HasTypeConstraint); @@ -1632,10 +1632,9 @@ class TemplateTemplateParmDecl final ArrayRef Expansions); static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, - DeclID ID); - static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, - DeclID ID, - unsigned NumExpansions); + GlobalDeclID ID); + static TemplateTemplateParmDecl * + CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions); using TemplateParmPosition::getDepth; using TemplateParmPosition::setDepth; @@ -1857,8 +1856,8 @@ class ClassTemplateSpecializationDecl ClassTemplateDecl *SpecializedTemplate, ArrayRef Args, ClassTemplateSpecializationDecl *PrevDecl); - static ClassTemplateSpecializationDecl * - CreateDeserialized(ASTContext &C, DeclID ID); + static ClassTemplateSpecializationDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const override; @@ -2110,7 +2109,7 @@ class ClassTemplatePartialSpecializationDecl ClassTemplatePartialSpecializationDecl *PrevDecl); static ClassTemplatePartialSpecializationDecl * - CreateDeserialized(ASTContext &C, DeclID ID); + CreateDeserialized(ASTContext &C, GlobalDeclID ID); ClassTemplatePartialSpecializationDecl *getMostRecentDecl() { return cast( @@ -2306,7 +2305,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { NamedDecl *Decl); /// Create an empty class template node. - static ClassTemplateDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ClassTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Return the specialization with the provided arguments if it exists, /// otherwise return the insertion point. @@ -2472,7 +2471,7 @@ class FriendTemplateDecl : public Decl { MutableArrayRef Params, FriendUnion Friend, SourceLocation FriendLoc); - static FriendTemplateDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// If this friend declaration names a templated type (or /// a dependent member type of a templated type), return that @@ -2573,7 +2572,8 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl { NamedDecl *Decl); /// Create an empty alias template node. - static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -2670,7 +2670,7 @@ class VarTemplateSpecializationDecl : public VarDecl, TypeSourceInfo *TInfo, StorageClass S, ArrayRef Args); static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + GlobalDeclID ID); void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const override; @@ -2900,8 +2900,8 @@ class VarTemplatePartialSpecializationDecl TypeSourceInfo *TInfo, StorageClass S, ArrayRef Args, const TemplateArgumentListInfo &ArgInfos); - static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + static VarTemplatePartialSpecializationDecl * + CreateDeserialized(ASTContext &C, GlobalDeclID ID); VarTemplatePartialSpecializationDecl *getMostRecentDecl() { return cast( @@ -3078,7 +3078,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { VarDecl *Decl); /// Create an empty variable template node. - static VarTemplateDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static VarTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); /// Return the specialization with the provided arguments if it exists, /// otherwise return the insertion point. @@ -3183,7 +3183,7 @@ class ConceptDecl : public TemplateDecl, public Mergeable { SourceLocation L, DeclarationName Name, TemplateParameterList *Params, Expr *ConstraintExpr); - static ConceptDecl *CreateDeserialized(ASTContext &C, DeclID ID); + static ConceptDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); Expr *getConstraintExpr() const { return ConstraintExpr; @@ -3232,7 +3232,7 @@ class ImplicitConceptSpecializationDecl final Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, ArrayRef ConvertedArgs); static ImplicitConceptSpecializationDecl * - CreateDeserialized(const ASTContext &C, DeclID ID, + CreateDeserialized(const ASTContext &C, GlobalDeclID ID, unsigned NumTemplateArgs); ArrayRef getTemplateArguments() const { @@ -3275,7 +3275,7 @@ class TemplateParamObjectDecl : public ValueDecl, static TemplateParamObjectDecl *Create(const ASTContext &C, QualType T, const APValue &V); static TemplateParamObjectDecl *CreateDeserialized(ASTContext &C, - DeclID ID); + GlobalDeclID ID); /// Only ASTContext::getTemplateParamObjectDecl and deserialization /// create these. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index ccb5b9d426ecc..b82b3be399fe9 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6651,6 +6651,275 @@ class TypoExpr : public Expr { }; +/// This class represents BOTH the OpenMP Array Section and OpenACC 'subarray', +/// with a boolean differentiator. +/// OpenMP 5.0 [2.1.5, Array Sections]. +/// To specify an array section in an OpenMP construct, array subscript +/// expressions are extended with the following syntax: +/// \code +/// [ lower-bound : length : stride ] +/// [ lower-bound : length : ] +/// [ lower-bound : length ] +/// [ lower-bound : : stride ] +/// [ lower-bound : : ] +/// [ lower-bound : ] +/// [ : length : stride ] +/// [ : length : ] +/// [ : length ] +/// [ : : stride ] +/// [ : : ] +/// [ : ] +/// \endcode +/// The array section must be a subset of the original array. +/// Array sections are allowed on multidimensional arrays. Base language array +/// subscript expressions can be used to specify length-one dimensions of +/// multidimensional array sections. +/// Each of the lower-bound, length, and stride expressions if specified must be +/// an integral type expressions of the base language. When evaluated +/// they represent a set of integer values as follows: +/// \code +/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... , +/// lower-bound + ((length - 1) * stride) } +/// \endcode +/// The lower-bound and length must evaluate to non-negative integers. +/// The stride must evaluate to a positive integer. +/// When the size of the array dimension is not known, the length must be +/// specified explicitly. +/// When the stride is absent it defaults to 1. +/// When the length is absent it defaults to ⌈(size − lower-bound)/stride⌉, +/// where size is the size of the array dimension. When the lower-bound is +/// absent it defaults to 0. +/// +/// +/// OpenACC 3.3 [2.7.1 Data Specification in Data Clauses] +/// In C and C++, a subarray is an array name followed by an extended array +/// range specification in brackets, with start and length, such as +/// +/// AA[2:n] +/// +/// If the lower bound is missing, zero is used. If the length is missing and +/// the array has known size, the size of the array is used; otherwise the +/// length is required. The subarray AA[2:n] means elements AA[2], AA[3], . . . +/// , AA[2+n-1]. In C and C++, a two dimensional array may be declared in at +/// least four ways: +/// +/// -Statically-sized array: float AA[100][200]; +/// -Pointer to statically sized rows: typedef float row[200]; row* BB; +/// -Statically-sized array of pointers: float* CC[200]; +/// -Pointer to pointers: float** DD; +/// +/// Each dimension may be statically sized, or a pointer to dynamically +/// allocated memory. Each of these may be included in a data clause using +/// subarray notation to specify a rectangular array: +/// +/// -AA[2:n][0:200] +/// -BB[2:n][0:m] +/// -CC[2:n][0:m] +/// -DD[2:n][0:m] +/// +/// Multidimensional rectangular subarrays in C and C++ may be specified for any +/// array with any combination of statically-sized or dynamically-allocated +/// dimensions. For statically sized dimensions, all dimensions except the first +/// must specify the whole extent to preserve the contiguous data restriction, +/// discussed below. For dynamically allocated dimensions, the implementation +/// will allocate pointers in device memory corresponding to the pointers in +/// local memory and will fill in those pointers as appropriate. +/// +/// In Fortran, a subarray is an array name followed by a comma-separated list +/// of range specifications in parentheses, with lower and upper bound +/// subscripts, such as +/// +/// arr(1:high,low:100) +/// +/// If either the lower or upper bounds are missing, the declared or allocated +/// bounds of the array, if known, are used. All dimensions except the last must +/// specify the whole extent, to preserve the contiguous data restriction, +/// discussed below. +/// +/// Restrictions +/// +/// -In Fortran, the upper bound for the last dimension of an assumed-size dummy +/// array must be specified. +/// +/// -In C and C++, the length for dynamically allocated dimensions of an array +/// must be explicitly specified. +/// +/// -In C and C++, modifying pointers in pointer arrays during the data +/// lifetime, either on the host or on the device, may result in undefined +/// behavior. +/// +/// -If a subarray appears in a data clause, the implementation may choose to +/// allocate memory for only that subarray on the accelerator. +/// +/// -In Fortran, array pointers may appear, but pointer association is not +/// preserved in device memory. +/// +/// -Any array or subarray in a data clause, including Fortran array pointers, +/// must be a contiguous section of memory, except for dynamic multidimensional +/// C arrays. +/// +/// -In C and C++, if a variable or array of composite type appears, all the +/// data members of the struct or class are allocated and copied, as +/// appropriate. If a composite member is a pointer type, the data addressed by +/// that pointer are not implicitly copied. +/// +/// -In Fortran, if a variable or array of composite type appears, all the +/// members of that derived type are allocated and copied, as appropriate. If +/// any member has the allocatable or pointer attribute, the data accessed +/// through that member are not copied. +/// +/// -If an expression is used in a subscript or subarray expression in a clause +/// on a data construct, the same value is used when copying data at the end of +/// the data region, even if the values of variables in the expression change +/// during the data region. +class ArraySectionExpr : public Expr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + enum ArraySectionType { OMPArraySection, OpenACCArraySection }; + +private: + enum { + BASE, + LOWER_BOUND, + LENGTH, + STRIDE, + END_EXPR, + OPENACC_END_EXPR = STRIDE + }; + + ArraySectionType ASType = OMPArraySection; + Stmt *SubExprs[END_EXPR] = {nullptr}; + SourceLocation ColonLocFirst; + SourceLocation ColonLocSecond; + SourceLocation RBracketLoc; + +public: + // Constructor for OMP array sections, which include a 'stride'. + ArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, Expr *Stride, + QualType Type, ExprValueKind VK, ExprObjectKind OK, + SourceLocation ColonLocFirst, SourceLocation ColonLocSecond, + SourceLocation RBracketLoc) + : Expr(ArraySectionExprClass, Type, VK, OK), ASType(OMPArraySection), + ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond), + RBracketLoc(RBracketLoc) { + setBase(Base); + setLowerBound(LowerBound); + setLength(Length); + setStride(Stride); + setDependence(computeDependence(this)); + } + + // Constructor for OpenACC sub-arrays, which do not permit a 'stride'. + ArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type, + ExprValueKind VK, ExprObjectKind OK, SourceLocation ColonLoc, + SourceLocation RBracketLoc) + : Expr(ArraySectionExprClass, Type, VK, OK), ASType(OpenACCArraySection), + ColonLocFirst(ColonLoc), RBracketLoc(RBracketLoc) { + setBase(Base); + setLowerBound(LowerBound); + setLength(Length); + setDependence(computeDependence(this)); + } + + /// Create an empty array section expression. + explicit ArraySectionExpr(EmptyShell Shell) + : Expr(ArraySectionExprClass, Shell) {} + + /// Return original type of the base expression for array section. + static QualType getBaseOriginalType(const Expr *Base); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArraySectionExprClass; + } + + bool isOMPArraySection() const { return ASType == OMPArraySection; } + bool isOpenACCArraySection() const { return ASType == OpenACCArraySection; } + + /// Get base of the array section. + Expr *getBase() { return cast(SubExprs[BASE]); } + const Expr *getBase() const { return cast(SubExprs[BASE]); } + + /// Get lower bound of array section. + Expr *getLowerBound() { return cast_or_null(SubExprs[LOWER_BOUND]); } + const Expr *getLowerBound() const { + return cast_or_null(SubExprs[LOWER_BOUND]); + } + + /// Get length of array section. + Expr *getLength() { return cast_or_null(SubExprs[LENGTH]); } + const Expr *getLength() const { return cast_or_null(SubExprs[LENGTH]); } + + /// Get stride of array section. + Expr *getStride() { + assert(ASType != OpenACCArraySection && + "Stride not valid in OpenACC subarrays"); + return cast_or_null(SubExprs[STRIDE]); + } + + const Expr *getStride() const { + assert(ASType != OpenACCArraySection && + "Stride not valid in OpenACC subarrays"); + return cast_or_null(SubExprs[STRIDE]); + } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBase()->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } + + SourceLocation getColonLocFirst() const { return ColonLocFirst; } + SourceLocation getColonLocSecond() const { + assert(ASType != OpenACCArraySection && + "second colon for stride not valid in OpenACC subarrays"); + return ColonLocSecond; + } + SourceLocation getRBracketLoc() const { return RBracketLoc; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + child_range children() { + return child_range( + &SubExprs[BASE], + &SubExprs[ASType == OMPArraySection ? END_EXPR : OPENACC_END_EXPR]); + } + + const_child_range children() const { + return const_child_range( + &SubExprs[BASE], + &SubExprs[ASType == OMPArraySection ? END_EXPR : OPENACC_END_EXPR]); + } + +private: + /// Set base of the array section. + void setBase(Expr *E) { SubExprs[BASE] = E; } + + /// Set lower bound of the array section. + void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } + + /// Set length of the array section. + void setLength(Expr *E) { SubExprs[LENGTH] = E; } + + /// Set length of the array section. + void setStride(Expr *E) { + assert(ASType != OpenACCArraySection && + "Stride not valid in OpenACC subarrays"); + SubExprs[STRIDE] = E; + } + + void setColonLocFirst(SourceLocation L) { ColonLocFirst = L; } + + void setColonLocSecond(SourceLocation L) { + assert(ASType != OpenACCArraySection && + "second colon for stride not valid in OpenACC subarrays"); + ColonLocSecond = L; + } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } +}; + /// Frontend produces RecoveryExprs on semantic errors that prevent creating /// other well-formed expressions. E.g. when type-checking of a binary operator /// fails, we cannot produce a BinaryOperator expression. Instead, we can choose diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index b633f686cd183..cb45e8640eb9b 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1482,6 +1482,8 @@ class CXXTemporary { /// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr. /// } /// \endcode +/// +/// Destructor might be null if destructor declaration is not valid. class CXXBindTemporaryExpr : public Expr { CXXTemporary *Temp = nullptr; Stmt *SubExpr = nullptr; diff --git a/clang/include/clang/AST/ExprOpenMP.h b/clang/include/clang/AST/ExprOpenMP.h index be5b1f3fdd112..54a0c203f656c 100644 --- a/clang/include/clang/AST/ExprOpenMP.h +++ b/clang/include/clang/AST/ExprOpenMP.h @@ -17,130 +17,6 @@ #include "clang/AST/Expr.h" namespace clang { -/// OpenMP 5.0 [2.1.5, Array Sections]. -/// To specify an array section in an OpenMP construct, array subscript -/// expressions are extended with the following syntax: -/// \code -/// [ lower-bound : length : stride ] -/// [ lower-bound : length : ] -/// [ lower-bound : length ] -/// [ lower-bound : : stride ] -/// [ lower-bound : : ] -/// [ lower-bound : ] -/// [ : length : stride ] -/// [ : length : ] -/// [ : length ] -/// [ : : stride ] -/// [ : : ] -/// [ : ] -/// \endcode -/// The array section must be a subset of the original array. -/// Array sections are allowed on multidimensional arrays. Base language array -/// subscript expressions can be used to specify length-one dimensions of -/// multidimensional array sections. -/// Each of the lower-bound, length, and stride expressions if specified must be -/// an integral type expressions of the base language. When evaluated -/// they represent a set of integer values as follows: -/// \code -/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... , -/// lower-bound + ((length - 1) * stride) } -/// \endcode -/// The lower-bound and length must evaluate to non-negative integers. -/// The stride must evaluate to a positive integer. -/// When the size of the array dimension is not known, the length must be -/// specified explicitly. -/// When the stride is absent it defaults to 1. -/// When the length is absent it defaults to ⌈(size − lower-bound)/stride⌉, -/// where size is the size of the array dimension. When the lower-bound is -/// absent it defaults to 0. -class OMPArraySectionExpr : public Expr { - enum { BASE, LOWER_BOUND, LENGTH, STRIDE, END_EXPR }; - Stmt *SubExprs[END_EXPR]; - SourceLocation ColonLocFirst; - SourceLocation ColonLocSecond; - SourceLocation RBracketLoc; - -public: - OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, Expr *Stride, - QualType Type, ExprValueKind VK, ExprObjectKind OK, - SourceLocation ColonLocFirst, - SourceLocation ColonLocSecond, SourceLocation RBracketLoc) - : Expr(OMPArraySectionExprClass, Type, VK, OK), - ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond), - RBracketLoc(RBracketLoc) { - SubExprs[BASE] = Base; - SubExprs[LOWER_BOUND] = LowerBound; - SubExprs[LENGTH] = Length; - SubExprs[STRIDE] = Stride; - setDependence(computeDependence(this)); - } - - /// Create an empty array section expression. - explicit OMPArraySectionExpr(EmptyShell Shell) - : Expr(OMPArraySectionExprClass, Shell) {} - - /// An array section can be written only as Base[LowerBound:Length]. - - /// Get base of the array section. - Expr *getBase() { return cast(SubExprs[BASE]); } - const Expr *getBase() const { return cast(SubExprs[BASE]); } - /// Set base of the array section. - void setBase(Expr *E) { SubExprs[BASE] = E; } - - /// Return original type of the base expression for array section. - static QualType getBaseOriginalType(const Expr *Base); - - /// Get lower bound of array section. - Expr *getLowerBound() { return cast_or_null(SubExprs[LOWER_BOUND]); } - const Expr *getLowerBound() const { - return cast_or_null(SubExprs[LOWER_BOUND]); - } - /// Set lower bound of the array section. - void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } - - /// Get length of array section. - Expr *getLength() { return cast_or_null(SubExprs[LENGTH]); } - const Expr *getLength() const { return cast_or_null(SubExprs[LENGTH]); } - /// Set length of the array section. - void setLength(Expr *E) { SubExprs[LENGTH] = E; } - - /// Get stride of array section. - Expr *getStride() { return cast_or_null(SubExprs[STRIDE]); } - const Expr *getStride() const { return cast_or_null(SubExprs[STRIDE]); } - /// Set length of the array section. - void setStride(Expr *E) { SubExprs[STRIDE] = E; } - - SourceLocation getBeginLoc() const LLVM_READONLY { - return getBase()->getBeginLoc(); - } - SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } - - SourceLocation getColonLocFirst() const { return ColonLocFirst; } - void setColonLocFirst(SourceLocation L) { ColonLocFirst = L; } - - SourceLocation getColonLocSecond() const { return ColonLocSecond; } - void setColonLocSecond(SourceLocation L) { ColonLocSecond = L; } - - SourceLocation getRBracketLoc() const { return RBracketLoc; } - void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } - - SourceLocation getExprLoc() const LLVM_READONLY { - return getBase()->getExprLoc(); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == OMPArraySectionExprClass; - } - - child_range children() { - return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); - } - - const_child_range children() const { - return const_child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); - } -}; - /// An explicit cast in C or a C-style cast in C++, which uses the syntax /// ([s1][s2]...[sn])expr. For example: @c ([3][3])f. class OMPArrayShapingExpr final diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index eee8d6b6c6ef1..385c32edbae0f 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -99,7 +99,7 @@ class ExternalASTSource : public RefCountedBase { /// passes back decl sets as VisibleDeclaration objects. /// /// The default implementation of this method is a no-op. - virtual Decl *GetExternalDecl(Decl::DeclID ID); + virtual Decl *GetExternalDecl(GlobalDeclID ID); /// Resolve a selector ID into a selector. /// @@ -375,7 +375,7 @@ struct LazyOffsetPtr { if (isOffset()) { assert(Source && "Cannot deserialize a lazy pointer without an AST source"); - Ptr = reinterpret_cast((Source->*Get)(Ptr >> 1)); + Ptr = reinterpret_cast((Source->*Get)(OffsT(Ptr >> 1))); } return reinterpret_cast(Ptr); } @@ -579,7 +579,7 @@ using LazyDeclStmtPtr = /// A lazy pointer to a declaration. using LazyDeclPtr = - LazyOffsetPtr; + LazyOffsetPtr; /// A lazy pointer to a set of CXXCtorInitializers. using LazyCXXCtorInitializersPtr = diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 7b0c21b9e7cfb..a1d9e30e660d1 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -266,7 +266,7 @@ class NestedNameSpecifierLoc { explicit operator bool() const { return Qualifier; } /// Evaluates true when this nested-name-specifier location is - /// empty. + /// non-empty. bool hasQualifier() const { return Qualifier; } /// Retrieve the nested-name-specifier to which this instance diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 277a351c49fcb..bb4cb1f5d5080 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -156,51 +156,50 @@ class OpenACCSelfClause : public OpenACCClauseWithCondition { Expr *ConditionExpr, SourceLocation EndLoc); }; -/// Represents a clause that has one or more IntExprs. It does not own the -/// IntExprs, but provides 'children' and other accessors. -class OpenACCClauseWithIntExprs : public OpenACCClauseWithParams { - MutableArrayRef IntExprs; +/// Represents a clause that has one or more expressions associated with it. +class OpenACCClauseWithExprs : public OpenACCClauseWithParams { + MutableArrayRef Exprs; protected: - OpenACCClauseWithIntExprs(OpenACCClauseKind K, SourceLocation BeginLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) + OpenACCClauseWithExprs(OpenACCClauseKind K, SourceLocation BeginLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) : OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc) {} /// Used only for initialization, the leaf class can initialize this to /// trailing storage. - void setIntExprs(MutableArrayRef NewIntExprs) { - assert(IntExprs.empty() && "Cannot change IntExprs list"); - IntExprs = NewIntExprs; + void setExprs(MutableArrayRef NewExprs) { + assert(Exprs.empty() && "Cannot change Exprs list"); + Exprs = NewExprs; } - /// Gets the entire list of integer expressions, but leave it to the + /// Gets the entire list of expressions, but leave it to the /// individual clauses to expose this how they'd like. - llvm::ArrayRef getIntExprs() const { return IntExprs; } + llvm::ArrayRef getExprs() const { return Exprs; } public: child_range children() { - return child_range(reinterpret_cast(IntExprs.begin()), - reinterpret_cast(IntExprs.end())); + return child_range(reinterpret_cast(Exprs.begin()), + reinterpret_cast(Exprs.end())); } const_child_range children() const { child_range Children = - const_cast(this)->children(); + const_cast(this)->children(); return const_child_range(Children.begin(), Children.end()); } }; class OpenACCNumGangsClause final - : public OpenACCClauseWithIntExprs, + : public OpenACCClauseWithExprs, public llvm::TrailingObjects { OpenACCNumGangsClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef IntExprs, SourceLocation EndLoc) - : OpenACCClauseWithIntExprs(OpenACCClauseKind::NumGangs, BeginLoc, - LParenLoc, EndLoc) { + : OpenACCClauseWithExprs(OpenACCClauseKind::NumGangs, BeginLoc, LParenLoc, + EndLoc) { std::uninitialized_copy(IntExprs.begin(), IntExprs.end(), getTrailingObjects()); - setIntExprs(MutableArrayRef(getTrailingObjects(), IntExprs.size())); + setExprs(MutableArrayRef(getTrailingObjects(), IntExprs.size())); } public: @@ -209,35 +208,35 @@ class OpenACCNumGangsClause final ArrayRef IntExprs, SourceLocation EndLoc); llvm::ArrayRef getIntExprs() { - return OpenACCClauseWithIntExprs::getIntExprs(); + return OpenACCClauseWithExprs::getExprs(); } llvm::ArrayRef getIntExprs() const { - return OpenACCClauseWithIntExprs::getIntExprs(); + return OpenACCClauseWithExprs::getExprs(); } }; /// Represents one of a handful of clauses that have a single integer /// expression. -class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithIntExprs { +class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs { Expr *IntExpr; protected: OpenACCClauseWithSingleIntExpr(OpenACCClauseKind K, SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *IntExpr, SourceLocation EndLoc) - : OpenACCClauseWithIntExprs(K, BeginLoc, LParenLoc, EndLoc), + : OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc), IntExpr(IntExpr) { - setIntExprs(MutableArrayRef{&this->IntExpr, 1}); + setExprs(MutableArrayRef{&this->IntExpr, 1}); } public: - bool hasIntExpr() const { return !getIntExprs().empty(); } + bool hasIntExpr() const { return !getExprs().empty(); } const Expr *getIntExpr() const { - return hasIntExpr() ? getIntExprs()[0] : nullptr; + return hasIntExpr() ? getExprs()[0] : nullptr; } - Expr *getIntExpr() { return hasIntExpr() ? getIntExprs()[0] : nullptr; }; + Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; }; }; class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr { @@ -261,6 +260,40 @@ class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr { Expr *IntExpr, SourceLocation EndLoc); }; +/// Represents a clause with one or more 'var' objects, represented as an expr, +/// as its arguments. Var-list is expected to be stored in trailing storage. +/// For now, we're just storing the original expression in its entirety, unlike +/// OMP which has to do a bunch of work to create a private. +class OpenACCClauseWithVarList : public OpenACCClauseWithExprs { +protected: + OpenACCClauseWithVarList(OpenACCClauseKind K, SourceLocation BeginLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc) {} + +public: + ArrayRef getVarList() { return getExprs(); } + ArrayRef getVarList() const { return getExprs(); } +}; + +class OpenACCPrivateClause final + : public OpenACCClauseWithVarList, + public llvm::TrailingObjects { + + OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc) + : OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc, + LParenLoc, EndLoc) { + std::uninitialized_copy(VarList.begin(), VarList.end(), + getTrailingObjects()); + setExprs(MutableArrayRef(getTrailingObjects(), VarList.size())); + } + +public: + static OpenACCPrivateClause * + Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc); +}; + template class OpenACCClauseVisitor { Impl &getDerived() { return static_cast(*this); } @@ -299,6 +332,9 @@ template class OpenACCClauseVisitor { class OpenACCClausePrinter final : public OpenACCClauseVisitor { raw_ostream &OS; + const PrintingPolicy &Policy; + + void printExpr(const Expr *E); public: void VisitClauseList(ArrayRef List) { @@ -309,7 +345,8 @@ class OpenACCClausePrinter final OS << ' '; } } - OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {} + OpenACCClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy) + : OS(OS), Policy(Policy) {} #define VISIT_CLAUSE(CLAUSE_NAME) \ void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 0959e38919e50..317790ddbb424 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2754,7 +2754,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {}) DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {}) -DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) +DEF_TRAVERSE_STMT(ArraySectionExpr, {}) DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {}) DEF_TRAVERSE_STMT(OMPIteratorExpr, {}) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index c9cb52fd1c462..0de2ecfa01789 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -25,8 +25,10 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/PointerAuthOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/Visibility.h" @@ -139,6 +141,174 @@ using CanQualType = CanQual; #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.inc" +/// Pointer-authentication qualifiers. +class PointerAuthQualifier { + enum : uint32_t { + EnabledShift = 0, + EnabledBits = 1, + EnabledMask = 1 << EnabledShift, + AddressDiscriminatedShift = EnabledShift + EnabledBits, + AddressDiscriminatedBits = 1, + AddressDiscriminatedMask = 1 << AddressDiscriminatedShift, + AuthenticationModeShift = + AddressDiscriminatedShift + AddressDiscriminatedBits, + AuthenticationModeBits = 2, + AuthenticationModeMask = ((1 << AuthenticationModeBits) - 1) + << AuthenticationModeShift, + IsaPointerShift = AuthenticationModeShift + AuthenticationModeBits, + IsaPointerBits = 1, + IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift, + AuthenticatesNullValuesShift = IsaPointerShift + IsaPointerBits, + AuthenticatesNullValuesBits = 1, + AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1) + << AuthenticatesNullValuesShift, + KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits, + KeyBits = 10, + KeyMask = ((1 << KeyBits) - 1) << KeyShift, + DiscriminatorShift = KeyShift + KeyBits, + DiscriminatorBits = 16, + DiscriminatorMask = ((1u << DiscriminatorBits) - 1) << DiscriminatorShift, + }; + + // bits: |0 |1 |2..3 |4 | + // |Enabled|Address|AuthenticationMode|ISA pointer| + // bits: |5 |6..15| 16...31 | + // |AuthenticatesNull|Key |Discriminator| + uint32_t Data = 0; + + // The following static assertions check that each of the 32 bits is present + // exactly in one of the constants. + static_assert((EnabledBits + AddressDiscriminatedBits + + AuthenticationModeBits + IsaPointerBits + + AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) == + 32, + "PointerAuthQualifier should be exactly 32 bits"); + static_assert((EnabledMask + AddressDiscriminatedMask + + AuthenticationModeMask + IsaPointerMask + + AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) == + 0xFFFFFFFF, + "All masks should cover the entire bits"); + static_assert((EnabledMask ^ AddressDiscriminatedMask ^ + AuthenticationModeMask ^ IsaPointerMask ^ + AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) == + 0xFFFFFFFF, + "All masks should cover the entire bits"); + + PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated, + unsigned ExtraDiscriminator, + PointerAuthenticationMode AuthenticationMode, + bool IsIsaPointer, bool AuthenticatesNullValues) + : Data(EnabledMask | + (IsAddressDiscriminated + ? llvm::to_underlying(AddressDiscriminatedMask) + : 0) | + (Key << KeyShift) | + (llvm::to_underlying(AuthenticationMode) + << AuthenticationModeShift) | + (ExtraDiscriminator << DiscriminatorShift) | + (IsIsaPointer << IsaPointerShift) | + (AuthenticatesNullValues << AuthenticatesNullValuesShift)) { + assert(Key <= KeyNoneInternal); + assert(ExtraDiscriminator <= MaxDiscriminator); + assert((Data == 0) == + (getAuthenticationMode() == PointerAuthenticationMode::None)); + } + +public: + enum { + KeyNoneInternal = (1u << KeyBits) - 1, + + /// The maximum supported pointer-authentication key. + MaxKey = KeyNoneInternal - 1, + + /// The maximum supported pointer-authentication discriminator. + MaxDiscriminator = (1u << DiscriminatorBits) - 1 + }; + +public: + PointerAuthQualifier() = default; + + static PointerAuthQualifier + Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator, + PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer, + bool AuthenticatesNullValues) { + if (Key == PointerAuthKeyNone) + Key = KeyNoneInternal; + assert(Key <= KeyNoneInternal && "out-of-range key value"); + return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator, + AuthenticationMode, IsIsaPointer, + AuthenticatesNullValues); + } + + bool isPresent() const { + assert((Data == 0) == + (getAuthenticationMode() == PointerAuthenticationMode::None)); + return Data != 0; + } + + explicit operator bool() const { return isPresent(); } + + unsigned getKey() const { + assert(isPresent()); + return (Data & KeyMask) >> KeyShift; + } + + bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; } + + bool isAddressDiscriminated() const { + assert(isPresent()); + return (Data & AddressDiscriminatedMask) >> AddressDiscriminatedShift; + } + + unsigned getExtraDiscriminator() const { + assert(isPresent()); + return (Data >> DiscriminatorShift); + } + + PointerAuthenticationMode getAuthenticationMode() const { + return PointerAuthenticationMode((Data & AuthenticationModeMask) >> + AuthenticationModeShift); + } + + bool isIsaPointer() const { + assert(isPresent()); + return (Data & IsaPointerMask) >> IsaPointerShift; + } + + bool authenticatesNullValues() const { + assert(isPresent()); + return (Data & AuthenticatesNullValuesMask) >> AuthenticatesNullValuesShift; + } + + PointerAuthQualifier withoutKeyNone() const { + return hasKeyNone() ? PointerAuthQualifier() : *this; + } + + friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) { + return Lhs.Data == Rhs.Data; + } + friend bool operator!=(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) { + return Lhs.Data != Rhs.Data; + } + + bool isEquivalent(PointerAuthQualifier Other) const { + return withoutKeyNone() == Other.withoutKeyNone(); + } + + uint32_t getAsOpaqueValue() const { return Data; } + + // Deserialize pointer-auth qualifiers from an opaque representation. + static PointerAuthQualifier fromOpaqueValue(uint32_t Opaque) { + PointerAuthQualifier Result; + Result.Data = Opaque; + assert((Result.Data == 0) == + (Result.getAuthenticationMode() == PointerAuthenticationMode::None)); + return Result; + } + + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); } +}; + /// The collection of all-type qualifiers we support. /// Clang supports five independent qualifiers: /// * C99: const, volatile, and restrict @@ -147,8 +317,9 @@ using CanQualType = CanQual; /// * Objective C: the GC attributes (none, weak, or strong) class Qualifiers { public: - enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. - Const = 0x1, + enum TQ : uint64_t { + // NOTE: These flags must be kept in sync with DeclSpec::TQ. + Const = 0x1, Restrict = 0x2, Volatile = 0x4, CVRMask = Const | Volatile | Restrict @@ -182,7 +353,7 @@ class Qualifiers { OCL_Autoreleasing }; - enum { + enum : uint64_t { /// The maximum supported address space number. /// 23 bits should be enough for anyone. MaxAddressSpace = 0x7fffffu, @@ -197,16 +368,25 @@ class Qualifiers { /// Returns the common set of qualifiers while removing them from /// the given sets. static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { + Qualifiers Q; + PointerAuthQualifier LPtrAuth = L.getPointerAuth(); + if (LPtrAuth.isPresent() && + LPtrAuth.getKey() != PointerAuthQualifier::KeyNoneInternal && + LPtrAuth == R.getPointerAuth()) { + Q.setPointerAuth(LPtrAuth); + PointerAuthQualifier Empty; + L.setPointerAuth(Empty); + R.setPointerAuth(Empty); + } + // If both are only CVR-qualified, bit operations are sufficient. if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { - Qualifiers Q; Q.Mask = L.Mask & R.Mask; L.Mask &= ~Q.Mask; R.Mask &= ~Q.Mask; return Q; } - Qualifiers Q; unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); Q.addCVRQualifiers(CommonCRV); L.removeCVRQualifiers(CommonCRV); @@ -251,16 +431,14 @@ class Qualifiers { } // Deserialize qualifiers from an opaque representation. - static Qualifiers fromOpaqueValue(unsigned opaque) { + static Qualifiers fromOpaqueValue(uint64_t opaque) { Qualifiers Qs; Qs.Mask = opaque; return Qs; } // Serialize these qualifiers into an opaque representation. - unsigned getAsOpaqueValue() const { - return Mask; - } + uint64_t getAsOpaqueValue() const { return Mask; } bool hasConst() const { return Mask & Const; } bool hasOnlyConst() const { return Mask == Const; } @@ -302,7 +480,7 @@ class Qualifiers { } void removeCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); - Mask &= ~mask; + Mask &= ~static_cast(mask); } void removeCVRQualifiers() { removeCVRQualifiers(CVRMask); @@ -407,6 +585,20 @@ class Qualifiers { setAddressSpace(space); } + bool hasPointerAuth() const { return Mask & PtrAuthMask; } + PointerAuthQualifier getPointerAuth() const { + return PointerAuthQualifier::fromOpaqueValue(Mask >> PtrAuthShift); + } + void setPointerAuth(PointerAuthQualifier Q) { + Mask = (Mask & ~PtrAuthMask) | + (uint64_t(Q.getAsOpaqueValue()) << PtrAuthShift); + } + void removePointerAuth() { Mask &= ~PtrAuthMask; } + void addPointerAuth(PointerAuthQualifier Q) { + assert(Q.isPresent()); + setPointerAuth(Q); + } + // Fast qualifiers are those that can be allocated directly // on a QualType object. bool hasFastQualifiers() const { return getFastQualifiers(); } @@ -417,7 +609,7 @@ class Qualifiers { } void removeFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); - Mask &= ~mask; + Mask &= ~static_cast(mask); } void removeFastQualifiers() { removeFastQualifiers(FastMask); @@ -454,6 +646,8 @@ class Qualifiers { addObjCGCAttr(Q.getObjCGCAttr()); if (Q.hasObjCLifetime()) addObjCLifetime(Q.getObjCLifetime()); + if (Q.hasPointerAuth()) + addPointerAuth(Q.getPointerAuth()); } } @@ -471,6 +665,8 @@ class Qualifiers { removeObjCLifetime(); if (getAddressSpace() == Q.getAddressSpace()) removeAddressSpace(); + if (getPointerAuth() == Q.getPointerAuth()) + removePointerAuth(); } } @@ -483,6 +679,8 @@ class Qualifiers { !hasObjCGCAttr() || !qs.hasObjCGCAttr()); assert(getObjCLifetime() == qs.getObjCLifetime() || !hasObjCLifetime() || !qs.hasObjCLifetime()); + assert(!hasPointerAuth() || !qs.hasPointerAuth() || + getPointerAuth() == qs.getPointerAuth()); Mask |= qs.Mask; } @@ -536,6 +734,8 @@ class Qualifiers { // be changed. (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || !other.hasObjCGCAttr()) && + // Pointer-auth qualifiers must match exactly. + getPointerAuth() == other.getPointerAuth() && // ObjC lifetime qualifiers must match exactly. getObjCLifetime() == other.getObjCLifetime() && // CVR qualifiers may subset. @@ -605,24 +805,26 @@ class Qualifiers { void print(raw_ostream &OS, const PrintingPolicy &Policy, bool appendSpaceIfNonEmpty = false) const; - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger(Mask); - } + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } private: - // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| - // |C R V|U|GCAttr|Lifetime|AddressSpace| - uint32_t Mask = 0; - - static const uint32_t UMask = 0x8; - static const uint32_t UShift = 3; - static const uint32_t GCAttrMask = 0x30; - static const uint32_t GCAttrShift = 4; - static const uint32_t LifetimeMask = 0x1C0; - static const uint32_t LifetimeShift = 6; - static const uint32_t AddressSpaceMask = + // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|32 ... 63| + // |C R V|U|GCAttr|Lifetime|AddressSpace| PtrAuth | + uint64_t Mask = 0; + static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t), + "PointerAuthQualifier must be 32 bits"); + + static constexpr uint64_t UMask = 0x8; + static constexpr uint64_t UShift = 3; + static constexpr uint64_t GCAttrMask = 0x30; + static constexpr uint64_t GCAttrShift = 4; + static constexpr uint64_t LifetimeMask = 0x1C0; + static constexpr uint64_t LifetimeShift = 6; + static constexpr uint64_t AddressSpaceMask = ~(CVRMask | UMask | GCAttrMask | LifetimeMask); - static const uint32_t AddressSpaceShift = 9; + static constexpr uint64_t AddressSpaceShift = 9; + static constexpr uint64_t PtrAuthShift = 32; + static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; }; class QualifiersAndAtomic { @@ -1242,6 +1444,10 @@ class QualType { // true when Type is objc's weak and weak is enabled but ARC isn't. bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; + PointerAuthQualifier getPointerAuth() const { + return getQualifiers().getPointerAuth(); + } + enum PrimitiveDefaultInitializeKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a @@ -2172,6 +2378,10 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { /// 'riscv_rvv_vector_bits' type attribute as VectorType. QualType getRVVEltType(const ASTContext &Ctx) const; + /// Returns the representative type for the element of a sizeless vector + /// builtin type. + QualType getSizelessVectorEltType(const ASTContext &Ctx) const; + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index bbfcdb66dd6f2..a7238f6000c82 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -604,6 +604,49 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Enumeration specifying what kind of behavior should be used for late +// parsing of attributes. +class LateAttrParseKind { + int Kind = val; +} + +// Never late parsed +def LateAttrParseNever : LateAttrParseKind<0>; + +// Standard late attribute parsing +// +// This is language dependent. For example: +// +// * For C++ enables late parsing of a declaration attributes +// * For C does not enable late parsing of attributes +// +def LateAttrParseStandard : LateAttrParseKind<1>; + +// Experimental extension to standard late attribute parsing +// +// This extension behaves like `LateAttrParseStandard` but allows +// late parsing attributes in more contexts. +// +// In contexts where `LateAttrParseStandard` attributes are late +// parsed, `LateAttrParseExperimentalExt` attributes will also +// be late parsed. +// +// In contexts that only late parse `LateAttrParseExperimentalExt` attributes +// (see `LateParsedAttrList::lateAttrParseExperimentalExtOnly()`) +// +// * If `-fexperimental-late-parse-attributes` +// (`LangOpts.ExperimentalLateParseAttributes`) is enabled the attribute +// will be late parsed. +// * If `-fexperimental-late-parse-attributes` +// (`LangOpts.ExperimentalLateParseAttributes`) is disabled the attribute +// will **not** be late parsed (i.e parsed immediately). +// +// The following contexts are supported: +// +// * TODO: Add contexts here when they are implemented. +// +def LateAttrParseExperimentalExt : LateAttrParseKind<2>; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -615,8 +658,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list TargetSpecificSpellings = []; - // Set to true for attributes with arguments which require delayed parsing. - bit LateParsed = 0; + // Specifies the late parsing kind. + LateAttrParseKind LateParsed = LateAttrParseNever; // Set to false to prevent an attribute from being propagated from a template // to the instantiation. bit Clone = 1; @@ -4179,7 +4222,7 @@ def DiagnoseIf : InheritableAttr { BoolArgument<"ArgDependent", 0, /*fake*/ 1>, DeclArgument]; let InheritEvenIfAlreadyPresent = 1; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let AdditionalMembers = [{ bool isError() const { return diagnosticType == DT_Error; } bool isWarning() const { return diagnosticType == DT_Warning; } @@ -4217,7 +4260,7 @@ def ObjCRequiresPropertyDefs : InheritableAttr { def Unused : InheritableAttr { let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, C23<"", "maybe_unused", 202106>]; - let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label, + let Subjects = SubjectList<[Var, Binding, ObjCIvar, Type, Enum, EnumConstant, Label, Field, ObjCMethod, FunctionLike]>; let Documentation = [WarnMaybeUnusedDocs]; } @@ -4478,7 +4521,7 @@ def AssertCapability : InheritableAttr { let Spellings = [Clang<"assert_capability", 0>, Clang<"assert_shared_capability", 0>]; let Subjects = SubjectList<[Function]>; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4494,7 +4537,7 @@ def AcquireCapability : InheritableAttr { GNU<"exclusive_lock_function">, GNU<"shared_lock_function">]; let Subjects = SubjectList<[Function]>; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4510,7 +4553,7 @@ def TryAcquireCapability : InheritableAttr { Clang<"try_acquire_shared_capability", 0>]; let Subjects = SubjectList<[Function], ErrorDiag>; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4526,7 +4569,7 @@ def ReleaseCapability : InheritableAttr { Clang<"release_generic_capability", 0>, Clang<"unlock_function", 0>]; let Subjects = SubjectList<[Function]>; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4545,7 +4588,7 @@ def RequiresCapability : InheritableAttr { Clang<"requires_shared_capability", 0>, Clang<"shared_locks_required", 0>]; let Args = [VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4565,7 +4608,7 @@ def NoThreadSafetyAnalysis : InheritableAttr { def GuardedBy : InheritableAttr { let Spellings = [GNU<"guarded_by">]; let Args = [ExprArgument<"Arg">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4576,7 +4619,7 @@ def GuardedBy : InheritableAttr { def PtGuardedBy : InheritableAttr { let Spellings = [GNU<"pt_guarded_by">]; let Args = [ExprArgument<"Arg">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4587,7 +4630,7 @@ def PtGuardedBy : InheritableAttr { def AcquiredAfter : InheritableAttr { let Spellings = [GNU<"acquired_after">]; let Args = [VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4598,7 +4641,7 @@ def AcquiredAfter : InheritableAttr { def AcquiredBefore : InheritableAttr { let Spellings = [GNU<"acquired_before">]; let Args = [VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4609,7 +4652,7 @@ def AcquiredBefore : InheritableAttr { def AssertExclusiveLock : InheritableAttr { let Spellings = [GNU<"assert_exclusive_lock">]; let Args = [VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4620,7 +4663,7 @@ def AssertExclusiveLock : InheritableAttr { def AssertSharedLock : InheritableAttr { let Spellings = [GNU<"assert_shared_lock">]; let Args = [VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4633,7 +4676,7 @@ def AssertSharedLock : InheritableAttr { def ExclusiveTrylockFunction : InheritableAttr { let Spellings = [GNU<"exclusive_trylock_function">]; let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4646,7 +4689,7 @@ def ExclusiveTrylockFunction : InheritableAttr { def SharedTrylockFunction : InheritableAttr { let Spellings = [GNU<"shared_trylock_function">]; let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; @@ -4657,7 +4700,7 @@ def SharedTrylockFunction : InheritableAttr { def LockReturned : InheritableAttr { let Spellings = [GNU<"lock_returned">]; let Args = [ExprArgument<"Arg">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let Subjects = SubjectList<[Function]>; @@ -4667,7 +4710,7 @@ def LockReturned : InheritableAttr { def LocksExcluded : InheritableAttr { let Spellings = [GNU<"locks_excluded">]; let Args = [VariadicExprArgument<"Args">]; - let LateParsed = 1; + let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index cf3ddb9869e37..430bf9dc3e17d 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -378,4 +378,7 @@ def warn_missing_symbol_graph_dir : Warning< "Missing symbol graph output directory, defaulting to working directory">, InGroup; +def err_ast_action_on_llvm_ir : Error< + "cannot apply AST actions to LLVM IR file '%0'">, + DefaultFatal; } diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 91a40cd589b38..6896e0f5aa593 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -24,7 +24,7 @@ def err_no_matching_target : Error<"no matching target found for target variant def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">; def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">; def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; -def err_cannot_read_alias_list : Error<"could not read alias list '%0': %1">; +def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 38174cf3549f1..44bc4e0e130de 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -478,6 +478,15 @@ def ext_decomp_decl_empty : ExtWarn< "ISO C++17 does not allow a decomposition group to be empty">, InGroup>; +// C++26 structured bindings +def ext_decl_attrs_on_binding : ExtWarn< + "an attribute specifier sequence attached to a structured binding declaration " + "is a C++2c extension">, InGroup; +def warn_cxx23_compat_decl_attrs_on_binding : Warning< + "an attribute specifier sequence attached to a structured binding declaration " + "is incompatible with C++ standards before C++2c">, + InGroup, DefaultIgnore; + /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< "method type specifier must start with '-' or '+'">; @@ -1429,6 +1438,9 @@ def err_omp_decl_in_declare_simd_variant : Error< def err_omp_sink_and_source_iteration_not_allowd: Error<" '%0 %select{sink:|source:}1' must be with '%select{omp_cur_iteration - 1|omp_cur_iteration}1'">; def err_omp_unknown_map_type : Error< "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; +def err_omp_more_one_map_type : Error<"map type is already specified">; +def note_previous_map_type_specified_here + : Note<"map type '%0' is previous specified here">; def err_omp_unknown_map_type_modifier : Error< "incorrect map type modifier, expected one of: 'always', 'close', 'mapper'" "%select{|, 'present'|, 'present', 'iterator'}0%select{|, 'ompx_hold'}1">; @@ -1436,6 +1448,8 @@ def err_omp_map_type_missing : Error< "missing map type">; def err_omp_map_type_modifier_missing : Error< "missing map type modifier">; +def err_omp_map_modifier_specification_list : Error< + "empty modifier-specification-list is not allowed">; def err_omp_declare_simd_inbranch_notinbranch : Error< "unexpected '%0' clause, '%1' is specified already">; def err_omp_expected_clause_argument diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index df1c588b94ffc..ea59bee0476e9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -375,6 +375,8 @@ def err_invalid_vector_long_long_decl_spec : Error < "POWER7 or later) to be enabled">; def err_invalid_vector_long_double_decl_spec : Error< "cannot use 'long double' with '__vector'">; +def err_invalid_vector_complex_decl_spec : Error< + "cannot use '_Complex' with '__vector'">; def warn_vector_long_decl_spec_combination : Warning< "Use of 'long' with '__vector' is deprecated">, InGroup; @@ -10001,6 +10003,9 @@ def warn_format_invalid_annotation : Warning< def warn_format_P_no_precision : Warning< "using '%%P' format specifier without precision">, InGroup; +def warn_format_P_with_objc_pointer : Warning< + "using '%%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value">, + InGroup; def warn_printf_ignored_flag: Warning< "flag '%0' is ignored when flag '%1' is present">, InGroup; @@ -10050,6 +10055,8 @@ def warn_ret_stack_addr_ref : Warning< def warn_ret_local_temp_addr_ref : Warning< "returning %select{address of|reference to}0 local temporary object">, InGroup; +def err_ret_local_temp_ref : Error< + "returning reference to local temporary object">; def warn_ret_addr_label : Warning< "returning address of label, which is local">, InGroup; @@ -10428,9 +10435,13 @@ def err_shufflevector_nonconstant_argument : Error< def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; +def err_shufflevector_minus_one_is_undefined_behavior_constexpr : Error< + "index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position %0 not permitted in a constexpr context.">; def err_convertvector_non_vector : Error< "first argument to __builtin_convertvector must be a vector">; +def err_convertvector_constexpr_unsupported_vector_cast : Error< + "unsupported vector cast from %0 to %1 in a constant expression.">; def err_builtin_non_vector_type : Error< "%0 argument to %1 must be of vector type">; def err_convertvector_incompatible_vector : Error< @@ -11268,7 +11279,7 @@ def err_omp_declare_mapper_redefinition : Error< "redefinition of user-defined mapper for type %0 with name %1">; def err_omp_invalid_mapper: Error< "cannot find a valid user-defined mapper for type %0 with name %1">; -def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">; +def err_array_section_use : Error<"%select{OpenACC sub-array|OpenMP array section}0 is not allowed here">; def err_omp_array_shaping_use : Error<"OpenMP array shaping operation is not allowed here">; def err_omp_iterator_use : Error<"OpenMP iterator is not allowed here">; def err_omp_typecheck_section_value : Error< @@ -12585,4 +12596,7 @@ def err_acc_num_gangs_num_args "OpenACC 'num_gangs' " "%select{|clause: '%1' directive expects maximum of %2, %3 were " "provided}0">; +def err_acc_not_a_var_ref + : Error<"OpenACC variable is not a valid variable name, sub-array, array " + "element, or composite variable member">; } // end of sema component. diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 2245fd78bfc9f..8b4206e52cd48 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -114,6 +114,12 @@ class FileManager : public RefCountedBase { /// unsigned NextFileUID; + /// Statistics gathered during the lifetime of the FileManager. + unsigned NumDirLookups = 0; + unsigned NumFileLookups = 0; + unsigned NumDirCacheMisses = 0; + unsigned NumFileCacheMisses = 0; + // Caching. std::unique_ptr StatCache; @@ -341,6 +347,10 @@ class FileManager : public RefCountedBase { public: void PrintStats() const; + + /// Import statistics from a child FileManager and add them to this current + /// FileManager. + void AddStats(const FileManager &Other); }; } // end namespace clang diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 8e4d3bb40ea3c..5c6029e2c6a12 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -164,6 +164,7 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics") LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") +LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes") COMPATIBLE_LANGOPT(RecoveryAST, 1, 1, "Preserve expressions in AST when encountering errors") COMPATIBLE_LANGOPT(RecoveryASTType, 1, 1, "Preserve the type in recovery expressions") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 14414fbcf6a78..dcf604f9a8ea8 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -57,6 +57,13 @@ enum class ShaderStage { Invalid, }; +enum class PointerAuthenticationMode : unsigned { + None, + Strip, + SignAndStrip, + SignAndAuth +}; + /// Bitfields of LangOptions, split out from LangOptions in order to ensure that /// this large collection of bitfields is a trivial class type. class LangOptionsBase { diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index dd5792e7ca8c3..6c3c2db66ef0c 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -20,6 +20,7 @@ VISIT_CLAUSE(If) VISIT_CLAUSE(Self) VISIT_CLAUSE(NumGangs) VISIT_CLAUSE(NumWorkers) +VISIT_CLAUSE(Private) VISIT_CLAUSE(VectorLength) #undef VISIT_CLAUSE diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h new file mode 100644 index 0000000000000..e5cdcc31ebfb7 --- /dev/null +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -0,0 +1,23 @@ +//===--- PointerAuthOptions.h -----------------------------------*- 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 options for configuring pointer-auth technologies +// like ARMv8.3. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H +#define LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H + +namespace clang { + +constexpr unsigned PointerAuthKeyNone = -1; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 4b1678252fd4f..c124be0b55c0f 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -72,7 +72,7 @@ def OffsetOfExpr : StmtNode; def UnaryExprOrTypeTraitExpr : StmtNode; def ArraySubscriptExpr : StmtNode; def MatrixSubscriptExpr : StmtNode; -def OMPArraySectionExpr : StmtNode; +def ArraySectionExpr : StmtNode; def OMPIteratorExpr : StmtNode; def CallExpr : StmtNode; def MemberExpr : StmtNode; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index e1ef7454f0166..3ced2e7397a75 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -40,6 +40,7 @@ #include #include #include +#include #include namespace llvm { @@ -1792,6 +1793,15 @@ class TargetInfo : public TransferrableTargetInfo, /// Whether to support HIP image/texture API's. virtual bool hasHIPImageSupport() const { return true; } + /// The first value in the pair is the minimum offset between two objects to + /// avoid false sharing (destructive interference). The second value in the + /// pair is maximum size of contiguous memory to promote true sharing + /// (constructive interference). Neither of these values are considered part + /// of the ABI and can be changed by targets at any time. + virtual std::pair hardwareInterferenceSizes() const { + return std::make_pair(64, 64); + } + protected: /// Copy type and layout related info. void copyAuxTarget(const TargetInfo *Aux); diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td index 6d655c39360d3..6390ba3f9fe5e 100644 --- a/clang/include/clang/Basic/arm_neon.td +++ b/clang/include/clang/Basic/arm_neon.td @@ -275,7 +275,7 @@ def OP_VCVT_BF16_F32_HI_A32 (call "vget_low", $p0))>; def OP_CVT_F32_BF16 - : Op<(bitcast "R", (op "<<", (bitcast "int32_t", $p0), + : Op<(bitcast "R", (op "<<", (cast "int32_t", (bitcast "int16_t", $p0)), (literal "int32_t", "16")))>; //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index 6cc249837d3f3..15340ebb62b36 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -1961,19 +1961,20 @@ def SVPSEL_D : SInst<"svpsel_lane_b64", "PPPm", "Pl", MergeNone, "", [IsStreamin // 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]>; +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", "csilUcUsUiUl", 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 SVFADDQV : SInst<"svaddqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_faddqv", [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 { diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td index 98ae17ec22a04..cca4367751b92 100644 --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -2601,8 +2601,7 @@ multiclass RVVOutBuiltinSetZvk { if HasVS then { foreach vs2_lmul = ["(SEFixedLog2LMUL:-1)", "(SEFixedLog2LMUL:0)", - "(SEFixedLog2LMUL:1)", "(SEFixedLog2LMUL:2)", - "(SEFixedLog2LMUL:3)"] in { + "(SEFixedLog2LMUL:1)", "(SEFixedLog2LMUL:2)"] in { defvar name = NAME # !if(!eq(NAME, "vaesz"), "", "_vs"); let OverloadedName = name, IRName = NAME # "_vs", Name = NAME # "_vs", IntrinsicTypes = [-1, 1] in diff --git a/clang/include/clang/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt index e69de29bb2d1d..f8d6f407a03d0 100644 --- a/clang/include/clang/CIR/CMakeLists.txt +++ b/clang/include/clang/CIR/CMakeLists.txt @@ -0,0 +1,6 @@ +set(MLIR_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../mlir/include ) # --includedir +set(MLIR_TABLEGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tools/mlir/include) +include_directories(${MLIR_INCLUDE_DIR}) +include_directories(${MLIR_TABLEGEN_OUTPUT_DIR}) + +add_subdirectory(Dialect) diff --git a/clang/include/clang/CIR/Dialect/CMakeLists.txt b/clang/include/clang/CIR/Dialect/CMakeLists.txt new file mode 100644 index 0000000000000..f33061b2d87cf --- /dev/null +++ b/clang/include/clang/CIR/Dialect/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(IR) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h new file mode 100644 index 0000000000000..d53e5d1663d62 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h @@ -0,0 +1,16 @@ +//===- CIRDialect.h - CIR dialect -------------------------------*- 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 declares the CIR dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H +#define LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H + +#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td new file mode 100644 index 0000000000000..69d6e9774942b --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -0,0 +1,44 @@ +//===- CIRDialect.td - CIR dialect -------------------------*- tablegen -*-===// +// +// 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 declares the CIR dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT +#define LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT + +include "mlir/IR/OpBase.td" + +def CIR_Dialect : Dialect { + let name = "cir"; + + // A short one-line summary of our dialect. + let summary = "A high-level dialect for analyzing and optimizing Clang " + "supported languages"; + + let cppNamespace = "::mlir::cir"; + + let useDefaultAttributePrinterParser = 0; + let useDefaultTypePrinterParser = 0; + + let extraClassDeclaration = [{ + void registerAttributes(); + void registerTypes(); + + Type parseType(DialectAsmParser &parser) const override; + void printType(Type type, DialectAsmPrinter &printer) const override; + + Attribute parseAttribute(DialectAsmParser &parser, + Type type) const override; + + void printAttribute(Attribute attr, DialectAsmPrinter &os) const override; + }]; +} + +#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td new file mode 100644 index 0000000000000..7311c8db783e0 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -0,0 +1,19 @@ +//===-- CIROps.td - CIR dialect definition -----------------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of the CIR dialect +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIROPS +#define LLVM_CLANG_CIR_DIALECT_IR_CIROPS + +include "clang/CIR/Dialect/IR/CIRDialect.td" + +#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt new file mode 100644 index 0000000000000..28ae30dab8dfb --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt @@ -0,0 +1,16 @@ +# This replicates part of the add_mlir_dialect cmake function from MLIR that +# cannot be used here. This happens because it expects to be run inside MLIR +# directory which is not the case for CIR (and also FIR, both have similar +# workarounds). + +# Equivalent to add_mlir_dialect(CIROps cir) +set(LLVM_TARGET_DEFINITIONS CIROps.td) +mlir_tablegen(CIROps.h.inc -gen-op-decls) +mlir_tablegen(CIROps.cpp.inc -gen-op-defs) +mlir_tablegen(CIROpsTypes.h.inc -gen-typedef-decls) +mlir_tablegen(CIROpsTypes.cpp.inc -gen-typedef-defs) +mlir_tablegen(CIROpsDialect.h.inc -gen-dialect-decls) +mlir_tablegen(CIROpsDialect.cpp.inc -gen-dialect-defs) +add_public_tablegen_target(MLIRCIROpsIncGen) +add_dependencies(mlir-headers MLIRCIROpsIncGen) + diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 0892134051c28..f75b4fb7c3d30 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1679,6 +1679,13 @@ defm double_square_bracket_attributes : BoolFOption<"double-square-bracket-attri LangOpts<"DoubleSquareBracketAttributes">, DefaultTrue, PosFlag, NegFlag>; +defm experimental_late_parse_attributes : BoolFOption<"experimental-late-parse-attributes", + LangOpts<"ExperimentalLateParseAttributes">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], [ClangOption, CC1Option], + " experimental late parsing of attributes">>; + defm autolink : BoolFOption<"autolink", CodeGenOpts<"Autolink">, DefaultTrue, NegFlag, NegFlag>; +defm daz_ftz : SimpleMFlag<"daz-ftz", + "Globally set", "Do not globally set", + " the denormals-are-zero (DAZ) and flush-to-zero (FTZ) bits in the " + "floating-point control register on program startup">; + def ffor_scope : Flag<["-"], "ffor-scope">, Group; def fno_for_scope : Flag<["-"], "fno-for-scope">, Group; @@ -2960,6 +2972,17 @@ def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group, Group, HelpText<"Force linking the clang builtins runtime library">; + +/// ClangIR-specific options - BEGIN +defm clangir : BoolFOption<"clangir", + FrontendOpts<"UseClangIRPipeline">, DefaultFalse, + PosFlag, + NegFlag LLVM pipeline to compile">, + BothFlags<[], [ClangOption, CC1Option], "">>; +def emit_cir : Flag<["-"], "emit-cir">, Visibility<[CC1Option]>, + Group, HelpText<"Build ASTs and then lower to ClangIR">; +/// ClangIR-specific options - END + def flto_EQ : Joined<["-"], "flto=">, Visibility<[ClangOption, CLOption, CC1Option, FC1Option, FlangOption]>, Group, @@ -5169,6 +5192,8 @@ def msimd128 : Flag<["-"], "msimd128">, Group; def mno_simd128 : Flag<["-"], "mno-simd128">, Group; def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group; def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group; +def mhalf_precision : Flag<["-"], "mhalf-precision">, Group; +def mno_half_precision : Flag<["-"], "mno-half-precision">, Group; def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group; def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group; def msign_ext : Flag<["-"], "msign-ext">, Group; @@ -6919,12 +6944,6 @@ def J : JoinedOrSeparate<["-"], "J">, Group, Alias; -let Visibility = [FlangOption] in { -def no_fortran_main : Flag<["-"], "fno-fortran-main">, - Visibility<[FlangOption]>, Group, - HelpText<"Do not include Fortran_main.a (provided by Flang) when linking">; -} // let Visibility = [ FlangOption ] - //===----------------------------------------------------------------------===// // FC1 Options //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index a2c1b25dd2247..080844893c13c 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -241,7 +241,7 @@ class ASTUnit { /// A list of the serialization ID numbers for each of the top-level /// declarations parsed within the precompiled preamble. - std::vector TopLevelDeclsInPreamble; + std::vector TopLevelDeclsInPreamble; /// Whether we should be caching code-completion results. bool ShouldCacheCodeCompletionResults : 1; diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index a738c1f375768..bd4981ca0ac08 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -65,6 +65,9 @@ enum ActionKind { /// Translate input source into HTML. EmitHTML, + /// Emit a .cir file + EmitCIR, + /// Emit a .ll file. EmitLLVM, @@ -408,6 +411,10 @@ class FrontendOptions { LLVM_PREFERRED_TYPE(bool) unsigned GenReducedBMI : 1; + /// Use Clang IR pipeline to emit code + LLVM_PREFERRED_TYPE(bool) + unsigned UseClangIRPipeline : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -590,7 +597,7 @@ class FrontendOptions { EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false), EmitSymbolGraphSymbolLabelsForTesting(false), EmitPrettySymbolGraphs(false), GenReducedBMI(false), - TimeTraceGranularity(500) {} + UseClangIRPipeline(false), TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. diff --git a/clang/include/clang/Frontend/MultiplexConsumer.h b/clang/include/clang/Frontend/MultiplexConsumer.h index 7f8d2858b3863..f29c8e92fded0 100644 --- a/clang/include/clang/Frontend/MultiplexConsumer.h +++ b/clang/include/clang/Frontend/MultiplexConsumer.h @@ -35,7 +35,7 @@ class MultiplexASTDeserializationListener : public ASTDeserializationListener { void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) override; void MacroRead(serialization::MacroID ID, MacroInfo *MI) override; void TypeRead(serialization::TypeIdx Idx, QualType T) override; - void DeclRead(serialization::DeclID ID, const Decl *D) override; + void DeclRead(GlobalDeclID ID, const Decl *D) override; void SelectorRead(serialization::SelectorID iD, Selector Sel) override; void MacroDefinitionRead(serialization::PreprocessedEntityID, MacroDefinitionRecord *MD) override; diff --git a/clang/include/clang/InstallAPI/FileList.h b/clang/include/clang/InstallAPI/FileList.h index 460af003b6a0a..913734b8dc7c8 100644 --- a/clang/include/clang/InstallAPI/FileList.h +++ b/clang/include/clang/InstallAPI/FileList.h @@ -29,9 +29,10 @@ class FileListReader { /// /// \param InputBuffer JSON input data. /// \param Destination Container to load headers into. + /// \param FM Optional File Manager to validate input files exist. static llvm::Error loadHeaders(std::unique_ptr InputBuffer, - HeaderSeq &Destination); + HeaderSeq &Destination, clang::FileManager *FM = nullptr); FileListReader() = delete; }; diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index c5f90ef4cb368..5ac63dddd4d4e 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -56,6 +56,12 @@ class TargetInfo; /// The preprocessor keeps track of this information for each /// file that is \#included. struct HeaderFileInfo { + // TODO: Whether the file was included is not a property of the file itself. + // It's a preprocessor state, move it there. + /// True if this file has been included (or imported) **locally**. + LLVM_PREFERRED_TYPE(bool) + unsigned IsLocallyIncluded : 1; + // TODO: Whether the file was imported is not a property of the file itself. // It's a preprocessor state, move it there. /// True if this is a \#import'd file. @@ -135,10 +141,10 @@ struct HeaderFileInfo { StringRef Framework; HeaderFileInfo() - : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), - External(false), isModuleHeader(false), isTextualModuleHeader(false), - isCompilingModuleHeader(false), Resolved(false), - IndexHeaderMapHeader(false), IsValid(false) {} + : IsLocallyIncluded(false), isImport(false), isPragmaOnce(false), + DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false), + isTextualModuleHeader(false), isCompilingModuleHeader(false), + Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {} /// Retrieve the controlling macro for this header file, if /// any. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 1ca0c8e4d47c7..97ce8e3f035f8 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1398,12 +1398,21 @@ class Parser : public CodeCompletionHandler { // A list of late-parsed attributes. Used by ParseGNUAttributes. class LateParsedAttrList: public SmallVector { public: - LateParsedAttrList(bool PSoon = false) : ParseSoon(PSoon) { } + LateParsedAttrList(bool PSoon = false, + bool LateAttrParseExperimentalExtOnly = false) + : ParseSoon(PSoon), + LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly) {} bool parseSoon() { return ParseSoon; } + /// returns true iff the attribute to be parsed should only be late parsed + /// if it is annotated with `LateAttrParseExperimentalExt` + bool lateAttrParseExperimentalExtOnly() { + return LateAttrParseExperimentalExtOnly; + } private: - bool ParseSoon; // Are we planning to parse these shortly after creation? + bool ParseSoon; // Are we planning to parse these shortly after creation? + bool LateAttrParseExperimentalExtOnly; }; /// Contains the lexed tokens of a member function definition @@ -3646,11 +3655,12 @@ class Parser : public CodeCompletionHandler { ExprResult ParseOpenACCIDExpression(); /// Parses the variable list for the `cache` construct. void ParseOpenACCCacheVarList(); + + using OpenACCVarParseResult = std::pair; /// Parses a single variable in a variable list for OpenACC. - bool ParseOpenACCVar(); - /// Parses the variable list for the variety of clauses that take a var-list, - /// including the optional Special Token listed for some,based on clause type. - bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind); + OpenACCVarParseResult ParseOpenACCVar(); + /// Parses the variable list for the variety of places that take a var-list. + llvm::SmallVector ParseOpenACCVarList(); /// Parses any parameters for an OpenACC Clause, including required/optional /// parens. OpenACCClauseParseResult diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index c9eecdafe62c7..23bc780e04979 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -36,6 +36,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include namespace clang { class ASTContext; @@ -1790,6 +1791,7 @@ class DecompositionDeclarator { struct Binding { IdentifierInfo *Name; SourceLocation NameLoc; + std::optional Attrs; }; private: @@ -1809,15 +1811,15 @@ class DecompositionDeclarator { : Bindings(nullptr), NumBindings(0), DeleteBindings(false) {} DecompositionDeclarator(const DecompositionDeclarator &G) = delete; DecompositionDeclarator &operator=(const DecompositionDeclarator &G) = delete; - ~DecompositionDeclarator() { - if (DeleteBindings) - delete[] Bindings; - } + ~DecompositionDeclarator() { clear(); } void clear() { LSquareLoc = RSquareLoc = SourceLocation(); if (DeleteBindings) delete[] Bindings; + else + llvm::for_each(llvm::MutableArrayRef(Bindings, NumBindings), + [](Binding &B) { B.Attrs.reset(); }); Bindings = nullptr; NumBindings = 0; DeleteBindings = false; @@ -2339,10 +2341,10 @@ class Declarator { } /// Set the decomposition bindings for this declarator. - void - setDecompositionBindings(SourceLocation LSquareLoc, - ArrayRef Bindings, - SourceLocation RSquareLoc); + void setDecompositionBindings( + SourceLocation LSquareLoc, + MutableArrayRef Bindings, + SourceLocation RSquareLoc); /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to /// EndLoc, which should be the last token of the chunk. diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index 0db5b847038ff..b0a08a05ac6a0 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -499,7 +499,9 @@ class LookupResult { /// Note that while no result was found in the current instantiation, /// there were dependent base classes that could not be searched. void setNotFoundInCurrentInstantiation() { - assert(ResultKind == NotFound && Decls.empty()); + assert((ResultKind == NotFound || + ResultKind == NotFoundInCurrentInstantiation) && + Decls.empty()); ResultKind = NotFoundInCurrentInstantiation; } diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 993c9b1daa309..238fb398b7d12 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -65,7 +65,7 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { /// Resolve a declaration ID into a declaration, potentially /// building a new declaration. - Decl *GetExternalDecl(Decl::DeclID ID) override; + Decl *GetExternalDecl(GlobalDeclID ID) override; /// Complete the redeclaration chain if it's been extended since the /// previous generation of the AST source. diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index ca766c3de5eea..dbb399d0c489b 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -953,6 +953,7 @@ class ParsedAttributes : public ParsedAttributesView { ParsedAttributes(AttributeFactory &factory) : pool(factory) {} ParsedAttributes(const ParsedAttributes &) = delete; ParsedAttributes &operator=(const ParsedAttributes &) = delete; + ParsedAttributes(ParsedAttributes &&G) = default; AttributePool &getPool() const { return pool; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0cddb730c3cc2..154bdf00ebe5f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4266,12 +4266,12 @@ class Sema final : public SemaBase { SmallVectorImpl &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI); - /// Add an exception-specification to the given member function - /// (or member function template). The exception-specification was parsed - /// after the method itself was declared. + /// Add an exception-specification to the given member or friend function + /// (or function template). The exception-specification was parsed + /// after the function itself was declared. void actOnDelayedExceptionSpecification( - Decl *Method, ExceptionSpecificationType EST, - SourceRange SpecificationRange, ArrayRef DynamicExceptions, + Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange, + ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr); class InheritedConstructorInfo; @@ -7147,12 +7147,6 @@ class Sema final : public SemaBase { SourceLocation TemplateKWLoc, UnqualifiedId &Member, Decl *ObjCImpDecl); - MemberExpr *BuildMemberExpr( - Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, - SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, - bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, - QualType Ty, ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = nullptr); MemberExpr * BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, @@ -7641,7 +7635,7 @@ class Sema final : public SemaBase { bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS); bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, - bool AllowBuiltinCreation = false, + QualType ObjectType, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol( IdentifierInfo *II, SourceLocation IdLoc, @@ -9074,11 +9068,13 @@ class Sema final : public SemaBase { /// functions (but no function templates). FoundFunctions, }; - bool LookupTemplateName( - LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, - bool EnteringContext, bool &MemberOfUnknownSpecialization, - RequiredTemplateKind RequiredTemplate = SourceLocation(), - AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true); + + bool + LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, + QualType ObjectType, bool EnteringContext, + RequiredTemplateKind RequiredTemplate = SourceLocation(), + AssumedTemplateKind *ATK = nullptr, + bool AllowTypoCorrection = true); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, @@ -9442,7 +9438,8 @@ class Sema final : public SemaBase { void NoteTemplateParameterLocation(const NamedDecl &Decl); ExprResult BuildExpressionFromDeclTemplateArgument( - const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); + const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc, + NamedDecl *TemplateParam = nullptr); ExprResult BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); @@ -9765,9 +9762,10 @@ class Sema final : public SemaBase { bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg); - TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, - QualType NTTPType, - SourceLocation Loc); + TemplateArgumentLoc + getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, + SourceLocation Loc, + NamedDecl *TemplateParam = nullptr); /// Get a template argument mapping the given template parameter to itself, /// e.g. for X in \c template, this would return an expression template diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index ea28617f79b81..edb0cbb7c5d55 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -48,8 +48,12 @@ class SemaOpenACC : public SemaBase { SmallVector IntExprs; }; + struct VarListDetails { + SmallVector VarList; + }; + std::variant + IntExprDetails, VarListDetails> Details = std::monostate{}; public: @@ -112,6 +116,16 @@ class SemaOpenACC : public SemaBase { return const_cast(this)->getIntExprs(); } + ArrayRef getVarList() { + assert(ClauseKind == OpenACCClauseKind::Private && + "Parsed clause kind does not have a var-list"); + return std::get(Details).VarList; + } + + ArrayRef getVarList() const { + return const_cast(this)->getVarList(); + } + void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } @@ -147,7 +161,19 @@ class SemaOpenACC : public SemaBase { ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); - Details = IntExprDetails{IntExprs}; + Details = IntExprDetails{std::move(IntExprs)}; + } + + void setVarListDetails(ArrayRef VarList) { + assert(ClauseKind == OpenACCClauseKind::Private && + "Parsed clause kind does not have a var-list"); + Details = VarListDetails{{VarList.begin(), VarList.end()}}; + } + + void setVarListDetails(llvm::SmallVector &&VarList) { + assert(ClauseKind == OpenACCClauseKind::Private && + "Parsed clause kind does not have a var-list"); + Details = VarListDetails{std::move(VarList)}; } }; @@ -193,6 +219,16 @@ class SemaOpenACC : public SemaBase { /// conversions and diagnostics to 'int'. ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation Loc, Expr *IntExpr); + + /// Called when encountering a 'var' for OpenACC, ensures it is actually a + /// declaration reference to a variable of the correct type. + ExprResult ActOnVar(Expr *VarExpr); + + /// Checks and creates an Array Section used in an OpenACC construct/clause. + ExprResult ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc, + Expr *LowerBound, + SourceLocation ColonLocFirst, Expr *Length, + SourceLocation RBLoc); }; } // namespace clang diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index a84e33eecd5c0..91621afd5d5eb 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -17,6 +17,7 @@ #ifndef LLVM_CLANG_SERIALIZATION_ASTBITCODES_H #define LLVM_CLANG_SERIALIZATION_ASTBITCODES_H +#include "clang/AST/DeclID.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" #include "clang/Basic/IdentifierTable.h" @@ -59,91 +60,9 @@ const unsigned VERSION_MINOR = 1; /// and start at 1. 0 is reserved for NULL. using IdentifierID = uint32_t; -/// An ID number that refers to a declaration in an AST file. -/// -/// The ID numbers of declarations are consecutive (in order of -/// discovery), with values below NUM_PREDEF_DECL_IDS being reserved. -/// At the start of a chain of precompiled headers, declaration ID 1 is -/// used for the translation unit declaration. -/// -/// FIXME: Merge with Decl::DeclID -using DeclID = uint32_t; - -class LocalDeclID { -public: - explicit LocalDeclID(DeclID ID) : ID(ID) {} - - DeclID get() const { return ID; } - -private: - DeclID ID; -}; - -/// Wrapper class for DeclID. This is helpful to not mix the use of LocalDeclID -/// and GlobalDeclID to improve the type safety. -class GlobalDeclID { -public: - GlobalDeclID() : ID(0) {} - explicit GlobalDeclID(DeclID ID) : ID(ID) {} - - DeclID get() const { return ID; } - - explicit operator DeclID() const { return ID; } - - friend bool operator==(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { - return LHS.ID == RHS.ID; - } - friend bool operator!=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { - return LHS.ID != RHS.ID; - } - // We may sort the global decl ID. - friend bool operator<(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { - return LHS.ID < RHS.ID; - } - friend bool operator>(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { - return LHS.ID > RHS.ID; - } - friend bool operator<=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { - return LHS.ID <= RHS.ID; - } - friend bool operator>=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { - return LHS.ID >= RHS.ID; - } - -private: - DeclID ID; -}; - -/// A helper iterator adaptor to convert the iterators to `SmallVector` -/// to the iterators to `SmallVector`. -class GlobalDeclIDIterator - : public llvm::iterator_adaptor_base { -public: - GlobalDeclIDIterator() : iterator_adaptor_base(nullptr) {} - - GlobalDeclIDIterator(const DeclID *ID) : iterator_adaptor_base(ID) {} - - value_type operator*() const { return GlobalDeclID(*I); } - - bool operator==(const GlobalDeclIDIterator &RHS) const { return I == RHS.I; } -}; - -/// A helper iterator adaptor to convert the iterators to -/// `SmallVector` to the iterators to `SmallVector`. -class DeclIDIterator - : public llvm::iterator_adaptor_base { -public: - DeclIDIterator() : iterator_adaptor_base(nullptr) {} - - DeclIDIterator(const GlobalDeclID *ID) : iterator_adaptor_base(ID) {} - - value_type operator*() const { return DeclID(*I); } - - bool operator==(const DeclIDIterator &RHS) const { return I == RHS.I; } -}; +/// An ID number that refers to a declaration in an AST file. See the comments +/// in DeclIDBase for details. +using DeclID = DeclIDBase::DeclID; /// An ID number that refers to a type in an AST file. /// @@ -1054,8 +973,8 @@ enum PredefinedTypeIDs { /// OpenCL reserve_id type. PREDEF_TYPE_RESERVE_ID_ID = 41, - /// The placeholder type for OpenMP array section. - PREDEF_TYPE_OMP_ARRAY_SECTION = 42, + /// The placeholder type for an array section. + PREDEF_TYPE_ARRAY_SECTION = 42, /// The '__float128' type PREDEF_TYPE_FLOAT128_ID = 43, @@ -1243,74 +1162,6 @@ enum SpecialTypeIDs { /// The number of special type IDs. const unsigned NumSpecialTypeIDs = 8; -/// Predefined declaration IDs. -/// -/// These declaration IDs correspond to predefined declarations in the AST -/// context, such as the NULL declaration ID. Such declarations are never -/// actually serialized, since they will be built by the AST context when -/// it is created. -enum PredefinedDeclIDs { - /// The NULL declaration. - PREDEF_DECL_NULL_ID = 0, - - /// The translation unit. - PREDEF_DECL_TRANSLATION_UNIT_ID = 1, - - /// The Objective-C 'id' type. - PREDEF_DECL_OBJC_ID_ID = 2, - - /// The Objective-C 'SEL' type. - PREDEF_DECL_OBJC_SEL_ID = 3, - - /// The Objective-C 'Class' type. - PREDEF_DECL_OBJC_CLASS_ID = 4, - - /// The Objective-C 'Protocol' type. - PREDEF_DECL_OBJC_PROTOCOL_ID = 5, - - /// The signed 128-bit integer type. - PREDEF_DECL_INT_128_ID = 6, - - /// The unsigned 128-bit integer type. - PREDEF_DECL_UNSIGNED_INT_128_ID = 7, - - /// The internal 'instancetype' typedef. - PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, - - /// The internal '__builtin_va_list' typedef. - PREDEF_DECL_BUILTIN_VA_LIST_ID = 9, - - /// The internal '__va_list_tag' struct, if any. - PREDEF_DECL_VA_LIST_TAG = 10, - - /// The internal '__builtin_ms_va_list' typedef. - PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11, - - /// The predeclared '_GUID' struct. - PREDEF_DECL_BUILTIN_MS_GUID_ID = 12, - - /// The extern "C" context. - PREDEF_DECL_EXTERN_C_CONTEXT_ID = 13, - - /// The internal '__make_integer_seq' template. - PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 14, - - /// The internal '__NSConstantString' typedef. - PREDEF_DECL_CF_CONSTANT_STRING_ID = 15, - - /// The internal '__NSConstantString' tag type. - PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 16, - - /// The internal '__type_pack_element' template. - PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17, -}; - -/// The number of declaration IDs that are predefined. -/// -/// For more information about predefined declarations, see the -/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. -const unsigned int NUM_PREDEF_DECL_IDS = 18; - /// Record of updates for a declaration that was modified after /// being deserialized. This can occur within DECLTYPES_BLOCK_ID. const unsigned int DECL_UPDATES = 49; @@ -2080,7 +1931,7 @@ enum StmtCode { STMT_OMP_TARGET_TEAMS_GENERIC_LOOP_DIRECTIVE, STMT_OMP_PARALLEL_GENERIC_LOOP_DIRECTIVE, STMT_OMP_TARGET_PARALLEL_GENERIC_LOOP_DIRECTIVE, - EXPR_OMP_ARRAY_SECTION, + EXPR_ARRAY_SECTION, EXPR_OMP_ARRAY_SHAPING, EXPR_OMP_ITERATOR, @@ -2143,7 +1994,7 @@ enum CleanupObjectKind { COK_Block, COK_CompoundLiteral }; /// Describes the categories of an Objective-C class. struct ObjCCategoriesInfo { // The ID of the definition - DeclID DefinitionID; + LocalDeclID DefinitionID; // Offset into the array of category lists. unsigned Offset; @@ -2242,27 +2093,6 @@ template <> struct DenseMapInfo { } }; -template <> struct DenseMapInfo { - using DeclID = clang::serialization::DeclID; - using GlobalDeclID = clang::serialization::GlobalDeclID; - - static GlobalDeclID getEmptyKey() { - return GlobalDeclID(DenseMapInfo::getEmptyKey()); - } - - static GlobalDeclID getTombstoneKey() { - return GlobalDeclID(DenseMapInfo::getTombstoneKey()); - } - - static unsigned getHashValue(const GlobalDeclID &Key) { - return DenseMapInfo::getHashValue(Key.get()); - } - - static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) { - return L == R; - } -}; - } // namespace llvm #endif // LLVM_CLANG_SERIALIZATION_ASTBITCODES_H diff --git a/clang/include/clang/Serialization/ASTDeserializationListener.h b/clang/include/clang/Serialization/ASTDeserializationListener.h index f3a01a4b97315..3ab7f1a91843b 100644 --- a/clang/include/clang/Serialization/ASTDeserializationListener.h +++ b/clang/include/clang/Serialization/ASTDeserializationListener.h @@ -44,7 +44,7 @@ class ASTDeserializationListener { /// unqualified. virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } /// A decl was deserialized from the AST file. - virtual void DeclRead(serialization::DeclID ID, const Decl *D) { } + virtual void DeclRead(GlobalDeclID ID, const Decl *D) {} /// A selector was read from the AST file. virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {} /// A macro definition was read from the AST file. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index ed917aa164229..64f1ebc117b32 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -501,10 +501,7 @@ class ASTReader /// = I + 1 has already been loaded. llvm::PagedVector DeclsLoaded; - static_assert(std::is_same_v); - - using GlobalDeclMapType = - ContinuousRangeMap; + using GlobalDeclMapType = ContinuousRangeMap; /// Mapping from global declaration IDs to the module in which the /// declaration resides. @@ -512,16 +509,15 @@ class ASTReader using FileOffset = std::pair; using FileOffsetsTy = SmallVector; - using DeclUpdateOffsetsMap = - llvm::DenseMap; + using DeclUpdateOffsetsMap = llvm::DenseMap; /// Declarations that have modifications residing in a later file /// in the chain. DeclUpdateOffsetsMap DeclUpdateOffsets; - using DelayedNamespaceOffsetMapTy = llvm::DenseMap< - serialization::GlobalDeclID, - std::pair>; + using DelayedNamespaceOffsetMapTy = + llvm::DenseMap>; /// Mapping from global declaration IDs to the lexical and visible block /// offset for delayed namespace in reduced BMI. @@ -535,13 +531,12 @@ class ASTReader struct PendingUpdateRecord { Decl *D; - serialization::GlobalDeclID ID; + GlobalDeclID ID; // Whether the declaration was just deserialized. bool JustLoaded; - PendingUpdateRecord(serialization::GlobalDeclID ID, Decl *D, - bool JustLoaded) + PendingUpdateRecord(GlobalDeclID ID, Decl *D, bool JustLoaded) : D(D), ID(ID), JustLoaded(JustLoaded) {} }; @@ -594,10 +589,10 @@ class ASTReader struct FileDeclsInfo { ModuleFile *Mod = nullptr; - ArrayRef Decls; + ArrayRef Decls; FileDeclsInfo() = default; - FileDeclsInfo(ModuleFile *Mod, ArrayRef Decls) + FileDeclsInfo(ModuleFile *Mod, ArrayRef Decls) : Mod(Mod), Decls(Decls) {} }; @@ -635,8 +630,7 @@ class ASTReader /// Updates to the visible declarations of declaration contexts that /// haven't been loaded yet. - llvm::DenseMap - PendingVisibleUpdates; + llvm::DenseMap PendingVisibleUpdates; /// The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. @@ -662,8 +656,7 @@ class ASTReader /// Read the record that describes the visible contents of a DC. bool ReadVisibleDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, - uint64_t Offset, - serialization::GlobalDeclID ID); + uint64_t Offset, GlobalDeclID ID); /// A vector containing identifiers that have already been /// loaded. @@ -816,14 +809,14 @@ class ASTReader /// This contains the data loaded from all EAGERLY_DESERIALIZED_DECLS blocks /// in the chain. The referenced declarations are deserialized and passed to /// the consumer eagerly. - SmallVector EagerlyDeserializedDecls; + SmallVector EagerlyDeserializedDecls; /// The IDs of all tentative definitions stored in the chain. /// /// Sema keeps track of all tentative definitions in a TU because it has to /// complete them and pass them on to CodeGen. Thus, tentative definitions in /// the PCH chain must be eagerly deserialized. - SmallVector TentativeDefinitions; + SmallVector TentativeDefinitions; /// The IDs of all CXXRecordDecls stored in the chain whose VTables are /// used. @@ -831,7 +824,7 @@ class ASTReader /// CodeGen has to emit VTables for these records, so they have to be eagerly /// deserialized. struct VTableUse { - serialization::GlobalDeclID ID; + GlobalDeclID ID; SourceLocation::UIntTy RawLoc; bool Used; }; @@ -844,7 +837,7 @@ class ASTReader /// instantiation where the first value is the ID of the decl and the second /// is the instantiation location. struct PendingInstantiation { - serialization::GlobalDeclID ID; + GlobalDeclID ID; SourceLocation::UIntTy RawLoc; }; SmallVector PendingInstantiations; @@ -857,11 +850,11 @@ class ASTReader /// A snapshot of Sema's unused file-scoped variable tracking, for /// generating warnings. - SmallVector UnusedFileScopedDecls; + SmallVector UnusedFileScopedDecls; /// A list of all the delegating constructors we've seen, to diagnose /// cycles. - SmallVector DelegatingCtorDecls; + SmallVector DelegatingCtorDecls; /// Method selectors used in a @selector expression. Used for /// implementation of -Wselector. @@ -874,7 +867,7 @@ class ASTReader /// The IDs of type aliases for ext_vectors that exist in the chain. /// /// Used by Sema for finding sugared names for ext_vectors in diagnostics. - SmallVector ExtVectorDecls; + SmallVector ExtVectorDecls; //@} @@ -885,7 +878,7 @@ class ASTReader /// The IDs of all potentially unused typedef names in the chain. /// /// Sema tracks these to emit warnings. - SmallVector UnusedLocalTypedefNameCandidates; + SmallVector UnusedLocalTypedefNameCandidates; /// Our current depth in #pragma cuda force_host_device begin/end /// macros. @@ -894,7 +887,7 @@ class ASTReader /// The IDs of the declarations Sema stores directly. /// /// Sema tracks a few important decls, such as namespace std, directly. - SmallVector SemaDeclRefs; + SmallVector SemaDeclRefs; /// The IDs of the types ASTContext stores directly. /// @@ -905,7 +898,7 @@ class ASTReader /// /// The AST context tracks a few important decls, currently cudaConfigureCall, /// directly. - SmallVector CUDASpecialDeclRefs; + SmallVector CUDASpecialDeclRefs; /// The floating point pragma option settings. SmallVector FPPragmaOptions; @@ -954,12 +947,12 @@ class ASTReader llvm::DenseMap> OpenCLDeclExtMap; /// A list of the namespaces we've seen. - SmallVector KnownNamespaces; + SmallVector KnownNamespaces; /// A list of undefined decls with internal linkage followed by the /// SourceLocation of a matching ODR-use. struct UndefinedButUsedDecl { - serialization::GlobalDeclID ID; + GlobalDeclID ID; SourceLocation::UIntTy RawLoc; }; SmallVector UndefinedButUsed; @@ -974,8 +967,7 @@ class ASTReader /// The IDs of all decls to be checked for deferred diags. /// /// Sema tracks these to emit deferred diags. - llvm::SmallSetVector - DeclsToCheckForDeferredDiags; + llvm::SmallSetVector DeclsToCheckForDeferredDiags; private: struct ImportedSubmodule { @@ -1112,7 +1104,7 @@ class ASTReader /// /// The declarations on the identifier chain for these identifiers will be /// loaded once the recursive loading has completed. - llvm::MapVector> + llvm::MapVector> PendingIdentifierInfos; /// The set of lookup results that we have faked in order to support @@ -1157,8 +1149,8 @@ class ASTReader /// been loaded but its DeclContext was not set yet. struct PendingDeclContextInfo { Decl *D; - serialization::GlobalDeclID SemaDC; - serialization::GlobalDeclID LexicalDC; + GlobalDeclID SemaDC; + GlobalDeclID LexicalDC; }; /// The set of Decls that have been loaded but their DeclContexts are @@ -1239,8 +1231,7 @@ class ASTReader /// module is loaded. SmallVector ObjCClassesLoaded; - using KeyDeclsMap = - llvm::DenseMap>; + using KeyDeclsMap = llvm::DenseMap>; /// A mapping from canonical declarations to the set of global /// declaration IDs for key declaration that have been merged with that @@ -1449,7 +1440,7 @@ class ASTReader QualType readTypeRecord(unsigned Index); RecordLocation TypeCursorForIndex(unsigned Index); void LoadedDecl(unsigned Index, Decl *D); - Decl *ReadDeclRecord(serialization::GlobalDeclID ID); + Decl *ReadDeclRecord(GlobalDeclID ID); void markIncompleteDeclChain(Decl *D); /// Returns the most recent declaration of a declaration (which must be @@ -1457,11 +1448,10 @@ class ASTReader /// merged into its redecl chain. Decl *getMostRecentExistingDecl(Decl *D); - RecordLocation DeclCursorForID(serialization::GlobalDeclID ID, - SourceLocation &Location); + RecordLocation DeclCursorForID(GlobalDeclID ID, SourceLocation &Location); void loadDeclUpdateRecords(PendingUpdateRecord &Record); void loadPendingDeclChain(Decl *D, uint64_t LocalOffset); - void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D, + void loadObjCCategories(GlobalDeclID ID, ObjCInterfaceDecl *D, unsigned PreviousGeneration = 0); RecordLocation getLocalBitOffset(uint64_t GlobalOffset); @@ -1496,11 +1486,10 @@ class ASTReader unsigned ClientLoadCapabilities); public: - class ModuleDeclIterator - : public llvm::iterator_adaptor_base< - ModuleDeclIterator, const serialization::LocalDeclID *, - std::random_access_iterator_tag, const Decl *, ptrdiff_t, - const Decl *, const Decl *> { + class ModuleDeclIterator : public llvm::iterator_adaptor_base< + ModuleDeclIterator, const LocalDeclID *, + std::random_access_iterator_tag, const Decl *, + ptrdiff_t, const Decl *, const Decl *> { ASTReader *Reader = nullptr; ModuleFile *Mod = nullptr; @@ -1508,7 +1497,7 @@ class ASTReader ModuleDeclIterator() : iterator_adaptor_base(nullptr) {} ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod, - const serialization::LocalDeclID *Pos) + const LocalDeclID *Pos) : iterator_adaptor_base(Pos), Reader(Reader), Mod(Mod) {} value_type operator*() const { @@ -1536,9 +1525,8 @@ class ASTReader void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); - void addPendingDeclContextInfo(Decl *D, - serialization::GlobalDeclID SemaDC, - serialization::GlobalDeclID LexicalDC) { + void addPendingDeclContextInfo(Decl *D, GlobalDeclID SemaDC, + GlobalDeclID LexicalDC) { assert(D); PendingDeclContextInfo Info = { D, SemaDC, LexicalDC }; PendingDeclContextInfos.push_back(Info); @@ -1916,38 +1904,36 @@ class ASTReader /// Map from a local declaration ID within a given module to a /// global declaration ID. - serialization::GlobalDeclID - getGlobalDeclID(ModuleFile &F, serialization::LocalDeclID LocalID) const; + GlobalDeclID getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const; /// Returns true if global DeclID \p ID originated from module \p M. - bool isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const; + bool isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const; /// Retrieve the module file that owns the given declaration, or NULL /// if the declaration is not from a module file. ModuleFile *getOwningModuleFile(const Decl *D); /// Returns the source location for the decl \p ID. - SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID); + SourceLocation getSourceLocationForDeclID(GlobalDeclID ID); /// Resolve a declaration ID into a declaration, potentially /// building a new declaration. - Decl *GetDecl(serialization::GlobalDeclID ID); - Decl *GetExternalDecl(Decl::DeclID ID) override; + Decl *GetDecl(GlobalDeclID ID); + Decl *GetExternalDecl(GlobalDeclID ID) override; /// Resolve a declaration ID into a declaration. Return 0 if it's not /// been loaded yet. - Decl *GetExistingDecl(serialization::GlobalDeclID ID); + Decl *GetExistingDecl(GlobalDeclID ID); /// Reads a declaration with the given local ID in the given module. - Decl *GetLocalDecl(ModuleFile &F, serialization::LocalDeclID LocalID) { + Decl *GetLocalDecl(ModuleFile &F, LocalDeclID LocalID) { return GetDecl(getGlobalDeclID(F, LocalID)); } /// Reads a declaration with the given local ID in the given module. /// /// \returns The requested declaration, casted to the given return type. - template - T *GetLocalDeclAs(ModuleFile &F, serialization::LocalDeclID LocalID) { + template T *GetLocalDeclAs(ModuleFile &F, LocalDeclID LocalID) { return cast_or_null(GetLocalDecl(F, LocalID)); } @@ -1956,16 +1942,15 @@ class ASTReader /// /// \returns the global ID of the given declaration as known in the given /// module file. - serialization::DeclID - mapGlobalIDToModuleFileGlobalID(ModuleFile &M, - serialization::GlobalDeclID GlobalID); + LocalDeclID mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + GlobalDeclID GlobalID); /// Reads a declaration ID from the given position in a record in the /// given module. /// /// \returns The declaration ID read from the record, adjusted to a global ID. - serialization::GlobalDeclID - ReadDeclID(ModuleFile &F, const RecordData &Record, unsigned &Idx); + GlobalDeclID ReadDeclID(ModuleFile &F, const RecordData &Record, + unsigned &Idx); /// Reads a declaration from the given position in a record in the /// given module. @@ -2139,10 +2124,9 @@ class ASTReader void LoadSelector(Selector Sel); void SetIdentifierInfo(unsigned ID, IdentifierInfo *II); - void SetGloballyVisibleDecls( - IdentifierInfo *II, - const SmallVectorImpl &DeclIDs, - SmallVectorImpl *Decls = nullptr); + void SetGloballyVisibleDecls(IdentifierInfo *II, + const SmallVectorImpl &DeclIDs, + SmallVectorImpl *Decls = nullptr); /// Report a diagnostic. DiagnosticBuilder Diag(unsigned DiagID) const; @@ -2383,7 +2367,7 @@ class ASTReader // Contains the IDs for declarations that were requested before we have // access to a Sema object. - SmallVector PreloadedDeclIDs; + SmallVector PreloadedDeclIDs; /// Retrieve the semantic analysis object used to analyze the /// translation unit in which the precompiled header is being diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 9eaf50a76d52f..1e11d2d5e42f9 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -136,7 +136,7 @@ class ASTRecordReader /// Reads a declaration with the given local ID in the given module. /// /// \returns The requested declaration, casted to the given return type. - template T *GetLocalDeclAs(serialization::LocalDeclID LocalID) { + template T *GetLocalDeclAs(LocalDeclID LocalID) { return cast_or_null(Reader->GetLocalDecl(*F, LocalID)); } @@ -182,9 +182,7 @@ class ASTRecordReader /// Reads a declaration ID from the given position in this record. /// /// \returns The declaration ID read from the record, adjusted to a global ID. - serialization::GlobalDeclID readDeclID() { - return Reader->ReadDeclID(*F, Record, Idx); - } + GlobalDeclID readDeclID() { return Reader->ReadDeclID(*F, Record, Idx); } /// Reads a declaration from the given position in a record in the /// given module, advancing Idx. @@ -271,6 +269,9 @@ class ASTRecordReader /// Read an OpenMP children, advancing Idx. void readOMPChildren(OMPChildren *Data); + /// Read a list of Exprs used for a var-list. + llvm::SmallVector readOpenACCVarList(); + /// Read an OpenACC clause, advancing Idx. OpenACCClause *readOpenACCClause(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index 1feb8fcbacf77..8b1da49bd4c57 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_SERIALIZATION_ASTRECORDWRITER_H #include "clang/AST/AbstractBasicWriter.h" +#include "clang/AST/OpenACCClause.h" #include "clang/AST/OpenMPClause.h" #include "clang/Serialization/ASTWriter.h" #include "clang/Serialization/SourceLocationEncoding.h" @@ -293,6 +294,8 @@ class ASTRecordWriter /// Writes data related to the OpenMP directives. void writeOMPChildren(OMPChildren *Data); + void writeOpenACCVarList(const OpenACCClauseWithVarList *C); + /// Writes out a single OpenACC Clause. void writeOpenACCClause(const OpenACCClause *C); diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 13b4ad4ad2953..a55dfd327670f 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -76,6 +76,10 @@ class StoredDeclsList; class SwitchCase; class Token; +namespace SrcMgr { +class FileInfo; +} // namespace SrcMgr + /// Writes an AST file containing the contents of a translation unit. /// /// The ASTWriter class produces a bitstream containing the serialized @@ -212,10 +216,10 @@ class ASTWriter : public ASTDeserializationListener, llvm::SmallVector DelayedNamespace; /// The first ID number we can use for our own declarations. - serialization::DeclID FirstDeclID = serialization::NUM_PREDEF_DECL_IDS; + LocalDeclID FirstDeclID = LocalDeclID(clang::NUM_PREDEF_DECL_IDS); /// The decl ID that will be assigned to the next new decl. - serialization::DeclID NextDeclID = FirstDeclID; + LocalDeclID NextDeclID = FirstDeclID; /// Map that provides the ID numbers of each declaration within /// the output stream, as well as those deserialized from a chained PCH. @@ -223,7 +227,7 @@ class ASTWriter : public ASTDeserializationListener, /// The ID numbers of declarations are consecutive (in order of /// discovery) and start at 2. 1 is reserved for the translation /// unit, while 0 is reserved for NULL. - llvm::DenseMap DeclIDs; + llvm::DenseMap DeclIDs; /// Offset of each declaration in the bitstream, indexed by /// the declaration's ID. @@ -233,9 +237,8 @@ class ASTWriter : public ASTDeserializationListener, /// are relative to this value. uint64_t DeclTypesBlockStartOffset = 0; - /// Sorted (by file offset) vector of pairs of file offset/DeclID. - using LocDeclIDsTy = - SmallVector, 64>; + /// Sorted (by file offset) vector of pairs of file offset/LocalDeclID. + using LocDeclIDsTy = SmallVector, 64>; struct DeclIDInFileInfo { LocDeclIDsTy DeclIDs; @@ -250,7 +253,7 @@ class ASTWriter : public ASTDeserializationListener, /// that it contains. FileDeclIDsTy FileDeclIDs; - void associateDeclWithFile(const Decl *D, serialization::DeclID); + void associateDeclWithFile(const Decl *D, LocalDeclID); /// The first ID number we can use for our own types. serialization::TypeID FirstTypeID = serialization::NUM_PREDEF_TYPE_IDS; @@ -421,8 +424,8 @@ class ASTWriter : public ASTDeserializationListener, /// headers. The declarations themselves are stored as declaration /// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS /// record. - SmallVector EagerlyDeserializedDecls; - SmallVector ModularCodegenDecls; + RecordData EagerlyDeserializedDecls; + RecordData ModularCodegenDecls; /// DeclContexts that have received extensions since their serialized /// form. @@ -491,6 +494,11 @@ class ASTWriter : public ASTDeserializationListener, /// during \c SourceManager serialization. void computeNonAffectingInputFiles(); + /// Some affecting files can be included from files that are not affecting. + /// This function erases source locations pointing into such files. + SourceLocation getAffectingIncludeLoc(const SourceManager &SourceMgr, + const SrcMgr::FileInfo &File); + /// Returns an adjusted \c FileID, accounting for any non-affecting input /// files. FileID getAdjustedFileID(FileID FID) const; @@ -526,6 +534,7 @@ class ASTWriter : public ASTDeserializationListener, /// Calculate hash of the pcm content. std::pair createSignature() const; + ASTFileSignature createSignatureForNamedModule() const; void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts); void WriteSourceManagerBlock(SourceManager &SourceMgr, @@ -709,7 +718,7 @@ class ASTWriter : public ASTDeserializationListener, return false; auto I = DeclIDs.find(D); return (I == DeclIDs.end() || - I->second >= serialization::NUM_PREDEF_DECL_IDS); + I->second.get() >= clang::NUM_PREDEF_DECL_IDS); }; /// Emit a reference to a declaration. @@ -717,12 +726,13 @@ class ASTWriter : public ASTDeserializationListener, // Emit a reference to a declaration if the declaration was emitted. void AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record); - /// Force a declaration to be emitted and get its ID. - serialization::DeclID GetDeclRef(const Decl *D); + /// Force a declaration to be emitted and get its local ID to the module file + /// been writing. + LocalDeclID GetDeclRef(const Decl *D); - /// Determine the declaration ID of an already-emitted + /// Determine the local declaration ID of an already-emitted /// declaration. - serialization::DeclID getDeclID(const Decl *D); + LocalDeclID getDeclID(const Decl *D); /// Whether or not the declaration got emitted. If not, it wouldn't be /// emitted. @@ -885,6 +895,8 @@ class ASTWriter : public ASTDeserializationListener, /// AST and semantic-analysis consumer that generates a /// precompiled header from the parsed source code. class PCHGenerator : public SemaConsumer { + void anchor() override; + Preprocessor &PP; std::string OutputFile; std::string isysroot; @@ -928,17 +940,34 @@ class PCHGenerator : public SemaConsumer { bool hasEmittedPCH() const { return Buffer->IsComplete; } }; -class ReducedBMIGenerator : public PCHGenerator { +class CXX20ModulesGenerator : public PCHGenerator { + void anchor() override; + protected: virtual Module *getEmittingModule(ASTContext &Ctx) override; + CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, + StringRef OutputFile, bool GeneratingReducedBMI); + public: - ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, - StringRef OutputFile); + CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, + StringRef OutputFile) + : CXX20ModulesGenerator(PP, ModuleCache, OutputFile, + /*GeneratingReducedBMI=*/false) {} void HandleTranslationUnit(ASTContext &Ctx) override; }; +class ReducedBMIGenerator : public CXX20ModulesGenerator { + void anchor() override; + +public: + ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, + StringRef OutputFile) + : CXX20ModulesGenerator(PP, ModuleCache, OutputFile, + /*GeneratingReducedBMI=*/true) {} +}; + /// If we can elide the definition of \param D in reduced BMI. /// /// Generally, we can elide the definition of a declaration if it won't affect diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h index 492c35dceb08d..25f644e76edb1 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -474,7 +474,7 @@ class ModuleFile { llvm::DenseMap GlobalToLocalDeclIDs; /// Array of file-level DeclIDs sorted by file. - const serialization::LocalDeclID *FileSortedDecls = nullptr; + const LocalDeclID *FileSortedDecls = nullptr; unsigned NumFileSortedDecls = 0; /// Array of category list location information within this diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 9aa1c6ddfe449..520286b57c9fd 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -563,6 +563,20 @@ def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">, Dependencies<[DynamicMemoryModeling]>, Documentation; +// This must appear before StdCLibraryFunctionsChecker because a dependency. +def StreamChecker : Checker<"Stream">, + HelpText<"Check stream handling functions">, + WeakDependencies<[NonNullParamChecker]>, + CheckerOptions<[ + CmdLineOption + ]>, + Documentation; + def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">, HelpText<"Check for invalid arguments of C standard library functions, " "and apply relations between arguments and return value">, @@ -581,7 +595,7 @@ def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">, "true", InAlpha> ]>, - WeakDependencies<[CallAndMessageChecker, NonNullParamChecker]>, + WeakDependencies<[CallAndMessageChecker, NonNullParamChecker, StreamChecker]>, Documentation; def VforkChecker : Checker<"Vfork">, @@ -601,20 +615,6 @@ def PthreadLockChecker : Checker<"PthreadLock">, Dependencies<[PthreadLockBase]>, Documentation; -def StreamChecker : Checker<"Stream">, - HelpText<"Check stream handling functions">, - WeakDependencies<[NonNullParamChecker]>, - CheckerOptions<[ - CmdLineOption - ]>, - Documentation; - def SimpleStreamChecker : Checker<"SimpleStream">, HelpText<"Check for misuses of stream APIs">, Documentation; @@ -1628,6 +1628,7 @@ def TaintTesterChecker : Checker<"TaintTest">, def StreamTesterChecker : Checker<"StreamTester">, HelpText<"Add test functions to StreamChecker for test and debugging " "purposes.">, + WeakDependencies<[StreamChecker]>, Documentation; def ErrnoTesterChecker : Checker<"ErrnoTest">, diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index fac0c04ae2caa..ef23b160a3c03 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -225,15 +225,11 @@ class StoreManager { /// invalidated. This should include any regions explicitly invalidated /// even if they do not currently have bindings. Pass \c NULL if this /// information will not be used. - virtual StoreRef invalidateRegions(Store store, - ArrayRef Values, - const Expr *E, unsigned Count, - const LocationContext *LCtx, - const CallEvent *Call, - InvalidatedSymbols &IS, - RegionAndSymbolInvalidationTraits &ITraits, - InvalidatedRegions *InvalidatedTopLevel, - InvalidatedRegions *Invalidated) = 0; + virtual StoreRef invalidateRegions( + Store store, ArrayRef Values, const Expr *Ex, unsigned Count, + const LocationContext *LCtx, const CallEvent *Call, + InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits, + InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution /// engine is about to execute into a callee. diff --git a/clang/include/clang/Tooling/CommonOptionsParser.h b/clang/include/clang/Tooling/CommonOptionsParser.h index 3c0480af37794..5e2cdc6ac4589 100644 --- a/clang/include/clang/Tooling/CommonOptionsParser.h +++ b/clang/include/clang/Tooling/CommonOptionsParser.h @@ -49,17 +49,22 @@ namespace tooling { /// using namespace clang::tooling; /// using namespace llvm; /// -/// static cl::OptionCategory MyToolCategory("My tool options"); +/// static cl::OptionCategory MyToolCategory("my-tool options"); /// static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); /// static cl::extrahelp MoreHelp("\nMore help text...\n"); -/// static cl::opt YourOwnOption(...); -/// ... /// /// int main(int argc, const char **argv) { -/// CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); +/// auto ExpectedParser = +/// CommonOptionsParser::create(argc, argv, MyToolCategory); +/// if (!ExpectedParser) { +/// llvm::errs() << ExpectedParser.takeError(); +/// return 1; +/// } +/// CommonOptionsParser& OptionsParser = ExpectedParser.get(); /// ClangTool Tool(OptionsParser.getCompilations(), /// OptionsParser.getSourcePathList()); -/// return Tool.run(newFrontendActionFactory().get()); +/// return Tool.run( +/// newFrontendActionFactory().get()); /// } /// \endcode class CommonOptionsParser { diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 615314c46f09c..97e630e97fdcc 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -24,7 +24,10 @@ const uint16_t VERSION_MAJOR = 0; /// API notes file minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t VERSION_MINOR = 25; // SwiftImportAs +const uint16_t VERSION_MINOR = 26; // SwiftCopyable + +const uint8_t kSwiftCopyable = 1; +const uint8_t kSwiftNonCopyable = 2; using IdentifierID = llvm::PointerEmbeddedInt; using IdentifierIDField = llvm::BCVBR<16>; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index dfc3beb6fa13e..b60ca685f62c9 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -527,6 +527,13 @@ class TagTableInfo Info.EnumExtensibility = static_cast((Payload & 0x3) - 1); + uint8_t Copyable = + endian::readNext(Data); + if (Copyable == kSwiftNonCopyable) + Info.setSwiftCopyable(std::optional(false)); + else if (Copyable == kSwiftCopyable) + Info.setSwiftCopyable(std::optional(true)); + unsigned ImportAsLength = endian::readNext(Data); if (ImportAsLength > 0) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index e3f5d102fcd07..3e61597631509 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -1128,7 +1128,7 @@ class TagTableInfo : public CommonTypeTableInfo { return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) + 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) + 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) + - 1 + getCommonTypeInfoSize(TI); + 2 + getCommonTypeInfoSize(TI); } void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) { @@ -1146,6 +1146,11 @@ class TagTableInfo : public CommonTypeTableInfo { writer.write(Flags); + if (auto Copyable = TI.isSwiftCopyable()) + writer.write(*Copyable ? kSwiftCopyable : kSwiftNonCopyable); + else + writer.write(0); + if (auto ImportAs = TI.SwiftImportAs) { writer.write(ImportAs->size() + 1); OS.write(ImportAs->c_str(), ImportAs->size()); diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index 57d6da7a17759..2295d769d344b 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -419,6 +419,7 @@ struct Tag { std::optional EnumExtensibility; std::optional FlagEnum; std::optional EnumConvenienceKind; + std::optional SwiftCopyable; }; typedef std::vector TagsSeq; @@ -452,6 +453,7 @@ template <> struct MappingTraits { IO.mapOptional("EnumExtensibility", T.EnumExtensibility); IO.mapOptional("FlagEnum", T.FlagEnum); IO.mapOptional("EnumKind", T.EnumConvenienceKind); + IO.mapOptional("SwiftCopyable", T.SwiftCopyable); } }; } // namespace yaml @@ -1009,6 +1011,9 @@ class YAMLConverter { if (Tag.SwiftReleaseOp) TI.SwiftReleaseOp = Tag.SwiftReleaseOp; + if (Tag.SwiftCopyable) + TI.setSwiftCopyable(Tag.SwiftCopyable); + if (Tag.EnumConvenienceKind) { if (Tag.EnumExtensibility) { emitError( diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4a419f522acab..d2ec7abc3c046 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1084,7 +1084,7 @@ void ASTContext::addModuleInitializer(Module *M, Decl *D) { } void ASTContext::addLazyModuleInitializers(Module *M, - ArrayRef IDs) { + ArrayRef IDs) { auto *&Inits = ModuleInitializers[M]; if (!Inits) Inits = new (*this) PerModuleInitializers; @@ -1321,16 +1321,14 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, // Placeholder type for OMP array sections. if (LangOpts.OpenMP) { - InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); + InitBuiltinType(ArraySectionTy, BuiltinType::ArraySection); InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping); InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); } - // Placeholder type for OpenACC array sections. - if (LangOpts.OpenACC) { - // FIXME: Once we implement OpenACC array sections in Sema, this will either - // be combined with the OpenMP type, or given its own type. In the meantime, - // just use the OpenMP type so that parsing can work. - InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); + // Placeholder type for OpenACC array sections, if we are ALSO in OMP mode, + // don't bother, as we're just using the same type as OMP. + if (LangOpts.OpenACC && !LangOpts.OpenMP) { + InitBuiltinType(ArraySectionTy, BuiltinType::ArraySection); } if (LangOpts.MatrixTypes) InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 3a94fc7eb9b28..8029bf66fc970 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -443,12 +443,17 @@ ExprDependence clang::computeDependence(ObjCIndirectCopyRestoreExpr *E) { return E->getSubExpr()->getDependence(); } -ExprDependence clang::computeDependence(OMPArraySectionExpr *E) { +ExprDependence clang::computeDependence(ArraySectionExpr *E) { auto D = E->getBase()->getDependence(); if (auto *LB = E->getLowerBound()) D |= LB->getDependence(); if (auto *Len = E->getLength()) D |= Len->getDependence(); + + if (E->isOMPArraySection()) { + if (auto *Stride = E->getStride()) + D |= Stride->getDependence(); + } return D; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 3075784598295..75f4e9a139cc8 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2155,7 +2155,7 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, return new (C, DC) VarDecl(Var, C, DC, StartL, IdL, Id, T, TInfo, S); } -VarDecl *VarDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +VarDecl *VarDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) VarDecl(Var, C, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, SC_None); @@ -2933,7 +2933,7 @@ QualType ParmVarDecl::getOriginalType() const { return T; } -ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ParmVarDecl(ParmVar, C, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, SC_None, nullptr); @@ -4557,7 +4557,7 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, BW, Mutable, InitStyle); } -FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, nullptr, false, ICIS_NoInit); @@ -4867,7 +4867,7 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, return Enum; } -EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { EnumDecl *Enum = new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr, false, false, false); @@ -5029,7 +5029,8 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, return R; } -RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, Decl::DeclID ID) { +RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, + GlobalDeclID ID) { RecordDecl *R = new (C, ID) RecordDecl(Record, TagTypeKind::Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); @@ -5301,7 +5302,7 @@ PragmaCommentDecl *PragmaCommentDecl::Create(const ASTContext &C, } PragmaCommentDecl *PragmaCommentDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID, + GlobalDeclID ID, unsigned ArgSize) { return new (C, ID, additionalSizeToAlloc(ArgSize + 1)) PragmaCommentDecl(nullptr, SourceLocation(), PCK_Unknown); @@ -5326,7 +5327,7 @@ PragmaDetectMismatchDecl::Create(const ASTContext &C, TranslationUnitDecl *DC, } PragmaDetectMismatchDecl * -PragmaDetectMismatchDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +PragmaDetectMismatchDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NameValueSize) { return new (C, ID, additionalSizeToAlloc(NameValueSize + 1)) PragmaDetectMismatchDecl(nullptr, SourceLocation(), 0); @@ -5353,7 +5354,7 @@ LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, GnuLabelL); } -LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) LabelDecl(nullptr, SourceLocation(), nullptr, nullptr, SourceLocation()); } @@ -5394,7 +5395,7 @@ ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, QualType Type, } ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) ImplicitParamDecl(C, QualType(), ImplicitParamKind::Other); } @@ -5412,7 +5413,7 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, return New; } -FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) FunctionDecl( Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, SC_None, false, false, ConstexprSpecKind::Unspecified, nullptr); @@ -5422,7 +5423,7 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { return new (C, DC) BlockDecl(DC, L); } -BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) BlockDecl(nullptr, SourceLocation()); } @@ -5436,7 +5437,7 @@ CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC, CapturedDecl(DC, NumParams); } -CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumParams) { return new (C, ID, additionalSizeToAlloc(NumParams)) CapturedDecl(nullptr, NumParams); @@ -5462,8 +5463,8 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, return new (C, CD) EnumConstantDecl(C, CD, L, Id, T, E, V); } -EnumConstantDecl * -EnumConstantDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +EnumConstantDecl *EnumConstantDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) EnumConstantDecl(C, nullptr, SourceLocation(), nullptr, QualType(), nullptr, llvm::APSInt()); } @@ -5490,7 +5491,7 @@ IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, } IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(), DeclarationName(), QualType(), std::nullopt); @@ -5551,7 +5552,7 @@ bool TypedefNameDecl::isTransparentTagSlow() const { return isTransparent; } -TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); } @@ -5564,7 +5565,8 @@ TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC, return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } -TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) TypeAliasDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); } @@ -5595,7 +5597,7 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, } FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) FileScopeAsmDecl(nullptr, nullptr, SourceLocation(), SourceLocation()); } @@ -5613,7 +5615,7 @@ TopLevelStmtDecl *TopLevelStmtDecl::Create(ASTContext &C, Stmt *Statement) { } TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) TopLevelStmtDecl(/*DC=*/nullptr, SourceLocation(), /*S=*/nullptr); } @@ -5634,7 +5636,7 @@ EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { return new (C, DC) EmptyDecl(DC, L); } -EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) EmptyDecl(nullptr, SourceLocation()); } @@ -5667,7 +5669,8 @@ HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C, return Result; } -HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, SourceLocation(), SourceLocation()); } @@ -5723,7 +5726,7 @@ ImportDecl *ImportDecl::CreateImplicit(ASTContext &C, DeclContext *DC, return Import; } -ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumLocations) { return new (C, ID, additionalSizeToAlloc(NumLocations)) ImportDecl(EmptyShell()); @@ -5756,6 +5759,6 @@ ExportDecl *ExportDecl::Create(ASTContext &C, DeclContext *DC, return new (C, DC) ExportDecl(DC, ExportLoc); } -ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ExportDecl(nullptr, SourceLocation()); } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 7cb6b31c541fd..03e1055251c24 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -71,7 +71,7 @@ void Decl::updateOutOfDate(IdentifierInfo &II) const { #include "clang/AST/DeclNodes.inc" void *Decl::operator new(std::size_t Size, const ASTContext &Context, - Decl::DeclID ID, std::size_t Extra) { + GlobalDeclID ID, std::size_t Extra) { // Allocate an extra 8 bytes worth of storage, which ensures that the // resulting pointer will still be 8-byte aligned. static_assert(sizeof(unsigned) * 2 >= alignof(Decl), @@ -85,7 +85,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Context, PrefixPtr[0] = 0; // Store the global declaration ID in the second 4 bytes. - PrefixPtr[1] = ID; + PrefixPtr[1] = ID.get(); return Result; } @@ -1115,7 +1115,9 @@ int64_t Decl::getID() const { const FunctionType *Decl::getFunctionType(bool BlocksToo) const { QualType Ty; - if (const auto *D = dyn_cast(this)) + if (isa(this)) + return nullptr; + else if (const auto *D = dyn_cast(this)) Ty = D->getType(); else if (const auto *D = dyn_cast(this)) Ty = D->getUnderlyingType(); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 426c526205109..75c441293d62e 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -57,7 +57,8 @@ using namespace clang; void AccessSpecDecl::anchor() {} -AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) AccessSpecDecl(EmptyShell()); } @@ -68,7 +69,7 @@ void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const { for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I) I.setDecl(cast(Source->GetExternalDecl( - reinterpret_cast(I.getDecl()) >> 2))); + GlobalDeclID(reinterpret_cast(I.getDecl()) >> 2)))); Impl.Decls.setLazy(false); } @@ -160,8 +161,8 @@ CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, return R; } -CXXRecordDecl * -CXXRecordDecl::CreateDeserialized(const ASTContext &C, Decl::DeclID ID) { +CXXRecordDecl *CXXRecordDecl::CreateDeserialized(const ASTContext &C, + GlobalDeclID ID) { auto *R = new (C, ID) CXXRecordDecl(CXXRecord, TagTypeKind::Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); @@ -2162,8 +2163,8 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create( TInfo, EndLocation, Ctor, Kind); } -CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +CXXDeductionGuideDecl * +CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) CXXDeductionGuideDecl( C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(), QualType(), nullptr, SourceLocation(), nullptr, @@ -2175,8 +2176,8 @@ RequiresExprBodyDecl *RequiresExprBodyDecl::Create( return new (C, DC) RequiresExprBodyDecl(C, DC, StartLoc); } -RequiresExprBodyDecl *RequiresExprBodyDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +RequiresExprBodyDecl * +RequiresExprBodyDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) RequiresExprBodyDecl(C, nullptr, SourceLocation()); } @@ -2281,7 +2282,8 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, isInline, ConstexprKind, EndLocation, TrailingRequiresClause); } -CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) CXXMethodDecl( CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, SC_None, false, false, @@ -2699,7 +2701,7 @@ CXXConstructorDecl::CXXConstructorDecl( void CXXConstructorDecl::anchor() {} CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID, + GlobalDeclID ID, uint64_t AllocKind) { bool hasTrailingExplicit = static_cast(AllocKind & TAKHasTailExplicit); bool isInheritingConstructor = @@ -2845,8 +2847,8 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { void CXXDestructorDecl::anchor() {} -CXXDestructorDecl * -CXXDestructorDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +CXXDestructorDecl *CXXDestructorDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) CXXDestructorDecl( C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, false, false, false, ConstexprSpecKind::Unspecified, nullptr); @@ -2877,8 +2879,8 @@ void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) { void CXXConversionDecl::anchor() {} -CXXConversionDecl * -CXXConversionDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +CXXConversionDecl *CXXConversionDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) CXXConversionDecl( C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, false, false, ExplicitSpecifier(), ConstexprSpecKind::Unspecified, @@ -2924,7 +2926,7 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, DeclContext *DC, } LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) LinkageSpecDecl(nullptr, SourceLocation(), SourceLocation(), LinkageSpecLanguageIDs::C, false); @@ -2946,7 +2948,7 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, } UsingDirectiveDecl *UsingDirectiveDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) UsingDirectiveDecl(nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), @@ -2985,7 +2987,8 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested); } -NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(), SourceLocation(), nullptr, nullptr, false); } @@ -3046,8 +3049,8 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, QualifierLoc, IdentLoc, Namespace); } -NamespaceAliasDecl * -NamespaceAliasDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +NamespaceAliasDecl *NamespaceAliasDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) NamespaceAliasDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, NestedNameSpecifierLoc(), @@ -3102,8 +3105,8 @@ UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, EmptyShell Empty) : NamedDecl(K, nullptr, SourceLocation(), DeclarationName()), redeclarable_base(C) {} -UsingShadowDecl * -UsingShadowDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +UsingShadowDecl *UsingShadowDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) UsingShadowDecl(UsingShadow, C, EmptyShell()); } @@ -3126,7 +3129,7 @@ ConstructorUsingShadowDecl::Create(ASTContext &C, DeclContext *DC, } ConstructorUsingShadowDecl * -ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ConstructorUsingShadowDecl(C, EmptyShell()); } @@ -3174,7 +3177,7 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL, return new (C, DC) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename); } -UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) UsingDecl(nullptr, SourceLocation(), NestedNameSpecifierLoc(), DeclarationNameInfo(), false); @@ -3198,7 +3201,8 @@ UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC, UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType); } -UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(), SourceLocation(), SourceLocation(), nullptr); @@ -3217,7 +3221,7 @@ UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC, return new (C, DC, Extra) UsingPackDecl(DC, InstantiatedFrom, UsingDecls); } -UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions) { size_t Extra = additionalSizeToAlloc(NumExpansions); auto *Result = @@ -3243,7 +3247,7 @@ UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, } UnresolvedUsingValueDecl * -UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) UnresolvedUsingValueDecl(nullptr, QualType(), SourceLocation(), NestedNameSpecifierLoc(), @@ -3273,7 +3277,8 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, } UnresolvedUsingTypenameDecl * -UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) UnresolvedUsingTypenameDecl( nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), nullptr, SourceLocation()); @@ -3286,7 +3291,8 @@ UnresolvedUsingIfExistsDecl::Create(ASTContext &Ctx, DeclContext *DC, } UnresolvedUsingIfExistsDecl * -UnresolvedUsingIfExistsDecl::CreateDeserialized(ASTContext &Ctx, Decl::DeclID ID) { +UnresolvedUsingIfExistsDecl::CreateDeserialized(ASTContext &Ctx, + GlobalDeclID ID) { return new (Ctx, ID) UnresolvedUsingIfExistsDecl(nullptr, SourceLocation(), DeclarationName()); } @@ -3310,7 +3316,7 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, } StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) StaticAssertDecl(nullptr, SourceLocation(), nullptr, nullptr, SourceLocation(), false); } @@ -3332,7 +3338,7 @@ BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC, return new (C, DC) BindingDecl(DC, IdLoc, Id); } -BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); } @@ -3363,7 +3369,7 @@ DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC, } DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID, + GlobalDeclID ID, unsigned NumBindings) { size_t Extra = additionalSizeToAlloc(NumBindings); auto *Result = new (C, ID, Extra) @@ -3402,7 +3408,7 @@ MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC, } MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) MSPropertyDecl(nullptr, SourceLocation(), DeclarationName(), QualType(), nullptr, SourceLocation(), nullptr, nullptr); @@ -3419,7 +3425,7 @@ MSGuidDecl *MSGuidDecl::Create(const ASTContext &C, QualType T, Parts P) { return new (C, DC) MSGuidDecl(DC, T, P); } -MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) MSGuidDecl(nullptr, QualType(), Parts()); } @@ -3529,7 +3535,7 @@ UnnamedGlobalConstantDecl::Create(const ASTContext &C, QualType T, } UnnamedGlobalConstantDecl * -UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) UnnamedGlobalConstantDecl(C, nullptr, QualType(), APValue()); } diff --git a/clang/lib/AST/DeclFriend.cpp b/clang/lib/AST/DeclFriend.cpp index 1fabf8aa80c2b..04b9b93699f36 100644 --- a/clang/lib/AST/DeclFriend.cpp +++ b/clang/lib/AST/DeclFriend.cpp @@ -62,7 +62,7 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, return FD; } -FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned FriendTypeNumTPLists) { std::size_t Extra = additionalSizeToAlloc(FriendTypeNumTPLists); diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index d4275eea05821..83062b0e68878 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -862,7 +862,8 @@ ObjCMethodDecl *ObjCMethodDecl::Create( isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); } -ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) ObjCMethodDecl(SourceLocation(), SourceLocation(), Selector(), QualType(), nullptr, nullptr); } @@ -1486,7 +1487,7 @@ ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, } ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, ObjCTypeParamVariance::Invariant, SourceLocation(), 0, SourceLocation(), @@ -1551,7 +1552,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create( } ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { auto *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr, SourceLocation(), nullptr, nullptr, SourceLocation(), nullptr, false); @@ -1865,7 +1866,7 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, synthesized); } -ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ObjCIvarDecl(nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, ObjCIvarDecl::None, nullptr, false); @@ -1914,7 +1915,7 @@ ObjCAtDefsFieldDecl } ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) ObjCAtDefsFieldDecl(nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr); @@ -1949,7 +1950,7 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, } ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { ObjCProtocolDecl *Result = new (C, ID) ObjCProtocolDecl(C, nullptr, nullptr, SourceLocation(), SourceLocation(), nullptr); @@ -2148,7 +2149,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create( } ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(), SourceLocation(), SourceLocation(), nullptr, nullptr, nullptr); @@ -2188,8 +2189,8 @@ ObjCCategoryImplDecl *ObjCCategoryImplDecl::Create( atStartLoc, CategoryNameLoc); } -ObjCCategoryImplDecl *ObjCCategoryImplDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +ObjCCategoryImplDecl * +ObjCCategoryImplDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ObjCCategoryImplDecl(nullptr, nullptr, nullptr, SourceLocation(), SourceLocation(), SourceLocation()); @@ -2296,7 +2297,7 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, } ObjCImplementationDecl * -ObjCImplementationDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ObjCImplementationDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ObjCImplementationDecl(nullptr, nullptr, nullptr, SourceLocation(), SourceLocation()); } @@ -2339,7 +2340,7 @@ ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, } ObjCCompatibleAliasDecl * -ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ObjCCompatibleAliasDecl(nullptr, SourceLocation(), nullptr, nullptr); } @@ -2360,7 +2361,7 @@ ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, } ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) ObjCPropertyDecl(nullptr, SourceLocation(), nullptr, SourceLocation(), SourceLocation(), QualType(), nullptr, None); @@ -2392,8 +2393,8 @@ ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C, ivarLoc); } -ObjCPropertyImplDecl *ObjCPropertyImplDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +ObjCPropertyImplDecl * +ObjCPropertyImplDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) ObjCPropertyImplDecl(nullptr, SourceLocation(), SourceLocation(), nullptr, Dynamic, nullptr, SourceLocation()); diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp index b178a15aab5f2..81ca48e60942d 100644 --- a/clang/lib/AST/DeclOpenMP.cpp +++ b/clang/lib/AST/DeclOpenMP.cpp @@ -36,7 +36,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, } OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID, + GlobalDeclID ID, unsigned N) { return OMPDeclarativeDirective::createEmptyDirective( C, ID, 0, N); @@ -63,7 +63,8 @@ OMPAllocateDecl *OMPAllocateDecl::Create(ASTContext &C, DeclContext *DC, return D; } -OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID, unsigned NVars, unsigned NClauses) { return OMPDeclarativeDirective::createEmptyDirective( @@ -89,7 +90,8 @@ OMPRequiresDecl *OMPRequiresDecl::Create(ASTContext &C, DeclContext *DC, L); } -OMPRequiresDecl *OMPRequiresDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +OMPRequiresDecl *OMPRequiresDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID, unsigned N) { return OMPDeclarativeDirective::createEmptyDirective( C, ID, N, 0, SourceLocation()); @@ -117,7 +119,7 @@ OMPDeclareReductionDecl *OMPDeclareReductionDecl::Create( } OMPDeclareReductionDecl * -OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) OMPDeclareReductionDecl( OMPDeclareReduction, /*DC=*/nullptr, SourceLocation(), DeclarationName(), QualType(), /*PrevDeclInScope=*/nullptr); @@ -148,7 +150,7 @@ OMPDeclareMapperDecl *OMPDeclareMapperDecl::Create( } OMPDeclareMapperDecl *OMPDeclareMapperDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID, + GlobalDeclID ID, unsigned N) { return OMPDeclarativeDirective::createEmptyDirective( C, ID, N, 1, SourceLocation(), DeclarationName(), QualType(), @@ -179,7 +181,7 @@ OMPCapturedExprDecl *OMPCapturedExprDecl::Create(ASTContext &C, DeclContext *DC, } OMPCapturedExprDecl *OMPCapturedExprDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) OMPCapturedExprDecl(C, nullptr, nullptr, QualType(), /*TInfo=*/nullptr, SourceLocation()); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 67bb9e41e3e61..d27a30e0c5fce 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -337,9 +337,10 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); if (CommonBasePtr->LazySpecializations) { ASTContext &Context = getASTContext(); - Decl::DeclID *Specs = CommonBasePtr->LazySpecializations; + GlobalDeclID *Specs = CommonBasePtr->LazySpecializations; CommonBasePtr->LazySpecializations = nullptr; - for (uint32_t I = 0, N = *Specs++; I != N; ++I) + unsigned SpecSize = (*Specs++).get(); + for (unsigned I = 0; I != SpecSize; ++I) (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); } } @@ -417,8 +418,8 @@ FunctionTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, return TD; } -FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +FunctionTemplateDecl * +FunctionTemplateDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) FunctionTemplateDecl(C, nullptr, SourceLocation(), DeclarationName(), nullptr, nullptr); } @@ -503,7 +504,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, DeclContext *DC, } ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) ClassTemplateDecl(C, nullptr, SourceLocation(), DeclarationName(), nullptr, nullptr); } @@ -652,14 +653,14 @@ TemplateTypeParmDecl *TemplateTypeParmDecl::Create( } TemplateTypeParmDecl * -TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, Decl::DeclID ID) { +TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID) { return new (C, ID) TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(), nullptr, false, false, std::nullopt); } TemplateTypeParmDecl * -TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, Decl::DeclID ID, +TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID, bool HasTypeConstraint) { return new (C, ID, additionalSizeToAlloc(HasTypeConstraint ? 1 : 0)) @@ -759,7 +760,7 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( } NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, bool HasTypeConstraint) { return new (C, ID, additionalSizeToAlloc, @@ -770,7 +771,7 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, } NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpandedTypes, bool HasTypeConstraint) { auto *NTTP = @@ -836,13 +837,13 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, } TemplateTemplateParmDecl * -TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, false, nullptr, false, nullptr); } TemplateTemplateParmDecl * -TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID, +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions) { auto *TTP = new (C, ID, additionalSizeToAlloc(NumExpansions)) @@ -949,7 +950,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { auto *Result = new (C, ID) ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization); Result->setMayHaveOutOfDateDef(false); @@ -1035,8 +1036,7 @@ ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC, return TD; } -ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(), DeclarationName(), nullptr, nullptr); @@ -1070,7 +1070,7 @@ ImplicitConceptSpecializationDecl *ImplicitConceptSpecializationDecl::Create( ImplicitConceptSpecializationDecl * ImplicitConceptSpecializationDecl::CreateDeserialized( - const ASTContext &C, Decl::DeclID ID, unsigned NumTemplateArgs) { + const ASTContext &C, GlobalDeclID ID, unsigned NumTemplateArgs) { return new (C, ID, additionalSizeToAlloc(NumTemplateArgs)) ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs); } @@ -1133,7 +1133,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { auto *Result = new (C, ID) ClassTemplatePartialSpecializationDecl(C); Result->setMayHaveOutOfDateDef(false); return Result; @@ -1160,7 +1160,7 @@ FriendTemplateDecl::Create(ASTContext &Context, DeclContext *DC, } FriendTemplateDecl *FriendTemplateDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) FriendTemplateDecl(EmptyShell()); } @@ -1179,8 +1179,8 @@ TypeAliasTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, return TD; } -TypeAliasTemplateDecl *TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { +TypeAliasTemplateDecl * +TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) TypeAliasTemplateDecl(C, nullptr, SourceLocation(), DeclarationName(), nullptr, nullptr); } @@ -1218,7 +1218,7 @@ VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, } VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) VarTemplateDecl(C, nullptr, SourceLocation(), DeclarationName(), nullptr, nullptr); } @@ -1340,7 +1340,8 @@ VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( } VarTemplateSpecializationDecl * -VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, + GlobalDeclID ID) { return new (C, ID) VarTemplateSpecializationDecl(VarTemplateSpecialization, C); } @@ -1432,7 +1433,7 @@ VarTemplatePartialSpecializationDecl::Create( VarTemplatePartialSpecializationDecl * VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, - Decl::DeclID ID) { + GlobalDeclID ID) { return new (C, ID) VarTemplatePartialSpecializationDecl(C); } @@ -1546,7 +1547,7 @@ TemplateParamObjectDecl *TemplateParamObjectDecl::Create(const ASTContext &C, } TemplateParamObjectDecl * -TemplateParamObjectDecl::CreateDeserialized(ASTContext &C, Decl::DeclID ID) { +TemplateParamObjectDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { auto *TPOD = new (C, ID) TemplateParamObjectDecl(nullptr, QualType(), APValue()); C.addDestruction(&TPOD->Value); return TPOD; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index ead0b9b3727e1..ca030871ceeea 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments( } } else if (const auto *ME = dyn_cast(E)) { if (!ME->isArrow()) { - assert(ME->getBase()->getType()->isRecordType()); + assert(ME->getBase()->getType()->getAsRecordDecl()); if (const auto *Field = dyn_cast(ME->getMemberDecl())) { if (!Field->isBitField() && !Field->getType()->isReferenceType()) { E = ME->getBase(); @@ -3737,7 +3737,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ParenExprClass: case ArraySubscriptExprClass: case MatrixSubscriptExprClass: - case OMPArraySectionExprClass: + case ArraySectionExprClass: case OMPArrayShapingExprClass: case OMPIteratorExprClass: case MemberExprClass: @@ -3950,9 +3950,14 @@ namespace { } void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) { - if (E->getTemporary()->getDestructor()->isTrivial()) { - Inherited::VisitStmt(E); - return; + // Destructor of the temporary might be null if destructor declaration + // is not valid. + if (const CXXDestructorDecl *DtorDecl = + E->getTemporary()->getDestructor()) { + if (DtorDecl->isTrivial()) { + Inherited::VisitStmt(E); + return; + } } NonTrivial = true; @@ -5117,9 +5122,9 @@ QualType AtomicExpr::getValueType() const { return T; } -QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) { +QualType ArraySectionExpr::getBaseOriginalType(const Expr *Base) { unsigned ArraySectionCount = 0; - while (auto *OASE = dyn_cast(Base->IgnoreParens())) { + while (auto *OASE = dyn_cast(Base->IgnoreParens())) { Base = OASE->getBase(); ++ArraySectionCount; } diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 9f9e70b50fa6c..04b9dbd4e1067 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -145,7 +145,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::FunctionParmPackExprClass: case Expr::MSPropertyRefExprClass: case Expr::MSPropertySubscriptExprClass: - case Expr::OMPArraySectionExprClass: + case Expr::ArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: return Cl::CL_LValue; @@ -220,8 +220,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { return ClassifyInternal(Ctx, cast(E)->getReplacement()); - case Expr::PackIndexingExprClass: + case Expr::PackIndexingExprClass: { + // A pack-index-expression always expands to an id-expression. + // Consider it as an LValue expression. + if (cast(E)->isInstantiationDependent()) + return Cl::CL_LValue; return ClassifyInternal(Ctx, cast(E)->getSelectedExpr()); + } // C, C++98 [expr.sub]p1: The result is an lvalue of type "T". // C++11 (DR1213): in the case of an array operand, the result is an lvalue diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index ac2df5473679e..46540096f25a8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2706,7 +2706,11 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E, static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, QualType SrcType, QualType DestType, APFloat &Result) { - assert(isa(E) || isa(E)); + assert((isa(E) || isa(E) || + isa(E)) && + "HandleFloatToFloatCast has been checked with only CastExpr, " + "CompoundAssignOperator and ConvertVectorExpr. Please either validate " + "the new expression or address the root cause of this usage."); llvm::RoundingMode RM = getActiveRoundingMode(Info, E); APFloat::opStatus St; APFloat Value = Result; @@ -9255,9 +9259,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { bool HasValidResult = !Result.InvalidBase && !Result.Designator.Invalid && !Result.IsNullPtr; bool VoidPtrCastMaybeOK = - HasValidResult && - Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx), - E->getType()->getPointeeType()); + Result.IsNullPtr || + (HasValidResult && + Info.Ctx.hasSimilarType(Result.Designator.getType(Info.Ctx), + E->getType()->getPointeeType())); // 1. We'll allow it in std::allocator::allocate, and anything which that // calls. // 2. HACK 2022-03-28: Work around an issue with libstdc++'s @@ -10727,8 +10732,11 @@ namespace { bool VisitUnaryImag(const UnaryOperator *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitConvertVectorExpr(const ConvertVectorExpr *E); + bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E); + // FIXME: Missing: conditional operator (for GNU - // conditional select), shufflevector, ExtVectorElementExpr + // conditional select), ExtVectorElementExpr }; } // end anonymous namespace @@ -10979,6 +10987,122 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } +static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO, + const Expr *E, QualType SourceTy, + QualType DestTy, APValue const &Original, + APValue &Result) { + if (SourceTy->isIntegerType()) { + if (DestTy->isRealFloatingType()) { + Result = APValue(APFloat(0.0)); + return HandleIntToFloatCast(Info, E, FPO, SourceTy, Original.getInt(), + DestTy, Result.getFloat()); + } + if (DestTy->isIntegerType()) { + Result = APValue( + HandleIntToIntCast(Info, E, DestTy, SourceTy, Original.getInt())); + return true; + } + } else if (SourceTy->isRealFloatingType()) { + if (DestTy->isRealFloatingType()) { + Result = Original; + return HandleFloatToFloatCast(Info, E, SourceTy, DestTy, + Result.getFloat()); + } + if (DestTy->isIntegerType()) { + Result = APValue(APSInt()); + return HandleFloatToIntCast(Info, E, SourceTy, Original.getFloat(), + DestTy, Result.getInt()); + } + } + + Info.FFDiag(E, diag::err_convertvector_constexpr_unsupported_vector_cast) + << SourceTy << DestTy; + return false; +} + +bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) { + APValue Source; + QualType SourceVecType = E->getSrcExpr()->getType(); + if (!EvaluateAsRValue(Info, E->getSrcExpr(), Source)) + return false; + + QualType DestTy = E->getType()->castAs()->getElementType(); + QualType SourceTy = SourceVecType->castAs()->getElementType(); + + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + + auto SourceLen = Source.getVectorLength(); + SmallVector ResultElements; + ResultElements.reserve(SourceLen); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APValue Elt; + if (!handleVectorElementCast(Info, FPO, E, SourceTy, DestTy, + Source.getVectorElt(EltNum), Elt)) + return false; + ResultElements.push_back(std::move(Elt)); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); +} + +static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E, + QualType ElemType, APValue const &VecVal1, + APValue const &VecVal2, unsigned EltNum, + APValue &Result) { + unsigned const TotalElementsInInputVector1 = VecVal1.getVectorLength(); + unsigned const TotalElementsInInputVector2 = VecVal2.getVectorLength(); + + APSInt IndexVal = E->getShuffleMaskIdx(Info.Ctx, EltNum); + int64_t index = IndexVal.getExtValue(); + // The spec says that -1 should be treated as undef for optimizations, + // but in constexpr we'd have to produce an APValue::Indeterminate, + // which is prohibited from being a top-level constant value. Emit a + // diagnostic instead. + if (index == -1) { + Info.FFDiag( + E, diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr) + << EltNum; + return false; + } + + if (index < 0 || + index >= TotalElementsInInputVector1 + TotalElementsInInputVector2) + llvm_unreachable("Out of bounds shuffle index"); + + if (index >= TotalElementsInInputVector1) + Result = VecVal2.getVectorElt(index - TotalElementsInInputVector1); + else + Result = VecVal1.getVectorElt(index); + return true; +} + +bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { + APValue VecVal1; + const Expr *Vec1 = E->getExpr(0); + if (!EvaluateAsRValue(Info, Vec1, VecVal1)) + return false; + APValue VecVal2; + const Expr *Vec2 = E->getExpr(1); + if (!EvaluateAsRValue(Info, Vec2, VecVal2)) + return false; + + VectorType const *DestVecTy = E->getType()->castAs(); + QualType DestElTy = DestVecTy->getElementType(); + + auto TotalElementsInOutputVector = DestVecTy->getNumElements(); + + SmallVector ResultElements; + ResultElements.reserve(TotalElementsInOutputVector); + for (unsigned EltNum = 0; EltNum < TotalElementsInOutputVector; ++EltNum) { + APValue Elt; + if (!handleVectorShuffle(Info, E, DestElTy, VecVal1, VecVal2, EltNum, Elt)) + return false; + ResultElements.push_back(std::move(Elt)); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); +} + //===----------------------------------------------------------------------===// // Array Evaluation //===----------------------------------------------------------------------===// @@ -16160,7 +16284,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::StringLiteralClass: case Expr::ArraySubscriptExprClass: case Expr::MatrixSubscriptExprClass: - case Expr::OMPArraySectionExprClass: + case Expr::ArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: case Expr::MemberExprClass: diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 2e54d9f9af1c6..e96a474968511 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -68,7 +68,7 @@ bool ExternalASTSource::layoutRecordType( return false; } -Decl *ExternalASTSource::GetExternalDecl(Decl::DeclID ID) { return nullptr; } +Decl *ExternalASTSource::GetExternalDecl(GlobalDeclID ID) { return nullptr; } Selector ExternalASTSource::GetExternalSelector(uint32_t ID) { return Selector(); diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 8cd0c198d9a84..f1a51e81a92c2 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -110,18 +110,37 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; - unsigned DerivedOffset = collectBaseOffset(getRecordTy(CE->getType()), - getRecordTy(SubExpr->getType())); + const auto extractRecordDecl = [](QualType Ty) -> const CXXRecordDecl * { + if (const auto *PT = dyn_cast(Ty)) + return PT->getPointeeType()->getAsCXXRecordDecl(); + return Ty->getAsCXXRecordDecl(); + }; - return this->emitGetPtrBasePop(DerivedOffset, CE); + // FIXME: We can express a series of non-virtual casts as a single + // GetPtrBasePop op. + QualType CurType = SubExpr->getType(); + for (const CXXBaseSpecifier *B : CE->path()) { + if (B->isVirtual()) { + if (!this->emitGetPtrVirtBasePop(extractRecordDecl(B->getType()), CE)) + return false; + CurType = B->getType(); + } else { + unsigned DerivedOffset = collectBaseOffset(B->getType(), CurType); + if (!this->emitGetPtrBasePop(DerivedOffset, CE)) + return false; + CurType = B->getType(); + } + } + + return true; } case CK_BaseToDerived: { if (!this->visit(SubExpr)) return false; - unsigned DerivedOffset = collectBaseOffset(getRecordTy(SubExpr->getType()), - getRecordTy(CE->getType())); + unsigned DerivedOffset = + collectBaseOffset(SubExpr->getType(), CE->getType()); return this->emitGetPtrDerivedPop(DerivedOffset, CE); } @@ -193,6 +212,13 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; + // If SubExpr doesn't result in a pointer, make it one. + if (PrimType FromT = classifyPrim(SubExpr->getType()); FromT != PT_Ptr) { + assert(isPtrType(FromT)); + if (!this->emitDecayPtr(FromT, PT_Ptr, CE)) + return false; + } + PrimType T = classifyPrim(CE->getType()); if (T == PT_IntAP) return this->emitCastPointerIntegralAP(Ctx.getBitWidth(CE->getType()), @@ -905,8 +931,31 @@ bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueIni if (std::optional T = classify(QT)) return this->visitZeroInitializer(*T, QT, E); - if (QT->isRecordType()) - return false; + if (QT->isRecordType()) { + const RecordDecl *RD = QT->getAsRecordDecl(); + assert(RD); + if (RD->isInvalidDecl()) + return false; + if (RD->isUnion()) { + // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the + // object's first non-static named data member is zero-initialized + // FIXME + return false; + } + + if (const auto *CXXRD = dyn_cast(RD); + CXXRD && CXXRD->getNumVBases() > 0) { + // TODO: Diagnose. + return false; + } + + const Record *R = getRecord(QT); + if (!R) + return false; + + assert(Initializing); + return this->visitZeroRecordInitializer(R, E); + } if (QT->isIncompleteArrayType()) return true; @@ -981,122 +1030,98 @@ bool ByteCodeExprGen::VisitArraySubscriptExpr( template bool ByteCodeExprGen::visitInitList(ArrayRef Inits, + const Expr *ArrayFiller, const Expr *E) { - assert(E->getType()->isRecordType()); - const Record *R = getRecord(E->getType()); + if (E->getType()->isVoidType()) + return this->emitInvalid(E); - if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) { - return this->visitInitializer(Inits[0]); + // Handle discarding first. + if (DiscardResult) { + for (const Expr *Init : Inits) { + if (!this->discard(Init)) + return false; + } + return true; } - unsigned InitIndex = 0; - for (const Expr *Init : Inits) { - // Skip unnamed bitfields. - while (InitIndex < R->getNumFields() && - R->getField(InitIndex)->Decl->isUnnamedBitField()) - ++InitIndex; + // Primitive values. + if (std::optional T = classify(E->getType())) { + assert(!DiscardResult); + if (Inits.size() == 0) + return this->visitZeroInitializer(*T, E->getType(), E); + assert(Inits.size() == 1); + return this->delegate(Inits[0]); + } - if (!this->emitDupPtr(E)) - return false; + QualType T = E->getType(); + if (T->isRecordType()) { + const Record *R = getRecord(E->getType()); - if (std::optional T = classify(Init)) { - const Record::Field *FieldToInit = R->getField(InitIndex); - if (!this->visit(Init)) - return false; + if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) { + return this->visitInitializer(Inits[0]); + } - if (FieldToInit->isBitField()) { - if (!this->emitInitBitField(*T, FieldToInit, E)) - return false; - } else { - if (!this->emitInitField(*T, FieldToInit->Offset, E)) - return false; - } + unsigned InitIndex = 0; + for (const Expr *Init : Inits) { + // Skip unnamed bitfields. + while (InitIndex < R->getNumFields() && + R->getField(InitIndex)->Decl->isUnnamedBitField()) + ++InitIndex; - if (!this->emitPopPtr(E)) + if (!this->emitDupPtr(E)) return false; - ++InitIndex; - } else { - // Initializer for a direct base class. - if (const Record::Base *B = R->getBase(Init->getType())) { - if (!this->emitGetPtrBasePop(B->Offset, Init)) - return false; - - if (!this->visitInitializer(Init)) - return false; - if (!this->emitFinishInitPop(E)) - return false; - // Base initializers don't increase InitIndex, since they don't count - // into the Record's fields. - } else { + if (std::optional T = classify(Init)) { const Record::Field *FieldToInit = R->getField(InitIndex); - // Non-primitive case. Get a pointer to the field-to-initialize - // on the stack and recurse into visitInitializer(). - if (!this->emitGetPtrField(FieldToInit->Offset, Init)) + if (!this->visit(Init)) return false; - if (!this->visitInitializer(Init)) - return false; + if (FieldToInit->isBitField()) { + if (!this->emitInitBitField(*T, FieldToInit, E)) + return false; + } else { + if (!this->emitInitField(*T, FieldToInit->Offset, E)) + return false; + } if (!this->emitPopPtr(E)) return false; ++InitIndex; - } - } - } - return true; -} + } else { + // Initializer for a direct base class. + if (const Record::Base *B = R->getBase(Init->getType())) { + if (!this->emitGetPtrBasePop(B->Offset, Init)) + return false; -/// Pointer to the array(not the element!) must be on the stack when calling -/// this. -template -bool ByteCodeExprGen::visitArrayElemInit(unsigned ElemIndex, - const Expr *Init) { - if (std::optional T = classify(Init->getType())) { - // Visit the primitive element like normal. - if (!this->visit(Init)) - return false; - return this->emitInitElem(*T, ElemIndex, Init); - } + if (!this->visitInitializer(Init)) + return false; - // Advance the pointer currently on the stack to the given - // dimension. - if (!this->emitConstUint32(ElemIndex, Init)) - return false; - if (!this->emitArrayElemPtrUint32(Init)) - return false; - if (!this->visitInitializer(Init)) - return false; - return this->emitFinishInitPop(Init); -} + if (!this->emitFinishInitPop(E)) + return false; + // Base initializers don't increase InitIndex, since they don't count + // into the Record's fields. + } else { + const Record::Field *FieldToInit = R->getField(InitIndex); + // Non-primitive case. Get a pointer to the field-to-initialize + // on the stack and recurse into visitInitializer(). + if (!this->emitGetPtrField(FieldToInit->Offset, Init)) + return false; -template -bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { - // Handle discarding first. - if (DiscardResult) { - for (const Expr *Init : E->inits()) { - if (!this->discard(Init)) - return false; + if (!this->visitInitializer(Init)) + return false; + + if (!this->emitPopPtr(E)) + return false; + ++InitIndex; + } + } } return true; } - // Primitive values. - if (std::optional T = classify(E->getType())) { - assert(!DiscardResult); - if (E->getNumInits() == 0) - return this->visitZeroInitializer(*T, E->getType(), E); - assert(E->getNumInits() == 1); - return this->delegate(E->inits()[0]); - } - - QualType T = E->getType(); - if (T->isRecordType()) - return this->visitInitList(E->inits(), E); - if (T->isArrayType()) { unsigned ElementIndex = 0; - for (const Expr *Init : E->inits()) { + for (const Expr *Init : Inits) { if (!this->visitArrayElemInit(ElementIndex, Init)) return false; ++ElementIndex; @@ -1104,13 +1129,13 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { // Expand the filler expression. // FIXME: This should go away. - if (const Expr *Filler = E->getArrayFiller()) { + if (ArrayFiller) { const ConstantArrayType *CAT = Ctx.getASTContext().getAsConstantArrayType(E->getType()); uint64_t NumElems = CAT->getZExtSize(); for (; ElementIndex != NumElems; ++ElementIndex) { - if (!this->visitArrayElemInit(ElementIndex, Filler)) + if (!this->visitArrayElemInit(ElementIndex, ArrayFiller)) return false; } } @@ -1119,10 +1144,10 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { } if (const auto *ComplexTy = E->getType()->getAs()) { - unsigned NumInits = E->getNumInits(); + unsigned NumInits = Inits.size(); if (NumInits == 1) - return this->delegate(E->inits()[0]); + return this->delegate(Inits[0]); QualType ElemQT = ComplexTy->getElementType(); PrimType ElemT = classifyPrim(ElemQT); @@ -1136,7 +1161,7 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { } } else if (NumInits == 2) { unsigned InitIndex = 0; - for (const Expr *Init : E->inits()) { + for (const Expr *Init : Inits) { if (!this->visit(Init)) return false; @@ -1150,22 +1175,32 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { if (const auto *VecT = E->getType()->getAs()) { unsigned NumVecElements = VecT->getNumElements(); - assert(NumVecElements >= E->getNumInits()); + assert(NumVecElements >= Inits.size()); QualType ElemQT = VecT->getElementType(); PrimType ElemT = classifyPrim(ElemQT); // All initializer elements. unsigned InitIndex = 0; - for (const Expr *Init : E->inits()) { + for (const Expr *Init : Inits) { if (!this->visit(Init)) return false; - if (!this->emitInitElem(ElemT, InitIndex, E)) - return false; - ++InitIndex; + // If the initializer is of vector type itself, we have to deconstruct + // that and initialize all the target fields from the initializer fields. + if (const auto *InitVecT = Init->getType()->getAs()) { + if (!this->emitCopyArray(ElemT, 0, InitIndex, InitVecT->getNumElements(), E)) + return false; + InitIndex += InitVecT->getNumElements(); + } else { + if (!this->emitInitElem(ElemT, InitIndex, E)) + return false; + ++InitIndex; + } } + assert(InitIndex <= NumVecElements); + // Fill the rest with zeroes. for (; InitIndex != NumVecElements; ++InitIndex) { if (!this->visitZeroInitializer(ElemT, ElemQT, E)) @@ -1179,19 +1214,38 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { return false; } +/// Pointer to the array(not the element!) must be on the stack when calling +/// this. template -bool ByteCodeExprGen::VisitCXXParenListInitExpr( - const CXXParenListInitExpr *E) { - if (DiscardResult) { - for (const Expr *Init : E->getInitExprs()) { - if (!this->discard(Init)) - return false; - } - return true; +bool ByteCodeExprGen::visitArrayElemInit(unsigned ElemIndex, + const Expr *Init) { + if (std::optional T = classify(Init->getType())) { + // Visit the primitive element like normal. + if (!this->visit(Init)) + return false; + return this->emitInitElem(*T, ElemIndex, Init); } - assert(E->getType()->isRecordType()); - return this->visitInitList(E->getInitExprs(), E); + // Advance the pointer currently on the stack to the given + // dimension. + if (!this->emitConstUint32(ElemIndex, Init)) + return false; + if (!this->emitArrayElemPtrUint32(Init)) + return false; + if (!this->visitInitializer(Init)) + return false; + return this->emitFinishInitPop(Init); +} + +template +bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { + return this->visitInitList(E->inits(), E->getArrayFiller(), E); +} + +template +bool ByteCodeExprGen::VisitCXXParenListInitExpr( + const CXXParenListInitExpr *E) { + return this->visitInitList(E->getInitExprs(), E->getArrayFiller(), E); } template @@ -1314,6 +1368,20 @@ bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr( assert(E->getTypeOfArgument()->isSizelessVectorType()); } + if (Kind == UETT_VecStep) { + if (const auto *VT = E->getTypeOfArgument()->getAs()) { + unsigned N = VT->getNumElements(); + + // The vec_step built-in functions that take a 3-component + // vector return 4. (OpenCL 1.1 spec 6.11.12) + if (N == 3) + N = 4; + + return this->emitConst(N, E); + } + return this->emitConst(1, E); + } + return false; } @@ -2224,26 +2292,54 @@ bool ByteCodeExprGen::VisitCXXScalarValueInitExpr( if (std::optional T = classify(Ty)) return this->visitZeroInitializer(*T, Ty, E); - assert(Ty->isAnyComplexType()); - if (!Initializing) { - std::optional LocalIndex = allocateLocal(E, /*IsExtended=*/false); - if (!LocalIndex) - return false; - if (!this->emitGetPtrLocal(*LocalIndex, E)) - return false; + if (const auto *CT = Ty->getAs()) { + if (!Initializing) { + std::optional LocalIndex = + allocateLocal(E, /*IsExtended=*/false); + if (!LocalIndex) + return false; + if (!this->emitGetPtrLocal(*LocalIndex, E)) + return false; + } + + // Initialize both fields to 0. + QualType ElemQT = CT->getElementType(); + PrimType ElemT = classifyPrim(ElemQT); + + for (unsigned I = 0; I != 2; ++I) { + if (!this->visitZeroInitializer(ElemT, ElemQT, E)) + return false; + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + return true; } - // Initialize both fields to 0. - QualType ElemQT = Ty->getAs()->getElementType(); - PrimType ElemT = classifyPrim(ElemQT); + if (const auto *VT = Ty->getAs()) { + // FIXME: Code duplication with the _Complex case above. + if (!Initializing) { + std::optional LocalIndex = + allocateLocal(E, /*IsExtended=*/false); + if (!LocalIndex) + return false; + if (!this->emitGetPtrLocal(*LocalIndex, E)) + return false; + } - for (unsigned I = 0; I != 2; ++I) { - if (!this->visitZeroInitializer(ElemT, ElemQT, E)) - return false; - if (!this->emitInitElem(ElemT, I, E)) - return false; + // Initialize all fields to 0. + QualType ElemQT = VT->getElementType(); + PrimType ElemT = classifyPrim(ElemQT); + + for (unsigned I = 0, N = VT->getNumElements(); I != N; ++I) { + if (!this->visitZeroInitializer(ElemT, ElemQT, E)) + return false; + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + return true; } - return true; + + return false; } template @@ -2321,8 +2417,7 @@ bool ByteCodeExprGen::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { if (!this->emitGetPtrGlobal(*GlobalIndex, E)) return false; - const Record *R = this->getRecord(E->getType()); - assert(R); + assert(this->getRecord(E->getType())); const APValue &V = E->getGuidDecl()->getAsAPValue(); if (V.getKind() == APValue::None) @@ -2330,41 +2425,8 @@ bool ByteCodeExprGen::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { assert(V.isStruct()); assert(V.getStructNumBases() == 0); - // FIXME: This could be useful in visitAPValue, too. - for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) { - const APValue &F = V.getStructField(I); - const Record::Field *RF = R->getField(I); - - if (F.isInt()) { - PrimType T = classifyPrim(RF->Decl->getType()); - if (!this->visitAPValue(F, T, E)) - return false; - if (!this->emitInitField(T, RF->Offset, E)) - return false; - } else if (F.isArray()) { - assert(RF->Desc->isPrimitiveArray()); - const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe(); - PrimType ElemT = classifyPrim(ArrType->getElementType()); - assert(ArrType); - - if (!this->emitDupPtr(E)) - return false; - if (!this->emitGetPtrField(RF->Offset, E)) - return false; - - for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) { - if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E)) - return false; - if (!this->emitInitElem(ElemT, A, E)) - return false; - } - - if (!this->emitPopPtr(E)) - return false; - } else { - assert(false && "I don't think this should be possible"); - } - } + if (!this->visitAPValueInitializer(V, E)) + return false; return this->emitFinishInit(E); } @@ -2929,6 +2991,54 @@ bool ByteCodeExprGen::visitAPValue(const APValue &Val, return false; } +template +bool ByteCodeExprGen::visitAPValueInitializer(const APValue &Val, + const Expr *E) { + if (Val.isStruct()) { + const Record *R = this->getRecord(E->getType()); + assert(R); + + for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) { + const APValue &F = Val.getStructField(I); + const Record::Field *RF = R->getField(I); + + if (F.isInt()) { + PrimType T = classifyPrim(RF->Decl->getType()); + if (!this->visitAPValue(F, T, E)) + return false; + if (!this->emitInitField(T, RF->Offset, E)) + return false; + } else if (F.isArray()) { + assert(RF->Desc->isPrimitiveArray()); + const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe(); + PrimType ElemT = classifyPrim(ArrType->getElementType()); + assert(ArrType); + + if (!this->emitDupPtr(E)) + return false; + if (!this->emitGetPtrField(RF->Offset, E)) + return false; + + for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) { + if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E)) + return false; + if (!this->emitInitElem(ElemT, A, E)) + return false; + } + + if (!this->emitPopPtr(E)) + return false; + } else { + assert(false && "I don't think this should be possible"); + } + } + return true; + } + // TODO: Other types. + + return false; +} + template bool ByteCodeExprGen::VisitBuiltinCallExpr(const CallExpr *E) { const Function *Func = getFunction(E->getDirectCallee()); @@ -3450,9 +3560,17 @@ bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { } else if (const auto *FuncDecl = dyn_cast(D)) { const Function *F = getFunction(FuncDecl); return F && this->emitGetFnPtr(F, E); - } else if (isa(D)) { - if (std::optional Index = P.getOrCreateGlobal(D)) - return this->emitGetPtrGlobal(*Index, E); + } else if (const auto *TPOD = dyn_cast(D)) { + if (std::optional Index = P.getOrCreateGlobal(D)) { + if (!this->emitGetPtrGlobal(*Index, E)) + return false; + if (std::optional T = classify(E->getType())) { + if (!this->visitAPValue(TPOD->getValue(), *T, E)) + return false; + return this->emitInitGlobal(*T, *Index, E); + } + return this->visitAPValueInitializer(TPOD->getValue(), E); + } return false; } @@ -3529,35 +3647,17 @@ void ByteCodeExprGen::emitCleanup() { template unsigned -ByteCodeExprGen::collectBaseOffset(const RecordType *BaseType, - const RecordType *DerivedType) { - assert(BaseType); - assert(DerivedType); - const auto *FinalDecl = cast(BaseType->getDecl()); - const RecordDecl *CurDecl = DerivedType->getDecl(); - const Record *CurRecord = getRecord(CurDecl); - assert(CurDecl && FinalDecl); - - unsigned OffsetSum = 0; - for (;;) { - assert(CurRecord->getNumBases() > 0); - // One level up - for (const Record::Base &B : CurRecord->bases()) { - const auto *BaseDecl = cast(B.Decl); - - if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) { - OffsetSum += B.Offset; - CurRecord = B.R; - CurDecl = BaseDecl; - break; - } - } - if (CurDecl == FinalDecl) - break; - } +ByteCodeExprGen::collectBaseOffset(const QualType BaseType, + const QualType DerivedType) { + const auto extractRecordDecl = [](QualType Ty) -> const CXXRecordDecl * { + if (const auto *PT = dyn_cast(Ty)) + return PT->getPointeeType()->getAsCXXRecordDecl(); + return Ty->getAsCXXRecordDecl(); + }; + const CXXRecordDecl *BaseDecl = extractRecordDecl(BaseType); + const CXXRecordDecl *DerivedDecl = extractRecordDecl(DerivedType); - assert(OffsetSum > 0); - return OffsetSum; + return Ctx.collectBaseOffset(BaseDecl, DerivedDecl); } /// Emit casts from a PrimType to another PrimType. diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 7e9dc8631fc0d..a89e37c67aa67 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -181,6 +181,7 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, bool visitVarDecl(const VarDecl *VD); /// Visit an APValue. bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E); + bool visitAPValueInitializer(const APValue &Val, const Expr *E); /// Visits an expression and converts it to a boolean. bool visitBool(const Expr *E); @@ -224,7 +225,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, return this->emitFinishInitPop(I); } - bool visitInitList(ArrayRef Inits, const Expr *E); + bool visitInitList(ArrayRef Inits, const Expr *ArrayFiller, + const Expr *E); bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init); /// Creates a local primitive value. @@ -283,8 +285,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, bool emitRecordDestruction(const Record *R); bool emitDestruction(const Descriptor *Desc); - unsigned collectBaseOffset(const RecordType *BaseType, - const RecordType *DerivedType); + unsigned collectBaseOffset(const QualType BaseType, + const QualType DerivedType); protected: /// Variable to storage mapping. diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index 36dab6252ece6..ff92bc117f9ef 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -189,14 +189,23 @@ bool ByteCodeStmtGen::visitFunc(const FunctionDecl *F) { if (!emitFieldInitializer(F, F->Offset, InitExpr)) return false; } else if (const Type *Base = Init->getBaseClass()) { - // Base class initializer. - // Get This Base and call initializer on it. const auto *BaseDecl = Base->getAsCXXRecordDecl(); assert(BaseDecl); - const Record::Base *B = R->getBase(BaseDecl); - assert(B); - if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) - return false; + + if (Init->isBaseVirtual()) { + assert(R->getVirtualBase(BaseDecl)); + if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr)) + return false; + + } else { + // Base class initializer. + // Get This Base and call initializer on it. + const Record::Base *B = R->getBase(BaseDecl); + assert(B); + if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) + return false; + } + if (!this->visitInitializer(InitExpr)) return false; if (!this->emitFinishInitPop(InitExpr)) @@ -283,8 +292,9 @@ bool ByteCodeStmtGen::visitStmt(const Stmt *S) { case Stmt::GCCAsmStmtClass: case Stmt::MSAsmStmtClass: case Stmt::GotoStmtClass: - case Stmt::LabelStmtClass: return this->emitInvalid(S); + case Stmt::LabelStmtClass: + return this->visitStmt(cast(S)->getSubStmt()); default: { if (auto *Exp = dyn_cast(S)) return this->discard(Exp); @@ -323,7 +333,8 @@ bool ByteCodeStmtGen::visitCompoundStmt( template bool ByteCodeStmtGen::visitDeclStmt(const DeclStmt *DS) { for (auto *D : DS->decls()) { - if (isa(D)) + if (isa(D)) continue; const auto *VD = dyn_cast(D); diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 274178837bf04..d51a57e5e92ea 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -262,3 +262,36 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) { return Func; } + +unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl, + const RecordDecl *DerivedDecl) const { + assert(BaseDecl); + assert(DerivedDecl); + const auto *FinalDecl = cast(BaseDecl); + const RecordDecl *CurDecl = DerivedDecl; + const Record *CurRecord = P->getOrCreateRecord(CurDecl); + assert(CurDecl && FinalDecl); + + unsigned OffsetSum = 0; + for (;;) { + assert(CurRecord->getNumBases() > 0); + // One level up + for (const Record::Base &B : CurRecord->bases()) { + const auto *BaseDecl = cast(B.Decl); + + if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) { + OffsetSum += B.Offset; + CurRecord = B.R; + CurDecl = BaseDecl; + break; + } + } + if (CurDecl == FinalDecl) + break; + + // break; + } + + assert(OffsetSum > 0); + return OffsetSum; +} diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index 23c439ad8912a..360e9499d0844 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -104,6 +104,9 @@ class Context final { /// Returns the program. This is only needed for unittests. Program &getProgram() const { return *P.get(); } + unsigned collectBaseOffset(const RecordDecl *BaseDecl, + const RecordDecl *DerivedDecl) const; + private: /// Runs a function. bool Run(State &Parent, const Function *Func, APValue &Result); diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index a4ccc0236d292..954c58c8cb371 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -136,28 +136,66 @@ static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst, } } +static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, + bool IsActive, const Descriptor *D, + unsigned FieldOffset) { + bool IsUnion = false; // FIXME + auto *Desc = reinterpret_cast(Ptr + FieldOffset) - 1; + Desc->Offset = FieldOffset; + Desc->Desc = D; + Desc->IsInitialized = D->IsArray; + Desc->IsBase = false; + Desc->IsActive = IsActive && !IsUnion; + Desc->IsConst = IsConst || D->IsConst; + Desc->IsFieldMutable = IsMutable || D->IsMutable; + + if (auto Fn = D->CtorFn) + Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable, + Desc->IsActive, D); +} + +static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, + bool IsActive, const Descriptor *D, unsigned FieldOffset, + bool IsVirtualBase) { + assert(D); + assert(D->ElemRecord); + + bool IsUnion = D->ElemRecord->isUnion(); + auto *Desc = reinterpret_cast(Ptr + FieldOffset) - 1; + Desc->Offset = FieldOffset; + Desc->Desc = D; + Desc->IsInitialized = D->IsArray; + Desc->IsBase = true; + Desc->IsActive = IsActive && !IsUnion; + Desc->IsConst = IsConst || D->IsConst; + Desc->IsFieldMutable = IsMutable || D->IsMutable; + + for (const auto &V : D->ElemRecord->bases()) + initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc, + V.Offset, false); + for (const auto &F : D->ElemRecord->fields()) + initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, F.Desc, + F.Offset); + + // If this is initializing a virtual base, we do NOT want to consider its + // virtual bases, those are already flattened into the parent record when + // creating it. + if (IsVirtualBase) + return; + + for (const auto &V : D->ElemRecord->virtual_bases()) + initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc, + V.Offset, true); +} + static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, const Descriptor *D) { - const bool IsUnion = D->ElemRecord->isUnion(); - auto CtorSub = [=](unsigned SubOff, const Descriptor *F, bool IsBase) { - auto *Desc = reinterpret_cast(Ptr + SubOff) - 1; - Desc->Offset = SubOff; - Desc->Desc = F; - Desc->IsInitialized = F->IsArray && !IsBase; - Desc->IsBase = IsBase; - Desc->IsActive = IsActive && !IsUnion; - Desc->IsConst = IsConst || F->IsConst; - Desc->IsFieldMutable = IsMutable || F->IsMutable; - if (auto Fn = F->CtorFn) - Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsFieldMutable, Desc->IsActive, - F); - }; - for (const auto &B : D->ElemRecord->bases()) - CtorSub(B.Offset, B.Desc, /*isBase=*/true); + for (const auto &V : D->ElemRecord->bases()) + initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false); for (const auto &F : D->ElemRecord->fields()) - CtorSub(F.Offset, F.Desc, /*isBase=*/false); + initField(B, Ptr, IsConst, IsMutable, IsActive, F.Desc, F.Offset); for (const auto &V : D->ElemRecord->virtual_bases()) - CtorSub(V.Offset, V.Desc, /*isBase=*/true); + initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true); } static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) { diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index c386fc8ac7b09..cd20495c259c7 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -82,6 +82,9 @@ struct InlineDescriptor { InlineDescriptor(const Descriptor *D) : Offset(sizeof(InlineDescriptor)), IsConst(false), IsInitialized(false), IsBase(false), IsActive(false), IsFieldMutable(false), Desc(D) {} + + void dump() const { dump(llvm::errs()); } + void dump(llvm::raw_ostream &OS) const; }; /// Describes a memory block created by an allocation site. diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index d127f33223e80..ccdc96a79436d 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -200,7 +200,7 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { OS << " primitive"; if (isZeroSizeArray()) - OS << " zero-size-arrary"; + OS << " zero-size-array"; else if (isUnknownSizeArray()) OS << " unknown-size-array"; @@ -208,6 +208,25 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { OS << " dummy"; } +LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const { + { + ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true}); + OS << "InlineDescriptor " << (const void *)this << "\n"; + } + OS << "Offset: " << Offset << "\n"; + OS << "IsConst: " << IsConst << "\n"; + OS << "IsInitialized: " << IsInitialized << "\n"; + OS << "IsBase: " << IsBase << "\n"; + OS << "IsActive: " << IsActive << "\n"; + OS << "IsFieldMutable: " << IsFieldMutable << "\n"; + OS << "Desc: "; + if (Desc) + Desc->dump(OS); + else + OS << "nullptr"; + OS << "\n"; +} + LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS, unsigned Indent) const { unsigned Spaces = Indent * 2; @@ -251,8 +270,6 @@ LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation, ++I; } - // FIXME: Virtual bases. - I = 0; for (const Record::Field &F : fields()) { OS.indent(Indent) << "- Field " << I << ": "; @@ -263,6 +280,14 @@ LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation, OS << ". Offset " << (Offset + F.Offset) << "\n"; ++I; } + + I = 0; + for (const Record::Base &B : virtual_bases()) { + OS.indent(Indent) << "- Virtual Base " << I << ". Offset " + << (Offset + B.Offset) << "\n"; + B.R->dump(OS, Indentation + 1, Offset + B.Offset); + ++I; + } } LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 9283f697c0070..66d30cc3fbaab 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1355,20 +1355,26 @@ inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, while (Base.isBaseClass()) Base = Base.getBase(); - auto *Field = Base.getRecord()->getVirtualBase(Decl); - S.Stk.push(Base.atField(Field->Offset)); + const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl); + S.Stk.push(Base.atField(VirtBase->Offset)); return true; } -inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { +inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, + const RecordDecl *D) { + assert(D); const Pointer &Ptr = S.Stk.pop(); if (!CheckNull(S, OpPC, Ptr, CSK_Base)) return false; + if (Ptr.isDummy()) // FIXME: Once we have type info for dummy pointers, this + // needs to go. + return false; return VirtBaseHelper(S, OpPC, D, Ptr); } inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { + assert(D); if (S.checkingPotentialConstantExpression()) return false; const Pointer &This = S.Current->getThis(); @@ -1929,10 +1935,15 @@ template inline bool Shr(InterpState &S, CodePtr OpPC) { using LT = typename PrimConv::T; using RT = typename PrimConv::T; - const auto &RHS = S.Stk.pop(); + auto RHS = S.Stk.pop(); const auto &LHS = S.Stk.pop(); const unsigned Bits = LHS.bitWidth(); + // OpenCL 6.3j: shift values are effectively % word size of LHS. + if (S.getLangOpts().OpenCL) + RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), + RHS.bitWidth(), &RHS); + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; @@ -1954,10 +1965,15 @@ template inline bool Shl(InterpState &S, CodePtr OpPC) { using LT = typename PrimConv::T; using RT = typename PrimConv::T; - const auto &RHS = S.Stk.pop(); + auto RHS = S.Stk.pop(); const auto &LHS = S.Stk.pop(); const unsigned Bits = LHS.bitWidth(); + // OpenCL 6.3j: shift values are effectively % word size of LHS. + if (S.getLangOpts().OpenCL) + RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), + RHS.bitWidth(), &RHS); + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; @@ -2074,6 +2090,24 @@ inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) { return true; } +template ::T> +inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) { + const auto &SrcPtr = S.Stk.pop(); + const auto &DestPtr = S.Stk.peek(); + + for (uint32_t I = 0; I != Size; ++I) { + const Pointer &SP = SrcPtr.atIndex(SrcIndex + I); + + if (!CheckLoad(S, OpPC, SP)) + return false; + + const Pointer &DP = DestPtr.atIndex(DestIndex + I); + DP.deref() = SP.deref(); + DP.initialize(); + } + return true; +} + /// Just takes a pointer and checks if it's an incomplete /// array type. inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 742785b28eb4d..cfbd7f93c32de 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -336,7 +336,7 @@ def GetPtrDerivedPop : Opcode { } // [Pointer] -> [Pointer] -def GetPtrVirtBase : Opcode { +def GetPtrVirtBasePop : Opcode { // RecordDecl of base class. let Args = [ArgRecordDecl]; } @@ -376,7 +376,11 @@ def ArrayElem : Opcode { let HasGroup = 1; } - +def CopyArray : Opcode { + let Args = [ArgUint32, ArgUint32, ArgUint32]; + let Types = [AllTypeClass]; + let HasGroup = 1; +} //===----------------------------------------------------------------------===// // Direct field accessors diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 3773e0662f784..02075c20cf556 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -173,7 +173,8 @@ std::optional Program::createGlobal(const ValueDecl *VD, if (const auto *Var = dyn_cast(VD)) { IsStatic = Context::shouldBeGloballyIndexed(VD); IsExtern = Var->hasExternalStorage(); - } else if (isa(VD)) { + } else if (isa(VD)) { IsStatic = true; IsExtern = false; } else { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index bbbb40ecf9b1b..81f14f4a41f52 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4723,7 +4723,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::MSPropertySubscriptExprClass: case Expr::TypoExprClass: // This should no longer exist in the AST by now. case Expr::RecoveryExprClass: - case Expr::OMPArraySectionExprClass: + case Expr::ArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: case Expr::CXXInheritedCtorInitExprClass: diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 2140ba6820c4c..83cc95012efd8 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -467,7 +467,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::PseudoObject: case BuiltinType::BuiltinFn: case BuiltinType::IncompleteMatrixIdx: - case BuiltinType::OMPArraySection: + case BuiltinType::ArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: case BuiltinType::BFloat16: diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 6cd5b28802187..885f3b7618ec5 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -134,35 +134,67 @@ OpenACCNumGangsClause *OpenACCNumGangsClause::Create(const ASTContext &C, return new (Mem) OpenACCNumGangsClause(BeginLoc, LParenLoc, IntExprs, EndLoc); } +OpenACCPrivateClause *OpenACCPrivateClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef VarList, + SourceLocation EndLoc) { + void *Mem = C.Allocate( + OpenACCPrivateClause::totalSizeToAlloc(VarList.size())); + return new (Mem) OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, EndLoc); +} + //===----------------------------------------------------------------------===// // OpenACC clauses printing methods //===----------------------------------------------------------------------===// + +void OpenACCClausePrinter::printExpr(const Expr *E) { + E->printPretty(OS, nullptr, Policy, 0); +} + void OpenACCClausePrinter::VisitDefaultClause(const OpenACCDefaultClause &C) { OS << "default(" << C.getDefaultClauseKind() << ")"; } void OpenACCClausePrinter::VisitIfClause(const OpenACCIfClause &C) { - OS << "if(" << C.getConditionExpr() << ")"; + OS << "if("; + printExpr(C.getConditionExpr()); + OS << ")"; } void OpenACCClausePrinter::VisitSelfClause(const OpenACCSelfClause &C) { OS << "self"; - if (const Expr *CondExpr = C.getConditionExpr()) - OS << "(" << CondExpr << ")"; + if (const Expr *CondExpr = C.getConditionExpr()) { + OS << "("; + printExpr(CondExpr); + OS << ")"; + } } void OpenACCClausePrinter::VisitNumGangsClause(const OpenACCNumGangsClause &C) { OS << "num_gangs("; - llvm::interleaveComma(C.getIntExprs(), OS); + llvm::interleaveComma(C.getIntExprs(), OS, + [&](const Expr *E) { printExpr(E); }); OS << ")"; } void OpenACCClausePrinter::VisitNumWorkersClause( const OpenACCNumWorkersClause &C) { - OS << "num_workers(" << C.getIntExpr() << ")"; + OS << "num_workers("; + printExpr(C.getIntExpr()); + OS << ")"; } void OpenACCClausePrinter::VisitVectorLengthClause( const OpenACCVectorLengthClause &C) { - OS << "vector_length(" << C.getIntExpr() << ")"; + OS << "vector_length("; + printExpr(C.getIntExpr()); + OS << ")"; +} + +void OpenACCClausePrinter::VisitPrivateClause(const OpenACCPrivateClause &C) { + OS << "private("; + llvm::interleaveComma(C.getVarList(), OS, + [&](const Expr *E) { printExpr(E); }); + OS << ")"; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 192bdb9294571..d8de1d083743d 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1148,9 +1148,10 @@ void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { if (!S->clauses().empty()) { OS << ' '; - OpenACCClausePrinter Printer(OS); + OpenACCClausePrinter Printer(OS, Policy); Printer.VisitClauseList(S->clauses()); } + OS << '\n'; PrintStmt(S->getStructuredBlock()); } @@ -1527,7 +1528,7 @@ void StmtPrinter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *Node) { OS << "]"; } -void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) { +void StmtPrinter::VisitArraySectionExpr(ArraySectionExpr *Node) { PrintExpr(Node->getBase()); OS << "["; if (Node->getLowerBound()) @@ -1537,7 +1538,7 @@ void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) { if (Node->getLength()) PrintExpr(Node->getLength()); } - if (Node->getColonLocSecond().isValid()) { + if (Node->isOMPArraySection() && Node->getColonLocSecond().isValid()) { OS << ":"; if (Node->getStride()) PrintExpr(Node->getStride()); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 2f77de6851448..e8213c098cedd 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1440,7 +1440,7 @@ void StmtProfiler::VisitMatrixSubscriptExpr(const MatrixSubscriptExpr *S) { VisitExpr(S); } -void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) { +void StmtProfiler::VisitArraySectionExpr(const ArraySectionExpr *S) { VisitExpr(S); } @@ -2536,6 +2536,12 @@ void OpenACCClauseProfiler::VisitNumWorkersClause( Profiler.VisitStmt(Clause.getIntExpr()); } +void OpenACCClauseProfiler::VisitPrivateClause( + const OpenACCPrivateClause &Clause) { + for (auto *E : Clause.getVarList()) + Profiler.VisitStmt(E); +} + void OpenACCClauseProfiler::VisitVectorLengthClause( const OpenACCVectorLengthClause &Clause) { assert(Clause.hasIntExpr() && diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 930b130f7782f..0c38e5124747a 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -401,6 +401,7 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { case OpenACCClauseKind::Self: case OpenACCClauseKind::NumGangs: case OpenACCClauseKind::NumWorkers: + case OpenACCClauseKind::Private: case OpenACCClauseKind::VectorLength: // The condition expression will be printed as a part of the 'children', // but print 'clause' here so it is clear what is happening from the dump. diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 59768cbabd79c..5b367d695db30 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2510,6 +2510,18 @@ bool Type::isSveVLSBuiltinType() const { return false; } +QualType Type::getSizelessVectorEltType(const ASTContext &Ctx) const { + assert(isSizelessVectorType() && "Must be sizeless vector type"); + // Currently supports SVE and RVV + if (isSVESizelessBuiltinType()) + return getSveEltType(Ctx); + + if (isRVVSizelessBuiltinType()) + return getRVVEltType(Ctx); + + llvm_unreachable("Unhandled type"); +} + QualType Type::getSveEltType(const ASTContext &Ctx) const { assert(isSveVLSBuiltinType() && "unsupported type!"); @@ -3419,8 +3431,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "reserve_id_t"; case IncompleteMatrixIdx: return ""; - case OMPArraySection: - return ""; + case ArraySection: + return ""; case OMPArrayShaping: return ""; case OMPIterator: @@ -4721,7 +4733,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case BuiltinType::BuiltinFn: case BuiltinType::NullPtr: case BuiltinType::IncompleteMatrixIdx: - case BuiltinType::OMPArraySection: + case BuiltinType::ArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: return false; diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index b85c7b802f2ad..abe259e36d7a2 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -434,7 +434,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { #include "clang/Basic/WebAssemblyReferenceTypes.def" case BuiltinType::BuiltinFn: case BuiltinType::IncompleteMatrixIdx: - case BuiltinType::OMPArraySection: + case BuiltinType::ArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: return TST_unspecified; diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 941322be8f870..3b3782fa1db9a 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -235,15 +235,17 @@ const Stmt *ExprMutationAnalyzer::Analyzer::findMutationMemoized( if (Memoized != MemoizedResults.end()) return Memoized->second; + // Assume Exp is not mutated before analyzing Exp. + MemoizedResults[Exp] = nullptr; if (isUnevaluated(Exp)) - return MemoizedResults[Exp] = nullptr; + return nullptr; for (const auto &Finder : Finders) { if (const Stmt *S = (this->*Finder)(Exp)) return MemoizedResults[Exp] = S; } - return MemoizedResults[Exp] = nullptr; + return nullptr; } const Stmt * diff --git a/clang/lib/Analysis/FlowSensitive/ASTOps.cpp b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp index 619bf772bba5e..bd1676583eccc 100644 --- a/clang/lib/Analysis/FlowSensitive/ASTOps.cpp +++ b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp @@ -33,12 +33,20 @@ namespace clang::dataflow { const Expr &ignoreCFGOmittedNodes(const Expr &E) { const Expr *Current = &E; - if (auto *EWC = dyn_cast(Current)) { - Current = EWC->getSubExpr(); + const Expr *Last = nullptr; + while (Current != Last) { + Last = Current; + if (auto *EWC = dyn_cast(Current)) { + Current = EWC->getSubExpr(); + assert(Current != nullptr); + } + if (auto *CE = dyn_cast(Current)) { + Current = CE->getSubExpr(); + assert(Current != nullptr); + } + Current = Current->IgnoreParens(); assert(Current != nullptr); } - Current = Current->IgnoreParens(); - assert(Current != nullptr); return *Current; } diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 3cb656adcbdc0..d79e734402892 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -157,7 +157,13 @@ static WidenResult widenDistinctValues(QualType Type, Value &Prev, Value &Current, Environment &CurrentEnv, Environment::ValueModel &Model) { // Boolean-model widening. - if (auto *PrevBool = dyn_cast(&Prev)) { + if (isa(Prev) && isa(Current)) { + // FIXME: Checking both values should be unnecessary, but we can currently + // end up with `BoolValue`s in integer-typed variables. See comment in + // `joinDistinctValues()` for details. + auto &PrevBool = cast(Prev); + auto &CurBool = cast(Current); + if (isa(Prev)) // Safe to return `Prev` here, because Top is never dependent on the // environment. @@ -166,13 +172,12 @@ static WidenResult widenDistinctValues(QualType Type, Value &Prev, // We may need to widen to Top, but before we do so, check whether both // values are implied to be either true or false in the current environment. // In that case, we can simply return a literal instead. - auto &CurBool = cast(Current); - bool TruePrev = PrevEnv.proves(PrevBool->formula()); + bool TruePrev = PrevEnv.proves(PrevBool.formula()); bool TrueCur = CurrentEnv.proves(CurBool.formula()); if (TruePrev && TrueCur) return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged}; if (!TruePrev && !TrueCur && - PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool->formula())) && + PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) && CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged}; @@ -333,6 +338,18 @@ class ResultObjectVisitor : public RecursiveASTVisitor { } } + bool TraverseDecl(Decl *D) { + // Don't traverse nested record or function declarations. + // - We won't be analyzing code contained in these anyway + // - We don't model fields that are used only in these nested declaration, + // so trying to propagate a result object to initializers of such fields + // would cause an error. + if (isa_and_nonnull(D) || isa_and_nonnull(D)) + return true; + + return RecursiveASTVisitor::TraverseDecl(D); + } + bool TraverseBindingDecl(BindingDecl *BD) { // `RecursiveASTVisitor` doesn't traverse holding variables for // `BindingDecl`s by itself, so we need to tell it to. diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 43fdfa5abcbb5..fd224aeb79b15 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -41,7 +41,11 @@ namespace dataflow { const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { auto BlockIt = ACFG.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); - assert(BlockIt != ACFG.getStmtToBlock().end()); + if (BlockIt == ACFG.getStmtToBlock().end()) { + assert(false); + // Return null to avoid dereferencing the end iterator in non-assert builds. + return nullptr; + } if (!ACFG.isBlockReachable(*BlockIt->getSecond())) return nullptr; if (BlockIt->getSecond()->getBlockID() == CurBlockID) diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index 2e218ba7c84cc..824d4a0e2eee5 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -130,6 +130,9 @@ add_clang_library(clangBasic DEPENDS omp_gen ClangDriverOptions + # These generated headers are included transitively. + ARMTargetParserTableGen + AArch64TargetParserTableGen ) target_link_libraries(clangBasic diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index cd520a6375e07..143c04309d075 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -39,12 +39,6 @@ using namespace clang; #define DEBUG_TYPE "file-search" -ALWAYS_ENABLED_STATISTIC(NumDirLookups, "Number of directory lookups."); -ALWAYS_ENABLED_STATISTIC(NumFileLookups, "Number of file lookups."); -ALWAYS_ENABLED_STATISTIC(NumDirCacheMisses, - "Number of directory cache misses."); -ALWAYS_ENABLED_STATISTIC(NumFileCacheMisses, "Number of file cache misses."); - //===----------------------------------------------------------------------===// // Common logic. //===----------------------------------------------------------------------===// @@ -656,6 +650,14 @@ StringRef FileManager::getCanonicalName(const void *Entry, StringRef Name) { return CanonicalName; } +void FileManager::AddStats(const FileManager &Other) { + assert(&Other != this && "Collecting stats into the same FileManager"); + NumDirLookups += Other.NumDirLookups; + NumFileLookups += Other.NumFileLookups; + NumDirCacheMisses += Other.NumDirCacheMisses; + NumFileCacheMisses += Other.NumFileCacheMisses; +} + void FileManager::PrintStats() const { llvm::errs() << "\n*** File Manager Stats:\n"; llvm::errs() << UniqueRealFiles.size() << " real files found, " diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index e69adbe754739..df9855a52e61c 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -225,6 +225,10 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { bool hasBitIntType() const override { return true; } const char *getBFloat16Mangling() const override { return "u6__bf16"; }; + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(getTriple().isArch64Bit() ? 256 : 64, 64); + } }; class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo { diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index 9376c46cd98ca..feeb04f37eeba 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -175,6 +175,10 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { std::optional handleAsmEscapedChar(char EscChar) const override; StringRef getABI() const override { return ABI; } + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } + protected: std::string CPU; StringRef ABI; diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index 489f29fc4fead..d19b37dd4df7a 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -113,6 +113,10 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { StringRef CPUName(Name); return isValidCPUName(CPUName); } + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/M68k.h b/clang/lib/Basic/Targets/M68k.h index 7ffa901127e50..b732add77e034 100644 --- a/clang/lib/Basic/Targets/M68k.h +++ b/clang/lib/Basic/Targets/M68k.h @@ -56,6 +56,10 @@ class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo { BuiltinVaListKind getBuiltinVaListKind() const override; bool setCPU(const std::string &Name) override; CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } }; } // namespace targets diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index 0d6e4b4d08089..730deb674aa57 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -431,6 +431,10 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { bool validateTarget(DiagnosticsEngine &Diags) const override; bool hasBitIntType() const override { return true; } + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 60bc1dec8f95c..cd0f08dfb3bc9 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -423,6 +423,10 @@ class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo { // This is the ELF definition return TargetInfo::PowerABIBuiltinVaList; } + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } }; // Note: ABI differences may eventually require us to have a separate @@ -503,6 +507,10 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { return CCCR_Warning; } } + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(128, 128); + } }; class LLVM_LIBRARY_VISIBILITY AIXPPC32TargetInfo : diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index 9fa42e75bbfd1..d0e9cdc6da07b 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -122,6 +122,10 @@ class RISCVTargetInfo : public TargetInfo { void fillValidTuneCPUList(SmallVectorImpl &Values) const override; bool supportsTargetAttributeTune() const override { return true; } ParsedTargetAttr parseTargetAttr(StringRef Str) const override; + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } }; class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo { public: diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index 214fef88e1dcd..3357bee33e1ac 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -140,6 +140,10 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { CPU = getCPUKind(Name); return CPU != CK_GENERIC; } + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(32, 32); + } }; // SPARC v8 is the 32-bit mode selected by Triple::sparc. diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index 8e302acd51b8a..73d3aa01a043f 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -220,6 +220,10 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { int getEHDataRegisterNumber(unsigned RegNo) const override { return RegNo < 4 ? 6 + RegNo : -1; } + + std::pair hardwareInterferenceSizes() const override { + return std::make_pair(256, 256); + } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index d473fd1908646..1f0418b21c1f8 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -47,6 +47,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("simd128", SIMDLevel >= SIMD128) .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD) + .Case("half-precision", HasHalfPrecision) .Case("nontrapping-fptoint", HasNontrappingFPToInt) .Case("sign-ext", HasSignExt) .Case("exception-handling", HasExceptionHandling) @@ -99,6 +100,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_extended_const__"); if (HasMultiMemory) Builder.defineMacro("__wasm_multimemory__"); + if (HasHalfPrecision) + Builder.defineMacro("__wasm_half_precision__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); @@ -147,19 +150,26 @@ void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap &Features, bool WebAssemblyTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { - if (CPU == "bleeding-edge") { + auto addGenericFeatures = [&]() { + Features["multivalue"] = true; + Features["mutable-globals"] = true; + Features["reference-types"] = true; + Features["sign-ext"] = true; + }; + auto addBleedingEdgeFeatures = [&]() { + addGenericFeatures(); Features["atomics"] = true; Features["bulk-memory"] = true; Features["multimemory"] = true; - Features["mutable-globals"] = true; Features["nontrapping-fptoint"] = true; - Features["reference-types"] = true; - Features["sign-ext"] = true; Features["tail-call"] = true; + Features["half-precision"] = true; setSIMDLevel(Features, SIMD128, true); - } else if (CPU == "generic") { - Features["mutable-globals"] = true; - Features["sign-ext"] = true; + }; + if (CPU == "generic") { + addGenericFeatures(); + } else if (CPU == "bleeding-edge") { + addBleedingEdgeFeatures(); } return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); @@ -216,6 +226,15 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasBulkMemory = false; continue; } + if (Feature == "+half-precision") { + SIMDLevel = std::max(SIMDLevel, SIMD128); + HasHalfPrecision = true; + continue; + } + if (Feature == "-half-precision") { + HasHalfPrecision = false; + continue; + } if (Feature == "+atomics") { HasAtomics = true; continue; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 5568aa28eaefa..e4c18879182ed 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -64,6 +64,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool HasReferenceTypes = false; bool HasExtendedConst = false; bool HasMultiMemory = false; + bool HasHalfPrecision = false; std::string ABI; diff --git a/clang/lib/CIR/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt index e69de29bb2d1d..d2ff200e0da5f 100644 --- a/clang/lib/CIR/CMakeLists.txt +++ b/clang/lib/CIR/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include) +include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include) + +add_subdirectory(Dialect) diff --git a/clang/lib/CIR/Dialect/CMakeLists.txt b/clang/lib/CIR/Dialect/CMakeLists.txt new file mode 100644 index 0000000000000..f33061b2d87cf --- /dev/null +++ b/clang/lib/CIR/Dialect/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(IR) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp new file mode 100644 index 0000000000000..c2829c3ff2af8 --- /dev/null +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -0,0 +1,13 @@ +//===- CIRDialect.cpp - MLIR CIR ops implementation -----------------------===// +// +// 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 implements the CIR dialect and its operations. +// +//===----------------------------------------------------------------------===// + +#include diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt new file mode 100644 index 0000000000000..0d7476b555705 --- /dev/null +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -0,0 +1,3 @@ +add_clang_library(MLIRCIR + CIRDialect.cpp + ) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e72b31baf1b98..31786efd357d3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -899,8 +899,9 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type, return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true); } -const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField( - ASTContext &Ctx, const RecordDecl *RD, StringRef Name, uint64_t &Offset) { +const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset( + ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FAMDecl, + uint64_t &Offset) { const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); uint32_t FieldNo = 0; @@ -909,7 +910,7 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField( return nullptr; for (const FieldDecl *FD : RD->fields()) { - if ((Name.empty() || FD->getNameAsString() == Name) && + if ((!FAMDecl || FD == FAMDecl) && Decl::isFlexibleArrayMemberLike( Ctx, FD, FD->getType(), StrictFlexArraysLevel, /*IgnoreTemplateOrMacroSubstitution=*/true)) { @@ -920,8 +921,8 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField( QualType Ty = FD->getType(); if (Ty->isRecordType()) { - if (const FieldDecl *Field = FindFlexibleArrayMemberField( - Ctx, Ty->getAsRecordDecl(), Name, Offset)) { + if (const FieldDecl *Field = FindFlexibleArrayMemberFieldAndOffset( + Ctx, Ty->getAsRecordDecl(), FAMDecl, Offset)) { const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); Offset += Layout.getFieldOffset(FieldNo); return Field; @@ -1007,12 +1008,14 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, // Get the flexible array member Decl. const RecordDecl *OuterRD = nullptr; - std::string FAMName; + const FieldDecl *FAMDecl = nullptr; if (const auto *ME = dyn_cast(Base)) { // Check if \p Base is referencing the FAM itself. const ValueDecl *VD = ME->getMemberDecl(); OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext(); - FAMName = VD->getNameAsString(); + FAMDecl = dyn_cast(VD); + if (!FAMDecl) + return nullptr; } else if (const auto *DRE = dyn_cast(Base)) { // Check if we're pointing to the whole struct. QualType Ty = DRE->getDecl()->getType(); @@ -1051,9 +1054,11 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, if (!OuterRD) return nullptr; + // We call FindFlexibleArrayMemberAndOffset even if FAMDecl is non-null to + // get its offset. uint64_t Offset = 0; - const FieldDecl *FAMDecl = - FindFlexibleArrayMemberField(Ctx, OuterRD, FAMName, Offset); + FAMDecl = + FindFlexibleArrayMemberFieldAndOffset(Ctx, OuterRD, FAMDecl, Offset); Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity(); if (!FAMDecl || !FAMDecl->getType()->isCountAttributedType()) @@ -3703,7 +3708,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // frexpl instead of legalizing this type in the BE. if (&getTarget().getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble()) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; } case Builtin::BI__builtin_frexp: case Builtin::BI__builtin_frexpf: @@ -3960,9 +3965,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } case Builtin::BI__builtin_reduce_max: { - auto GetIntrinsicID = [](QualType QT) { + auto GetIntrinsicID = [this](QualType QT) { if (auto *VecTy = QT->getAs()) QT = VecTy->getElementType(); + else if (QT->isSizelessVectorType()) + QT = QT->getSizelessVectorEltType(CGM.getContext()); + if (QT->isSignedIntegerType()) return llvm::Intrinsic::vector_reduce_smax; if (QT->isUnsignedIntegerType()) @@ -3975,9 +3983,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } case Builtin::BI__builtin_reduce_min: { - auto GetIntrinsicID = [](QualType QT) { + auto GetIntrinsicID = [this](QualType QT) { if (auto *VecTy = QT->getAs()) QT = VecTy->getElementType(); + else if (QT->isSizelessVectorType()) + QT = QT->getSizelessVectorEltType(CGM.getContext()); + if (QT->isSignedIntegerType()) return llvm::Intrinsic::vector_reduce_smin; if (QT->isUnsignedIntegerType()) @@ -5441,7 +5452,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_ptrauth_auth_and_resign: if (Args[4]->getType()->isPointerTy()) Args[4] = Builder.CreatePtrToInt(Args[4], IntPtrTy); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_ptrauth_auth: case Builtin::BI__builtin_ptrauth_sign_unauthenticated: @@ -18945,7 +18956,7 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_wmma_f16_16x16x16_f16_w32_gfx12: case AMDGPU::BI__builtin_amdgcn_wmma_f16_16x16x16_f16_w64_gfx12: AppendFalseForOpselArg = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case AMDGPU::BI__builtin_amdgcn_wmma_f16_16x16x16_f16_w32: case AMDGPU::BI__builtin_amdgcn_wmma_f16_16x16x16_f16_w64: ArgsForMatchingMatrixTypes = {2, 0}; // CD, AB @@ -18954,7 +18965,7 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w32_gfx12: case AMDGPU::BI__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w64_gfx12: AppendFalseForOpselArg = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case AMDGPU::BI__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w32: case AMDGPU::BI__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w64: ArgsForMatchingMatrixTypes = {2, 0}; // CD, AB diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 9846aa85a1cf5..bde818319fc72 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -426,6 +426,33 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, CGM.CreateRuntimeFunction(FTy, LaunchKernelName); CGF.EmitCall(FI, CGCallee::forDirect(cudaLaunchKernelFn), ReturnValueSlot(), LaunchKernelArgs); + + // To prevent CUDA device stub functions from being merged by ICF in MSVC + // environment, create an unique global variable for each kernel and write to + // the variable in the device stub. + if (CGM.getContext().getTargetInfo().getCXXABI().isMicrosoft() && + !CGF.getLangOpts().HIP) { + llvm::Function *KernelFunction = llvm::cast(Kernel); + std::string GlobalVarName = (KernelFunction->getName() + ".id").str(); + + llvm::GlobalVariable *HandleVar = + CGM.getModule().getNamedGlobal(GlobalVarName); + if (!HandleVar) { + HandleVar = new llvm::GlobalVariable( + CGM.getModule(), CGM.Int8Ty, + /*Constant=*/false, KernelFunction->getLinkage(), + llvm::ConstantInt::get(CGM.Int8Ty, 0), GlobalVarName); + HandleVar->setDSOLocal(KernelFunction->isDSOLocal()); + HandleVar->setVisibility(KernelFunction->getVisibility()); + if (KernelFunction->hasComdat()) + HandleVar->setComdat(CGM.getModule().getOrInsertComdat(GlobalVarName)); + } + + CGF.Builder.CreateAlignedStore(llvm::ConstantInt::get(CGM.Int8Ty, 1), + HandleVar, CharUnits::One(), + /*IsVolatile=*/true); + } + CGF.EmitBranch(EndBlock); CGF.EmitBlock(EndBlock); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 65c088ef5082e..5c07540145395 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1594,6 +1594,11 @@ bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) { return RI.isIndirect() || (RI.isInAlloca() && RI.getInAllocaSRet()); } +bool CodeGenModule::ReturnTypeHasInReg(const CGFunctionInfo &FI) { + const auto &RI = FI.getReturnInfo(); + return RI.getInReg(); +} + bool CodeGenModule::ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI) { return ReturnTypeUsesSRet(FI) && getTargetCodeGenInfo().doesReturnSlotInterfereWithArgs(); @@ -4774,11 +4779,11 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, AggValueSlot Slot = args.isUsingInAlloca() ? createPlaceholderSlot(*this, type) : CreateAggTemp(type, "agg.tmp"); - bool DestroyedInCallee = true, NeedsEHCleanup = true; + bool DestroyedInCallee = true, NeedsCleanup = true; if (const auto *RD = type->getAsCXXRecordDecl()) DestroyedInCallee = RD->hasNonTrivialDestructor(); else - NeedsEHCleanup = needsEHCleanup(type.isDestructedType()); + NeedsCleanup = type.isDestructedType(); if (DestroyedInCallee) Slot.setExternallyDestructed(); @@ -4787,14 +4792,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, RValue RV = Slot.asRValue(); args.add(RV, type); - if (DestroyedInCallee && NeedsEHCleanup) { + if (DestroyedInCallee && NeedsCleanup) { // Create a no-op GEP between the placeholder and the cleanup so we can // RAUW it successfully. It also serves as a marker of the first // instruction where the cleanup is active. - pushFullExprCleanup(EHCleanup, Slot.getAddress(), - type); + pushFullExprCleanup(NormalAndEHCleanup, + Slot.getAddress(), type); // This unreachable is a temporary marker which will be removed later. - llvm::Instruction *IsActive = Builder.CreateUnreachable(); + llvm::Instruction *IsActive = + Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy)); args.addArgCleanupDeactivation(EHStack.stable_begin(), IsActive); } return; diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index e6f8e6873004f..469e0363b744a 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -634,12 +634,19 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF, /// Pops a cleanup block. If the block includes a normal cleanup, the /// current insertion point is threaded through the cleanup, as are /// any branch fixups on the cleanup. -void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { +void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough, + bool ForDeactivation) { assert(!EHStack.empty() && "cleanup stack is empty!"); assert(isa(*EHStack.begin()) && "top not a cleanup!"); EHCleanupScope &Scope = cast(*EHStack.begin()); assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups()); + // If we are deactivating a normal cleanup, we need to pretend that the + // fallthrough is unreachable. We restore this IP before returning. + CGBuilderTy::InsertPoint NormalDeactivateOrigIP; + if (ForDeactivation && (Scope.isNormalCleanup() || !getLangOpts().EHAsynch)) { + NormalDeactivateOrigIP = Builder.saveAndClearIP(); + } // Remember activation information. bool IsActive = Scope.isActive(); Address NormalActiveFlag = @@ -667,7 +674,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // - whether there's a fallthrough llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock(); - bool HasFallthrough = (FallthroughSource != nullptr && IsActive); + bool HasFallthrough = + FallthroughSource != nullptr && (IsActive || HasExistingBranches); // Branch-through fall-throughs leave the insertion point set to the // end of the last cleanup, which points to the current scope. The @@ -692,7 +700,11 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // If we have a prebranched fallthrough into an inactive normal // cleanup, rewrite it so that it leads to the appropriate place. - if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) { + if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && + !RequiresNormalCleanup) { + // FIXME: Come up with a program which would need forwarding prebranched + // fallthrough and add tests. Otherwise delete this and assert against it. + assert(!IsActive); llvm::BasicBlock *prebranchDest; // If the prebranch is semantically branching through the next @@ -724,6 +736,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { EHStack.popCleanup(); // safe because there are no fixups assert(EHStack.getNumBranchFixups() == 0 || EHStack.hasNormalCleanups()); + if (NormalDeactivateOrigIP.isSet()) + Builder.restoreIP(NormalDeactivateOrigIP); return; } @@ -760,11 +774,19 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { if (!RequiresNormalCleanup) { // Mark CPP scope end for passed-by-value Arg temp // per Windows ABI which is "normally" Cleanup in callee - if (IsEHa && getInvokeDest() && Builder.GetInsertBlock()) { - if (Personality.isMSVCXXPersonality()) + if (IsEHa && getInvokeDest()) { + // If we are deactivating a normal cleanup then we don't have a + // fallthrough. Restore original IP to emit CPP scope ends in the correct + // block. + if (NormalDeactivateOrigIP.isSet()) + Builder.restoreIP(NormalDeactivateOrigIP); + if (Personality.isMSVCXXPersonality() && Builder.GetInsertBlock()) EmitSehCppScopeEnd(); + if (NormalDeactivateOrigIP.isSet()) + NormalDeactivateOrigIP = Builder.saveAndClearIP(); } destroyOptimisticNormalEntry(*this, Scope); + Scope.MarkEmitted(); EHStack.popCleanup(); } else { // If we have a fallthrough and no other need for the cleanup, @@ -781,6 +803,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } destroyOptimisticNormalEntry(*this, Scope); + Scope.MarkEmitted(); EHStack.popCleanup(); EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag); @@ -916,6 +939,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } // IV. Pop the cleanup and emit it. + Scope.MarkEmitted(); EHStack.popCleanup(); assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); @@ -984,6 +1008,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } } + if (NormalDeactivateOrigIP.isSet()) + Builder.restoreIP(NormalDeactivateOrigIP); assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0); // Emit the EH cleanup if required. @@ -1143,25 +1169,6 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { Builder.ClearInsertionPoint(); } -static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack, - EHScopeStack::stable_iterator C) { - // If we needed a normal block for any reason, that counts. - if (cast(*EHStack.find(C)).getNormalBlock()) - return true; - - // Check whether any enclosed cleanups were needed. - for (EHScopeStack::stable_iterator - I = EHStack.getInnermostNormalCleanup(); - I != C; ) { - assert(C.strictlyEncloses(I)); - EHCleanupScope &S = cast(*EHStack.find(I)); - if (S.getNormalBlock()) return true; - I = S.getEnclosingNormalCleanup(); - } - - return false; -} - static bool IsUsedAsEHCleanup(EHScopeStack &EHStack, EHScopeStack::stable_iterator cleanup) { // If we needed an EH block for any reason, that counts. @@ -1210,8 +1217,7 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF, // Calculate whether the cleanup was used: // - as a normal cleanup - if (Scope.isNormalCleanup() && - (isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) { + if (Scope.isNormalCleanup()) { Scope.setTestFlagInNormalCleanup(); needFlag = true; } @@ -1224,13 +1230,16 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF, } // If it hasn't yet been used as either, we're done. - if (!needFlag) return; + if (!needFlag) + return; Address var = Scope.getActiveFlag(); if (!var.isValid()) { + CodeGenFunction::AllocaTrackerRAII AllocaTracker(CGF); var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), CharUnits::One(), "cleanup.isactive"); Scope.setActiveFlag(var); + Scope.AddAuxAllocas(AllocaTracker.Take()); assert(dominatingIP && "no existing variable and no dominating IP!"); @@ -1273,17 +1282,8 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C, // to the current RunCleanupsScope. if (C == EHStack.stable_begin() && CurrentCleanupScopeDepth.strictlyEncloses(C)) { - // Per comment below, checking EHAsynch is not really necessary - // it's there to assure zero-impact w/o EHAsynch option - if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch) { - PopCleanupBlock(); - } else { - // If it's a normal cleanup, we need to pretend that the - // fallthrough is unreachable. - CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); - PopCleanupBlock(); - Builder.restoreIP(SavedIP); - } + PopCleanupBlock(/*FallthroughIsBranchThrough=*/false, + /*ForDeactivation=*/true); return; } diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h index 03e4a29d7b3db..c73c97146abc4 100644 --- a/clang/lib/CodeGen/CGCleanup.h +++ b/clang/lib/CodeGen/CGCleanup.h @@ -16,8 +16,11 @@ #include "EHScopeStack.h" #include "Address.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Instruction.h" namespace llvm { class BasicBlock; @@ -266,6 +269,51 @@ class alignas(8) EHCleanupScope : public EHScope { }; mutable struct ExtInfo *ExtInfo; + /// Erases auxillary allocas and their usages for an unused cleanup. + /// Cleanups should mark these allocas as 'used' if the cleanup is + /// emitted, otherwise these instructions would be erased. + struct AuxillaryAllocas { + SmallVector AuxAllocas; + bool used = false; + + // Records a potentially unused instruction to be erased later. + void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); } + + // Mark all recorded instructions as used. These will not be erased later. + void MarkUsed() { + used = true; + AuxAllocas.clear(); + } + + ~AuxillaryAllocas() { + if (used) + return; + llvm::SetVector Uses; + for (auto *Inst : llvm::reverse(AuxAllocas)) + CollectUses(Inst, Uses); + // Delete uses in the reverse order of insertion. + for (auto *I : llvm::reverse(Uses)) + I->eraseFromParent(); + } + + private: + void CollectUses(llvm::Instruction *I, + llvm::SetVector &Uses) { + if (!I || !Uses.insert(I)) + return; + for (auto *User : I->users()) + CollectUses(cast(User), Uses); + } + }; + mutable struct AuxillaryAllocas *AuxAllocas; + + AuxillaryAllocas &getAuxillaryAllocas() { + if (!AuxAllocas) { + AuxAllocas = new struct AuxillaryAllocas(); + } + return *AuxAllocas; + } + /// The number of fixups required by enclosing scopes (not including /// this one). If this is the top cleanup scope, all the fixups /// from this index onwards belong to this scope. @@ -298,7 +346,7 @@ class alignas(8) EHCleanupScope : public EHScope { EHScopeStack::stable_iterator enclosingEH) : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal), NormalBlock(nullptr), - ActiveFlag(Address::invalid()), ExtInfo(nullptr), + ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr), FixupDepth(fixupDepth) { CleanupBits.IsNormalCleanup = isNormal; CleanupBits.IsEHCleanup = isEH; @@ -312,8 +360,15 @@ class alignas(8) EHCleanupScope : public EHScope { } void Destroy() { + if (AuxAllocas) + delete AuxAllocas; delete ExtInfo; } + void AddAuxAllocas(llvm::SmallVector Allocas) { + for (auto *Alloca : Allocas) + getAuxillaryAllocas().Add(Alloca); + } + void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); } // Objects of EHCleanupScope are not destructed. Use Destroy(). ~EHCleanupScope() = delete; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index f219b14e4a81d..789d77f8773e4 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1425,7 +1425,28 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, SourceLocation Loc = AliasDecl->getLocation(); - if (CGM.getCodeGenOpts().DebugTemplateAlias) { + if (CGM.getCodeGenOpts().DebugTemplateAlias && + // FIXME: This is a workaround for the issue + // https://github.com/llvm/llvm-project/issues/89774 + // The TemplateSpecializationType doesn't contain any instantiation + // information; dependent template arguments can't be resolved. For now, + // fall back to DW_TAG_typedefs for template aliases that are + // instantiation dependent, e.g.: + // ``` + // template + // using A = int; + // + // template + // struct S { + // using AA = A; // Instantiation dependent. + // AA aa; + // }; + // + // S<0> s; + // ``` + // S::AA's underlying type A is dependent on I so will be emitted as a + // DW_TAG_typedef. + !Ty->isInstantiationDependentType()) { auto ArgVector = ::GetTemplateArgs(TD, Ty); TemplateArgs Args = {TD->getTemplateParameters(), ArgVector}; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 4dbecebb70029..5a7dbe68e6c39 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -20,6 +20,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "EHScopeStack.h" #include "PatternInit.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -36,6 +37,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Type.h" #include @@ -2255,6 +2257,27 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr, destroyer, useEHCleanupForArray); } +// Pushes a destroy and defers its deactivation until its +// CleanupDeactivationScope is exited. +void CodeGenFunction::pushDestroyAndDeferDeactivation( + QualType::DestructionKind dtorKind, Address addr, QualType type) { + assert(dtorKind && "cannot push destructor for trivial type"); + + CleanupKind cleanupKind = getCleanupKind(dtorKind); + pushDestroyAndDeferDeactivation( + cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup); +} + +void CodeGenFunction::pushDestroyAndDeferDeactivation( + CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer, + bool useEHCleanupForArray) { + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy)); + pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); +} + void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) { EHStack.pushCleanup(Kind, SPMem); } @@ -2271,39 +2294,48 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind, // If we're not in a conditional branch, we don't need to bother generating a // conditional cleanup. if (!isInConditionalBranch()) { - // Push an EH-only cleanup for the object now. // FIXME: When popping normal cleanups, we need to keep this EH cleanup // around in case a temporary's destructor throws an exception. - if (cleanupKind & EHCleanup) - EHStack.pushCleanup( - static_cast(cleanupKind & ~NormalCleanup), addr, type, - destroyer, useEHCleanupForArray); + // Add the cleanup to the EHStack. After the full-expr, this would be + // deactivated before being popped from the stack. + pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer, + useEHCleanupForArray); + + // Since this is lifetime-extended, push it once again to the EHStack after + // the full expression. return pushCleanupAfterFullExprWithActiveFlag( - cleanupKind, Address::invalid(), addr, type, destroyer, useEHCleanupForArray); + cleanupKind, Address::invalid(), addr, type, destroyer, + useEHCleanupForArray); } // Otherwise, we should only destroy the object if it's been initialized. - // Re-use the active flag and saved address across both the EH and end of - // scope cleanups. - using SavedType = typename DominatingValue
::saved_type; using ConditionalCleanupType = EHScopeStack::ConditionalCleanup; - - Address ActiveFlag = createCleanupActiveFlag(); - SavedType SavedAddr = saveValueInCond(addr); - - if (cleanupKind & EHCleanup) { - EHStack.pushCleanup( - static_cast(cleanupKind & ~NormalCleanup), SavedAddr, type, - destroyer, useEHCleanupForArray); - initFullExprCleanupWithFlag(ActiveFlag); - } - + DominatingValue
::saved_type SavedAddr = saveValueInCond(addr); + + // Remember to emit cleanup if we branch-out before end of full-expression + // (eg: through stmt-expr or coro suspensions). + AllocaTrackerRAII DeactivationAllocas(*this); + Address ActiveFlagForDeactivation = createCleanupActiveFlag(); + + pushCleanupAndDeferDeactivation( + cleanupKind, SavedAddr, type, destroyer, useEHCleanupForArray); + initFullExprCleanupWithFlag(ActiveFlagForDeactivation); + EHCleanupScope &cleanup = cast(*EHStack.begin()); + // Erase the active flag if the cleanup was not emitted. + cleanup.AddAuxAllocas(std::move(DeactivationAllocas).Take()); + + // Since this is lifetime-extended, push it once again to the EHStack after + // the full expression. + // The previous active flag would always be 'false' due to forced deferred + // deactivation. Use a separate flag for lifetime-extension to correctly + // remember if this branch was taken and the object was initialized. + Address ActiveFlagForLifetimeExt = createCleanupActiveFlag(); pushCleanupAfterFullExprWithActiveFlag( - cleanupKind, ActiveFlag, SavedAddr, type, destroyer, + cleanupKind, ActiveFlagForLifetimeExt, SavedAddr, type, destroyer, useEHCleanupForArray); } @@ -2496,9 +2528,9 @@ namespace { }; } // end anonymous namespace -/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy -/// already-constructed elements of the given array. The cleanup -/// may be popped with DeactivateCleanupBlock or PopCleanupBlock. +/// pushIrregularPartialArrayCleanup - Push a NormalAndEHCleanup to +/// destroy already-constructed elements of the given array. The cleanup may be +/// popped with DeactivateCleanupBlock or PopCleanupBlock. /// /// \param elementType - the immediate element type of the array; /// possibly still an array type @@ -2507,10 +2539,9 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin, QualType elementType, CharUnits elementAlign, Destroyer *destroyer) { - pushFullExprCleanup(EHCleanup, - arrayBegin, arrayEndPointer, - elementType, elementAlign, - destroyer); + pushFullExprCleanup( + NormalAndEHCleanup, arrayBegin, arrayEndPointer, elementType, + elementAlign, destroyer); } /// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 08e424e86e542..97ec887d2734f 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -116,10 +116,16 @@ RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, const Twine &Name, llvm::Value *ArraySize) { + llvm::AllocaInst *Alloca; if (ArraySize) - return Builder.CreateAlloca(Ty, ArraySize, Name); - return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(), - ArraySize, Name, AllocaInsertPt); + Alloca = Builder.CreateAlloca(Ty, ArraySize, Name); + else + Alloca = new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(), + ArraySize, Name, AllocaInsertPt); + if (Allocas) { + Allocas->Add(Alloca); + } + return Alloca; } /// CreateDefaultAlignTempAlloca - This creates an alloca with the @@ -1622,8 +1628,8 @@ LValue CodeGenFunction::EmitLValueHelper(const Expr *E, return EmitArraySubscriptExpr(cast(E)); case Expr::MatrixSubscriptExprClass: return EmitMatrixSubscriptExpr(cast(E)); - case Expr::OMPArraySectionExprClass: - return EmitOMPArraySectionExpr(cast(E)); + case Expr::ArraySectionExprClass: + return EmitArraySectionExpr(cast(E)); case Expr::ExtVectorElementExprClass: return EmitExtVectorElementExpr(cast(E)); case Expr::CXXThisExprClass: @@ -4399,8 +4405,8 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, QualType BaseTy, QualType ElTy, bool IsLowerBound) { LValue BaseLVal; - if (auto *ASE = dyn_cast(Base->IgnoreParenImpCasts())) { - BaseLVal = CGF.EmitOMPArraySectionExpr(ASE, IsLowerBound); + if (auto *ASE = dyn_cast(Base->IgnoreParenImpCasts())) { + BaseLVal = CGF.EmitArraySectionExpr(ASE, IsLowerBound); if (BaseTy->isArrayType()) { Address Addr = BaseLVal.getAddress(CGF); BaseInfo = BaseLVal.getBaseInfo(); @@ -4432,9 +4438,13 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo); } -LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, - bool IsLowerBound) { - QualType BaseTy = OMPArraySectionExpr::getBaseOriginalType(E->getBase()); +LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E, + bool IsLowerBound) { + + assert(!E->isOpenACCArraySection() && + "OpenACC Array section codegen not implemented"); + + QualType BaseTy = ArraySectionExpr::getBaseOriginalType(E->getBase()); QualType ResultExprTy; if (auto *AT = getContext().getAsArrayType(BaseTy)) ResultExprTy = AT->getElementType(); diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index fad8d405e95c4..8c1b92a3c6656 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -15,6 +15,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "EHScopeStack.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" @@ -24,6 +25,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" using namespace clang; @@ -557,24 +559,27 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, // For that, we'll need an EH cleanup. QualType::DestructionKind dtorKind = elementType.isDestructedType(); Address endOfInit = Address::invalid(); - EHScopeStack::stable_iterator cleanup; - llvm::Instruction *cleanupDominator = nullptr; - if (CGF.needsEHCleanup(dtorKind)) { + CodeGenFunction::CleanupDeactivationScope deactivation(CGF); + + if (dtorKind) { + CodeGenFunction::AllocaTrackerRAII allocaTracker(CGF); // In principle we could tell the cleanup where we are more // directly, but the control flow can get so varied here that it // would actually be quite complex. Therefore we go through an // alloca. + llvm::Instruction *dominatingIP = + Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(CGF.Int8PtrTy)); endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(), "arrayinit.endOfInit"); - cleanupDominator = Builder.CreateStore(begin, endOfInit); + Builder.CreateStore(begin, endOfInit); CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType, elementAlign, CGF.getDestroyer(dtorKind)); - cleanup = CGF.EHStack.stable_begin(); + cast(*CGF.EHStack.find(CGF.EHStack.stable_begin())) + .AddAuxAllocas(allocaTracker.Take()); - // Otherwise, remember that we didn't need a cleanup. - } else { - dtorKind = QualType::DK_none; + CGF.DeferredDeactivationCleanupStack.push_back( + {CGF.EHStack.stable_begin(), dominatingIP}); } llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1); @@ -670,9 +675,6 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, CGF.EmitBlock(endBB); } - - // Leave the partial-array cleanup if we entered one. - if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator); } //===----------------------------------------------------------------------===// @@ -1373,9 +1375,8 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType()); // We'll need to enter cleanup scopes in case any of the element - // initializers throws an exception. - SmallVector Cleanups; - llvm::Instruction *CleanupDominator = nullptr; + // initializers throws an exception or contains branch out of the expressions. + CodeGenFunction::CleanupDeactivationScope scope(CGF); CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin(); for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(), @@ -1394,28 +1395,12 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { if (QualType::DestructionKind DtorKind = CurField->getType().isDestructedType()) { assert(LV.isSimple()); - if (CGF.needsEHCleanup(DtorKind)) { - if (!CleanupDominator) - CleanupDominator = CGF.Builder.CreateAlignedLoad( - CGF.Int8Ty, - llvm::Constant::getNullValue(CGF.Int8PtrTy), - CharUnits::One()); // placeholder - - CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(), - CGF.getDestroyer(DtorKind), false); - Cleanups.push_back(CGF.EHStack.stable_begin()); - } + if (DtorKind) + CGF.pushDestroyAndDeferDeactivation( + NormalAndEHCleanup, LV.getAddress(CGF), CurField->getType(), + CGF.getDestroyer(DtorKind), false); } } - - // Deactivate all the partial cleanups in reverse order, which - // generally means popping them. - for (unsigned i = Cleanups.size(); i != 0; --i) - CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator); - - // Destroy the placeholder if we made one. - if (CleanupDominator) - CleanupDominator->eraseFromParent(); } void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) { @@ -1704,14 +1689,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // We'll need to enter cleanup scopes in case any of the element // initializers throws an exception. SmallVector cleanups; - llvm::Instruction *cleanupDominator = nullptr; - auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) { - cleanups.push_back(cleanup); - if (!cleanupDominator) // create placeholder once needed - cleanupDominator = CGF.Builder.CreateAlignedLoad( - CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy), - CharUnits::One()); - }; + CodeGenFunction::CleanupDeactivationScope DeactivateCleanups(CGF); unsigned curInitIndex = 0; @@ -1734,10 +1712,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot); if (QualType::DestructionKind dtorKind = - Base.getType().isDestructedType()) { - CGF.pushDestroy(dtorKind, V, Base.getType()); - addCleanup(CGF.EHStack.stable_begin()); - } + Base.getType().isDestructedType()) + CGF.pushDestroyAndDeferDeactivation(dtorKind, V, Base.getType()); } } @@ -1814,10 +1790,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( if (QualType::DestructionKind dtorKind = field->getType().isDestructedType()) { assert(LV.isSimple()); - if (CGF.needsEHCleanup(dtorKind)) { - CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(), - CGF.getDestroyer(dtorKind), false); - addCleanup(CGF.EHStack.stable_begin()); + if (dtorKind) { + CGF.pushDestroyAndDeferDeactivation( + NormalAndEHCleanup, LV.getAddress(CGF), field->getType(), + CGF.getDestroyer(dtorKind), false); pushedCleanup = true; } } @@ -1830,17 +1806,6 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( if (GEP->use_empty()) GEP->eraseFromParent(); } - - // Deactivate all the partial cleanups in reverse order, which - // generally means popping them. - assert((cleanupDominator || cleanups.empty()) && - "Missing cleanupDominator before deactivating cleanup blocks"); - for (unsigned i = cleanups.size(); i != 0; --i) - CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator); - - // Destroy the placeholder if we made one. - if (cleanupDominator) - cleanupDominator->eraseFromParent(); } void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 673ccef84d678..c18c36d3f3f32 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1008,8 +1008,8 @@ void CodeGenFunction::EmitNewArrayInitializer( const Expr *Init = E->getInitializer(); Address EndOfInit = Address::invalid(); QualType::DestructionKind DtorKind = ElementType.isDestructedType(); - EHScopeStack::stable_iterator Cleanup; - llvm::Instruction *CleanupDominator = nullptr; + CleanupDeactivationScope deactivation(*this); + bool pushedCleanup = false; CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType); CharUnits ElementAlign = @@ -1105,19 +1105,24 @@ void CodeGenFunction::EmitNewArrayInitializer( } // Enter a partial-destruction Cleanup if necessary. - if (needsEHCleanup(DtorKind)) { + if (DtorKind) { + AllocaTrackerRAII AllocaTracker(*this); // In principle we could tell the Cleanup where we are more // directly, but the control flow can get so varied here that it // would actually be quite complex. Therefore we go through an // alloca. + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy)); EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(), "array.init.end"); - CleanupDominator = - Builder.CreateStore(BeginPtr.emitRawPointer(*this), EndOfInit); pushIrregularPartialArrayCleanup(BeginPtr.emitRawPointer(*this), EndOfInit, ElementType, ElementAlign, getDestroyer(DtorKind)); - Cleanup = EHStack.stable_begin(); + cast(*EHStack.find(EHStack.stable_begin())) + .AddAuxAllocas(AllocaTracker.Take()); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); + pushedCleanup = true; } CharUnits StartAlign = CurPtr.getAlignment(); @@ -1164,9 +1169,6 @@ void CodeGenFunction::EmitNewArrayInitializer( // initialization. llvm::ConstantInt *ConstNum = dyn_cast(NumElements); if (ConstNum && ConstNum->getZExtValue() <= InitListElements) { - // If there was a Cleanup, deactivate it. - if (CleanupDominator) - DeactivateCleanupBlock(Cleanup, CleanupDominator); return; } @@ -1281,13 +1283,14 @@ void CodeGenFunction::EmitNewArrayInitializer( Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); // Enter a partial-destruction Cleanup if necessary. - if (!CleanupDominator && needsEHCleanup(DtorKind)) { - llvm::Value *BeginPtrRaw = BeginPtr.emitRawPointer(*this); - llvm::Value *CurPtrRaw = CurPtr.emitRawPointer(*this); - pushRegularPartialArrayCleanup(BeginPtrRaw, CurPtrRaw, ElementType, + if (!pushedCleanup && needsEHCleanup(DtorKind)) { + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy)); + pushRegularPartialArrayCleanup(BeginPtr.emitRawPointer(*this), + CurPtr.emitRawPointer(*this), ElementType, ElementAlign, getDestroyer(DtorKind)); - Cleanup = EHStack.stable_begin(); - CleanupDominator = Builder.CreateUnreachable(); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); } // Emit the initializer into this element. @@ -1295,10 +1298,7 @@ void CodeGenFunction::EmitNewArrayInitializer( AggValueSlot::DoesNotOverlap); // Leave the Cleanup if we entered one. - if (CleanupDominator) { - DeactivateCleanupBlock(Cleanup, CleanupDominator); - CleanupDominator->eraseFromParent(); - } + deactivation.ForceDeactivate(); // Advance to the next element by adjusting the pointer type as necessary. llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32( diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 3e544be7748a7..5ef68ece927ab 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2356,7 +2356,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } // Perform VLAT <-> VLST bitcast through memory. - // TODO: since the llvm.experimental.vector.{insert,extract} intrinsics + // TODO: since the llvm.vector.{insert,extract} intrinsics // require the element types of the vectors to be the same, we // need to keep this around for bitcasts between VLAT <-> VLST where // the element types of the vectors are not the same, until we figure diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp index 099f92c92a826..247a4141f2a09 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -896,8 +896,6 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, setPipelineDisabled(true); break; case LoopHintAttr::UnrollCount: - setUnrollState(LoopAttributes::Disable); - break; case LoopHintAttr::UnrollAndJamCount: case LoopHintAttr::VectorizeWidth: case LoopHintAttr::InterleaveCount: diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 4e7f777ba1d91..43dd38659518d 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -2905,23 +2905,29 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, break; case CodeGenOptions::Mixed: case CodeGenOptions::NonLegacy: + StringRef name = "objc_msgSend"; if (CGM.ReturnTypeUsesFPRet(ResultType)) { - imp = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), - "objc_msgSend_fpret") - .getCallee(); + name = "objc_msgSend_fpret"; } else if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) { - // The actual types here don't matter - we're going to bitcast the - // function anyway - imp = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), - "objc_msgSend_stret") - .getCallee(); - } else { - imp = CGM.CreateRuntimeFunction( - llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend") - .getCallee(); + name = "objc_msgSend_stret"; + + // The address of the memory block is be passed in x8 for POD type, + // or in x0 for non-POD type (marked as inreg). + bool shouldCheckForInReg = + CGM.getContext() + .getTargetInfo() + .getTriple() + .isWindowsMSVCEnvironment() && + CGM.getContext().getTargetInfo().getTriple().isAArch64(); + if (shouldCheckForInReg && CGM.ReturnTypeHasInReg(MSI.CallInfo)) { + name = "objc_msgSend_stret2"; + } } + // The actual types here don't matter - we're going to bitcast the + // function anyway + imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), + name) + .getCallee(); } // Reset the receiver in case the lookup modified it diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 28271160649af..436aa2b74464b 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -742,8 +742,8 @@ LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) { LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF, const Expr *E) { - if (const auto *OASE = dyn_cast(E)) - return CGF.EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false); + if (const auto *OASE = dyn_cast(E)) + return CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false); return LValue(); } @@ -800,7 +800,7 @@ void ReductionCodeGen::emitSharedOrigLValue(CodeGenFunction &CGF, unsigned N) { void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { QualType PrivateType = getPrivateType(N); - bool AsArraySection = isa(ClausesData[N].Ref); + bool AsArraySection = isa(ClausesData[N].Ref); if (!PrivateType->isVariablyModifiedType()) { Sizes.emplace_back( CGF.getTypeSize(OrigAddresses[N].first.getType().getNonReferenceType()), @@ -941,9 +941,9 @@ static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, static const VarDecl *getBaseDecl(const Expr *Ref, const DeclRefExpr *&DE) { const VarDecl *OrigVD = nullptr; - if (const auto *OASE = dyn_cast(Ref)) { + if (const auto *OASE = dyn_cast(Ref)) { const Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); - while (const auto *TempOASE = dyn_cast(Base)) + while (const auto *TempOASE = dyn_cast(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (const auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); @@ -3570,9 +3570,8 @@ getPointerAndSize(CodeGenFunction &CGF, const Expr *E) { SizeVal = CGF.Builder.CreateNUWMul(SizeVal, Sz); } } else if (const auto *ASE = - dyn_cast(E->IgnoreParenImpCasts())) { - LValue UpAddrLVal = - CGF.EmitOMPArraySectionExpr(ASE, /*IsLowerBound=*/false); + dyn_cast(E->IgnoreParenImpCasts())) { + LValue UpAddrLVal = CGF.EmitArraySectionExpr(ASE, /*IsLowerBound=*/false); Address UpAddrAddress = UpAddrLVal.getAddress(CGF); llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32( UpAddrAddress.getElementType(), UpAddrAddress.emitRawPointer(CGF), @@ -6674,8 +6673,8 @@ class MappableExprsHandler { // Given that an array section is considered a built-in type, we need to // do the calculation based on the length of the section instead of relying // on CGF.getTypeSize(E->getType()). - if (const auto *OAE = dyn_cast(E)) { - QualType BaseTy = OMPArraySectionExpr::getBaseOriginalType( + if (const auto *OAE = dyn_cast(E)) { + QualType BaseTy = ArraySectionExpr::getBaseOriginalType( OAE->getBase()->IgnoreParenImpCasts()) .getCanonicalType(); @@ -6781,7 +6780,7 @@ class MappableExprsHandler { /// Return true if the provided expression is a final array section. A /// final array section, is one whose length can't be proved to be one. bool isFinalArraySectionExpression(const Expr *E) const { - const auto *OASE = dyn_cast(E); + const auto *OASE = dyn_cast(E); // It is not an array section and therefore not a unity-size one. if (!OASE) @@ -6797,7 +6796,7 @@ class MappableExprsHandler { // for this dimension. Also, we should always expect a length if the // base type is pointer. if (!Length) { - QualType BaseQTy = OMPArraySectionExpr::getBaseOriginalType( + QualType BaseQTy = ArraySectionExpr::getBaseOriginalType( OASE->getBase()->IgnoreParenImpCasts()) .getCanonicalType(); if (const auto *ATy = dyn_cast(BaseQTy.getTypePtr())) @@ -7029,7 +7028,7 @@ class MappableExprsHandler { Address BP = Address::invalid(); const Expr *AssocExpr = I->getAssociatedExpression(); const auto *AE = dyn_cast(AssocExpr); - const auto *OASE = dyn_cast(AssocExpr); + const auto *OASE = dyn_cast(AssocExpr); const auto *OAShE = dyn_cast(AssocExpr); if (isa(AssocExpr)) { @@ -7181,14 +7180,14 @@ class MappableExprsHandler { // special treatment for array sections given that they are built-in // types. const auto *OASE = - dyn_cast(I->getAssociatedExpression()); + dyn_cast(I->getAssociatedExpression()); const auto *OAShE = dyn_cast(I->getAssociatedExpression()); const auto *UO = dyn_cast(I->getAssociatedExpression()); const auto *BO = dyn_cast(I->getAssociatedExpression()); bool IsPointer = OAShE || - (OASE && OMPArraySectionExpr::getBaseOriginalType(OASE) + (OASE && ArraySectionExpr::getBaseOriginalType(OASE) .getCanonicalType() ->isAnyPointerType()) || I->getAssociatedExpression()->getType()->isAnyPointerType(); @@ -7209,7 +7208,7 @@ class MappableExprsHandler { assert((Next == CE || isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression()) || - isa(Next->getAssociatedExpression()) || + isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression())) && @@ -7441,7 +7440,7 @@ class MappableExprsHandler { PartialStruct.LowestElem = {FieldIndex, LowestElem}; if (IsFinalArraySection) { Address HB = - CGF.EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false) + CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false) .getAddress(CGF); PartialStruct.HighestElem = {FieldIndex, HB}; } else { @@ -7454,7 +7453,7 @@ class MappableExprsHandler { } else if (FieldIndex > PartialStruct.HighestElem.first) { if (IsFinalArraySection) { Address HB = - CGF.EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false) + CGF.EmitArraySectionExpr(OASE, /*IsLowerBound=*/false) .getAddress(CGF); PartialStruct.HighestElem = {FieldIndex, HB}; } else { @@ -7512,12 +7511,12 @@ class MappableExprsHandler { for (const OMPClauseMappableExprCommon::MappableComponent &Component : Components) { const Expr *AssocExpr = Component.getAssociatedExpression(); - const auto *OASE = dyn_cast(AssocExpr); + const auto *OASE = dyn_cast(AssocExpr); if (!OASE) continue; - QualType Ty = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + QualType Ty = ArraySectionExpr::getBaseOriginalType(OASE->getBase()); auto *CAT = Context.getAsConstantArrayType(Ty); auto *VAT = Context.getAsVariableArrayType(Ty); @@ -7591,7 +7590,7 @@ class MappableExprsHandler { continue; } - const auto *OASE = dyn_cast(AssocExpr); + const auto *OASE = dyn_cast(AssocExpr); if (!OASE) continue; @@ -8782,7 +8781,7 @@ static ValueDecl *getDeclFromThisExpr(const Expr *E) { if (!E) return nullptr; - if (const auto *OASE = dyn_cast(E->IgnoreParenCasts())) + if (const auto *OASE = dyn_cast(E->IgnoreParenCasts())) if (const MemberExpr *ME = dyn_cast(OASE->getBase()->IgnoreParenImpCasts())) return ME->getMemberDecl(); diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index eb716520e5ff5..87496c8e488c6 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -92,9 +92,9 @@ static const ValueDecl *getPrivateItem(const Expr *RefExpr) { while (const auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); RefExpr = Base; - } else if (auto *OASE = dyn_cast(RefExpr)) { + } else if (auto *OASE = dyn_cast(RefExpr)) { const Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); - while (const auto *TempOASE = dyn_cast(Base)) + while (const auto *TempOASE = dyn_cast(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (const auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index c294b6e69ace3..4a7a7ca07a9ca 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1256,7 +1256,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit( const auto *LHSVD = cast(cast(*ILHS)->getDecl()); const auto *RHSVD = cast(cast(*IRHS)->getDecl()); QualType Type = PrivateVD->getType(); - bool isaOMPArraySectionExpr = isa(IRef); + bool isaOMPArraySectionExpr = isa(IRef); if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) { // Store the address of the original variable associated with the LHS // implicit variable. @@ -7289,7 +7289,7 @@ void CodeGenFunction::EmitOMPUseDevicePtrClause( static const VarDecl *getBaseDecl(const Expr *Ref) { const Expr *Base = Ref->IgnoreParenImpCasts(); - while (const auto *OASE = dyn_cast(Base)) + while (const auto *OASE = dyn_cast(Base)) Base = OASE->getBase()->IgnoreParenImpCasts(); while (const auto *ASE = dyn_cast(Base)) Base = ASE->getBase()->IgnoreParenImpCasts(); diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 40e7094f762f5..567bbb5d3aa33 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -145,6 +145,9 @@ add_clang_library(clangCodeGen ${codegen_deps} intrinsics_gen ClangDriverOptions + # These generated headers are included transitively. + ARMTargetParserTableGen + AArch64TargetParserTableGen LINK_LIBS clangAST diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 4befefcad187c..2f718da9693e7 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -93,6 +93,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) CodeGenFunction::~CodeGenFunction() { assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup"); + assert(DeferredDeactivationCleanupStack.empty() && + "missed to deactivate a cleanup"); if (getLangOpts().OpenMP && CurFn) CGM.getOpenMPRuntime().functionFinished(*this); @@ -348,6 +350,10 @@ static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) { void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { assert(BreakContinueStack.empty() && "mismatched push/pop in break/continue stack!"); + assert(LifetimeExtendedCleanupStack.empty() && + "mismatched push/pop of cleanups in EHStack!"); + assert(DeferredDeactivationCleanupStack.empty() && + "mismatched activate/deactivate of cleanups!"); bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0 && NumSimpleReturnExprs == NumReturnExprs diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b5d173086e62d..99177f8990f53 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -39,6 +39,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/SanitizerStats.h" @@ -670,6 +671,51 @@ class CodeGenFunction : public CodeGenTypeCache { EHScopeStack EHStack; llvm::SmallVector LifetimeExtendedCleanupStack; + + // A stack of cleanups which were added to EHStack but have to be deactivated + // later before being popped or emitted. These are usually deactivated on + // exiting a `CleanupDeactivationScope` scope. For instance, after a + // full-expr. + // + // These are specially useful for correctly emitting cleanups while + // encountering branches out of expression (through stmt-expr or coroutine + // suspensions). + struct DeferredDeactivateCleanup { + EHScopeStack::stable_iterator Cleanup; + llvm::Instruction *DominatingIP; + }; + llvm::SmallVector DeferredDeactivationCleanupStack; + + // Enters a new scope for capturing cleanups which are deferred to be + // deactivated, all of which will be deactivated once the scope is exited. + struct CleanupDeactivationScope { + CodeGenFunction &CGF; + size_t OldDeactivateCleanupStackSize; + bool Deactivated; + CleanupDeactivationScope(CodeGenFunction &CGF) + : CGF(CGF), OldDeactivateCleanupStackSize( + CGF.DeferredDeactivationCleanupStack.size()), + Deactivated(false) {} + + void ForceDeactivate() { + assert(!Deactivated && "Deactivating already deactivated scope"); + auto &Stack = CGF.DeferredDeactivationCleanupStack; + for (size_t I = Stack.size(); I > OldDeactivateCleanupStackSize; I--) { + CGF.DeactivateCleanupBlock(Stack[I - 1].Cleanup, + Stack[I - 1].DominatingIP); + Stack[I - 1].DominatingIP->eraseFromParent(); + } + Stack.resize(OldDeactivateCleanupStackSize); + Deactivated = true; + } + + ~CleanupDeactivationScope() { + if (Deactivated) + return; + ForceDeactivate(); + } + }; + llvm::SmallVector SEHTryEpilogueStack; llvm::Instruction *CurrentFuncletPad = nullptr; @@ -875,6 +921,19 @@ class CodeGenFunction : public CodeGenTypeCache { new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag); } + // Push a cleanup onto EHStack and deactivate it later. It is usually + // deactivated when exiting a `CleanupDeactivationScope` (for example: after a + // full expression). + template + void pushCleanupAndDeferDeactivation(CleanupKind Kind, As... A) { + // Placeholder dominating IP for this cleanup. + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy)); + EHStack.pushCleanup(Kind, A...); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); + } + /// Set up the last cleanup that was pushed as a conditional /// full-expression cleanup. void initFullExprCleanup() { @@ -898,7 +957,8 @@ class CodeGenFunction : public CodeGenTypeCache { /// PopCleanupBlock - Will pop the cleanup entry on the stack and /// process all branch fixups. - void PopCleanupBlock(bool FallThroughIsBranchThrough = false); + void PopCleanupBlock(bool FallThroughIsBranchThrough = false, + bool ForDeactivation = false); /// DeactivateCleanupBlock - Deactivates the given cleanup block. /// The block cannot be reactivated. Pops it if it's the top of the @@ -926,6 +986,7 @@ class CodeGenFunction : public CodeGenTypeCache { class RunCleanupsScope { EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth; size_t LifetimeExtendedCleanupStackSize; + CleanupDeactivationScope DeactivateCleanups; bool OldDidCallStackSave; protected: bool PerformCleanup; @@ -940,8 +1001,7 @@ class CodeGenFunction : public CodeGenTypeCache { public: /// Enter a new cleanup scope. explicit RunCleanupsScope(CodeGenFunction &CGF) - : PerformCleanup(true), CGF(CGF) - { + : DeactivateCleanups(CGF), PerformCleanup(true), CGF(CGF) { CleanupStackDepth = CGF.EHStack.stable_begin(); LifetimeExtendedCleanupStackSize = CGF.LifetimeExtendedCleanupStack.size(); @@ -971,6 +1031,7 @@ class CodeGenFunction : public CodeGenTypeCache { void ForceCleanup(std::initializer_list ValuesToReload = {}) { assert(PerformCleanup && "Already forced cleanup"); CGF.DidCallStackSave = OldDidCallStackSave; + DeactivateCleanups.ForceDeactivate(); CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize, ValuesToReload); PerformCleanup = false; @@ -2182,6 +2243,11 @@ class CodeGenFunction : public CodeGenTypeCache { Address addr, QualType type); void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); + void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind, + Address addr, QualType type); + void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr, + QualType type, Destroyer *destroyer, + bool useEHCleanupForArray); void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); @@ -2720,6 +2786,33 @@ class CodeGenFunction : public CodeGenTypeCache { TBAAAccessInfo *TBAAInfo = nullptr); LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy); +private: + struct AllocaTracker { + void Add(llvm::AllocaInst *I) { Allocas.push_back(I); } + llvm::SmallVector Take() { return std::move(Allocas); } + + private: + llvm::SmallVector Allocas; + }; + AllocaTracker *Allocas = nullptr; + +public: + // Captures all the allocas created during the scope of its RAII object. + struct AllocaTrackerRAII { + AllocaTrackerRAII(CodeGenFunction &CGF) + : CGF(CGF), OldTracker(CGF.Allocas) { + CGF.Allocas = &Tracker; + } + ~AllocaTrackerRAII() { CGF.Allocas = OldTracker; } + + llvm::SmallVector Take() { return Tracker.Take(); } + + private: + CodeGenFunction &CGF; + AllocaTracker *OldTracker; + AllocaTracker Tracker; + }; + /// CreateTempAlloca - This creates an alloca and inserts it into the entry /// block if \p ArraySize is nullptr, otherwise inserts it at the current /// insertion point of the builder. The caller is responsible for setting an @@ -3226,12 +3319,12 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *Index, QualType IndexType, QualType IndexedType, bool Accessed); - // Find a struct's flexible array member. It may be embedded inside multiple - // sub-structs, but must still be the last field. - const FieldDecl *FindFlexibleArrayMemberField(ASTContext &Ctx, - const RecordDecl *RD, - StringRef Name, - uint64_t &Offset); + // Find a struct's flexible array member and get its offset. It may be + // embedded inside multiple sub-structs, but must still be the last field. + const FieldDecl * + FindFlexibleArrayMemberFieldAndOffset(ASTContext &Ctx, const RecordDecl *RD, + const FieldDecl *FAMDecl, + uint64_t &Offset); /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns /// \p nullptr if either the attribute or the field doesn't exist. @@ -4191,8 +4284,8 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed = false); LValue EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E); - LValue EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, - bool IsLowerBound = true); + LValue EmitArraySectionExpr(const ArraySectionExpr *E, + bool IsLowerBound = true); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 33d94f72636fc..de28b471e7326 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -76,6 +76,7 @@ #include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/Triple.h" #include "llvm/TargetParser/X86TargetParser.h" +#include "llvm/Transforms/Utils/BuildLibCalls.h" #include using namespace clang; @@ -458,6 +459,11 @@ CodeGenModule::CodeGenModule(ASTContext &C, } ModuleNameHash = llvm::getUniqueInternalLinkagePostfix(Path); } + + // Record mregparm value now so it is visible through all of codegen. + if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) + getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters", + CodeGenOpts.NumRegisterParameters); } CodeGenModule::~CodeGenModule() {} @@ -1024,11 +1030,6 @@ void CodeGenModule::Release() { NMD->addOperand(MD); } - // Record mregparm value now so it is visible through rest of codegen. - if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) - getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters", - CodeGenOpts.NumRegisterParameters); - if (CodeGenOpts.DwarfVersion) { getModule().addModuleFlag(llvm::Module::Max, "Dwarf Version", CodeGenOpts.DwarfVersion); @@ -5213,6 +5214,10 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, } } setDSOLocal(F); + // FIXME: We should use CodeGenModule::SetLLVMFunctionAttributes() instead + // of trying to approximate the attributes using the LLVM function + // signature. This requires revising the API of CreateRuntimeFunction(). + markRegisterParameterAttributes(F); } } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e5f4949599135..c14a963e03c5b 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1272,6 +1272,9 @@ class CodeGenModule : public CodeGenTypeCache { /// Return true iff the given type uses 'sret' when used as a return type. bool ReturnTypeUsesSRet(const CGFunctionInfo &FI); + /// Return true iff the given type has `inreg` set. + bool ReturnTypeHasInReg(const CGFunctionInfo &FI); + /// Return true iff the given type uses an argument slot when 'sret' is used /// as a return type. bool ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 4fbc08f64dc85..279402a845de2 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -486,7 +486,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { break; case BuiltinType::LongDouble: LongDoubleReferenced = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case BuiltinType::BFloat16: case BuiltinType::Float: case BuiltinType::Double: diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index ca00324949f09..dbedd5995c61a 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1132,9 +1132,15 @@ static bool isTrivialForMSVC(const CXXRecordDecl *RD, QualType Ty, return false; if (RD->hasNonTrivialCopyAssignment()) return false; - for (const CXXConstructorDecl *Ctor : RD->ctors()) - if (Ctor->isUserProvided()) - return false; + for (const Decl *D : RD->decls()) { + if (auto *Ctor = dyn_cast(D)) { + if (Ctor->isUserProvided()) + return false; + } else if (auto *Template = dyn_cast(D)) { + if (isa(Template->getTemplatedDecl())) + return false; + } + } if (RD->hasNonTrivialDestructor()) return false; return true; diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 94400f08154a2..6d6bd71cba9b5 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -99,6 +99,9 @@ add_clang_library(clangDriver DEPENDS ClangDriverOptions DeviceConfigFile + # These generated headers are included transitively. + ARMTargetParserTableGen + AArch64TargetParserTableGen LINK_LIBS clangBasic diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 1a1d4db9a1e46..b6e0fa33dd9f5 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -382,6 +382,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || + (PhaseArg = DAL.getLastArg(options::OPT_emit_cir)) || (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; @@ -8100,6 +8101,8 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction(Input, types::TY_Remap); if (Args.hasArg(options::OPT_emit_ast)) return C.MakeAction(Input, types::TY_AST); + if (Args.hasArg(options::OPT_emit_cir)) + return C.MakeAction(Input, types::TY_CIR); if (Args.hasArg(options::OPT_module_file_info)) return C.MakeAction(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 5948bc34d61d1..90c0c9cb24652 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1385,19 +1385,35 @@ void ToolChain::AddCCKextLibArgs(const ArgList &Args, bool ToolChain::isFastMathRuntimeAvailable(const ArgList &Args, std::string &Path) const { + // Don't implicitly link in mode-changing libraries in a shared library, since + // this can have very deleterious effects. See the various links from + // https://github.com/llvm/llvm-project/issues/57589 for more information. + bool Default = !Args.hasArgNoClaim(options::OPT_shared); + // Do not check for -fno-fast-math or -fno-unsafe-math when -Ofast passed // (to keep the linker options consistent with gcc and clang itself). - if (!isOptimizationLevelFast(Args)) { + if (Default && !isOptimizationLevelFast(Args)) { // Check if -ffast-math or -funsafe-math. - Arg *A = - Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math, - options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations); + Arg *A = Args.getLastArg( + options::OPT_ffast_math, options::OPT_fno_fast_math, + options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, options::OPT_ffp_model_EQ); if (!A || A->getOption().getID() == options::OPT_fno_fast_math || A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations) - return false; + Default = false; + if (A && A->getOption().getID() == options::OPT_ffp_model_EQ) { + StringRef Model = A->getValue(); + if (Model != "fast") + Default = false; + } } + + // Whatever decision came as a result of the above implicit settings, either + // -mdaz-ftz or -mno-daz-ftz is capable of overriding it. + if (!Args.hasFlag(options::OPT_mdaz_ftz, options::OPT_mno_daz_ftz, Default)) + return false; + // If crtfastmath.o exists add it to the arguments. Path = GetFilePath("crtfastmath.o"); return (Path != "crtfastmath.o"); // Not found. diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index c1b350893b374..aab98506adb96 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -376,9 +376,7 @@ void AIX::AddOpenMPIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, PathOpenMP.str()); break; case Driver::OMPRT_IOMP5: - LLVM_FALLTHROUGH; case Driver::OMPRT_GOMP: - LLVM_FALLTHROUGH; case Driver::OMPRT_Unknown: // Unknown / unsupported include paths. break; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6fc3101a9d415..e079b1e5aa53a 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -869,46 +869,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } } -/// Check whether the given input tree contains any compilation actions. -static bool ContainsCompileAction(const Action *A) { - if (isa(A) || isa(A)) - return true; - - return llvm::any_of(A->inputs(), ContainsCompileAction); -} - -/// Check if -relax-all should be passed to the internal assembler. -/// This is done by default when compiling non-assembler source with -O0. -static bool UseRelaxAll(Compilation &C, const ArgList &Args) { - bool RelaxDefault = true; - - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - RelaxDefault = A->getOption().matches(options::OPT_O0); - - // RISC-V requires an indirect jump for offsets larger than 1MiB. This cannot - // be done by assembler branch relaxation as it needs a free temporary - // register. Because of this, branch relaxation is handled by a MachineIR - // pass before the assembler. Forcing assembler branch relaxation for -O0 - // makes the MachineIR branch relaxation inaccurate and it will miss cases - // where an indirect branch is necessary. To avoid this issue we are - // sacrificing the compile time improvement of using -mrelax-all for -O0. - if (C.getDefaultToolChain().getTriple().isRISCV()) - RelaxDefault = false; - - if (RelaxDefault) { - RelaxDefault = false; - for (const auto &Act : C.getActions()) { - if (ContainsCompileAction(Act)) { - RelaxDefault = true; - break; - } - } - } - - return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, - RelaxDefault); -} - static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, llvm::codegenoptions::DebugInfoKind DebugInfoKind, @@ -2604,8 +2564,16 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, const Driver &D) { - if (UseRelaxAll(C, Args)) - CmdArgs.push_back("-mrelax-all"); + // Default to -mno-relax-all. + // + // Note: RISC-V requires an indirect jump for offsets larger than 1MiB. This + // cannot be done by assembler branch relaxation as it needs a free temporary + // register. Because of this, branch relaxation is handled by a MachineIR pass + // before the assembler. Forcing assembler branch relaxation for -O0 makes the + // MachineIR branch relaxation inaccurate and it will miss cases where an + // indirect branch is necessary. + Args.addOptInFlag(CmdArgs, options::OPT_mrelax_all, + options::OPT_mno_relax_all); // Only default to -mincremental-linker-compatible if we think we are // targeting the MSVC linker. @@ -2907,13 +2875,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, StringRef FPExceptionBehavior = ""; // -ffp-eval-method options: double, extended, source StringRef FPEvalMethod = ""; - const llvm::DenormalMode DefaultDenormalFPMath = + llvm::DenormalMode DenormalFPMath = TC.getDefaultDenormalModeForType(Args, JA); - const llvm::DenormalMode DefaultDenormalFP32Math = + llvm::DenormalMode DenormalFP32Math = TC.getDefaultDenormalModeForType(Args, JA, &llvm::APFloat::IEEEsingle()); - llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath; - llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math; // CUDA and HIP don't rely on the frontend to pass an ffp-contract option. // If one wasn't given by the user, don't pass it here. StringRef FPContract; @@ -3071,11 +3037,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, SignedZeros = true; // -fno_fast_math restores default denormal and fpcontract handling FPContract = "on"; - DenormalFPMath = llvm::DenormalMode::getIEEE(); - - // FIXME: The target may have picked a non-IEEE default mode here based on - // -cl-denorms-are-zero. Should the target consider -fp-model interaction? - DenormalFP32Math = llvm::DenormalMode::getIEEE(); StringRef Val = A->getValue(); if (OFastEnabled && !Val.equals("fast")) { @@ -3296,12 +3257,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = false; SignedZeros = true; ApproxFunc = false; - TrappingMath = true; - FPExceptionBehavior = "strict"; - // The target may have opted to flush by default, so force IEEE. - DenormalFPMath = llvm::DenormalMode::getIEEE(); - DenormalFP32Math = llvm::DenormalMode::getIEEE(); if (!JA.isDeviceOffloading(Action::OFK_Cuda) && !JA.isOffloading(Action::OFK_HIP)) { if (LastSeenFfpContractOption != "") { @@ -3332,9 +3288,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = false; ApproxFunc = false; SignedZeros = true; - // -fno_fast_math restores default denormal and fpcontract handling - DenormalFPMath = DefaultDenormalFPMath; - DenormalFP32Math = llvm::DenormalMode::getIEEE(); + // -fno_fast_math restores default fpcontract handling if (!JA.isDeviceOffloading(Action::OFK_Cuda) && !JA.isOffloading(Action::OFK_HIP)) { if (LastSeenFfpContractOption != "") { @@ -3349,8 +3303,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // subsequent options conflict then emit warning diagnostic. if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath && SignedZeros && TrappingMath && RoundingFPMath && !ApproxFunc && - DenormalFPMath == llvm::DenormalMode::getIEEE() && - DenormalFP32Math == llvm::DenormalMode::getIEEE() && FPContract.equals("off")) // OK: Current Arg doesn't conflict with -ffp-model=strict ; @@ -8329,6 +8281,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions, options::OPT_fno_safe_buffer_usage_suggestions); + Args.addOptInFlag(CmdArgs, options::OPT_fexperimental_late_parse_attributes, + options::OPT_fno_experimental_late_parse_attributes); + // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index fdaf8be1c725c..7da71f3102e4a 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -745,7 +745,7 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC, StringRef V = A->getValue(); bool SupportedArgument = false, EnableTLSDESC = false; bool Unsupported = !Triple.isOSBinFormatELF(); - if (Triple.isRISCV()) { + if (Triple.isLoongArch() || Triple.isRISCV()) { SupportedArgument = V == "desc" || V == "trad"; EnableTLSDESC = V == "desc"; } else if (Triple.isX86()) { @@ -1197,118 +1197,10 @@ bool tools::addOpenMPRuntime(const Compilation &C, ArgStringList &CmdArgs, return true; } -/// Determines if --whole-archive is active in the list of arguments. -static bool isWholeArchivePresent(const ArgList &Args) { - bool WholeArchiveActive = false; - for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA)) { - if (Arg) { - for (StringRef ArgValue : Arg->getValues()) { - if (ArgValue == "--whole-archive") - WholeArchiveActive = true; - if (ArgValue == "--no-whole-archive") - WholeArchiveActive = false; - } - } - } - - return WholeArchiveActive; -} - -/// Determine if driver is invoked to create a shared object library (-static) -static bool isSharedLinkage(const ArgList &Args) { - return Args.hasArg(options::OPT_shared); -} - -/// Determine if driver is invoked to create a static object library (-shared) -static bool isStaticLinkage(const ArgList &Args) { - return Args.hasArg(options::OPT_static); -} - -/// Add Fortran runtime libs for MSVC -static void addFortranRuntimeLibsMSVC(const ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) { - unsigned RTOptionID = options::OPT__SLASH_MT; - if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { - RTOptionID = llvm::StringSwitch(rtl->getValue()) - .Case("static", options::OPT__SLASH_MT) - .Case("static_dbg", options::OPT__SLASH_MTd) - .Case("dll", options::OPT__SLASH_MD) - .Case("dll_dbg", options::OPT__SLASH_MDd) - .Default(options::OPT__SLASH_MT); - } - switch (RTOptionID) { - case options::OPT__SLASH_MT: - CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib"); - break; - case options::OPT__SLASH_MTd: - CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib"); - break; - case options::OPT__SLASH_MD: - CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib"); - break; - case options::OPT__SLASH_MDd: - CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib"); - break; - } -} - -// Add FortranMain runtime lib -static void addFortranMain(const ToolChain &TC, const ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) { - // 0. Shared-library linkage - // If we are attempting to link a library, we should not add - // -lFortran_main.a to the link line, as the `main` symbol is not - // required for a library and should also be provided by one of - // the translation units of the code that this shared library - // will be linked against eventually. - if (isSharedLinkage(Args) || isStaticLinkage(Args)) { - return; - } - - // 1. MSVC - if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { - addFortranRuntimeLibsMSVC(Args, CmdArgs); - return; - } - - // 2. GNU and similar - const Driver &D = TC.getDriver(); - const char *FortranMainLinkFlag = "-lFortran_main"; - - // Warn if the user added `-lFortran_main` - this library is an implementation - // detail of Flang and should be handled automaticaly by the driver. - for (const char *arg : CmdArgs) { - if (strncmp(arg, FortranMainLinkFlag, strlen(FortranMainLinkFlag)) == 0) - D.Diag(diag::warn_drv_deprecated_custom) - << FortranMainLinkFlag - << "see the Flang driver documentation for correct usage"; - } - - // The --whole-archive option needs to be part of the link line to make - // sure that the main() function from Fortran_main.a is pulled in by the - // linker. However, it shouldn't be used if it's already active. - // TODO: Find an equivalent of `--whole-archive` for Darwin and AIX. - if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX() && - !TC.getTriple().isOSAIX()) { - CmdArgs.push_back("--whole-archive"); - CmdArgs.push_back(FortranMainLinkFlag); - CmdArgs.push_back("--no-whole-archive"); - return; - } - - CmdArgs.push_back(FortranMainLinkFlag); -} - /// Add Fortran runtime libs void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args, llvm::opt::ArgStringList &CmdArgs) { - // 1. Link FortranMain - // FortranMain depends on FortranRuntime, so needs to be listed first. If - // -fno-fortran-main has been passed, skip linking Fortran_main.a - if (!Args.hasArg(options::OPT_no_fortran_main)) - addFortranMain(TC, Args, CmdArgs); - - // 2. Link FortranRuntime and FortranDecimal + // Link FortranRuntime and FortranDecimal // These are handled earlier on Windows by telling the frontend driver to // add the correct libraries to link against as dependents in the object // file. diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 6d93c1f3d7034..8955b9fb653c2 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -282,7 +282,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && "can only add VS runtime library on Windows!"); // if -fno-fortran-main has been passed, skip linking Fortran_main.a - bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main); if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { CmdArgs.push_back(Args.MakeArgString( "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); @@ -300,8 +299,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, case options::OPT__SLASH_MT: CmdArgs.push_back("-D_MT"); CmdArgs.push_back("--dependent-lib=libcmt"); - if (LinkFortranMain) - CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib"); CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); break; @@ -309,8 +306,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-D_MT"); CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("--dependent-lib=libcmtd"); - if (LinkFortranMain) - CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib"); CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); break; @@ -318,8 +313,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-D_MT"); CmdArgs.push_back("-D_DLL"); CmdArgs.push_back("--dependent-lib=msvcrt"); - if (LinkFortranMain) - CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib"); CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); break; @@ -328,8 +321,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_DLL"); CmdArgs.push_back("--dependent-lib=msvcrtd"); - if (LinkFortranMain) - CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib"); CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); break; diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 2e0c371dc9778..7b94dedd43b07 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1935,9 +1935,7 @@ selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch, } auto &MLConfigISAInfo = *MLConfigParseResult; - const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts = - MLConfigISAInfo->getExtensions(); - for (auto MLConfigArchExt : MLConfigArchExts) { + for (auto &MLConfigArchExt : MLConfigISAInfo->getExtensions()) { auto ExtName = MLConfigArchExt.first; NewMultilib.flag(Twine("-", ExtName).str()); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index dda4c9d517e5f..254f8171ca359 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -855,25 +855,6 @@ void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, ToolChain::addProfileRTLibs(Args, CmdArgs); } -llvm::DenormalMode -Linux::getDefaultDenormalModeForType(const llvm::opt::ArgList &DriverArgs, - const JobAction &JA, - const llvm::fltSemantics *FPType) const { - switch (getTriple().getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: { - std::string Unused; - // DAZ and FTZ are turned on in crtfastmath.o - if (!DriverArgs.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && - isFastMathRuntimeAvailable(DriverArgs, Unused)) - return llvm::DenormalMode::getPreserveSign(); - return llvm::DenormalMode::getIEEE(); - } - default: - return llvm::DenormalMode::getIEEE(); - } -} - void Linux::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { for (const auto &Opt : ExtraOpts) CmdArgs.push_back(Opt.c_str()); diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index 524391743090b..2d9e674e50a63 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -59,10 +59,6 @@ class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { std::vector ExtraOpts; - llvm::DenormalMode getDefaultDenormalModeForType( - const llvm::opt::ArgList &DriverArgs, const JobAction &JA, - const llvm::fltSemantics *FPType = nullptr) const override; - const char *getDefaultLinker() const override; protected: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index ccb2c9190e2ef..c8d8ec3afbd99 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -807,7 +807,6 @@ template <> struct MappingTraits { FormatStyle PredefinedStyle; if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) && Style == PredefinedStyle) { - IO.mapOptional("# BasedOnStyle", StyleName); BasedOnStyle = StyleName; break; } @@ -3117,6 +3116,7 @@ static void sortCppIncludes(const FormatStyle &Style, return; } + const auto OldCursor = Cursor ? *Cursor : 0; std::string result; for (unsigned Index : Indices) { if (!result.empty()) { @@ -3140,6 +3140,8 @@ static void sortCppIncludes(const FormatStyle &Style, // the entire range of blocks. Otherwise, no replacement is generated. if (replaceCRLF(result) == replaceCRLF(std::string(Code.substr( IncludesBeginOffset, IncludesBlockSize)))) { + if (Cursor) + *Cursor = OldCursor; return; } diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index f651e6228c206..28b6488e54a42 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -1623,10 +1623,10 @@ struct AdditionalKeywords { IdentifierInfo *kw_then; /// Returns \c true if \p Tok is a keyword or an identifier. - bool isWordLike(const FormatToken &Tok) const { + bool isWordLike(const FormatToken &Tok, bool IsVerilog = true) const { // getIdentifierinfo returns non-null for keywords as well as identifiers. return Tok.Tok.getIdentifierInfo() && - !Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe); + (!IsVerilog || !isVerilogKeywordSymbol(Tok)); } /// Returns \c true if \p Tok is a true JavaScript identifier, returns @@ -1755,6 +1755,10 @@ struct AdditionalKeywords { } } + bool isVerilogKeywordSymbol(const FormatToken &Tok) const { + return Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe); + } + bool isVerilogWordOperator(const FormatToken &Tok) const { return Tok.isOneOf(kw_before, kw_intersect, kw_dist, kw_iff, kw_inside, kw_with); diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index cdfb4256e41d9..d366ae2080bc2 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -4780,9 +4780,14 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.Finalized) return Right.hasWhitespaceBefore(); + const bool IsVerilog = Style.isVerilog(); + assert(!IsVerilog || !IsCpp); + // Never ever merge two words. - if (Keywords.isWordLike(Right) && Keywords.isWordLike(Left)) + if (Keywords.isWordLike(Right, IsVerilog) && + Keywords.isWordLike(Left, IsVerilog)) { return true; + } // Leave a space between * and /* to avoid C4138 `comment end` found outside // of comment. @@ -4834,10 +4839,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_TemplateOpener)) { return true; } - if (Left.is(tok::identifier) && Right.is(tok::numeric_constant) && - Right.TokenText[0] == '.') { - return false; - } + if (Left.Tok.getIdentifierInfo() && Right.is(tok::numeric_constant)) + return Right.TokenText[0] != '.'; } else if (Style.isProto()) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, @@ -5065,12 +5068,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_TemplateOpener)) { return true; } - } else if (Style.isVerilog()) { + } else if (IsVerilog) { // An escaped identifier ends with whitespace. - if (Style.isVerilog() && Left.is(tok::identifier) && - Left.TokenText[0] == '\\') { + if (Left.is(tok::identifier) && Left.TokenText[0] == '\\') return true; - } // Add space between things in a primitive's state table unless in a // transition like `(0?)`. if ((Left.is(TT_VerilogTableItem) && @@ -5266,21 +5267,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } if (Left.is(TT_UnaryOperator)) { - if (Right.isNot(tok::l_paren)) { - // The alternative operators for ~ and ! are "compl" and "not". - // If they are used instead, we do not want to combine them with - // the token to the right, unless that is a left paren. - if (Left.is(tok::exclaim) && Left.TokenText == "not") - return true; - if (Left.is(tok::tilde) && Left.TokenText == "compl") - return true; - // Lambda captures allow for a lone &, so "&]" needs to be properly - // handled. - if (Left.is(tok::amp) && Right.is(tok::r_square)) - return Style.SpacesInSquareBrackets; - } - return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || - Right.is(TT_BinaryOperator); + // Lambda captures allow for a lone &, so "&]" needs to be properly + // handled. + if (Left.is(tok::amp) && Right.is(tok::r_square)) + return Style.SpacesInSquareBrackets; + return Style.SpaceAfterLogicalNot && Left.is(tok::exclaim); } // If the next token is a binary operator or a selector name, we have diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 6e4e6901e473f..854428389740d 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -534,11 +534,11 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { case tok::r_brace: if (LBraceStack.empty()) break; - if (LBraceStack.back().Tok->is(BK_Unknown)) { + if (auto *LBrace = LBraceStack.back().Tok; LBrace->is(BK_Unknown)) { bool ProbablyBracedList = false; if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); - } else { + } else if (LBrace->isNot(TT_EnumLBrace)) { // Using OriginalColumn to distinguish between ObjC methods and // binary operators is a bit hacky. bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && @@ -552,7 +552,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // If we already marked the opening brace as braced list, the closing // must also be part of it. - ProbablyBracedList = LBraceStack.back().Tok->is(TT_BracedListLBrace); + ProbablyBracedList = LBrace->is(TT_BracedListLBrace); ProbablyBracedList = ProbablyBracedList || (Style.isJavaScript() && @@ -608,13 +608,9 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { ProbablyBracedList = true; } } - if (ProbablyBracedList) { - Tok->setBlockKind(BK_BracedInit); - LBraceStack.back().Tok->setBlockKind(BK_BracedInit); - } else { - Tok->setBlockKind(BK_Block); - LBraceStack.back().Tok->setBlockKind(BK_Block); - } + const auto BlockKind = ProbablyBracedList ? BK_BracedInit : BK_Block; + Tok->setBlockKind(BlockKind); + LBrace->setBlockKind(BlockKind); } LBraceStack.pop_back(); break; @@ -2418,6 +2414,7 @@ bool UnwrappedLineParser::tryToParseChildBlock() { } bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { + assert(!IsAngleBracket || !IsEnum); bool HasError = false; // FIXME: Once we have an expression parser in the UnwrappedLineParser, @@ -2440,8 +2437,11 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { } } if (FormatTok->is(IsAngleBracket ? tok::greater : tok::r_brace)) { - if (IsEnum && !Style.AllowShortEnumsOnASingleLine) - addUnwrappedLine(); + if (IsEnum) { + FormatTok->setBlockKind(BK_Block); + if (!Style.AllowShortEnumsOnASingleLine) + addUnwrappedLine(); + } nextToken(); return !HasError; } @@ -3944,8 +3944,11 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { switch (FormatTok->Tok.getKind()) { case tok::l_paren: // We can have macros in between 'class' and the class name. - if (!IsNonMacroIdentifier(Previous)) + if (!IsNonMacroIdentifier(Previous) || + // e.g. `struct macro(a) S { int i; };` + Previous->Previous == &InitialToken) { parseParens(); + } break; case tok::coloncolon: break; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 4f822807dd987..44fd807ec27ea 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -128,11 +128,14 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() { void WhitespaceManager::calculateLineBreakInformation() { Changes[0].PreviousEndOfTokenColumn = 0; Change *LastOutsideTokenChange = &Changes[0]; - for (unsigned i = 1, e = Changes.size(); i != e; ++i) { + for (unsigned I = 1, e = Changes.size(); I != e; ++I) { + auto &C = Changes[I]; + auto &P = Changes[I - 1]; + auto &PrevTokLength = P.TokenLength; SourceLocation OriginalWhitespaceStart = - Changes[i].OriginalWhitespaceRange.getBegin(); + C.OriginalWhitespaceRange.getBegin(); SourceLocation PreviousOriginalWhitespaceEnd = - Changes[i - 1].OriginalWhitespaceRange.getEnd(); + P.OriginalWhitespaceRange.getEnd(); unsigned OriginalWhitespaceStartOffset = SourceMgr.getFileOffset(OriginalWhitespaceStart); unsigned PreviousOriginalWhitespaceEndOffset = @@ -167,31 +170,28 @@ void WhitespaceManager::calculateLineBreakInformation() { // line of the token. auto NewlinePos = Text.find_first_of('\n'); if (NewlinePos == StringRef::npos) { - Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset - - PreviousOriginalWhitespaceEndOffset + - Changes[i].PreviousLinePostfix.size() + - Changes[i - 1].CurrentLinePrefix.size(); + PrevTokLength = OriginalWhitespaceStartOffset - + PreviousOriginalWhitespaceEndOffset + + C.PreviousLinePostfix.size() + P.CurrentLinePrefix.size(); + if (!P.IsInsideToken) + PrevTokLength = std::min(PrevTokLength, P.Tok->ColumnWidth); } else { - Changes[i - 1].TokenLength = - NewlinePos + Changes[i - 1].CurrentLinePrefix.size(); + PrevTokLength = NewlinePos + P.CurrentLinePrefix.size(); } // If there are multiple changes in this token, sum up all the changes until // the end of the line. - if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0) { - LastOutsideTokenChange->TokenLength += - Changes[i - 1].TokenLength + Changes[i - 1].Spaces; - } else { - LastOutsideTokenChange = &Changes[i - 1]; - } + if (P.IsInsideToken && P.NewlinesBefore == 0) + LastOutsideTokenChange->TokenLength += PrevTokLength + P.Spaces; + else + LastOutsideTokenChange = &P; - Changes[i].PreviousEndOfTokenColumn = - Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength; + C.PreviousEndOfTokenColumn = P.StartOfTokenColumn + PrevTokLength; - Changes[i - 1].IsTrailingComment = - (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) || - (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) && - Changes[i - 1].Tok->is(tok::comment) && + P.IsTrailingComment = + (C.NewlinesBefore > 0 || C.Tok->is(tok::eof) || + (C.IsInsideToken && C.Tok->is(tok::comment))) && + P.Tok->is(tok::comment) && // FIXME: This is a dirty hack. The problem is that // BreakableLineCommentSection does comment reflow changes and here is // the aligning of trailing comments. Consider the case where we reflow diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 3610a08831e79..1b93588553a27 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1067,7 +1067,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks { std::vector takeTopLevelDecls() { return std::move(TopLevelDecls); } - std::vector takeTopLevelDeclIDs() { + std::vector takeTopLevelDeclIDs() { return std::move(TopLevelDeclIDs); } @@ -1101,7 +1101,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks { private: unsigned Hash = 0; std::vector TopLevelDecls; - std::vector TopLevelDeclIDs; + std::vector TopLevelDeclIDs; llvm::SmallVector PreambleDiags; }; @@ -1467,11 +1467,12 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() { std::vector Resolved; Resolved.reserve(TopLevelDeclsInPreamble.size()); - ExternalASTSource &Source = *getASTContext().getExternalSource(); + // The module file of the preamble. + serialization::ModuleFile &MF = Reader->getModuleManager().getPrimaryModule(); for (const auto TopLevelDecl : TopLevelDeclsInPreamble) { // Resolve the declaration ID to an actual declaration, possibly // deserializing the declaration in the process. - if (Decl *D = Source.GetExternalDecl(TopLevelDecl)) + if (Decl *D = Reader->GetDecl(Reader->getGlobalDeclID(MF, TopLevelDecl))) Resolved.push_back(D); } TopLevelDeclsInPreamble.clear(); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 92efbeba543b2..9ceecd2e34d38 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1295,6 +1295,10 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, diag::remark_module_build_done) << ModuleName; + // Propagate the statistics to the parent FileManager. + if (!FrontendOpts.ModulesShareFileManager) + ImportingInstance.getFileManager().AddStats(Instance.getFileManager()); + if (Crashed) { // Clear the ASTConsumer if it hasn't been already, in case it owns streams // that must be closed before clearing output files. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 39e75dc63dc2e..55f40bd107e55 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2565,6 +2565,7 @@ static const auto &getFrontendActionTable() { {frontend::DumpTokens, OPT_dump_tokens}, {frontend::EmitAssembly, OPT_S}, {frontend::EmitBC, OPT_emit_llvm_bc}, + {frontend::EmitCIR, OPT_emit_cir}, {frontend::EmitHTML, OPT_emit_html}, {frontend::EmitLLVM, OPT_emit_llvm}, {frontend::EmitLLVMOnly, OPT_emit_llvm_only}, @@ -2907,6 +2908,8 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, if (Opts.ProgramAction != frontend::GenerateModule && Opts.IsSystemModule) Diags.Report(diag::err_drv_argument_only_allowed_with) << "-fsystem-module" << "-emit-module"; + if (Args.hasArg(OPT_fclangir) || Args.hasArg(OPT_emit_cir)) + Opts.UseClangIRPipeline = true; if (Args.hasArg(OPT_aux_target_cpu)) Opts.AuxTargetCPU = std::string(Args.getLastArgValue(OPT_aux_target_cpu)); @@ -4519,6 +4522,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::ASTView: case frontend::EmitAssembly: case frontend::EmitBC: + case frontend::EmitCIR: case frontend::EmitHTML: case frontend::EmitLLVM: case frontend::EmitLLVMOnly: diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b7c9967316f0b..9ae7664b4b49d 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -80,7 +80,7 @@ class DelegatingDeserializationListener : public ASTDeserializationListener { if (Previous) Previous->TypeRead(Idx, T); } - void DeclRead(serialization::DeclID ID, const Decl *D) override { + void DeclRead(GlobalDeclID ID, const Decl *D) override { if (Previous) Previous->DeclRead(ID, D); } @@ -102,7 +102,7 @@ class DeserializedDeclsDumper : public DelegatingDeserializationListener { bool DeletePrevious) : DelegatingDeserializationListener(Previous, DeletePrevious) {} - void DeclRead(serialization::DeclID ID, const Decl *D) override { + void DeclRead(GlobalDeclID ID, const Decl *D) override { llvm::outs() << "PCH DECL: " << D->getDeclKindName(); if (const NamedDecl *ND = dyn_cast(D)) { llvm::outs() << " - "; @@ -128,7 +128,7 @@ class DeserializedDeclsChecker : public DelegatingDeserializationListener { : DelegatingDeserializationListener(Previous, DeletePrevious), Ctx(Ctx), NamesToCheck(NamesToCheck) {} - void DeclRead(serialization::DeclID ID, const Decl *D) override { + void DeclRead(GlobalDeclID ID, const Decl *D) override { if (const NamedDecl *ND = dyn_cast(D)) if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) { unsigned DiagID @@ -757,8 +757,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // IR files bypass the rest of initialization. if (Input.getKind().getLanguage() == Language::LLVM_IR) { - assert(hasIRSupport() && - "This action does not have IR file support!"); + if (!hasIRSupport()) { + CI.getDiagnostics().Report(diag::err_ast_action_on_llvm_ir) + << Input.getFile(); + return false; + } // Inform the diagnostic client we are processing a source file. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr); diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 04eb104132671..454653a31534c 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -272,14 +272,10 @@ bool GenerateModuleInterfaceAction::BeginSourceFileAction( std::unique_ptr GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - CI.getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true; - CI.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true; - CI.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = true; - - std::vector> Consumers = - CreateMultiplexConsumer(CI, InFile); - if (Consumers.empty()) - return nullptr; + std::vector> Consumers; + Consumers.push_back(std::make_unique( + CI.getPreprocessor(), CI.getModuleCache(), + CI.getFrontendOpts().OutputFile)); if (CI.getFrontendOpts().GenReducedBMI && !CI.getFrontendOpts().ModuleOutputPath.empty()) { diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index d2e8fb2e8d6f2..b8cd54dc4fc4d 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -389,8 +389,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Twine((unsigned)LangOpts.getHLSLVersion())); if (LangOpts.NativeHalfType) - Builder.defineMacro("__HLSL_ENABLE_16_BIT", - Twine((unsigned)LangOpts.getHLSLVersion())); + Builder.defineMacro("__HLSL_ENABLE_16_BIT", "1"); // Shader target information // "enums" for shader stages @@ -737,7 +736,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_nested_namespace_definitions", "201411L"); Builder.defineMacro("__cpp_variadic_using", "201611L"); Builder.defineMacro("__cpp_aggregate_bases", "201603L"); - Builder.defineMacro("__cpp_structured_bindings", "201606L"); + Builder.defineMacro("__cpp_structured_bindings", "202403L"); Builder.defineMacro("__cpp_nontype_template_args", "201411L"); // (not latest) Builder.defineMacro("__cpp_fold_expressions", "201603L"); @@ -1342,6 +1341,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1"); } + // GCC defines these macros in both C and C++ modes despite them being needed + // mostly for STL implementations in C++. + auto [Destructive, Constructive] = TI.hardwareInterferenceSizes(); + Builder.defineMacro("__GCC_DESTRUCTIVE_SIZE", Twine(Destructive)); + Builder.defineMacro("__GCC_CONSTRUCTIVE_SIZE", Twine(Constructive)); + // We need to use push_macro to allow users to redefine these macros from the + // command line with -D and not issue a -Wmacro-redefined warning. + Builder.append("#pragma push_macro(\"__GCC_DESTRUCTIVE_SIZE\")"); + Builder.append("#pragma push_macro(\"__GCC_CONSTRUCTIVE_SIZE\")"); + auto addLockFreeMacros = [&](const llvm::Twine &Prefix) { // Used by libc++ and libstdc++ to implement ATOMIC__LOCK_FREE. #define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \ diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp index 744ea70cc24de..c74bfd86195fe 100644 --- a/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/clang/lib/Frontend/MultiplexConsumer.cpp @@ -52,8 +52,8 @@ void MultiplexASTDeserializationListener::TypeRead( Listeners[i]->TypeRead(Idx, T); } -void MultiplexASTDeserializationListener::DeclRead( - serialization::DeclID ID, const Decl *D) { +void MultiplexASTDeserializationListener::DeclRead(GlobalDeclID ID, + const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclRead(ID, D); } diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index f85f0365616f9..7476b1076d103 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -53,6 +53,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case DumpTokens: return std::make_unique(); case EmitAssembly: return std::make_unique(); case EmitBC: return std::make_unique(); + case EmitCIR: + llvm_unreachable("CIR suppport not built into clang"); case EmitHTML: return std::make_unique(); case EmitLLVM: return std::make_unique(); case EmitLLVMOnly: return std::make_unique(); diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index e6ae4e19e81db..3416811e39de2 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -335,6 +335,10 @@ set(llvm_libc_wrapper_files llvm_libc_wrappers/time.h ) +set(zos_wrapper_files + zos_wrappers/builtins.h +) + include(GetClangResourceDir) get_clang_resource_dir(output_dir PREFIX ${LLVM_LIBRARY_OUTPUT_INTDIR}/.. SUBDIR include) set(out_files) @@ -370,7 +374,7 @@ endfunction(clang_generate_header) # Copy header files from the source directory to the build directory foreach( f ${files} ${cuda_wrapper_files} ${cuda_wrapper_bits_files} - ${ppc_wrapper_files} ${openmp_wrapper_files} ${hlsl_files} + ${ppc_wrapper_files} ${openmp_wrapper_files} ${zos_wrapper_files} ${hlsl_files} ${llvm_libc_wrapper_files}) copy_header_to_output_dir(${CMAKE_CURRENT_SOURCE_DIR} ${f}) endforeach( f ) @@ -487,7 +491,7 @@ add_header_target("mips-resource-headers" "${mips_msa_files}") add_header_target("ppc-resource-headers" "${ppc_files};${ppc_wrapper_files}") add_header_target("ppc-htm-resource-headers" "${ppc_htm_files}") add_header_target("riscv-resource-headers" "${riscv_files};${riscv_generated_files}") -add_header_target("systemz-resource-headers" "${systemz_files}") +add_header_target("systemz-resource-headers" "${systemz_files};${zos_wrapper_files}") add_header_target("ve-resource-headers" "${ve_files}") add_header_target("webassembly-resource-headers" "${webassembly_files}") add_header_target("x86-resource-headers" "${x86_files}") @@ -538,6 +542,11 @@ install( DESTINATION ${header_install_dir}/openmp_wrappers COMPONENT clang-resource-headers) +install( + FILES ${zos_wrapper_files} + DESTINATION ${header_install_dir}/zos_wrappers + COMPONENT clang-resource-headers) + ############################################################# # Install rules for separate header lists install( @@ -642,6 +651,12 @@ install( EXCLUDE_FROM_ALL COMPONENT systemz-resource-headers) +install( + FILES ${zos_wrapper_files} + DESTINATION ${header_install_dir}/zos_wrappers + EXCLUDE_FROM_ALL + COMPONENT systemz-resource-headers) + install( FILES ${ve_files} DESTINATION ${header_install_dir} diff --git a/clang/lib/Headers/builtins.h b/clang/lib/Headers/builtins.h index 65095861ca9b1..1e534e632c8ea 100644 --- a/clang/lib/Headers/builtins.h +++ b/clang/lib/Headers/builtins.h @@ -13,4 +13,7 @@ #ifndef __BUILTINS_H #define __BUILTINS_H +#if defined(__MVS__) && __has_include_next() +#include_next +#endif /* __MVS__ */ #endif /* __BUILTINS_H */ diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h index 0bb9912b465ff..bb7692efb78ff 100644 --- a/clang/lib/Headers/cpuid.h +++ b/clang/lib/Headers/cpuid.h @@ -10,7 +10,7 @@ #ifndef __CPUID_H #define __CPUID_H -#if !(__x86_64__ || __i386__) +#if !defined(__x86_64__) && !defined(__i386__) #error this header is for x86 only #endif @@ -256,7 +256,7 @@ #define bit_AVX10_256 0x00020000 #define bit_AVX10_512 0x00040000 -#if __i386__ +#ifdef __i386__ #define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ : "0"(__leaf)) @@ -285,7 +285,7 @@ static __inline unsigned int __get_cpuid_max (unsigned int __leaf, unsigned int *__sig) { unsigned int __eax, __ebx, __ecx, __edx; -#if __i386__ +#ifdef __i386__ int __cpuid_supported; __asm(" pushfl\n" diff --git a/clang/lib/Headers/float.h b/clang/lib/Headers/float.h index 0e73bca0a2d6e..642c8f06cc938 100644 --- a/clang/lib/Headers/float.h +++ b/clang/lib/Headers/float.h @@ -10,6 +10,10 @@ #ifndef __CLANG_FLOAT_H #define __CLANG_FLOAT_H +#if defined(__MVS__) && __has_include_next() +#include_next +#else + /* If we're on MinGW, fall back to the system's float.h, which might have * additional definitions provided for Windows. * For more details see http://msdn.microsoft.com/en-us/library/y0ybw9fy.aspx @@ -165,4 +169,5 @@ # define FLT16_TRUE_MIN __FLT16_TRUE_MIN__ #endif /* __STDC_WANT_IEC_60559_TYPES_EXT__ */ +#endif /* __MVS__ */ #endif /* __CLANG_FLOAT_H */ diff --git a/clang/lib/Headers/inttypes.h b/clang/lib/Headers/inttypes.h index 1c894c4aca497..5150d22f8b2e4 100644 --- a/clang/lib/Headers/inttypes.h +++ b/clang/lib/Headers/inttypes.h @@ -13,6 +13,9 @@ #if !defined(_AIX) || !defined(_STD_TYPES_T) #define __CLANG_INTTYPES_H #endif +#if defined(__MVS__) && __has_include_next() +#include_next +#else #if defined(_MSC_VER) && _MSC_VER < 1800 #error MSVC does not have inttypes.h prior to Visual Studio 2013 @@ -94,4 +97,5 @@ #define SCNxFAST32 "x" #endif +#endif /* __MVS__ */ #endif /* __CLANG_INTTYPES_H */ diff --git a/clang/lib/Headers/iso646.h b/clang/lib/Headers/iso646.h index e0a20c6f1891b..b53fcd9b4e535 100644 --- a/clang/lib/Headers/iso646.h +++ b/clang/lib/Headers/iso646.h @@ -9,6 +9,9 @@ #ifndef __ISO646_H #define __ISO646_H +#if defined(__MVS__) && __has_include_next() +#include_next +#else #ifndef __cplusplus #define and && @@ -24,4 +27,5 @@ #define xor_eq ^= #endif +#endif /* __MVS__ */ #endif /* __ISO646_H */ diff --git a/clang/lib/Headers/limits.h b/clang/lib/Headers/limits.h index 15e6bbe0abcf7..56dffe568486c 100644 --- a/clang/lib/Headers/limits.h +++ b/clang/lib/Headers/limits.h @@ -9,6 +9,10 @@ #ifndef __CLANG_LIMITS_H #define __CLANG_LIMITS_H +#if defined(__MVS__) && __has_include_next() +#include_next +#else + /* The system's limits.h may, in turn, try to #include_next GCC's limits.h. Avert this #include_next madness. */ #if defined __GNUC__ && !defined _GCC_LIMITS_H_ @@ -122,4 +126,5 @@ #define ULONG_LONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL) #endif +#endif /* __MVS__ */ #endif /* __CLANG_LIMITS_H */ diff --git a/clang/lib/Headers/stdalign.h b/clang/lib/Headers/stdalign.h index 158508e65d2b3..56cdfa52d4baf 100644 --- a/clang/lib/Headers/stdalign.h +++ b/clang/lib/Headers/stdalign.h @@ -10,6 +10,10 @@ #ifndef __STDALIGN_H #define __STDALIGN_H +#if defined(__MVS__) && __has_include_next() +#include_next +#else + #if defined(__cplusplus) || \ (defined(__STDC_VERSION__) && __STDC_VERSION__ < 202311L) #ifndef __cplusplus @@ -21,4 +25,5 @@ #define __alignof_is_defined 1 #endif /* __STDC_VERSION__ */ +#endif /* __MVS__ */ #endif /* __STDALIGN_H */ diff --git a/clang/lib/Headers/stdarg.h b/clang/lib/Headers/stdarg.h index 94b066566f084..6e7bd604b2df4 100644 --- a/clang/lib/Headers/stdarg.h +++ b/clang/lib/Headers/stdarg.h @@ -33,6 +33,16 @@ defined(__need_va_arg) || defined(__need___va_copy) || \ defined(__need_va_copy) +#if defined(__MVS__) && __has_include_next() +#define __STDARG_H +#undef __need___va_list +#undef __need_va_list +#undef __need_va_arg +#undef __need___va_copy +#undef __need_va_copy +#include_next + +#else #if !defined(__need___va_list) && !defined(__need_va_list) && \ !defined(__need_va_arg) && !defined(__need___va_copy) && \ !defined(__need_va_copy) @@ -76,4 +86,6 @@ #undef __need_va_copy #endif /* defined(__need_va_copy) */ +#endif /* __MVS__ */ + #endif diff --git a/clang/lib/Headers/stdbool.h b/clang/lib/Headers/stdbool.h index 9406aab0ca72c..dfaad2b65a9b5 100644 --- a/clang/lib/Headers/stdbool.h +++ b/clang/lib/Headers/stdbool.h @@ -12,6 +12,10 @@ #define __bool_true_false_are_defined 1 +#if defined(__MVS__) && __has_include_next() +#include_next +#else + #if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L /* FIXME: We should be issuing a deprecation warning here, but cannot yet due * to system headers which include this header file unconditionally. @@ -31,4 +35,5 @@ #endif #endif +#endif /* __MVS__ */ #endif /* __STDBOOL_H */ diff --git a/clang/lib/Headers/stddef.h b/clang/lib/Headers/stddef.h index e0ad7b8d17aff..9ccc0a68fbff3 100644 --- a/clang/lib/Headers/stddef.h +++ b/clang/lib/Headers/stddef.h @@ -36,6 +36,22 @@ defined(__need_unreachable) || defined(__need_max_align_t) || \ defined(__need_offsetof) || defined(__need_wint_t) +#if defined(__MVS__) && __has_include_next() +#define __STDDEF_H +#undef __need_ptrdiff_t +#undef __need_size_t +#undef __need_rsize_t +#undef __need_wchar_t +#undef __need_NULL +#undef __need_nullptr_t +#undef __need_unreachable +#undef __need_max_align_t +#undef __need_offsetof +#undef __need_wint_t +#include_next + +#else + #if !defined(__need_ptrdiff_t) && !defined(__need_size_t) && \ !defined(__need_rsize_t) && !defined(__need_wchar_t) && \ !defined(__need_NULL) && !defined(__need_nullptr_t) && \ @@ -120,4 +136,5 @@ __WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */ #undef __need_wint_t #endif /* __need_wint_t */ +#endif /* __MVS__ */ #endif diff --git a/clang/lib/Headers/stdint.h b/clang/lib/Headers/stdint.h index b6699b6ca3d4b..01feab7b1ee2c 100644 --- a/clang/lib/Headers/stdint.h +++ b/clang/lib/Headers/stdint.h @@ -14,6 +14,10 @@ #define __CLANG_STDINT_H #endif +#if defined(__MVS__) && __has_include_next() +#include_next +#else + /* If we're hosted, fall back to the system's stdint.h, which might have * additional definitions. */ @@ -947,4 +951,5 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif #endif /* __STDC_HOSTED__ */ +#endif /* __MVS__ */ #endif /* __CLANG_STDINT_H */ diff --git a/clang/lib/Headers/stdnoreturn.h b/clang/lib/Headers/stdnoreturn.h index c90bf77e840e1..6a9b209c7218b 100644 --- a/clang/lib/Headers/stdnoreturn.h +++ b/clang/lib/Headers/stdnoreturn.h @@ -10,9 +10,15 @@ #ifndef __STDNORETURN_H #define __STDNORETURN_H +#if defined(__MVS__) && __has_include_next() +#include_next +#else + #define noreturn _Noreturn #define __noreturn_is_defined 1 +#endif /* __MVS__ */ + #if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) && \ !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS) /* The noreturn macro is deprecated in C23. We do not mark it as such because diff --git a/clang/lib/Headers/varargs.h b/clang/lib/Headers/varargs.h index d241b7de3cb2a..d33ddc5ae7f8a 100644 --- a/clang/lib/Headers/varargs.h +++ b/clang/lib/Headers/varargs.h @@ -8,5 +8,9 @@ */ #ifndef __VARARGS_H #define __VARARGS_H - #error "Please use instead of " +#if defined(__MVS__) && __has_include_next() +#include_next +#else +#error "Please use instead of " +#endif /* __MVS__ */ #endif diff --git a/clang/lib/Headers/zos_wrappers/builtins.h b/clang/lib/Headers/zos_wrappers/builtins.h new file mode 100644 index 0000000000000..1f0d0e27ecb3a --- /dev/null +++ b/clang/lib/Headers/zos_wrappers/builtins.h @@ -0,0 +1,18 @@ +/*===---- builtins.h - z/Architecture Builtin Functions --------------------=== + * + * 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 __ZOS_WRAPPERS_BUILTINS_H +#define __ZOS_WRAPPERS_BUILTINS_H +#if defined(__MVS__) +#include_next +#if defined(__VEC__) +#include +#endif +#endif /* defined(__MVS__) */ +#endif /* __ZOS_WRAPPERS_BUILTINS_H */ diff --git a/clang/lib/InstallAPI/FileList.cpp b/clang/lib/InstallAPI/FileList.cpp index 8a01248659b7d..65610903840af 100644 --- a/clang/lib/InstallAPI/FileList.cpp +++ b/clang/lib/InstallAPI/FileList.cpp @@ -51,6 +51,7 @@ class Implementation { public: std::unique_ptr InputBuffer; + clang::FileManager *FM; unsigned Version; HeaderSeq HeaderList; @@ -124,6 +125,12 @@ Error Implementation::parseHeaders(Array &Headers) { HeaderFile{PathStr, *Type, /*IncludeName=*/"", Language}); continue; } + + if (FM) + if (!FM->getOptionalFileRef(PathStr)) + return createFileError( + PathStr, make_error_code(std::errc::no_such_file_or_directory)); + auto IncludeName = createIncludeHeaderName(PathStr); HeaderList.emplace_back(PathStr, *Type, IncludeName.has_value() ? IncludeName.value() : "", @@ -170,9 +177,10 @@ Error Implementation::parse(StringRef Input) { llvm::Error FileListReader::loadHeaders(std::unique_ptr InputBuffer, - HeaderSeq &Destination) { + HeaderSeq &Destination, clang::FileManager *FM) { Implementation Impl; Impl.InputBuffer = std::move(InputBuffer); + Impl.FM = FM; if (llvm::Error Err = Impl.parse(Impl.InputBuffer->getBuffer())) return Err; diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 0632882b29614..574723b33866a 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1574,6 +1574,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, } } + FileInfo.IsLocallyIncluded = true; IsFirstIncludeOfFile = PP.markIncluded(File); return true; } diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 499813f8ab7df..10f0ab7180e62 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1444,7 +1444,8 @@ struct PragmaWarningHandler : public PragmaHandler { .Case("once", PPCallbacks::PWS_Once) .Case("suppress", PPCallbacks::PWS_Suppress) .Default(-1); - if ((SpecifierValid = SpecifierInt != -1)) + SpecifierValid = SpecifierInt != -1; + if (SpecifierValid) Specifier = static_cast(SpecifierInt); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a16259ebfccd3..b3f4bae32dbd5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -91,13 +91,23 @@ static StringRef normalizeAttrName(StringRef Name) { return Name; } -/// isAttributeLateParsed - Return true if the attribute has arguments that -/// require late parsing. -static bool isAttributeLateParsed(const IdentifierInfo &II) { +/// returns true iff attribute is annotated with `LateAttrParseExperimentalExt` +/// in `Attr.td`. +static bool IsAttributeLateParsedExperimentalExt(const IdentifierInfo &II) { +#define CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST + return llvm::StringSwitch(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(false); +#undef CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST +} + +/// returns true iff attribute is annotated with `LateAttrParseStandard` in +/// `Attr.td`. +static bool IsAttributeLateParsedStandard(const IdentifierInfo &II) { #define CLANG_ATTR_LATE_PARSED_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(normalizeAttrName(II.getName())) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_LATE_PARSED_LIST } @@ -222,8 +232,26 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs, continue; } + bool LateParse = false; + if (!LateAttrs) + LateParse = false; + else if (LateAttrs->lateAttrParseExperimentalExtOnly()) { + // The caller requested that this attribute **only** be late + // parsed for `LateAttrParseExperimentalExt` attributes. This will + // only be late parsed if the experimental language option is enabled. + LateParse = getLangOpts().ExperimentalLateParseAttributes && + IsAttributeLateParsedExperimentalExt(*AttrName); + } else { + // The caller did not restrict late parsing to only + // `LateAttrParseExperimentalExt` attributes so late parse + // both `LateAttrParseStandard` and `LateAttrParseExperimentalExt` + // attributes. + LateParse = IsAttributeLateParsedExperimentalExt(*AttrName) || + IsAttributeLateParsedStandard(*AttrName); + } + // Handle "parameterized" attributes - if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { + if (!LateParse) { ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, &EndLoc, nullptr, SourceLocation(), ParsedAttr::Form::GNU(), D); continue; @@ -2999,7 +3027,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, << TokenName << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName); - if (Actions.LookupParsedName(R, getCurScope(), SS)) { + if (Actions.LookupName(R, getCurScope())) { for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) @@ -7039,18 +7067,23 @@ void Parser::ParseDirectDeclarator(Declarator &D) { void Parser::ParseDecompositionDeclarator(Declarator &D) { assert(Tok.is(tok::l_square)); + TentativeParsingAction PA(*this); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + if (isCXX11AttributeSpecifier()) + DiagnoseAndSkipCXX11Attributes(); + // If this doesn't look like a structured binding, maybe it's a misplaced // array declarator. - // FIXME: Consume the l_square first so we don't need extra lookahead for - // this. - if (!(NextToken().is(tok::identifier) && - GetLookAheadToken(2).isOneOf(tok::comma, tok::r_square)) && - !(NextToken().is(tok::r_square) && - GetLookAheadToken(2).isOneOf(tok::equal, tok::l_brace))) + if (!(Tok.is(tok::identifier) && + NextToken().isOneOf(tok::comma, tok::r_square, tok::kw_alignas, + tok::l_square)) && + !(Tok.is(tok::r_square) && + NextToken().isOneOf(tok::equal, tok::l_brace))) { + PA.Revert(); return ParseMisplacedBracketDeclarator(D); - - BalancedDelimiterTracker T(*this, tok::l_square); - T.consumeOpen(); + } SmallVector Bindings; while (Tok.isNot(tok::r_square)) { @@ -7075,13 +7108,27 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) { } } + if (isCXX11AttributeSpecifier()) + DiagnoseAndSkipCXX11Attributes(); + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; break; } - Bindings.push_back({Tok.getIdentifierInfo(), Tok.getLocation()}); + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation Loc = Tok.getLocation(); ConsumeToken(); + + ParsedAttributes Attrs(AttrFactory); + if (isCXX11AttributeSpecifier()) { + Diag(Tok, getLangOpts().CPlusPlus26 + ? diag::warn_cxx23_compat_decl_attrs_on_binding + : diag::ext_decl_attrs_on_binding); + MaybeParseCXX11Attributes(Attrs); + } + + Bindings.push_back({II, Loc, std::move(Attrs)}); } if (Tok.isNot(tok::r_square)) @@ -7096,6 +7143,8 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) { T.consumeClose(); } + PA.Commit(); + return D.setDecompositionBindings(T.getOpenLocation(), Bindings, T.getCloseLocation()); } @@ -7368,12 +7417,20 @@ void Parser::ParseFunctionDeclarator(Declarator &D, std::optional ThisScope; InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); - // Parse exception-specification[opt]. - // FIXME: Per [class.mem]p6, all exception-specifications at class scope - // should be delayed, including those for non-members (eg, friend - // declarations). But only applying this to member declarations is - // consistent with what other implementations do. - bool Delayed = D.isFirstDeclarationOfMember() && + // C++ [class.mem.general]p8: + // A complete-class context of a class (template) is a + // - function body, + // - default argument, + // - default template argument, + // - noexcept-specifier, or + // - default member initializer + // within the member-specification of the class or class template. + // + // Parse exception-specification[opt]. If we are in the + // member-specification of a class or class template, this is a + // complete-class context and parsing of the noexcept-specifier should be + // delayed (even if this is a friend declaration). + bool Delayed = D.getContext() == DeclaratorContext::Member && D.isFunctionDeclaratorAFunctionDeclaration(); if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) && GetLookAheadToken(0).is(tok::kw_noexcept) && diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 69746eaccb43b..c6b611e9e2a8b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCUDA.h" +#include "clang/Sema/SemaOpenACC.h" #include "clang/Sema/SemaOpenMP.h" #include "clang/Sema/SemaSYCL.h" #include "clang/Sema/TypoCorrection.h" @@ -2139,15 +2140,22 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (!LHS.isInvalid() && !HasError && !Length.isInvalid() && !Stride.isInvalid() && Tok.is(tok::r_square)) { if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) { - // FIXME: OpenACC hasn't implemented Sema/Array section handling at a - // semantic level yet. For now, just reuse the OpenMP implementation - // as it gets the parsing/type management mostly right, and we can - // replace this call to ActOnOpenACCArraySectionExpr in the future. - // Eventually we'll genericize the OPenMPArraySectionExpr type as - // well. - LHS = Actions.OpenMP().ActOnOMPArraySectionExpr( - LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0], - ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc); + // Like above, AllowOpenACCArraySections is 'more specific' and only + // enabled when actively parsing a 'var' in a 'var-list' during + // clause/'cache' construct parsing, so it is more specific. So we + // should do it first, so that the correct node gets created. + if (AllowOpenACCArraySections) { + assert(!Stride.isUsable() && !ColonLocSecond.isValid() && + "Stride/second colon not allowed for OpenACC"); + LHS = Actions.OpenACC().ActOnArraySectionExpr( + LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0], + ColonLocFirst, Length.get(), RLoc); + } else { + LHS = Actions.OpenMP().ActOnOMPArraySectionExpr( + LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0], + ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), + RLoc); + } } else { LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc, ArgExprs, RLoc); diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 8a18fca8064ee..2d1ec6539b2fd 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -86,6 +86,10 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { if (Tok.is(tok::kw_if)) return OpenACCClauseKind::If; + // 'private' is also a keyword, make sure we pare it correctly. + if (Tok.is(tok::kw_private)) + return OpenACCClauseKind::Private; + if (!Tok.is(tok::identifier)) return OpenACCClauseKind::Invalid; @@ -327,7 +331,7 @@ OpenACCReductionOperator ParseReductionOperator(Parser &P) { return OpenACCReductionOperator::Max; if (ReductionKindTok.getIdentifierInfo()->isStr("min")) return OpenACCReductionOperator::Min; - LLVM_FALLTHROUGH; + [[fallthrough]]; default: P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator); return OpenACCReductionOperator::Invalid; @@ -682,28 +686,6 @@ bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK, return false; } -bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) { - // FIXME: Future clauses will require 'special word' parsing, check for one, - // then parse it based on whether it is a clause that requires a 'special - // word'. - (void)Kind; - - // If the var parsing fails, skip until the end of the directive as this is - // an expression and gets messy if we try to continue otherwise. - if (ParseOpenACCVar()) - return true; - - while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { - ExpectAndConsume(tok::comma); - - // If the var parsing fails, skip until the end of the directive as this is - // an expression and gets messy if we try to continue otherwise. - if (ParseOpenACCVar()) - return true; - } - return false; -} - /// OpenACC 3.3 Section 2.4: /// The argument to the device_type clause is a comma-separated list of one or /// more device architecture name identifiers, or an asterisk. @@ -917,35 +899,26 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( case OpenACCClauseKind::CopyIn: tryParseAndConsumeSpecialTokenKind( *this, OpenACCSpecialTokenKind::ReadOnly, ClauseKind); - if (ParseOpenACCClauseVarList(ClauseKind)) { - Parens.skipToEnd(); - return OpenACCCanContinue(); - } + ParseOpenACCVarList(); break; case OpenACCClauseKind::Create: case OpenACCClauseKind::CopyOut: tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Zero, ClauseKind); - if (ParseOpenACCClauseVarList(ClauseKind)) { - Parens.skipToEnd(); - return OpenACCCanContinue(); - } + ParseOpenACCVarList(); break; case OpenACCClauseKind::Reduction: // If we're missing a clause-kind (or it is invalid), see if we can parse // the var-list anyway. ParseReductionOperator(*this); - if (ParseOpenACCClauseVarList(ClauseKind)) { - Parens.skipToEnd(); - return OpenACCCanContinue(); - } + ParseOpenACCVarList(); break; case OpenACCClauseKind::Self: // The 'self' clause is a var-list instead of a 'condition' in the case of // the 'update' clause, so we have to handle it here. U se an assert to // make sure we get the right differentiator. assert(DirKind == OpenACCDirectiveKind::Update); - LLVM_FALLTHROUGH; + [[fallthrough]]; case OpenACCClauseKind::Attach: case OpenACCClauseKind::Copy: case OpenACCClauseKind::Delete: @@ -958,12 +931,11 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( case OpenACCClauseKind::Link: case OpenACCClauseKind::NoCreate: case OpenACCClauseKind::Present: - case OpenACCClauseKind::Private: case OpenACCClauseKind::UseDevice: - if (ParseOpenACCClauseVarList(ClauseKind)) { - Parens.skipToEnd(); - return OpenACCCanContinue(); - } + ParseOpenACCVarList(); + break; + case OpenACCClauseKind::Private: + ParsedClause.setVarListDetails(ParseOpenACCVarList()); break; case OpenACCClauseKind::Collapse: { tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force, @@ -1227,16 +1199,51 @@ ExprResult Parser::ParseOpenACCBindClauseArgument() { /// OpenACC 3.3, section 1.6: /// In this spec, a 'var' (in italics) is one of the following: -/// - a variable name (a scalar, array, or compisite variable name) +/// - a variable name (a scalar, array, or composite variable name) /// - a subarray specification with subscript ranges /// - an array element /// - a member of a composite variable /// - a common block name between slashes (fortran only) -bool Parser::ParseOpenACCVar() { +Parser::OpenACCVarParseResult Parser::ParseOpenACCVar() { OpenACCArraySectionRAII ArraySections(*this); - ExprResult Res = - getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - return Res.isInvalid(); + + ExprResult Res = ParseAssignmentExpression(); + if (!Res.isUsable()) + return {Res, OpenACCParseCanContinue::Cannot}; + + Res = getActions().CorrectDelayedTyposInExpr(Res.get()); + if (!Res.isUsable()) + return {Res, OpenACCParseCanContinue::Can}; + + Res = getActions().OpenACC().ActOnVar(Res.get()); + + return {Res, OpenACCParseCanContinue::Can}; +} + +llvm::SmallVector Parser::ParseOpenACCVarList() { + llvm::SmallVector Vars; + + auto [Res, CanContinue] = ParseOpenACCVar(); + if (Res.isUsable()) { + Vars.push_back(Res.get()); + } else if (CanContinue == OpenACCParseCanContinue::Cannot) { + SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch); + return Vars; + } + + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { + ExpectAndConsume(tok::comma); + + auto [Res, CanContinue] = ParseOpenACCVar(); + + if (Res.isUsable()) { + Vars.push_back(Res.get()); + } else if (CanContinue == OpenACCParseCanContinue::Cannot) { + SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, StopBeforeMatch); + return Vars; + } + } + return Vars; } /// OpenACC 3.3, section 2.10: @@ -1259,24 +1266,9 @@ void Parser::ParseOpenACCCacheVarList() { // Sema/AST generation. } - bool FirstArray = true; - while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { - if (!FirstArray) - ExpectAndConsume(tok::comma); - FirstArray = false; - - // OpenACC 3.3, section 2.10: - // A 'var' in a cache directive must be a single array element or a simple - // subarray. In C and C++, a simple subarray is an array name followed by - // an extended array range specification in brackets, with a start and - // length such as: - // - // arr[lower:length] - // - if (ParseOpenACCVar()) - SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma, - StopBeforeMatch); - } + // ParseOpenACCVarList should leave us before a r-paren, so no need to skip + // anything here. + ParseOpenACCVarList(); } Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 480201bc06f61..53d89ce2fa3e9 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -4228,13 +4228,20 @@ bool Parser::parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data) { return T.consumeClose(); } +static OpenMPMapClauseKind isMapType(Parser &P); + /// Parse map-type-modifiers in map clause. -/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list) +/// map([ [map-type-modifier[,] [map-type-modifier[,] ...] [map-type] : ] list) /// where, map-type-modifier ::= always | close | mapper(mapper-identifier) | /// present +/// where, map-type ::= alloc | delete | from | release | to | tofrom bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) { + bool HasMapType = false; + SourceLocation PreMapLoc = Tok.getLocation(); + StringRef PreMapName = ""; while (getCurToken().isNot(tok::colon)) { OpenMPMapModifierKind TypeModifier = isMapModifier(*this); + OpenMPMapClauseKind MapKind = isMapType(*this); if (TypeModifier == OMPC_MAP_MODIFIER_always || TypeModifier == OMPC_MAP_MODIFIER_close || TypeModifier == OMPC_MAP_MODIFIER_present || @@ -4257,6 +4264,19 @@ bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) { Diag(Data.MapTypeModifiersLoc.back(), diag::err_omp_missing_comma) << "map type modifier"; + } else if (getLangOpts().OpenMP >= 60 && MapKind != OMPC_MAP_unknown) { + if (!HasMapType) { + HasMapType = true; + Data.ExtraModifier = MapKind; + MapKind = OMPC_MAP_unknown; + PreMapLoc = Tok.getLocation(); + PreMapName = Tok.getIdentifierInfo()->getName(); + } else { + Diag(Tok, diag::err_omp_more_one_map_type); + Diag(PreMapLoc, diag::note_previous_map_type_specified_here) + << PreMapName; + } + ConsumeToken(); } else { // For the case of unknown map-type-modifier or a map-type. // Map-type is followed by a colon; the function returns when it @@ -4267,8 +4287,14 @@ bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) { continue; } // Potential map-type token as it is followed by a colon. - if (PP.LookAhead(0).is(tok::colon)) - return false; + if (PP.LookAhead(0).is(tok::colon)) { + if (getLangOpts().OpenMP >= 60) { + break; + } else { + return false; + } + } + Diag(Tok, diag::err_omp_unknown_map_type_modifier) << (getLangOpts().OpenMP >= 51 ? (getLangOpts().OpenMP >= 52 ? 2 : 1) : 0) @@ -4278,6 +4304,14 @@ bool Parser::parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data) { if (getCurToken().is(tok::comma)) ConsumeToken(); } + if (getLangOpts().OpenMP >= 60 && !HasMapType) { + if (!Tok.is(tok::colon)) { + Diag(Tok, diag::err_omp_unknown_map_type); + ConsumeToken(); + } else { + Data.ExtraModifier = OMPC_MAP_unknown; + } + } return false; } @@ -4675,8 +4709,10 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // Only parse map-type-modifier[s] and map-type if a colon is present in // the map clause. if (ColonPresent) { + if (getLangOpts().OpenMP >= 60 && getCurToken().is(tok::colon)) + Diag(Tok, diag::err_omp_map_modifier_specification_list); IsInvalidMapperModifier = parseMapTypeModifiers(Data); - if (!IsInvalidMapperModifier) + if (getLangOpts().OpenMP < 60 && !IsInvalidMapperModifier) parseMapType(*this, Data); else SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index b79683bb32a69..60e8189025700 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -293,7 +293,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, void Declarator::setDecompositionBindings( SourceLocation LSquareLoc, - ArrayRef Bindings, + MutableArrayRef Bindings, SourceLocation RSquareLoc) { assert(!hasName() && "declarator given multiple names!"); @@ -317,7 +317,7 @@ void Declarator::setDecompositionBindings( new DecompositionDeclarator::Binding[Bindings.size()]; BindingGroup.DeleteBindings = true; } - std::uninitialized_copy(Bindings.begin(), Bindings.end(), + std::uninitialized_move(Bindings.begin(), Bindings.end(), BindingGroup.Bindings); } } @@ -1202,7 +1202,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { !S.Context.getTargetInfo().hasFeature("power8-vector")) S.Diag(TSTLoc, diag::err_invalid_vector_int128_decl_spec); - if (TypeAltiVecBool) { + // Complex vector types are not supported. + if (TypeSpecComplex != TSC_unspecified) + S.Diag(TSCLoc, diag::err_invalid_vector_complex_decl_spec); + else if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (getTypeSpecSign() != TypeSpecifierSign::Unspecified) { S.Diag(TSSLoc, diag::err_invalid_vector_bool_decl_spec) diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 1a1febf7a3524..bb283c54b3d29 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -126,12 +126,15 @@ struct BuiltinTypeDeclBuilder { static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, StringRef Name) { - CXXScopeSpec SS; IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); DeclarationNameInfo NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation()); LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); - S.LookupParsedName(R, S.getCurScope(), &SS, false); + // AllowBuiltinCreation is false but LookupDirect will create + // the builtin when searching the global scope anyways... + S.LookupName(R, S.getCurScope()); + // FIXME: If the builtin function was user-declared in global scope, + // this assert *will* fail. Should this call LookupBuiltin instead? assert(R.isSingleResult() && "Since this is a builtin it should always resolve!"); auto *VD = cast(R.getFoundDecl()); diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index ce6211c23218b..8af36d5c24e3d 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -180,7 +180,8 @@ static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) { } const Expr *Init = VD->getInit(); - if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init) { + if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init && + !Init->containsErrors()) { // C++11 [stmt.dcl]p3: // A program that jumps from a point where a variable with automatic // storage duration is not in scope to a point where it is in scope diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 6a5f9f6680e64..79e656eb4b7e2 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -46,7 +46,7 @@ void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) { // ExternalASTSource. //===----------------------------------------------------------------------===// -Decl *MultiplexExternalSemaSource::GetExternalDecl(Decl::DeclID ID) { +Decl *MultiplexExternalSemaSource::GetExternalDecl(GlobalDeclID ID) { for(size_t i = 0; i < Sources.size(); ++i) if (Decl *Result = Sources[i]->GetExternalDecl(ID)) return Result; diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 4c445f28bba8c..c5998aca0d721 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -594,6 +594,11 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info, D->addAttr( SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value())); + if (auto Copyable = Info.isSwiftCopyable()) { + if (!*Copyable) + D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable")); + } + if (auto Extensibility = Info.EnumExtensibility) { using api_notes::EnumExtensibilityKind; bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index a5dd158808f26..a83b1e8afadbc 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -837,7 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, IdentifierInfo *Name = IdTok.getIdentifierInfo(); LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName); - LookupParsedName(Lookup, curScope, nullptr, true); + LookupName(Lookup, curScope, /*AllowBuiltinCreation=*/true); if (Lookup.empty()) { Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index f16594bf16d93..6bbbab4302a18 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3217,13 +3217,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, const Expr *Arg = TheCall->getArg(0); const auto *TyA = Arg->getType()->getAs(); - if (!TyA) { + + QualType ElTy; + if (TyA) + ElTy = TyA->getElementType(); + else if (Arg->getType()->isSizelessVectorType()) + ElTy = Arg->getType()->getSizelessVectorEltType(Context); + + if (ElTy.isNull()) { Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) << 1 << /* vector ty*/ 4 << Arg->getType(); return ExprError(); } - TheCall->setType(TyA->getElementType()); + TheCall->setType(ElTy); break; } @@ -3239,12 +3246,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, const Expr *Arg = TheCall->getArg(0); const auto *TyA = Arg->getType()->getAs(); - if (!TyA || !TyA->getElementType()->isIntegerType()) { + + QualType ElTy; + if (TyA) + ElTy = TyA->getElementType(); + else if (Arg->getType()->isSizelessVectorType()) + ElTy = Arg->getType()->getSizelessVectorEltType(Context); + + if (ElTy.isNull() || !ElTy->isIntegerType()) { Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) << 1 << /* vector of integers */ 6 << Arg->getType(); return ExprError(); } - TheCall->setType(TyA->getElementType()); + + TheCall->setType(ElTy); break; } @@ -12918,6 +12933,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, return true; } + // Diagnose attempts to use '%P' with ObjC object types, which will result in + // dumping raw class data (like is-a pointer), not actual data. + if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::PArg && + ExprTy->isObjCObjectPointerType()) { + const CharSourceRange &CSR = + getSpecifierRange(StartSpecifier, SpecifierLen); + EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_with_objc_pointer), + E->getExprLoc(), false, CSR); + return true; + } + ArgType::MatchKind ImplicitMatch = ArgType::NoMatch; ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); ArgType::MatchKind OrigMatch = Match; @@ -19115,8 +19141,10 @@ void Sema::CheckArrayAccess(const Expr *expr) { expr = cast(expr)->getBase(); break; } - case Stmt::OMPArraySectionExprClass: { - const OMPArraySectionExpr *ASE = cast(expr); + case Stmt::ArraySectionExprClass: { + const ArraySectionExpr *ASE = cast(expr); + // FIXME: We should probably be checking all of the elements to the + // 'length' here as well. if (ASE->getLowerBound()) CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), /*ASE=*/nullptr, AllowOnePastEnd > 0); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e27ccb95c9887..b104f357dc64d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -833,7 +833,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, IdentifierInfo *&Name, SourceLocation NameLoc) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); - SemaRef.LookupParsedName(R, S, &SS); + SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); if (TagDecl *Tag = R.getAsSingle()) { StringRef FixItTagName; switch (Tag->getTagKind()) { @@ -870,7 +870,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, // Replace lookup results with just the tag decl. Result.clear(Sema::LookupTagName); - SemaRef.LookupParsedName(Result, S, &SS); + SemaRef.LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType()); return true; } @@ -897,7 +897,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, &SS, !CurMethod); + LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/!CurMethod); if (SS.isInvalid()) return NameClassification::Error(); @@ -1975,7 +1976,7 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts, // it is, by the bindings' expressions). bool IsAllPlaceholders = true; for (const auto *BD : DD->bindings()) { - if (BD->isReferenced()) + if (BD->isReferenced() || BD->hasAttr()) return false; IsAllPlaceholders = IsAllPlaceholders && BD->isPlaceholderVar(LangOpts); } @@ -13601,16 +13602,18 @@ void Sema::checkNonTrivialCUnion(QualType QT, SourceLocation Loc, void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. - if (!RealDecl || RealDecl->isInvalidDecl()) { + if (!RealDecl) { CorrectDelayedTyposInExpr(Init, dyn_cast_or_null(RealDecl)); return; } - if (CXXMethodDecl *Method = dyn_cast(RealDecl)) { - // Pure-specifiers are handled in ActOnPureSpecifier. - Diag(Method->getLocation(), diag::err_member_function_initialization) - << Method->getDeclName() << Init->getSourceRange(); - Method->setInvalidDecl(); + if (auto *Method = dyn_cast(RealDecl)) { + if (!Method->isInvalidDecl()) { + // Pure-specifiers are handled in ActOnPureSpecifier. + Diag(Method->getLocation(), diag::err_member_function_initialization) + << Method->getDeclName() << Init->getSourceRange(); + Method->setInvalidDecl(); + } return; } @@ -13622,6 +13625,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + if (VDecl->isInvalidDecl()) { + CorrectDelayedTyposInExpr(Init, VDecl); + ExprResult Recovery = + CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), {Init}); + if (Expr *E = Recovery.get()) + VDecl->setInit(E); + return; + } + // WebAssembly tables can't be used to initialise a variable. if (Init && !Init->getType().isNull() && Init->getType()->isWebAssemblyTableType()) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f08aa5ee49d92..38c21b866a3a9 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -911,6 +911,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, VarName); + ProcessDeclAttributeList(S, BD, *B.Attrs); + // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() ? getShadowedDeclaration(BD, Previous) @@ -4545,7 +4547,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, DS.getBeginLoc(), DS.getEllipsisLoc()); } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); TypeDecl *TyD = R.getAsSingle(); if (!TyD) { @@ -12080,11 +12082,17 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { Template = Specialization->getSpecializedTemplate(); Arguments = Specialization->getTemplateArgs().data(); - } else if (const TemplateSpecializationType *TST = - Ty->getAs()) { - Template = dyn_cast_or_null( - TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->template_arguments().begin(); + } else { + const TemplateSpecializationType *TST = nullptr; + if (auto *ICN = Ty->getAs()) + TST = ICN->getInjectedTST(); + else + TST = Ty->getAs(); + if (TST) { + Template = dyn_cast_or_null( + TST->getTemplateName().getAsTemplateDecl()); + Arguments = TST->template_arguments().begin(); + } } if (!Template) return false; @@ -12290,7 +12298,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, // Lookup namespace name. LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); if (R.isAmbiguous()) return nullptr; @@ -13749,7 +13757,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, // Lookup the namespace name. LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); if (R.isAmbiguous()) return nullptr; @@ -19192,40 +19200,40 @@ void Sema::checkExceptionSpecification( } } -void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, - ExceptionSpecificationType EST, - SourceRange SpecificationRange, - ArrayRef DynamicExceptions, - ArrayRef DynamicExceptionRanges, - Expr *NoexceptExpr) { - if (!MethodD) +void Sema::actOnDelayedExceptionSpecification( + Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange, + ArrayRef DynamicExceptions, + ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr) { + if (!D) return; - // Dig out the method we're referring to. - if (FunctionTemplateDecl *FunTmpl = dyn_cast(MethodD)) - MethodD = FunTmpl->getTemplatedDecl(); + // Dig out the function we're referring to. + if (FunctionTemplateDecl *FTD = dyn_cast(D)) + D = FTD->getTemplatedDecl(); - CXXMethodDecl *Method = dyn_cast(MethodD); - if (!Method) + FunctionDecl *FD = dyn_cast(D); + if (!FD) return; // Check the exception specification. llvm::SmallVector Exceptions; FunctionProtoType::ExceptionSpecInfo ESI; - checkExceptionSpecification(/*IsTopLevel*/true, EST, DynamicExceptions, + checkExceptionSpecification(/*IsTopLevel=*/true, EST, DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, Exceptions, ESI); // Update the exception specification on the function type. - Context.adjustExceptionSpec(Method, ESI, /*AsWritten*/true); + Context.adjustExceptionSpec(FD, ESI, /*AsWritten=*/true); - if (Method->isStatic()) - checkThisInStaticMemberFunctionExceptionSpec(Method); + if (CXXMethodDecl *MD = dyn_cast(D)) { + if (MD->isStatic()) + checkThisInStaticMemberFunctionExceptionSpec(MD); - if (Method->isVirtual()) { - // Check overrides, which we previously had to delay. - for (const CXXMethodDecl *O : Method->overridden_methods()) - CheckOverridingFunctionExceptionSpec(Method, O); + if (MD->isVirtual()) { + // Check overrides, which we previously had to delay. + for (const CXXMethodDecl *O : MD->overridden_methods()) + CheckOverridingFunctionExceptionSpec(MD, O); + } } } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 21b8b08ce672f..b0fcb5903832f 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -258,13 +258,14 @@ Sema::UpdateExceptionSpec(FunctionDecl *FD, } static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) { - auto *MD = dyn_cast(FD); - if (!MD) + ExceptionSpecificationType EST = + FD->getType()->castAs()->getExceptionSpecType(); + if (EST == EST_Unparsed) + return true; + else if (EST != EST_Unevaluated) return false; - - auto EST = MD->getType()->castAs()->getExceptionSpecType(); - return EST == EST_Unparsed || - (EST == EST_Unevaluated && MD->getParent()->isBeingDefined()); + const DeclContext *DC = FD->getLexicalDeclContext(); + return DC->isRecord() && cast(DC)->isBeingDefined(); } static bool CheckEquivalentExceptionSpecImpl( @@ -1314,7 +1315,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: case Expr::MatrixSubscriptExprClass: - case Expr::OMPArraySectionExprClass: + case Expr::ArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: case Expr::BinaryOperatorClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e52cd581713b6..9ac440d65bf9b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -741,8 +741,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // expressions of certain types in C++. if (getLangOpts().CPlusPlus && (E->getType() == Context.OverloadTy || - T->isDependentType() || - T->isRecordType())) + // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied + // to pointer types even if the pointee type is dependent. + (T->isDependentType() && !T->isPointerType()) || T->isRecordType())) return E; // The C standard is actually really unclear on this point, and @@ -2819,8 +2820,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) { // See if this is reference to a field of struct. LookupResult R(*this, NameInfo, LookupMemberName); - // LookupParsedName handles a name lookup from within anonymous struct. - if (LookupParsedName(R, S, &SS)) { + // LookupName handles a name lookup from within anonymous struct. + if (LookupName(R, S)) { if (auto *VD = dyn_cast(R.getFoundDecl())) { QualType type = VD->getType().getNonReferenceType(); // This will eventually be translated into MemberExpr upon @@ -2841,20 +2842,19 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // lookup to determine that it was a template name in the first place. If // this becomes a performance hit, we can work harder to preserve those // results until we get here but it's likely not worth it. - bool MemberOfUnknownSpecialization; AssumedTemplateKind AssumedTemplate; - if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, - MemberOfUnknownSpecialization, TemplateKWLoc, + if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(), + /*EnteringContext=*/false, TemplateKWLoc, &AssumedTemplate)) return ExprError(); - if (MemberOfUnknownSpecialization || - (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) + if (R.wasNotFoundInCurrentInstantiation()) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); } else { bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); - LookupParsedName(R, S, &SS, !IvarLookupFollowUp); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/!IvarLookupFollowUp); // If the result might be in a dependent base class, this is a dependent // id-expression. @@ -5137,11 +5137,18 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation rbLoc) { if (base && !base->getType().isNull() && - base->hasPlaceholderType(BuiltinType::OMPArraySection)) - return OpenMP().ActOnOMPArraySectionExpr(base, lbLoc, ArgExprs.front(), - SourceLocation(), SourceLocation(), - /*Length*/ nullptr, - /*Stride=*/nullptr, rbLoc); + base->hasPlaceholderType(BuiltinType::ArraySection)) { + auto *AS = cast(base); + if (AS->isOMPArraySection()) + return OpenMP().ActOnOMPArraySectionExpr( + base, lbLoc, ArgExprs.front(), SourceLocation(), SourceLocation(), + /*Length*/ nullptr, + /*Stride=*/nullptr, rbLoc); + + return OpenACC().ActOnArraySectionExpr(base, lbLoc, ArgExprs.front(), + SourceLocation(), /*Length*/ nullptr, + rbLoc); + } // Since this might be a postfix expression, get rid of ParenListExprs. if (isa(base)) { @@ -6434,7 +6441,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: case BuiltinType::IncompleteMatrixIdx: - case BuiltinType::OMPArraySection: + case BuiltinType::ArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: return true; @@ -21416,8 +21423,9 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { return ExprError(); // Expressions of unknown type. - case BuiltinType::OMPArraySection: - Diag(E->getBeginLoc(), diag::err_omp_array_section_use); + case BuiltinType::ArraySection: + Diag(E->getBeginLoc(), diag::err_array_section_use) + << cast(E)->isOMPArraySection(); return ExprError(); // Expressions of unknown type. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index dbf3a85fe0364..7616e118a53c3 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9166,7 +9166,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, RedeclarationKind::NotForRedeclaration); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); R.suppressDiagnostics(); switch (R.getResultKind()) { diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 6e30716b9ae43..5facb14a18b7c 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -667,8 +667,8 @@ namespace { // classes, one of its base classes. class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { public: - explicit RecordMemberExprValidatorCCC(const RecordType *RTy) - : Record(RTy->getDecl()) { + explicit RecordMemberExprValidatorCCC(QualType RTy) + : Record(RTy->getAsRecordDecl()) { // Don't add bare keywords to the consumer since they will always fail // validation by virtue of not being associated with any decls. WantTypeSpecifiers = false; @@ -713,58 +713,36 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { } static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - Expr *BaseExpr, - const RecordType *RTy, + Expr *BaseExpr, QualType RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, TypoExpr *&TE) { SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); - RecordDecl *RDecl = RTy->getDecl(); - if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && - SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), - diag::err_typecheck_incomplete_tag, - BaseRange)) + if (!RTy->isDependentType() && + !SemaRef.isThisOutsideMemberFunctionBody(RTy) && + SemaRef.RequireCompleteType( + OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange)) return true; - if (HasTemplateArgs || TemplateKWLoc.isValid()) { - // LookupTemplateName doesn't expect these both to exist simultaneously. - QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); + // LookupTemplateName/LookupParsedName don't expect these both to exist + // simultaneously. + QualType ObjectType = SS.isSet() ? QualType() : RTy; + if (HasTemplateArgs || TemplateKWLoc.isValid()) + return SemaRef.LookupTemplateName(R, + /*S=*/nullptr, SS, ObjectType, + /*EnteringContext=*/false, TemplateKWLoc); - bool MOUS; - return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS, - TemplateKWLoc); - } - - DeclContext *DC = RDecl; - if (SS.isSet()) { - // If the member name was a qualified-id, look into the - // nested-name-specifier. - DC = SemaRef.computeDeclContext(SS, false); - - if (SemaRef.RequireCompleteDeclContext(SS, DC)) { - SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) - << SS.getRange() << DC; - return true; - } - - assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - - if (!isa(DC)) { - SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) - << DC << SS.getRange(); - return true; - } - } - - // The record definition is complete, now look up the member. - SemaRef.LookupQualifiedName(R, DC, SS); + SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType); - if (!R.empty()) + if (!R.empty() || R.wasNotFoundInCurrentInstantiation()) return false; DeclarationName Typo = R.getLookupName(); SourceLocation TypoLoc = R.getNameLoc(); + // Recompute the lookup context. + DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS) + : SemaRef.computeDeclContext(RTy); struct QueryState { Sema &SemaRef; @@ -788,7 +766,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, << Typo << DC << DroppedSpecifier << SS.getRange()); } else { - SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange; + SemaRef.Diag(TypoLoc, diag::err_no_member) + << Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange); } }, [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable { @@ -814,34 +793,25 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, Decl *ObjCImpDecl, bool HasTemplateArgs, SourceLocation TemplateKWLoc); -ExprResult -Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, - SourceLocation OpLoc, bool IsArrow, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs, - const Scope *S, - ActOnMemberAccessExtraArgs *ExtraArgs) { - if (BaseType->isDependentType() || - (SS.isSet() && isDependentScopeSpecifier(SS)) || - NameInfo.getName().isDependentName()) - return ActOnDependentMemberExpr(Base, BaseType, - IsArrow, OpLoc, - SS, TemplateKWLoc, FirstQualifierInScope, - NameInfo, TemplateArgs); - +ExprResult Sema::BuildMemberReferenceExpr( + Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + ActOnMemberAccessExtraArgs *ExtraArgs) { LookupResult R(*this, NameInfo, LookupMemberName); + if (SS.isInvalid()) + return ExprError(); + // Implicit member accesses. if (!Base) { TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->castAs()->getPointeeType(); - if (LookupMemberExprInRecord( - *this, R, nullptr, RecordTy->castAs(), OpLoc, IsArrow, - SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) + if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow, + SS, TemplateArgs != nullptr, TemplateKWLoc, + TE)) return ExprError(); if (TE) return TE; @@ -968,19 +938,6 @@ BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow, NameInfo.getLoc()); } -MemberExpr *Sema::BuildMemberExpr( - Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, - SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, - bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, - QualType Ty, ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs) { - NestedNameSpecifierLoc NNS = - SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(); - return BuildMemberExpr(Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member, - FoundDecl, HadMultipleCandidates, MemberNameInfo, Ty, - VK, OK, TemplateArgs); -} - MemberExpr *Sema::BuildMemberExpr( Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, @@ -1033,6 +990,17 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, const Scope *S, bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { + assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid"); + // If the member wasn't found in the current instantiation, or if the + // arrow operator was used with a dependent non-pointer object expression, + // build a CXXDependentScopeMemberExpr. + if (R.wasNotFoundInCurrentInstantiation() || + (IsArrow && !BaseExprType->isPointerType() && + BaseExprType->isDependentType())) + return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, + TemplateKWLoc, FirstQualifierInScope, + R.getLookupNameInfo(), TemplateArgs); + QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); @@ -1040,6 +1008,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } R.setBaseObjectType(BaseType); + assert((SS.isEmpty() + ? !BaseType->isDependentType() || computeDeclContext(BaseType) + : !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) && + "dependent lookup context that isn't the current instantiation?"); + // C++1z [expr.ref]p2: // For the first option (dot) the first expression shall be a glvalue [...] if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) { @@ -1068,40 +1041,39 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, << isa(FD); if (R.empty()) { - // Rederive where we looked up. - DeclContext *DC = (SS.isSet() - ? computeDeclContext(SS, false) - : BaseType->castAs()->getDecl()); - - if (ExtraArgs) { - ExprResult RetryExpr; - if (!IsArrow && BaseExpr) { - SFINAETrap Trap(*this, true); - ParsedType ObjectType; - bool MayBePseudoDestructor = false; - RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr, - OpLoc, tok::arrow, ObjectType, - MayBePseudoDestructor); - if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) { - CXXScopeSpec TempSS(SS); - RetryExpr = ActOnMemberAccessExpr( - ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS, - TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl); - } - if (Trap.hasErrorOccurred()) - RetryExpr = ExprError(); - } - if (RetryExpr.isUsable()) { - Diag(OpLoc, diag::err_no_member_overloaded_arrow) - << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->"); - return RetryExpr; + ExprResult RetryExpr = ExprError(); + if (ExtraArgs && !IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) { + SFINAETrap Trap(*this, true); + ParsedType ObjectType; + bool MayBePseudoDestructor = false; + RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr, OpLoc, + tok::arrow, ObjectType, + MayBePseudoDestructor); + if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) { + CXXScopeSpec TempSS(SS); + RetryExpr = ActOnMemberAccessExpr( + ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS, + TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl); } + if (Trap.hasErrorOccurred()) + RetryExpr = ExprError(); } - Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC - << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); - return ExprError(); + // Rederive where we looked up. + DeclContext *DC = + (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType)); + assert(DC); + + if (RetryExpr.isUsable()) + Diag(OpLoc, diag::err_no_member_overloaded_arrow) + << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->"); + else + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << DC + << (SS.isSet() + ? SS.getRange() + : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange())); + return RetryExpr; } // Diagnose lookups that find only declarations from a non-base @@ -1186,7 +1158,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, OpLoc); if (VarDecl *Var = dyn_cast(MemberDecl)) { - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, + SS.getWithLocInContext(Context), TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); @@ -1203,17 +1176,18 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, type = MemberFn->getType(); } - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, + SS.getWithLocInContext(Context), TemplateKWLoc, MemberFn, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, type, valueKind, OK_Ordinary); } assert(!isa(MemberDecl) && "member function not C++ method?"); if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum, - FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Enum->getType(), VK_PRValue, - OK_Ordinary); + return BuildMemberExpr( + BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext(Context), + TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false, + MemberNameInfo, Enum->getType(), VK_PRValue, OK_Ordinary); } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { @@ -1237,7 +1211,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (!Var->getTemplateSpecializationKind()) Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc); - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, + SS.getWithLocInContext(Context), TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary, TemplateArgs); @@ -1330,7 +1305,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, return ExprError(); QualType BaseType = BaseExpr.get()->getType(); - assert(!BaseType->isDependentType()); DeclarationName MemberName = R.getLookupName(); SourceLocation MemberLoc = R.getNameLoc(); @@ -1342,29 +1316,31 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (IsArrow) { if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); - else if (const ObjCObjectPointerType *Ptr - = BaseType->getAs()) + else if (const ObjCObjectPointerType *Ptr = + BaseType->getAs()) BaseType = Ptr->getPointeeType(); - else if (BaseType->isRecordType()) { - // Recover from arrow accesses to records, e.g.: - // struct MyRecord foo; - // foo->bar - // This is actually well-formed in C++ if MyRecord has an - // overloaded operator->, but that should have been dealt with - // by now--or a diagnostic message already issued if a problem - // was encountered while looking for the overloaded operator->. - if (!S.getLangOpts().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "."); + else if (!BaseType->isDependentType()) { + if (BaseType->isRecordType()) { + // Recover from arrow accesses to records, e.g.: + // struct MyRecord foo; + // foo->bar + // This is actually well-formed in C++ if MyRecord has an + // overloaded operator->, but that should have been dealt with + // by now--or a diagnostic message already issued if a problem + // was encountered while looking for the overloaded operator->. + if (!S.getLangOpts().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() + << FixItHint::CreateReplacement(OpLoc, "."); + } + IsArrow = false; + } else if (BaseType->isFunctionType()) { + goto fail; + } else { + S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr.get()->getSourceRange(); + return ExprError(); } - IsArrow = false; - } else if (BaseType->isFunctionType()) { - goto fail; - } else { - S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr.get()->getSourceRange(); - return ExprError(); } } @@ -1384,10 +1360,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } // Handle field access to simple records. - if (const RecordType *RTy = BaseType->getAs()) { + if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) { TypoExpr *TE = nullptr; - if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS, - HasTemplateArgs, TemplateKWLoc, TE)) + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, + SS, HasTemplateArgs, TemplateKWLoc, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that @@ -1810,7 +1786,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); - DeclarationName Name = NameInfo.getName(); bool IsArrow = (OpKind == tok::arrow); if (getLangOpts().HLSL && IsArrow) @@ -1824,13 +1799,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, if (Result.isInvalid()) return ExprError(); Base = Result.get(); - if (Base->getType()->isDependentType() || Name.isDependentName() || - isDependentScopeSpecifier(SS)) { - return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS, - TemplateKWLoc, FirstQualifierInScope, - NameInfo, TemplateArgs); - } - ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, @@ -1949,10 +1917,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, } } - return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS, - /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, - /*HadMultipleCandidates=*/false, MemberNameInfo, - MemberType, VK, OK); + return BuildMemberExpr( + Base.get(), IsArrow, OpLoc, SS.getWithLocInContext(Context), + /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, + /*HadMultipleCandidates=*/false, MemberNameInfo, MemberType, VK, OK); } /// Builds an implicit member access expression. The current context diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 771a56c1bc21b..c00f0eac3b09e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7754,9 +7754,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, break; } - case Stmt::OMPArraySectionExprClass: { + case Stmt::ArraySectionExprClass: { visitLocalsRetainedByInitializer(Path, - cast(Init)->getBase(), + cast(Init)->getBase(), Visit, true, EnableLifetimeWarnings); break; } @@ -8341,8 +8341,17 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, << Entity.getType()->isReferenceType() << CLE->getInitializer() << 2 << DiagRange; } else { - Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) - << Entity.getType()->isReferenceType() << DiagRange; + // P2748R5: Disallow Binding a Returned Glvalue to a Temporary. + // [stmt.return]/p6: In a function whose return type is a reference, + // other than an invented function for std::is_convertible ([meta.rel]), + // a return statement that binds the returned reference to a temporary + // expression ([class.temporary]) is ill-formed. + if (getLangOpts().CPlusPlus26 && Entity.getType()->isReferenceType()) + Diag(DiagLoc, diag::err_ret_local_temp_ref) + << Entity.getType()->isReferenceType() << DiagRange; + else + Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) + << Entity.getType()->isReferenceType() << DiagRange; } break; } @@ -10801,8 +10810,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // FIXME: Perform "exact type" matching first, per CWG discussion? // Or implement this via an implied 'T(T) -> T' deduction guide? - // FIXME: Do we need/want a std::initializer_list special case? - // Look up deduction guides, including those synthesized from constructors. // // C++1z [over.match.class.deduct]p1: diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 9355dcd1707c3..80e672166c9a3 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1333,6 +1333,31 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (DeclContext *DC = PreS->getEntity()) DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC); } + // C++23 [temp.dep.general]p2: + // The component name of an unqualified-id is dependent if + // - it is a conversion-function-id whose conversion-type-id + // is dependent, or + // - it is operator= and the current class is a templated entity, or + // - the unqualified-id is the postfix-expression in a dependent call. + if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + + // If this is the name of an implicitly-declared special member function, + // go through the scope stack to implicitly declare + if (isImplicitlyDeclaredMemberFunctionName(Name)) { + for (Scope *PreS = S; PreS; PreS = PreS->getParent()) + if (DeclContext *DC = PreS->getEntity()) { + if (DC->isDependentContext() && isa(DC) && + Name.getCXXOverloadedOperator() == OO_Equal) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC); + } + } // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. @@ -2497,10 +2522,33 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, } } QL(LookupCtx); + CXXRecordDecl *LookupRec = dyn_cast(LookupCtx); + // FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent + // if it's a dependent conversion-function-id or operator= where the current + // class is a templated entity. This should be handled in LookupName. + if (!InUnqualifiedLookup && !R.isForRedeclaration()) { + // C++23 [temp.dep.type]p5: + // A qualified name is dependent if + // - it is a conversion-function-id whose conversion-type-id + // is dependent, or + // - [...] + // - its lookup context is the current instantiation and it + // is operator=, or + // - [...] + if (DeclarationName Name = R.getLookupName(); + (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) || + (Name.getCXXOverloadedOperator() == OO_Equal && LookupRec && + LookupRec->isDependentContext())) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + } + if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); - if (isa(LookupCtx)) - R.setNamingClass(cast(LookupCtx)); + if (LookupRec) + R.setNamingClass(LookupRec); return true; } @@ -2522,7 +2570,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. - CXXRecordDecl *LookupRec = dyn_cast(LookupCtx); if (!LookupRec || !LookupRec->getDefinition()) return false; @@ -2769,38 +2816,54 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, - bool AllowBuiltinCreation, bool EnteringContext) { - if (SS && SS->isInvalid()) { - // When the scope specifier is invalid, don't even look for - // anything. + QualType ObjectType, bool AllowBuiltinCreation, + bool EnteringContext) { + // When the scope specifier is invalid, don't even look for anything. + if (SS && SS->isInvalid()) return false; - } - if (SS && SS->isSet()) { - NestedNameSpecifier *NNS = SS->getScopeRep(); - if (NNS->getKind() == NestedNameSpecifier::Super) + // Determine where to perform name lookup + DeclContext *DC = nullptr; + bool IsDependent = false; + if (!ObjectType.isNull()) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert((!SS || SS->isEmpty()) && + "ObjectType and scope specifier cannot coexist"); + DC = computeDeclContext(ObjectType); + IsDependent = !DC && ObjectType->isDependentType(); + assert(((!DC && ObjectType->isDependentType()) || + !ObjectType->isIncompleteType() || !ObjectType->getAs() || + ObjectType->castAs()->isBeingDefined()) && + "Caller should have completed object type"); + } else if (SS && SS->isNotEmpty()) { + if (NestedNameSpecifier *NNS = SS->getScopeRep(); + NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); - - if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { - // We have resolved the scope specifier to a particular declaration - // contex, and will perform name lookup in that context. + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + if ((DC = computeDeclContext(*SS, EnteringContext))) { + // The declaration context must be complete. if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; - R.setContextRange(SS->getRange()); - return LookupQualifiedName(R, DC); } + IsDependent = !DC && isDependentScopeSpecifier(*SS); + } else { + // Perform unqualified name lookup starting in the given scope. + return LookupName(R, S, AllowBuiltinCreation); + } + // If we were able to compute a declaration context, perform qualified name + // lookup in that context. + if (DC) + return LookupQualifiedName(R, DC); + else if (IsDependent) // We could not resolve the scope specified to a specific declaration // context, which means that SS refers to an unknown specialization. // Name lookup can't find anything in this case. R.setNotFoundInCurrentInstantiation(); - R.setContextRange(SS->getRange()); - return false; - } - - // Perform unqualified name lookup starting in the given scope. - return LookupName(R, S, AllowBuiltinCreation); + return false; } /// Perform qualified name lookup into all base classes of the given @@ -5069,8 +5132,9 @@ static void LookupPotentialTypoResult(Sema &SemaRef, return; } - SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, - EnteringContext); + SemaRef.LookupParsedName(Res, S, SS, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/false, EnteringContext); // Fake ivar lookup; this should really be part of // LookupParsedName. diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index ba69e71e30a18..3ea81e0497c20 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -103,6 +103,18 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, default: return false; } + case OpenACCClauseKind::Private: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } default: // Do nothing so we can go to the 'unimplemented' diagnostic instead. return true; @@ -303,6 +315,21 @@ SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], Clause.getEndLoc()); } + case OpenACCClauseKind::Private: { + // Restrictions only properly implemented on 'compute' constructs, and + // 'compute' constructs are the only construct that can do anything with + // this yet, so skip/treat as unimplemented in this case. + if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind())) + break; + + // ActOnVar ensured that everything is a valid variable reference, so there + // really isn't anything to do here. GCC does some duplicate-finding, though + // it isn't apparent in the standard where this is justified. + + return OpenACCPrivateClause::Create( + getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(), + Clause.getVarList(), Clause.getEndLoc()); + } default: break; } @@ -423,6 +450,67 @@ ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK, return IntExpr; } +ExprResult SemaOpenACC::ActOnVar(Expr *VarExpr) { + // We still need to retain the array subscript/subarray exprs, so work on a + // copy. + Expr *CurVarExpr = VarExpr->IgnoreParenImpCasts(); + + // Sub-arrays/subscript-exprs are fine as long as the base is a + // VarExpr/MemberExpr. So strip all of those off. + while (isa(CurVarExpr)) { + if (auto *SubScrpt = dyn_cast(CurVarExpr)) + CurVarExpr = SubScrpt->getBase()->IgnoreParenImpCasts(); + else + CurVarExpr = + cast(CurVarExpr)->getBase()->IgnoreParenImpCasts(); + } + + // References to a VarDecl are fine. + if (const auto *DRE = dyn_cast(CurVarExpr)) { + if (isa( + DRE->getDecl()->getCanonicalDecl())) + return VarExpr; + } + + // A MemberExpr that references a Field is valid. + if (const auto *ME = dyn_cast(CurVarExpr)) { + if (isa(ME->getMemberDecl()->getCanonicalDecl())) + return VarExpr; + } + + // Referring to 'this' is always OK. + if (isa(CurVarExpr)) + return VarExpr; + + // Nothing really we can do here, as these are dependent. So just return they + // are valid. + if (isa(CurVarExpr)) + return VarExpr; + + // There isn't really anything we can do in the case of a recovery expr, so + // skip the diagnostic rather than produce a confusing diagnostic. + if (isa(CurVarExpr)) + return ExprError(); + + Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref); + return ExprError(); +} + +ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc, + Expr *LowerBound, + SourceLocation ColonLoc, + Expr *Length, + SourceLocation RBLoc) { + ASTContext &Context = getASTContext(); + + // TODO OpenACC: We likely have to reproduce a lot of the same logic from the + // OMP version of this, but at the moment we don't have a good way to test it, + // so for now we'll just create the node. + return new (Context) + ArraySectionExpr(Base, LowerBound, Length, Context.ArraySectionTy, + VK_LValue, OK_Ordinary, ColonLoc, RBLoc); +} + bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc) { return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 190fb3b8d8ec1..8ad7a7c40d533 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -2232,7 +2232,7 @@ bool SemaOpenMP::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, dyn_cast(Last->getAssociatedExpression()); if ((UO && UO->getOpcode() == UO_Deref) || isa(Last->getAssociatedExpression()) || - isa(Last->getAssociatedExpression()) || + isa(Last->getAssociatedExpression()) || isa(EI->getAssociatedExpression()) || isa(Last->getAssociatedExpression())) { IsVariableAssociatedWithSection = true; @@ -3063,7 +3063,9 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope, OpenMPDirectiveKind Kind) { ASTContext &Context = getASTContext(); LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName); - SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true); + SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/true); if (Lookup.isAmbiguous()) return ExprError(); @@ -3886,7 +3888,7 @@ class DSAAttrChecker final : public StmtVisitor { MappableComponent &MC) { return MC.getAssociatedDeclaration() == nullptr && - (isa( + (isa( MC.getAssociatedExpression()) || isa( MC.getAssociatedExpression()) || @@ -4064,7 +4066,7 @@ class DSAAttrChecker final : public StmtVisitor { // Do both expressions have the same kind? if (CCI->getAssociatedExpression()->getStmtClass() != SC.getAssociatedExpression()->getStmtClass()) - if (!((isa( + if (!((isa( SC.getAssociatedExpression()) || isa( SC.getAssociatedExpression())) && @@ -5430,9 +5432,9 @@ static std::pair getPrivateItem(Sema &S, Expr *&RefExpr, Base = TempASE->getBase()->IgnoreParenImpCasts(); RefExpr = Base; IsArrayExpr = ArraySubscript; - } else if (auto *OASE = dyn_cast_or_null(RefExpr)) { + } else if (auto *OASE = dyn_cast_or_null(RefExpr)) { Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempOASE = dyn_cast(Base)) + while (auto *TempOASE = dyn_cast(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); @@ -6062,10 +6064,10 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack, // Array section - need to check for the mapping of the array section // element. QualType CanonType = E->getType().getCanonicalType(); - if (CanonType->isSpecificBuiltinType(BuiltinType::OMPArraySection)) { - const auto *OASE = cast(E->IgnoreParenImpCasts()); + if (CanonType->isSpecificBuiltinType(BuiltinType::ArraySection)) { + const auto *OASE = cast(E->IgnoreParenImpCasts()); QualType BaseType = - OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + ArraySectionExpr::getBaseOriginalType(OASE->getBase()); QualType ElemType; if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) ElemType = ATy->getElementType(); @@ -7409,7 +7411,8 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( const IdentifierInfo *BaseII = D.getIdentifier(); LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(), Sema::LookupOrdinaryName); - SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); + SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec(), + /*ObjectType=*/QualType()); TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D); QualType FType = TInfo->getType(); @@ -19313,7 +19316,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, if (S) { LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); Lookup.suppressDiagnostics(); - while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) { + while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec, + /*ObjectType=*/QualType())) { NamedDecl *D = Lookup.getRepresentativeDecl(); do { S = S->getParent(); @@ -19515,7 +19519,7 @@ struct ReductionData { } // namespace static bool checkOMPArraySectionConstantForReduction( - ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement, + ASTContext &Context, const ArraySectionExpr *OASE, bool &SingleElement, SmallVectorImpl &ArraySizes) { const Expr *Length = OASE->getLength(); if (Length == nullptr) { @@ -19542,7 +19546,7 @@ static bool checkOMPArraySectionConstantForReduction( // We require length = 1 for all array sections except the right-most to // guarantee that the memory region is contiguous and has no holes in it. - while (const auto *TempOASE = dyn_cast(Base)) { + while (const auto *TempOASE = dyn_cast(Base)) { Length = TempOASE->getLength(); if (Length == nullptr) { // For array sections of the form [1:] or [:], we would need to analyze @@ -19747,12 +19751,12 @@ static bool actOnOMPReductionKindClause( Expr *TaskgroupDescriptor = nullptr; QualType Type; auto *ASE = dyn_cast(RefExpr->IgnoreParens()); - auto *OASE = dyn_cast(RefExpr->IgnoreParens()); + auto *OASE = dyn_cast(RefExpr->IgnoreParens()); if (ASE) { Type = ASE->getType().getNonReferenceType(); } else if (OASE) { QualType BaseType = - OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + ArraySectionExpr::getBaseOriginalType(OASE->getBase()); if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) Type = ATy->getElementType(); else @@ -21286,10 +21290,10 @@ OMPClause *SemaOpenMP::ActOnOpenMPDependClause( // List items used in depend clauses cannot be zero-length array // sections. QualType ExprTy = RefExpr->getType().getNonReferenceType(); - const auto *OASE = dyn_cast(SimpleExpr); + const auto *OASE = dyn_cast(SimpleExpr); if (OASE) { QualType BaseType = - OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + ArraySectionExpr::getBaseOriginalType(OASE->getBase()); if (BaseType.isNull()) return nullptr; if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) @@ -21348,7 +21352,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDependClause( Res = SemaRef.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); } - if (!Res.isUsable() && !isa(SimpleExpr) && + if (!Res.isUsable() && !isa(SimpleExpr) && !isa(SimpleExpr)) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) << (getLangOpts().OpenMP >= 50 ? 1 : 0) @@ -21449,7 +21453,7 @@ static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, const Expr *E, QualType BaseQTy) { - const auto *OASE = dyn_cast(E); + const auto *OASE = dyn_cast(E); // If this is an array subscript, it refers to the whole size if the size of // the dimension is constant and equals 1. Also, an array section assumes the @@ -21507,7 +21511,7 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, const Expr *E, QualType BaseQTy) { - const auto *OASE = dyn_cast(E); + const auto *OASE = dyn_cast(E); // An array subscript always refer to a single element. Also, an array section // assumes the format of an array subscript if no colon is used. @@ -21722,14 +21726,14 @@ class MapBaseChecker final : public StmtVisitor { return RelevantExpr || Visit(E); } - bool VisitOMPArraySectionExpr(OMPArraySectionExpr *OASE) { + bool VisitArraySectionExpr(ArraySectionExpr *OASE) { // After OMP 5.0 Array section in reduction clause will be implicitly // mapped assert(!(SemaRef.getLangOpts().OpenMP < 50 && NoDiagnose) && "Array sections cannot be implicitly mapped."); Expr *E = OASE->getBase()->IgnoreParenImpCasts(); QualType CurType = - OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + ArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] // If the type of a list item is a reference to a type T then the type @@ -21902,7 +21906,7 @@ static const Expr *checkMapClauseExpressionBase( auto CE = CurComponents.rend(); for (; CI != CE; ++CI) { const auto *OASE = - dyn_cast(CI->getAssociatedExpression()); + dyn_cast(CI->getAssociatedExpression()); if (!OASE) continue; if (OASE && OASE->getLength()) @@ -21972,10 +21976,10 @@ static bool checkMapConflicts( // variable in map clauses of the same construct. if (CurrentRegionOnly && (isa(CI->getAssociatedExpression()) || - isa(CI->getAssociatedExpression()) || + isa(CI->getAssociatedExpression()) || isa(CI->getAssociatedExpression())) && (isa(SI->getAssociatedExpression()) || - isa(SI->getAssociatedExpression()) || + isa(SI->getAssociatedExpression()) || isa(SI->getAssociatedExpression()))) { SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(), diag::err_omp_multiple_array_items_in_map_clause) @@ -22003,11 +22007,10 @@ static bool checkMapConflicts( if (const auto *ASE = dyn_cast(SI->getAssociatedExpression())) { Type = ASE->getBase()->IgnoreParenImpCasts()->getType(); - } else if (const auto *OASE = dyn_cast( + } else if (const auto *OASE = dyn_cast( SI->getAssociatedExpression())) { const Expr *E = OASE->getBase()->IgnoreParenImpCasts(); - Type = - OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + Type = ArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); } else if (const auto *OASE = dyn_cast( SI->getAssociatedExpression())) { Type = OASE->getBase()->getType()->getPointeeType(); @@ -22183,7 +22186,8 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName); Lookup.suppressDiagnostics(); if (S) { - while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) { + while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec, + /*ObjectType=*/QualType())) { NamedDecl *D = Lookup.getRepresentativeDecl(); while (S && !S->isDeclScope(D)) S = S->getParent(); @@ -22482,13 +22486,13 @@ static void checkMappableExpressionList( (void)I; QualType Type; auto *ASE = dyn_cast(VE->IgnoreParens()); - auto *OASE = dyn_cast(VE->IgnoreParens()); + auto *OASE = dyn_cast(VE->IgnoreParens()); auto *OAShE = dyn_cast(VE->IgnoreParens()); if (ASE) { Type = ASE->getType().getNonReferenceType(); } else if (OASE) { QualType BaseType = - OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + ArraySectionExpr::getBaseOriginalType(OASE->getBase()); if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) Type = ATy->getElementType(); else @@ -23500,7 +23504,9 @@ void SemaOpenMP::DiagnoseUnterminatedOpenMPDeclareTarget() { NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName( Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) { LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName); - SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true); + SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/true); if (Lookup.isAmbiguous()) return nullptr; @@ -23957,7 +23963,7 @@ SemaOpenMP::ActOnOpenMPUseDeviceAddrClause(ArrayRef VarList, MVLI.VarBaseDeclarations.push_back(D); MVLI.VarComponents.emplace_back(); Expr *Component = SimpleRefExpr; - if (VD && (isa(RefExpr->IgnoreParenImpCasts()) || + if (VD && (isa(RefExpr->IgnoreParenImpCasts()) || isa(RefExpr->IgnoreParenImpCasts()))) Component = SemaRef.DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get(); @@ -24107,7 +24113,7 @@ SemaOpenMP::ActOnOpenMPHasDeviceAddrClause(ArrayRef VarList, // against other clauses later on. Expr *Component = SimpleRefExpr; auto *VD = dyn_cast(D); - if (VD && (isa(RefExpr->IgnoreParenImpCasts()) || + if (VD && (isa(RefExpr->IgnoreParenImpCasts()) || isa(RefExpr->IgnoreParenImpCasts()))) Component = SemaRef.DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get(); @@ -24521,7 +24527,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAffinityClause( Sema::TentativeAnalysisScope Trap(SemaRef); Res = SemaRef.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, SimpleExpr); } - if (!Res.isUsable() && !isa(SimpleExpr) && + if (!Res.isUsable() && !isa(SimpleExpr) && !isa(SimpleExpr)) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) << 1 << 0 << RefExpr->getSourceRange(); @@ -24634,7 +24640,7 @@ ExprResult SemaOpenMP::ActOnOMPArraySectionExpr( Expr *Stride, SourceLocation RBLoc) { ASTContext &Context = getASTContext(); if (Base->hasPlaceholderType() && - !Base->hasPlaceholderType(BuiltinType::OMPArraySection)) { + !Base->hasPlaceholderType(BuiltinType::ArraySection)) { ExprResult Result = SemaRef.CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); @@ -24674,13 +24680,13 @@ ExprResult SemaOpenMP::ActOnOMPArraySectionExpr( (LowerBound->isTypeDependent() || LowerBound->isValueDependent())) || (Length && (Length->isTypeDependent() || Length->isValueDependent())) || (Stride && (Stride->isTypeDependent() || Stride->isValueDependent()))) { - return new (Context) OMPArraySectionExpr( + return new (Context) ArraySectionExpr( Base, LowerBound, Length, Stride, Context.DependentTy, VK_LValue, OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc); } // Perform default conversions. - QualType OriginalTy = OMPArraySectionExpr::getBaseOriginalType(Base); + QualType OriginalTy = ArraySectionExpr::getBaseOriginalType(Base); QualType ResultTy; if (OriginalTy->isAnyPointerType()) { ResultTy = OriginalTy->getPointeeType(); @@ -24803,14 +24809,14 @@ ExprResult SemaOpenMP::ActOnOMPArraySectionExpr( } } - if (!Base->hasPlaceholderType(BuiltinType::OMPArraySection)) { + if (!Base->hasPlaceholderType(BuiltinType::ArraySection)) { ExprResult Result = SemaRef.DefaultFunctionArrayLvalueConversion(Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); } - return new (Context) OMPArraySectionExpr( - Base, LowerBound, Length, Stride, Context.OMPArraySectionTy, VK_LValue, + return new (Context) ArraySectionExpr( + Base, LowerBound, Length, Stride, Context.ArraySectionTy, VK_LValue, OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc); } diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 95b7f28984d5b..c481a24acfaf6 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -524,16 +524,14 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable); } else if (PragmaName == "unroll") { // #pragma unroll N - if (ValueExpr && !ValueExpr->isValueDependent()) { - llvm::APSInt ValueAPS; - ExprResult R = S.VerifyIntegerConstantExpression(ValueExpr, &ValueAPS); - assert(!R.isInvalid() && "unroll count value must be a valid value, it's " - "should be checked in Sema::CheckLoopHintExpr"); - (void)R; - // The values of 0 and 1 block any unrolling of the loop. - if (ValueAPS.isZero() || ValueAPS.isOne()) - SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Disable); - else + if (ValueExpr) { + if (!ValueExpr->isValueDependent()) { + auto Value = ValueExpr->EvaluateKnownConstInt(S.getASTContext()); + if (Value.isZero() || Value.isOne()) + SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable); + else + SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric); + } else SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric); } else SetHints(LoopHintAttr::Unroll, LoopHintAttr::Enable); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index bbcb7c33a9857..7f18631c6096d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -210,10 +210,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S, AssumedTemplateKind AssumedTemplate; LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, - MemberOfUnknownSpecialization, SourceLocation(), + /*RequiredTemplate=*/SourceLocation(), &AssumedTemplate, /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; + MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation(); if (AssumedTemplate != AssumedTemplateKind::None) { TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName)); @@ -320,15 +321,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, CXXScopeSpec &SS, ParsedTemplateTy *Template /*=nullptr*/) { - bool MemberOfUnknownSpecialization = false; - // We could use redeclaration lookup here, but we don't need to: the // syntactic form of a deduction guide is enough to identify it even // if we can't look up the template name at all. LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(), - /*EnteringContext*/ false, - MemberOfUnknownSpecialization)) + /*EnteringContext*/ false)) return false; if (R.empty()) return false; @@ -374,11 +372,8 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, return true; } -bool Sema::LookupTemplateName(LookupResult &Found, - Scope *S, CXXScopeSpec &SS, - QualType ObjectType, - bool EnteringContext, - bool &MemberOfUnknownSpecialization, +bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, + QualType ObjectType, bool EnteringContext, RequiredTemplateKind RequiredTemplate, AssumedTemplateKind *ATK, bool AllowTypoCorrection) { @@ -391,7 +386,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, Found.setTemplateNameLookup(true); // Determine where to perform name lookup - MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; bool IsDependent = false; if (!ObjectType.isNull()) { @@ -548,7 +542,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); if (Found.empty()) { if (IsDependent) { - MemberOfUnknownSpecialization = true; + Found.setNotFoundInCurrentInstantiation(); return false; } @@ -5595,11 +5589,9 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); - bool MemberOfUnknownSpecialization; LookupResult R(*this, NameInfo, LookupOrdinaryName); if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(), - /*Entering*/false, MemberOfUnknownSpecialization, - TemplateKWLoc)) + /*Entering*/ false, TemplateKWLoc)) return ExprError(); if (R.isAmbiguous()) @@ -5720,14 +5712,13 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); LookupResult R(*this, DNI.getName(), Name.getBeginLoc(), LookupOrdinaryName); - bool MOUS; // Tell LookupTemplateName that we require a template so that it diagnoses // cases where it finds a non-template. RequiredTemplateKind RTK = TemplateKWLoc.isValid() ? RequiredTemplateKind(TemplateKWLoc) : TemplateNameIsRequired; - if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS, - RTK, nullptr, /*AllowTypoCorrection=*/false) && + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, RTK, + /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) && !R.isAmbiguous()) { if (LookupCtx) Diag(Name.getBeginLoc(), diag::err_no_member) @@ -5816,7 +5807,7 @@ bool Sema::CheckTemplateTypeArgument( if (auto *II = NameInfo.getName().getAsIdentifierInfo()) { LookupResult Result(*this, NameInfo, LookupOrdinaryName); - LookupParsedName(Result, CurScope, &SS); + LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType()); if (Result.getAsSingle() || Result.getResultKind() == @@ -7706,7 +7697,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // FIXME: The language rules don't say what happens in this case. // FIXME: We get an opaque dependent type out of decltype(auto) if the // expression is merely instantiation-dependent; is this enough? - if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) { + if (Arg->isTypeDependent()) { auto *AT = dyn_cast(DeducedT); if (AT && AT->isDecltypeAuto()) { SugaredConverted = TemplateArgument(Arg); @@ -8438,10 +8429,9 @@ void Sema::NoteTemplateParameterLocation(const NamedDecl &Decl) { /// declaration and the type of its corresponding non-type template /// parameter, produce an expression that properly refers to that /// declaration. -ExprResult -Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, - QualType ParamType, - SourceLocation Loc) { +ExprResult Sema::BuildExpressionFromDeclTemplateArgument( + const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc, + NamedDecl *TemplateParam) { // C++ [temp.param]p8: // // A non-type template-parameter of type "array of T" or @@ -8508,6 +8498,18 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, } else { assert(ParamType->isReferenceType() && "unexpected type for decl template argument"); + if (NonTypeTemplateParmDecl *NTTP = + dyn_cast_if_present(TemplateParam)) { + QualType TemplateParamType = NTTP->getType(); + const AutoType *AT = TemplateParamType->getAs(); + if (AT && AT->isDecltypeAuto()) { + RefExpr = new (getASTContext()) SubstNonTypeTemplateParmExpr( + ParamType->getPointeeType(), RefExpr.get()->getValueKind(), + RefExpr.get()->getExprLoc(), RefExpr.get(), VD, NTTP->getIndex(), + /*PackIndex=*/std::nullopt, + /*RefParam=*/true); + } + } } // At this point we should have the right value category. @@ -11179,7 +11181,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, : TSK_ExplicitInstantiationDeclaration; LookupResult Previous(*this, NameInfo, LookupOrdinaryName); - LookupParsedName(Previous, S, &D.getCXXScopeSpec()); + LookupParsedName(Previous, S, &D.getCXXScopeSpec(), + /*ObjectType=*/QualType()); if (!R->isFunctionType()) { // C++ [temp.explicit]p1: diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index c3815bca03855..e93f7bd842e44 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2639,7 +2639,8 @@ static bool isSameTemplateArg(ASTContext &Context, /// argument. TemplateArgumentLoc Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, - QualType NTTPType, SourceLocation Loc) { + QualType NTTPType, SourceLocation Loc, + NamedDecl *TemplateParam) { switch (Arg.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't get a NULL template argument here"); @@ -2651,7 +2652,8 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, case TemplateArgument::Declaration: { if (NTTPType.isNull()) NTTPType = Arg.getParamTypeForDecl(); - Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc, + TemplateParam) .getAs(); return TemplateArgumentLoc(TemplateArgument(E), E); } @@ -2718,8 +2720,8 @@ static bool ConvertDeducedTemplateArgument( // Convert the deduced template argument into a template // argument that we can check, almost as if the user had written // the template argument explicitly. - TemplateArgumentLoc ArgLoc = - S.getTrivialTemplateArgumentLoc(Arg, QualType(), Info.getLocation()); + TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc( + Arg, QualType(), Info.getLocation(), Param); // Check the template argument, converting it as necessary. return S.CheckTemplateArgument( diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 7196337599252..9510f3d7f860c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2174,13 +2174,25 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { // Generate error if there is a problem with the value. if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation(), - LH->getOption() == LoopHintAttr::UnrollCount)) + LH->getSemanticSpelling() == + LoopHintAttr::Pragma_unroll)) return LH; + LoopHintAttr::OptionType Option = LH->getOption(); + LoopHintAttr::LoopHintState State = LH->getState(); + + llvm::APSInt ValueAPS = + TransformedExpr->EvaluateKnownConstInt(getSema().getASTContext()); + // The values of 0 and 1 block any unrolling of the loop. + if (ValueAPS.isZero() || ValueAPS.isOne()) { + Option = LoopHintAttr::Unroll; + State = LoopHintAttr::Disable; + } + // Create new LoopHintValueAttr with integral expression in place of the // non-type template parameter. - return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(), - LH->getState(), TransformedExpr, *LH); + return LoopHintAttr::CreateImplicit(getSema().Context, Option, State, + TransformedExpr, *LH); } const NoInlineAttr *TemplateInstantiator::TransformStmtNoInlineAttr( const Stmt *OrigS, const Stmt *InstS, const NoInlineAttr *A) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 66f743a574e05..19a46a406f06e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5702,6 +5702,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ParmVarDecl *Parm = Function->getParamDecl(0); TypeSourceInfo *NewParmSI = IR.TransformType(Parm->getTypeSourceInfo()); + assert(NewParmSI && "Type transformation failed."); Parm->setType(NewParmSI->getType()); Parm->setTypeSourceInfo(NewParmSI); }; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index e66784d0d2ede..86fb0f50d9e46 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2792,15 +2792,23 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildOMPArraySectionExpr(Expr *Base, SourceLocation LBracketLoc, - Expr *LowerBound, - SourceLocation ColonLocFirst, - SourceLocation ColonLocSecond, - Expr *Length, Expr *Stride, - SourceLocation RBracketLoc) { - return getSema().OpenMP().ActOnOMPArraySectionExpr( - Base, LBracketLoc, LowerBound, ColonLocFirst, ColonLocSecond, Length, - Stride, RBracketLoc); + ExprResult RebuildArraySectionExpr(bool IsOMPArraySection, Expr *Base, + SourceLocation LBracketLoc, + Expr *LowerBound, + SourceLocation ColonLocFirst, + SourceLocation ColonLocSecond, + Expr *Length, Expr *Stride, + SourceLocation RBracketLoc) { + if (IsOMPArraySection) + return getSema().OpenMP().ActOnOMPArraySectionExpr( + Base, LBracketLoc, LowerBound, ColonLocFirst, ColonLocSecond, Length, + Stride, RBracketLoc); + + assert(Stride == nullptr && !ColonLocSecond.isValid() && + "Stride/second colon not allowed for OpenACC"); + + return getSema().OpenACC().ActOnArraySectionExpr( + Base, LBracketLoc, LowerBound, ColonLocFirst, Length, RBracketLoc); } /// Build a new array shaping expression. @@ -6677,6 +6685,10 @@ TreeTransform::TransformPackIndexingType(TypeLocBuilder &TLB, } } + // A pack indexing type can appear in a larger pack expansion, + // e.g. `Pack...[pack_of_indexes]...` + // so we need to temporarily disable substitution of pack elements + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); QualType Result = getDerived().TransformType(TLB, TL.getPatternLoc()); QualType Out = getDerived().RebuildPackIndexingType( @@ -11124,13 +11136,15 @@ template class OpenACCClauseTransform final : public OpenACCClauseVisitor> { TreeTransform &Self; + ArrayRef ExistingClauses; SemaOpenACC::OpenACCParsedClause &ParsedClause; OpenACCClause *NewClause = nullptr; public: OpenACCClauseTransform(TreeTransform &Self, + ArrayRef ExistingClauses, SemaOpenACC::OpenACCParsedClause &PC) - : Self(Self), ParsedClause(PC) {} + : Self(Self), ExistingClauses(ExistingClauses), ParsedClause(PC) {} OpenACCClause *CreatedClause() const { return NewClause; } @@ -11216,6 +11230,31 @@ void OpenACCClauseTransform::VisitNumGangsClause( ParsedClause.getLParenLoc(), ParsedClause.getIntExprs(), ParsedClause.getEndLoc()); } + +template +void OpenACCClauseTransform::VisitPrivateClause( + const OpenACCPrivateClause &C) { + llvm::SmallVector InstantiatedVarList; + + for (Expr *CurVar : C.getVarList()) { + ExprResult Res = Self.TransformExpr(CurVar); + + if (!Res.isUsable()) + return; + + Res = Self.getSema().OpenACC().ActOnVar(Res.get()); + + if (Res.isUsable()) + InstantiatedVarList.push_back(Res.get()); + } + ParsedClause.setVarListDetails(std::move(InstantiatedVarList)); + + NewClause = OpenACCPrivateClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getEndLoc()); +} + template void OpenACCClauseTransform::VisitNumWorkersClause( const OpenACCNumWorkersClause &C) { @@ -11274,7 +11313,8 @@ OpenACCClause *TreeTransform::TransformOpenACCClause( if (const auto *WithParms = dyn_cast(OldClause)) ParsedClause.setLParenLoc(WithParms->getLParenLoc()); - OpenACCClauseTransform Transform{*this, ParsedClause}; + OpenACCClauseTransform Transform{*this, ExistingClauses, + ParsedClause}; Transform.Visit(OldClause); return Transform.CreatedClause(); @@ -11794,7 +11834,7 @@ TreeTransform::TransformMatrixSubscriptExpr(MatrixSubscriptExpr *E) { template ExprResult -TreeTransform::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { +TreeTransform::TransformArraySectionExpr(ArraySectionExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); @@ -11814,20 +11854,25 @@ TreeTransform::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { } ExprResult Stride; - if (Expr *Str = E->getStride()) { - Stride = getDerived().TransformExpr(Str); - if (Stride.isInvalid()) - return ExprError(); + if (E->isOMPArraySection()) { + if (Expr *Str = E->getStride()) { + Stride = getDerived().TransformExpr(Str); + if (Stride.isInvalid()) + return ExprError(); + } } if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && - LowerBound.get() == E->getLowerBound() && Length.get() == E->getLength()) + LowerBound.get() == E->getLowerBound() && + Length.get() == E->getLength() && + (E->isOpenACCArraySection() || Stride.get() == E->getStride())) return E; - return getDerived().RebuildOMPArraySectionExpr( - Base.get(), E->getBase()->getEndLoc(), LowerBound.get(), - E->getColonLocFirst(), E->getColonLocSecond(), Length.get(), Stride.get(), - E->getRBracketLoc()); + return getDerived().RebuildArraySectionExpr( + E->isOMPArraySection(), Base.get(), E->getBase()->getEndLoc(), + LowerBound.get(), E->getColonLocFirst(), + E->isOMPArraySection() ? E->getColonLocSecond() : SourceLocation{}, + Length.get(), Stride.get(), E->getRBracketLoc()); } template @@ -13314,6 +13359,26 @@ bool TreeTransform::TransformOverloadExprDecls(OverloadExpr *Old, // Resolve a kind, but don't do any further analysis. If it's // ambiguous, the callee needs to deal with it. R.resolveKind(); + + if (Old->hasTemplateKeyword() && !R.empty()) { + NamedDecl *FoundDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); + getSema().FilterAcceptableTemplateNames(R, + /*AllowFunctionTemplates=*/true, + /*AllowDependent=*/true); + if (R.empty()) { + // If a 'template' keyword was used, a lookup that finds only non-template + // names is an error. + getSema().Diag(R.getNameLoc(), + diag::err_template_kw_refers_to_non_template) + << R.getLookupName() << Old->getQualifierLoc().getSourceRange() + << Old->hasTemplateKeyword() << Old->getTemplateKeywordLoc(); + getSema().Diag(FoundDecl->getLocation(), + diag::note_template_kw_refers_to_non_template) + << R.getLookupName(); + return true; + } + } + return false; } @@ -14296,6 +14361,8 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { // FIXME: Sema's lambda-building mechanism expects us to push an expression // evaluation context even if we're not transforming the function body. getSema().PushExpressionEvaluationContext( + E->getCallOperator()->isConsteval() ? + Sema::ExpressionEvaluationContext::ImmediateFunctionContext : Sema::ExpressionEvaluationContext::PotentiallyEvaluated); Sema::CodeSynthesisContext C; diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index eb4cbbfbe9bb2..b279ef80d663e 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -268,8 +268,8 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::IncompleteMatrixIdx: ID = PREDEF_TYPE_INCOMPLETE_MATRIX_IDX; break; - case BuiltinType::OMPArraySection: - ID = PREDEF_TYPE_OMP_ARRAY_SECTION; + case BuiltinType::ArraySection: + ID = PREDEF_TYPE_ARRAY_SECTION; break; case BuiltinType::OMPArrayShaping: ID = PREDEF_TYPE_OMP_ARRAY_SHAPING; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index da48f0c5676d7..d0fbd2dc0dfc7 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2630,6 +2630,14 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { F.StandardCXXModule && FileChange.Kind == Change::None) FileChange = HasInputContentChanged(FileChange); + // When we have StoredTime equal to zero and ValidateASTInputFilesContent, + // it is better to check the content of the input files because we cannot rely + // on the file modification time, which will be the same (zero) for these + // files. + if (!StoredTime && ValidateASTInputFilesContent && + FileChange.Kind == Change::None) + FileChange = HasInputContentChanged(FileChange); + // For an overridden file, there is nothing to validate. if (!Overridden && FileChange.Kind != Change::None) { if (Complain && !Diags.isDiagnosticInFlight()) { @@ -5101,8 +5109,9 @@ void ASTReader::InitializeContext() { // If there's a listener, notify them that we "read" the translation unit. if (DeserializationListener) - DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, - Context.getTranslationUnitDecl()); + DeserializationListener->DeclRead( + GlobalDeclID(PREDEF_DECL_TRANSLATION_UNIT_ID), + Context.getTranslationUnitDecl()); // FIXME: Find a better way to deal with collisions between these // built-in types. Right now, we just ignore the problem. @@ -6010,9 +6019,9 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, case SUBMODULE_INITIALIZERS: { if (!ContextObj) break; - SmallVector Inits; + SmallVector Inits; for (auto &ID : Record) - Inits.push_back(getGlobalDeclID(F, LocalDeclID(ID)).get()); + Inits.push_back(getGlobalDeclID(F, LocalDeclID(ID))); ContextObj->addLazyModuleInitializers(CurrentModule, Inits); break; } @@ -7391,11 +7400,11 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_INCOMPLETE_MATRIX_IDX: T = Context.IncompleteMatrixIdxTy; break; - case PREDEF_TYPE_OMP_ARRAY_SECTION: - T = Context.OMPArraySectionTy; + case PREDEF_TYPE_ARRAY_SECTION: + T = Context.ArraySectionTy; break; case PREDEF_TYPE_OMP_ARRAY_SHAPING: - T = Context.OMPArraySectionTy; + T = Context.OMPArrayShapingTy; break; case PREDEF_TYPE_OMP_ITERATOR: T = Context.OMPIteratorTy; @@ -7524,9 +7533,7 @@ ASTRecordReader::readASTTemplateArgumentListInfo() { return ASTTemplateArgumentListInfo::Create(getContext(), Result); } -Decl *ASTReader::GetExternalDecl(DeclID ID) { - return GetDecl(GlobalDeclID(ID)); -} +Decl *ASTReader::GetExternalDecl(GlobalDeclID ID) { return GetDecl(ID); } void ASTReader::CompleteRedeclChain(const Decl *D) { if (NumCurrentElementsDeserializing) { @@ -7675,8 +7682,7 @@ GlobalDeclID ASTReader::getGlobalDeclID(ModuleFile &F, return GlobalDeclID(ID + I->second); } -bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, - ModuleFile &M) const { +bool ASTReader::isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const { // Predefined decls aren't from any module. if (ID.get() < NUM_PREDEF_DECL_IDS) return false; @@ -7775,7 +7781,7 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { Decl *ASTReader::GetExistingDecl(GlobalDeclID ID) { assert(ContextObj && "reading decl with no AST context"); if (ID.get() < NUM_PREDEF_DECL_IDS) { - Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID.get()); + Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID); if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. @@ -7812,28 +7818,28 @@ Decl *ASTReader::GetDecl(GlobalDeclID ID) { if (!DeclsLoaded[Index]) { ReadDeclRecord(ID); if (DeserializationListener) - DeserializationListener->DeclRead(ID.get(), DeclsLoaded[Index]); + DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); } return DeclsLoaded[Index]; } -DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, - GlobalDeclID GlobalID) { +LocalDeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + GlobalDeclID GlobalID) { DeclID ID = GlobalID.get(); if (ID < NUM_PREDEF_DECL_IDS) - return ID; + return LocalDeclID(ID); GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID); assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); ModuleFile *Owner = I->second; - llvm::DenseMap::iterator Pos - = M.GlobalToLocalDeclIDs.find(Owner); + llvm::DenseMap::iterator Pos = + M.GlobalToLocalDeclIDs.find(Owner); if (Pos == M.GlobalToLocalDeclIDs.end()) - return 0; + return LocalDeclID(); - return ID - Owner->BaseDeclID + Pos->second; + return LocalDeclID(ID - Owner->BaseDeclID + Pos->second); } GlobalDeclID ASTReader::ReadDeclID(ModuleFile &F, const RecordData &Record, @@ -7879,7 +7885,7 @@ void ASTReader::FindExternalLexicalDecls( if (!IsKindWeWant(K)) continue; - auto ID = (serialization::DeclID)+LexicalDecls[I + 1]; + auto ID = (DeclID) + LexicalDecls[I + 1]; // Don't add predefined declarations to the lexical context more // than once. @@ -7961,7 +7967,7 @@ void ASTReader::FindFileRegionDecls(FileID File, SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length); DeclIDComp DIDComp(*this, *DInfo.Mod); - ArrayRef::iterator BeginIt = + ArrayRef::iterator BeginIt = llvm::lower_bound(DInfo.Decls, BeginLoc, DIDComp); if (BeginIt != DInfo.Decls.begin()) --BeginIt; @@ -7974,13 +7980,12 @@ void ASTReader::FindFileRegionDecls(FileID File, ->isTopLevelDeclInObjCContainer()) --BeginIt; - ArrayRef::iterator EndIt = + ArrayRef::iterator EndIt = llvm::upper_bound(DInfo.Decls, EndLoc, DIDComp); if (EndIt != DInfo.Decls.end()) ++EndIt; - for (ArrayRef::iterator - DIt = BeginIt; DIt != EndIt; ++DIt) + for (ArrayRef::iterator DIt = BeginIt; DIt != EndIt; ++DIt) Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); } @@ -8001,6 +8006,7 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, // Load the list of declarations. SmallVector Decls; llvm::SmallPtrSet Found; + for (GlobalDeclID ID : It->second.Table.find(Name)) { NamedDecl *ND = cast(GetDecl(ID)); if (ND->getDeclName() == Name && Found.insert(ND).second) @@ -11777,6 +11783,14 @@ void ASTRecordReader::readOMPChildren(OMPChildren *Data) { Data->getChildren()[I] = readStmt(); } +SmallVector ASTRecordReader::readOpenACCVarList() { + unsigned NumVars = readInt(); + llvm::SmallVector VarList; + for (unsigned I = 0; I < NumVars; ++I) + VarList.push_back(readSubExpr()); + return VarList; +} + OpenACCClause *ASTRecordReader::readOpenACCClause() { OpenACCClauseKind ClauseKind = readEnum(); SourceLocation BeginLoc = readSourceLocation(); @@ -11822,6 +11836,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCVectorLengthClause::Create(getContext(), BeginLoc, LParenLoc, IntExpr, EndLoc); } + case OpenACCClauseKind::Private: { + SourceLocation LParenLoc = readSourceLocation(); + llvm::SmallVector VarList = readOpenACCVarList(); + return OpenACCPrivateClause::Create(getContext(), BeginLoc, LParenLoc, + VarList, EndLoc); + } case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Seq: @@ -11843,7 +11863,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { case OpenACCClauseKind::Link: case OpenACCClauseKind::NoCreate: case OpenACCClauseKind::Present: - case OpenACCClauseKind::Private: case OpenACCClauseKind::CopyOut: case OpenACCClauseKind::CopyIn: case OpenACCClauseKind::Create: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index bb82173dfe0b3..744f11de88c2f 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -273,17 +273,15 @@ namespace clang { auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), GlobalDeclIDIterator(Old + 1), - GlobalDeclIDIterator(Old + 1 + Old[0])); + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].get()); llvm::sort(IDs); IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); } - auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; - *Result = IDs.size(); + auto *Result = new (C) GlobalDeclID[1 + IDs.size()]; + *Result = GlobalDeclID(IDs.size()); - std::copy(DeclIDIterator(IDs.begin()), DeclIDIterator(IDs.end()), - Result + 1); + std::copy(IDs.begin(), IDs.end(), Result + 1); LazySpecializations = Result; } @@ -558,7 +556,7 @@ void ASTDeclReader::Visit(Decl *D) { // If this is a tag declaration with a typedef name for linkage, it's safe // to load that typedef now. - if (NamedDeclForTagDecl != GlobalDeclID()) + if (NamedDeclForTagDecl.isValid()) cast(D)->TypedefNameDeclOrQualifier = cast(Reader.GetDecl(NamedDeclForTagDecl)); } else if (auto *ID = dyn_cast(D)) { @@ -603,7 +601,7 @@ void ASTDeclReader::VisitDecl(Decl *D) { GlobalDeclID SemaDCIDForTemplateParmDecl = readDeclID(); GlobalDeclID LexicalDCIDForTemplateParmDecl = HasStandaloneLexicalDC ? readDeclID() : GlobalDeclID(); - if (LexicalDCIDForTemplateParmDecl == GlobalDeclID()) + if (LexicalDCIDForTemplateParmDecl.isInvalid()) LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl; Reader.addPendingDeclContextInfo(D, SemaDCIDForTemplateParmDecl, @@ -1860,7 +1858,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { mergeRedeclarable(D, Redecl); - if (AnonNamespace != GlobalDeclID()) { + if (AnonNamespace.isValid()) { // Each module has its own anonymous namespace, which is disjoint from // any other module's anonymous namespaces, so don't attach the anonymous // namespace at all. @@ -2792,9 +2790,9 @@ ASTDeclReader::VisitRedeclarable(Redeclarable *D) { uint64_t RedeclOffset = 0; - // 0 indicates that this declaration was the only declaration of its entity, - // and is used for space optimization. - if (FirstDeclID == GlobalDeclID()) { + // invalid FirstDeclID indicates that this declaration was the only + // declaration of its entity, and is used for space optimization. + if (FirstDeclID.isInvalid()) { FirstDeclID = ThisDeclID; IsKeyDecl = true; IsFirstLocalDecl = true; @@ -3829,240 +3827,232 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { Twine("ASTReader::readDeclRecord failed reading decl code: ") + toString(MaybeDeclCode.takeError())); - DeclID RawGlobalID = ID.get(); switch ((DeclCode)MaybeDeclCode.get()) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: llvm_unreachable("Record cannot be de-serialized with readDeclRecord"); case DECL_TYPEDEF: - D = TypedefDecl::CreateDeserialized(Context, RawGlobalID); + D = TypedefDecl::CreateDeserialized(Context, ID); break; case DECL_TYPEALIAS: - D = TypeAliasDecl::CreateDeserialized(Context, RawGlobalID); + D = TypeAliasDecl::CreateDeserialized(Context, ID); break; case DECL_ENUM: - D = EnumDecl::CreateDeserialized(Context, RawGlobalID); + D = EnumDecl::CreateDeserialized(Context, ID); break; case DECL_RECORD: - D = RecordDecl::CreateDeserialized(Context, RawGlobalID); + D = RecordDecl::CreateDeserialized(Context, ID); break; case DECL_ENUM_CONSTANT: - D = EnumConstantDecl::CreateDeserialized(Context, RawGlobalID); + D = EnumConstantDecl::CreateDeserialized(Context, ID); break; case DECL_FUNCTION: - D = FunctionDecl::CreateDeserialized(Context, RawGlobalID); + D = FunctionDecl::CreateDeserialized(Context, ID); break; case DECL_LINKAGE_SPEC: - D = LinkageSpecDecl::CreateDeserialized(Context, RawGlobalID); + D = LinkageSpecDecl::CreateDeserialized(Context, ID); break; case DECL_EXPORT: - D = ExportDecl::CreateDeserialized(Context, RawGlobalID); + D = ExportDecl::CreateDeserialized(Context, ID); break; case DECL_LABEL: - D = LabelDecl::CreateDeserialized(Context, RawGlobalID); + D = LabelDecl::CreateDeserialized(Context, ID); break; case DECL_NAMESPACE: - D = NamespaceDecl::CreateDeserialized(Context, RawGlobalID); + D = NamespaceDecl::CreateDeserialized(Context, ID); break; case DECL_NAMESPACE_ALIAS: - D = NamespaceAliasDecl::CreateDeserialized(Context, RawGlobalID); + D = NamespaceAliasDecl::CreateDeserialized(Context, ID); break; case DECL_USING: - D = UsingDecl::CreateDeserialized(Context, RawGlobalID); + D = UsingDecl::CreateDeserialized(Context, ID); break; case DECL_USING_PACK: - D = UsingPackDecl::CreateDeserialized(Context, RawGlobalID, - Record.readInt()); + D = UsingPackDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_USING_SHADOW: - D = UsingShadowDecl::CreateDeserialized(Context, RawGlobalID); + D = UsingShadowDecl::CreateDeserialized(Context, ID); break; case DECL_USING_ENUM: - D = UsingEnumDecl::CreateDeserialized(Context, RawGlobalID); + D = UsingEnumDecl::CreateDeserialized(Context, ID); break; case DECL_CONSTRUCTOR_USING_SHADOW: - D = ConstructorUsingShadowDecl::CreateDeserialized(Context, RawGlobalID); + D = ConstructorUsingShadowDecl::CreateDeserialized(Context, ID); break; case DECL_USING_DIRECTIVE: - D = UsingDirectiveDecl::CreateDeserialized(Context, RawGlobalID); + D = UsingDirectiveDecl::CreateDeserialized(Context, ID); break; case DECL_UNRESOLVED_USING_VALUE: - D = UnresolvedUsingValueDecl::CreateDeserialized(Context, RawGlobalID); + D = UnresolvedUsingValueDecl::CreateDeserialized(Context, ID); break; case DECL_UNRESOLVED_USING_TYPENAME: - D = UnresolvedUsingTypenameDecl::CreateDeserialized(Context, RawGlobalID); + D = UnresolvedUsingTypenameDecl::CreateDeserialized(Context, ID); break; case DECL_UNRESOLVED_USING_IF_EXISTS: - D = UnresolvedUsingIfExistsDecl::CreateDeserialized(Context, RawGlobalID); + D = UnresolvedUsingIfExistsDecl::CreateDeserialized(Context, ID); break; case DECL_CXX_RECORD: - D = CXXRecordDecl::CreateDeserialized(Context, RawGlobalID); + D = CXXRecordDecl::CreateDeserialized(Context, ID); break; case DECL_CXX_DEDUCTION_GUIDE: - D = CXXDeductionGuideDecl::CreateDeserialized(Context, RawGlobalID); + D = CXXDeductionGuideDecl::CreateDeserialized(Context, ID); break; case DECL_CXX_METHOD: - D = CXXMethodDecl::CreateDeserialized(Context, RawGlobalID); + D = CXXMethodDecl::CreateDeserialized(Context, ID); break; case DECL_CXX_CONSTRUCTOR: - D = CXXConstructorDecl::CreateDeserialized(Context, RawGlobalID, - Record.readInt()); + D = CXXConstructorDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_CXX_DESTRUCTOR: - D = CXXDestructorDecl::CreateDeserialized(Context, RawGlobalID); + D = CXXDestructorDecl::CreateDeserialized(Context, ID); break; case DECL_CXX_CONVERSION: - D = CXXConversionDecl::CreateDeserialized(Context, RawGlobalID); + D = CXXConversionDecl::CreateDeserialized(Context, ID); break; case DECL_ACCESS_SPEC: - D = AccessSpecDecl::CreateDeserialized(Context, RawGlobalID); + D = AccessSpecDecl::CreateDeserialized(Context, ID); break; case DECL_FRIEND: - D = FriendDecl::CreateDeserialized(Context, RawGlobalID, Record.readInt()); + D = FriendDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_FRIEND_TEMPLATE: - D = FriendTemplateDecl::CreateDeserialized(Context, RawGlobalID); + D = FriendTemplateDecl::CreateDeserialized(Context, ID); break; case DECL_CLASS_TEMPLATE: - D = ClassTemplateDecl::CreateDeserialized(Context, RawGlobalID); + D = ClassTemplateDecl::CreateDeserialized(Context, ID); break; case DECL_CLASS_TEMPLATE_SPECIALIZATION: - D = ClassTemplateSpecializationDecl::CreateDeserialized(Context, - RawGlobalID); + D = ClassTemplateSpecializationDecl::CreateDeserialized(Context, ID); break; case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: - D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, - RawGlobalID); + D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); break; case DECL_VAR_TEMPLATE: - D = VarTemplateDecl::CreateDeserialized(Context, RawGlobalID); + D = VarTemplateDecl::CreateDeserialized(Context, ID); break; case DECL_VAR_TEMPLATE_SPECIALIZATION: - D = VarTemplateSpecializationDecl::CreateDeserialized(Context, RawGlobalID); + D = VarTemplateSpecializationDecl::CreateDeserialized(Context, ID); break; case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION: - D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, - RawGlobalID); + D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); break; case DECL_FUNCTION_TEMPLATE: - D = FunctionTemplateDecl::CreateDeserialized(Context, RawGlobalID); + D = FunctionTemplateDecl::CreateDeserialized(Context, ID); break; case DECL_TEMPLATE_TYPE_PARM: { bool HasTypeConstraint = Record.readInt(); - D = TemplateTypeParmDecl::CreateDeserialized(Context, RawGlobalID, + D = TemplateTypeParmDecl::CreateDeserialized(Context, ID, HasTypeConstraint); break; } case DECL_NON_TYPE_TEMPLATE_PARM: { bool HasTypeConstraint = Record.readInt(); - D = NonTypeTemplateParmDecl::CreateDeserialized(Context, RawGlobalID, + D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, HasTypeConstraint); break; } case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: { bool HasTypeConstraint = Record.readInt(); D = NonTypeTemplateParmDecl::CreateDeserialized( - Context, RawGlobalID, Record.readInt(), HasTypeConstraint); + Context, ID, Record.readInt(), HasTypeConstraint); break; } case DECL_TEMPLATE_TEMPLATE_PARM: - D = TemplateTemplateParmDecl::CreateDeserialized(Context, RawGlobalID); + D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID); break; case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK: - D = TemplateTemplateParmDecl::CreateDeserialized(Context, RawGlobalID, + D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_TYPE_ALIAS_TEMPLATE: - D = TypeAliasTemplateDecl::CreateDeserialized(Context, RawGlobalID); + D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID); break; case DECL_CONCEPT: - D = ConceptDecl::CreateDeserialized(Context, RawGlobalID); + D = ConceptDecl::CreateDeserialized(Context, ID); break; case DECL_REQUIRES_EXPR_BODY: - D = RequiresExprBodyDecl::CreateDeserialized(Context, RawGlobalID); + D = RequiresExprBodyDecl::CreateDeserialized(Context, ID); break; case DECL_STATIC_ASSERT: - D = StaticAssertDecl::CreateDeserialized(Context, RawGlobalID); + D = StaticAssertDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_METHOD: - D = ObjCMethodDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCMethodDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_INTERFACE: - D = ObjCInterfaceDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCInterfaceDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_IVAR: - D = ObjCIvarDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCIvarDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_PROTOCOL: - D = ObjCProtocolDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCProtocolDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_AT_DEFS_FIELD: - D = ObjCAtDefsFieldDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCAtDefsFieldDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_CATEGORY: - D = ObjCCategoryDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCCategoryDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_CATEGORY_IMPL: - D = ObjCCategoryImplDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCCategoryImplDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_IMPLEMENTATION: - D = ObjCImplementationDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCImplementationDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_COMPATIBLE_ALIAS: - D = ObjCCompatibleAliasDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCCompatibleAliasDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_PROPERTY: - D = ObjCPropertyDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCPropertyDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_PROPERTY_IMPL: - D = ObjCPropertyImplDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCPropertyImplDecl::CreateDeserialized(Context, ID); break; case DECL_FIELD: - D = FieldDecl::CreateDeserialized(Context, RawGlobalID); + D = FieldDecl::CreateDeserialized(Context, ID); break; case DECL_INDIRECTFIELD: - D = IndirectFieldDecl::CreateDeserialized(Context, RawGlobalID); + D = IndirectFieldDecl::CreateDeserialized(Context, ID); break; case DECL_VAR: - D = VarDecl::CreateDeserialized(Context, RawGlobalID); + D = VarDecl::CreateDeserialized(Context, ID); break; case DECL_IMPLICIT_PARAM: - D = ImplicitParamDecl::CreateDeserialized(Context, RawGlobalID); + D = ImplicitParamDecl::CreateDeserialized(Context, ID); break; case DECL_PARM_VAR: - D = ParmVarDecl::CreateDeserialized(Context, RawGlobalID); + D = ParmVarDecl::CreateDeserialized(Context, ID); break; case DECL_DECOMPOSITION: - D = DecompositionDecl::CreateDeserialized(Context, RawGlobalID, - Record.readInt()); + D = DecompositionDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_BINDING: - D = BindingDecl::CreateDeserialized(Context, RawGlobalID); + D = BindingDecl::CreateDeserialized(Context, ID); break; case DECL_FILE_SCOPE_ASM: - D = FileScopeAsmDecl::CreateDeserialized(Context, RawGlobalID); + D = FileScopeAsmDecl::CreateDeserialized(Context, ID); break; case DECL_TOP_LEVEL_STMT_DECL: - D = TopLevelStmtDecl::CreateDeserialized(Context, RawGlobalID); + D = TopLevelStmtDecl::CreateDeserialized(Context, ID); break; case DECL_BLOCK: - D = BlockDecl::CreateDeserialized(Context, RawGlobalID); + D = BlockDecl::CreateDeserialized(Context, ID); break; case DECL_MS_PROPERTY: - D = MSPropertyDecl::CreateDeserialized(Context, RawGlobalID); + D = MSPropertyDecl::CreateDeserialized(Context, ID); break; case DECL_MS_GUID: - D = MSGuidDecl::CreateDeserialized(Context, RawGlobalID); + D = MSGuidDecl::CreateDeserialized(Context, ID); break; case DECL_UNNAMED_GLOBAL_CONSTANT: - D = UnnamedGlobalConstantDecl::CreateDeserialized(Context, RawGlobalID); + D = UnnamedGlobalConstantDecl::CreateDeserialized(Context, ID); break; case DECL_TEMPLATE_PARAM_OBJECT: - D = TemplateParamObjectDecl::CreateDeserialized(Context, RawGlobalID); + D = TemplateParamObjectDecl::CreateDeserialized(Context, ID); break; case DECL_CAPTURED: - D = CapturedDecl::CreateDeserialized(Context, RawGlobalID, - Record.readInt()); + D = CapturedDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_CXX_BASE_SPECIFIERS: Error("attempt to read a C++ base-specifier record as a declaration"); @@ -4073,66 +4063,62 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { case DECL_IMPORT: // Note: last entry of the ImportDecl record is the number of stored source // locations. - D = ImportDecl::CreateDeserialized(Context, RawGlobalID, Record.back()); + D = ImportDecl::CreateDeserialized(Context, ID, Record.back()); break; case DECL_OMP_THREADPRIVATE: { Record.skipInts(1); unsigned NumChildren = Record.readInt(); Record.skipInts(1); - D = OMPThreadPrivateDecl::CreateDeserialized(Context, RawGlobalID, - NumChildren); + D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, NumChildren); break; } case DECL_OMP_ALLOCATE: { unsigned NumClauses = Record.readInt(); unsigned NumVars = Record.readInt(); Record.skipInts(1); - D = OMPAllocateDecl::CreateDeserialized(Context, RawGlobalID, NumVars, - NumClauses); + D = OMPAllocateDecl::CreateDeserialized(Context, ID, NumVars, NumClauses); break; } case DECL_OMP_REQUIRES: { unsigned NumClauses = Record.readInt(); Record.skipInts(2); - D = OMPRequiresDecl::CreateDeserialized(Context, RawGlobalID, NumClauses); + D = OMPRequiresDecl::CreateDeserialized(Context, ID, NumClauses); break; } case DECL_OMP_DECLARE_REDUCTION: - D = OMPDeclareReductionDecl::CreateDeserialized(Context, RawGlobalID); + D = OMPDeclareReductionDecl::CreateDeserialized(Context, ID); break; case DECL_OMP_DECLARE_MAPPER: { unsigned NumClauses = Record.readInt(); Record.skipInts(2); - D = OMPDeclareMapperDecl::CreateDeserialized(Context, RawGlobalID, - NumClauses); + D = OMPDeclareMapperDecl::CreateDeserialized(Context, ID, NumClauses); break; } case DECL_OMP_CAPTUREDEXPR: - D = OMPCapturedExprDecl::CreateDeserialized(Context, RawGlobalID); + D = OMPCapturedExprDecl::CreateDeserialized(Context, ID); break; case DECL_PRAGMA_COMMENT: - D = PragmaCommentDecl::CreateDeserialized(Context, RawGlobalID, - Record.readInt()); + D = PragmaCommentDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_PRAGMA_DETECT_MISMATCH: - D = PragmaDetectMismatchDecl::CreateDeserialized(Context, RawGlobalID, + D = PragmaDetectMismatchDecl::CreateDeserialized(Context, ID, Record.readInt()); break; case DECL_EMPTY: - D = EmptyDecl::CreateDeserialized(Context, RawGlobalID); + D = EmptyDecl::CreateDeserialized(Context, ID); break; case DECL_LIFETIME_EXTENDED_TEMPORARY: - D = LifetimeExtendedTemporaryDecl::CreateDeserialized(Context, RawGlobalID); + D = LifetimeExtendedTemporaryDecl::CreateDeserialized(Context, ID); break; case DECL_OBJC_TYPE_PARAM: - D = ObjCTypeParamDecl::CreateDeserialized(Context, RawGlobalID); + D = ObjCTypeParamDecl::CreateDeserialized(Context, ID); break; case DECL_HLSL_BUFFER: - D = HLSLBufferDecl::CreateDeserialized(Context, RawGlobalID); + D = HLSLBufferDecl::CreateDeserialized(Context, ID); break; case DECL_IMPLICIT_CONCEPT_SPECIALIZATION: - D = ImplicitConceptSpecializationDecl::CreateDeserialized( - Context, RawGlobalID, Record.readInt()); + D = ImplicitConceptSpecializationDecl::CreateDeserialized(Context, ID, + Record.readInt()); break; } @@ -4215,7 +4201,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { // The declaration may have been modified by files later in the chain. // If this is the case, read the record containing the updates from each file // and pass it to ASTDeclReader to make the modifications. - serialization::GlobalDeclID ID = Record.ID; + GlobalDeclID ID = Record.ID; Decl *D = Record.D; ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); @@ -4357,7 +4343,7 @@ namespace { llvm::SmallPtrSetImpl &Deserialized; ObjCCategoryDecl *Tail = nullptr; llvm::DenseMap NameCategoryMap; - serialization::GlobalDeclID InterfaceID; + GlobalDeclID InterfaceID; unsigned PreviousGeneration; void add(ObjCCategoryDecl *Cat) { @@ -4399,11 +4385,10 @@ namespace { } public: - ObjCCategoriesVisitor(ASTReader &Reader, - ObjCInterfaceDecl *Interface, - llvm::SmallPtrSetImpl &Deserialized, - serialization::GlobalDeclID InterfaceID, - unsigned PreviousGeneration) + ObjCCategoriesVisitor( + ASTReader &Reader, ObjCInterfaceDecl *Interface, + llvm::SmallPtrSetImpl &Deserialized, + GlobalDeclID InterfaceID, unsigned PreviousGeneration) : Reader(Reader), Interface(Interface), Deserialized(Deserialized), InterfaceID(InterfaceID), PreviousGeneration(PreviousGeneration) { // Populate the name -> category map with the set of known categories. @@ -4425,8 +4410,9 @@ namespace { // Map global ID of the definition down to the local ID used in this // module file. If there is no such mapping, we'll find nothing here // (or in any module it imports). - DeclID LocalID = Reader.mapGlobalIDToModuleFileGlobalID(M, InterfaceID); - if (!LocalID) + LocalDeclID LocalID = + Reader.mapGlobalIDToModuleFileGlobalID(M, InterfaceID); + if (LocalID.isInvalid()) return true; // Perform a binary search to find the local redeclarations for this @@ -4457,8 +4443,7 @@ namespace { } // namespace -void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID, - ObjCInterfaceDecl *D, +void ASTReader::loadObjCCategories(GlobalDeclID ID, ObjCInterfaceDecl *D, unsigned PreviousGeneration) { ObjCCategoriesVisitor Visitor(*this, D, CategoriesDeserialized, ID, PreviousGeneration); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index f301da1f0031e..d0dd9d8759f6e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -966,14 +966,22 @@ void ASTStmtReader::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) { E->setRBracketLoc(readSourceLocation()); } -void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { +void ASTStmtReader::VisitArraySectionExpr(ArraySectionExpr *E) { VisitExpr(E); + E->ASType = Record.readEnum(); + E->setBase(Record.readSubExpr()); E->setLowerBound(Record.readSubExpr()); E->setLength(Record.readSubExpr()); - E->setStride(Record.readSubExpr()); + + if (E->isOMPArraySection()) + E->setStride(Record.readSubExpr()); + E->setColonLocFirst(readSourceLocation()); - E->setColonLocSecond(readSourceLocation()); + + if (E->isOMPArraySection()) + E->setColonLocSecond(readSourceLocation()); + E->setRBracketLoc(readSourceLocation()); } @@ -3126,8 +3134,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) MatrixSubscriptExpr(Empty); break; - case EXPR_OMP_ARRAY_SECTION: - S = new (Context) OMPArraySectionExpr(Empty); + case EXPR_ARRAY_SECTION: + S = new (Context) ArraySectionExpr(Empty); break; case EXPR_OMP_ARRAY_SHAPING: diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index d0c1217156a59..80c7ce643088b 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -171,76 +171,101 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) { .ModulesPruneNonAffectingModuleMaps) return std::nullopt; - SmallVector ModulesToProcess{RootModule}; - const HeaderSearch &HS = PP.getHeaderSearchInfo(); - - SmallVector FilesByUID; - HS.getFileMgr().GetUniqueIDMapping(FilesByUID); - - if (FilesByUID.size() > HS.header_file_size()) - FilesByUID.resize(HS.header_file_size()); - - for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { - OptionalFileEntryRef File = FilesByUID[UID]; - if (!File) - continue; - - const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo(*File); - if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) - continue; - - for (const auto &KH : HS.findResolvedModulesForHeader(*File)) { - if (!KH.getModule()) - continue; - ModulesToProcess.push_back(KH.getModule()); - } - } - const ModuleMap &MM = HS.getModuleMap(); - SourceManager &SourceMgr = PP.getSourceManager(); std::set ModuleMaps; - auto CollectIncludingModuleMaps = [&](FileID FID, FileEntryRef F) { - if (!ModuleMaps.insert(F).second) + std::set ProcessedModules; + auto CollectModuleMapsForHierarchy = [&](const Module *M) { + M = M->getTopLevelModule(); + + if (!ProcessedModules.insert(M).second) return; - SourceLocation Loc = SourceMgr.getIncludeLoc(FID); - // The include location of inferred module maps can point into the header - // file that triggered the inferring. Cut off the walk if that's the case. - while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { - FID = SourceMgr.getFileID(Loc); - F = *SourceMgr.getFileEntryRefForID(FID); - if (!ModuleMaps.insert(F).second) - break; - Loc = SourceMgr.getIncludeLoc(FID); - } - }; - std::set ProcessedModules; - auto CollectIncludingMapsFromAncestors = [&](const Module *M) { - for (const Module *Mod = M; Mod; Mod = Mod->Parent) { - if (!ProcessedModules.insert(Mod).second) - break; + std::queue Q; + Q.push(M); + while (!Q.empty()) { + const Module *Mod = Q.front(); + Q.pop(); + // The containing module map is affecting, because it's being pointed // into by Module::DefinitionLoc. - if (FileID FID = MM.getContainingModuleMapFileID(Mod); FID.isValid()) - CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID)); - // For inferred modules, the module map that allowed inferring is not in - // the include chain of the virtual containing module map file. It did - // affect the compilation, though. - if (FileID FID = MM.getModuleMapFileIDForUniquing(Mod); FID.isValid()) - CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID)); + if (auto FE = MM.getContainingModuleMapFile(Mod)) + ModuleMaps.insert(*FE); + // For inferred modules, the module map that allowed inferring is not + // related to the virtual containing module map file. It did affect the + // compilation, though. + if (auto FE = MM.getModuleMapFileForUniquing(Mod)) + ModuleMaps.insert(*FE); + + for (auto *SubM : Mod->submodules()) + Q.push(SubM); } }; - for (const Module *CurrentModule : ModulesToProcess) { - CollectIncludingMapsFromAncestors(CurrentModule); + // Handle all the affecting modules referenced from the root module. + + CollectModuleMapsForHierarchy(RootModule); + + std::queue Q; + Q.push(RootModule); + while (!Q.empty()) { + const Module *CurrentModule = Q.front(); + Q.pop(); + for (const Module *ImportedModule : CurrentModule->Imports) - CollectIncludingMapsFromAncestors(ImportedModule); + CollectModuleMapsForHierarchy(ImportedModule); for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses) - CollectIncludingMapsFromAncestors(UndeclaredModule); + CollectModuleMapsForHierarchy(UndeclaredModule); + + for (auto *M : CurrentModule->submodules()) + Q.push(M); } + // Handle textually-included headers that belong to other modules. + + SmallVector FilesByUID; + HS.getFileMgr().GetUniqueIDMapping(FilesByUID); + + if (FilesByUID.size() > HS.header_file_size()) + FilesByUID.resize(HS.header_file_size()); + + for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { + OptionalFileEntryRef File = FilesByUID[UID]; + if (!File) + continue; + + const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo(*File); + if (!HFI) + continue; // We have no information on this being a header file. + if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader) + continue; // Modular header, handled in the above module-based loop. + if (!HFI->isCompilingModuleHeader && !HFI->IsLocallyIncluded) + continue; // Non-modular header not included locally is not affecting. + + for (const auto &KH : HS.findResolvedModulesForHeader(*File)) + if (const Module *M = KH.getModule()) + CollectModuleMapsForHierarchy(M); + } + + // FIXME: This algorithm is not correct for module map hierarchies where + // module map file defining a (sub)module of a top-level module X includes + // a module map file that defines a (sub)module of another top-level module Y. + // Whenever X is affecting and Y is not, "replaying" this PCM file will fail + // when parsing module map files for X due to not knowing about the `extern` + // module map for Y. + // + // We don't have a good way to fix it here. We could mark all children of + // affecting module map files as being affecting as well, but that's + // expensive. SourceManager does not model the edge from parent to child + // SLocEntries, so instead, we would need to iterate over leaf module map + // files, walk up their include hierarchy and check whether we arrive at an + // affecting module map. + // + // Instead of complicating and slowing down this function, we should probably + // just ban module map hierarchies where module map defining a (sub)module X + // includes a module map defining a module that's not a submodule of X. + return ModuleMaps; } @@ -1163,26 +1188,47 @@ ASTWriter::createSignature() const { return std::make_pair(ASTBlockHash, Signature); } +ASTFileSignature ASTWriter::createSignatureForNamedModule() const { + llvm::SHA1 Hasher; + Hasher.update(StringRef(Buffer.data(), Buffer.size())); + + assert(WritingModule); + assert(WritingModule->isNamedModule()); + + // We need to combine all the export imported modules no matter + // we used it or not. + for (auto [ExportImported, _] : WritingModule->Exports) + Hasher.update(ExportImported->Signature); + + return ASTFileSignature::create(Hasher.result()); +} + +static void BackpatchSignatureAt(llvm::BitstreamWriter &Stream, + const ASTFileSignature &S, uint64_t BitNo) { + for (uint8_t Byte : S) { + Stream.BackpatchByte(BitNo, Byte); + BitNo += 8; + } +} + ASTFileSignature ASTWriter::backpatchSignature() { + if (isWritingStdCXXNamedModules()) { + ASTFileSignature Signature = createSignatureForNamedModule(); + BackpatchSignatureAt(Stream, Signature, SignatureOffset); + return Signature; + } + if (!WritingModule || !PP->getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) return {}; // For implicit modules, write the hash of the PCM as its signature. - - auto BackpatchSignatureAt = [&](const ASTFileSignature &S, uint64_t BitNo) { - for (uint8_t Byte : S) { - Stream.BackpatchByte(BitNo, Byte); - BitNo += 8; - } - }; - ASTFileSignature ASTBlockHash; ASTFileSignature Signature; std::tie(ASTBlockHash, Signature) = createSignature(); - BackpatchSignatureAt(ASTBlockHash, ASTBlockHashOffset); - BackpatchSignatureAt(Signature, SignatureOffset); + BackpatchSignatureAt(Stream, ASTBlockHash, ASTBlockHashOffset); + BackpatchSignatureAt(Stream, Signature, SignatureOffset); return Signature; } @@ -1199,9 +1245,11 @@ void ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, RecordData Record; Stream.EnterSubblock(UNHASHED_CONTROL_BLOCK_ID, 5); - // For implicit modules, write the hash of the PCM as its signature. - if (WritingModule && - PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) { + // For implicit modules and C++20 named modules, write the hash of the PCM as + // its signature. + if (isWritingStdCXXNamedModules() || + (WritingModule && + PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent)) { // At this point, we don't know the actual signature of the file or the AST // block - we're only able to compute those at the end of the serialization // process. Let's store dummy signatures for now, and replace them with the @@ -1212,21 +1260,24 @@ void ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, auto Dummy = ASTFileSignature::createDummy(); SmallString<128> Blob{Dummy.begin(), Dummy.end()}; - auto Abbrev = std::make_shared(); - Abbrev->Add(BitCodeAbbrevOp(AST_BLOCK_HASH)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned ASTBlockHashAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + // We don't need AST Block hash in named modules. + if (!isWritingStdCXXNamedModules()) { + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(AST_BLOCK_HASH)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned ASTBlockHashAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); - Abbrev = std::make_shared(); + Record.push_back(AST_BLOCK_HASH); + Stream.EmitRecordWithBlob(ASTBlockHashAbbrev, Record, Blob); + ASTBlockHashOffset = Stream.GetCurrentBitNo() - Blob.size() * 8; + Record.clear(); + } + + auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SIGNATURE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned SignatureAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); - Record.push_back(AST_BLOCK_HASH); - Stream.EmitRecordWithBlob(ASTBlockHashAbbrev, Record, Blob); - ASTBlockHashOffset = Stream.GetCurrentBitNo() - Blob.size() * 8; - Record.clear(); - Record.push_back(SIGNATURE); Stream.EmitRecordWithBlob(SignatureAbbrev, Record, Blob); SignatureOffset = Stream.GetCurrentBitNo() - Blob.size() * 8; @@ -1628,6 +1679,18 @@ struct InputFileEntry { } // namespace +SourceLocation ASTWriter::getAffectingIncludeLoc(const SourceManager &SourceMgr, + const SrcMgr::FileInfo &File) { + SourceLocation IncludeLoc = File.getIncludeLoc(); + if (IncludeLoc.isValid()) { + FileID IncludeFID = SourceMgr.getFileID(IncludeLoc); + assert(IncludeFID.isValid() && "IncludeLoc in invalid file"); + if (!IsSLocAffecting[IncludeFID.ID]) + IncludeLoc = SourceLocation(); + } + return IncludeLoc; +} + void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts) { using namespace llvm; @@ -1681,7 +1744,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, Entry.IsSystemFile = isSystem(File.getFileCharacteristic()); Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; - Entry.IsTopLevel = File.getIncludeLoc().isInvalid(); + Entry.IsTopLevel = getAffectingIncludeLoc(SourceMgr, File).isInvalid(); Entry.IsModuleMap = isModuleMap(File.getFileCharacteristic()); auto ContentHash = hash_code(-1); @@ -2053,14 +2116,13 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { if (!File) continue; - // Get the file info. Skip emitting this file if we have no information on - // it as a header file (in which case HFI will be null) or if it hasn't - // changed since it was loaded. Also skip it if it's for a modular header - // from a different module; in that case, we rely on the module(s) - // containing the header to provide this information. const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo(*File); - if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) - continue; + if (!HFI) + continue; // We have no information on this being a header file. + if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader) + continue; // Header file info is tracked by the owning module file. + if (!HFI->isCompilingModuleHeader && !PP->alreadyIncluded(*File)) + continue; // Non-modular header not included is not needed. // Massage the file path into an appropriate form. StringRef Filename = File->getName(); @@ -2209,7 +2271,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, SLocEntryOffsets.push_back(Offset); // Starting offset of this entry within this module, so skip the dummy. Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2); - AddSourceLocation(File.getIncludeLoc(), Record); + AddSourceLocation(getAffectingIncludeLoc(SourceMgr, File), Record); Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding Record.push_back(File.hasLineDirectives()); @@ -3033,7 +3095,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { RecordData Inits; for (Decl *D : Context->getModuleInitializers(Mod)) if (wasDeclEmitted(D)) - Inits.push_back(GetDeclRef(D)); + AddDeclRef(D, Inits); if (!Inits.empty()) Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits); @@ -3195,6 +3257,17 @@ void ASTWriter::WriteType(QualType T) { // Declaration Serialization //===----------------------------------------------------------------------===// +static bool IsInternalDeclFromFileContext(const Decl *D) { + auto *ND = dyn_cast(D); + if (!ND) + return false; + + if (!D->getDeclContext()->getRedeclContext()->isFileContext()) + return false; + + return ND->getFormalLinkage() == Linkage::Internal; +} + /// Write the block containing all of the declaration IDs /// lexically declared within the given DeclContext. /// @@ -3215,8 +3288,17 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, if (DoneWritingDeclsAndTypes && !wasDeclEmitted(D)) continue; + // We don't need to write decls with internal linkage into reduced BMI. + // If such decls gets emitted due to it get used from inline functions, + // the program illegal. However, there are too many use of static inline + // functions in the global module fragment and it will be breaking change + // to forbid that. So we have to allow to emit such declarations from GMF. + if (GeneratingReducedBMI && !D->isFromExplicitGlobalModule() && + IsInternalDeclFromFileContext(D)) + continue; + KindDeclPairs.push_back(D->getKind()); - KindDeclPairs.push_back(GetDeclRef(D)); + KindDeclPairs.push_back(GetDeclRef(D).get()); } ++NumLexicalDeclContexts; @@ -3251,7 +3333,7 @@ void ASTWriter::WriteTypeDeclOffsets() { unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); { RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size(), - FirstDeclID - NUM_PREDEF_DECL_IDS}; + FirstDeclID.get() - NUM_PREDEF_DECL_IDS}; Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); } } @@ -3272,7 +3354,7 @@ void ASTWriter::WriteFileDeclIDsMap() { Info.FirstDeclIndex = FileGroupedDeclIDs.size(); llvm::stable_sort(Info.DeclIDs); for (auto &LocDeclEntry : Info.DeclIDs) - FileGroupedDeclIDs.push_back(LocDeclEntry.second); + FileGroupedDeclIDs.push_back(LocDeclEntry.second.get()); } auto Abbrev = std::make_shared(); @@ -3410,11 +3492,11 @@ class ASTMethodPoolTrait { for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) - LE.write(Writer.getDeclID(Method->getMethod())); + LE.write((DeclID)Writer.getDeclID(Method->getMethod())); for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) - LE.write(Writer.getDeclID(Method->getMethod())); + LE.write((DeclID)Writer.getDeclID(Method->getMethod())); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } @@ -3733,8 +3815,8 @@ class ASTIdentifierTableTrait { // Only emit declarations that aren't from a chained PCH, though. SmallVector Decls(IdResolver.decls(II)); for (NamedDecl *D : llvm::reverse(Decls)) - LE.write( - Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), D))); + LE.write((DeclID)Writer.getDeclID( + getDeclForLocalLookup(PP.getLangOpts(), D))); } } }; @@ -3850,7 +3932,7 @@ namespace { // Trait used for the on-disk hash table used in the method pool. class ASTDeclContextNameLookupTrait { ASTWriter &Writer; - llvm::SmallVector DeclIDs; + llvm::SmallVector DeclIDs; public: using key_type = DeclarationNameKey; @@ -3876,6 +3958,13 @@ class ASTDeclContextNameLookupTrait { !Writer.wasDeclEmitted(DeclForLocalLookup)) continue; + // Try to avoid writing internal decls to reduced BMI. + // See comments in ASTWriter::WriteDeclContextLexicalBlock for details. + if (Writer.isGeneratingReducedBMI() && + !DeclForLocalLookup->isFromExplicitGlobalModule() && + IsInternalDeclFromFileContext(DeclForLocalLookup)) + continue; + DeclIDs.push_back(Writer.GetDeclRef(DeclForLocalLookup)); } return std::make_pair(Start, DeclIDs.size()); @@ -3883,8 +3972,10 @@ class ASTDeclContextNameLookupTrait { data_type ImportData(const reader::ASTDeclContextNameLookupTrait::data_type &FromReader) { unsigned Start = DeclIDs.size(); - DeclIDs.insert(DeclIDs.end(), DeclIDIterator(FromReader.begin()), - DeclIDIterator(FromReader.end())); + DeclIDs.insert( + DeclIDs.end(), + DeclIDIterator(FromReader.begin()), + DeclIDIterator(FromReader.end())); return std::make_pair(Start, DeclIDs.size()); } @@ -3973,7 +4064,7 @@ class ASTDeclContextNameLookupTrait { endian::Writer LE(Out, llvm::endianness::little); uint64_t Start = Out.tell(); (void)Start; for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) - LE.write(DeclIDs[I]); + LE.write((DeclID)DeclIDs[I]); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } }; @@ -4245,6 +4336,12 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, if (DoneWritingDeclsAndTypes && !wasDeclEmitted(ND)) continue; + // We don't need to force emitting internal decls into reduced BMI. + // See comments in ASTWriter::WriteDeclContextLexicalBlock for details. + if (GeneratingReducedBMI && !ND->isFromExplicitGlobalModule() && + IsInternalDeclFromFileContext(ND)) + continue; + GetDeclRef(ND); } } @@ -4307,7 +4404,8 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { DC = cast(Chain->getKeyDeclaration(cast(DC))); // Write the lookup table - RecordData::value_type Record[] = {UPDATE_VISIBLE, getDeclID(cast(DC))}; + RecordData::value_type Record[] = {UPDATE_VISIBLE, + getDeclID(cast(DC)).get()}; Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable); } @@ -4361,7 +4459,7 @@ void ASTWriter::WriteObjCCategories() { Cat = Class->known_categories_begin(), CatEnd = Class->known_categories_end(); Cat != CatEnd; ++Cat, ++Size) { - assert(getDeclID(*Cat) != 0 && "Bogus category"); + assert(getDeclID(*Cat).isValid() && "Bogus category"); AddDeclRef(*Cat, Categories); } @@ -4904,8 +5002,7 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) { // is ill-formed. However, in practice, there are a lot of projects // uses `static inline` in the headers. So we can't get rid of all // static entities in reduced BMI now. - if (auto *ND = dyn_cast(D); - ND && ND->getFormalLinkage() == Linkage::Internal) + if (IsInternalDeclFromFileContext(D)) continue; } @@ -5079,7 +5176,7 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) { if (!D || !wasDeclEmitted(D)) SemaDeclRefs.push_back(0); else - SemaDeclRefs.push_back(getDeclID(D)); + AddDeclRef(D, SemaDeclRefs); }; AddEmittedDeclRefOrZero(SemaRef.getStdNamespace()); @@ -5090,10 +5187,10 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) { Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); // Write the record containing decls to be checked for deferred diags. - SmallVector DeclsToCheckForDeferredDiags; + RecordData DeclsToCheckForDeferredDiags; for (auto *D : SemaRef.DeclsToCheckForDeferredDiags) if (wasDeclEmitted(D)) - DeclsToCheckForDeferredDiags.push_back(getDeclID(D)); + AddDeclRef(D, DeclsToCheckForDeferredDiags); if (!DeclsToCheckForDeferredDiags.empty()) Stream.EmitRecord(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS, DeclsToCheckForDeferredDiags); @@ -5463,7 +5560,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { if (VisibleOffset) VisibleOffset -= DeclTypesBlockStartOffset; - DelayedNamespaceRecord.push_back(getDeclID(NS)); + AddDeclRef(NS, DelayedNamespaceRecord); DelayedNamespaceRecord.push_back(LexicalOffset); DelayedNamespaceRecord.push_back(VisibleOffset); } @@ -5497,7 +5594,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { continue; NewGlobalKindDeclPairs.push_back(D->getKind()); - NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); + NewGlobalKindDeclPairs.push_back(GetDeclRef(D).get()); } auto Abv = std::make_shared(); @@ -5558,7 +5655,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: assert(Update.getDecl() && "no decl to add?"); - Record.push_back(GetDeclRef(Update.getDecl())); + Record.AddDeclRef(Update.getDecl()); break; case UPD_CXX_ADDED_FUNCTION_DEFINITION: @@ -5699,7 +5796,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { } } - OffsetsRecord.push_back(GetDeclRef(D)); + AddDeclRef(D, OffsetsRecord); OffsetsRecord.push_back(Record.Emit(DECL_UPDATES)); } } @@ -5964,18 +6061,18 @@ void ASTWriter::AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record) { if (!wasDeclEmitted(D)) return; - Record.push_back(GetDeclRef(D)); + Record.push_back(GetDeclRef(D).get()); } void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) { - Record.push_back(GetDeclRef(D)); + Record.push_back(GetDeclRef(D).get()); } -DeclID ASTWriter::GetDeclRef(const Decl *D) { +LocalDeclID ASTWriter::GetDeclRef(const Decl *D) { assert(WritingAST && "Cannot request a declaration ID before AST writing"); if (!D) { - return 0; + return LocalDeclID(); } // If the DeclUpdate from the GMF gets touched, emit it. @@ -5989,14 +6086,14 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) { // If D comes from an AST file, its declaration ID is already known and // fixed. if (D->isFromASTFile()) - return D->getGlobalID(); + return LocalDeclID(D->getGlobalID()); assert(!(reinterpret_cast(D) & 0x01) && "Invalid decl pointer"); - DeclID &ID = DeclIDs[D]; - if (ID == 0) { + LocalDeclID &ID = DeclIDs[D]; + if (ID.isInvalid()) { if (DoneWritingDeclsAndTypes) { assert(0 && "New decl seen after serializing all the decls to emit!"); - return 0; + return LocalDeclID(); } // We haven't seen this declaration before. Give it a new ID and @@ -6008,14 +6105,14 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) { return ID; } -DeclID ASTWriter::getDeclID(const Decl *D) { +LocalDeclID ASTWriter::getDeclID(const Decl *D) { if (!D) - return 0; + return LocalDeclID(); // If D comes from an AST file, its declaration ID is already known and // fixed. if (D->isFromASTFile()) - return D->getGlobalID(); + return LocalDeclID(D->getGlobalID()); assert(DeclIDs.contains(D) && "Declaration not emitted!"); return DeclIDs[D]; @@ -6036,8 +6133,8 @@ bool ASTWriter::wasDeclEmitted(const Decl *D) const { return Emitted; } -void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) { - assert(ID); +void ASTWriter::associateDeclWithFile(const Decl *D, LocalDeclID ID) { + assert(ID.isValid()); assert(D); SourceLocation Loc = D->getLocation(); @@ -6069,7 +6166,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) { if (!Info) Info = std::make_unique(); - std::pair LocDecl(Offset, ID); + std::pair LocDecl(Offset, ID); LocDeclIDsTy &Decls = Info->DeclIDs; Decls.push_back(LocDecl); } @@ -6339,7 +6436,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType(); Record->push_back(ModulesDebugInfo); if (ModulesDebugInfo) - Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D)); + Writer->AddDeclRef(D, Writer->ModularCodegenDecls); // IsLambda bit is already saved. @@ -6443,7 +6540,7 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { // Note, this will get called multiple times, once one the reader starts up // and again each time it's done reading a PCH or module. - FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls(); + FirstDeclID = LocalDeclID(NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls()); FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes(); FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers(); FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros(); @@ -7632,6 +7729,12 @@ void ASTRecordWriter::writeOMPChildren(OMPChildren *Data) { AddStmt(Data->getChildren()[I]); } +void ASTRecordWriter::writeOpenACCVarList(const OpenACCClauseWithVarList *C) { + writeUInt32(C->getVarList().size()); + for (Expr *E : C->getVarList()) + AddStmt(E); +} + void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeEnum(C->getClauseKind()); writeSourceLocation(C->getBeginLoc()); @@ -7678,6 +7781,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { AddStmt(const_cast(NWC->getIntExpr())); return; } + case OpenACCClauseKind::Private: { + const auto *PC = cast(C); + writeSourceLocation(PC->getLParenLoc()); + writeOpenACCVarList(PC); + return; + } case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Seq: @@ -7699,7 +7808,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::Link: case OpenACCClauseKind::NoCreate: case OpenACCClauseKind::Present: - case OpenACCClauseKind::Private: case OpenACCClauseKind::CopyOut: case OpenACCClauseKind::CopyIn: case OpenACCClauseKind::Create: diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c6db107e0ca42..0edc4feda3ef2 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -223,9 +223,9 @@ namespace clang { assert(!Common->LazySpecializations); } - ArrayRef LazySpecializations; + ArrayRef LazySpecializations; if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0]); + LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].get()); // Add a slot to the record for the number of specializations. unsigned I = Record.size(); @@ -243,7 +243,9 @@ namespace clang { assert(D->isCanonicalDecl() && "non-canonical decl in set"); AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); } - Record.append(LazySpecializations.begin(), LazySpecializations.end()); + Record.append( + DeclIDIterator(LazySpecializations.begin()), + DeclIDIterator(LazySpecializations.end())); // Update the size entry we added earlier. Record[I] = Record.size() - I - 1; @@ -1166,7 +1168,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(VarDeclBits); if (ModulesCodegen) - Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D)); + Writer.AddDeclRef(D, Writer.ModularCodegenDecls); if (D->hasAttr()) { BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D); @@ -2786,10 +2788,10 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { "serializing"); // Determine the ID for this declaration. - serialization::DeclID ID; + LocalDeclID ID; assert(!D->isFromASTFile() && "should not be emitting imported decl"); - serialization::DeclID &IDR = DeclIDs[D]; - if (IDR == 0) + LocalDeclID &IDR = DeclIDs[D]; + if (IDR.isInvalid()) IDR = NextDeclID++; ID = IDR; @@ -2807,7 +2809,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { // Record the offset for this declaration SourceLocation Loc = D->getLocation(); - unsigned Index = ID - FirstDeclID; + unsigned Index = ID.get() - FirstDeclID.get(); if (DeclOffsets.size() == Index) DeclOffsets.emplace_back(getAdjustedLocation(Loc), Offset, DeclTypesBlockStartOffset); @@ -2827,7 +2829,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { // Note declarations that should be deserialized eagerly so that we can add // them to a record in the AST file later. if (isRequiredDecl(D, Context, WritingModule)) - EagerlyDeserializedDecls.push_back(ID); + AddDeclRef(D, EagerlyDeserializedDecls); } void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { @@ -2863,7 +2865,7 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { } Record->push_back(ModulesCodegen); if (ModulesCodegen) - Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD)); + Writer->AddDeclRef(FD, Writer->ModularCodegenDecls); if (auto *CD = dyn_cast(FD)) { Record->push_back(CD->getNumCtorInitializers()); if (CD->getNumCtorInitializers()) diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index a74ac0182b7c6..8e3a646ac51ef 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -891,16 +891,21 @@ void ASTStmtWriter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) { Code = serialization::EXPR_ARRAY_SUBSCRIPT; } -void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { +void ASTStmtWriter::VisitArraySectionExpr(ArraySectionExpr *E) { VisitExpr(E); + Record.writeEnum(E->ASType); Record.AddStmt(E->getBase()); Record.AddStmt(E->getLowerBound()); Record.AddStmt(E->getLength()); - Record.AddStmt(E->getStride()); + if (E->isOMPArraySection()) + Record.AddStmt(E->getStride()); Record.AddSourceLocation(E->getColonLocFirst()); - Record.AddSourceLocation(E->getColonLocSecond()); + + if (E->isOMPArraySection()) + Record.AddSourceLocation(E->getColonLocSecond()); + Record.AddSourceLocation(E->getRBracketLoc()); - Code = serialization::EXPR_OMP_ARRAY_SECTION; + Code = serialization::EXPR_ARRAY_SECTION; } void ASTStmtWriter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index bed74399098d7..cc06106a47708 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -88,36 +88,34 @@ ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { return &Writer; } -ReducedBMIGenerator::ReducedBMIGenerator(Preprocessor &PP, - InMemoryModuleCache &ModuleCache, - StringRef OutputFile) +void PCHGenerator::anchor() {} + +CXX20ModulesGenerator::CXX20ModulesGenerator(Preprocessor &PP, + InMemoryModuleCache &ModuleCache, + StringRef OutputFile, + bool GeneratingReducedBMI) : PCHGenerator( PP, ModuleCache, OutputFile, llvm::StringRef(), std::make_shared(), /*Extensions=*/ArrayRef>(), /*AllowASTWithErrors*/ false, /*IncludeTimestamps=*/false, /*BuildingImplicitModule=*/false, /*ShouldCacheASTInMemory=*/false, - /*GeneratingReducedBMI=*/true) {} + GeneratingReducedBMI) {} -Module *ReducedBMIGenerator::getEmittingModule(ASTContext &Ctx) { +Module *CXX20ModulesGenerator::getEmittingModule(ASTContext &Ctx) { Module *M = Ctx.getCurrentNamedModule(); assert(M && M->isNamedModuleUnit() && - "ReducedBMIGenerator should only be used with C++20 Named modules."); + "CXX20ModulesGenerator should only be used with C++20 Named modules."); return M; } -void ReducedBMIGenerator::HandleTranslationUnit(ASTContext &Ctx) { - // We need to do this to make sure the size of reduced BMI not to be larger - // than full BMI. - // +void CXX20ModulesGenerator::HandleTranslationUnit(ASTContext &Ctx) { // FIMXE: We'd better to wrap such options to a new class ASTWriterOptions // since this is not about searching header really. - // FIXME2: We'd better to move the class writing full BMI with reduced BMI. HeaderSearchOptions &HSOpts = getPreprocessor().getHeaderSearchInfo().getHeaderSearchOpts(); HSOpts.ModulesSkipDiagnosticOptions = true; HSOpts.ModulesSkipHeaderSearchPaths = true; - HSOpts.ModulesSkipPragmaDiagnosticMappings = true; PCHGenerator::HandleTranslationUnit(Ctx); @@ -135,3 +133,7 @@ void ReducedBMIGenerator::HandleTranslationUnit(ASTContext &Ctx) { *OS << getBufferPtr()->Data; OS->flush(); } + +void CXX20ModulesGenerator::anchor() {} + +void ReducedBMIGenerator::anchor() {} diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index a678c3827e7f1..1cebfbbee77da 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -188,9 +188,9 @@ void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, os << DerefStr1; break; } - case Stmt::OMPArraySectionExprClass: { + case Stmt::ArraySectionExprClass: { os << "Array access"; - const OMPArraySectionExpr *AE = cast(S); + const ArraySectionExpr *AE = cast(S); AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), N->getLocationContext()); os << DerefStr1; diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp index 1cf81b54e77d3..7ac34ef8164e4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -350,7 +350,7 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, return false; case Stmt::CallExprClass: case Stmt::ArraySubscriptExprClass: - case Stmt::OMPArraySectionExprClass: + case Stmt::ArraySectionExprClass: case Stmt::OMPArrayShapingExprClass: case Stmt::OMPIteratorExprClass: case Stmt::ImplicitCastExprClass: diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index bd495cd0f9710..a0aa2316a7b45 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -600,7 +600,7 @@ struct StreamOperationEvaluator { SValBuilder &SVB; const ASTContext &ACtx; - SymbolRef StreamSym; + SymbolRef StreamSym = nullptr; const StreamState *SS = nullptr; const CallExpr *CE = nullptr; StreamErrorState NewES; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 9ed8e7cab6abb..ec1db1cc33580 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -50,6 +50,9 @@ std::optional isUncounted(const clang::CXXRecordDecl* Class); /// class, false if not, std::nullopt if inconclusive. std::optional isUncountedPtr(const clang::Type* T); +/// \returns true if Name is a RefPtr, Ref, or its variant, false if not. +bool isRefType(const std::string &Name); + /// \returns true if \p F creates ref-countable object from uncounted parameter, /// false if not. bool isCtorOfRefCounted(const clang::FunctionDecl *F); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index 8b41a949fd673..ae494de58da3d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -53,6 +53,13 @@ class UncountedCallArgsChecker bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return false; } + bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl) { + if (isRefType(safeGetName(Decl))) + return true; + return RecursiveASTVisitor::TraverseClassTemplateDecl( + Decl); + } + bool VisitCallExpr(const CallExpr *CE) { Checker->visitCallExpr(CE); return true; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 1cde37c81f611..b8299fac002ea 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1952,7 +1952,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXPseudoDestructorExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::OMPArraySectionExprClass: + case Stmt::ArraySectionExprClass: case Stmt::OMPArrayShapingExprClass: case Stmt::OMPIteratorExprClass: case Stmt::SYCLUniqueStableNameExprClass: diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 32850f5eea92a..0c047b6c5da2f 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -439,6 +439,9 @@ class DependencyScanningAction : public tooling::ToolAction { if (Result) setLastCC1Arguments(std::move(OriginalInvocation)); + // Propagate the statistics to the parent FileManager. + DriverFileMgr->AddStats(ScanInstance.getFileManager()); + return Result; } diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes index 5dbb83cab86bd..b0eead42869a4 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes @@ -7,3 +7,7 @@ Tags: SwiftImportAs: reference SwiftReleaseOp: RCRelease SwiftRetainOp: RCRetain +- Name: NonCopyableType + SwiftCopyable: false +- Name: CopyableType + SwiftCopyable: true diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h index 82b8a6749c4fe..a8f6d0248eae4 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h @@ -4,3 +4,6 @@ struct RefCountedType { int value; }; inline void RCRetain(RefCountedType *x) { x->value++; } inline void RCRelease(RefCountedType *x) { x->value--; } + +struct NonCopyableType { int value; }; +struct CopyableType { int value; }; diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp index 904857e585930..103cf02f431af 100644 --- a/clang/test/APINotes/swift-import-as.cpp +++ b/clang/test/APINotes/swift-import-as.cpp @@ -2,6 +2,8 @@ // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter ImmortalRefType | FileCheck -check-prefix=CHECK-IMMORTAL %s // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter RefCountedType | FileCheck -check-prefix=CHECK-REF-COUNTED %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter NonCopyableType | FileCheck -check-prefix=CHECK-NON-COPYABLE %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter CopyableType | FileCheck -check-prefix=CHECK-COPYABLE %s #include @@ -14,3 +16,11 @@ // CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <> "import_reference" // CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <> "retain:RCRetain" // CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <> "release:RCRelease" + +// CHECK-NON-COPYABLE: Dumping NonCopyableType: +// CHECK-NON-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct NonCopyableType +// CHECK-NON-COPYABLE: SwiftAttrAttr {{.+}} <> "~Copyable" + +// CHECK-COPYABLE: Dumping CopyableType: +// CHECK-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct CopyableType +// CHECK-COPYABLE-NOT: SwiftAttrAttr diff --git a/clang/test/AST/HLSL/this-reference-template.hlsl b/clang/test/AST/HLSL/this-reference-template.hlsl index 60e057986ebf8..d427e73044b78 100644 --- a/clang/test/AST/HLSL/this-reference-template.hlsl +++ b/clang/test/AST/HLSL/this-reference-template.hlsl @@ -24,7 +24,7 @@ void main() { // CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:8:5 getFirst 'K ()' implicit-inline // CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} // CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} -// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} '' lvalue .First +// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} 'K' lvalue .First 0x{{[0-9A-Fa-f]+}} // CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} 'Pair' lvalue this // CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} line:12:5 getSecond 'V ()' implicit-inline // CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index a5951158ed0e0..207da5fe81260 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -263,3 +263,10 @@ const int *p = &b; const __int128 K = (__int128)(int*)0; const unsigned __int128 KU = (unsigned __int128)(int*)0; #endif + + +int test3(void) { + int a[2]; + a[0] = test3; // all-error {{incompatible pointer to integer conversion assigning to 'int' from 'int (void)'}} + return 0; +} diff --git a/clang/test/AST/Interp/cxx23.cpp b/clang/test/AST/Interp/cxx23.cpp index f0325eef6d87c..d1ec93e99803e 100644 --- a/clang/test/AST/Interp/cxx23.cpp +++ b/clang/test/AST/Interp/cxx23.cpp @@ -141,3 +141,32 @@ struct check_ice { }; }; static_assert(check_ice<42>::x == 42); + + +namespace VirtualBases { + namespace One { + struct U { int n; }; + struct V : U { int n; }; + struct A : virtual V { int n; }; + struct Aa { int n; }; + struct B : virtual A, Aa {}; + struct C : virtual A, Aa {}; + struct D : B, C {}; + + /// Calls the constructor of D. + D d; + } +} + +namespace LabelGoto { + constexpr int foo() { // all20-error {{never produces a constant expression}} + a: // all20-warning {{use of this statement in a constexpr function is a C++23 extension}} + goto a; // all20-note 2{{subexpression not valid in a constant expression}} \ + // ref23-note {{subexpression not valid in a constant expression}} \ + // expected23-note {{subexpression not valid in a constant expression}} + + return 1; + } + static_assert(foo() == 1, ""); // all-error {{not an integral constant expression}} \ + // all-note {{in call to}} +} diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index f9bb5d53634e0..a5bb9f1a19aaa 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -601,3 +601,19 @@ namespace FromIntegral { // both-warning {{variable length arrays}} #endif } + +namespace { + template using id = T; + template + constexpr void g() { + constexpr id f; + } + + static_assert((g(), true), ""); +} + +namespace { + /// The InitListExpr here is of void type. + void bir [[clang::annotate("B", {1, 2, 3, 4})]] (); // both-error {{'annotate' attribute requires parameter 1 to be a constant expression}} \ + // both-note {{subexpression not valid in a constant expression}} +} diff --git a/clang/test/AST/Interp/opencl.cl b/clang/test/AST/Interp/opencl.cl new file mode 100644 index 0000000000000..fd7756fff7c11 --- /dev/null +++ b/clang/test/AST/Interp/opencl.cl @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -fsyntax-only -cl-std=CL2.0 -verify=ref,both %s +// RUN: %clang_cc1 -fsyntax-only -cl-std=CL2.0 -verify=expected,both %s -fexperimental-new-constant-interpreter + +// both-no-diagnostics + +typedef int int2 __attribute__((ext_vector_type(2))); +typedef int int3 __attribute__((ext_vector_type(3))); +typedef int int4 __attribute__((ext_vector_type(4))); +typedef int int8 __attribute__((ext_vector_type(8))); +typedef int int16 __attribute__((ext_vector_type(16))); + +void foo(int3 arg1, int8 arg2) { + int4 auto1; + int16 *auto2; + int auto3; + int2 auto4; + struct S *incomplete1; + + int res1[vec_step(arg1) == 4 ? 1 : -1]; + int res2[vec_step(arg2) == 8 ? 1 : -1]; + int res3[vec_step(auto1) == 4 ? 1 : -1]; + int res4[vec_step(*auto2) == 16 ? 1 : -1]; + int res5[vec_step(auto3) == 1 ? 1 : -1]; + int res6[vec_step(auto4) == 2 ? 1 : -1]; + int res7[vec_step(int2) == 2 ? 1 : -1]; + int res8[vec_step(int3) == 4 ? 1 : -1]; + int res9[vec_step(int4) == 4 ? 1 : -1]; + int res10[vec_step(int8) == 8 ? 1 : -1]; + int res11[vec_step(int16) == 16 ? 1 : -1]; + int res12[vec_step(void) == 1 ? 1 : -1]; +} + +void negativeShift32(int a,int b) { + char array0[((int)1)<<40]; +} + +int2 A = {1,2}; +int4 B = {(int2)(1,2), (int2)(3,4)}; diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 3e52354a4a106..771e5adfca34a 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -90,8 +90,7 @@ struct Ints2 { int a = 10; int b; }; -constexpr Ints2 ints22; // both-error {{without a user-provided default constructor}} \ - // expected-error {{must be initialized by a constant expression}} +constexpr Ints2 ints22; // both-error {{without a user-provided default constructor}} constexpr Ints2 I2 = Ints2{12, 25}; static_assert(I2.a == 12, ""); @@ -1031,6 +1030,12 @@ namespace ParenInit { // both-note {{required by 'constinit' specifier}} \ // both-note {{reference to temporary is not a constant expression}} \ // both-note {{temporary created here}} + + + /// Initializing an array. + constexpr void bar(int i, int j) { + int arr[4](i, j); + } } #endif @@ -1330,3 +1335,108 @@ namespace UnnamedBitFields { static_assert(a.f == 1.0, ""); static_assert(a.c == 'a', ""); } + +/// FIXME: This still doesn't work in the new interpreter because +/// we lack type information for dummy pointers. +namespace VirtualBases { + /// This used to crash. + namespace One { + class A { + protected: + int x; + }; + class B : public virtual A { + public: + int getX() { return x; } // ref-note {{declared here}} + }; + + class DV : virtual public B{}; + + void foo() { + DV b; + int a[b.getX()]; // both-warning {{variable length arrays}} \ + // ref-note {{non-constexpr function 'getX' cannot be used}} + } + } + + namespace Two { + struct U { int n; }; + struct A : virtual U { int n; }; + struct B : A {}; + B a; + static_assert((U*)(A*)(&a) == (U*)(&a), ""); + + struct C : virtual A {}; + struct D : B, C {}; + D d; + constexpr B *p = &d; + constexpr C *q = &d; + static_assert((A*)p == (A*)q, ""); // both-error {{failed}} + } + + namespace Three { + struct U { int n; }; + struct V : U { int n; }; + struct A : virtual V { int n; }; + struct Aa { int n; }; + struct B : virtual A, Aa {}; + + struct C : virtual A, Aa {}; + + struct D : B, C {}; + + D d; + + constexpr B *p = &d; + constexpr C *q = &d; + + static_assert((void*)p != (void*)q, ""); + static_assert((A*)p == (A*)q, ""); + static_assert((Aa*)p != (Aa*)q, ""); + + constexpr V *v = p; + constexpr V *w = q; + constexpr V *x = (A*)p; + static_assert(v == w, ""); + static_assert(v == x, ""); + + static_assert((U*)&d == p, ""); + static_assert((U*)&d == q, ""); + static_assert((U*)&d == v, ""); + static_assert((U*)&d == w, ""); + static_assert((U*)&d == x, ""); + + struct X {}; + struct Y1 : virtual X {}; + struct Y2 : X {}; + struct Z : Y1, Y2 {}; + Z z; + static_assert((X*)(Y1*)&z != (X*)(Y2*)&z, ""); + } +} + +namespace ZeroInit { + struct S3 { + S3() = default; + S3(const S3&) = default; + S3(S3&&) = default; + constexpr S3(int n) : n(n) {} + int n; + }; + constexpr S3 s3d; // both-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} + static_assert(s3d.n == 0, ""); +} + +namespace { +#if __cplusplus >= 202002L + struct C { + template constexpr C(const char (&)[N]) : n(N) {} + unsigned n; + }; + template + constexpr auto operator""_c() { return c.n; } + + constexpr auto waldo = "abc"_c; + static_assert(waldo == 4, ""); +#endif +} diff --git a/clang/test/AST/ast-dump-macro-json.c b/clang/test/AST/ast-dump-macro-json.c index 96f4be6fec3dd..fb9b4118b4f17 100644 --- a/clang/test/AST/ast-dump-macro-json.c +++ b/clang/test/AST/ast-dump-macro-json.c @@ -132,7 +132,7 @@ void BLAP(foo, __COUNTER__)(void); // CHECK-NEXT: "spellingLoc": { // CHECK-NEXT: "offset": {{[0-9]+}}, // CHECK-NEXT: "file": "", -// CHECK-NEXT: "line": 3, +// CHECK-NEXT: "line": 5, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, @@ -169,7 +169,7 @@ void BLAP(foo, __COUNTER__)(void); // CHECK-NEXT: "spellingLoc": { // CHECK-NEXT: "offset": {{[0-9]+}}, // CHECK-NEXT: "file": "", -// CHECK-NEXT: "line": 5, +// CHECK-NEXT: "line": 7, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, diff --git a/clang/test/AST/ast-dump-pragma-unroll.cpp b/clang/test/AST/ast-dump-pragma-unroll.cpp new file mode 100644 index 0000000000000..f9c254b803ff2 --- /dev/null +++ b/clang/test/AST/ast-dump-pragma-unroll.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump %s | FileCheck %s + +using size_t = unsigned long long; + +// CHECK: LoopHintAttr {{.*}} Implicit unroll UnrollCount Numeric +// CHECK: LoopHintAttr {{.*}} Implicit unroll UnrollCount Numeric +// CHECK: LoopHintAttr {{.*}} Implicit unroll Unroll Disable +// CHECK: LoopHintAttr {{.*}} Implicit unroll Unroll Disable +template +int value_dependent(int n) { + constexpr int N = 100; + auto init = [=]() { return Flag ? n : 0UL; }; + auto cond = [=](size_t ix) { return Flag ? ix != 0 : ix < 10; }; + auto iter = [=](size_t ix) { + return Flag ? ix & ~(1ULL << __builtin_clzll(ix)) : ix + 1; + }; + +#pragma unroll Flag ? 1 : N + for (size_t ix = init(); cond(ix); ix = iter(ix)) { + n *= n; + } +#pragma unroll Flag ? 0 : N + for (size_t ix = init(); cond(ix); ix = iter(ix)) { + n *= n; + } + return n; +} + +void test_value_dependent(int n) { + value_dependent(n); +} diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index cfb013585ad74..77527743fe857 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -413,6 +413,14 @@ void RecoveryExprForInvalidDecls(Unknown InvalidDecl) { // CHECK-NEXT: `-RecoveryExpr {{.*}} '' } +void InitializerOfInvalidDecl() { + int ValidDecl; + Unkown InvalidDecl = ValidDecl; + // CHECK: VarDecl {{.*}} invalid InvalidDecl + // CHECK-NEXT: `-RecoveryExpr {{.*}} '' contains-errors + // CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'ValidDecl' +} + void RecoverToAnInvalidDecl() { Unknown* foo; // invalid decl goo; // the typo was correct to the invalid foo. diff --git a/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp b/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp index cf740516db6f4..5ac55d269dce4 100644 --- a/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp +++ b/clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp @@ -1846,6 +1846,42 @@ int main() // CHECK-NEXT: "kind": "VarTemplateDecl", // CHECK-NEXT: "name": "is_const_v" // CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "TemplateArgument", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "const _Ty" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "QualType", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "const _Ty" +// CHECK-NEXT: }, +// CHECK-NEXT: "qualifiers": "const", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmType", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "_Ty" +// CHECK-NEXT: }, +// CHECK-NEXT: "isDependent": true, +// CHECK-NEXT: "isInstantiationDependent": true, +// CHECK-NEXT: "depth": 0, +// CHECK-NEXT: "index": 0, +// CHECK-NEXT: "decl": { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmDecl", +// CHECK-NEXT: "name": "_Ty" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ] @@ -1900,6 +1936,32 @@ int main() // CHECK-NEXT: "kind": "VarTemplateDecl", // CHECK-NEXT: "name": "is_reference_v" // CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "TemplateArgument", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "_Ty" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmType", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "_Ty" +// CHECK-NEXT: }, +// CHECK-NEXT: "isDependent": true, +// CHECK-NEXT: "isInstantiationDependent": true, +// CHECK-NEXT: "depth": 0, +// CHECK-NEXT: "index": 0, +// CHECK-NEXT: "decl": { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmDecl", +// CHECK-NEXT: "name": "_Ty" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ] @@ -2565,6 +2627,32 @@ int main() // CHECK-NEXT: "kind": "VarTemplateDecl", // CHECK-NEXT: "name": "is_function_v" // CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "TemplateArgument", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "_Ty1" +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmType", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "_Ty1" +// CHECK-NEXT: }, +// CHECK-NEXT: "isDependent": true, +// CHECK-NEXT: "isInstantiationDependent": true, +// CHECK-NEXT: "depth": 0, +// CHECK-NEXT: "index": 0, +// CHECK-NEXT: "decl": { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmDecl", +// CHECK-NEXT: "name": "_Ty1" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ] diff --git a/clang/test/AST/ast-dump-templates.cpp b/clang/test/AST/ast-dump-templates.cpp index d25ef36dd4d32..9fcafbcbcc46b 100644 --- a/clang/test/AST/ast-dump-templates.cpp +++ b/clang/test/AST/ast-dump-templates.cpp @@ -104,3 +104,17 @@ void (*q)() = f<>; // CHECK1: template<> void f<0L>() // CHECK1: template<> void f<0U>() } + +namespace test6 { +template +constexpr bool C = true; + +template +void func() { + C; +// DUMP: UnresolvedLookupExpr {{.*}} '' lvalue (no ADL) = 'C' +// DUMP-NEXT: `-TemplateArgument type 'Key' +// DUMP-NEXT: `-TemplateTypeParmType {{.*}} 'Key' dependent depth 0 index 0 +// DUMP-NEXT: `-TemplateTypeParm {{.*}} 'Key' +} +} diff --git a/clang/test/AST/ast-print-openacc-compute-construct.cpp b/clang/test/AST/ast-print-openacc-compute-construct.cpp new file mode 100644 index 0000000000000..cd39ea087b3ca --- /dev/null +++ b/clang/test/AST/ast-print-openacc-compute-construct.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s + +void foo() { + int i; + float array[5]; +// CHECK: #pragma acc parallel default(none) +// CHECK-NEXT: while (true) +#pragma acc parallel default(none) + while(true); +// CHECK: #pragma acc serial default(present) +// CHECK-NEXT: while (true) +#pragma acc serial default(present) + while(true); +// CHECK: #pragma acc kernels if(i == array[1]) +// CHECK-NEXT: while (true) +#pragma acc kernels if(i == array[1]) + while(true); +// CHECK: #pragma acc parallel self(i == 3) +// CHECK-NEXT: while (true) +#pragma acc parallel self(i == 3) + while(true); + +// CHECK: #pragma acc parallel num_gangs(i, (int)array[2]) +// CHECK-NEXT: while (true) +#pragma acc parallel num_gangs(i, (int)array[2]) + while(true); + +// CHECK: #pragma acc parallel num_workers(i) +// CHECK-NEXT: while (true) +#pragma acc parallel num_workers(i) + while(true); + +// CHECK: #pragma acc parallel vector_length((int)array[1]) +// CHECK-NEXT: while (true) +#pragma acc parallel vector_length((int)array[1]) + while(true); + +// CHECK: #pragma acc parallel private(i, array[1], array, array[1:2]) +#pragma acc parallel private(i, array[1], array, array[1:2]) + while(true); +} + diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-regression-traverse-decl-crash.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-regression-traverse-decl-crash.cpp new file mode 100644 index 0000000000000..3d8e822025f62 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/call-args-regression-traverse-decl-crash.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s +// expected-no-diagnostics + +template struct T; +template